Search code examples
assemblyx86-64cpu-architectureosdev

x86_64 running in Long mode 64-bit submode


I would ask a clarification on how an x86_64 processor knows it is in IA-32e 64 bit submode.

As far as I known, the LM-bit inside EFER MSR (0xC0000080) must be set. Furthermore the L bit in the current code segment descriptor (currently cached in the CS descriptor cache) must be set (1).

Are there any other pieces that need to be configured?


Solution

  • According to Intel 10.8.5 "Initializing IA-32e Mode" section:

    On Intel 64 processors, the IA32_EFER MSR is cleared on system reset. The operating system must be in protected mode with paging enabled before attempting to initialize IA-32e mode. IA-32e mode operation also requires physical-address extensions with four or five levels of enhanced paging structures (see Section 4.5, “4-Level Paging and 5-Level Paging”).

    Operating systems should follow this sequence to initialize IA-32e mode:

    1. Starting from protected mode, disable paging by setting CR0.PG = 0. Use the MOV CR0 instruction to disable paging (the instruction must be located in an identity-mapped page).

    2. Enable physical-address extensions (PAE) by setting CR4.PAE = 1. Failure to enable PAE will result in a #GP fault when an attempt is made to initialize IA-32e mode.

    3. Load CR3 with the physical base address of the Level 4 page map table (PML4) or Level 5 page map table (PML5).

    4. Enable IA-32e mode by setting IA32_EFER.LME = 1.

    5. Enable paging by setting CR0.PG = 1. This causes the processor to set the IA32_EFER.LMA bit to 1. The MOV CR0 instruction that enables paging and the following instructions must be located in an identity-mapped page (until such time that a branch to non-identity mapped pages can be effected).

    So, you first need to prepare 4/5-level page tables, next you must enable PAE (Physical Address Extension) and only then enable LME bit. Once you enabled LME bit you can enable paging (if you enable it before you set LME bit the processor will think you use 32-bit paging, i.e. 2/3-level page tables and produce incorrect translation).

    This picture is the illustration of how paging mode transitions work: enter image description here

    Right after switching to IA-32e 64-bit submode you must reload system data structures (GDT, IDT, TSS, etc.). Especially to be able to jump onto 64-bit code you must turn on L bit for GDT code descriptors. After reloading all those structures you can do your work as usual in 64-bit mode.