diff --git a/common/usermode.c b/common/usermode.c index 667edef8..aa5d107f 100644 --- a/common/usermode.c +++ b/common/usermode.c @@ -113,8 +113,8 @@ void init_usermode(percpu_t *percpu) { init_sysenter(percpu); } -static inline long __user_text syscall(long syscall_nr, long arg1, long arg2, long arg3, - long arg4, long arg5) { +static inline long __user_text _syscall(long syscall_nr, long arg1, long arg2, long arg3, + long arg4, long arg5) { register long return_code asm(STR(_ASM_AX)); register long _arg4 asm("r8") = arg4; register long _arg5 asm("r9") = arg5; @@ -131,6 +131,53 @@ static inline long __user_text syscall(long syscall_nr, long arg1, long arg2, lo return return_code; } +static inline long __user_text _sysenter(long syscall_nr, long arg1, long arg2, long arg3, + long arg4, long arg5) { + register long return_code asm(STR(_ASM_AX)); + register long _arg4 asm("r8") = arg4; + register long _arg5 asm("r9") = arg5; + register long _arg3 asm("r10") = arg3; + + /* clang-format off */ + asm volatile ( + "mov %%" STR(_ASM_SP) ", %%" STR(_ASM_CX) "\n" + "lea 1f(%%" STR(_ASM_IP) "), %%" STR(_ASM_DX) "\n" + "sysenter\n" + "1: " + : "=a"(return_code) + : "0"(syscall_nr), "S"(arg1), "D" (arg2), "r" (_arg3), "r"(_arg4), "r"(_arg5) + : STR(_ASM_CX), STR(_ASM_DX) + ); + /* clang-format on */ + + return return_code; +} + +static __user_data syscall_mode_t sc_mode = SYSCALL_MODE_SYSCALL; + +bool __user_text syscall_mode(syscall_mode_t mode) { + if (mode > SYSCALL_MODE_INT) { + return false; + } + sc_mode = mode; + + return true; +} + +static long __user_text syscall(long syscall_nr, long arg1, long arg2, long arg3, + long arg4, long arg5) { + switch (sc_mode) { + case SYSCALL_MODE_SYSCALL: + return _syscall(syscall_nr, arg1, arg2, arg3, arg4, arg5); + case SYSCALL_MODE_SYSENTER: + return _sysenter(syscall_nr, arg1, arg2, arg3, arg4, arg5); + case SYSCALL_MODE_INT: + // unimplemented + default: + UNREACHABLE(); + } +} + #define syscall0(nr) syscall((nr), 0, 0, 0, 0, 0) #define syscall1(nr, a1) syscall((nr), (a1), 0, 0, 0, 0) #define syscall2(nr, a1, a2) syscall((nr), (a1), (a2), 0, 0, 0) diff --git a/include/usermode.h b/include/usermode.h index 811d9b96..a45f33dc 100644 --- a/include/usermode.h +++ b/include/usermode.h @@ -39,6 +39,13 @@ #include #include +enum syscall_mode { + SYSCALL_MODE_SYSCALL, // use SYSCALL + SYSCALL_MODE_SYSENTER, // use SYSENTER + SYSCALL_MODE_INT, // TODO: use INT $SYSVEC +}; +typedef enum syscall_mode syscall_mode_t; + /* Static declarations */ static inline bool enter_from_usermode(uint16_t cs) { @@ -57,6 +64,7 @@ extern void __user_text exit(unsigned long exit_code); extern void __user_text printf(const char *fmt, ...); extern void *__user_text mmap(void *va, unsigned long order); extern void __user_text munmap(void *va, unsigned long order); +extern bool __user_text syscall_mode(syscall_mode_t); #endif /* __ASSEMBLY__ */