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:
2026-02-23 18:26:21 +00:00
parent 273557fa9f
commit dbe117135b
4 changed files with 47 additions and 15 deletions

View File

@@ -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