From c85ef31f6a6f0d7ba4fc7e72ce65895537b59196 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Sun, 13 Oct 2019 19:33:00 +0200 Subject: [PATCH] [FREELDR] Improvements for GDT descriptors initialization. Triggered by a fix attempt by M.Harmstone in PR #1905. - Introduce #defines and helper functions so as to initialize the descriptors in a human-readable and tractable way, without magic values. - Rework some comments. - Document what the changes are in (Longhorn and) Vista+. Data has been obtained through using the WinDbg command: dg 0x00 0xFF (for example), that lists all the selectors from 0x00 to 0xFF included. See https://docs.microsoft.com/en-us/windows-hardware/drivers/debugger/dg--display-selector- for more details. --- boot/freeldr/freeldr/ntldr/arch/i386/winldr.c | 510 +++++++++++------- 1 file changed, 302 insertions(+), 208 deletions(-) diff --git a/boot/freeldr/freeldr/ntldr/arch/i386/winldr.c b/boot/freeldr/freeldr/ntldr/arch/i386/winldr.c index c3917709b32..ae1a7979be9 100644 --- a/boot/freeldr/freeldr/ntldr/arch/i386/winldr.c +++ b/boot/freeldr/freeldr/ntldr/arch/i386/winldr.c @@ -6,7 +6,7 @@ * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org) */ -/* INCLUDES ***************************************************************/ +/* INCLUDES ******************************************************************/ #include #include @@ -23,14 +23,148 @@ DBG_DEFAULT_CHANNEL(WINDOWS); // This is needed only for SetProcessorContext routine #pragma pack(2) - typedef struct - { - USHORT Limit; - ULONG Base; - } GDTIDT; +typedef struct +{ + USHORT Limit; + ULONG Base; +} GDTIDT; #pragma pack(4) -/* GLOBALS ***************************************************************/ +/* + * Consider adding these definitions into + * ntoskrnl/include/internal/i386/intrin_i.h and/or the NDK. + */ + +#define DPL_SYSTEM 0 +#define DPL_USER 3 + +#define TYPE_TSS16A 0x01 // 16-bit Task State Segment (Available) +#define TYPE_LDT 0x02 // Local Descriptor Table +#define TYPE_TSS16B 0x03 // 16-bit Task State Segment (Busy) +#define TYPE_CALL16 0x04 // 16-bit Call Gate +#define TYPE_TASK 0x05 // Task Gate (I386_TASK_GATE) +#define TYPE_INT16 0x06 // 16-bit Interrupt Gate +#define TYPE_TRAP16 0x07 // 16-bit Trap Gate +// #define TYPE_RESERVED_1 0x08 +#define TYPE_TSS32A 0x09 // 32-bit Task State Segment (Available) (I386_TSS) +// #define TYPE_RESERVED_2 0x0A +#define TYPE_TSS32B 0x0B // 32-bit Task State Segment (Busy) (I386_ACTIVE_TSS) +#define TYPE_CALL32 0x0C // 32-bit Call Gate (I386_CALL_GATE) +// #define TYPE_RESERVED_3 0x0D +#define TYPE_INT32 0x0E // 32-bit Interrupt Gate (I386_INTERRUPT_GATE) +#define TYPE_TRAP32 0x0F // 32-bit Trap Gate (I386_TRAP_GATE) + +#define DESCRIPTOR_ACCESSED 0x1 +#define DESCRIPTOR_READ_WRITE 0x2 +#define DESCRIPTOR_EXECUTE_READ 0x2 +#define DESCRIPTOR_EXPAND_DOWN 0x4 +#define DESCRIPTOR_CONFORMING 0x4 +#define DESCRIPTOR_CODE 0x8 + +#define TYPE_CODE (0x10 | DESCRIPTOR_CODE | DESCRIPTOR_EXECUTE_READ) +#define TYPE_DATA (0x10 | DESCRIPTOR_READ_WRITE) + +PKGDTENTRY +FORCEINLINE +KiGetGdtEntry( + IN PVOID pGdt, + IN USHORT Selector) +{ + return (PKGDTENTRY)((ULONG_PTR)pGdt + (Selector & ~RPL_MASK)); +} + +VOID +FORCEINLINE +KiSetGdtDescriptorBase( + IN OUT PKGDTENTRY Entry, + IN ULONG32 Base) +{ + Entry->BaseLow = (USHORT)(Base & 0xffff); + Entry->HighWord.Bytes.BaseMid = (UCHAR)((Base >> 16) & 0xff); + Entry->HighWord.Bytes.BaseHi = (UCHAR)((Base >> 24) & 0xff); + // Entry->BaseUpper = (ULONG)(Base >> 32); +} + +VOID +FORCEINLINE +KiSetGdtDescriptorLimit( + IN OUT PKGDTENTRY Entry, + IN ULONG Limit) +{ + if (Limit < 0x100000) + { + Entry->HighWord.Bits.Granularity = 0; + } + else + { + Limit >>= 12; + Entry->HighWord.Bits.Granularity = 1; + } + Entry->LimitLow = (USHORT)(Limit & 0xffff); + Entry->HighWord.Bits.LimitHi = ((Limit >> 16) & 0x0f); +} + +VOID +KiSetGdtEntryEx( + IN OUT PKGDTENTRY Entry, + IN ULONG32 Base, + IN ULONG Limit, + IN UCHAR Type, + IN UCHAR Dpl, + IN BOOLEAN Granularity, + IN UCHAR SegMode) // 0: 16-bit, 1: 32-bit, 2: 64-bit +{ + KiSetGdtDescriptorBase(Entry, Base); + KiSetGdtDescriptorLimit(Entry, Limit); + Entry->HighWord.Bits.Type = (Type & 0x1f); + Entry->HighWord.Bits.Dpl = (Dpl & 0x3); + Entry->HighWord.Bits.Pres = (Type != 0); // Present, must be 1 when the GDT entry is valid. + Entry->HighWord.Bits.Sys = 0; // System + Entry->HighWord.Bits.Reserved_0 = 0; // LongMode = !!(SegMode & 1); + Entry->HighWord.Bits.Default_Big = !!(SegMode & 2); + Entry->HighWord.Bits.Granularity |= !!Granularity; // The flag may have been already set by KiSetGdtDescriptorLimit(). + // Entry->MustBeZero = 0; +} + +VOID +FORCEINLINE +KiSetGdtEntry( + IN OUT PKGDTENTRY Entry, + IN ULONG32 Base, + IN ULONG Limit, + IN UCHAR Type, + IN UCHAR Dpl, + IN UCHAR SegMode) // 0: 16-bit, 1: 32-bit, 2: 64-bit +{ + KiSetGdtEntryEx(Entry, Base, Limit, Type, Dpl, FALSE, SegMode); +} + +#if 0 +VOID +DumpGDTEntry(ULONG_PTR Base, ULONG Selector) +{ + PKGDTENTRY pGdt = (PKGDTENTRY)((ULONG_PTR)Base + Selector); + + TRACE("\n" + "Selector 0x%04x\n" + "===============\n" + "LimitLow = 0x%04x\n" + "BaseLow = 0x%04x\n" + "HighWord.Bytes.BaseMid = 0x%02x\n" + "HighWord.Bytes.Flags1 = 0x%02x\n" + "HighWord.Bytes.Flags2 = 0x%02x\n" + "HighWord.Bytes.BaseHi = 0x%02x\n" + "\n", + Selector, + pGdt->LimitLow, pGdt->BaseLow, + pGdt->HighWord.Bytes.BaseMid, + pGdt->HighWord.Bytes.Flags1, + pGdt->HighWord.Bytes.Flags2, + pGdt->HighWord.Bytes.BaseHi); +} +#endif + +/* GLOBALS *******************************************************************/ PHARDWARE_PTE PDE; PHARDWARE_PTE HalPageTable; @@ -44,7 +178,7 @@ ULONG PcrBasePage; ULONG TssBasePage; PVOID GdtIdt; -/* FUNCTIONS **************************************************************/ +/* FUNCTIONS *****************************************************************/ static BOOLEAN @@ -160,7 +294,7 @@ MempSetupPaging(IN PFN_NUMBER StartPage, if (StartPage+NumberOfPages >= 0x80000) { // - // We can't map this as it requires more than 1 PDE + // We cannot map this as it requires more than 1 PDE // and in fact it's not possible at all ;) // //Print(L"skipping...\n"); @@ -259,12 +393,12 @@ static BOOLEAN WinLdrMapSpecialPages(void) { - - //VideoDisplayString(L"Hello from VGA, going into the kernel\n"); TRACE("HalPageTable: 0x%X\n", HalPageTable); - // Page Tables have been setup, make special handling for PCR and TSS - // (which is done in BlSetupFotNt in usual ntldr) + /* + * The Page Tables have been setup, make special handling + * for the boot processor PCR and KI_USER_SHARED_DATA. + */ HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage+1; HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1; HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1; @@ -273,10 +407,10 @@ WinLdrMapSpecialPages(void) HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1; HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1; - // Map APIC + /* Map APIC */ WinLdrpMapApic(); - // Map VGA memory + /* Map VGA memory */ //VideoMemoryBase = MmMapIoSpace(0xb8000, 4000, MmNonCached); //TRACE("VideoMemoryBase: 0x%X\n", VideoMemoryBase); @@ -319,13 +453,12 @@ void WinLdrSetupMachineDependent(PLOADER_PARAMETER_BLOCK LoaderBlock) LoaderBlock->u.I386.CommonDataArea = NULL; // Force No ABIOS support LoaderBlock->u.I386.MachineType = MACHINE_TYPE_ISA; - /* Allocate 2 pages for PCR */ + /* Allocate 2 pages for PCR: one for the boot processor PCR and one for KI_USER_SHARED_DATA */ Pcr = (ULONG_PTR)MmAllocateMemoryWithType(2 * MM_PAGE_SIZE, LoaderStartupPcrPage); PcrBasePage = Pcr >> MM_PAGE_SHIFT; - if (Pcr == 0) { - UiMessageBox("Can't allocate PCR."); + UiMessageBox("Could not allocate PCR."); return; } @@ -334,17 +467,20 @@ void WinLdrSetupMachineDependent(PLOADER_PARAMETER_BLOCK LoaderBlock) //TssPages = TssSize / MM_PAGE_SIZE; Tss = (ULONG_PTR)MmAllocateMemoryWithType(TssSize, LoaderMemoryData); - TssBasePage = Tss >> MM_PAGE_SHIFT; + if (Tss == 0) + { + UiMessageBox("Could not allocate TSS."); + return; + } /* Allocate space for new GDT + IDT */ BlockSize = NUM_GDT*sizeof(KGDTENTRY) + NUM_IDT*sizeof(KIDTENTRY);//FIXME: Use GDT/IDT limits here? NumPages = (BlockSize + MM_PAGE_SIZE - 1) >> MM_PAGE_SHIFT; GdtIdt = (PKGDTENTRY)MmAllocateMemoryWithType(NumPages * MM_PAGE_SIZE, LoaderMemoryData); - if (GdtIdt == NULL) { - UiMessageBox("Can't allocate pages for GDT+IDT!"); + UiMessageBox("Could not allocate pages for GDT+IDT!"); return; } @@ -380,37 +516,36 @@ WinLdrSetProcessorContext(void) Pcr = KIP0PCRADDRESS; Tss = KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT); - TRACE("GDtIdt %p, Pcr %p, Tss 0x%08X\n", - GdtIdt, Pcr, Tss); + TRACE("GdtIdt %p, Pcr %p, Tss 0x%08x\n", + GdtIdt, Pcr, Tss); - // Enable paging + /* Enable paging */ //BS->ExitBootServices(ImageHandle,MapKey); - // Disable Interrupts + /* Disable Interrupts */ _disable(); - // Re-initialize EFLAGS + /* Re-initialize EFLAGS */ __writeeflags(0); - // Set the PDBR + /* Set the PDBR */ __writecr3((ULONG_PTR)PDE); - // Enable paging by modifying CR0 + /* Enable paging by modifying CR0 */ __writecr0(__readcr0() | CR0_PG); - // Kernel expects the PCR to be zero-filled on startup - // FIXME: Why zero it here when we can zero it right after allocation? - RtlZeroMemory((PVOID)Pcr, MM_PAGE_SIZE); //FIXME: Why zero only 1 page when we allocate 2? + /* The Kernel expects the boot processor PCR to be zero-filled on startup */ + RtlZeroMemory((PVOID)Pcr, MM_PAGE_SIZE); - // Get old values of GDT and IDT + /* Get old values of GDT and IDT */ Ke386GetGlobalDescriptorTable(&GdtDesc); __sidt(&IdtDesc); - // Save old IDT - OldIdt.Base = IdtDesc.Base; + /* Save old IDT */ + OldIdt.Base = IdtDesc.Base; OldIdt.Limit = IdtDesc.Limit; - // Prepare new IDT+GDT + /* Prepare new IDT+GDT */ GdtDesc.Base = KSEG0_BASE | (ULONG_PTR)GdtIdt; GdtDesc.Limit = NUM_GDT * sizeof(KGDTENTRY) - 1; IdtDesc.Base = (ULONG)((PUCHAR)GdtDesc.Base + GdtDesc.Limit + 1); @@ -423,170 +558,129 @@ WinLdrSetProcessorContext(void) pGdt = (PKGDTENTRY)GdtDesc.Base; pIdt = (PKIDTENTRY)IdtDesc.Base; - // - // Code selector (0x8) - // Flat 4Gb - // - pGdt[1].LimitLow = 0xFFFF; - pGdt[1].BaseLow = 0; - pGdt[1].HighWord.Bytes.BaseMid = 0; - pGdt[1].HighWord.Bytes.Flags1 = 0x9A; - pGdt[1].HighWord.Bytes.Flags2 = 0xCF; - pGdt[1].HighWord.Bytes.BaseHi = 0; - - // - // Data selector (0x10) - // Flat 4Gb - // - pGdt[2].LimitLow = 0xFFFF; - pGdt[2].BaseLow = 0; - pGdt[2].HighWord.Bytes.BaseMid = 0; - pGdt[2].HighWord.Bytes.Flags1 = 0x92; - pGdt[2].HighWord.Bytes.Flags2 = 0xCF; - pGdt[2].HighWord.Bytes.BaseHi = 0; - - // - // Selector (0x18) - // Flat 2Gb - // - pGdt[3].LimitLow = 0xFFFF; - pGdt[3].BaseLow = 0; - pGdt[3].HighWord.Bytes.BaseMid = 0; - pGdt[3].HighWord.Bytes.Flags1 = 0xFA; - pGdt[3].HighWord.Bytes.Flags2 = 0xCF; - pGdt[3].HighWord.Bytes.BaseHi = 0; - - // - // Selector (0x20) - // Flat 2Gb - // - pGdt[4].LimitLow = 0xFFFF; - pGdt[4].BaseLow = 0; - pGdt[4].HighWord.Bytes.BaseMid = 0; - pGdt[4].HighWord.Bytes.Flags1 = 0xF2; - pGdt[4].HighWord.Bytes.Flags2 = 0xCF; - pGdt[4].HighWord.Bytes.BaseHi = 0; - - // - // TSS Selector (0x28) - // - pGdt[5].LimitLow = 0x78-1; //FIXME: Check this - pGdt[5].BaseLow = (USHORT)(Tss & 0xffff); - pGdt[5].HighWord.Bytes.BaseMid = (UCHAR)((Tss >> 16) & 0xff); - pGdt[5].HighWord.Bytes.Flags1 = 0x89; - pGdt[5].HighWord.Bytes.Flags2 = 0x00; - pGdt[5].HighWord.Bytes.BaseHi = (UCHAR)((Tss >> 24) & 0xff); - - // - // PCR Selector (0x30) - // - pGdt[6].LimitLow = 0x01; - pGdt[6].BaseLow = (USHORT)(Pcr & 0xffff); - pGdt[6].HighWord.Bytes.BaseMid = (UCHAR)((Pcr >> 16) & 0xff); - pGdt[6].HighWord.Bytes.Flags1 = 0x92; - pGdt[6].HighWord.Bytes.Flags2 = 0xC0; - pGdt[6].HighWord.Bytes.BaseHi = (UCHAR)((Pcr >> 24) & 0xff); - - // - // Selector (0x38) - // - pGdt[7].LimitLow = 0xFFFF; - pGdt[7].BaseLow = 0; - pGdt[7].HighWord.Bytes.BaseMid = 0; - pGdt[7].HighWord.Bytes.Flags1 = 0xF3; - pGdt[7].HighWord.Bytes.Flags2 = 0x40; - pGdt[7].HighWord.Bytes.BaseHi = 0; - - // - // Some BIOS stuff (0x40) - // - pGdt[8].LimitLow = 0xFFFF; - pGdt[8].BaseLow = 0x400; - pGdt[8].HighWord.Bytes.BaseMid = 0; - pGdt[8].HighWord.Bytes.Flags1 = 0xF2; - pGdt[8].HighWord.Bytes.Flags2 = 0x0; - pGdt[8].HighWord.Bytes.BaseHi = 0; - - // - // Selector (0x48) - // - pGdt[9].LimitLow = 0; - pGdt[9].BaseLow = 0; - pGdt[9].HighWord.Bytes.BaseMid = 0; - pGdt[9].HighWord.Bytes.Flags1 = 0; - pGdt[9].HighWord.Bytes.Flags2 = 0; - pGdt[9].HighWord.Bytes.BaseHi = 0; - - // - // Selector (0x50) - // - pGdt[10].LimitLow = 0xFFFF; //FIXME: Not correct! - pGdt[10].BaseLow = 0; - pGdt[10].HighWord.Bytes.BaseMid = 0x2; - pGdt[10].HighWord.Bytes.Flags1 = 0x89; - pGdt[10].HighWord.Bytes.Flags2 = 0; - pGdt[10].HighWord.Bytes.BaseHi = 0; - - // - // Selector (0x58) - // - pGdt[11].LimitLow = 0xFFFF; - pGdt[11].BaseLow = 0; - pGdt[11].HighWord.Bytes.BaseMid = 0x2; - pGdt[11].HighWord.Bytes.Flags1 = 0x9A; - pGdt[11].HighWord.Bytes.Flags2 = 0; - pGdt[11].HighWord.Bytes.BaseHi = 0; - - // - // Selector (0x60) - // - pGdt[12].LimitLow = 0xFFFF; - pGdt[12].BaseLow = 0; //FIXME: Maybe not correct, but noone cares - pGdt[12].HighWord.Bytes.BaseMid = 0x2; - pGdt[12].HighWord.Bytes.Flags1 = 0x92; - pGdt[12].HighWord.Bytes.Flags2 = 0; - pGdt[12].HighWord.Bytes.BaseHi = 0; - - // - // Video buffer Selector (0x68) - // - pGdt[13].LimitLow = 0x3FFF; - pGdt[13].BaseLow = 0x8000; - pGdt[13].HighWord.Bytes.BaseMid = 0x0B; - pGdt[13].HighWord.Bytes.Flags1 = 0x92; - pGdt[13].HighWord.Bytes.Flags2 = 0; - pGdt[13].HighWord.Bytes.BaseHi = 0; - - // - // Points to GDT (0x70) - // - pGdt[14].LimitLow = NUM_GDT*sizeof(KGDTENTRY) - 1; - pGdt[14].BaseLow = 0x7000; - pGdt[14].HighWord.Bytes.BaseMid = 0xFF; - pGdt[14].HighWord.Bytes.Flags1 = 0x92; - pGdt[14].HighWord.Bytes.Flags2 = 0; - pGdt[14].HighWord.Bytes.BaseHi = 0xFF; - - // - // Some unused descriptors should go here - // - - // Copy the old IDT + /* KGDT_NULL (0x00) Null Selector - Unused */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_NULL), 0x0000, 0, 0, DPL_SYSTEM, 0); + // DumpGDTEntry(GdtDesc.Base, KGDT_NULL); + + /* KGDT_R0_CODE (0x08) Ring 0 Code selector - Flat 4Gb */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_R0_CODE), 0x0000, 0xFFFFFFFF, + TYPE_CODE, DPL_SYSTEM, 2); + // DumpGDTEntry(GdtDesc.Base, KGDT_R0_CODE); + + /* KGDT_R0_DATA (0x10) Ring 0 Data selector - Flat 4Gb */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_R0_DATA), 0x0000, 0xFFFFFFFF, + TYPE_DATA, DPL_SYSTEM, 2); + // DumpGDTEntry(GdtDesc.Base, KGDT_R0_DATA); + + /* KGDT_R3_CODE (0x18) Ring 3 Code Selector - Flat 2Gb */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_R3_CODE), 0x0000, 0xFFFFFFFF, + TYPE_CODE, DPL_USER, 2); + // DumpGDTEntry(GdtDesc.Base, KGDT_R3_CODE); + + /* KGDT_R3_DATA (0x20) Ring 3 Data Selector - Flat 2Gb */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_R3_DATA), 0x0000, 0xFFFFFFFF, + TYPE_DATA, DPL_USER, 2); + // DumpGDTEntry(GdtDesc.Base, KGDT_R3_DATA); + + /* KGDT_TSS (0x28) TSS Selector (Ring 0) */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_TSS), (ULONG32)Tss, + 0x78-1 /* FIXME: Check this; would be sizeof(KTSS)-1 */, + TYPE_TSS32A, DPL_SYSTEM, 0); + // DumpGDTEntry(GdtDesc.Base, KGDT_TSS); + + /* + * KGDT_R0_PCR (0x30) PCR Selector (Ring 0) + * + * IMPORTANT COMPATIBILITY NOTE: + * Windows <= Server 2003 sets a Base == KIP0PCRADDRESS (0xffdff000 on x86) + * with a Limit of 1 page (LimitLow == 1, Granularity == 1, that is interpreted + * as a "Limit" == 0x1fff but is incorrect, of course). + * On Windows Longhorn/Vista+ however, the Base is not hardcoded to KIP0PCRADDRESS + * and the limit is set in bytes (Granularity == 0): + * Longhorn/Vista reports LimitLow == 0x0fff == MM_PAGE_SIZE - 1, whereas + * Windows 7+ uses larger sizes there (not aligned on a page boundary). + */ +#if 1 + /* Server 2003 way */ + KiSetGdtEntryEx(KiGetGdtEntry(pGdt, KGDT_R0_PCR), (ULONG32)Pcr, 0x1, + TYPE_DATA, DPL_SYSTEM, TRUE, 2); +#else + /* Vista+ way */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_R0_PCR), (ULONG32)Pcr, MM_PAGE_SIZE - 1, + TYPE_DATA, DPL_SYSTEM, 2); +#endif + // DumpGDTEntry(GdtDesc.Base, KGDT_R0_PCR); + + /* KGDT_R3_TEB (0x38) Thread Environment Block Selector (Ring 3) */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_R3_TEB), 0x0000, 0x0FFF, + TYPE_DATA | DESCRIPTOR_ACCESSED, DPL_USER, 2); + // DumpGDTEntry(GdtDesc.Base, KGDT_R3_TEB); + + /* KGDT_VDM_TILE (0x40) VDM BIOS Data Area Selector (Ring 3) */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_VDM_TILE), 0x0400, 0xFFFF, + TYPE_DATA, DPL_USER, 0); + // DumpGDTEntry(GdtDesc.Base, KGDT_VDM_TILE); + + /* KGDT_LDT (0x48) LDT Selector (Reserved) */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_LDT), 0x0000, 0, 0, DPL_SYSTEM, 0); + // DumpGDTEntry(GdtDesc.Base, KGDT_LDT); + + /* KGDT_DF_TSS (0x50) Double-Fault Task Switch Selector (Ring 0) */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_DF_TSS), 0x20000 /* FIXME: Not correct! */, + 0xFFFF /* FIXME: Not correct! */, + TYPE_TSS32A, DPL_SYSTEM, 0); + // DumpGDTEntry(GdtDesc.Base, KGDT_DF_TSS); + + /* KGDT_NMI_TSS (0x58) NMI Task Switch Selector (Ring 0) */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_NMI_TSS), 0x20000, 0xFFFF, + TYPE_CODE, DPL_SYSTEM, 0); + // DumpGDTEntry(GdtDesc.Base, KGDT_NMI_TSS); + + /* Selector (0x60) - Unused (Reserved) on Windows Longhorn/Vista+ */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, 0x60), 0x20000 /* FIXME: Maybe not correct, but noone cares */, + 0xFFFF, TYPE_DATA, DPL_SYSTEM, 0); + // DumpGDTEntry(GdtDesc.Base, 0x60); + + /* Video Display Buffer Selector (0x68) - Unused (Reserved) on Windows Longhorn/Vista+ */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, 0x68), 0xB8000, 0x3FFF, + TYPE_DATA, DPL_SYSTEM, 0); + // DumpGDTEntry(GdtDesc.Base, 0x68); + + /* + * GDT Alias Selector (points to GDT) (0x70) + * + * IMPORTANT COMPATIBILITY NOTE: + * The Base is not fixed to 0xFFFF7000 on Windows Longhorn/Vista+. + */ + KiSetGdtEntry(KiGetGdtEntry(pGdt, 0x70), 0xFFFF7000 /* GdtDesc.Base ?? */, GdtDesc.Limit, + TYPE_DATA, DPL_SYSTEM, 0); + // DumpGDTEntry(GdtDesc.Base, 0x70); + + /* + * Windows <= Server 2003 defines three additional unused but valid + * descriptors there, possibly for debugging purposes only. + * They are not present on Windows Longhorn/Vista+. + */ + // KiSetGdtEntry(KiGetGdtEntry(pGdt, 0x78), 0x80400000, 0xffff, TYPE_CODE, DPL_SYSTEM, 0); + // KiSetGdtEntry(KiGetGdtEntry(pGdt, 0x80), 0x80400000, 0xffff, TYPE_DATA, DPL_SYSTEM, 0); + // KiSetGdtEntry(KiGetGdtEntry(pGdt, 0x88), 0x0000, 0, TYPE_DATA, DPL_SYSTEM, 0); + + /* Copy the old IDT */ RtlCopyMemory(pIdt, (PVOID)OldIdt.Base, OldIdt.Limit + 1); - // Mask interrupts + /* Mask interrupts */ //asm("cli\n"); // they are already masked before enabling paged mode - // Load GDT+IDT + /* Load GDT+IDT */ Ke386SetGlobalDescriptorTable(&GdtDesc); __lidt(&IdtDesc); - // Jump to proper CS and clear prefetch queue + /* Jump to proper CS and clear prefetch queue */ #if defined(__GNUC__) asm("ljmp $0x08, $1f\n" "1:\n"); #elif defined(_MSC_VER) - /* We can't express the above in MASM so we use this far return instead */ + /* We cannot express the above in MASM so we use this far return instead */ __asm { push 8 @@ -598,34 +692,34 @@ WinLdrSetProcessorContext(void) #error #endif - // Set SS selector - Ke386SetSs(0x10); // DataSelector=0x10 + /* Set SS selector */ + Ke386SetSs(KGDT_R0_DATA); - // Set DS and ES selectors - Ke386SetDs(0x10); - Ke386SetEs(0x10); // this is vital for rep stosd + /* Set DS and ES selectors */ + Ke386SetDs(KGDT_R0_DATA); + Ke386SetEs(KGDT_R0_DATA); // This is vital for rep stosd - // LDT = not used ever, thus set to 0 + /* LDT = not used ever, thus set to 0 */ Ke386SetLocalDescriptorTable(Ldt); - // Load TSR + /* Load TSR */ Ke386SetTr(KGDT_TSS); - // Clear GS + /* Clear GS */ Ke386SetGs(0); - // Set FS to PCR - Ke386SetFs(0x30); - - // Real end of the function, just for information - /* do not uncomment! - pop edi; - pop esi; - pop ebx; - mov esp, ebp; - pop ebp; - ret - */ + /* Set FS to PCR */ + Ke386SetFs(KGDT_R0_PCR); + + // Real end of the function, just for information + /* do not uncomment! + pop edi; + pop esi; + pop ebx; + mov esp, ebp; + pop ebp; + ret + */ } #if DBG -- 2.17.1