x86_64: implement proper user/kernel %gs base switching
the %gs base address is now always set to the current cpu block while in kernel-mode, and is switched back to the userspace %gs base when returning to user-mode.
This commit is contained in:
@@ -4,6 +4,7 @@
|
||||
#include <stdint.h>
|
||||
|
||||
#define MSR_GS_BASE 0xC0000101
|
||||
#define MSR_KERNEL_GS_BASE 0xC0000102
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -73,4 +73,5 @@ ml_thread_switch_user:
|
||||
pop %rax
|
||||
|
||||
add $16, %rsp
|
||||
swapgs
|
||||
iretq
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
#include "arch/msr.h"
|
||||
|
||||
#include <arch/gdt.h>
|
||||
#include <arch/tss.h>
|
||||
#include <kernel/libc/string.h>
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user