if I'm understanding correctly, it is using the user stack for interrupts by setting IDT.IST to 0.. And upon interrupts the code manually switch to kernel stack using the gs register.
// switch to task kernel stack
mov rdi, rsp
// cs of call, if it from user, last 3 bit is 0b11
mov rsi, [rsp + 11*8]
//caused in user mode?
and rsi, 0b11
jz 1f
//load kernel rsp
swapgs
mov rsp, gs:0
jmp 2f
1:
//load exception rsp, which is kernel rsp
mov rsi, [rsp + 13 *8]
2:
// ...
also for syscall:
syscall_entry:
swapgs
//user stack
mov gs:8, rsp
//kernel stack
mov rsp, gs:0
//reserve the space for exception stack frame
sub rsp, 1 * 8
// ....
It could be simpler to specify another stack in the IDT.IST and maintain the kernel stack address in the TSS instead of in the GS register.
IST: A 3-bit value which is an offset into the Interrupt Stack Table, which is stored in the Task State Segment.
This is not bug fix nor improvement. Just an idea of simplifying the low level code.
Currently we have in
interrupt::InitSingleton
if I'm understanding correctly, it is using the user stack for interrupts by setting IDT.IST to 0.. And upon interrupts the code manually switch to kernel stack using the gs register.
also for syscall:
It could be simpler to specify another stack in the IDT.IST and maintain the kernel stack address in the TSS instead of in the GS register.
This is not bug fix nor improvement. Just an idea of simplifying the low level code.
ref: https://wiki.osdev.org/Interrupt_Descriptor_Table