Problems reloading the GDT in long mode?

Question about which tools to use, bugs, the best way to implement a function, etc should go here. Don't forget to see if your question is answered in the wiki first! When in doubt post here.
rpio
Member
Member
Posts: 92
Joined: Sat Feb 20, 2021 3:11 pm

Problems reloading the GDT in long mode?

Post by rpio »

My bootloader switches to the long mode for me, but using it's GDT is very risky and undefined so I wanted to reload the GDT. I wrote a small bit of code to reload GDT which always fails with covering screen(framebuffer) in random colors and then it just triple faults in a second
Last edited by rpio on Sun Jan 23, 2022 4:46 am, edited 1 time in total.
SKC
Member
Member
Posts: 28
Joined: Thu Feb 18, 2021 3:07 am

Re: Problems reloading the GDT in long mode?

Post by SKC »

Hi.
Your code uses iretq, but you don't push CS and RFLAGS (iretq pops RIP, CS and RFLAGS).
Personally, I use retfq to reload CS (retfq pops RIP and CS).
rpio
Member
Member
Posts: 92
Joined: Sat Feb 20, 2021 3:11 pm

Re: Problems reloading the GDT in long mode?

Post by rpio »

SKC wrote:Hi.
Your code uses iretq, but you don't push CS and RFLAGS (iretq pops RIP, CS and RFLAGS).
Personally, I use retfq to reload CS (retfq pops RIP and CS).

Thanks, I am not really good in assembly so I would probably never fix this on my own.

So in addition to RIP should i also just push CS - but before pushing CS, should I load the new offset in GDT into it?

mov cs, 0x10
push cs
push rdi


But what are RFLAGs and how do I push them?
How do you reload with retfq, do you use it instead of iretq?
User avatar
iansjack
Member
Member
Posts: 4703
Joined: Sat Mar 31, 2012 3:07 am
Location: Chichester, UK

Re: Problems reloading the GDT in long mode?

Post by iansjack »

ngx wrote: But what are RFLAGs and how do I push them?
How do you reload with retfq, do you use it instead of iretq?
I'd suggest that you could profit from looking at the Intel (or AMD) Programmer's Manual.
sj95126
Member
Member
Posts: 151
Joined: Tue Aug 11, 2020 12:14 pm

Re: Problems reloading the GDT in long mode?

Post by sj95126 »

You could also just perform a direct inter-segment jmp (even if it's functionally the same code segment) which would make the intent clearer than setting up a stack for a ret or iret.

e.g. (in AT&T syntax):

Code: Select all

         lgdt gdt64_ptr
         jmp $CODE_SEG, $rejump_label
rejump_label:
         [continue on]
Also, and just IMO, I'd reset the code segment flow immediately after loading a new GDT, and then set the data segment registers. It's what you have to do to go into protected or long mode, so seems best to be consistent.
rpio
Member
Member
Posts: 92
Joined: Sat Feb 20, 2021 3:11 pm

Re: Problems reloading the GDT in long mode?

Post by rpio »

sj95126 wrote:You could also just perform a direct inter-segment jmp (even if it's functionally the same code segment) which would make the intent clearer than setting up a stack for a ret or iret.

e.g. (in AT&T syntax):

Code: Select all

         lgdt gdt64_ptr
         jmp $CODE_SEG, $rejump_label
rejump_label:
         [continue on]
Also, and just IMO, I'd reset the code segment flow immediately after loading a new GDT, and then set the data segment registers. It's what you have to do to go into protected or long mode, so seems best to be consistent.
Wow, never heard of inter-segment jump(also does $ mean address or content of address?)

What do you mean by "reset code segment flow and data segment registers"?
Last edited by rpio on Sun Jan 23, 2022 4:47 am, edited 1 time in total.
nullplan
Member
Member
Posts: 1790
Joined: Wed Aug 30, 2017 8:24 am

Re: Problems reloading the GDT in long mode?

Post by nullplan »

ngx wrote:Wow, never heard of inter-segment jump
Also called far jump.
ngx wrote:(also does $ mean address or content of address?)
Address. Well, "immediate" is what it means, but when applied to a label, you get the address.
ngx wrote:What do you mean by "reset code segment flow and data segment registers"?
That was probably a word salad problem, but I'm guessing he meant that you have to reload your segment registers immediately after loading a new GDT. I concur. If you don't, you are just asking for something to at some point push an invalid segment descriptor to stack, and then crash when it's loaded back.
ngx wrote:I added inter-segment jump, please correct me if I forgot something or got something wrong:
For NASM, the syntax is

Code: Select all

jmp 8:.reload_registers
Carpe diem!
sj95126
Member
Member
Posts: 151
Joined: Tue Aug 11, 2020 12:14 pm

Re: Problems reloading the GDT in long mode?

Post by sj95126 »

ngx wrote:Wow, never heard of inter-segment jump(also does $ mean address or content of address?)
AT&T and Intel syntax do everything backwards from each other.

AT&T "$label" is the same as Intel "label" (address of label)
AT&T "label" is the same as Intel "[label]" (content of label)
ngx wrote:What do you mean by "reset code segment flow and data segment registers"?
It just means reloading the CS register and the hidden portion of the register behind it. If you change your GDT, you need to make sure it's using the correct values from the updated GDT. This is why you have to perform a jump immediately after entering protected mode or long mode. You can't load CS directly, so you have to perform a jump or a ret.

In your case, you may not have actually changed any relevant settings in the GDT, you're just pointing to the same GDT (or a copy of it) using a different linear address. Still, it's a good idea to reload CS, just to be on the safe side.

In most cases, you probably won't change the GDT after you finish booting. You need kernel code and data segments, eventually user code and data segments, and a TSS per CPU. Once you have all that in place, you perform one last jump to load CS properly, and you're good. Then you can be reasonably assured that you're not going to trip over something later as a result of the CPU holding older values from the GDT that was updated mid-boot.

Update: just saw nullplan's post. Yeah, sorry, "reset code segment flow" is just sort of my own word salad. It means what I said above, you've changed the GDT, so you want to be sure you're executing from the correct code segment, with all the correct settings, so you do a jump.
rpio
Member
Member
Posts: 92
Joined: Sat Feb 20, 2021 3:11 pm

Re: Problems reloading the GDT in long mode?

Post by rpio »

nullplan wrote:
ngx wrote:Wow, never heard of inter-segment jump
Also called far jump.
ngx wrote:(also does $ mean address or content of address?)
Address. Well, "immediate" is what it means, but when applied to a label, you get the address.
ngx wrote:What do you mean by "reset code segment flow and data segment registers"?
That was probably a word salad problem, but I'm guessing he meant that you have to reload your segment registers immediately after loading a new GDT. I concur. If you don't, you are just asking for something to at some point push an invalid segment descriptor to stack, and then crash when it's loaded back.
ngx wrote:I added inter-segment jump, please correct me if I forgot something or got something wrong:
For NASM, the syntax is

Code: Select all

jmp 8:.reload_registers
Oh, if an inter segment jump is a far jump then I can't use it as I am in long mode where it is unavailable.

Then how do I reload GDT in long mode, I know about long return(iretq), but I didn't really understand what I should supply it with(push on the stack). So first I push the offset of code segment, then I push flags which I forgot how to do, and finally I push the address of where I should jump - am I right?(and how do i push flags?)

E.g.

push 0x8
SOMEHOW PUSH FLAGS
push flus_label iretq
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: Problems reloading the GDT in long mode?

Post by kzinti »

Just use retfq, no need for iretq:

Code: Select all

        pushq $0x08
        pushq $label
        retfq
label:
        ...
sj95126
Member
Member
Posts: 151
Joined: Tue Aug 11, 2020 12:14 pm

Re: Problems reloading the GDT in long mode?

Post by sj95126 »

ngx wrote:Oh, if an inter segment jump is a far jump then I can't use it as I am in long mode where it is unavailable.
Oops, sorry, yes, that's right. My mind completely overlooked the "already in long mode" part. Sheesh, where's the coffee.

Then yes, you would push a code segment selector and address on the stack and do a retq. There's no need for iretq because you don't need to update any flags. It's probably better if you don't in case you accidentally enable interrupts before you're ready.

However, if you're SURE that you haven't modified your GDT, you can probably get away with not jumping. It's perhaps not good practice, but I do it when I switch from low memory to high mapped memory. I do an lgdt of exactly the same GDT at a different linear address. I know I haven't modified it in the meantime.
rpio
Member
Member
Posts: 92
Joined: Sat Feb 20, 2021 3:11 pm

Re: Problems reloading the GDT in long mode?

Post by rpio »

kzinti wrote:Just use retfq, no need for iretq:

Code: Select all

        pushq $0x08
        pushq $label
        retfq
label:
        ...
What is the difference between retq and retfq?
This will reload everything, right or do I have to do something else?
I have heard some people lost their stack after reload - could this happen or is it just them having some bugs?
Is my GDT structure right - is it the same in long mode ?
rpio
Member
Member
Posts: 92
Joined: Sat Feb 20, 2021 3:11 pm

Re: Problems reloading the GDT in long mode?

Post by rpio »

sj95126 wrote:
ngx wrote:Oh, if an inter segment jump is a far jump then I can't use it as I am in long mode where it is unavailable.
Oops, sorry, yes, that's right. My mind completely overlooked the "already in long mode" part. Sheesh, where's the coffee.

Then yes, you would push a code segment selector and address on the stack and do a retq. There's no need for iretq because you don't need to update any flags. It's probably better if you don't in case you accidentally enable interrupts before you're ready.

However, if you're SURE that you haven't modified your GDT, you can probably get away with not jumping. It's perhaps not good practice, but I do it when I switch from low memory to high mapped memory. I do an lgdt of exactly the same GDT at a different linear address. I know I haven't modified it in the meantime.
Should I use retq or retfq?
kzinti
Member
Member
Posts: 898
Joined: Mon Feb 02, 2015 7:11 pm

Re: Problems reloading the GDT in long mode?

Post by kzinti »

ngx wrote:Should I use retq or retfq?
Why don't you try both?
Why don't you try to determine the difference between the two to answer your question?
Why don't you read the manual?
Why don't you look at existing code that does what you need?

We are not here to spoon-feed you...
rpio
Member
Member
Posts: 92
Joined: Sat Feb 20, 2021 3:11 pm

Re: Problems reloading the GDT in long mode?

Post by rpio »

kzinti wrote:
ngx wrote:Should I use retq or retfq?
Why don't you try both?
Why don't you try to determine the difference between the two to answer your question?
Why don't you read the manual?
Why don't you look at existing code that does what you need?

We are not here to spoon-feed you...
I have searched for it in the intel manual and nasm manual and it is not there, google searches give only forms and no description
Post Reply