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>
|
#include <stdint.h>
|
||||||
|
|
||||||
#define MSR_GS_BASE 0xC0000101
|
#define MSR_GS_BASE 0xC0000101
|
||||||
|
#define MSR_KERNEL_GS_BASE 0xC0000102
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|||||||
@@ -333,11 +333,30 @@ IRQ 223, 255
|
|||||||
isr_common_stub:
|
isr_common_stub:
|
||||||
PUSH_REGS
|
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
|
mov %rsp, %rdi
|
||||||
call isr_dispatch
|
call isr_dispatch
|
||||||
|
|
||||||
POP_REGS
|
POP_REGS
|
||||||
add $16, %rsp
|
add $16, %rsp
|
||||||
|
|
||||||
|
cmpq $0x1b, 32(%rsp)
|
||||||
|
jne isr_skipgs2
|
||||||
|
|
||||||
|
swapgs
|
||||||
|
|
||||||
|
isr_skipgs2:
|
||||||
|
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
|
|
||||||
@@ -347,11 +366,31 @@ isr_common_stub:
|
|||||||
irq_common_stub:
|
irq_common_stub:
|
||||||
PUSH_REGS
|
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
|
mov %rsp, %rdi
|
||||||
call irq_dispatch
|
call irq_dispatch
|
||||||
|
|
||||||
|
|
||||||
POP_REGS
|
POP_REGS
|
||||||
add $16, %rsp
|
add $16, %rsp
|
||||||
|
|
||||||
|
cmpq $0x1b, 32(%rsp)
|
||||||
|
jne isr_skipgs2
|
||||||
|
|
||||||
|
swapgs
|
||||||
|
|
||||||
|
irq_skipgs2:
|
||||||
|
|
||||||
iretq
|
iretq
|
||||||
|
|
||||||
|
|
||||||
@@ -363,12 +402,12 @@ irq_common_stub:
|
|||||||
|
|
||||||
syscall_gate:
|
syscall_gate:
|
||||||
swapgs
|
swapgs
|
||||||
movq %rsp, %gs:20 # GS+20 = rsp2 in the current TSS block (user stack storage)
|
movq %rsp, %gs:94 # 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 %gs:78, %rsp # GS+4 = rsp0 in the current TSS block (per-thread kstack)
|
||||||
|
|
||||||
# start building a ml_cpu_context
|
# start building a ml_cpu_context
|
||||||
pushq $0x1b
|
pushq $0x1b
|
||||||
pushq %gs:20
|
pushq %gs:94
|
||||||
push %r11
|
push %r11
|
||||||
push $0x23
|
push $0x23
|
||||||
push %rcx
|
push %rcx
|
||||||
@@ -380,10 +419,6 @@ syscall_gate:
|
|||||||
|
|
||||||
mov %rsp, %rdi
|
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
|
call syscall_dispatch
|
||||||
|
|
||||||
POP_REGS
|
POP_REGS
|
||||||
@@ -394,8 +429,8 @@ syscall_gate:
|
|||||||
pop %r11
|
pop %r11
|
||||||
add $16, %rsp
|
add $16, %rsp
|
||||||
|
|
||||||
swapgs
|
movq %gs:94, %rsp # GS+20 = rsp2 in the current TSS block
|
||||||
movq %gs:20, %rsp # GS+20 = rsp2 in the current TSS block
|
|
||||||
swapgs
|
swapgs
|
||||||
|
|
||||||
# back to usermode
|
# back to usermode
|
||||||
|
|||||||
@@ -73,4 +73,5 @@ ml_thread_switch_user:
|
|||||||
pop %rax
|
pop %rax
|
||||||
|
|
||||||
add $16, %rsp
|
add $16, %rsp
|
||||||
|
swapgs
|
||||||
iretq
|
iretq
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
#include "arch/msr.h"
|
|
||||||
|
|
||||||
#include <arch/gdt.h>
|
#include <arch/gdt.h>
|
||||||
#include <arch/tss.h>
|
#include <arch/tss.h>
|
||||||
#include <kernel/libc/string.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)
|
void tss_load(struct tss *tss)
|
||||||
{
|
{
|
||||||
tss_flush(TSS_GDT_INDEX);
|
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)
|
virt_addr_t tss_get_kstack(struct tss *tss)
|
||||||
|
|||||||
Reference in New Issue
Block a user