From 701b9bf5600d7f6dd70c7f1f096e4da88e204217 Mon Sep 17 00:00:00 2001 From: Florian Lukas <florian.lukas@gmail.com> Date: Thu, 13 Feb 2014 15:47:36 +0100 Subject: [PATCH] arch: syscalls support up to 3 parameters syscall() now supports 0-3 parameters, which are all passed in registers. The option to execute the syscall directly in the IRQ handler has become a template parameter. Change-Id: Id939c3317d4eb263098f443b63827b624b4c215f --- arch/i386/dispatch.h | 2 +- arch/i386/machine.cc | 2 +- arch/i386/syscall.cc | 14 ++++++++------ arch/i386/syscall.h | 39 +++++++++++++++++++++++++++++++-------- 4 files changed, 41 insertions(+), 16 deletions(-) diff --git a/arch/i386/dispatch.h b/arch/i386/dispatch.h index 2237d61..be55edd 100644 --- a/arch/i386/dispatch.h +++ b/arch/i386/dispatch.h @@ -84,7 +84,7 @@ public: /** \brief Syscall to start idle loop (in ring 0) */ static forceinline void idle(void) { - syscall(&idle_loop, 0, true); + syscall<true>(&idle_loop); } /** \brief The idle loop diff --git a/arch/i386/machine.cc b/arch/i386/machine.cc index d1a65a8..af8b063 100644 --- a/arch/i386/machine.cc +++ b/arch/i386/machine.cc @@ -11,6 +11,6 @@ noinline void __OS_trigger_syscall(uint8_t irq) { } void Machine::trigger_interrupt_from_user(uint8_t irq) { - arch::syscall(__OS_trigger_syscall, irq, true); + arch::syscall<true>(__OS_trigger_syscall, irq); } diff --git a/arch/i386/syscall.cc b/arch/i386/syscall.cc index 7a92815..5ce6072 100644 --- a/arch/i386/syscall.cc +++ b/arch/i386/syscall.cc @@ -15,10 +15,10 @@ namespace arch { IRQ_HANDLER(IRQ_SYSCALL) { // get arguments from registers // also, store pointer to context in %esi before we change %esp - uint32_t fun, arg; + uint32_t fun, arg1, arg2, arg3; bool direct; cpu_context* ctx; - asm volatile("leal -4(%%esp), %0" : "=r"(ctx), "=c"(arg), "=b"(fun), "=d"(direct)); + asm volatile("leal -4(%%esp), %0" : "=r"(ctx), "=c"(arg1), "=a"(arg2), "=D"(arg3), "=b"(fun), "=d"(direct)); // TODO: remove/reuse pushed CPU context? @@ -42,13 +42,15 @@ IRQ_HANDLER(IRQ_SYSCALL) { save_sp = 0; // for detecting bugs, not stricly neccessary } - // put syscall argument on top kernel stack + // put syscall arguments on top kernel stack uint32_t* sp = (uint32_t*) (&_estack_os - 2048); - *sp = arg; + *sp = arg3; + *(sp-1) = arg2; + *(sp-2) = arg1; // push the syscall stack address/segment Machine::push(GDT::USER_DATA_SEGMENT | 0x3); // push stack segment, DPL3 - Machine::push((uint32_t)(sp) - 4); // push stack pointer above argument + Machine::push((uint32_t)(sp-3)); // push stack pointer above argument // push flags, IO privilege level 3 Machine::push(ctx->eflags | 0x3000); @@ -74,7 +76,7 @@ IRQ_HANDLER(IRQ_SYSCALL) { // call syscall function with argument // C code does not work as compiler overwrites our return address with arg //void (* f)(uint32_t) = (void (*)(uint32_t))fun; f(arg); - asm volatile("push %0; call *%1; pop %0" :: "r"(arg), "r"(fun)); + asm volatile("push %3; push %2; push %1; call *%0; pop %1; pop %2; pop %3" :: "r"(fun), "r"(arg1), "r"(arg2), "r"(arg3)); // restore page directory asm volatile("mov %0, %%cr3" :: "S"(pd)); diff --git a/arch/i386/syscall.h b/arch/i386/syscall.h index a21b9e8..970732f 100644 --- a/arch/i386/syscall.h +++ b/arch/i386/syscall.h @@ -13,29 +13,52 @@ namespace arch { +/**@{*/ /** \brief Run specified function as syscall * * Currently, any function can be called this way. Eventually, this will be replaced * by an (encoded) index to a static jumptable of syscalls * * \param fun syscall function to be called - * \param arg (optional) argument for syscall - * \param direct execute syscall directly in IRQ handler instead of userspace (default: false) + * \param arg1 (optional) argument for syscall + * \param arg2 (optional) argument for syscall + * \param arg3 (optional) argument for syscall + * \tparam direct execute syscall directly in IRQ handler instead of userspace (default: false) */ -template<typename F, typename A=int> -forceinline void syscall(F fun, A arg=0, bool direct=false) { - // save all registers and call syscall interrupt - //asm volatile("pusha; int %0; popa" :: "i"(IRQ_SYSCALL), "b"(fun), "c"(*((uint32_t*)&arg))); - +template<bool direct=false, typename F> +forceinline void syscall(F fun) { // use clobber instead of pusha to save and restore only required registers: // gcc documentation says to list modified input in outputs and they must not be included // in clobber list, but LLVM works only the other way ... - asm volatile("int %0" :: "i"(IRQ_SYSCALL), "b"(fun), "c"(*((uint32_t*)&arg)), "d"(direct) : + asm volatile("int %0" :: "i"(IRQ_SYSCALL), "b"(fun), "d"(direct) : + "ebx", "ecx", "eax", "edx", "ebp", "esi", "edi", "cc", "memory"); +} + +template<bool direct=false, typename F, typename A> +forceinline void syscall(F fun, A arg1) { + asm volatile("int %0" :: "i"(IRQ_SYSCALL), "b"(fun), "c"(*((uint32_t*)&arg1)), "d"(direct) : "ebx", "ecx", "eax", "edx", "ebp", "esi", "edi", "cc", "memory"); } +template<bool direct=false, typename F, typename A, typename B> +forceinline void syscall(F fun, A arg1, B arg2) { + asm volatile("int %0" :: "i"(IRQ_SYSCALL), "b"(fun), "c"(*((uint32_t*)&arg1)), "d"(direct), + "a"(*((uint32_t*)&arg2)) : + "ebx", "ecx", "eax", "edx", "ebp", "esi", "edi", "cc", "memory"); +} + +template<bool direct=false, typename F, typename A, typename B, typename C> +forceinline void syscall(F fun, A arg1, B arg2, C arg3) { + asm volatile("int %0" :: "i"(IRQ_SYSCALL), "b"(fun), "c"(*((uint32_t*)&arg1)), "d"(direct), + "a"(*((uint32_t*)&arg2)), "D"(*((uint32_t*)&arg3)) : + "ebx", "ecx", "eax", "edx", "ebp", "esi", "edi", "cc", "memory"); +} + +/**@}*/ + /** \brief Return true if calling code is running as part of a syscall */ forceinline bool in_syscall() { + // TODO: determine using some (encoded) system variable instead of hardware register? return (LAPIC::get_task_prio() == 128); } -- GitLab