/* * Userspace system call interface. * * Copyright (C) 2007 - 2009 Bahadir Balban */ #include #include #include #include #include INC_GLUE(message.h) /* Old macro */ #if 0 .macro utcb_address rx ldr \rx, =utcb .endm #endif /* New macro does double dereference */ .macro utcb_address rx ldr \rx, =kip_utcb_ref @ First get pointer to utcb pointer in KIP ldr \rx, [\rx] @ Get pointer to UTCB address from UTCB pointer in KIP ldr \rx, [\rx] @ Get the utcb address .endm BEGIN_PROC(l4_thread_switch) ldr r12, =__l4_thread_switch ldr pc, [r12] @ Jump into the SWI. Kernel returns to LR_USR, which is the caller. END_PROC(l4_thread_switch) /* * The syscall returns process ids. This function saves the returned values in the * arguments passed by reference. @r0 = struct task_ids * */ BEGIN_PROC(l4_getid) ldr r12, =__l4_getid @ See l4_kdata_read for why its so simple. ldr pc, [r12] @ Return. END_PROC(l4_getid) /* * For clone() we need special assembler handling * Same signature as ipc(): @r0 = to, @r1 = from @r2 = flags * * NOTE: Note that this breaks l4 system call interface, * this should be moved elsewhere and modified using existing l4 mechanisms. */ BEGIN_PROC(arch_clone) stmfd sp!, {r4-r8,lr} @ Save context. utcb_address r12 @ Get utcb address. ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5 ldr r12, =__l4_ipc mov lr, pc ldr pc, [r12] @ Perform the ipc() /* * At this moment: * - MR_RETURN tells us whether we are parent or child (or have failed). * - Child has new SP set, with |func_ptr|arg1|{End of stack}SP<-| on stack. * - Child needs exit logic when its function is finished. */ cmp r0, #0 @ Check ipc success blt ipc_failed cmp MR_RETURN_REGISTER, #0 @ Check ipc return register MR_RETURN. blt clone_failed @ Ipc was ok but clone() failed. bgt parent_return @ It has child pid, goto parent return. child: ldr r0, [sp, #-4]! @ Load child's first argument. mov lr, pc @ Save return address ldr pc, [sp, #-4]! @ Load function pointer from stack child_exit: b child_exit @ We infinitely loop for now. @ Return with normal ipc return sequence parent_return: clone_failed: ipc_failed: utcb_address r12 @ Get utcb stmia r12, {r3-r8} @ Store mrs. ldmfd sp!, {r4-r8,pc} @ Return restoring pc and context. END_PROC(arch_clone) /* * Inter-process communication. Loads message registers as arguments before the call, * and stores them as results after the call. @r0 = to, @r1 = from. */ BEGIN_PROC(l4_ipc) stmfd sp!, {r4-r8,lr} @ Save context. utcb_address r12 @ Get utcb address. ldmia r12!, {r3-r8} @ Load 6 Message registers from utcb. MR0-MR5 ldr r12, =__l4_ipc mov lr, pc ldr pc, [r12] utcb_address r12 @ Get utcb address. stmia r12, {r3-r8} @ Store 6 Message registers to utcb. MR0-MR5 ldmfd sp!, {r4-r8,pc} @ Return restoring pc, and context. END_PROC(l4_ipc) /* * System call that maps an area of memory into the given address space. * @r0 = physical address, @r1 = virtual address, @r2 = map size in pages, * @r3 = map flags, @r4 = The tgid of the address space to map. */ BEGIN_PROC(l4_map) stmfd sp!, {r4, lr} ldr r4, [sp, #8] @ FIXME: Is this right? ldr r12, =__l4_map mov lr, pc @ We must return here to restore r4. ldr pc, [r12] ldmfd sp!, {r4, pc} END_PROC(l4_map) /* * Reads/manipulates capabilities of a thread, particularly a pager. * @r0 = request type, @r1 = request flags, * @r2 = capid, @r3 = target thread id, @r4 = io buffer ptr */ BEGIN_PROC(l4_capability_control) stmfd sp!, {r4, lr} ldr r4, [sp, #8] @ FIXME: Is this right? ldr r12, =__l4_capability_control mov lr, pc @ We must return here to restore r4. ldr pc, [r12] ldmfd sp!, {r4, pc} END_PROC(l4_capability_control) /* * System call that unmaps an area of memory into the given address space. * @r0 = virtual, @r1 = pages, @r2 = tid of address space to unmap */ BEGIN_PROC(l4_unmap) stmfd sp!, {lr} ldr r12, =__l4_unmap mov lr, pc ldr pc, [r12] ldmfd sp!, {pc} @ Restore original lr and return. END_PROC(l4_unmap) /* * System call that controls containers and their parameters. * @r0 = request type, @r1 = request flags, @r2 = io buffer ptr */ BEGIN_PROC(l4_container_control) stmfd sp!, {lr} ldr r12, =__l4_container_control mov lr, pc ldr pc, [r12] ldmfd sp!, {pc} @ Restore original lr and return. END_PROC(l4_container_control) /* * System call that gets or sets the time info structure. * @r0 = ptr to time structure @r1 = set or get. set = 1, get = 0. */ BEGIN_PROC(l4_time) stmfd sp!, {lr} ldr r12, =__l4_time mov lr, pc ldr pc, [r12] ldmfd sp!, {pc} @ Restore original lr and return. END_PROC(l4_time) /* * System call that controls thread creation, destruction and modification. * @r0 = thread action, @r1 = &ids, @r2 = utcb address */ BEGIN_PROC(l4_thread_control) stmfd sp!, {lr} ldr r12, =__l4_thread_control mov lr, pc ldr pc, [r12] ldmfd sp!, {pc} @ Restore original lr and return. END_PROC(l4_thread_control) /* * System call that modifies ipc blocked sender lists of receivers. * @r0 = Action (e.g. block/unblock), @r1 = sender id, @r2 = sender tag */ BEGIN_PROC(l4_ipc_control) stmfd sp!, {lr} ldr r12, =__l4_ipc_control mov lr, pc ldr pc, [r12] ldmfd sp!, {pc} @ Restore original lr and return. END_PROC(l4_ipc_control) /* * Manipulates address spaces, e.g. sets up shared memory areas between threads * @r0 = operation code, @r1 = operation flags, @r2 = An id (irqnum, or capid) */ BEGIN_PROC(l4_irq_control) stmfd sp!, {lr} ldr r12, =__l4_irq_control mov lr, pc ldr pc, [r12] ldmfd sp!, {pc} @ Restore original lr and return. END_PROC(l4_irq_control) /* * Locks/unlocks a userspace mutex. * @r0 = mutex virtual address, @r1 = mutex operation code */ BEGIN_PROC(l4_mutex_control) stmfd sp!, {lr} ldr r12, =__l4_mutex_control mov lr, pc ldr pc, [r12] ldmfd sp!, {pc} @ Restore original lr and return. END_PROC(l4_mutex_control) /* * Sets registers of a thread and its pager. * @r0 = ptr to exregs_data structure, @r1 = tid of thread. */ BEGIN_PROC(l4_exchange_registers) stmfd sp!, {lr} ldr r12, =__l4_exchange_registers mov lr, pc ldr pc, [r12] ldmfd sp!, {pc} @ Restore original lr and return. END_PROC(l4_exchange_registers)