Changeset efdfebc in mainline for kernel


Ignore:
Timestamp:
2012-11-06T21:03:44Z (13 years ago)
Author:
Jakub Jermar <jakub@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
338810f
Parents:
de73242 (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:

Merge mainline changes.

Location:
kernel
Files:
19 added
51 edited

Legend:

Unmodified
Added
Removed
  • kernel/Makefile

    rde73242 refdfebc  
    196196        generic/src/console/chardev.c \
    197197        generic/src/console/console.c \
     198        generic/src/console/prompt.c \
    198199        generic/src/cpu/cpu.c \
    199200        generic/src/ddi/ddi.c \
     
    256257        generic/src/ipc/ipc.c \
    257258        generic/src/ipc/sysipc.c \
     259        generic/src/ipc/sysipc_ops.c \
     260        generic/src/ipc/ops/clnestab.c \
     261        generic/src/ipc/ops/conctmeto.c \
     262        generic/src/ipc/ops/concttome.c \
     263        generic/src/ipc/ops/connclone.c \
     264        generic/src/ipc/ops/dataread.c \
     265        generic/src/ipc/ops/datawrite.c \
     266        generic/src/ipc/ops/debug.c \
     267        generic/src/ipc/ops/sharein.c \
     268        generic/src/ipc/ops/shareout.c \
     269        generic/src/ipc/ops/stchngath.c \
    258270        generic/src/ipc/ipcrsc.c \
    259271        generic/src/ipc/irq.c \
  • kernel/arch/amd64/src/asm.S

    rde73242 refdfebc  
    362362         */
    363363        call syscall_handler
    364        
     364
     365        /*
     366         * Test if the saved return address is canonical and not-kernel.
     367         * We do this by looking at the 16 most significant bits
     368         * of the saved return address (two bytes at offset 6).
     369         */
     370        testw $0xffff, ISTATE_OFFSET_RIP+6(%rsp)
     371        jnz bad_rip
     372
    365373        cli
    366374       
     
    388396        sysretq
    389397
     398bad_rip:
     399        movq %rsp, %rdi
     400        movabs $bad_rip_msg, %rsi
     401        xorb %al, %al
     402        callq fault_from_uspace
     403        /* not reached */
     404       
     405bad_rip_msg:
     406        .asciz "Invalid instruction pointer."
     407
    390408/** Print Unicode character to EGA display.
    391409 *
  • kernel/arch/amd64/src/boot/multiboot.S

    rde73242 refdfebc  
    7676
    7777multiboot_image_start:
     78        cli
    7879        cld
    7980       
     
    8182        movl $START_STACK, %esp
    8283       
    83         /* Initialize Global Descriptor Table register */
     84        /*
     85         * Initialize Global Descriptor Table and
     86         * Interrupt Descriptor Table registers
     87         */
    8488        lgdtl bootstrap_gdtr
     89        lidtl bootstrap_idtr
    8590       
    8691        /* Kernel data + stack */
     
    645650.section K_DATA_START, "aw", @progbits
    646651
     652.global bootstrap_idtr
     653bootstrap_idtr:
     654        .word 0
     655        .long 0
     656
    647657.global bootstrap_gdtr
    648658bootstrap_gdtr:
  • kernel/arch/amd64/src/boot/multiboot2.S

    rde73242 refdfebc  
    116116
    117117multiboot2_image_start:
     118        cli
    118119        cld
    119120       
     
    121122        movl $START_STACK, %esp
    122123       
    123         /* Initialize Global Descriptor Table register */
     124        /*
     125         * Initialize Global Descriptor Table and
     126         * Interrupt Descriptor Table registers
     127         */
    124128        lgdtl bootstrap_gdtr
     129        lidtl bootstrap_idtr
    125130       
    126131        /* Kernel data + stack */
  • kernel/arch/amd64/src/boot/vesa_ret.inc

    rde73242 refdfebc  
    11.code32
    22vesa_init_protected:
     3        cli
    34        cld
    45       
  • kernel/arch/arm32/Makefile.inc

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    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/arch/ia32/src/boot/multiboot.S

    rde73242 refdfebc  
    7373
    7474multiboot_image_start:
     75        cli
    7576        cld
    7677       
     
    7879        movl $START_STACK, %esp
    7980       
    80         /* Initialize Global Descriptor Table register */
     81        /*
     82         * Initialize Global Descriptor Table and
     83         * Interrupt Descriptor Table registers
     84         */
    8185        lgdtl bootstrap_gdtr
     86        lidtl bootstrap_idtr
    8287       
    8388        /* Kernel data + stack */
     
    701706page_directory:
    702707        .space 4096, 0
     708
     709.global bootstrap_idtr
     710bootstrap_idtr:
     711        .word 0
     712        .long 0
    703713
    704714.global bootstrap_gdtr
  • kernel/arch/ia32/src/boot/multiboot2.S

    rde73242 refdfebc  
    114114
    115115multiboot2_image_start:
     116        cli
    116117        cld
    117118       
     
    119120        movl $START_STACK, %esp
    120121       
    121         /* Initialize Global Descriptor Table register */
     122        /*
     123         * Initialize Global Descriptor Table and
     124         * Interrupt Descriptor Table registers
     125         */
    122126        lgdtl bootstrap_gdtr
     127        lidtl bootstrap_idtr
    123128       
    124129        /* Kernel data + stack */
  • kernel/arch/ia32/src/boot/vesa_prot.inc

    rde73242 refdfebc  
    8888                /* Returned back to protected mode */
    8989               
     90                /*
     91                 * Initialize Global Descriptor Table and
     92                 * Interrupt Descriptor Table registers
     93                 */
     94                lgdtl bootstrap_gdtr
     95                lidtl bootstrap_idtr
     96               
    9097                movzx %ax, %ecx
    9198                mov %ecx, KA2PA(bfb_scanline)
  • kernel/arch/ia32/src/boot/vesa_real.inc

    rde73242 refdfebc  
    3030.code32
    3131vesa_init:
     32        lidtl vesa_idtr
    3233        jmp $GDT_SELECTOR(VESA_INIT_DES), $vesa_init_real - vesa_init
     34
     35vesa_idtr:
     36        .word 0x3ff
     37        .long 0
    3338
    3439.code16
  • kernel/arch/ia32/src/boot/vesa_ret.inc

    rde73242 refdfebc  
    11.code32
    22vesa_init_protected:
     3        cli
    34        cld
    45       
  • kernel/arch/ia32/src/smp/apic.c

    rde73242 refdfebc  
    259259}
    260260
     261#define DELIVS_PENDING_SILENT_RETRIES   4       
     262
     263static void l_apic_wait_for_delivery(void)
     264{
     265        icr_t icr;
     266        unsigned retries = 0;
     267
     268        do {
     269                if (retries++ > DELIVS_PENDING_SILENT_RETRIES) {
     270                        retries = 0;
     271#ifdef CONFIG_DEBUG
     272                        printf("IPI is pending.\n");
     273#endif
     274                        delay(20);
     275                }
     276                icr.lo = l_apic[ICRlo];
     277        } while (icr.delivs == DELIVS_PENDING);
     278       
     279}
     280
    261281/** Send all CPUs excluding CPU IPI vector.
    262282 *
     
    279299       
    280300        l_apic[ICRlo] = icr.lo;
    281        
    282         icr.lo = l_apic[ICRlo];
    283         if (icr.delivs == DELIVS_PENDING) {
    284 #ifdef CONFIG_DEBUG
    285                 printf("IPI is pending.\n");
    286 #endif
    287         }
     301
     302        l_apic_wait_for_delivery();
    288303       
    289304        return apic_poll_errors();
     
    327342                return 0;
    328343       
     344        l_apic_wait_for_delivery();
     345
    329346        icr.lo = l_apic[ICRlo];
    330         if (icr.delivs == DELIVS_PENDING) {
    331 #ifdef CONFIG_DEBUG
    332                 printf("IPI is pending.\n");
    333 #endif
    334         }
    335        
    336347        icr.delmod = DELMOD_INIT;
    337348        icr.destmod = DESTMOD_PHYS;
  • kernel/arch/ia64/Makefile.inc

    rde73242 refdfebc  
    3030BFD_ARCH = ia64-elf64
    3131
    32 CMN1 = -mconstant-gp -fno-unwind-tables -mfixed-range=f32-f127
     32#
     33# FIXME:
     34#
     35# The -fno-selective-scheduling and -fno-selective-scheduling2 options
     36# should be removed as soon as a bug in GCC concerning unchecked
     37# speculative loads is fixed.
     38#
     39# See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=53975 for reference.
     40#
     41
     42CMN1 = -mconstant-gp -fno-unwind-tables -mfixed-range=f32-f127 -fno-selective-scheduling -fno-selective-scheduling2
    3343GCC_CFLAGS += $(CMN1)
    3444ICC_CFLAGS += $(CMN1)
  • kernel/arch/mips32/Makefile.inc

    rde73242 refdfebc  
    2929BFD_ARCH = mips
    3030BFD = binary
    31 GCC_CFLAGS += -mno-abicalls -G 0 -fno-zero-initialized-in-bss -mips3 -mabi=32
     31GCC_CFLAGS += -msoft-float -mno-abicalls -G 0 -fno-zero-initialized-in-bss -mips3 -mabi=32
    3232
    3333BITS = 32
     
    4848        BFD_NAME = elf32-tradlittlemips
    4949        ENDIANESS = LE
    50         GCC_CFLAGS += -mhard-float
    5150endif
    5251
  • kernel/arch/mips64/Makefile.inc

    rde73242 refdfebc  
    2929BFD_ARCH = mips:4000
    3030BFD = binary
    31 GCC_CFLAGS += -mno-abicalls -G 0 -fno-zero-initialized-in-bss -mips3 -mabi=64
     31GCC_CFLAGS += -msoft-float -mno-abicalls -G 0 -fno-zero-initialized-in-bss -mips3 -mabi=64
    3232AFLAGS = -64
    3333
     
    4040        BFD_NAME = elf64-tradlittlemips
    4141        ENDIANESS = LE
    42         GCC_CFLAGS += -mhard-float
    4342endif
    4443
  • kernel/arch/sparc64/src/smp/sun4u/ipi.c

    rde73242 refdfebc  
    124124                        (void) interrupts_disable();
    125125                }
    126         } while (done);
     126        } while (!done);
    127127       
    128128        preemption_enable();
  • kernel/genarch/Makefile.inc

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    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/debug.h

    rde73242 refdfebc  
    3737
    3838#include <panic.h>
    39 #include <symtab.h>
     39#include <symtab_lookup.h>
    4040
    4141#define CALLER  ((uintptr_t) __builtin_return_address(0))
  • kernel/generic/include/interrupt.h

    rde73242 refdfebc  
    3838#include <arch/interrupt.h>
    3939#include <print.h>
     40#include <stdarg.h>
    4041#include <typedefs.h>
    4142#include <proc/task.h>
     
    5859extern exc_table_t exc_table[];
    5960
     61extern void fault_from_uspace(istate_t *, const char *, ...)
     62    PRINTF_ATTRIBUTE(2, 3);
    6063extern void fault_if_from_uspace(istate_t *, const char *, ...)
    6164    PRINTF_ATTRIBUTE(2, 3);
  • kernel/generic/include/ipc/ipc.h

    rde73242 refdfebc  
    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;
    7680       
    7781        waitq_t wq;
    78        
    79         /** Linkage for the list of task's synchronous answerboxes. */
    80         link_t sync_box_link;
    8182       
    8283        /** Phones connected to this answerbox. */
     
    109110
    110111typedef struct {
    111         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;
    112123       
    113124        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;
    114142       
    115         /** Identification of the caller. */
     143        /**
     144         * Identification of the caller.
     145         * Valid only when the call is not forgotten.
     146         */
    116147        struct task *sender;
    117148       
    118         /*
    119          * The caller box is different from sender->answerbox
    120          * for synchronous calls.
    121          */
    122         answerbox_t *callerbox;
     149        /** Phone which was used to send the call. */
     150        phone_t *caller_phone;
    123151       
    124152        /** Private data to internal IPC. */
     
    127155        /** Data passed from/to userspace. */
    128156        ipc_data_t data;
    129        
     157
     158        /** Method as it was sent in the request. */
     159        sysarg_t request_method;
     160
    130161        /** Buffer for IPC_M_DATA_WRITE and IPC_M_DATA_READ. */
    131162        uint8_t *buffer;
    132        
    133         /*
    134          * The forward operation can masquerade the caller phone. For those
    135          * cases, we must keep it aside so that the answer is processed
    136          * correctly.
    137          */
    138         phone_t *caller_phone;
    139163} call_t;
    140164
     
    145169extern call_t *ipc_call_alloc(unsigned int);
    146170extern void ipc_call_free(call_t *);
     171extern void ipc_call_hold(call_t *);
     172extern void ipc_call_release(call_t *);
    147173
    148174extern int ipc_call(phone_t *, call_t *);
    149 extern int ipc_call_sync(phone_t *, call_t *);
    150175extern call_t *ipc_wait_for_call(answerbox_t *, uint32_t, unsigned int);
    151176extern int ipc_forward(call_t *, phone_t *, answerbox_t *, unsigned int);
    152177extern void ipc_answer(answerbox_t *, call_t *);
     178extern void _ipc_answer_free_call(call_t *, bool);
    153179
    154 extern void ipc_phone_init(phone_t *);
    155 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 *);
    156182extern int ipc_phone_hangup(phone_t *);
    157183
     
    161187extern void ipc_backsend_err(phone_t *, call_t *, sysarg_t);
    162188extern void ipc_answerbox_slam_phones(answerbox_t *, bool);
    163 extern void ipc_cleanup_call_list(list_t *);
     189extern void ipc_cleanup_call_list(answerbox_t *, list_t *);
    164190
    165191extern void ipc_print_task(task_id_t);
  • kernel/generic/include/ipc/ipcrsc.h

    rde73242 refdfebc  
    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/ipc/irq.h

    rde73242 refdfebc  
    3737
    3838/** Maximum number of IPC IRQ programmed I/O ranges. */
    39 #define IRQ_MAX_RANGE_COUNT     8
     39#define IRQ_MAX_RANGE_COUNT  8
    4040
    4141/** Maximum length of IPC IRQ program. */
    42 #define IRQ_MAX_PROG_SIZE  20
     42#define IRQ_MAX_PROG_SIZE  256
    4343
    4444#include <ipc/ipc.h>
  • kernel/generic/include/ipc/sysipc.h

    rde73242 refdfebc  
    4040#include <typedefs.h>
    4141
    42 extern sysarg_t sys_ipc_call_sync_fast(sysarg_t, sysarg_t, sysarg_t,
    43     sysarg_t, sysarg_t, ipc_data_t *);
    44 extern sysarg_t sys_ipc_call_sync_slow(sysarg_t, ipc_data_t *, ipc_data_t *);
    4542extern sysarg_t sys_ipc_call_async_fast(sysarg_t, sysarg_t, sysarg_t,
    4643    sysarg_t, sysarg_t, sysarg_t);
  • kernel/generic/include/lib/elf_load.h

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    9191       
    9292        /* IPC stuff */
    93         answerbox_t answerbox;  /**< Communication endpoint */
     93
     94        /** Receiving communication endpoint */
     95        answerbox_t answerbox;
     96
     97        /** Sending communication endpoints */
    9498        phone_t phones[IPC_MAX_PHONES];
    95         stats_ipc_t ipc_info;   /**< IPC statistics */
    96         list_t sync_boxes;      /**< List of synchronous answerboxes. */
     99
     100        /** Spinlock protecting the active_calls list. */
     101        SPINLOCK_DECLARE(active_calls_lock);
     102
     103        /**
     104         * List of all calls sent by this task that have not yet been
     105         * answered.
     106         */
     107        list_t active_calls;
     108
    97109        event_t events[EVENT_TASK_END - EVENT_END];
     110
     111        /** IPC statistics */
     112        stats_ipc_t ipc_info;
    98113       
    99114#ifdef CONFIG_UDEBUG
  • kernel/generic/include/symtab.h

    rde73242 refdfebc  
    3636#define KERN_SYMTAB_H_
    3737
    38 #include <typedefs.h>
     38#include <symtab_lookup.h>
     39#include <console/chardev.h>
    3940
    40 #define MAX_SYMBOL_NAME  64
    41 
    42 struct symtab_entry {
    43         uint64_t address_le;
    44         char symbol_name[MAX_SYMBOL_NAME];
    45 };
    46 
    47 extern int symtab_name_lookup(uintptr_t, const char **, uintptr_t *);
    48 extern const char *symtab_fmt_name_lookup(uintptr_t);
    49 extern int symtab_addr_lookup(const char *, uintptr_t *);
    5041extern void symtab_print_search(const char *);
    51 extern int symtab_compl(char *, size_t);
    52 
    53 #ifdef CONFIG_SYMTAB
    54 
    55 /** Symtable linked together by build process
    56  *
    57  */
    58 extern struct symtab_entry symbol_table[];
    59 
    60 #endif /* CONFIG_SYMTAB */
     42extern int symtab_compl(char *, size_t, indev_t *);
    6143
    6244#endif
  • kernel/generic/src/console/kconsole.c

    rde73242 refdfebc  
    4343#include <console/chardev.h>
    4444#include <console/cmd.h>
     45#include <console/prompt.h>
    4546#include <print.h>
    4647#include <panic.h>
     
    201202 *
    202203 */
    203 NO_TRACE static int cmdtab_compl(char *input, size_t size)
     204NO_TRACE static int cmdtab_compl(char *input, size_t size, indev_t *indev)
    204205{
    205206        const char *name = input;
    206207       
    207208        size_t found = 0;
     209       
     210        /*
     211         * Maximum Match Length: Length of longest matching common
     212         * substring in case more than one match is found.
     213         */
     214        size_t max_match_len = size;
     215        size_t max_match_len_tmp = size;
     216        size_t input_len = str_length(input);
    208217        link_t *pos = NULL;
    209218        const char *hint;
    210219        char *output = malloc(MAX_CMDLINE, 0);
     220        size_t hints_to_show = MAX_TAB_HINTS - 1;
     221        size_t total_hints_shown = 0;
     222        bool continue_showing_hints = true;
    211223       
    212224        output[0] = 0;
     
    218230                pos = pos->next;
    219231                found++;
     232        }
     233       
     234        /*
     235         * If the number of possible completions is more than MAX_TAB_HINTS,
     236         * ask the user whether to display them or not.
     237         */
     238        if (found > MAX_TAB_HINTS) {
     239                printf("\n");
     240                continue_showing_hints =
     241                    console_prompt_display_all_hints(indev, found);
    220242        }
    221243       
     
    225247                while (cmdtab_search_one(name, &pos)) {
    226248                        cmd_info_t *hlp = list_get_instance(pos, cmd_info_t, link);
    227                         printf("%s (%s)\n", hlp->name, hlp->description);
     249                       
     250                        if (continue_showing_hints) {
     251                                printf("%s (%s)\n", hlp->name, hlp->description);
     252                                --hints_to_show;
     253                                ++total_hints_shown;
     254                               
     255                                if ((hints_to_show == 0) && (total_hints_shown != found)) {
     256                                        /* Ask user to continue */
     257                                        continue_showing_hints =
     258                                            console_prompt_more_hints(indev, &hints_to_show);
     259                                }
     260                        }
     261                       
    228262                        pos = pos->next;
    229                 }
     263                       
     264                        for (max_match_len_tmp = 0;
     265                            (output[max_match_len_tmp] ==
     266                            hlp->name[input_len + max_match_len_tmp]) &&
     267                            (max_match_len_tmp < max_match_len); ++max_match_len_tmp);
     268                       
     269                        max_match_len = max_match_len_tmp;
     270                }
     271               
     272                /* Keep only the characters common in all completions */
     273                output[max_match_len] = 0;
    230274        }
    231275       
     
    280324                                continue;
    281325                       
    282                         /* Find the beginning of the word
    283                            and copy it to tmp */
     326                        /*
     327                         * Find the beginning of the word
     328                         * and copy it to tmp
     329                         */
    284330                        size_t beg;
    285331                        for (beg = position - 1; (beg > 0) && (!isspace(current[beg]));
     
    294340                        if (beg == 0) {
    295341                                /* Command completion */
    296                                 found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE));
     342                                found = cmdtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev);
    297343                        } else {
    298344                                /* Symbol completion */
    299                                 found = symtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE));
     345                                found = symtab_compl(tmp, STR_BOUNDS(MAX_CMDLINE), indev);
    300346                        }
    301347                       
    302348                        if (found == 0)
    303349                                continue;
    304                        
    305                         if (found > 1) {
    306                                 /* No unique hint, list was printed */
    307                                 printf("%s> ", prompt);
    308                                 printf("%ls", current);
    309                                 print_cc('\b', wstr_length(current) - position);
    310                                 continue;
    311                         }
    312                        
    313                         /* We have a hint */
    314                        
     350
     351                        /*
     352                         * We have hints, possibly many. In case of more than one hint,
     353                         * tmp will contain the common prefix.
     354                         */
    315355                        size_t off = 0;
    316356                        size_t i = 0;
     
    318358                                if (!wstr_linsert(current, ch, position + i, MAX_CMDLINE))
    319359                                        break;
     360                               
    320361                                i++;
    321362                        }
     363                       
     364                        if (found > 1) {
     365                                /* No unique hint, list was printed */
     366                                printf("%s> ", prompt);
     367                                printf("%ls", current);
     368                                position += str_length(tmp);
     369                                print_cc('\b', wstr_length(current) - position);
     370                                continue;
     371                        }
     372                       
     373                        /* We have a hint */
    322374                       
    323375                        printf("%ls", current + position);
     
    540592/** Parse command line.
    541593 *
    542  * @param cmdline Command line as read from input device. 
     594 * @param cmdline Command line as read from input device.
    543595 * @param size    Size (in bytes) of the string.
    544596 *
  • kernel/generic/src/debug/symtab.c

    rde73242 refdfebc  
    4343#include <typedefs.h>
    4444#include <errno.h>
     45#include <console/prompt.h>
    4546
    4647/** Get name of a symbol that seems most likely to correspond to address.
     
    209210 *
    210211 */
    211 int symtab_compl(char *input, size_t size)
     212int symtab_compl(char *input, size_t size, indev_t *indev)
    212213{
    213214#ifdef CONFIG_SYMTAB
     
    227228        char output[MAX_SYMBOL_NAME];
    228229       
     230        /*
     231         * Maximum Match Length: Length of longest matching common substring in
     232         * case more than one match is found.
     233         */
     234        size_t max_match_len = size;
     235        size_t max_match_len_tmp = size;
     236        size_t input_len = str_length(input);
     237        char *sym_name;
     238        size_t hints_to_show = MAX_TAB_HINTS - 1;
     239        size_t total_hints_shown = 0;
     240        bool continue_showing_hints = true;
     241       
    229242        output[0] = 0;
     243       
     244        while ((hint = symtab_search_one(name, &pos)))
     245                pos++;
     246       
     247        pos = 0;
    230248       
    231249        while ((hint = symtab_search_one(name, &pos))) {
     
    235253                pos++;
    236254                found++;
     255        }
     256       
     257        /*
     258         * If the number of possible completions is more than MAX_TAB_HINTS,
     259         * ask the user whether to display them or not.
     260         */
     261        if (found > MAX_TAB_HINTS) {
     262                printf("\n");
     263                continue_showing_hints =
     264                    console_prompt_display_all_hints(indev, found);
    237265        }
    238266       
     
    241269                pos = 0;
    242270                while (symtab_search_one(name, &pos)) {
    243                         printf("%s\n", symbol_table[pos].symbol_name);
     271                        sym_name = symbol_table[pos].symbol_name;
    244272                        pos++;
     273                       
     274                        if (continue_showing_hints) {
     275                                /* We are still showing hints */
     276                                printf("%s\n", sym_name);
     277                                --hints_to_show;
     278                                ++total_hints_shown;
     279                               
     280                                if ((hints_to_show == 0) && (total_hints_shown != found)) {
     281                                        /* Ask the user to continue */
     282                                        continue_showing_hints =
     283                                            console_prompt_more_hints(indev, &hints_to_show);
     284                                }
     285                        }
     286                       
     287                        for (max_match_len_tmp = 0;
     288                            (output[max_match_len_tmp] ==
     289                            sym_name[input_len + max_match_len_tmp]) &&
     290                            (max_match_len_tmp < max_match_len); ++max_match_len_tmp);
     291                       
     292                        max_match_len = max_match_len_tmp;
    245293                }
     294               
     295                /* Keep only the characters common in all completions */
     296                output[max_match_len] = 0;
    246297        }
    247298       
  • kernel/generic/src/interrupt/interrupt.c

    rde73242 refdfebc  
    5050#include <panic.h>
    5151#include <print.h>
     52#include <stdarg.h>
    5253#include <symtab.h>
    5354#include <proc/thread.h>
     
    165166}
    166167
    167 /** Terminate thread and task if exception came from userspace.
    168  *
    169  */
    170 NO_TRACE void fault_if_from_uspace(istate_t *istate, const char *fmt, ...)
    171 {
    172         if (!istate_from_uspace(istate))
    173                 return;
    174        
     168static NO_TRACE void fault_from_uspace_core(istate_t *istate, const char *fmt, va_list args)
     169{
    175170        printf("Task %s (%" PRIu64 ") killed due to an exception at "
    176171            "program counter %p.\n", TASK->name, TASK->taskid,
     
    181176       
    182177        printf("Kill message: ");
     178        vprintf(fmt, args);
     179        printf("\n");
     180       
     181        task_kill_self(true);
     182}
     183
     184/** Terminate thread and task after the exception came from userspace.
     185 *
     186 */
     187NO_TRACE void fault_from_uspace(istate_t *istate, const char *fmt, ...)
     188{
     189        va_list args;
     190
     191        va_start(args, fmt);
     192        fault_from_uspace_core(istate, fmt, args);
     193        va_end(args);
     194}
     195
     196/** Terminate thread and task if exception came from userspace.
     197 *
     198 */
     199NO_TRACE void fault_if_from_uspace(istate_t *istate, const char *fmt, ...)
     200{
     201        if (!istate_from_uspace(istate))
     202                return;
    183203       
    184204        va_list args;
    185205        va_start(args, fmt);
    186         vprintf(fmt, args);
     206        fault_from_uspace_core(istate, fmt, args);
    187207        va_end(args);
    188         printf("\n");
    189        
    190         task_kill_self(true);
    191208}
    192209
  • kernel/generic/src/ipc/event.c

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    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->callerbox = &TASK->answerbox;
    74         call->sender = TASK;
     75        spinlock_initialize(&call->forget_lock, "forget_lock");
     76        call->active = false;
     77        call->forget = false;
     78        call->sender = NULL;
    7579        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        }
    7694}
    7795
     
    84102 *
    85103 * @return If flags permit it, return NULL, or initialized kernel
    86  *         call structure.
     104 *         call structure with one reference.
    87105 *
    88106 */
     
    90108{
    91109        call_t *call = slab_alloc(ipc_call_slab, flags);
    92         if (call)
     110        if (call) {
    93111                _ipc_call_init(call);
     112                ipc_call_hold(call);
     113        }
    94114       
    95115        return call;
     
    103123void ipc_call_free(call_t *call)
    104124{
    105         /* Check to see if we have data in the IPC_M_DATA_SEND buffer. */
    106         if (call->buffer)
    107                 free(call->buffer);
    108         slab_free(ipc_call_slab, call);
     125        ipc_call_release(call);
    109126}
    110127
     
    120137        irq_spinlock_initialize(&box->irq_lock, "ipc.box.irqlock");
    121138        waitq_initialize(&box->wq);
    122         link_initialize(&box->sync_box_link);
    123139        list_initialize(&box->connected_phones);
    124140        list_initialize(&box->calls);
     
    134150 * @param phone Initialized phone structure.
    135151 * @param box   Initialized answerbox structure.
    136  *
    137  */
    138 void ipc_phone_connect(phone_t *phone, answerbox_t *box)
    139 {
     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
    140158        mutex_lock(&phone->lock);
    141        
    142         phone->state = IPC_PHONE_CONNECTED;
    143         phone->callee = box;
    144        
    145159        irq_spinlock_lock(&box->lock, true);
    146         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
    147168        irq_spinlock_unlock(&box->lock, true);
    148        
    149169        mutex_unlock(&phone->lock);
     170
     171        return active;
    150172}
    151173
     
    153175 *
    154176 * @param phone Phone structure to be initialized.
    155  *
    156  */
    157 void ipc_phone_init(phone_t *phone)
     177 * @param caller Owning task.
     178 *
     179 */
     180void ipc_phone_init(phone_t *phone, task_t *caller)
    158181{
    159182        mutex_initialize(&phone->lock, MUTEX_PASSIVE);
     183        phone->caller = caller;
    160184        phone->callee = NULL;
    161185        phone->state = IPC_PHONE_FREE;
     
    163187}
    164188
    165 /** Helper function to facilitate synchronous calls.
    166  *
    167  * @param phone   Destination kernel phone structure.
    168  * @param request Call structure with request.
    169  *
    170  * @return EOK on success or EINTR if the sleep was interrupted.
    171  *
    172  */
    173 int ipc_call_sync(phone_t *phone, call_t *request)
    174 {
    175         answerbox_t *sync_box = slab_alloc(ipc_answerbox_slab, 0);
    176         ipc_answerbox_init(sync_box, TASK);
    177        
    178         /*
    179          * Put the answerbox on the TASK's list of synchronous answerboxes so
    180          * that it can be cleaned up if the call is interrupted.
    181          */
    182         irq_spinlock_lock(&TASK->lock, true);
    183         list_append(&sync_box->sync_box_link, &TASK->sync_boxes);
    184         irq_spinlock_unlock(&TASK->lock, true);
    185        
    186         /* We will receive data in a special box. */
    187         request->callerbox = sync_box;
    188        
    189         ipc_call(phone, request);
    190         if (!ipc_wait_for_call(sync_box, SYNCH_NO_TIMEOUT,
    191             SYNCH_FLAGS_INTERRUPTIBLE)) {
    192                 /* The answerbox and the call will be freed by ipc_cleanup(). */
    193                 return EINTR;
    194         }
    195        
    196         /*
    197          * The answer arrived without interruption so we can remove the
    198          * answerbox from the TASK's list of synchronous answerboxes.
    199          */
    200         irq_spinlock_lock(&TASK->lock, true);
    201         list_remove(&sync_box->sync_box_link);
    202         irq_spinlock_unlock(&TASK->lock, true);
    203        
    204         slab_free(ipc_answerbox_slab, sync_box);
    205         return EOK;
    206 }
    207 
    208189/** Answer a message which was not dispatched and is not listed in any queue.
    209190 *
     
    212193 *
    213194 */
    214 static void _ipc_answer_free_call(call_t *call, bool selflocked)
    215 {
    216         answerbox_t *callerbox = call->callerbox;
    217         bool do_lock = ((!selflocked) || callerbox != (&TASK->answerbox));
    218        
     195void _ipc_answer_free_call(call_t *call, bool selflocked)
     196{
    219197        /* Count sent answer */
    220198        irq_spinlock_lock(&TASK->lock, true);
    221199        TASK->ipc_info.answer_sent++;
    222200        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));
    223224       
    224225        call->flags |= IPC_CALL_ANSWERED;
    225226       
    226         if (call->flags & IPC_CALL_FORWARDED) {
    227                 if (call->caller_phone) {
    228                         /* Demasquerade the caller phone. */
    229                         call->data.phone = call->caller_phone;
    230                 }
    231         }
    232 
    233227        call->data.task_id = TASK->taskid;
    234228       
     
    236230                irq_spinlock_lock(&callerbox->lock, true);
    237231       
    238         list_append(&call->link, &callerbox->answers);
     232        list_append(&call->ab_link, &callerbox->answers);
    239233       
    240234        if (do_lock)
     
    254248        /* Remove from active box */
    255249        irq_spinlock_lock(&box->lock, true);
    256         list_remove(&call->link);
     250        list_remove(&call->ab_link);
    257251        irq_spinlock_unlock(&box->lock, true);
    258252       
    259253        /* Send back answer */
    260254        _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;
    261272}
    262273
     
    273284void ipc_backsend_err(phone_t *phone, call_t *call, sysarg_t err)
    274285{
    275         call->data.phone = phone;
    276         atomic_inc(&phone->active_calls);
     286        _ipc_call_actions_internal(phone, call);
    277287        IPC_SET_RETVAL(call->data, err);
    278288        _ipc_answer_free_call(call, false);
     
    288298static void _ipc_call(phone_t *phone, answerbox_t *box, call_t *call)
    289299{
     300        task_t *caller = phone->caller;
     301
    290302        /* Count sent ipc call */
    291         irq_spinlock_lock(&TASK->lock, true);
    292         TASK->ipc_info.call_sent++;
    293         irq_spinlock_unlock(&TASK->lock, true);
    294        
    295         if (!(call->flags & IPC_CALL_FORWARDED)) {
    296                 atomic_inc(&phone->active_calls);
    297                 call->data.phone = phone;
    298                 call->data.task_id = TASK->taskid;
    299         }
     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);
    300309       
    301310        irq_spinlock_lock(&box->lock, true);
    302         list_append(&call->link, &box->calls);
     311        list_append(&call->ab_link, &box->calls);
    303312        irq_spinlock_unlock(&box->lock, true);
    304313       
     
    320329        if (phone->state != IPC_PHONE_CONNECTED) {
    321330                mutex_unlock(&phone->lock);
    322                 if (call->flags & IPC_CALL_FORWARDED) {
    323                         IPC_SET_RETVAL(call->data, EFORWARD);
    324                         _ipc_answer_free_call(call, false);
    325                 } else {
     331                if (!(call->flags & IPC_CALL_FORWARDED)) {
    326332                        if (phone->state == IPC_PHONE_HUNGUP)
    327333                                ipc_backsend_err(phone, call, EHANGUP);
     
    370376                call_t *call = ipc_call_alloc(0);
    371377                IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
     378                call->request_method = IPC_M_PHONE_HUNGUP;
    372379                call->flags |= IPC_CALL_DISCARD_ANSWER;
    373380                _ipc_call(phone, box, call);
     
    401408        TASK->ipc_info.forwarded++;
    402409        irq_spinlock_pass(&TASK->lock, &oldbox->lock);
    403         list_remove(&call->link);
     410        list_remove(&call->ab_link);
    404411        irq_spinlock_unlock(&oldbox->lock, true);
    405412       
    406413        if (mode & IPC_FF_ROUTE_FROM_ME) {
    407                 if (!call->caller_phone)
    408                         call->caller_phone = call->data.phone;
    409414                call->data.phone = newphone;
    410415                call->data.task_id = TASK->taskid;
     
    451456               
    452457                request = list_get_instance(list_first(&box->irq_notifs),
    453                     call_t, link);
    454                 list_remove(&request->link);
     458                    call_t, ab_link);
     459                list_remove(&request->ab_link);
    455460               
    456461                irq_spinlock_unlock(&box->irq_lock, false);
     
    461466                /* Handle asynchronous answers */
    462467                request = list_get_instance(list_first(&box->answers),
    463                     call_t, link);
    464                 list_remove(&request->link);
    465                 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);
    466471        } else if (!list_empty(&box->calls)) {
    467472                /* Count received call */
     
    470475                /* Handle requests */
    471476                request = list_get_instance(list_first(&box->calls),
    472                     call_t, link);
    473                 list_remove(&request->link);
     477                    call_t, ab_link);
     478                list_remove(&request->ab_link);
    474479               
    475480                /* Append request to dispatch queue */
    476                 list_append(&request->link, &box->dispatched_calls);
     481                list_append(&request->ab_link, &box->dispatched_calls);
    477482        } else {
    478483                /* This can happen regularly after ipc_cleanup */
     
    494499/** Answer all calls from list with EHANGUP answer.
    495500 *
     501 * @param box Answerbox with the list.
    496502 * @param lst Head of the list to be cleaned up.
    497  *
    498  */
    499 void ipc_cleanup_call_list(list_t *lst)
    500 {
     503 */
     504void ipc_cleanup_call_list(answerbox_t *box, list_t *lst)
     505{
     506        irq_spinlock_lock(&box->lock, true);
    501507        while (!list_empty(lst)) {
    502                 call_t *call = list_get_instance(list_first(lst), call_t, link);
    503                 if (call->buffer)
    504                         free(call->buffer);
    505                
    506                 list_remove(&call->link);
    507                
     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;
    508519                IPC_SET_RETVAL(call->data, EHANGUP);
     520                answer_preprocess(call, &old);
    509521                _ipc_answer_free_call(call, true);
    510         }
     522
     523                irq_spinlock_lock(&box->lock, true);
     524        }
     525        irq_spinlock_unlock(&box->lock, true);
    511526}
    512527
     
    546561                        mutex_unlock(&phone->lock);
    547562                        irq_spinlock_unlock(&box->lock, true);
    548                        
     563
     564                        // FIXME: phone can become deallocated at any time now
     565
    549566                        /*
    550567                         * Send one message to the answerbox for each
     
    554571                         */
    555572                        IPC_SET_IMETHOD(call->data, IPC_M_PHONE_HUNGUP);
     573                        call->request_method = IPC_M_PHONE_HUNGUP;
    556574                        call->flags |= IPC_CALL_DISCARD_ANSWER;
    557575                        _ipc_call(phone, box, call);
     
    574592}
    575593
     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
    576717/** Clean up all IPC communication of the current task.
    577718 *
     
    582723void ipc_cleanup(void)
    583724{
     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
    584735        /* Disconnect all our phones ('ipc_phone_hangup') */
    585         size_t i;
    586         for (i = 0; i < IPC_MAX_PHONES; i++)
     736        for (size_t i = 0; i < IPC_MAX_PHONES; i++)
    587737                ipc_phone_hangup(&TASK->phones[i]);
    588738       
     
    602752       
    603753        /* Answer all messages in 'calls' and 'dispatched_calls' queues */
    604         irq_spinlock_lock(&TASK->answerbox.lock, true);
    605         ipc_cleanup_call_list(&TASK->answerbox.dispatched_calls);
    606         ipc_cleanup_call_list(&TASK->answerbox.calls);
    607         irq_spinlock_unlock(&TASK->answerbox.lock, true);
    608        
    609         /* Wait for all answers to interrupted synchronous calls to arrive */
    610         ipl_t ipl = interrupts_disable();
    611         while (!list_empty(&TASK->sync_boxes)) {
    612                 answerbox_t *box = list_get_instance(
    613                     list_first(&TASK->sync_boxes), answerbox_t, sync_box_link);
    614                
    615                 list_remove(&box->sync_box_link);
    616                 call_t *call = ipc_wait_for_call(box, SYNCH_NO_TIMEOUT,
    617                     SYNCH_FLAGS_NONE);
    618                 ipc_call_free(call);
    619                 slab_free(ipc_answerbox_slab, box);
    620         }
    621         interrupts_restore(ipl);
    622        
    623         /* Wait for all answers to asynchronous calls to arrive */
    624         while (true) {
    625                 /*
    626                  * Go through all phones, until they are all FREE
    627                  * Locking is not needed, no one else should modify
    628                  * it when we are in cleanup
    629                  */
    630                 for (i = 0; i < IPC_MAX_PHONES; i++) {
    631                         if (TASK->phones[i].state == IPC_PHONE_HUNGUP &&
    632                             atomic_get(&TASK->phones[i].active_calls) == 0) {
    633                                 TASK->phones[i].state = IPC_PHONE_FREE;
    634                                 TASK->phones[i].callee = NULL;
    635                         }
    636                        
    637                         /*
    638                          * Just for sure, we might have had some
    639                          * IPC_PHONE_CONNECTING phones
    640                          */
    641                         if (TASK->phones[i].state == IPC_PHONE_CONNECTED)
    642                                 ipc_phone_hangup(&TASK->phones[i]);
    643                        
    644                         /*
    645                          * If the hangup succeeded, it has sent a HANGUP
    646                          * message, the IPC is now in HUNGUP state, we
    647                          * wait for the reply to come
    648                          */
    649                        
    650                         if (TASK->phones[i].state != IPC_PHONE_FREE)
    651                                 break;
    652                 }
    653                
    654                 /* Got into cleanup */
    655                 if (i == IPC_MAX_PHONES)
    656                         break;
    657                
    658                 call_t *call = ipc_wait_for_call(&TASK->answerbox, SYNCH_NO_TIMEOUT,
    659                     SYNCH_FLAGS_NONE);
    660                 ASSERT((call->flags & IPC_CALL_ANSWERED) ||
    661                     (call->flags & IPC_CALL_NOTIF));
    662                
    663                 ipc_call_free(call);
    664         }
     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();
    665760}
    666761
     
    674769        ipc_answerbox_slab = slab_cache_create("answerbox_t",
    675770            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        }
    676805}
    677806
     
    747876       
    748877        printf(" --- incomming calls ---\n");
    749         list_foreach(task->answerbox.calls, cur) {
    750                 call_t *call = list_get_instance(cur, call_t, link);
    751                
    752 #ifdef __32_BITS__
    753                 printf("%10p ", call);
    754 #endif
    755                
    756 #ifdef __64_BITS__
    757                 printf("%18p ", call);
    758 #endif
    759                
    760                 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
    761                     " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
    762                     IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
    763                     IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    764                     IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
    765                     call->flags, call->sender->taskid, call->sender->name);
    766         }
    767        
     878        ipc_print_call_list(&task->answerbox.calls);
    768879        printf(" --- dispatched calls ---\n");
    769         list_foreach(task->answerbox.dispatched_calls, cur) {
    770                 call_t *call = list_get_instance(cur, call_t, link);
    771                
    772 #ifdef __32_BITS__
    773                 printf("%10p ", call);
    774 #endif
    775                
    776 #ifdef __64_BITS__
    777                 printf("%18p ", call);
    778 #endif
    779                
    780                 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
    781                     " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
    782                     IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
    783                     IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    784                     IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
    785                     call->flags, call->sender->taskid, call->sender->name);
    786         }
    787        
     880        ipc_print_call_list(&task->answerbox.dispatched_calls);
    788881        printf(" --- incoming answers ---\n");
    789         list_foreach(task->answerbox.answers, cur) {
    790                 call_t *call = list_get_instance(cur, call_t, link);
    791                
    792 #ifdef __32_BITS__
    793                 printf("%10p ", call);
    794 #endif
    795                
    796 #ifdef __64_BITS__
    797                 printf("%18p ", call);
    798 #endif
    799                
    800                 printf("%-8" PRIun " %-6" PRIun " %-6" PRIun " %-6" PRIun
    801                     " %-6" PRIun " %-6" PRIun " %-7x %" PRIu64 " (%s)\n",
    802                     IPC_GET_IMETHOD(call->data), IPC_GET_ARG1(call->data),
    803                     IPC_GET_ARG2(call->data), IPC_GET_ARG3(call->data),
    804                     IPC_GET_ARG4(call->data), IPC_GET_ARG5(call->data),
    805                     call->flags, call->sender->taskid, call->sender->name);
    806         }
     882        ipc_print_call_list(&task->answerbox.answers);
    807883       
    808884        irq_spinlock_unlock(&task->answerbox.lock, false);
  • kernel/generic/src/ipc/ipcrsc.c

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    3939 * when interrupt is detected. The application may provide a simple 'top-half'
    4040 * handler as part of its registration, which can perform simple operations
    41  * (read/write port/memory, add information to notification ipc message).
     41 * (read/write port/memory, add information to notification IPC message).
    4242 *
    4343 * The structure of a notification message is as follows:
    4444 * - IMETHOD: interface and method as registered by
    4545 *            the SYS_IRQ_REGISTER syscall
    46  * - ARG1: payload modified by a 'top-half' handler
    47  * - ARG2: payload modified by a 'top-half' handler
    48  * - ARG3: payload modified by a 'top-half' handler
    49  * - ARG4: payload modified by a 'top-half' handler
    50  * - ARG5: payload modified by a 'top-half' handler
     46 * - ARG1: payload modified by a 'top-half' handler (scratch[1])
     47 * - ARG2: payload modified by a 'top-half' handler (scratch[2])
     48 * - ARG3: payload modified by a 'top-half' handler (scratch[3])
     49 * - ARG4: payload modified by a 'top-half' handler (scratch[4])
     50 * - ARG5: payload modified by a 'top-half' handler (scratch[5])
    5151 * - in_phone_hash: interrupt counter (may be needed to assure correct order
    5252 *                  in multithreaded drivers)
     
    8787static void ranges_unmap(irq_pio_range_t *ranges, size_t rangecount)
    8888{
    89         size_t i;
    90 
    91         for (i = 0; i < rangecount; i++) {
     89        for (size_t i = 0; i < rangecount; i++) {
    9290#ifdef IO_SPACE_BOUNDARY
    9391                if ((void *) ranges[i].base >= IO_SPACE_BOUNDARY)
     
    10098    irq_cmd_t *cmds, size_t cmdcount)
    10199{
    102         uintptr_t *pbase;
    103         size_t i, j;
    104 
    105100        /* Copy the physical base addresses aside. */
    106         pbase = malloc(rangecount * sizeof(uintptr_t), 0);
    107         for (i = 0; i < rangecount; i++)
     101        uintptr_t *pbase = malloc(rangecount * sizeof(uintptr_t), 0);
     102        for (size_t i = 0; i < rangecount; i++)
    108103                pbase[i] = ranges[i].base;
    109 
     104       
    110105        /* Map the PIO ranges into the kernel virtual address space. */
    111         for (i = 0; i < rangecount; i++) {
     106        for (size_t i = 0; i < rangecount; i++) {
    112107#ifdef IO_SPACE_BOUNDARY
    113108                if ((void *) ranges[i].base < IO_SPACE_BOUNDARY)
     
    122117                }
    123118        }
    124 
     119       
    125120        /* Rewrite the pseudocode addresses from physical to kernel virtual. */
    126         for (i = 0; i < cmdcount; i++) {
     121        for (size_t i = 0; i < cmdcount; i++) {
    127122                uintptr_t addr;
    128123                size_t size;
    129 
     124               
    130125                /* Process only commands that use an address. */
    131126                switch (cmds[i].cmd) {
    132127                case CMD_PIO_READ_8:
    133                 case CMD_PIO_WRITE_8:
    134                 case CMD_PIO_WRITE_A_8:
     128                case CMD_PIO_WRITE_8:
     129                case CMD_PIO_WRITE_A_8:
    135130                        size = 1;
    136131                        break;
    137                 case CMD_PIO_READ_16:
    138                 case CMD_PIO_WRITE_16:
    139                 case CMD_PIO_WRITE_A_16:
     132                case CMD_PIO_READ_16:
     133                case CMD_PIO_WRITE_16:
     134                case CMD_PIO_WRITE_A_16:
    140135                        size = 2;
    141136                        break;
    142                 case CMD_PIO_READ_32:
    143                 case CMD_PIO_WRITE_32:
    144                 case CMD_PIO_WRITE_A_32:
     137                case CMD_PIO_READ_32:
     138                case CMD_PIO_WRITE_32:
     139                case CMD_PIO_WRITE_A_32:
    145140                        size = 4;
    146141                        break;
     
    149144                        continue;
    150145                }
    151 
     146               
    152147                addr = (uintptr_t) cmds[i].addr;
    153148               
     149                size_t j;
    154150                for (j = 0; j < rangecount; j++) {
    155 
    156151                        /* Find the matching range. */
    157152                        if (!iswithin(pbase[j], ranges[j].size, addr, size))
    158153                                continue;
    159 
     154                       
    160155                        /* Switch the command to a kernel virtual address. */
    161156                        addr -= pbase[j];
    162157                        addr += ranges[j].base;
    163 
     158                       
    164159                        cmds[i].addr = (void *) addr;
    165160                        break;
    166161                }
    167 
     162               
    168163                if (j == rangecount) {
    169164                        /*
     
    176171                }
    177172        }
    178 
     173       
    179174        free(pbase);
     175        return EOK;
     176}
     177
     178/** Statically check the top-half pseudocode
     179 *
     180 * Check the top-half pseudocode for invalid or unsafe
     181 * constructs.
     182 *
     183 */
     184static int code_check(irq_cmd_t *cmds, size_t cmdcount)
     185{
     186        for (size_t i = 0; i < cmdcount; i++) {
     187                /*
     188                 * Check for accepted ranges.
     189                 */
     190                if (cmds[i].cmd >= CMD_LAST)
     191                        return EINVAL;
     192               
     193                if (cmds[i].srcarg >= IPC_CALL_LEN)
     194                        return EINVAL;
     195               
     196                if (cmds[i].dstarg >= IPC_CALL_LEN)
     197                        return EINVAL;
     198               
     199                switch (cmds[i].cmd) {
     200                case CMD_PREDICATE:
     201                        /*
     202                         * Check for control flow overflow.
     203                         * Note that jumping just beyond the last
     204                         * command is a correct behaviour.
     205                         */
     206                        if (i + cmds[i].value > cmdcount)
     207                                return EINVAL;
     208                       
     209                        break;
     210                default:
     211                        break;
     212                }
     213        }
     214       
    180215        return EOK;
    181216}
     
    207242        irq_pio_range_t *ranges = NULL;
    208243        irq_cmd_t *cmds = NULL;
    209 
     244       
    210245        irq_code_t *code = malloc(sizeof(*code), 0);
    211246        int rc = copy_from_uspace(code, ucode, sizeof(*code));
     
    222257        if (rc != EOK)
    223258                goto error;
    224 
     259       
    225260        cmds = malloc(sizeof(code->cmds[0]) * code->cmdcount, 0);
    226261        rc = copy_from_uspace(cmds, code->cmds,
     
    228263        if (rc != EOK)
    229264                goto error;
    230 
     265       
     266        rc = code_check(cmds, code->cmdcount);
     267        if (rc != EOK)
     268                goto error;
     269       
    231270        rc = ranges_map_and_apply(ranges, code->rangecount, cmds,
    232271            code->cmdcount);
    233272        if (rc != EOK)
    234273                goto error;
    235 
     274       
    236275        code->ranges = ranges;
    237276        code->cmds = cmds;
    238 
     277       
    239278        return code;
    240 
     279       
    241280error:
    242281        if (cmds)
    243282                free(cmds);
     283       
    244284        if (ranges)
    245285                free(ranges);
     286       
    246287        free(code);
    247288        return NULL;
     
    250291/** Register an answerbox as a receiving end for IRQ notifications.
    251292 *
    252  * @param box           Receiving answerbox.
    253  * @param inr           IRQ number.
    254  * @param devno         Device number.
    255  * @param imethod       Interface and method to be associated with the
    256  *                      notification.
    257  * @param ucode         Uspace pointer to top-half pseudocode.
    258  * @return              EOK on success or a negative error code.
     293 * @param box     Receiving answerbox.
     294 * @param inr     IRQ number.
     295 * @param devno   Device number.
     296 * @param imethod Interface and method to be associated with the
     297 *                notification.
     298 * @param ucode   Uspace pointer to top-half pseudocode.
     299 *
     300 * @return EOK on success or a negative error code.
    259301 *
    260302 */
     
    266308                (sysarg_t) devno
    267309        };
    268 
     310       
    269311        if ((inr < 0) || (inr > last_inr))
    270312                return ELIMIT;
     
    329371/** Unregister task from IRQ notification.
    330372 *
    331  * @param box           Answerbox associated with the notification.
    332  * @param inr           IRQ number.
    333  * @param devno         Device number.
    334  * @return              EOK on success or a negative error code.
     373 * @param box   Answerbox associated with the notification.
     374 * @param inr   IRQ number.
     375 * @param devno Device number.
     376 *
     377 * @return EOK on success or a negative error code.
     378 *
    335379 */
    336380int ipc_irq_unregister(answerbox_t *box, inr_t inr, devno_t devno)
     
    340384                (sysarg_t) devno
    341385        };
    342 
     386       
    343387        if ((inr < 0) || (inr > last_inr))
    344388                return ELIMIT;
     
    436480                /* Remove from the hash table. */
    437481                hash_table_remove(&irq_uspace_hash_table, key, 2);
    438 
     482               
    439483                /*
    440484                 * Release both locks so that we can free the pseudo code.
     
    442486                irq_spinlock_unlock(&box->irq_lock, false);
    443487                irq_spinlock_unlock(&irq_uspace_hash_table_lock, true);
    444 
     488               
    445489                code_free(irq->notif_cfg.code);
    446490                free(irq);
     
    466510{
    467511        irq_spinlock_lock(&irq->notif_cfg.answerbox->irq_lock, false);
    468         list_append(&call->link, &irq->notif_cfg.answerbox->irq_notifs);
     512        list_append(&call->ab_link, &irq->notif_cfg.answerbox->irq_notifs);
    469513        irq_spinlock_unlock(&irq->notif_cfg.answerbox->irq_lock, false);
    470514       
     
    492536       
    493537        for (size_t i = 0; i < code->cmdcount; i++) {
    494                 uint32_t dstval;
    495                
    496538                uintptr_t srcarg = code->cmds[i].srcarg;
    497539                uintptr_t dstarg = code->cmds[i].dstarg;
    498540               
    499                 if (srcarg >= IPC_CALL_LEN)
    500                         break;
    501                
    502                 if (dstarg >= IPC_CALL_LEN)
    503                         break;
    504        
    505541                switch (code->cmds[i].cmd) {
    506542                case CMD_PIO_READ_8:
    507                         dstval = pio_read_8((ioport8_t *) code->cmds[i].addr);
    508                         if (dstarg)
    509                                 scratch[dstarg] = dstval;
     543                        scratch[dstarg] =
     544                            pio_read_8((ioport8_t *) code->cmds[i].addr);
    510545                        break;
    511546                case CMD_PIO_READ_16:
    512                         dstval = pio_read_16((ioport16_t *) code->cmds[i].addr);
    513                         if (dstarg)
    514                                 scratch[dstarg] = dstval;
     547                        scratch[dstarg] =
     548                            pio_read_16((ioport16_t *) code->cmds[i].addr);
    515549                        break;
    516550                case CMD_PIO_READ_32:
    517                         dstval = pio_read_32((ioport32_t *) code->cmds[i].addr);
    518                         if (dstarg)
    519                                 scratch[dstarg] = dstval;
     551                        scratch[dstarg] =
     552                            pio_read_32((ioport32_t *) code->cmds[i].addr);
    520553                        break;
    521554                case CMD_PIO_WRITE_8:
     
    532565                        break;
    533566                case CMD_PIO_WRITE_A_8:
    534                         if (srcarg) {
    535                                 pio_write_8((ioport8_t *) code->cmds[i].addr,
    536                                     (uint8_t) scratch[srcarg]);
    537                         }
     567                        pio_write_8((ioport8_t *) code->cmds[i].addr,
     568                            (uint8_t) scratch[srcarg]);
    538569                        break;
    539570                case CMD_PIO_WRITE_A_16:
    540                         if (srcarg) {
    541                                 pio_write_16((ioport16_t *) code->cmds[i].addr,
    542                                     (uint16_t) scratch[srcarg]);
    543                         }
     571                        pio_write_16((ioport16_t *) code->cmds[i].addr,
     572                            (uint16_t) scratch[srcarg]);
    544573                        break;
    545574                case CMD_PIO_WRITE_A_32:
    546                         if (srcarg) {
    547                                 pio_write_32((ioport32_t *) code->cmds[i].addr,
    548                                     (uint32_t) scratch[srcarg]);
    549                         }
    550                         break;
    551                 case CMD_BTEST:
    552                         if ((srcarg) && (dstarg)) {
    553                                 dstval = scratch[srcarg] & code->cmds[i].value;
    554                                 scratch[dstarg] = dstval;
    555                         }
     575                        pio_write_32((ioport32_t *) code->cmds[i].addr,
     576                            (uint32_t) scratch[srcarg]);
     577                        break;
     578                case CMD_LOAD:
     579                        scratch[dstarg] = code->cmds[i].value;
     580                        break;
     581                case CMD_AND:
     582                        scratch[dstarg] = scratch[srcarg] &
     583                            code->cmds[i].value;
    556584                        break;
    557585                case CMD_PREDICATE:
    558                         if ((srcarg) && (!scratch[srcarg])) {
     586                        if (scratch[srcarg] == 0)
    559587                                i += code->cmds[i].value;
    560                                 continue;
    561                         }
     588                       
    562589                        break;
    563590                case CMD_ACCEPT:
     
    582609{
    583610        ASSERT(irq);
    584 
     611       
    585612        ASSERT(interrupts_disabled());
    586613        ASSERT(irq_spinlock_locked(&irq->lock));
  • kernel/generic/src/ipc/kbox.c

    rde73242 refdfebc  
    4848{
    4949        /*
     50         * Not really needed, just to be consistent with the meaning of
     51         * answerbox_t.active.
     52         */
     53        irq_spinlock_lock(&TASK->kb.box.lock, true);
     54        TASK->kb.box.active = false;
     55        irq_spinlock_unlock(&TASK->kb.box.lock, true);
     56
     57        /*
    5058         * Only hold kb.cleanup_lock while setting kb.finished -
    5159         * this is enough.
     
    8896       
    8997        /* Answer all messages in 'calls' and 'dispatched_calls' queues. */
    90         irq_spinlock_lock(&TASK->kb.box.lock, true);
    91         ipc_cleanup_call_list(&TASK->kb.box.dispatched_calls);
    92         ipc_cleanup_call_list(&TASK->kb.box.calls);
    93         irq_spinlock_unlock(&TASK->kb.box.lock, true);
     98        ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.calls);
     99        ipc_cleanup_call_list(&TASK->kb.box, &TASK->kb.box.dispatched_calls);
    94100}
    95101
     
    162168        while (!done) {
    163169                call_t *call = ipc_wait_for_call(&TASK->kb.box, SYNCH_NO_TIMEOUT,
    164                         SYNCH_FLAGS_NONE);
     170                    SYNCH_FLAGS_NONE);
    165171               
    166172                if (call == NULL)
     
    236242       
    237243        /* Connect the newly allocated phone to the kbox */
    238         ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
     244        (void) ipc_phone_connect(&TASK->phones[newphid], &task->kb.box);
    239245       
    240246        if (task->kb.thread != NULL) {
  • kernel/generic/src/ipc/sysipc.c

    rde73242 refdfebc  
    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;
    616 }
    617 
    618 /** Make a fast call over IPC, wait for reply and return to user.
    619  *
    620  * This function can handle only three arguments of payload, but is faster than
    621  * the generic function (i.e. sys_ipc_call_sync_slow()).
    622  *
    623  * @param phoneid Phone handle for the call.
    624  * @param imethod Interface and method of the call.
    625  * @param arg1    Service-defined payload argument.
    626  * @param arg2    Service-defined payload argument.
    627  * @param arg3    Service-defined payload argument.
    628  * @param data    Address of user-space structure where the reply call will
    629  *                be stored.
    630  *
    631  * @return 0 on success.
    632  * @return ENOENT if there is no such phone handle.
    633  *
    634  */
    635 sysarg_t sys_ipc_call_sync_fast(sysarg_t phoneid, sysarg_t imethod,
    636     sysarg_t arg1, sysarg_t arg2, sysarg_t arg3, ipc_data_t *data)
    637 {
    638         phone_t *phone;
    639         if (phone_get(phoneid, &phone) != EOK)
    640                 return ENOENT;
    641        
    642         call_t *call = ipc_call_alloc(0);
    643         IPC_SET_IMETHOD(call->data, imethod);
    644         IPC_SET_ARG1(call->data, arg1);
    645         IPC_SET_ARG2(call->data, arg2);
    646         IPC_SET_ARG3(call->data, arg3);
    647        
    648         /*
    649          * To achieve deterministic behavior, zero out arguments that are beyond
    650          * the limits of the fast version.
    651          */
    652         IPC_SET_ARG4(call->data, 0);
    653         IPC_SET_ARG5(call->data, 0);
    654        
    655         int res = request_preprocess(call, phone);
    656         int rc;
    657        
    658         if (!res) {
    659 #ifdef CONFIG_UDEBUG
    660                 udebug_stoppable_begin();
    661 #endif
    662                 rc = ipc_call_sync(phone, call);
    663 #ifdef CONFIG_UDEBUG
    664                 udebug_stoppable_end();
    665 #endif
    666                
    667                 if (rc != EOK) {
    668                         /* The call will be freed by ipc_cleanup(). */
    669                         return rc;
    670                 }
    671                
    672                 process_answer(call);
    673         } else
    674                 IPC_SET_RETVAL(call->data, res);
    675        
    676         rc = STRUCT_TO_USPACE(&data->args, &call->data.args);
    677         ipc_call_free(call);
    678         if (rc != 0)
    679                 return rc;
    680        
    681         return 0;
    682 }
    683 
    684 /** Make a synchronous IPC call allowing to transmit the entire payload.
    685  *
    686  * @param phoneid Phone handle for the call.
    687  * @param request User-space address of call data with the request.
    688  * @param reply   User-space address of call data where to store the
    689  *                answer.
    690  *
    691  * @return Zero on success or an error code.
    692  *
    693  */
    694 sysarg_t sys_ipc_call_sync_slow(sysarg_t phoneid, ipc_data_t *request,
    695     ipc_data_t *reply)
    696 {
    697         phone_t *phone;
    698         if (phone_get(phoneid, &phone) != EOK)
    699                 return ENOENT;
    700        
    701         call_t *call = ipc_call_alloc(0);
    702         int rc = copy_from_uspace(&call->data.args, &request->args,
    703             sizeof(call->data.args));
    704         if (rc != 0) {
    705                 ipc_call_free(call);
    706                 return (sysarg_t) rc;
    707         }
    708        
    709         int res = request_preprocess(call, phone);
    710        
    711         if (!res) {
    712 #ifdef CONFIG_UDEBUG
    713                 udebug_stoppable_begin();
    714 #endif
    715                 rc = ipc_call_sync(phone, call);
    716 #ifdef CONFIG_UDEBUG
    717                 udebug_stoppable_end();
    718 #endif
    719                
    720                 if (rc != EOK) {
    721                         /* The call will be freed by ipc_cleanup(). */
    722                         return rc;
    723                 }
    724                
    725                 process_answer(call);
    726         } else
    727                 IPC_SET_RETVAL(call->data, res);
    728        
    729         rc = STRUCT_TO_USPACE(&reply->args, &call->data.args);
    730         ipc_call_free(call);
    731         if (rc != 0)
    732                 return rc;
    733        
    734         return 0;
     258        return SYSIPC_OP(request_process, call, box);
    735259}
    736260
     
    864388{
    865389        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
    866396        if (!call)
    867397                return ENOENT;
    868        
     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
    869412        call->flags |= IPC_CALL_FORWARDED;
    870        
    871         phone_t *phone;
    872         if (phone_get(phoneid, &phone) != EOK) {
    873                 IPC_SET_RETVAL(call->data, EFORWARD);
    874                 ipc_answer(&TASK->answerbox, call);
    875                 return ENOENT;
    876         }
    877        
    878         if (!method_is_forwardable(IPC_GET_IMETHOD(call->data))) {
    879                 IPC_SET_RETVAL(call->data, EFORWARD);
    880                 ipc_answer(&TASK->answerbox, call);
    881                 return EPERM;
    882         }
    883413       
    884414        /*
     
    916446        }
    917447       
    918         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;
    919465}
    920466
  • kernel/generic/src/lib/str.c

    rde73242 refdfebc  
    456456 *
    457457 * Do a char-by-char comparison of two NULL-terminated strings.
    458  * The strings are considered equal iff they consist of the same
    459  * characters on the minimum of their lengths.
     458 * The strings are considered equal iff their length is equal
     459 * and both strings consist of the same sequence of characters.
     460 *
     461 * A string S1 is less than another string S2 if it has a character with
     462 * lower value at the first character position where the strings differ.
     463 * If the strings differ in length, the shorter one is treated as if
     464 * padded by characters with a value of zero.
    460465 *
    461466 * @param s1 First string to compare.
    462467 * @param s2 Second string to compare.
    463468 *
    464  * @return 0 if the strings are equal, -1 if first is smaller,
    465  *         1 if second smaller.
     469 * @return 0 if the strings are equal, -1 if the first is less than the second,
     470 *         1 if the second is less than the first.
    466471 *
    467472 */
     
    494499 *
    495500 * Do a char-by-char comparison of two NULL-terminated strings.
    496  * The strings are considered equal iff they consist of the same
    497  * characters on the minimum of their lengths and the length limit.
     501 * The strings are considered equal iff
     502 * min(str_length(s1), max_len) == min(str_length(s2), max_len)
     503 * and both strings consist of the same sequence of characters,
     504 * up to max_len characters.
     505 *
     506 * A string S1 is less than another string S2 if it has a character with
     507 * lower value at the first character position where the strings differ.
     508 * If the strings differ in length, the shorter one is treated as if
     509 * padded by characters with a value of zero. Only the first max_len
     510 * characters are considered.
    498511 *
    499512 * @param s1      First string to compare.
     
    501514 * @param max_len Maximum number of characters to consider.
    502515 *
    503  * @return 0 if the strings are equal, -1 if first is smaller,
    504  *         1 if second smaller.
     516 * @return 0 if the strings are equal, -1 if the first is less than the second,
     517 *         1 if the second is less than the first.
    505518 *
    506519 */
  • kernel/generic/src/main/kinit.c

    rde73242 refdfebc  
    6969#include <str.h>
    7070#include <sysinfo/stats.h>
     71#include <sysinfo/sysinfo.h>
    7172#include <align.h>
    7273
     
    179180        program_t programs[CONFIG_INIT_TASKS];
    180181       
     182        // FIXME: do not propagate arguments through sysinfo
     183        // but pass them directly to the tasks
     184        for (i = 0; i < init.cnt; i++) {
     185                const char *arguments = init.tasks[i].arguments;
     186                if (str_length(arguments) == 0)
     187                        continue;
     188                if (str_length(init.tasks[i].name) == 0)
     189                        continue;
     190                size_t arguments_size = str_size(arguments);
     191
     192                void *arguments_copy = malloc(arguments_size, 0);
     193                if (arguments_copy == NULL)
     194                        continue;
     195                memcpy(arguments_copy, arguments, arguments_size);
     196
     197                char item_name[CONFIG_TASK_NAME_BUFLEN + 15];
     198                snprintf(item_name, CONFIG_TASK_NAME_BUFLEN + 15,
     199                    "init_args.%s", init.tasks[i].name);
     200
     201                sysinfo_set_item_data(item_name, NULL, arguments_copy, arguments_size);
     202        }
     203
    181204        for (i = 0; i < init.cnt; i++) {
    182205                if (init.tasks[i].paddr % FRAME_SIZE) {
  • kernel/generic/src/mm/as.c

    rde73242 refdfebc  
    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

    rde73242 refdfebc  
    156156       
    157157        list_initialize(&task->threads);
    158         list_initialize(&task->sync_boxes);
    159158       
    160159        ipc_answerbox_init(&task->answerbox, task);
     
    162161        size_t i;
    163162        for (i = 0; i < IPC_MAX_PHONES; i++)
    164                 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);
    165167       
    166168#ifdef CONFIG_UDEBUG
     
    204206        event_task_init(task);
    205207       
     208        task->answerbox.active = true;
     209
    206210#ifdef CONFIG_UDEBUG
    207211        /* Init debugging stuff */
     
    209213       
    210214        /* Init kbox stuff */
     215        task->kb.box.active = true;
    211216        task->kb.finished = false;
    212217#endif
     
    214219        if ((ipc_phone_0) &&
    215220            (container_check(ipc_phone_0->task->container, task->container)))
    216                 ipc_phone_connect(&task->phones[0], ipc_phone_0);
     221                (void) ipc_phone_connect(&task->phones[0], ipc_phone_0);
    217222       
    218223        btree_create(&task->futexes);
  • kernel/generic/src/syscall/syscall.c

    rde73242 refdfebc  
    151151       
    152152        /* IPC related syscalls. */
    153         (syshandler_t) sys_ipc_call_sync_fast,
    154         (syshandler_t) sys_ipc_call_sync_slow,
    155153        (syshandler_t) sys_ipc_call_async_fast,
    156154        (syshandler_t) sys_ipc_call_async_slow,
Note: See TracChangeset for help on using the changeset viewer.