Skip to content
Snippets Groups Projects
Commit 701b9bf5 authored by Florian Lukas's avatar Florian Lukas
Browse files

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
parent 189853ac
No related branches found
No related tags found
No related merge requests found
......@@ -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
......
......@@ -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);
}
......@@ -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));
......
......@@ -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);
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment