diff --git a/arch/x86_64/include/arch/msr.h b/arch/x86_64/include/arch/msr.h index 89ec3fb..e59b6b2 100644 --- a/arch/x86_64/include/arch/msr.h +++ b/arch/x86_64/include/arch/msr.h @@ -3,7 +3,8 @@ #include -#define MSR_GS_BASE 0xC0000101 +#define MSR_GS_BASE 0xC0000101 +#define MSR_KERNEL_GS_BASE 0xC0000102 #ifdef __cplusplus extern "C" { diff --git a/arch/x86_64/irqvec.S b/arch/x86_64/irqvec.S index 74bd02b..892fc68 100644 --- a/arch/x86_64/irqvec.S +++ b/arch/x86_64/irqvec.S @@ -333,11 +333,30 @@ IRQ 223, 255 isr_common_stub: PUSH_REGS + # When ISR occurs in Ring 3, CPU sets %ss (and other non-code selectors) + # to 0. + mov %ss, %ax + cmp $0, %ax + jne isr_skipgs1 + + mov $0x10, %ax + mov %ax, %ss + swapgs + +isr_skipgs1: mov %rsp, %rdi call isr_dispatch POP_REGS add $16, %rsp + + cmpq $0x1b, 32(%rsp) + jne isr_skipgs2 + + swapgs + +isr_skipgs2: + iretq @@ -347,11 +366,31 @@ isr_common_stub: irq_common_stub: PUSH_REGS + # When IRQ occurs in Ring 3, CPU sets %ss (and other non-code selectors) + # to 0. + mov %ss, %ax + cmp $0, %ax + jne irq_skipgs1 + + mov $0x10, %ax + mov %ax, %ss + swapgs + +irq_skipgs1: mov %rsp, %rdi call irq_dispatch + POP_REGS add $16, %rsp + + cmpq $0x1b, 32(%rsp) + jne isr_skipgs2 + + swapgs + +irq_skipgs2: + iretq @@ -363,12 +402,12 @@ irq_common_stub: syscall_gate: swapgs - movq %rsp, %gs:20 # GS+20 = rsp2 in the current TSS block (user stack storage) - movq %gs:4, %rsp # GS+4 = rsp0 in the current TSS block (per-thread kstack) + movq %rsp, %gs:94 # GS+20 = rsp2 in the current TSS block (user stack storage) + movq %gs:78, %rsp # GS+4 = rsp0 in the current TSS block (per-thread kstack) # start building a ml_cpu_context pushq $0x1b - pushq %gs:20 + pushq %gs:94 push %r11 push $0x23 push %rcx @@ -380,10 +419,6 @@ syscall_gate: mov %rsp, %rdi - # switch back to user gs while in syscall_dispatch. Interrupts are enabled in syscall_dispatch, - # and if the task gets pre-empted, the incoming task will expect %gs to have its usermode value. - swapgs - call syscall_dispatch POP_REGS @@ -394,8 +429,8 @@ syscall_gate: pop %r11 add $16, %rsp - swapgs - movq %gs:20, %rsp # GS+20 = rsp2 in the current TSS block + movq %gs:94, %rsp # GS+20 = rsp2 in the current TSS block + swapgs # back to usermode diff --git a/arch/x86_64/thread_switch.S b/arch/x86_64/thread_switch.S index 47b7407..76f51ac 100644 --- a/arch/x86_64/thread_switch.S +++ b/arch/x86_64/thread_switch.S @@ -73,4 +73,5 @@ ml_thread_switch_user: pop %rax add $16, %rsp + swapgs iretq diff --git a/arch/x86_64/tss.c b/arch/x86_64/tss.c index d22450f..643e9e5 100644 --- a/arch/x86_64/tss.c +++ b/arch/x86_64/tss.c @@ -1,5 +1,3 @@ -#include "arch/msr.h" - #include #include #include @@ -22,9 +20,6 @@ void tss_init(struct tss *tss, struct tss_ptr *ptr) void tss_load(struct tss *tss) { tss_flush(TSS_GDT_INDEX); - - uintptr_t kernel_gs_base_reg = 0xC0000102; - wrmsr(kernel_gs_base_reg, (uintptr_t)tss); } virt_addr_t tss_get_kstack(struct tss *tss)