Page 1 of 1
Reload GDTR 64bit
Posted: Mon Aug 20, 2012 4:31 pm
by gabe
I've been attempting to reload the GDT while already in 64 bit mode and for some reason it works fine but completely smashes my stack.
I've confirmed that before entering this function and exiting that the stack pointer is in fact at the same position but again for some reason my kernel crashes very shortly after for what appears to be a poisoned stack.
Code below simply pushes SS:RSP flags CS and RIP and then iretq to force a reload of CS is my understanding of the only correct way of doing this in 64 bit mode since far jmps aren't allowed.
Code: Select all
asm ("\
movq %%rsp, %%rax\n\
pushq $0x0\n\
pushq %%rax\n\
pushfq\n\
pushq $0x08\n\
movabs $1f, %%rax\n\
pushq %%rax\n\
lgdt %0\n\
iretq\n\
1:"
:
:"m"(gdt->limit)
:"memory","rax", "rsp");
Re: Reload GDTR 64bit
Posted: Mon Aug 20, 2012 4:39 pm
by bluemoon
You should push a proper DATA64 selector instead of 0.
Re: Reload GDTR 64bit
Posted: Mon Aug 20, 2012 4:51 pm
by gabe
the first one is the SS selector and doesn't need it.
the CS selector is 0x8
Re: Reload GDTR 64bit
Posted: Mon Aug 20, 2012 5:03 pm
by gerryg400
gabe wrote:the first one is the SS selector and doesn't need it.
the CS selector is 0x8
You do need to supply a valid SS. 0 will not work.
Re: Reload GDTR 64bit
Posted: Mon Aug 20, 2012 5:46 pm
by bluemoon
Ok I experimented with setting SS=0 during IRETQ from 64-bit ring0 to 64-bit ring0 and it work, so it might actually legal to do so (I'm not sure if that's just luck).
So, the inline block seems correctly to me, although it is ugly to reuses the same stack but I'm also doing that.
perhaps we can look into the whole C function to see if there is anything wrong.
By the way, this is my code for your reference (however, in plain assembly)
Code: Select all
; Load GDT & Reload selectors
; ----------------------------------------------
mov rdi, qword gdtr
lgdt [rdi]
mov eax, SEG_DATA64_0
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ss, ax
mov rsp, qword kstack + KSTACK_SIZE
mov rcx, qword .reloadcs
mov rsi, rsp
push rax ; new SS
push rsi ; new RSP
push 2 ; new FLAGS
push SEG_CODE64_0 ; new CS
push rcx ; new RIP
iretq
.reloadcs:
Re: Reload GDTR 64bit
Posted: Mon Aug 20, 2012 5:57 pm
by Owen
The processor itself will set your SS to 0 (see the AMD64 manuals on this). Most kernels will spend more time with SS=0 than without.
far returns (In GAS syntax, "retf") work in long mode and use 64-bit displacements.
With that said, in my experience, except perhaps when booted from EFI, you should have no reason to explicitly reload CS in long mode
Re: Reload GDTR 64bit
Posted: Mon Aug 20, 2012 6:09 pm
by gerryg400
Ok I experimented with setting SS=0 during IRETQ from 64-bit ring0 to 64-bit ring0 and it work, so it might actually legal to do so (I'm not sure if that's just luck).
Oh, I thought we were trying to get to ring 3. To iret to ring 3 you need a valid SS.
Re: Reload GDTR 64bit
Posted: Mon Aug 20, 2012 7:43 pm
by gabe
well I found the problem, had nothing to do with SS but rather the fact that the GDT entries weren't properly aligned.
tx
Re: Reload GDTR 64bit
Posted: Tue Aug 21, 2012 2:55 am
by turdus
gerryg400 wrote:Oh, I thought we were trying to get to ring 3. To iret to ring 3 you need a valid SS.
Not necessairly. In long mode it's allowed to use SS=0 on iretq, for nested ISRs. But we agreed that you should not rely on that because when the first time you switch to userspace from kernel (in other words, when you set up segment registers for the first and only time), there's no nesting, therefore SS should contain a valid selector. Normally only the cpu will push ss=0 on stack, and pop it back, and software has nothing to do with it (unless you want to count reentrant calls and your kernel checks the stack for ss=0 to accomplish that task).
Re: Reload GDTR 64bit
Posted: Tue Aug 21, 2012 3:00 am
by bluemoon
If SS=0 when going to user mode, #GP as according to the manual for IRETQ:
64-Bit Mode Exceptions
#GP(0) If EFLAGS.NT[bit 14] = 1.
If the return code segment selector is NULL.
If the stack segment selector is NULL going back to compatibility mode.
If the stack segment selector is NULL going back to CPL3 64-bit mode.
If a NULL stack segment selector RPL is not equal to CPL going back to non-CPL3 64-bit mode.
If the return instruction pointer is not within the return code segment limit.
If the return instruction pointer is non-canonical.
SS=0 only possible in ring0, and as mentioned above, is usually set by CPU in some circumstances.