Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Restructure GDT. Add sysenter support #290

Merged
merged 6 commits into from
Aug 30, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 42 additions & 3 deletions arch/x86/entry.S
Original file line number Diff line number Diff line change
Expand Up @@ -180,9 +180,10 @@ ENTRY(enter_usermode)
SAVE_ALL_REGS
wipawel marked this conversation as resolved.
Show resolved Hide resolved
PUSHF

/* Save stack pointer onto per-cpu */
/* Save user stack pointer onto per-cpu */
mov %_ASM_DX, %gs:(usermode_private)

/* Now switch stack and address space */
syscall_to_usermode

/* SS + SP */
Expand All @@ -201,7 +202,7 @@ ENTRY(enter_usermode)
END_FUNC(enter_usermode)

ENTRY(syscall_handler_entry)
SAVE_CALLEE_SAVED_REGS
SAVE_ALL_REGS
syscall_from_usermode

cmp $SYSCALL_EXIT, %_ASM_AX
Expand All @@ -218,9 +219,47 @@ ENTRY(syscall_handler_entry)
pop %_ASM_CX

syscall_to_usermode
RESTORE_CALLEE_SAVED_REGS
RESTORE_ALL_REGS
SYSRET
END_FUNC(syscall_handler_entry)

ENTRY(sysenter_handler_entry)
sktt marked this conversation as resolved.
Show resolved Hide resolved
SAVE_ALL_REGS
syscall_from_usermode

MASK_USER_FLAGS

cmp $SYSCALL_EXIT, %_ASM_AX
jz syscall_exit

mov %_ASM_DI, %_ASM_DX
mov %r10, %_ASM_CX
mov %_ASM_AX, %_ASM_DI
call syscall_handler

syscall_to_usermode
RESTORE_ALL_REGS

SYSEXIT
END_FUNC(sysenter_handler_entry)

ENTRY(int80_handler_entry)
SAVE_ALL_REGS
syscall_from_usermode

MASK_USER_FLAGS

cmp $SYSCALL_EXIT, %_ASM_AX
jz syscall_exit

mov %_ASM_DI, %_ASM_CX
mov %_ASM_AX, %_ASM_DI
call syscall_handler

syscall_to_usermode
RESTORE_ALL_REGS
IRET
END_FUNC(int80_handler_entry)
GLOBAL(end_usermode_helpers)

SECTION(.text.user, "ax", 16)
Expand Down
4 changes: 2 additions & 2 deletions arch/x86/real_mode.S
Original file line number Diff line number Diff line change
Expand Up @@ -164,15 +164,15 @@ END_FUNC(_prot_to_real)
mov rmode_stack, %esp

/* Use 16-bit protected mode segment selectors */
mov $__KERN_DS16, %eax
mov $__RMODE_DS16, %eax
mov %eax, %ds
mov %eax, %es
mov %eax, %gs
mov %eax, %fs
mov %eax, %ss

/* Jump to real mode */
ljmp $__KERN_CS16, $.Lreal_mode
ljmp $__RMODE_CS16, $.Lreal_mode

.code16
.align 16
Expand Down
6 changes: 6 additions & 0 deletions arch/x86/segment.c
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,10 @@ gdt_desc_t __data_init boot_gdt[NR_BOOT_GDT_ENTRIES] __aligned(16) = {
[GDT_NULL].desc = GDT_ENTRY(0x0, 0x0, 0x0),
[GDT_KERN_CS32].desc = GDT_ENTRY(DESC_FLAGS(GR, SZ, P, DPL0, S, CODE, R, A), 0x0, 0xfffff),
[GDT_KERN_DS32].desc = GDT_ENTRY(DESC_FLAGS(GR, SZ, P, DPL0, S, DATA, W, A), 0x0, 0xfffff),
#if defined(__x86_64__)
/* We only need this entry to transition to long mode. Hence, no use for any DS64. */
[GDT_KERN_CS64].desc = GDT_ENTRY(DESC_FLAGS(GR, L, P, DPL0, S, CODE, R, A), 0x0, 0x00000),
#endif
/* clang-format on */
};

Expand All @@ -68,7 +71,10 @@ gdt_desc_t __data_rmode rmode_gdt[NR_RMODE_GDT_ENTRIES] __aligned(16) = {
[GDT_NULL].desc = GDT_ENTRY(0x0, 0x0, 0x0),
[GDT_KERN_CS32].desc = GDT_ENTRY(DESC_FLAGS(GR, SZ, P, DPL0, S, CODE, R, A), 0x0, 0xfffff),
[GDT_KERN_DS32].desc = GDT_ENTRY(DESC_FLAGS(GR, SZ, P, DPL0, S, DATA, W, A), 0x0, 0xfffff),
#if defined(__x86_64__)
/* We only need this entry to transition to long mode. Hence, no use for any DS64. */
[GDT_KERN_CS64].desc = GDT_ENTRY(DESC_FLAGS(GR, L, P, DPL0, S, CODE, R, A), 0x0, 0x00000),
#endif
[GDT_RMODE_CS16].desc = GDT_ENTRY(DESC_FLAGS(P, DPL0, S, CODE, R, A), 0x0, 0xfffff),
[GDT_RMODE_DS16].desc = GDT_ENTRY(DESC_FLAGS(P, DPL0, S, DATA, W, A), 0x0, 0xfffff),
/* clang-format on */
Expand Down
11 changes: 7 additions & 4 deletions arch/x86/traps.c
Original file line number Diff line number Diff line change
Expand Up @@ -90,13 +90,16 @@ static void init_gdt(percpu_t *percpu) {
percpu->gdt[GDT_NULL].desc = GDT_ENTRY(0x0, 0x0, 0x0);
percpu->gdt[GDT_KERN_CS32].desc = GDT_ENTRY(DESC_FLAGS(GR, SZ, P, DPL0, S, CODE, R, A), 0x0, 0xfffff);
percpu->gdt[GDT_KERN_DS32].desc = GDT_ENTRY(DESC_FLAGS(GR, SZ, P, DPL0, S, DATA, W, A), 0x0, 0xfffff);
#if defined(__x86_64__)
percpu->gdt[GDT_KERN_CS64].desc = GDT_ENTRY(DESC_FLAGS(GR, L, P, DPL0, S, CODE, R, A), 0x0, 0x00000);
percpu->gdt[GDT_KERN_DS64].desc = GDT_ENTRY(DESC_FLAGS(GR, L, P, DPL0, S, DATA, W, A), 0x0, 0x00000);

#endif
percpu->gdt[GDT_USER_CS32].desc = GDT_ENTRY(DESC_FLAGS(GR, SZ, P, DPL3, S, CODE, R, A), 0x0, 0xfffff);
percpu->gdt[GDT_USER_DS32].desc = GDT_ENTRY(DESC_FLAGS(GR, SZ, P, DPL3, S, DATA, W, A), 0x0, 0xfffff);
percpu->gdt[GDT_USER_CS64].desc = GDT_ENTRY(DESC_FLAGS(GR, L, P, DPL3, S, CODE, R, A), 0x0, 0xfffff);
percpu->gdt[GDT_USER_DS64].desc = GDT_ENTRY(DESC_FLAGS(GR, L, P, DPL3, S, DATA, W, A), 0x0, 0xfffff);
percpu->gdt[GDT_USER_DS].desc = GDT_ENTRY(DESC_FLAGS(GR, SZ, P, DPL3, S, DATA, W, A), 0x0, 0xfffff);
#if defined(__x86_64__)
percpu->gdt[GDT_USER_CS64].desc = GDT_ENTRY(DESC_FLAGS(GR, L, P, DPL3, S, CODE, R, A), 0x0, 0xfffff);
percpu->gdt[GDT_USER_SYSEXITQ].desc = GDT_ENTRY(DESC_FLAGS(GR, L, P, DPL3, S, DATA, W, A), 0x0, 0xfffff);
#endif

/* Assign identity mapping of the percpu, because GDT has only 32-bit base. */
percpu->gdt[GDT_PERCPU].desc = GDT_ENTRY(DESC_FLAGS(GR, L, P, DPL0, S, CODE, R, A), virt_to_paddr(percpu), PAGE_SIZE);
Expand Down
85 changes: 81 additions & 4 deletions common/usermode.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,11 @@
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <lib.h>
#include <mm/vmm.h>
#include <pagetable.h>
#include <percpu.h>
#include <processor.h>
#include <traps.h>
#include <usermode.h>

extern char exception_handlers[], end_exception_handlers[];
Expand Down Expand Up @@ -75,8 +77,10 @@ static void init_syscall(void) {
msr_star_t star;

star.eip = _u(_ul(&syscall_handler_entry));
star.kern_cs = __KERN_CS64;
star.user_cs = __USER_CS64;

/* see segment.h for details regarding these values */
star.kern_cs = __KERN_CS;
star.user_cs = __USER_CS32;

wrmsr(MSR_STAR, star.reg);
wrmsr(MSR_LSTAR, _ul(&syscall_handler_entry));
Expand All @@ -87,6 +91,12 @@ static void init_syscall(void) {
wrmsr(MSR_EFER, rdmsr(MSR_EFER) | EFER_SCE);
}

static void init_sysenter(percpu_t *percpu) {
wrmsr(MSR_SYSENTER_CS, _ul(__KERN_CS));
wrmsr(MSR_SYSENTER_ESP, _ul(percpu->tss.rsp0));
wrmsr(MSR_SYSENTER_EIP, _ul(&sysenter_handler_entry));
sktt marked this conversation as resolved.
Show resolved Hide resolved
}

void init_usermode(percpu_t *percpu) {
vmap_user_4k(&cr3, virt_to_mfn(&cr3), L1_PROT);
vmap_user_4k(&user_cr3, virt_to_mfn(&user_cr3), L1_PROT);
Expand All @@ -101,10 +111,30 @@ void init_usermode(percpu_t *percpu) {
vmap_user_4k(usermode_helpers, virt_to_mfn(usermode_helpers), L1_PROT);

init_syscall();
init_sysenter(percpu);
set_intr_gate(&percpu->idt[SYSCALL_INT], __KERN_CS, _ul(int80_handler_entry),
GATE_DPL3, GATE_PRESENT, 0);
}

static inline long __user_text _int80(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;

/* clang-format off */
asm volatile(
"int $" STR(SYSCALL_INT) "\n"
: "=a"(return_code)
: "0"(syscall_nr), "S"(arg1), "d"(arg2), "D" (arg3), "r"(_arg4), "r"(_arg5)
);
/* clang-format on */

return return_code;
}

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 @@ -121,6 +151,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;
sktt marked this conversation as resolved.
Show resolved Hide resolved

/* 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_INT80) {
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_INT80:
return _int80(syscall_nr, arg1, arg2, arg3, arg4, arg5);
default:
UNREACHABLE();
sktt marked this conversation as resolved.
Show resolved Hide resolved
}
}

#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/arch/x86/asm-macros.h
Original file line number Diff line number Diff line change
Expand Up @@ -170,6 +170,14 @@
#endif
.endm

.macro SYSEXIT
#if defined(__x86_64__)
sysexitq
#else
sysexit
#endif
.endm

.macro SET_CR3 val
push %_ASM_AX
mov (\val), %_ASM_AX
Expand Down
13 changes: 13 additions & 0 deletions include/arch/x86/processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@
#define EFER_FFXSR (_U64(1) << 14) /* Fast FXSAVE/FXRSTOR */
#define EFER_TCE (_U64(1) << 15) /* Translation Cache Extension */

#define MSR_SYSENTER_CS 0x174
#define MSR_SYSENTER_ESP 0x175
#define MSR_SYSENTER_EIP 0x176

#define MSR_STAR 0xc0000081
#define MSR_LSTAR 0xc0000082
#define MSR_CSTAR 0xc0000083
Expand Down Expand Up @@ -286,6 +290,15 @@ union msr_star {
};
typedef union msr_star msr_star_t;

typedef uint16_t msr_sysenter_cs_t;
#if defined(__x86_64__)
typedef uint64_t msr_sysenter_esp_t;
typedef uint64_t msr_sysenter_eip_t;
#else
typedef uint32_t msr_sysenter_esp_t;
typedef uint32_t msr_sysenter_eip_t;
#endif

static inline bool has_error_code(uint32_t vector) {
return !!((1U << vector) & X86_EX_HAS_ERROR_CODE);
}
Expand Down
Loading