d'Oh! Mystery solved. Working through the `info registers' output you sent helped me see what was happening. The system I'm working with had a buggy printf: in particular, it was parsing but effectively throwing away the `l' in a %ld or %lx specifier, so my attempts to print GDT entries with %lx were giving misleading results. (Yes, I realize I should have been using EFI's Print routine - lesson learned...) I apologize for the confusion.
I appreciate all the pointers from you and Andrew. I feel I have a much better handle on all this now. Thanks, Brett S. On Tue, Jun 7, 2016 at 11:15 AM, Laszlo Ersek <[email protected]> wrote: > On 06/07/16 17:35, Andrew Fish wrote: >> >>> On Jun 7, 2016, at 8:31 AM, Brett Stahlman <[email protected]> wrote: >>> >>> Ah. I think I may have found the answer to at least part of my >>> question, but would appreciate if someone could confirm... >>> >>> Section 2.3.4 of the UEFI spec states: >>> "Selectors are set to be flat and are otherwise not used." >>> >>> Section 3.2.4 of the Intel processor spec (Vol. 3A 3-7) states: >>> "In 64-bit mode, segmentation is generally (but not completely) >>> disabled, creating a >>> flat 64-bit linear-address space... Note that the processor does not >>> perform segment limit checks at runtime in 64-bit mode." >>> >>> So if I'm reading all this correctly... The value of the fields >>> governing the interpretation of the segment limits (e.g., L and D/B) >>> are "don't cares" in IA32e 64-bit mode. But what about fields not >>> directly related to limit checks: e.g., P (Present) flag, and DPL >>> (Descriptor Privilege Level)? Do their values not matter either? >>> >> >> Brett, >> >> Yes you only need valid entries for segments that are used. If I'm >> remembering correctly you can use the index in the segment registers to map >> to the GDT entry. > > Right, here's the output of the "info registers" QEMU monitor command, > while standing in the setup browser in OVMF: > > RAX=00000000bfdbbcf0 RBX=00000000beafdc84 RCX=00000000bf645a98 > RDX=0000000000000000 > RSI=00000000bff5d588 RDI=00000000bff99fb0 RBP=00000000bff5d350 > RSP=00000000bff5d328 > R8 =0000000000000000 R9 =0000000000000001 R10=0000000000000064 > R11=0000000000000040 > R12=0000000000000000 R13=0000000000000000 R14=0000000000000000 > R15=0000000000000000 > RIP=00000000bfdbbcf1 RFL=00000206 [-----P-] CPL=0 II=0 A20=1 SMM=0 HLT=1 > ES =0030 0000000000000000 ffffffff 00c09300 DPL=0 DS [-WA] > CS =0038 0000000000000000 ffffffff 00a09b00 DPL=0 CS64 [-RA] > SS =0030 0000000000000000 ffffffff 00c09300 DPL=0 DS [-WA] > DS =0030 0000000000000000 ffffffff 00c09300 DPL=0 DS [-WA] > FS =0030 0000000000000000 ffffffff 00c09300 DPL=0 DS [-WA] > GS =0030 0000000000000000 ffffffff 00c09300 DPL=0 DS [-WA] > LDT=0000 0000000000000000 0000ffff 00008200 DPL=0 LDT > TR =0000 0000000000000000 0000ffff 00008b00 DPL=0 TSS64-busy > GDT= 00000000bfeea698 00000047 > IDT= 00000000bf646018 00000fff > CR0=80000033 CR2=0000000000000000 CR3=00000000bfefc000 CR4=00000668 > DR0=0000000000000000 DR1=0000000000000000 DR2=0000000000000000 > DR3=0000000000000000 > DR6=00000000ffff0ff0 DR7=0000000000000400 > EFER=0000000000000500 > FCW=037f FSW=0000 [ST=0] FTW=00 MXCSR=00001f80 > FPR0=0000000000000000 0000 FPR1=0000000000000000 0000 > FPR2=0000000000000000 0000 FPR3=0000000000000000 0000 > FPR4=0000000000000000 0000 FPR5=0000000000000000 0000 > FPR6=0000000000000000 0000 FPR7=0000000000000000 0000 > XMM00=00000000000000000000000000000000 XMM01=00000000000000000000000000000000 > XMM02=00000000000000000000000000000000 XMM03=00000000000000000000000000000000 > XMM04=00000000000000000000000000000000 XMM05=00000000000000000000000000000000 > XMM06=00000000000000000000000000000000 XMM07=00000000000000000000000000000000 > XMM08=00000000000000000000000000000000 XMM09=00000000000000000000000000000000 > XMM10=00000000000000000000000000000000 XMM11=00000000000000000000000000000000 > XMM12=00000000000000000000000000000000 XMM13=00000000000000000000000000000000 > XMM14=00000000000000000000000000000000 XMM15=00000000000000000000000000000000 > > CS points to offset 0x38 in the GDT, and the other segment registers > (data and stack) all point to the entry at offset 0x30. > > * For the DXE Core, the GDT is set up in > "MdeModulePkg/Core/DxeIplPeim/Ia32/DxeLoadFunc.c": > > // > // Global Descriptor Table (GDT) > // > GLOBAL_REMOVE_IF_UNREFERENCED IA32_GDT gGdtEntries[] = { > /* selector { Global Segment Descriptor } */ > /* 0x00 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, > //null descriptor > /* 0x08 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, > //linear data segment descriptor > /* 0x10 */ {{0xffff, 0, 0, 0xf, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, > //linear code segment descriptor > /* 0x18 */ {{0xffff, 0, 0, 0x3, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, > //system data segment descriptor > /* 0x20 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, > //system code segment descriptor > /* 0x28 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, > //spare segment descriptor > /* 0x30 */ {{0xffff, 0, 0, 0x2, 1, 0, 1, 0xf, 0, 0, 1, 1, 0}}, > //system data segment descriptor > /* 0x38 */ {{0xffff, 0, 0, 0xa, 1, 0, 1, 0xf, 0, 1, 0, 1, 0}}, > //system code segment descriptor > /* 0x40 */ {{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}}, > //spare segment descriptor > }; > > * For the DXE phase, the GDT is set up by the CpuDxe driver, in its > entry point. It uses the GDT entries at offsets LINEAR_DATA64_SEL (0x30) > and LINEAR_CODE64_SEL (0x38) in the same vein; see > InitGlobalDescriptorTable() in "UefiCpuPkg/CpuDxe/CpuGdt.c". And, the > byte-limit (= limit in units * unit granularity) is never raised above > 4GB, I think. > > I believe the settings from this driver are the ones visible in the > above "info registers" output. > > * In SMM, the GDT is managed by UefiCpuPkg/PiSmmCpuDxeSmm, and it also > seems to store the GDT entry that describes the long mode code segment > at offset 0x38 (LONG_MODE_CS) in the GDT. > > So 0x38 appears to be an edk2 convention for the offset of the > descriptor that describes the 64-bit code segment. > > Related commit: > - https://github.com/tianocore/edk2/commit/0d4c1db81aab > > Related emails preceding that commit: > - http://thread.gmane.org/gmane.comp.bios.edk2.devel/3509/focus=3568 > - http://thread.gmane.org/gmane.comp.bios.edk2.devel/3509/focus=3605 > - http://thread.gmane.org/gmane.comp.bios.edk2.devel/3571 > > Thanks > Laszlo > >>> On Tue, Jun 7, 2016 at 8:46 AM, Brett Stahlman <[email protected]> >>> wrote: >>>> Just inside my 64-bit x64 EFI boot loader, I print out the contents of >>>> the GDT to see how it was initialized by the firmware. I've tried >>>> running the boot loader both in QEMU (OVMF) and VMware ESXi. In both >>>> cases, the first 5 descriptors after the leading null descriptor look >>>> like this: >>>> >>>> 0x000000000000ffff >>>> >>>> Note all the leading zeroes: in particular, flags such as D/B and L >>>> being clear seem to suggest a GDT that's inappropriate for 64-bit long >>>> mode. I've verified by looking at CR* registers and such that the >>>> firmware has indeed placed me in IA32e "long mode" with identity >>>> paging. This is what I would expect, in light of section 2.3.4 in the >>>> UEFI spec. But why does the GDT have all leading 0's? >>>> >>>> Thanks, >>>> Brett S. >>> _______________________________________________ >>> edk2-devel mailing list >>> [email protected] >>> https://lists.01.org/mailman/listinfo/edk2-devel >> >> _______________________________________________ >> edk2-devel mailing list >> [email protected] >> https://lists.01.org/mailman/listinfo/edk2-devel >> > _______________________________________________ edk2-devel mailing list [email protected] https://lists.01.org/mailman/listinfo/edk2-devel

