Loading 64-bit GDT When Switch to 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.
Post Reply
mesterjakel
Posts: 2
Joined: Tue Feb 05, 2013 3:14 pm

Loading 64-bit GDT When Switch to Long Mode

Post by mesterjakel »

First of all thanks (1<<20)-1 for the awesome tutorials and information present on osdev.org! Second of all I apologize in advance for probably making all the classic newbie mistakes with this post (I promise, I did try to search for an answer before posting!)

AMD64 Architecture Programmer’s Manual Volume 2 Rev. 3.22 states in section 14.6.1 "Activating Long Mode" that:
Enable paging by setting CR0.PG to 1. This causes the processor to set the EFER.LMA bit to 1.
The instruction following the MOV CR0 that enables paging must be a branch[...]
(Emphasis mine)

However Entering Long Mode Directly and a few other samples I've looked at (a noteable exception being the sample directly following in the AMD manual) load the 64-bit GDT after enabling paging, but before branching.

Normally I would just ignore this (as I'm only playing around with os/x64 development for my own amusement) but since I can't get the sample (*) to work if follow the "proper way" (by moving the

Code: Select all

lgdt [GDT.pointer]
instruction to some place after jumping to 64-bit mode) I got curious about what I was doing wrong.

My question is: am I misreading the documentation or missing something? I'm testing with qemu and virtualbox (i realize they share the same emulation core).

(*) What prompted me to ask this question was my own code only working if I loaded the 64-bit GDT before switching to long mode, not so much randomly moving around instructions in the sample.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Loading 64-bit GDT When Switch to Long Mode

Post by bluemoon »

It's totally legal to LGDT after jump to 64-bit segment, however you should aware the difference in parameter between 32 and 64-bit modes, and double check the segment attributes of the current operating mode (that execute LGDT).
mesterjakel wrote:What prompted me to ask this question was my own code only working if I loaded the 64-bit GDT before switching to long mode, not so much randomly moving around instructions in the sample.
How would you think you can enter (64-bit) long mode without loading 64-bit GDT?

The proper way is enter 32-bit protected mode (you also loaded 32-bit GDT in this step), then enable LME to enter compatibility mode, then load 64-bit GDT, and jump to 64-bit segment, check the manual for details and example. The "enter long mode directly" hack currently works, but it is not the official method thus you can't blame anyone if it does not work in the future.
rdos
Member
Member
Posts: 3306
Joined: Wed Oct 01, 2008 1:55 pm

Re: Loading 64-bit GDT When Switch to Long Mode

Post by rdos »

There is no need to load a 64-bit GDT unless you plan to place GDT above 4G. The protected mode GDT will work just fine in long mode as well.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Loading 64-bit GDT When Switch to Long Mode

Post by bluemoon »

By 64-bit GDT I was referring the 16 bytes GDT designed for 64-bit mode.
mesterjakel
Posts: 2
Joined: Tue Feb 05, 2013 3:14 pm

Re: Loading 64-bit GDT When Switch to Long Mode

Post by mesterjakel »

bluemoon wrote:It's totally legal to LGDT after jump to 64-bit segment, however you should aware the difference in parameter between 32 and 64-bit modes, and double check the segment attributes of the current operating mode (that execute LGDT).
mesterjakel wrote:What prompted me to ask this question was my own code only working if I loaded the 64-bit GDT before switching to long mode, not so much randomly moving around instructions in the sample.
How would you think you can enter (64-bit) long mode without loading 64-bit GDT?

The proper way is enter 32-bit protected mode (you also loaded 32-bit GDT in this step), then enable LME to enter compatibility mode, then load 64-bit GDT, and jump to 64-bit segment, check the manual for details and example. The "enter long mode directly" hack currently works, but it is not the official method thus you can't blame anyone if it does not work in the future.
D'oh, you're of course right that it could never work in the "Entering LM directly" example as there is no proper 32-bit GDT loaded.

In my own code I'm already in 32-bit protected mode (with standard flat 4G descriptors) and I guess what was tripping up my understanding was that loading a 64-bit GDT is OK since I already entered compability mode after setting EFER.LME=1 (long mode enable).

I'm not particularly interested in the direct 16->64bit transition, it just seemed (a mistake I now realize) like the a good way to test/explain my theory. And I guess the part about the instruction following the mov to cr0 having to be a branch is just not strictly enforced (either way that turned out to be a red herring w.r.g. to my question).

Thanks!
rdos
Member
Member
Posts: 3306
Joined: Wed Oct 01, 2008 1:55 pm

Re: Loading 64-bit GDT When Switch to Long Mode

Post by rdos »

bluemoon wrote:By 64-bit GDT I was referring the 16 bytes GDT designed for 64-bit mode.
The only GDT descriptor that is 16 bytes in long mode is the call gate descriptor, and it is not very useful (because the target selector must be 64-bit). You can define these descriptors in a 32-bit GDT as well. The only difference between the 32 and 64 bit ldgt instructions is how many bits are loaded. Once loaded, the GDT works the same way regardless how the base was loaded.

It is the IDT that contains 16 byte descriptors, not the GDT.
User avatar
Owen
Member
Member
Posts: 1700
Joined: Fri Jun 13, 2008 3:21 pm
Location: Cambridge, United Kingdom
Contact:

Re: Loading 64-bit GDT When Switch to Long Mode

Post by Owen »

rdos wrote:
bluemoon wrote:By 64-bit GDT I was referring the 16 bytes GDT designed for 64-bit mode.
The only GDT descriptor that is 16 bytes in long mode is the call gate descriptor
TSS
LDT
rdos
Member
Member
Posts: 3306
Joined: Wed Oct 01, 2008 1:55 pm

Re: Loading 64-bit GDT When Switch to Long Mode

Post by rdos »

Owen wrote:
rdos wrote:
bluemoon wrote:By 64-bit GDT I was referring the 16 bytes GDT designed for 64-bit mode.
The only GDT descriptor that is 16 bytes in long mode is the call gate descriptor
TSS
LDT
Neither the TSS, nor the LDT need to be 16 bytes long. They can be loaded in protected mode with 8 bytes entries, and they will work just fine. It is similar to GDT. If the OS doesn't need to reload these while in long mode, they can be kept as single descriptor entries. I know it works because I reload these in protected mode in the mode-switching code. The LDT especially doesn't need to be reloaded in long mode under normal circumstances since long mode doesn't support segmentation. I avoid having a 16 byte TSS by having a per CPU core TSS for long mode tasks which is loaded before switching to long mode in the mode switch code.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Loading 64-bit GDT When Switch to Long Mode

Post by bluemoon »

The manual said you need it, so although it turns out that it works with 32-bit GDT I would consider it a trick, or pure luck, or an undefined behavior, but not unnecessary.
User avatar
Owen
Member
Member
Posts: 1700
Joined: Fri Jun 13, 2008 3:21 pm
Location: Cambridge, United Kingdom
Contact:

Re: Loading 64-bit GDT When Switch to Long Mode

Post by Owen »

rdos wrote:
Owen wrote:
rdos wrote:The only GDT descriptor that is 16 bytes in long mode is the call gate descriptor
TSS
LDT
Neither the TSS, nor the LDT need to be 16 bytes long. They can be loaded in protected mode with 8 bytes entries, and they will work just fine. It is similar to GDT. If the OS doesn't need to reload these while in long mode, they can be kept as single descriptor entries. I know it works because I reload these in protected mode in the mode-switching code. The LDT especially doesn't need to be reloaded in long mode under normal circumstances since long mode doesn't support segmentation. I avoid having a 16 byte TSS by having a per CPU core TSS for long mode tasks which is loaded before switching to long mode in the mode switch code.
In spite of the above, when loaded in long mode they are 64-bit descriptors.

The LDT is needed by some apps, even in long mode (the most common examples are apps like dosemu, to provide DPMI services, and WINE, to support Win32 exception handling for the apps running inside of it)

Most OSes will place their TSSes somewhere in the higher half of the long mode address space, thereby requiring it be loaded in long mode.
rdos
Member
Member
Posts: 3306
Joined: Wed Oct 01, 2008 1:55 pm

Re: Loading 64-bit GDT When Switch to Long Mode

Post by rdos »

bluemoon wrote:The manual said you need it, so although it turns out that it works with 32-bit GDT I would consider it a trick, or pure luck, or an undefined behavior, but not unnecessary.
I don't consider it a trick. It is pretty logical that LGDT will setup the base of the GDT, and then either use a 24-bit, 32-bit or 64-bit operand. The GDT semantics operates using the current processor mode (real mode, V86 mode, protected mode, long mode). Interpretation of gates both in IDT and GDT is dependent on processor mode, not how the base for the GDT/IDT were loaded. If this was not so, the processor would need some invisible state to determine the state. I find it pretty unlikely that this will become broken in any future processor.
User avatar
bluemoon
Member
Member
Posts: 1761
Joined: Wed Dec 01, 2010 3:41 am
Location: Hong Kong

Re: Loading 64-bit GDT When Switch to Long Mode

Post by bluemoon »

I would not encourage to ignore the manual or specification just because it should work as logical consequent... especially there is no justifiable benefits in usual case. However I agree there is justifiable benefits is your case.
rdos
Member
Member
Posts: 3306
Joined: Wed Oct 01, 2008 1:55 pm

Re: Loading 64-bit GDT When Switch to Long Mode

Post by rdos »

The TSS load operates in the same way, which was essential in my implementation. It doesn't matter if a TSS is loaded in protected mode or long mode, it will still use the semantics of the current operation mode. This also was not obvious in the manual, but that's the way it works in both Intel and AMD. Thus, in my implementation, I load the long mode per-core TSS as a 8-byte entry in protected mode, and once the processor is switched to long mode, this TSS uses the fields of long mode, not of protected mode.
Post Reply