Skip to content

Commit

Permalink
usermode: add sysenter and syscall_mode selection
Browse files Browse the repository at this point in the history
To give usermode the option to choose sysenter instead of syscall, we
expose syscall_mode(enum syscall_mode), which is by default using
syscall.

Signed-off-by: Johannes Wikner <[email protected]>
  • Loading branch information
sktt committed Aug 30, 2023
1 parent 683d273 commit eec2373
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 8 deletions.
8 changes: 2 additions & 6 deletions arch/x86/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -224,9 +224,7 @@ ENTRY(syscall_handler_entry)
END_FUNC(syscall_handler_entry)

ENTRY(sysenter_handler_entry)
push %_ASM_CX
push %_ASM_DX
SAVE_CALLEE_SAVED_REGS
SAVE_ALL_REGS
syscall_from_usermode

MASK_USER_FLAGS
Expand All @@ -240,9 +238,7 @@ ENTRY(sysenter_handler_entry)
call syscall_handler

syscall_to_usermode
RESTORE_CALLEE_SAVED_REGS
pop %_ASM_DX
pop %_ASM_CX
RESTORE_ALL_REGS

SYSEXIT
END_FUNC(sysenter_handler_entry)
Expand Down
51 changes: 49 additions & 2 deletions common/usermode.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
Expand Down
8 changes: 8 additions & 0 deletions include/usermode.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,13 @@
#include <percpu.h>
#include <sched.h>

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) {
Expand All @@ -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__ */

Expand Down

0 comments on commit eec2373

Please sign in to comment.