Changeset 33c2952 in mainline for kernel


Ignore:
Timestamp:
2012-11-07T21:00:02Z (13 years ago)
Author:
Adam Hraska <adam.hraska+hos@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
dcb0751
Parents:
fc89e32 (diff), 94795812 (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merged with mainline.

Location:
kernel
Files:
16 added
28 edited

Legend:

Unmodified
Added
Removed
  • kernel/Makefile

    rfc89e32 r33c2952  
    262262        generic/src/ipc/ipc.c \
    263263        generic/src/ipc/sysipc.c \
     264        generic/src/ipc/sysipc_ops.c \
     265        generic/src/ipc/ops/clnestab.c \
     266        generic/src/ipc/ops/conctmeto.c \
     267        generic/src/ipc/ops/concttome.c \
     268        generic/src/ipc/ops/connclone.c \
     269        generic/src/ipc/ops/dataread.c \
     270        generic/src/ipc/ops/datawrite.c \
     271        generic/src/ipc/ops/debug.c \
     272        generic/src/ipc/ops/sharein.c \
     273        generic/src/ipc/ops/shareout.c \
     274        generic/src/ipc/ops/stchngath.c \
    264275        generic/src/ipc/ipcrsc.c \
    265276        generic/src/ipc/irq.c \
  • kernel/arch/arm32/Makefile.inc

    rfc89e32 r33c2952  
    3333ATSIGN = %
    3434
    35 GCC_CFLAGS += -march=armv4
     35GCC_CFLAGS += -march=armv4 -fno-omit-frame-pointer -mapcs-frame
    3636
    3737BITS = 32
  • kernel/arch/arm32/include/istate.h

    rfc89e32 r33c2952  
    4949/** Struct representing CPU state saved when an exception occurs. */
    5050typedef struct istate {
     51        uint32_t dummy;
    5152        uint32_t spsr;
    5253        uint32_t sp;
  • kernel/arch/arm32/src/exc_handler.S

    rfc89e32 r33c2952  
    130130        stmfd r13!, {r2}
    1311312:
     132        sub sp, sp, #4
    132133.endm
    133134
    134135.macro LOAD_REGS_FROM_STACK
     136        add sp, sp, #4
    135137        ldmfd r13!, {r0}
    136138        msr spsr, r0
  • kernel/arch/arm32/src/exception.c

    rfc89e32 r33c2952  
    123123       
    124124        asm volatile (
    125                 "mrc p15, 0, %[control_reg], c1, c1"
     125                "mrc p15, 0, %[control_reg], c1, c0"
    126126                : [control_reg] "=r" (control_reg)
    127127        );
     
    131131       
    132132        asm volatile (
    133                 "mcr p15, 0, %[control_reg], c1, c1"
     133                "mcr p15, 0, %[control_reg], c1, c0"
    134134                :: [control_reg] "r" (control_reg)
    135135        );
  • kernel/arch/arm32/src/mach/integratorcp/integratorcp.c

    rfc89e32 r33c2952  
    3838#include <console/chardev.h>
    3939#include <genarch/drivers/pl050/pl050.h>
     40#include <genarch/drivers/arm926_uart/arm926_uart.h>
    4041#include <genarch/kbrd/kbrd.h>
     42#include <genarch/srln/srln.h>
    4143#include <console/console.h>
    4244#include <sysinfo/sysinfo.h>
     
    5355#include <print.h>
    5456
     57
    5558#define SDRAM_SIZE      (sdram[((*(uint32_t *)(ICP_CMCR+ICP_SDRAMCR_OFFSET) & ICP_SDRAM_MASK) >> 2)])
    56 static icp_hw_map_t icp_hw_map;
    57 static irq_t icp_timer_irq;
     59
     60static struct {
     61        icp_hw_map_t hw_map;
     62        irq_t timer_irq;
     63        arm926_uart_t uart;
     64} icp;
     65
     66
     67
    5868struct arm_machine_ops icp_machine_ops = {
    5969        icp_init,
     
    7080
    7181static bool hw_map_init_called = false;
    72 static bool vga_init = false;
    7382uint32_t sdram[8] = {
    7483        16777216,       /* 16mb */
     
    8998void icp_vga_init(void)
    9099{
    91         *(uint32_t*)((char *)(icp_hw_map.cmcr)+0x14) = 0xA05F0000;
    92         *(uint32_t*)((char *)(icp_hw_map.cmcr)+0x1C) = 0x12C11000;
    93         *(uint32_t*)icp_hw_map.vga = 0x3F1F3F9C;
    94         *(uint32_t*)((char *)(icp_hw_map.vga) + 0x4) = 0x080B61DF;
    95         *(uint32_t*)((char *)(icp_hw_map.vga) + 0x8) = 0x067F3800;
    96         *(uint32_t*)((char *)(icp_hw_map.vga) + 0x10) = ICP_FB;
    97         *(uint32_t *)((char *)(icp_hw_map.vga) + 0x1C) = 0x182B;
    98         *(uint32_t*)((char *)(icp_hw_map.cmcr)+0xC) = 0x33805000;
     100        *(uint32_t*)((char *)(icp.hw_map.cmcr)+0x14) = 0xA05F0000;
     101        *(uint32_t*)((char *)(icp.hw_map.cmcr)+0x1C) = 0x12C11000;
     102        *(uint32_t*)icp.hw_map.vga = 0x3F1F3F9C;
     103        *(uint32_t*)((char *)(icp.hw_map.vga) + 0x4) = 0x080B61DF;
     104        *(uint32_t*)((char *)(icp.hw_map.vga) + 0x8) = 0x067F3800;
     105        *(uint32_t*)((char *)(icp.hw_map.vga) + 0x10) = ICP_FB;
     106        *(uint32_t *)((char *)(icp.hw_map.vga) + 0x1C) = 0x182B;
     107        *(uint32_t*)((char *)(icp.hw_map.cmcr)+0xC) = 0x33805000;
    99108       
    100109}
     
    103112static inline uint32_t icp_irqc_get_sources(void)
    104113{
    105         return *((uint32_t *) icp_hw_map.irqc);
     114        return *((uint32_t *) icp.hw_map.irqc);
    106115}
    107116
     
    113122static inline void icp_irqc_mask(uint32_t irq)
    114123{
    115         *((uint32_t *) icp_hw_map.irqc_mask) = (1 << irq);
     124        *((uint32_t *) icp.hw_map.irqc_mask) = (1 << irq);
    116125}
    117126
     
    123132static inline void icp_irqc_unmask(uint32_t irq)
    124133{
    125         *((uint32_t *) icp_hw_map.irqc_unmask) |= (1 << irq);
    126 }
    127 
    128 /** Initializes icp_hw_map. */
     134        *((uint32_t *) icp.hw_map.irqc_unmask) |= (1 << irq);
     135}
     136
     137/** Initializes icp.hw_map. */
    129138void icp_init(void)
    130139{
    131         icp_hw_map.uart = km_map(ICP_UART, PAGE_SIZE,
    132             PAGE_WRITE | PAGE_NOT_CACHEABLE);
    133         icp_hw_map.kbd_ctrl = km_map(ICP_KBD, PAGE_SIZE, PAGE_NOT_CACHEABLE);
    134         icp_hw_map.kbd_stat = icp_hw_map.kbd_ctrl + ICP_KBD_STAT;
    135         icp_hw_map.kbd_data = icp_hw_map.kbd_ctrl + ICP_KBD_DATA;
    136         icp_hw_map.kbd_intstat = icp_hw_map.kbd_ctrl + ICP_KBD_INTR_STAT;
    137         icp_hw_map.rtc = km_map(ICP_RTC, PAGE_SIZE,
    138             PAGE_WRITE | PAGE_NOT_CACHEABLE);
    139         icp_hw_map.rtc1_load = icp_hw_map.rtc + ICP_RTC1_LOAD_OFFSET;
    140         icp_hw_map.rtc1_read = icp_hw_map.rtc + ICP_RTC1_READ_OFFSET;
    141         icp_hw_map.rtc1_ctl = icp_hw_map.rtc + ICP_RTC1_CTL_OFFSET;
    142         icp_hw_map.rtc1_intrclr = icp_hw_map.rtc + ICP_RTC1_INTRCLR_OFFSET;
    143         icp_hw_map.rtc1_bgload = icp_hw_map.rtc + ICP_RTC1_BGLOAD_OFFSET;
    144         icp_hw_map.rtc1_intrstat = icp_hw_map.rtc + ICP_RTC1_INTRSTAT_OFFSET;
    145 
    146         icp_hw_map.irqc = km_map(ICP_IRQC, PAGE_SIZE,
    147             PAGE_WRITE | PAGE_NOT_CACHEABLE);
    148         icp_hw_map.irqc_mask = icp_hw_map.irqc + ICP_IRQC_MASK_OFFSET;
    149         icp_hw_map.irqc_unmask = icp_hw_map.irqc + ICP_IRQC_UNMASK_OFFSET;
    150         icp_hw_map.cmcr = km_map(ICP_CMCR, PAGE_SIZE,
    151             PAGE_WRITE | PAGE_NOT_CACHEABLE);
    152         icp_hw_map.sdramcr = icp_hw_map.cmcr + ICP_SDRAMCR_OFFSET;
    153         icp_hw_map.vga = km_map(ICP_VGA, PAGE_SIZE,
     140        icp.hw_map.uart = km_map(ICP_UART, PAGE_SIZE,
     141            PAGE_WRITE | PAGE_NOT_CACHEABLE);
     142        icp.hw_map.kbd_ctrl = km_map(ICP_KBD, PAGE_SIZE, PAGE_NOT_CACHEABLE);
     143        icp.hw_map.kbd_stat = icp.hw_map.kbd_ctrl + ICP_KBD_STAT;
     144        icp.hw_map.kbd_data = icp.hw_map.kbd_ctrl + ICP_KBD_DATA;
     145        icp.hw_map.kbd_intstat = icp.hw_map.kbd_ctrl + ICP_KBD_INTR_STAT;
     146        icp.hw_map.rtc = km_map(ICP_RTC, PAGE_SIZE,
     147            PAGE_WRITE | PAGE_NOT_CACHEABLE);
     148        icp.hw_map.rtc1_load = icp.hw_map.rtc + ICP_RTC1_LOAD_OFFSET;
     149        icp.hw_map.rtc1_read = icp.hw_map.rtc + ICP_RTC1_READ_OFFSET;
     150        icp.hw_map.rtc1_ctl = icp.hw_map.rtc + ICP_RTC1_CTL_OFFSET;
     151        icp.hw_map.rtc1_intrclr = icp.hw_map.rtc + ICP_RTC1_INTRCLR_OFFSET;
     152        icp.hw_map.rtc1_bgload = icp.hw_map.rtc + ICP_RTC1_BGLOAD_OFFSET;
     153        icp.hw_map.rtc1_intrstat = icp.hw_map.rtc + ICP_RTC1_INTRSTAT_OFFSET;
     154
     155        icp.hw_map.irqc = km_map(ICP_IRQC, PAGE_SIZE,
     156            PAGE_WRITE | PAGE_NOT_CACHEABLE);
     157        icp.hw_map.irqc_mask = icp.hw_map.irqc + ICP_IRQC_MASK_OFFSET;
     158        icp.hw_map.irqc_unmask = icp.hw_map.irqc + ICP_IRQC_UNMASK_OFFSET;
     159        icp.hw_map.cmcr = km_map(ICP_CMCR, PAGE_SIZE,
     160            PAGE_WRITE | PAGE_NOT_CACHEABLE);
     161        icp.hw_map.sdramcr = icp.hw_map.cmcr + ICP_SDRAMCR_OFFSET;
     162        icp.hw_map.vga = km_map(ICP_VGA, PAGE_SIZE,
    154163            PAGE_WRITE | PAGE_NOT_CACHEABLE);
    155164
     
    164173{
    165174        icp_irqc_mask(ICP_TIMER_IRQ);
    166         *((uint32_t*) icp_hw_map.rtc1_load) = frequency;
    167         *((uint32_t*) icp_hw_map.rtc1_bgload) = frequency;
    168         *((uint32_t*) icp_hw_map.rtc1_ctl) = ICP_RTC_CTL_VALUE;
     175        *((uint32_t*) icp.hw_map.rtc1_load) = frequency;
     176        *((uint32_t*) icp.hw_map.rtc1_bgload) = frequency;
     177        *((uint32_t*) icp.hw_map.rtc1_ctl) = ICP_RTC_CTL_VALUE;
    169178        icp_irqc_unmask(ICP_TIMER_IRQ);
    170179}
     
    172181static irq_ownership_t icp_timer_claim(irq_t *irq)
    173182{
    174         if (icp_hw_map.rtc1_intrstat) {
    175                 *((uint32_t*) icp_hw_map.rtc1_intrclr) = 1;
     183        if (icp.hw_map.rtc1_intrstat) {
     184                *((uint32_t*) icp.hw_map.rtc1_intrclr) = 1;
    176185                return IRQ_ACCEPT;
    177186        } else
     
    200209static void icp_timer_irq_init(void)
    201210{
    202         irq_initialize(&icp_timer_irq);
    203         icp_timer_irq.devno = device_assign_devno();
    204         icp_timer_irq.inr = ICP_TIMER_IRQ;
    205         icp_timer_irq.claim = icp_timer_claim;
    206         icp_timer_irq.handler = icp_timer_irq_handler;
    207 
    208         irq_register(&icp_timer_irq);
     211        irq_initialize(&icp.timer_irq);
     212        icp.timer_irq.devno = device_assign_devno();
     213        icp.timer_irq.inr = ICP_TIMER_IRQ;
     214        icp.timer_irq.claim = icp_timer_claim;
     215        icp.timer_irq.handler = icp_timer_irq_handler;
     216
     217        irq_register(&icp.timer_irq);
    209218}
    210219
     
    231240
    232241        if (hw_map_init_called) {
    233                 *size = (sdram[((*(uint32_t *)icp_hw_map.sdramcr &
     242                *size = (sdram[((*(uint32_t *)icp.hw_map.sdramcr &
    234243                    ICP_SDRAM_MASK) >> 2)]);
    235244        } else {
     
    286295{
    287296#ifdef CONFIG_FB
     297        static bool vga_init = false;
    288298        if (!vga_init) {
    289299                icp_vga_init();
     
    304314                stdout_wire(fbdev);
    305315#endif
     316#ifdef CONFIG_ARM926_UART
     317        if (arm926_uart_init(&icp.uart, ARM926_UART0_IRQ,
     318            ARM926_UART0_BASE_ADDRESS, sizeof(arm926_uart_regs_t)))
     319                stdout_wire(&icp.uart.outdev);
     320#endif
    306321}
    307322
     
    310325
    311326        pl050_t *pl050 = malloc(sizeof(pl050_t), FRAME_ATOMIC);
    312         pl050->status = (ioport8_t *)icp_hw_map.kbd_stat;
    313         pl050->data = (ioport8_t *)icp_hw_map.kbd_data;
    314         pl050->ctrl = (ioport8_t *)icp_hw_map.kbd_ctrl;
     327        pl050->status = (ioport8_t *)icp.hw_map.kbd_stat;
     328        pl050->data = (ioport8_t *)icp.hw_map.kbd_data;
     329        pl050->ctrl = (ioport8_t *)icp.hw_map.kbd_ctrl;
    315330               
    316331        pl050_instance_t *pl050_instance = pl050_init(pl050, ICP_KBD_IRQ);
     
    335350            ICP_KBD);
    336351
     352#ifdef CONFIG_ARM926_UART
     353        srln_instance_t *srln_instance = srln_init();
     354        if (srln_instance) {
     355                indev_t *sink = stdin_wire();
     356                indev_t *srln = srln_wire(srln_instance, sink);
     357                arm926_uart_input_wire(&icp.uart, srln);
     358                icp_irqc_unmask(ARM926_UART0_IRQ);
     359        }
     360#endif
    337361}
    338362
  • kernel/arch/arm32/src/mm/page_fault.c

    rfc89e32 r33c2952  
    7777}
    7878
    79 /** Decides whether the instruction is load/store or not.
    80  *
    81  * @param instr Instruction
    82  *
    83  * @return true when instruction is load/store, false otherwise
    84  *
    85  */
    86 static inline bool is_load_store_instruction(instruction_t instr)
    87 {
    88         /* load store immediate offset */
    89         if (instr.type == 0x2)
    90                 return true;
    91        
    92         /* load store register offset */
    93         if ((instr.type == 0x3) && (instr.bit4 == 0))
    94                 return true;
    95        
    96         /* load store multiple */
    97         if (instr.type == 0x4)
    98                 return true;
    99        
    100         /* oprocessor load/store */
    101         if (instr.type == 0x6)
    102                 return true;
    103        
    104         return false;
    105 }
    106 
    107 /** Decides whether the instruction is swap or not.
    108  *
    109  * @param instr Instruction
    110  *
    111  * @return true when instruction is swap, false otherwise
    112  */
    113 static inline bool is_swap_instruction(instruction_t instr)
    114 {
    115         /* swap, swapb instruction */
    116         if ((instr.type == 0x0) &&
    117             ((instr.opcode == 0x8) || (instr.opcode == 0xa)) &&
    118             (instr.access == 0x0) && (instr.bits567 == 0x4) && (instr.bit4 == 1))
    119                 return true;
    120        
    121         return false;
    122 }
    123 
    12479/** Decides whether read or write into memory is requested.
    12580 *
     
    12883 *
    12984 * @return Type of access into memory, PF_ACCESS_EXEC if no memory access is
    130  *         requested.
     85 *         requested.
    13186 */
    13287static pf_access_t get_memory_access_type(uint32_t instr_addr,
     
    146101        }
    147102
    148         /* load store instructions */
    149         if (is_load_store_instruction(instr)) {
    150                 if (instr.access == 1) {
    151                         return PF_ACCESS_READ;
    152                 } else {
    153                         return PF_ACCESS_WRITE;
     103        /* See ARM Architecture reference manual ARMv7-A and ARMV7-R edition
     104         * A5.3 (PDF p. 206) */
     105        static const struct {
     106                uint32_t mask;
     107                uint32_t value;
     108                pf_access_t access;
     109        } ls_inst[] = {
     110                /* Store word/byte */
     111                { 0x0e100000, 0x04000000, PF_ACCESS_WRITE }, /*STR(B) imm*/
     112                { 0x0e100010, 0x06000000, PF_ACCESS_WRITE }, /*STR(B) reg*/
     113                /* Load word/byte */
     114                { 0x0e100000, 0x04100000, PF_ACCESS_READ }, /*LDR(B) imm*/
     115                { 0x0e100010, 0x06100000, PF_ACCESS_READ }, /*LDR(B) reg*/
     116                /* Store half-word/dual  A5.2.8 */
     117                { 0x0e1000b0, 0x000000b0, PF_ACCESS_WRITE }, /*STRH imm reg*/
     118                /* Load half-word/dual A5.2.8 */
     119                { 0x0e0000f0, 0x000000d0, PF_ACCESS_READ }, /*LDRH imm reg*/
     120                { 0x0e1000b0, 0x001000b0, PF_ACCESS_READ }, /*LDRH imm reg*/
     121                /* Block data transfer, Store */
     122                { 0x0e100000, 0x08000000, PF_ACCESS_WRITE }, /* STM variants */
     123                { 0x0e100000, 0x08100000, PF_ACCESS_READ },  /* LDM variants */
     124                /* Swap */
     125                { 0x0fb00000, 0x01000000, PF_ACCESS_WRITE },
     126        };
     127        const uint32_t inst = *(uint32_t*)instr_addr;
     128        for (unsigned i = 0; i < sizeof(ls_inst) / sizeof(ls_inst[0]); ++i) {
     129                if ((inst & ls_inst[i].mask) == ls_inst[i].value) {
     130                        return ls_inst[i].access;
    154131                }
    155         }
    156 
    157         /* swap, swpb instruction */
    158         if (is_swap_instruction(instr)) {
    159                 return PF_ACCESS_WRITE;
    160132        }
    161133
    162134        panic("page_fault - instruction doesn't access memory "
    163135            "(instr_code: %#0" PRIx32 ", badvaddr:%p).",
    164             instr_union.pc, (void *) badvaddr);
    165 
    166         return PF_ACCESS_EXEC;
     136            inst, (void *) badvaddr);
    167137}
    168138
  • kernel/genarch/Makefile.inc

    rfc89e32 r33c2952  
    9191endif
    9292
     93ifeq ($(CONFIG_ARM926_UART),y)
     94        GENARCH_SOURCES += \
     95                genarch/src/drivers/arm926_uart/arm926_uart.c
     96endif
     97
    9398ifeq ($(CONFIG_S3C24XX_IRQC),y)
    9499        GENARCH_SOURCES += \
  • kernel/genarch/include/multiboot/multiboot.h

    rfc89e32 r33c2952  
    9999
    100100extern void multiboot_extract_command(char *, size_t, const char *);
     101extern void multiboot_extract_argument(char *, size_t, const char *);
    101102extern void multiboot_info_parse(uint32_t, const multiboot_info_t *);
    102103
  • kernel/genarch/src/multiboot/multiboot.c

    rfc89e32 r33c2952  
    7171}
    7272
     73/** Extract arguments from the multiboot module command line.
     74 *
     75 * @param buf      Destination buffer (will be always NULL-terminated).
     76 * @param size     Size of destination buffer (in bytes).
     77 * @param cmd_line Input string (the command line).
     78 *
     79 */
     80void multiboot_extract_argument(char *buf, size_t size, const char *cmd_line)
     81{
     82        /* Start after first space. */
     83        const char *start = str_chr(cmd_line, ' ');
     84        if (start == NULL) {
     85                str_cpy(buf, size, "");
     86                return;
     87        }
     88
     89        const char *end = cmd_line + str_size(cmd_line);
     90
     91        /* Skip the space(s). */
     92        while (start != end) {
     93                if (start[0] == ' ')
     94                        start++;
     95                else
     96                        break;
     97        }
     98
     99        str_ncpy(buf, size, start, (size_t) (end - start));
     100}
     101
    73102static void multiboot_modules(uint32_t count, multiboot_module_t *mods)
    74103{
     
    84113                        multiboot_extract_command(init.tasks[init.cnt].name,
    85114                            CONFIG_TASK_NAME_BUFLEN, MULTIBOOT_PTR(mods[i].string));
    86                 } else
     115                        multiboot_extract_argument(init.tasks[init.cnt].arguments,
     116                            CONFIG_TASK_ARGUMENTS_BUFLEN, MULTIBOOT_PTR(mods[i].string));
     117                } else {
    87118                        init.tasks[init.cnt].name[0] = 0;
     119                        init.tasks[init.cnt].arguments[0] = 0;
     120                }
    88121               
    89122                init.cnt++;
  • kernel/genarch/src/multiboot/multiboot2.c

    rfc89e32 r33c2952  
    4949                multiboot_extract_command(init.tasks[init.cnt].name,
    5050                    CONFIG_TASK_NAME_BUFLEN, module->string);
     51                multiboot_extract_argument(init.tasks[init.cnt].arguments,
     52                    CONFIG_TASK_ARGUMENTS_BUFLEN, module->string);
    5153               
    5254                init.cnt++;
  • kernel/generic/include/config.h

    rfc89e32 r33c2952  
    4747#define CONFIG_INIT_TASKS        32
    4848#define CONFIG_TASK_NAME_BUFLEN  32
     49#define CONFIG_TASK_ARGUMENTS_BUFLEN 64
     50
     51/**
     52 * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ
     53 * requests.
     54 */
     55#define DATA_XFER_LIMIT  (64 * 1024)
    4956
    5057#ifndef __ASM__
     
    5663        size_t size;
    5764        char name[CONFIG_TASK_NAME_BUFLEN];
     65        char arguments[CONFIG_TASK_ARGUMENTS_BUFLEN];
    5866} init_task_t;
    5967
  • kernel/generic/include/interrupt.h

    rfc89e32 r33c2952  
    5959extern exc_table_t exc_table[];
    6060
    61 extern void fault_from_uspace(istate_t *, const char *, ...);
     61extern void fault_from_uspace(istate_t *, const char *, ...)
     62    PRINTF_ATTRIBUTE(2, 3);
    6263extern void fault_if_from_uspace(istate_t *, const char *, ...)
    6364    PRINTF_ATTRIBUTE(2, 3);
  • kernel/generic/include/ipc/ipc.h

    rfc89e32 r33c2952  
    6565        mutex_t lock;
    6666        link_t link;
     67        struct task *caller;
    6768        struct answerbox *callee;
    6869        ipc_phone_state_t state;
     
    7273typedef struct answerbox {
    7374        IRQ_SPINLOCK_DECLARE(lock);
     75
     76        /** Answerbox is active until it enters cleanup. */
     77        bool active;
    7478       
    7579        struct task *task;
     
    106110
    107111typedef struct {
    108         link_t link;
     112        /**
     113         * Task link.
     114         * Valid only when the call is not forgotten.
     115         * Protected by the task's active_calls_lock.
     116         */
     117        link_t ta_link;
     118
     119        atomic_t refcnt;
     120
     121        /** Answerbox link. */
     122        link_t ab_link;
    109123       
    110124        unsigned int flags;
     125
     126        /** Protects the forget member. */
     127        SPINLOCK_DECLARE(forget_lock);
     128
     129        /**
     130         * True if the caller 'forgot' this call and donated it to the callee.
     131         * Forgotten calls are discarded upon answering (the answer is not
     132         * delivered) and answered calls cannot be forgotten. Forgotten calls
     133         * also do not figure on the task's active call list.
     134         *
     135         * We keep this separate from the flags so that it is not necessary
     136         * to take a lock when accessing them.
     137         */
     138        bool forget;
     139
     140        /** True if the call is in the active list. */
     141        bool active;
    111142       
    112         /** Identification of the caller. */
     143        /**
     144         * Identification of the caller.
     145         * Valid only when the call is not forgotten.
     146         */
    113147        struct task *sender;
     148       
     149        /** Phone which was used to send the call. */
     150        phone_t *caller_phone;
    114151       
    115152        /** Private data to internal IPC. */
     
    118155        /** Data passed from/to userspace. */
    119156        ipc_data_t data;
    120        
     157
     158        /** Method as it was sent in the request. */
     159        sysarg_t request_method;
     160
    121161        /** Buffer for IPC_M_DATA_WRITE and IPC_M_DATA_READ. */
    122162        uint8_t *buffer;
    123        
    124         /*
    125          * The forward operation can masquerade the caller phone. For those
    126          * cases, we must keep it aside so that the answer is processed
    127          * correctly.
    128          */
    129         phone_t *caller_phone;
    130163} call_t;
    131164
     
    136169extern call_t *ipc_call_alloc(unsigned int);
    137170extern void ipc_call_free(call_t *);
     171extern void ipc_call_hold(call_t *);
     172extern void ipc_call_release(call_t *);
    138173
    139174extern int ipc_call(phone_t *, call_t *);
     
    141176extern int ipc_forward(call_t *, phone_t *, answerbox_t *, unsigned int);
    142177extern void ipc_answer(answerbox_t *, call_t *);
     178extern void _ipc_answer_free_call(call_t *, bool);
    143179
    144 extern void ipc_phone_init(phone_t *);
    145 extern void ipc_phone_connect(phone_t *, answerbox_t *);
     180extern void ipc_phone_init(phone_t *, struct task *);
     181extern bool ipc_phone_connect(phone_t *, answerbox_t *);
    146182extern int ipc_phone_hangup(phone_t *);
    147183
     
    151187extern void ipc_backsend_err(phone_t *, call_t *, sysarg_t);
    152188extern void ipc_answerbox_slam_phones(answerbox_t *, bool);
    153 extern void ipc_cleanup_call_list(list_t *);
     189extern void ipc_cleanup_call_list(answerbox_t *, list_t *);
    154190
    155191extern void ipc_print_task(task_id_t);
  • kernel/generic/include/ipc/ipcrsc.h

    rfc89e32 r33c2952  
    4040
    4141extern call_t *get_call(sysarg_t);
     42extern int phone_get(sysarg_t, phone_t **);
    4243extern int phone_alloc(task_t *);
    43 extern void phone_connect(int, answerbox_t *);
     44extern bool phone_connect(int, answerbox_t *);
    4445extern void phone_dealloc(int);
    4546
  • kernel/generic/include/lib/elf_load.h

    rfc89e32 r33c2952  
    4242 * ELF error return codes
    4343 */
    44 #define EE_OK                   0       /* No error */
    45 #define EE_INVALID              1       /* Invalid ELF image */
    46 #define EE_MEMORY               2       /* Cannot allocate address space */
    47 #define EE_INCOMPATIBLE         3       /* ELF image is not compatible with current architecture */
    48 #define EE_UNSUPPORTED          4       /* Non-supported ELF (e.g. dynamic ELFs) */
    49 #define EE_LOADER               5       /* The image is actually a program loader. */
    50 #define EE_IRRECOVERABLE        6
     44#define EE_OK             0  /* No error */
     45#define EE_INVALID        1  /* Invalid ELF image */
     46#define EE_MEMORY         2  /* Cannot allocate address space */
     47#define EE_INCOMPATIBLE   3  /* ELF image is not compatible with current architecture */
     48#define EE_UNSUPPORTED    4  /* Non-supported ELF (e.g. dynamic ELFs) */
     49#define EE_LOADER         5  /* The image is actually a program loader. */
     50#define EE_IRRECOVERABLE  6  /* Irrecoverable error. */
    5151
    5252/**
    5353 * This flags is passed when running the loader, otherwise elf_load()
    5454 * would return with a EE_LOADER error code.
    55  *
    5655 */
    5756#define ELD_F_NONE    0
  • kernel/generic/include/macros.h

    rfc89e32 r33c2952  
    5252    uint64_t sz2)
    5353{
    54         uint64_t e1 = s1 + sz1;
    55         uint64_t e2 = s2 + sz2;
    56        
    57         return ((s1 < e2) && (s2 < e1));
     54        uint64_t e1 = s1 + sz1 - 1;
     55        uint64_t e2 = s2 + sz2 - 1;
     56
     57        /* both sizes are non-zero */
     58        if (sz1 && sz2)
     59                return ((s1 <= e2) && (s2 <= e1));
     60
     61        /* one size is non-zero */
     62        if (sz2)
     63                return ((s1 >= s2) && (s1 <= e2));
     64        if (sz1)
     65                return ((s2 >= s1) && (s2 <= e1));
     66
     67        /* both are zero */
     68        return (s1 == s2);
    5869}
    5970
     
    119130            | ((((uint64_t) (up)) & UINT32_C(0xffffffff)) << 32))
    120131
     132/* Test for sum overflow. */
     133#define overflows(a, b) \
     134        ((a) + (b) < (a))
     135
     136/* Test for sum overflow into positive numbers. */
     137#define overflows_into_positive(a, b)   \
     138        (overflows((a), (b)) && ((a) + (b) > 0))
     139
    121140/** Pseudorandom generator
    122141 *
  • kernel/generic/include/print.h

    rfc89e32 r33c2952  
    3838#include <typedefs.h>
    3939#include <stdarg.h>
    40 
    41 #ifndef NVERIFY_PRINTF
    42 
    43 #define PRINTF_ATTRIBUTE(start, end) \
    44         __attribute__((format(gnu_printf, start, end)))
    45 
    46 #else /* NVERIFY_PRINTF */
    47 
    48 #define PRINTF_ATTRIBUTE(start, end)
    49 
    50 #endif /* NVERIFY_PRINTF */
     40#include <printf/verify.h>
    5141
    5242#define EOF  (-1)
  • kernel/generic/include/proc/task.h

    rfc89e32 r33c2952  
    9595       
    9696        /* IPC stuff */
    97         answerbox_t answerbox;  /**< Communication endpoint */
     97
     98        /** Receiving communication endpoint */
     99        answerbox_t answerbox;
     100
     101        /** Sending communication endpoints */
    98102        phone_t phones[IPC_MAX_PHONES];
    99         stats_ipc_t ipc_info;   /**< IPC statistics */
     103
     104        /** Spinlock protecting the active_calls list. */
     105        SPINLOCK_DECLARE(active_calls_lock);
     106
     107        /**
     108         * List of all calls sent by this task that have not yet been
     109         * answered.
     110         */
     111        list_t active_calls;
     112
    100113        event_t events[EVENT_TASK_END - EVENT_END];
     114
     115        /** IPC statistics */
     116        stats_ipc_t ipc_info;
    101117       
    102118#ifdef CONFIG_UDEBUG
  • kernel/generic/src/ipc/event.c

    rfc89e32 r33c2952  
    163163                                call->data.task_id = TASK ? TASK->taskid : 0;
    164164                               
    165                                 irq_spinlock_lock(&event->answerbox->irq_lock, true);
    166                                 list_append(&call->link, &event->answerbox->irq_notifs);
    167                                 irq_spinlock_unlock(&event->answerbox->irq_lock, true);
    168                                
    169                                 waitq_wakeup(&event->answerbox->wq, WAKEUP_FIRST);
     165                                irq_spinlock_lock(&event->answerbox->irq_lock,
     166                                    true);
     167                                list_append(&call->ab_link,
     168                                    &event->answerbox->irq_notifs);
     169                                irq_spinlock_unlock(&event->answerbox->irq_lock,
     170                                    true);
     171                               
     172                                waitq_wakeup(&event->answerbox->wq,
     173                                    WAKEUP_FIRST);
    170174                               
    171175                                if (mask)
  • kernel/generic/src/ipc/ipc.c

    rfc89e32 r33c2952  
    4545#include <ipc/kbox.h>
    4646#include <ipc/event.h>
     47#include <ipc/sysipc_ops.h>
     48#include <ipc/sysipc_priv.h>
    4749#include <errno.h>
    4850#include <mm/slab.h>
     
    7173{
    7274        memsetb(call, sizeof(*call), 0);
    73         call->sender = TASK;
     75        spinlock_initialize(&call->forget_lock, "forget_lock");
     76        call->active = false;
     77        call->forget = false;
     78        call->sender = NULL;
    7479        call->buffer = NULL;
     80}
     81
     82void ipc_call_hold(call_t *call)
     83{
     84        atomic_inc(&call->refcnt);
     85}
     86
     87void ipc_call_release(call_t *call)
     88{
     89        if (atomic_predec(&call->refcnt) == 0) {
     90                if (call->buffer)
     91                        free(call->buffer);
     92                slab_free(ipc_call_slab, call);
     93        }
    7594}
    7695
     
    83102 *
    84103 * @return If flags permit it, return NULL, or initialized kernel
    85  *         call structure.
     104 *         call structure with one reference.
    86105 *
    87106 */
     
    89108{
    90109        call_t *call = slab_alloc(ipc_call_slab, flags);
    91         if (call)
     110        if (call) {
    92111                _ipc_call_init(call);
     112                ipc_call_hold(call);
     113        }
    93114       
    94115        return call;
     
    102123void ipc_call_free(call_t *call)
    103124{
    104         /* Check to see if we have data in the IPC_M_DATA_SEND buffer. */
    105         if (call->buffer)
    106                 free(call->buffer);
    107         slab_free(ipc_call_slab, call);
     125        ipc_call_release(call);
    108126}
    109127
     
    132150 * @param phone Initialized phone structure.
    133151 * @param box   Initialized answerbox structure.
    134  *
    135  */
    136 void ipc_phone_connect(phone_t *phone, answerbox_t *box)
    137 {
     152 * @return      True if the phone was connected, false otherwise.
     153 */
     154bool ipc_phone_connect(phone_t *phone, answerbox_t *box)
     155{
     156        bool active;
     157
    138158        mutex_lock(&phone->lock);
    139        
    140         phone->state = IPC_PHONE_CONNECTED;
    141         phone->callee = box;
    142        
    143159        irq_spinlock_lock(&box->lock, true);
    144         list_append(&phone->link, &box->connected_phones);
     160
     161        active = box->active;
     162        if (active) {
     163                phone->state = IPC_PHONE_CONNECTED;
     164                phone->callee = box;
     165                list_append(&phone->link, &box->connected_phones);
     166        }
     167
    145168        irq_spinlock_unlock(&box->lock, true);
    146        
    147169        mutex_unlock(&phone->lock);
     170
     171        return active;
    148172}
    149173
     
    151175 *
    152176 * @param phone Phone structure to be initialized.
    153  *
    154  */
    155 void ipc_phone_init(phone_t *phone)
     177 * @param caller Owning task.
     178 *
     179 */
     180void ipc_phone_init(phone_t *phone, task_t *caller)
    156181{
    157182        mutex_initialize(&phone->lock, MUTEX_PASSIVE);
     183        phone->caller = caller;
    158184        phone->callee = NULL;
    159185        phone->state = IPC_PHONE_FREE;
     
    167193 *
    168194 */
    169 static void _ipc_answer_free_call(call_t *call, bool selflocked)
    170 {
    171         answerbox_t *callerbox = &call->sender->answerbox;
    172         bool do_lock = ((!selflocked) || callerbox != (&TASK->answerbox));
    173        
     195void _ipc_answer_free_call(call_t *call, bool selflocked)
     196{
    174197        /* Count sent answer */
    175198        irq_spinlock_lock(&TASK->lock, true);
    176199        TASK->ipc_info.answer_sent++;
    177200        irq_spinlock_unlock(&TASK->lock, true);
     201
     202        spinlock_lock(&call->forget_lock);
     203        if (call->forget) {
     204                /* This is a forgotten call and call->sender is not valid. */
     205                spinlock_unlock(&call->forget_lock);
     206                ipc_call_free(call);
     207                return;
     208        } else {
     209                /*
     210                 * If the call is still active, i.e. it was answered
     211                 * in a non-standard way, remove the call from the
     212                 * sender's active call list.
     213                 */
     214                if (call->active) {
     215                        spinlock_lock(&call->sender->active_calls_lock);
     216                        list_remove(&call->ta_link);
     217                        spinlock_unlock(&call->sender->active_calls_lock);
     218                }
     219        }
     220        spinlock_unlock(&call->forget_lock);
     221
     222        answerbox_t *callerbox = &call->sender->answerbox;
     223        bool do_lock = ((!selflocked) || (callerbox != &TASK->answerbox));
    178224       
    179225        call->flags |= IPC_CALL_ANSWERED;
    180226       
    181         if (call->flags & IPC_CALL_FORWARDED) {
    182                 if (call->caller_phone) {
    183                         /* Demasquerade the caller phone. */
    184                         call->data.phone = call->caller_phone;
    185                 }
    186         }
    187 
    188227        call->data.task_id = TASK->taskid;
    189228       
     
    191230                irq_spinlock_lock(&callerbox->lock, true);
    192231       
    193         list_append(&call->link, &callerbox->answers);
     232        list_append(&call->ab_link, &callerbox->answers);
    194233       
    195234        if (do_lock)
     
    209248        /* Remove from active box */
    210249        irq_spinlock_lock(&box->lock, true);
    211         list_remove(&call->link);
     250        list_remove(&call->ab_link);
    212251        irq_spinlock_unlock(&box->lock, true);
    213252       
    214253        /* Send back answer */
    215254        _ipc_answer_free_call(call, false);
     255}
     256
     257static void _ipc_call_actions_internal(phone_t *phone, call_t *call)
     258{
     259        task_t *caller = phone->caller;
     260
     261        atomic_inc(&phone->active_calls);
     262        call->caller_phone = phone;
     263        call->sender = caller;
     264
     265        call->active = true;
     266        spinlock_lock(&caller->active_calls_lock);
     267        list_append(&call->ta_link, &caller->active_calls);
     268        spinlock_unlock(&caller->active_calls_lock);
     269
     270        call->data.phone = phone;
     271        call->data.task_id = caller->taskid;
    216272}
    217273
     
    228284void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
    229285{
    230         call->data.phone = phone;
    231         atomic_inc(&phone->active_calls);
     286        _ipc_call_actions_internal(phone, call);
    232287        IPC_SET_RETVAL(call->data, err);
    233288        _ipc_answer_free_call(call, false);
     
    243298static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
    244299{
     300        task_t *caller = phone->caller;
     301
    245302        /* Count sent ipc call */
    246         irq_spinlock_lock(&TASK->lock, true);
    247         TASK->ipc_info.call_sent++;
    248         irq_spinlock_unlock(&TASK->lock, true);
    249        
    250         if (!(call->flags & IPC_CALL_FORWARDED)) {
    251                 atomic_inc(&phone->active_calls);
    252                 call->data.phone = phone;
    253                 call->data.task_id = TASK->taskid;
    254         }
     303        irq_spinlock_lock(&caller->lock, true);
     304        caller->ipc_info.call_sent++;
     305        irq_spinlock_unlock(&caller->lock, true);
     306       
     307        if (!(call->flags & IPC_CALL_FORWARDED))
     308                _ipc_call_actions_internal(phone, call);
    255309       
    256310        irq_spinlock_lock(&box->lock, true);
    257         list_append(&call->link, &box->calls);
     311        list_append(&call->ab_link, &box->calls);
    258312        irq_spinlock_unlock(&box->lock, true);
    259313       
     
    275329        if (phone->state != IPC_PHONE_CONNECTED) {
    276330                mutex_unlock(&phone->lock);
    277                 if (call->flags & IPC_CALL_FORWARDED) {
    278                         IPC_SET_RETVAL(call->data, EFORWARD);
    279                         _ipc_answer_free_call(call, false);
    280                 } else {
     331                if (!(call->flags & IPC_CALL_FORWARDED)) {
    281332                        if (phone->state == IPC_PHONE_HUNGUP)
    282333                                ipc_backsend_err(phone, call, EHANGUP);
     
    325376                call_t *call = ipc_call_alloc(0);
    326377                IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
     378                call->request_method = IPC_M_PHONE_HUNGUP;
    327379                call->flags |= IPC_CALL_DISCARD_ANSWER;
    328380                _ipc_call(phone, box, call);
     
    356408        TASK->ipc_info.forwarded++;
    357409        irq_spinlock_pass(&TASK->lock, &oldbox->lock);
    358         list_remove(&call->link);
     410        list_remove(&call->ab_link);
    359411        irq_spinlock_unlock(&oldbox->lock, true);
    360412       
    361413        if (mode & IPC_FF_ROUTE_FROM_ME) {
    362                 if (!call->caller_phone)
    363                         call->caller_phone = call->data.phone;
    364414                call->data.phone = newphone;
    365415                call->data.task_id = TASK->taskid;
     
    406456               
    407457                request = list_get_instance(list_first(&box->irq_notifs),
    408                     call_t, link);
    409                 list_remove(&request->link);
     458                    call_t, ab_link);
     459                list_remove(&request->ab_link);
    410460               
    411461                irq_spinlock_unlock(&box->irq_lock, false);
     
    416466                /* Handle asynchronous answers */
    417467                request = list_get_instance(list_first(&box->answers),
    418                     call_t, link);
    419                 list_remove(&request->link);
    420                 atomic_dec(&request->data.phone->active_calls);
     468                    call_t, ab_link);
     469                list_remove(&request->ab_link);
     470                atomic_dec(&request->caller_phone->active_calls);
    421471        } else if (!list_empty(&box->calls)) {
    422472                /* Count received call */
     
    425475                /* Handle requests */
    426476                request = list_get_instance(list_first(&box->calls),
    427                     call_t, link);
    428                 list_remove(&request->link);
     477                    call_t, ab_link);
     478                list_remove(&request->ab_link);
    429479               
    430480                /* Append request to dispatch queue */
    431                 list_append(&request->link, &box->dispatched_calls);
     481                list_append(&request->ab_link, &box->dispatched_calls);
    432482        } else {
    433483                /* This can happen regularly after ipc_cleanup */
     
    449499/** Answer all calls from list with EHANGUP answer.
    450500 *
     501 * @param box Answerbox with the list.
    451502 * @param lst Head of the list to be cleaned up.
    452  *
    453  */
    454 void ipc_cleanup_call_list(list_t *lst)
    455 {
     503 */
     504void ipc_cleanup_call_list(answerbox_t *box, list_t *lst)
     505{
     506        irq_spinlock_lock(&box->lock, true);
    456507        while (!list_empty(lst)) {
    457                 call_t *call = list_get_instance(list_first(lst), call_t, link);
    458                 if (call->buffer)
    459                         free(call->buffer);
    460                
    461                 list_remove(&call->link);
    462                
     508                call_t *call = list_get_instance(list_first(lst), call_t,
     509                    ab_link);
     510               
     511                list_remove(&call->ab_link);
     512
     513                irq_spinlock_unlock(&box->lock, true);
     514
     515                if (lst == &box->calls)
     516                        SYSIPC_OP(request_process, call, box);
     517
     518                ipc_data_t old = call->data;
    463519                IPC_SET_RETVAL(call->data, EHANGUP);
     520                answer_preprocess(call, &old);
    464521                _ipc_answer_free_call(call, true);
    465         }
     522
     523                irq_spinlock_lock(&box->lock, true);
     524        }
     525        irq_spinlock_unlock(&box->lock, true);
    466526}
    467527
     
    501561                        mutex_unlock(&phone->lock);
    502562                        irq_spinlock_unlock(&box->lock, true);
    503                        
     563
     564                        // FIXME: phone can become deallocated at any time now
     565
    504566                        /*
    505567                         * Send one message to the answerbox for each
     
    509571                         */
    510572                        IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
     573                        call->request_method = IPC_M_PHONE_HUNGUP;
    511574                        call->flags |= IPC_CALL_DISCARD_ANSWER;
    512575                        _ipc_call(phone, box, call);
     
    529592}
    530593
     594static void ipc_forget_all_active_calls(void)
     595{
     596        call_t *call;
     597
     598restart:
     599        spinlock_lock(&TASK->active_calls_lock);
     600        if (list_empty(&TASK->active_calls)) {
     601                /*
     602                 * We are done, there are no more active calls.
     603                 * Nota bene: there may still be answers waiting for pick up.
     604                 */
     605                spinlock_unlock(&TASK->active_calls_lock);     
     606                return;
     607        }
     608       
     609        call = list_get_instance(list_first(&TASK->active_calls), call_t,
     610            ta_link);
     611
     612        if (!spinlock_trylock(&call->forget_lock)) {
     613                /*
     614                 * Avoid deadlock and let async_answer() or
     615                 *  _ipc_answer_free_call() win the race to dequeue the first
     616                 * call on the list.
     617                 */
     618                spinlock_unlock(&TASK->active_calls_lock);     
     619                goto restart;
     620        }
     621
     622        /*
     623         * Forget the call and donate it to the task which holds up the answer.
     624         */
     625
     626        call->forget = true;
     627        call->sender = NULL;
     628        list_remove(&call->ta_link);
     629
     630        /*
     631         * The call may be freed by _ipc_answer_free_call() before we are done
     632         * with it; to avoid working with a destroyed call_t structure, we
     633         * must hold a reference to it.
     634         */
     635        ipc_call_hold(call);
     636
     637        spinlock_unlock(&call->forget_lock);
     638        spinlock_unlock(&TASK->active_calls_lock);
     639
     640        atomic_dec(&call->caller_phone->active_calls);
     641
     642        SYSIPC_OP(request_forget, call);
     643
     644        ipc_call_release(call);
     645
     646        goto restart;
     647}
     648
     649/** Wait for all answers to asynchronous calls to arrive. */
     650static void ipc_wait_for_all_answered_calls(void)
     651{
     652        call_t *call;
     653        size_t i;
     654
     655restart:
     656        /*
     657         * Go through all phones, until they are all free.
     658         * Locking is needed as there may be connection handshakes in progress.
     659         */
     660        for (i = 0; i < IPC_MAX_PHONES; i++) {
     661                phone_t *phone = &TASK->phones[i];
     662
     663                mutex_lock(&phone->lock);       
     664                if ((phone->state == IPC_PHONE_HUNGUP) &&
     665                    (atomic_get(&phone->active_calls) == 0)) {
     666                        phone->state = IPC_PHONE_FREE;
     667                        phone->callee = NULL;
     668                }
     669
     670                /*
     671                 * We might have had some IPC_PHONE_CONNECTING phones at the
     672                 * beginning of ipc_cleanup(). Depending on whether these were
     673                 * forgotten or answered, they will eventually enter the
     674                 * IPC_PHONE_FREE or IPC_PHONE_CONNECTED states, respectively.
     675                 * In the latter case, the other side may slam the open phones
     676                 * at any time, in which case we will get an IPC_PHONE_SLAMMED
     677                 * phone.
     678                 */
     679                if ((phone->state == IPC_PHONE_CONNECTED) ||
     680                    (phone->state == IPC_PHONE_SLAMMED)) {
     681                        mutex_unlock(&phone->lock);
     682                        ipc_phone_hangup(phone);
     683                        /*
     684                         * Now there may be one extra active call, which needs
     685                         * to be forgotten.
     686                         */
     687                        ipc_forget_all_active_calls();
     688                        goto restart;
     689                }
     690
     691                /*
     692                 * If the hangup succeeded, it has sent a HANGUP message, the
     693                 * IPC is now in HUNGUP state, we wait for the reply to come
     694                 */
     695                if (phone->state != IPC_PHONE_FREE) {
     696                        mutex_unlock(&phone->lock);
     697                        break;
     698                }
     699
     700                mutex_unlock(&phone->lock);
     701        }
     702               
     703        /* Got into cleanup */
     704        if (i == IPC_MAX_PHONES)
     705                return;
     706               
     707        call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
     708            SYNCH_FLAGS_NONE);
     709        ASSERT(call->flags & (IPC_CALL_ANSWERED | IPC_CALL_NOTIF));
     710
     711        SYSIPC_OP(answer_process, call);
     712
     713        ipc_call_free(call);
     714        goto restart;
     715}
     716
    531717/** Clean up all IPC communication of the current task.
    532718 *
     
    537723void ipc_cleanup(void)
    538724{
     725        /*
     726         * Mark the answerbox as inactive.
     727         *
     728         * The main purpose for doing this is to prevent any pending callback
     729         * connections from getting established beyond this point.
     730         */
     731        irq_spinlock_lock(&TASK->answerbox.lock, true);
     732        TASK->answerbox.active = false;
     733        irq_spinlock_unlock(&TASK->answerbox.lock, true);
     734
    539735        /* Disconnect all our phones ('ipc_phone_hangup') */
    540         size_t i;
    541         for (i = 0; i < IPC_MAX_PHONES; i++)
     736        for (size_t i = 0; i < IPC_MAX_PHONES; i++)
    542737                ipc_phone_hangup(&TASK->phones[i]);
    543738       
     
    557752       
    558753        /* Answer all messages in 'calls' and 'dispatched_calls' queues */
    559         irq_spinlock_lock(&TASK->answerbox.lock, true);
    560         ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
    561         ipc_cleanup_call_list(&TASK->answerbox.calls);
    562         irq_spinlock_unlock(&TASK->answerbox.lock, true);
    563        
    564         /* Wait for all answers to asynchronous calls to arrive */
    565         while (true) {
    566                 /*
    567                  * Go through all phones, until they are all FREE
    568                  * Locking is not needed, no one else should modify
    569                  * it when we are in cleanup
    570                  */
    571                 for (i = 0; i < IPC_MAX_PHONES; i++) {
    572                         if (TASK->phones[i].state == IPC_PHONE_HUNGUP &&
    573                             atomic_get(&TASK->phones[i].active_calls) == 0) {
    574                                 TASK->phones[i].state = IPC_PHONE_FREE;
    575                                 TASK->phones[i].callee = NULL;
    576                         }
    577                        
    578                         /*
    579                          * Just for sure, we might have had some
    580                          * IPC_PHONE_CONNECTING phones
    581                          */
    582                         if (TASK->phones[i].state == IPC_PHONE_CONNECTED)
    583                                 ipc_phone_hangup(&TASK->phones[i]);
    584                        
    585                         /*
    586                          * If the hangup succeeded, it has sent a HANGUP
    587                          * message, the IPC is now in HUNGUP state, we
    588                          * wait for the reply to come
    589                          */
    590                        
    591                         if (TASK->phones[i].state != IPC_PHONE_FREE)
    592                                 break;
    593                 }
    594                
    595                 /* Got into cleanup */
    596                 if (i == IPC_MAX_PHONES)
    597                         break;
    598                
    599                 call_t *call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
    600                     SYNCH_FLAGS_NONE);
    601                 ASSERT((call->flags & IPC_CALL_ANSWERED) ||
    602                     (call->flags & IPC_CALL_NOTIF));
    603                
    604                 ipc_call_free(call);
    605         }
     754        ipc_cleanup_call_list(&TASK->answerbox, &TASK->answerbox.calls);
     755        ipc_cleanup_call_list(&TASK->answerbox,
     756            &TASK->answerbox.dispatched_calls);
     757
     758        ipc_forget_all_active_calls();
     759        ipc_wait_for_all_answered_calls();
    606760}
    607761
     
    615769        ipc_answerbox_slab = slab_cache_create("answerbox_t",
    616770            sizeof(answerbox_t), 0, NULL, NULL, 0);
     771}
     772
     773
     774static void ipc_print_call_list(list_t *list)
     775{
     776        list_foreach(*list, cur) {
     777                call_t *call = list_get_instance(cur, call_t, ab_link);
     778               
     779#ifdef __32_BITS__
     780                printf("%10p ", call);
     781#endif
     782               
     783#ifdef __64_BITS__
     784                printf("%18p ", call);
     785#endif
     786               
     787                spinlock_lock(&call->forget_lock);
     788
     789                printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
     790                    " %-6" PRIun " %-6" PRIun " %-7x",
     791                    IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
     792                    IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
     793                    IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
     794                    call->flags);
     795
     796                if (call->forget) {
     797                        printf(" ? (call forgotten)\n");
     798                } else {
     799                        printf(" %" PRIu64 " (%s)\n",
     800                            call->sender->taskid, call->sender->name);
     801                }
     802
     803                spinlock_unlock(&call->forget_lock);
     804        }
    617805}
    618806
     
    688876       
    689877        printf(" --- incomming calls ---\n");
    690         list_foreach(task->answerbox.calls, cur) {
    691                 call_t *call = list_get_instance(cur, call_t, link);
    692                
    693 #ifdef __32_BITS__
    694                 printf("%10p ", call);
    695 #endif
    696                
    697 #ifdef __64_BITS__
    698                 printf("%18p ", call);
    699 #endif
    700                
    701                 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
    702                     " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
    703                     IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
    704                     IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    705                     IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
    706                     call->flags, call->sender->taskid, call->sender->name);
    707         }
    708        
     878        ipc_print_call_list(&task->answerbox.calls);
    709879        printf(" --- dispatched calls ---\n");
    710         list_foreach(task->answerbox.dispatched_calls, cur) {
    711                 call_t *call = list_get_instance(cur, call_t, link);
    712                
    713 #ifdef __32_BITS__
    714                 printf("%10p ", call);
    715 #endif
    716                
    717 #ifdef __64_BITS__
    718                 printf("%18p ", call);
    719 #endif
    720                
    721                 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
    722                     " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
    723                     IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
    724                     IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    725                     IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
    726                     call->flags, call->sender->taskid, call->sender->name);
    727         }
    728        
     880        ipc_print_call_list(&task->answerbox.dispatched_calls);
    729881        printf(" --- incoming answers ---\n");
    730         list_foreach(task->answerbox.answers, cur) {
    731                 call_t *call = list_get_instance(cur, call_t, link);
    732                
    733 #ifdef __32_BITS__
    734                 printf("%10p ", call);
    735 #endif
    736                
    737 #ifdef __64_BITS__
    738                 printf("%18p ", call);
    739 #endif
    740                
    741                 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
    742                     " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
    743                     IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
    744                     IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    745                     IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
    746                     call->flags, call->sender->taskid, call->sender->name);
    747         }
     882        ipc_print_call_list(&task->answerbox.answers);
    748883       
    749884        irq_spinlock_unlock(&task->answerbox.lock, false);
  • kernel/generic/src/ipc/ipcrsc.c

    rfc89e32 r33c2952  
    132132#include <ipc/ipcrsc.h>
    133133#include <debug.h>
     134#include <abi/errno.h>
    134135
    135136/** Find call_t * in call table according to callid.
     
    151152       
    152153        list_foreach(TASK->answerbox.dispatched_calls, lst) {
    153                 call_t *call = list_get_instance(lst, call_t, link);
     154                call_t *call = list_get_instance(lst, call_t, ab_link);
    154155                if ((sysarg_t) call == callid) {
    155156                        result = call;
     
    162163}
    163164
     165/** Get phone from the current task by ID.
     166 *
     167 * @param phoneid Phone ID.
     168 * @param phone   Place to store pointer to phone.
     169 *
     170 * @return EOK on success, EINVAL if ID is invalid.
     171 *
     172 */
     173int phone_get(sysarg_t phoneid, phone_t **phone)
     174{
     175        if (phoneid >= IPC_MAX_PHONES)
     176                return EINVAL;
     177       
     178        *phone = &TASK->phones[phoneid];
     179        return EOK;
     180}
     181
    164182/** Allocate new phone slot in the specified task.
    165183 *
     
    176194        size_t i;
    177195        for (i = 0; i < IPC_MAX_PHONES; i++) {
    178                 if ((task->phones[i].state == IPC_PHONE_HUNGUP) &&
    179                     (atomic_get(&task->phones[i].active_calls) == 0))
    180                         task->phones[i].state = IPC_PHONE_FREE;
     196                phone_t *phone = &task->phones[i];
     197
     198                if ((phone->state == IPC_PHONE_HUNGUP) &&
     199                    (atomic_get(&phone->active_calls) == 0))
     200                        phone->state = IPC_PHONE_FREE;
    181201               
    182                 if (task->phones[i].state == IPC_PHONE_FREE) {
    183                         task->phones[i].state = IPC_PHONE_CONNECTING;
     202                if (phone->state == IPC_PHONE_FREE) {
     203                        phone->state = IPC_PHONE_CONNECTING;
    184204                        break;
    185205                }
     
    223243 * @param phoneid Phone handle to be connected.
    224244 * @param box     Answerbox to which to connect the phone handle.
     245 * @return        True if the phone was connected, false otherwise.
    225246 *
    226247 * The procedure _enforces_ that the user first marks the phone
     
    229250 *
    230251 */
    231 void phone_connect(int phoneid, answerbox_t *box)
     252bool phone_connect(int phoneid, answerbox_t *box)
    232253{
    233254        phone_t *phone = &TASK->phones[phoneid];
    234255       
    235256        ASSERT(phone->state == IPC_PHONE_CONNECTING);
    236         ipc_phone_connect(phone, box);
     257        return ipc_phone_connect(phone, box);
    237258}
    238259
  • kernel/generic/src/ipc/irq.c

    rfc89e32 r33c2952  
    510510{
    511511        irq_spinlock_lock(&irq->notif_cfg.answerbox->irq_lock, false);
    512         list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs);
     512        list_append(&call->ab_link, &irq->notif_cfg.answerbox->irq_notifs);
    513513        irq_spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock, false);
    514514       
  • kernel/generic/src/ipc/kbox.c

    rfc89e32 r33c2952  
    4949{
    5050        /*
     51         * Not really needed, just to be consistent with the meaning of
     52         * answerbox_t.active.
     53         */
     54        irq_spinlock_lock(&TASK->kb.box.lock, true);
     55        TASK->kb.box.active = false;
     56        irq_spinlock_unlock(&TASK->kb.box.lock, true);
     57
     58        /*
    5159         * Only hold kb.cleanup_lock while setting kb.finished -
    5260         * this is enough.
     
    8997       
    9098        /* Answer all messages in 'calls' and 'dispatched_calls' queues. */
    91         irq_spinlock_lock(&TASK->kb.box.lock, true);
    92         ipc_cleanup_call_list(&TASK->kb.box.dispatched_calls);
    93         ipc_cleanup_call_list(&TASK->kb.box.calls);
    94         irq_spinlock_unlock(&TASK->kb.box.lock, true);
     99        ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.calls);
     100        ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.dispatched_calls);
    95101}
    96102
     
    163169        while (!done) {
    164170                call_t *call = ipc_wait_for_call(&TASK->kb.box, SYNCH_NO_TIMEOUT,
    165                         SYNCH_FLAGS_NONE);
     171                    SYNCH_FLAGS_NONE);
    166172               
    167173                if (call == NULL)
     
    237243       
    238244        /* Connect the newly allocated phone to the kbox */
    239         ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
     245        (void) ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
    240246       
    241247        if (task->kb.thread != NULL) {
  • kernel/generic/src/ipc/sysipc.c

    rfc89e32 r33c2952  
    3434
    3535#include <arch.h>
    36 #include <proc/task.h>
    37 #include <proc/thread.h>
    3836#include <errno.h>
    3937#include <memstr.h>
    40 #include <debug.h>
    4138#include <ipc/ipc.h>
    4239#include <abi/ipc/methods.h>
    4340#include <ipc/sysipc.h>
     41#include <ipc/sysipc_ops.h>
     42#include <ipc/sysipc_priv.h>
    4443#include <ipc/irq.h>
    4544#include <ipc/ipcrsc.h>
     
    4746#include <ipc/kbox.h>
    4847#include <synch/waitq.h>
    49 #include <udebug/udebug_ipc.h>
    5048#include <arch/interrupt.h>
    5149#include <syscall/copy.h>
    5250#include <security/cap.h>
    5351#include <console/console.h>
    54 #include <mm/as.h>
    5552#include <print.h>
    5653#include <macros.h>
    5754
    58 /**
    59  * Maximum buffer size allowed for IPC_M_DATA_WRITE and IPC_M_DATA_READ
    60  * requests.
    61  */
    62 #define DATA_XFER_LIMIT  (64 * 1024)
    63 
    6455#define STRUCT_TO_USPACE(dst, src)  copy_to_uspace((dst), (src), sizeof(*(src)))
    65 
    66 /** Get phone from the current task by ID.
    67  *
    68  * @param phoneid Phone ID.
    69  * @param phone   Place to store pointer to phone.
    70  *
    71  * @return EOK on success, EINVAL if ID is invalid.
    72  *
    73  */
    74 static int phone_get(sysarg_t phoneid, phone_t **phone)
    75 {
    76         if (phoneid >= IPC_MAX_PHONES)
    77                 return EINVAL;
    78        
    79         *phone = &TASK->phones[phoneid];
    80         return EOK;
    81 }
    8256
    8357/** Decide if the interface and method is a system method.
     
    181155 * @param olddata Saved data of the request.
    182156 *
    183  * @return Return 0 on success or an error code.
    184  *
    185  */
    186 static inline int answer_preprocess(call_t *answer, ipc_data_t *olddata)
    187 {
     157 * @return Return EOK on success or a negative error code.
     158 *
     159 */
     160int answer_preprocess(call_t *answer, ipc_data_t *olddata)
     161{
     162        int rc = EOK;
     163
     164        spinlock_lock(&answer->forget_lock);
     165        if (answer->forget) {
     166                /*
     167                 * This is a forgotten call and answer->sender is not valid.
     168                 */
     169                spinlock_unlock(&answer->forget_lock);
     170
     171                SYSIPC_OP(answer_cleanup, answer, olddata);
     172                return rc;
     173        } else {
     174                ASSERT(answer->active);
     175
     176                /*
     177                 * Mark the call as inactive to prevent _ipc_answer_free_call()
     178                 * from attempting to remove the call from the active list
     179                 * itself.
     180                 */
     181                answer->active = false;
     182
     183                /*
     184                 * Remove the call from the sender's active call list.
     185                 * We enforce this locking order so that any potential
     186                 * concurrently executing forget operation is forced to
     187                 * release its active_calls_lock and lose the race to
     188                 * forget this soon to be answered call.
     189                 */
     190                spinlock_lock(&answer->sender->active_calls_lock);
     191                list_remove(&answer->ta_link);
     192                spinlock_unlock(&answer->sender->active_calls_lock);
     193        }
     194        spinlock_unlock(&answer->forget_lock);
     195
    188196        if ((native_t) IPC_GET_RETVAL(answer->data) == EHANGUP) {
    189                 /* In case of forward, hangup the forwared phone,
    190                  * not the originator
    191                  */
    192                 mutex_lock(&answer->data.phone->lock);
    193                 irq_spinlock_lock(&TASK->answerbox.lock, true);
    194                 if (answer->data.phone->state == IPC_PHONE_CONNECTED) {
    195                         list_remove(&answer->data.phone->link);
    196                         answer->data.phone->state = IPC_PHONE_SLAMMED;
     197                phone_t *phone = answer->caller_phone;
     198                mutex_lock(&phone->lock);
     199                if (phone->state == IPC_PHONE_CONNECTED) {
     200                        irq_spinlock_lock(&phone->callee->lock, true);
     201                        list_remove(&phone->link);
     202                        phone->state = IPC_PHONE_SLAMMED;
     203                        irq_spinlock_unlock(&phone->callee->lock, true);
    197204                }
    198                 irq_spinlock_unlock(&TASK->answerbox.lock, true);
    199                 mutex_unlock(&answer->data.phone->lock);
     205                mutex_unlock(&phone->lock);
    200206        }
    201207       
    202208        if (!olddata)
    203                 return 0;
    204        
    205         if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECTION_CLONE) {
    206                 int phoneid = IPC_GET_ARG1(*olddata);
    207                 phone_t *phone = &TASK->phones[phoneid];
    208                
    209                 if (IPC_GET_RETVAL(answer->data) != EOK) {
    210                         /*
    211                          * The recipient of the cloned phone rejected the offer.
    212                          * In this case, the connection was established at the
    213                          * request time and therefore we need to slam the phone.
    214                          * We don't merely hangup as that would result in
    215                          * sending IPC_M_HUNGUP to the third party on the
    216                          * other side of the cloned phone.
    217                          */
    218                         mutex_lock(&phone->lock);
    219                         if (phone->state == IPC_PHONE_CONNECTED) {
    220                                 irq_spinlock_lock(&phone->callee->lock, true);
    221                                 list_remove(&phone->link);
    222                                 phone->state = IPC_PHONE_SLAMMED;
    223                                 irq_spinlock_unlock(&phone->callee->lock, true);
    224                         }
    225                         mutex_unlock(&phone->lock);
    226                 }
    227         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CLONE_ESTABLISH) {
    228                 phone_t *phone = (phone_t *) IPC_GET_ARG5(*olddata);
    229                
    230                 if (IPC_GET_RETVAL(answer->data) != EOK) {
    231                         /*
    232                          * The other party on the cloned phoned rejected our
    233                          * request for connection on the protocol level.
    234                          * We need to break the connection without sending
    235                          * IPC_M_HUNGUP back.
    236                          */
    237                         mutex_lock(&phone->lock);
    238                         if (phone->state == IPC_PHONE_CONNECTED) {
    239                                 irq_spinlock_lock(&phone->callee->lock, true);
    240                                 list_remove(&phone->link);
    241                                 phone->state = IPC_PHONE_SLAMMED;
    242                                 irq_spinlock_unlock(&phone->callee->lock, true);
    243                         }
    244                         mutex_unlock(&phone->lock);
    245                 }
    246         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_TO_ME) {
    247                 int phoneid = IPC_GET_ARG5(*olddata);
    248                
    249                 if (IPC_GET_RETVAL(answer->data) != EOK) {
    250                         /* The connection was not accepted */
    251                         phone_dealloc(phoneid);
    252                 } else {
    253                         /* The connection was accepted */
    254                         phone_connect(phoneid, &answer->sender->answerbox);
    255                         /* Set 'phone hash' as arg5 of response */
    256                         IPC_SET_ARG5(answer->data,
    257                             (sysarg_t) &TASK->phones[phoneid]);
    258                 }
    259         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_CONNECT_ME_TO) {
    260                 /* If the users accepted call, connect */
    261                 if (IPC_GET_RETVAL(answer->data) == EOK) {
    262                         ipc_phone_connect((phone_t *) IPC_GET_ARG5(*olddata),
    263                             &TASK->answerbox);
    264                 }
    265         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_OUT) {
    266                 if (!IPC_GET_RETVAL(answer->data)) {
    267                         /* Accepted, handle as_area receipt */
    268                        
    269                         irq_spinlock_lock(&answer->sender->lock, true);
    270                         as_t *as = answer->sender->as;
    271                         irq_spinlock_unlock(&answer->sender->lock, true);
    272                        
    273                         uintptr_t dst_base = (uintptr_t) -1;
    274                         int rc = as_area_share(as, IPC_GET_ARG1(*olddata),
    275                             IPC_GET_ARG2(*olddata), AS, IPC_GET_ARG3(*olddata),
    276                             &dst_base, IPC_GET_ARG1(answer->data));
    277                        
    278                         if (rc == EOK)
    279                                 rc = copy_to_uspace((void *) IPC_GET_ARG2(answer->data),
    280                                     &dst_base, sizeof(dst_base));
    281                        
    282                         IPC_SET_RETVAL(answer->data, rc);
    283                         return rc;
    284                 }
    285         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_SHARE_IN) {
    286                 if (!IPC_GET_RETVAL(answer->data)) {
    287                         irq_spinlock_lock(&answer->sender->lock, true);
    288                         as_t *as = answer->sender->as;
    289                         irq_spinlock_unlock(&answer->sender->lock, true);
    290                        
    291                         uintptr_t dst_base = (uintptr_t) -1;
    292                         int rc = as_area_share(AS, IPC_GET_ARG1(answer->data),
    293                             IPC_GET_ARG1(*olddata), as, IPC_GET_ARG2(answer->data),
    294                             &dst_base, IPC_GET_ARG3(answer->data));
    295                         IPC_SET_ARG4(answer->data, dst_base);
    296                         IPC_SET_RETVAL(answer->data, rc);
    297                 }
    298         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_READ) {
    299                 ASSERT(!answer->buffer);
    300                 if (!IPC_GET_RETVAL(answer->data)) {
    301                         /* The recipient agreed to send data. */
    302                         uintptr_t src = IPC_GET_ARG1(answer->data);
    303                         uintptr_t dst = IPC_GET_ARG1(*olddata);
    304                         size_t max_size = IPC_GET_ARG2(*olddata);
    305                         size_t size = IPC_GET_ARG2(answer->data);
    306                         if (size && size <= max_size) {
    307                                 /*
    308                                  * Copy the destination VA so that this piece of
    309                                  * information is not lost.
    310                                  */
    311                                 IPC_SET_ARG1(answer->data, dst);
    312                                
    313                                 answer->buffer = malloc(size, 0);
    314                                 int rc = copy_from_uspace(answer->buffer,
    315                                     (void *) src, size);
    316                                 if (rc) {
    317                                         IPC_SET_RETVAL(answer->data, rc);
    318                                         free(answer->buffer);
    319                                         answer->buffer = NULL;
    320                                 }
    321                         } else if (!size) {
    322                                 IPC_SET_RETVAL(answer->data, EOK);
    323                         } else {
    324                                 IPC_SET_RETVAL(answer->data, ELIMIT);
    325                         }
    326                 }
    327         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_DATA_WRITE) {
    328                 ASSERT(answer->buffer);
    329                 if (!IPC_GET_RETVAL(answer->data)) {
    330                         /* The recipient agreed to receive data. */
    331                         uintptr_t dst = (uintptr_t)IPC_GET_ARG1(answer->data);
    332                         size_t size = (size_t)IPC_GET_ARG2(answer->data);
    333                         size_t max_size = (size_t)IPC_GET_ARG2(*olddata);
    334                        
    335                         if (size <= max_size) {
    336                                 int rc = copy_to_uspace((void *) dst,
    337                                     answer->buffer, size);
    338                                 if (rc)
    339                                         IPC_SET_RETVAL(answer->data, rc);
    340                         } else {
    341                                 IPC_SET_RETVAL(answer->data, ELIMIT);
    342                         }
    343                 }
    344                 free(answer->buffer);
    345                 answer->buffer = NULL;
    346         } else if (IPC_GET_IMETHOD(*olddata) == IPC_M_STATE_CHANGE_AUTHORIZE) {
    347                 if (!IPC_GET_RETVAL(answer->data)) {
    348                         /* The recipient authorized the change of state. */
    349                         phone_t *recipient_phone;
    350                         task_t *other_task_s;
    351                         task_t *other_task_r;
    352                         int rc;
    353 
    354                         rc = phone_get(IPC_GET_ARG1(answer->data),
    355                             &recipient_phone);
    356                         if (rc != EOK) {
    357                                 IPC_SET_RETVAL(answer->data, ENOENT);
    358                                 return ENOENT;
    359                         }
    360 
    361                         mutex_lock(&recipient_phone->lock);
    362                         if (recipient_phone->state != IPC_PHONE_CONNECTED) {
    363                                 mutex_unlock(&recipient_phone->lock);
    364                                 IPC_SET_RETVAL(answer->data, EINVAL);
    365                                 return EINVAL;
    366                         }
    367 
    368                         other_task_r = recipient_phone->callee->task;
    369                         other_task_s = (task_t *) IPC_GET_ARG5(*olddata);
    370 
    371                         /*
    372                          * See if both the sender and the recipient meant the
    373                          * same third party task.
    374                          */
    375                         if (other_task_r != other_task_s) {
    376                                 IPC_SET_RETVAL(answer->data, EINVAL);
    377                                 rc = EINVAL;
    378                         } else {
    379                                 rc = event_task_notify_5(other_task_r,
    380                                     EVENT_TASK_STATE_CHANGE, false,
    381                                     IPC_GET_ARG1(*olddata),
    382                                     IPC_GET_ARG2(*olddata),
    383                                     IPC_GET_ARG3(*olddata),
    384                                     LOWER32(olddata->task_id),
    385                                     UPPER32(olddata->task_id));
    386                                 IPC_SET_RETVAL(answer->data, rc);
    387                         }
    388 
    389                         mutex_unlock(&recipient_phone->lock);
    390                         return rc;
    391                 }
    392         }
    393        
    394         return 0;
    395 }
    396 
    397 static void phones_lock(phone_t *p1, phone_t *p2)
    398 {
    399         if (p1 < p2) {
    400                 mutex_lock(&p1->lock);
    401                 mutex_lock(&p2->lock);
    402         } else if (p1 > p2) {
    403                 mutex_lock(&p2->lock);
    404                 mutex_lock(&p1->lock);
    405         } else
    406                 mutex_lock(&p1->lock);
    407 }
    408 
    409 static void phones_unlock(phone_t *p1, phone_t *p2)
    410 {
    411         mutex_unlock(&p1->lock);
    412         if (p1 != p2)
    413                 mutex_unlock(&p2->lock);
     209                return rc;
     210
     211        return SYSIPC_OP(answer_preprocess, answer, olddata);
    414212}
    415213
     
    424222static int request_preprocess(call_t *call, phone_t *phone)
    425223{
    426         switch (IPC_GET_IMETHOD(call->data)) {
    427         case IPC_M_CONNECTION_CLONE: {
    428                 phone_t *cloned_phone;
    429                 if (phone_get(IPC_GET_ARG1(call->data), &cloned_phone) != EOK)
    430                         return ENOENT;
    431                
    432                 phones_lock(cloned_phone, phone);
    433                
    434                 if ((cloned_phone->state != IPC_PHONE_CONNECTED) ||
    435                     phone->state != IPC_PHONE_CONNECTED) {
    436                         phones_unlock(cloned_phone, phone);
    437                         return EINVAL;
    438                 }
    439                
    440                 /*
    441                  * We can be pretty sure now that both tasks exist and we are
    442                  * connected to them. As we continue to hold the phone locks,
    443                  * we are effectively preventing them from finishing their
    444                  * potential cleanup.
    445                  *
    446                  */
    447                 int newphid = phone_alloc(phone->callee->task);
    448                 if (newphid < 0) {
    449                         phones_unlock(cloned_phone, phone);
    450                         return ELIMIT;
    451                 }
    452                
    453                 ipc_phone_connect(&phone->callee->task->phones[newphid],
    454                     cloned_phone->callee);
    455                 phones_unlock(cloned_phone, phone);
    456                
    457                 /* Set the new phone for the callee. */
    458                 IPC_SET_ARG1(call->data, newphid);
    459                 break;
    460         }
    461         case IPC_M_CLONE_ESTABLISH:
    462                 IPC_SET_ARG5(call->data, (sysarg_t) phone);
    463                 break;
    464         case IPC_M_CONNECT_ME_TO: {
    465                 int newphid = phone_alloc(TASK);
    466                 if (newphid < 0)
    467                         return ELIMIT;
    468                
    469                 /* Set arg5 for server */
    470                 IPC_SET_ARG5(call->data, (sysarg_t) &TASK->phones[newphid]);
    471                 call->flags |= IPC_CALL_CONN_ME_TO;
    472                 call->priv = newphid;
    473                 break;
    474         }
    475         case IPC_M_SHARE_OUT: {
    476                 size_t size = as_area_get_size(IPC_GET_ARG1(call->data));
    477                 if (!size)
    478                         return EPERM;
    479                
    480                 IPC_SET_ARG2(call->data, size);
    481                 break;
    482         }
    483         case IPC_M_DATA_READ: {
    484                 size_t size = IPC_GET_ARG2(call->data);
    485                 if (size > DATA_XFER_LIMIT) {
    486                         int flags = IPC_GET_ARG3(call->data);
    487                         if (flags & IPC_XF_RESTRICT)
    488                                 IPC_SET_ARG2(call->data, DATA_XFER_LIMIT);
    489                         else
    490                                 return ELIMIT;
    491                 }
    492                 break;
    493         }
    494         case IPC_M_DATA_WRITE: {
    495                 uintptr_t src = IPC_GET_ARG1(call->data);
    496                 size_t size = IPC_GET_ARG2(call->data);
    497                
    498                 if (size > DATA_XFER_LIMIT) {
    499                         int flags = IPC_GET_ARG3(call->data);
    500                         if (flags & IPC_XF_RESTRICT) {
    501                                 size = DATA_XFER_LIMIT;
    502                                 IPC_SET_ARG2(call->data, size);
    503                         } else
    504                                 return ELIMIT;
    505                 }
    506                
    507                 call->buffer = (uint8_t *) malloc(size, 0);
    508                 int rc = copy_from_uspace(call->buffer, (void *) src, size);
    509                 if (rc != 0) {
    510                         free(call->buffer);
    511                         return rc;
    512                 }
    513                
    514                 break;
    515         }
    516         case IPC_M_STATE_CHANGE_AUTHORIZE: {
    517                 phone_t *sender_phone;
    518                 task_t *other_task_s;
    519 
    520                 if (phone_get(IPC_GET_ARG5(call->data), &sender_phone) != EOK)
    521                         return ENOENT;
    522 
    523                 mutex_lock(&sender_phone->lock);
    524                 if (sender_phone->state != IPC_PHONE_CONNECTED) {
    525                         mutex_unlock(&sender_phone->lock);
    526                         return EINVAL;
    527                 }
    528 
    529                 other_task_s = sender_phone->callee->task;
    530 
    531                 mutex_unlock(&sender_phone->lock);
    532 
    533                 /* Remember the third party task hash. */
    534                 IPC_SET_ARG5(call->data, (sysarg_t) other_task_s);
    535                 break;
    536         }
    537 #ifdef CONFIG_UDEBUG
    538         case IPC_M_DEBUG:
    539                 return udebug_request_preprocess(call, phone);
    540 #endif
    541         default:
    542                 break;
    543         }
    544        
    545         return 0;
     224        call->request_method = IPC_GET_IMETHOD(call->data);
     225        return SYSIPC_OP(request_preprocess, call, phone);
    546226}
    547227
     
    561241                IPC_SET_RETVAL(call->data, EFORWARD);
    562242       
    563         if (call->flags & IPC_CALL_CONN_ME_TO) {
    564                 if (IPC_GET_RETVAL(call->data))
    565                         phone_dealloc(call->priv);
    566                 else
    567                         IPC_SET_ARG5(call->data, call->priv);
    568         }
    569        
    570         if (call->buffer) {
    571                 /*
    572                  * This must be an affirmative answer to IPC_M_DATA_READ
    573                  * or IPC_M_DEBUG/UDEBUG_M_MEM_READ...
    574                  *
    575                  */
    576                 uintptr_t dst = IPC_GET_ARG1(call->data);
    577                 size_t size = IPC_GET_ARG2(call->data);
    578                 int rc = copy_to_uspace((void *) dst, call->buffer, size);
    579                 if (rc)
    580                         IPC_SET_RETVAL(call->data, rc);
    581                 free(call->buffer);
    582                 call->buffer = NULL;
    583         }
    584 }
     243        SYSIPC_OP(answer_process, call);
     244}
     245
    585246
    586247/** Do basic kernel processing of received call request.
     
    595256static int process_request(answerbox_t *box, call_t *call)
    596257{
    597         if (IPC_GET_IMETHOD(call->data) == IPC_M_CONNECT_TO_ME) {
    598                 int phoneid = phone_alloc(TASK);
    599                 if (phoneid < 0) {  /* Failed to allocate phone */
    600                         IPC_SET_RETVAL(call->data, ELIMIT);
    601                         ipc_answer(box, call);
    602                         return -1;
    603                 }
    604                
    605                 IPC_SET_ARG5(call->data, phoneid);
    606         }
    607        
    608         switch (IPC_GET_IMETHOD(call->data)) {
    609         case IPC_M_DEBUG:
    610                 return -1;
    611         default:
    612                 break;
    613         }
    614        
    615         return 0;
     258        return SYSIPC_OP(request_process, call, box);
    616259}
    617260
     
    745388{
    746389        call_t *call = get_call(callid);
     390        phone_t *phone;
     391        bool need_old = answer_need_old(call);
     392        bool after_forward = false;
     393        ipc_data_t old;
     394        int rc;
     395
    747396        if (!call)
    748397                return ENOENT;
    749        
     398
     399        if (need_old)
     400                old = call->data;
     401       
     402        if (phone_get(phoneid, &phone) != EOK) {
     403                rc = ENOENT;
     404                goto error;
     405        }
     406       
     407        if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
     408                rc = EPERM;
     409                goto error;
     410        }
     411
    750412        call->flags |= IPC_CALL_FORWARDED;
    751        
    752         phone_t *phone;
    753         if (phone_get(phoneid, &phone) != EOK) {
    754                 IPC_SET_RETVAL(call->data, EFORWARD);
    755                 ipc_answer(&TASK->answerbox, call);
    756                 return ENOENT;
    757         }
    758        
    759         if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
    760                 IPC_SET_RETVAL(call->data, EFORWARD);
    761                 ipc_answer(&TASK->answerbox, call);
    762                 return EPERM;
    763         }
    764413       
    765414        /*
     
    797446        }
    798447       
    799         return ipc_forward(call, phone, &TASK->answerbox, mode);
     448        rc = ipc_forward(call, phone, &TASK->answerbox, mode);
     449        if (rc != EOK) {
     450                after_forward = true;
     451                goto error;
     452        }
     453
     454        return EOK;
     455
     456error:
     457        IPC_SET_RETVAL(call->data, EFORWARD);
     458        (void) answer_preprocess(call, need_old ? &old : NULL);
     459        if (after_forward)
     460                _ipc_answer_free_call(call, false);
     461        else
     462                ipc_answer(&TASK->answerbox, call);
     463
     464        return rc;
    800465}
    801466
  • kernel/generic/src/main/kinit.c

    rfc89e32 r33c2952  
    6969#include <str.h>
    7070#include <sysinfo/stats.h>
     71#include <sysinfo/sysinfo.h>
    7172#include <align.h>
    7273
     
    189190        program_t programs[CONFIG_INIT_TASKS];
    190191       
     192        // FIXME: do not propagate arguments through sysinfo
     193        // but pass them directly to the tasks
     194        for (i = 0; i < init.cnt; i++) {
     195                const char *arguments = init.tasks[i].arguments;
     196                if (str_length(arguments) == 0)
     197                        continue;
     198                if (str_length(init.tasks[i].name) == 0)
     199                        continue;
     200                size_t arguments_size = str_size(arguments);
     201
     202                void *arguments_copy = malloc(arguments_size, 0);
     203                if (arguments_copy == NULL)
     204                        continue;
     205                memcpy(arguments_copy, arguments, arguments_size);
     206
     207                char item_name[CONFIG_TASK_NAME_BUFLEN + 15];
     208                snprintf(item_name, CONFIG_TASK_NAME_BUFLEN + 15,
     209                    "init_args.%s", init.tasks[i].name);
     210
     211                sysinfo_set_item_data(item_name, NULL, arguments_copy, arguments_size);
     212        }
     213
    191214        for (i = 0; i < init.cnt; i++) {
    192215                if (init.tasks[i].paddr % FRAME_SIZE) {
  • kernel/generic/src/mm/as.c

    rfc89e32 r33c2952  
    285285/** Check area conflicts with other areas.
    286286 *
    287  * @param as    Address space.
    288  * @param addr  Starting virtual address of the area being tested.
    289  * @param count Number of pages in the area being tested.
    290  * @param avoid Do not touch this area.
     287 * @param as      Address space.
     288 * @param addr    Starting virtual address of the area being tested.
     289 * @param count   Number of pages in the area being tested.
     290 * @param guarded True if the area being tested is protected by guard pages.
     291 * @param avoid   Do not touch this area.
    291292 *
    292293 * @return True if there is no conflict, false otherwise.
     
    294295 */
    295296NO_TRACE static bool check_area_conflicts(as_t *as, uintptr_t addr,
    296     size_t count, as_area_t *avoid)
     297    size_t count, bool guarded, as_area_t *avoid)
    297298{
    298299        ASSERT((addr % PAGE_SIZE) == 0);
    299300        ASSERT(mutex_locked(&as->lock));
     301
     302        /*
     303         * If the addition of the supposed area address and size overflows,
     304         * report conflict.
     305         */
     306        if (overflows_into_positive(addr, P2SZ(count)))
     307                return false;
    300308       
    301309        /*
     
    304312        if (overlaps(addr, P2SZ(count), (uintptr_t) NULL, PAGE_SIZE))
    305313                return false;
    306        
     314
    307315        /*
    308316         * The leaf node is found in O(log n), where n is proportional to
     
    328336                if (area != avoid) {
    329337                        mutex_lock(&area->lock);
    330                        
     338
     339                        /*
     340                         * If at least one of the two areas are protected
     341                         * by the AS_AREA_GUARD flag then we must be sure
     342                         * that they are separated by at least one unmapped
     343                         * page.
     344                         */
     345                        int const gp = (guarded ||
     346                            (area->flags & AS_AREA_GUARD)) ? 1 : 0;
     347                       
     348                        /*
     349                         * The area comes from the left neighbour node, which
     350                         * means that there already are some areas in the leaf
     351                         * node, which in turn means that adding gp is safe and
     352                         * will not cause an integer overflow.
     353                         */
    331354                        if (overlaps(addr, P2SZ(count), area->base,
     355                            P2SZ(area->pages + gp))) {
     356                                mutex_unlock(&area->lock);
     357                                return false;
     358                        }
     359                       
     360                        mutex_unlock(&area->lock);
     361                }
     362        }
     363       
     364        node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf);
     365        if (node) {
     366                area = (as_area_t *) node->value[0];
     367               
     368                if (area != avoid) {
     369                        int gp;
     370
     371                        mutex_lock(&area->lock);
     372
     373                        gp = (guarded || (area->flags & AS_AREA_GUARD)) ? 1 : 0;
     374                        if (gp && overflows(addr, P2SZ(count))) {
     375                                /*
     376                                 * Guard page not needed if the supposed area
     377                                 * is adjacent to the end of the address space.
     378                                 * We already know that the following test is
     379                                 * going to fail...
     380                                 */
     381                                gp--;
     382                        }
     383                       
     384                        if (overlaps(addr, P2SZ(count + gp), area->base,
    332385                            P2SZ(area->pages))) {
    333386                                mutex_unlock(&area->lock);
     
    339392        }
    340393       
    341         node = btree_leaf_node_right_neighbour(&as->as_area_btree, leaf);
    342         if (node) {
    343                 area = (as_area_t *) node->value[0];
    344                
    345                 if (area != avoid) {
    346                         mutex_lock(&area->lock);
    347                        
    348                         if (overlaps(addr, P2SZ(count), area->base,
    349                             P2SZ(area->pages))) {
    350                                 mutex_unlock(&area->lock);
    351                                 return false;
    352                         }
    353                        
    354                         mutex_unlock(&area->lock);
    355                 }
    356         }
    357        
    358394        /* Second, check the leaf node. */
    359395        btree_key_t i;
    360396        for (i = 0; i < leaf->keys; i++) {
    361397                area = (as_area_t *) leaf->value[i];
     398                int agp;
     399                int gp;
    362400               
    363401                if (area == avoid)
     
    365403               
    366404                mutex_lock(&area->lock);
    367                
    368                 if (overlaps(addr, P2SZ(count), area->base,
    369                     P2SZ(area->pages))) {
     405
     406                gp = (guarded || (area->flags & AS_AREA_GUARD)) ? 1 : 0;
     407                agp = gp;
     408
     409                /*
     410                 * Sanitize the two possible unsigned integer overflows.
     411                 */
     412                if (gp && overflows(addr, P2SZ(count)))
     413                        gp--;
     414                if (agp && overflows(area->base, P2SZ(area->pages)))
     415                        agp--;
     416
     417                if (overlaps(addr, P2SZ(count + gp), area->base,
     418                    P2SZ(area->pages + agp))) {
    370419                        mutex_unlock(&area->lock);
    371420                        return false;
     
    392441 * this function.
    393442 *
    394  * @param as    Address space.
    395  * @param bound Lowest address bound.
    396  * @param size  Requested size of the allocation.
     443 * @param as      Address space.
     444 * @param bound   Lowest address bound.
     445 * @param size    Requested size of the allocation.
     446 * @param guarded True if the allocation must be protected by guard pages.
    397447 *
    398448 * @return Address of the beginning of unmapped address space area.
     
    401451 */
    402452NO_TRACE static uintptr_t as_get_unmapped_area(as_t *as, uintptr_t bound,
    403     size_t size)
     453    size_t size, bool guarded)
    404454{
    405455        ASSERT(mutex_locked(&as->lock));
     
    423473        /* First check the bound address itself */
    424474        uintptr_t addr = ALIGN_UP(bound, PAGE_SIZE);
    425         if ((addr >= bound) &&
    426             (check_area_conflicts(as, addr, pages, NULL)))
    427                 return addr;
     475        if (addr >= bound) {
     476                if (guarded) {
     477                        /* Leave an unmapped page between the lower
     478                         * bound and the area's start address.
     479                         */
     480                        addr += P2SZ(1);
     481                }
     482
     483                if (check_area_conflicts(as, addr, pages, guarded, NULL))
     484                        return addr;
     485        }
    428486       
    429487        /* Eventually check the addresses behind each area */
     
    439497                        addr =
    440498                            ALIGN_UP(area->base + P2SZ(area->pages), PAGE_SIZE);
     499
     500                        if (guarded || area->flags & AS_AREA_GUARD) {
     501                                /* We must leave an unmapped page
     502                                 * between the two areas.
     503                                 */
     504                                addr += P2SZ(1);
     505                        }
     506
    441507                        bool avail =
    442508                            ((addr >= bound) && (addr >= area->base) &&
    443                             (check_area_conflicts(as, addr, pages, area)));
     509                            (check_area_conflicts(as, addr, pages, guarded, area)));
    444510                       
    445511                        mutex_unlock(&area->lock);
     
    481547        if (size == 0)
    482548                return NULL;
    483        
     549
    484550        size_t pages = SIZE2FRAMES(size);
    485551       
     
    487553        if ((flags & AS_AREA_EXEC) && (flags & AS_AREA_WRITE))
    488554                return NULL;
     555
     556        bool const guarded = flags & AS_AREA_GUARD;
    489557       
    490558        mutex_lock(&as->lock);
    491559       
    492560        if (*base == (uintptr_t) -1) {
    493                 *base = as_get_unmapped_area(as, bound, size);
     561                *base = as_get_unmapped_area(as, bound, size, guarded);
    494562                if (*base == (uintptr_t) -1) {
    495563                        mutex_unlock(&as->lock);
     
    497565                }
    498566        }
    499        
    500         if (!check_area_conflicts(as, *base, pages, NULL)) {
     567
     568        if (overflows_into_positive(*base, size))
     569                return NULL;
     570
     571        if (!check_area_conflicts(as, *base, pages, guarded, NULL)) {
    501572                mutex_unlock(&as->lock);
    502573                return NULL;
     
    776847                /*
    777848                 * Growing the area.
     849                 */
     850
     851                if (overflows_into_positive(address, P2SZ(pages)))
     852                        return EINVAL;
     853
     854                /*
    778855                 * Check for overlaps with other address space areas.
    779856                 */
    780                 if (!check_area_conflicts(as, address, pages, area)) {
     857                bool const guarded = area->flags & AS_AREA_GUARD;
     858                if (!check_area_conflicts(as, address, pages, guarded, area)) {
    781859                        mutex_unlock(&area->lock);
    782860                        mutex_unlock(&as->lock);
  • kernel/generic/src/proc/task.c

    rfc89e32 r33c2952  
    161161        size_t i;
    162162        for (i = 0; i < IPC_MAX_PHONES; i++)
    163                 ipc_phone_init(&task->phones[i]);
     163                ipc_phone_init(&task->phones[i], task);
     164
     165        spinlock_initialize(&task->active_calls_lock, "active_calls_lock");
     166        list_initialize(&task->active_calls);
    164167       
    165168#ifdef CONFIG_UDEBUG
     
    203206        event_task_init(task);
    204207       
     208        task->answerbox.active = true;
     209
    205210#ifdef CONFIG_UDEBUG
    206211        /* Init debugging stuff */
     
    208213       
    209214        /* Init kbox stuff */
     215        task->kb.box.active = true;
    210216        task->kb.finished = false;
    211217#endif
     
    213219        if ((ipc_phone_0) &&
    214220            (container_check(ipc_phone_0->task->container, task->container)))
    215                 ipc_phone_connect(&task->phones[0], ipc_phone_0);
     221                (void) ipc_phone_connect(&task->phones[0], ipc_phone_0);
    216222       
    217223        btree_create(&task->futexes);
Note: See TracChangeset for help on using the changeset viewer.