1 /*
2  * PROJECT:         EFI Windows Loader
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            boot/freeldr/freeldr/arch/i386/winldr.c
5  * PURPOSE:         Memory related routines
6  * PROGRAMMERS:     Aleksey Bragin (aleksey@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <freeldr.h>
12 #include <ndk/asm.h>
13 #include <internal/i386/intrin_i.h>
14 #include "../../winldr.h"
15 
16 #include <debug.h>
17 DBG_DEFAULT_CHANNEL(WINDOWS);
18 
19 // This is needed because headers define wrong one for ReactOS
20 #undef KIP0PCRADDRESS
21 #define KIP0PCRADDRESS                      0xffdff000
22 
23 #define SELFMAP_ENTRY       0x300
24 
25 // This is needed only for SetProcessorContext routine
26 #pragma pack(2)
27 typedef struct
28 {
29     USHORT Limit;
30     ULONG Base;
31 } GDTIDT;
32 #pragma pack(4)
33 
34 /*
35  * Consider adding these definitions into
36  * ntoskrnl/include/internal/i386/intrin_i.h and/or the NDK.
37  */
38 
39 #define DPL_SYSTEM  0
40 #define DPL_USER    3
41 
42 #define TYPE_TSS16A 0x01    // 16-bit Task State Segment (Available)
43 #define TYPE_LDT    0x02    // Local Descriptor Table
44 #define TYPE_TSS16B 0x03    // 16-bit Task State Segment (Busy)
45 #define TYPE_CALL16 0x04    // 16-bit Call Gate
46 #define TYPE_TASK   0x05    // Task Gate (I386_TASK_GATE)
47 #define TYPE_INT16  0x06    // 16-bit Interrupt Gate
48 #define TYPE_TRAP16 0x07    // 16-bit Trap Gate
49 // #define TYPE_RESERVED_1 0x08
50 #define TYPE_TSS32A 0x09    // 32-bit Task State Segment (Available) (I386_TSS)
51 // #define TYPE_RESERVED_2 0x0A
52 #define TYPE_TSS32B 0x0B    // 32-bit Task State Segment (Busy) (I386_ACTIVE_TSS)
53 #define TYPE_CALL32 0x0C    // 32-bit Call Gate (I386_CALL_GATE)
54 // #define TYPE_RESERVED_3 0x0D
55 #define TYPE_INT32  0x0E    // 32-bit Interrupt Gate (I386_INTERRUPT_GATE)
56 #define TYPE_TRAP32 0x0F    // 32-bit Trap Gate (I386_TRAP_GATE)
57 
58 #define DESCRIPTOR_ACCESSED     0x1
59 #define DESCRIPTOR_READ_WRITE   0x2
60 #define DESCRIPTOR_EXECUTE_READ 0x2
61 #define DESCRIPTOR_EXPAND_DOWN  0x4
62 #define DESCRIPTOR_CONFORMING   0x4
63 #define DESCRIPTOR_CODE         0x8
64 
65 #define TYPE_CODE   (0x10 | DESCRIPTOR_CODE | DESCRIPTOR_EXECUTE_READ)
66 #define TYPE_DATA   (0x10 | DESCRIPTOR_READ_WRITE)
67 
68 #if 0
69 VOID
70 DumpGDTEntry(ULONG_PTR Base, ULONG Selector)
71 {
72     PKGDTENTRY pGdt = (PKGDTENTRY)((ULONG_PTR)Base + Selector);
73 
74     TRACE("\n"
75           "Selector 0x%04x\n"
76           "===============\n"
77           "LimitLow               = 0x%04x\n"
78           "BaseLow                = 0x%04x\n"
79           "HighWord.Bytes.BaseMid = 0x%02x\n"
80           "HighWord.Bytes.Flags1  = 0x%02x\n"
81           "HighWord.Bytes.Flags2  = 0x%02x\n"
82           "HighWord.Bytes.BaseHi  = 0x%02x\n"
83           "\n",
84           Selector,
85           pGdt->LimitLow, pGdt->BaseLow,
86           pGdt->HighWord.Bytes.BaseMid,
87           pGdt->HighWord.Bytes.Flags1,
88           pGdt->HighWord.Bytes.Flags2,
89           pGdt->HighWord.Bytes.BaseHi);
90 }
91 #endif
92 
93 /* GLOBALS *******************************************************************/
94 
95 PHARDWARE_PTE PDE;
96 PHARDWARE_PTE HalPageTable;
97 
98 PUCHAR PhysicalPageTablesBuffer;
99 PUCHAR KernelPageTablesBuffer;
100 ULONG PhysicalPageTables;
101 ULONG KernelPageTables;
102 
103 ULONG PcrBasePage;
104 ULONG TssBasePage;
105 PVOID GdtIdt;
106 
107 /* FUNCTIONS *****************************************************************/
108 
109 static
110 BOOLEAN
MempAllocatePageTables(VOID)111 MempAllocatePageTables(VOID)
112 {
113     ULONG NumPageTables, TotalSize;
114     PUCHAR Buffer;
115     // It's better to allocate PDE + PTEs contiguous
116 
117     // Max number of entries = MaxPageNum >> 10
118     // FIXME: This is a number to describe ALL physical memory
119     // and windows doesn't expect ALL memory mapped...
120     NumPageTables = TotalPagesInLookupTable >> 10;
121 
122     TRACE("NumPageTables = %d\n", NumPageTables);
123 
124     // Allocate memory block for all these things:
125     // PDE, HAL mapping page table, physical mapping, kernel mapping
126     TotalSize = (1 + 1 + NumPageTables * 2) * MM_PAGE_SIZE;
127 
128     // PDE+HAL+KernelPTEs == MemoryData
129     Buffer = MmAllocateMemoryWithType(TotalSize, LoaderMemoryData);
130 
131     // Physical PTEs = FirmwareTemporary
132     PhysicalPageTablesBuffer = (PUCHAR)Buffer + TotalSize - NumPageTables*MM_PAGE_SIZE;
133     MmSetMemoryType(PhysicalPageTablesBuffer,
134                     NumPageTables*MM_PAGE_SIZE,
135                     LoaderFirmwareTemporary);
136 
137     // This check is now redundant
138     if (Buffer + (TotalSize - NumPageTables*MM_PAGE_SIZE) !=
139         PhysicalPageTablesBuffer)
140     {
141         TRACE("There was a problem allocating two adjacent blocks of memory!\n");
142     }
143 
144     if (Buffer == NULL || PhysicalPageTablesBuffer == NULL)
145     {
146         UiMessageBox("Impossible to allocate memory block for page tables!");
147         return FALSE;
148     }
149 
150     // Zero all this memory block
151     RtlZeroMemory(Buffer, TotalSize);
152 
153     // Set up pointers correctly now
154     PDE = (PHARDWARE_PTE)Buffer;
155 
156     // Map the page directory at 0xC0000000 (maps itself)
157     PDE[SELFMAP_ENTRY].PageFrameNumber = (ULONG)PDE >> MM_PAGE_SHIFT;
158     PDE[SELFMAP_ENTRY].Valid = 1;
159     PDE[SELFMAP_ENTRY].Write = 1;
160 
161     // The last PDE slot is allocated for HAL's memory mapping (Virtual Addresses 0xFFC00000 - 0xFFFFFFFF)
162     HalPageTable = (PHARDWARE_PTE)&Buffer[MM_PAGE_SIZE*1];
163 
164     // Map it
165     PDE[1023].PageFrameNumber = (ULONG)HalPageTable >> MM_PAGE_SHIFT;
166     PDE[1023].Valid = 1;
167     PDE[1023].Write = 1;
168 
169     // Store pointer to the table for easier access
170     KernelPageTablesBuffer = &Buffer[MM_PAGE_SIZE*2];
171 
172     // Zero counters of page tables used
173     PhysicalPageTables = 0;
174     KernelPageTables = 0;
175 
176     return TRUE;
177 }
178 
179 static
180 VOID
MempAllocatePTE(ULONG Entry,PHARDWARE_PTE * PhysicalPT,PHARDWARE_PTE * KernelPT)181 MempAllocatePTE(ULONG Entry, PHARDWARE_PTE *PhysicalPT, PHARDWARE_PTE *KernelPT)
182 {
183     //TRACE("Creating PDE Entry %X\n", Entry);
184 
185     // Identity mapping
186     *PhysicalPT = (PHARDWARE_PTE)&PhysicalPageTablesBuffer[PhysicalPageTables*MM_PAGE_SIZE];
187     PhysicalPageTables++;
188 
189     PDE[Entry].PageFrameNumber = (ULONG)*PhysicalPT >> MM_PAGE_SHIFT;
190     PDE[Entry].Valid = 1;
191     PDE[Entry].Write = 1;
192 
193     if (Entry+(KSEG0_BASE >> 22) > 1023)
194     {
195         TRACE("WARNING! Entry: %X > 1023\n", Entry+(KSEG0_BASE >> 22));
196     }
197 
198     // Kernel-mode mapping
199     *KernelPT = (PHARDWARE_PTE)&KernelPageTablesBuffer[KernelPageTables*MM_PAGE_SIZE];
200     KernelPageTables++;
201 
202     PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber = ((ULONG)*KernelPT >> MM_PAGE_SHIFT);
203     PDE[Entry+(KSEG0_BASE >> 22)].Valid = 1;
204     PDE[Entry+(KSEG0_BASE >> 22)].Write = 1;
205 }
206 
207 BOOLEAN
MempSetupPaging(IN PFN_NUMBER StartPage,IN PFN_COUNT NumberOfPages,IN BOOLEAN KernelMapping)208 MempSetupPaging(IN PFN_NUMBER StartPage,
209                 IN PFN_COUNT NumberOfPages,
210                 IN BOOLEAN KernelMapping)
211 {
212     PHARDWARE_PTE PhysicalPT;
213     PHARDWARE_PTE KernelPT;
214     PFN_COUNT Entry, Page;
215 
216     TRACE("MempSetupPaging: SP 0x%X, Number: 0x%X, Kernel: %s\n",
217        StartPage, NumberOfPages, KernelMapping ? "yes" : "no");
218 
219     // HACK
220     if (StartPage+NumberOfPages >= 0x80000)
221     {
222         //
223         // We cannot map this as it requires more than 1 PDE
224         // and in fact it's not possible at all ;)
225         //
226         //TRACE("skipping...\n");
227         return TRUE;
228     }
229 
230     //
231     // Now actually set up the page tables for identity mapping
232     //
233     for (Page = StartPage; Page < StartPage + NumberOfPages; Page++)
234     {
235         Entry = Page >> 10;
236 
237         if (((PULONG)PDE)[Entry] == 0)
238         {
239             MempAllocatePTE(Entry, &PhysicalPT, &KernelPT);
240         }
241         else
242         {
243             PhysicalPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT);
244             KernelPT = (PHARDWARE_PTE)(PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber << MM_PAGE_SHIFT);
245         }
246 
247         PhysicalPT[Page & 0x3ff].PageFrameNumber = Page;
248         PhysicalPT[Page & 0x3ff].Valid = 1;
249         PhysicalPT[Page & 0x3ff].Write = (Page != 0);
250 
251         if (KernelMapping)
252         {
253             if (KernelPT[Page & 0x3ff].Valid) WARN("KernelPT already mapped\n");
254             KernelPT[Page & 0x3ff].PageFrameNumber = Page;
255             KernelPT[Page & 0x3ff].Valid = (Page != 0);
256             KernelPT[Page & 0x3ff].Write = (Page != 0);
257         }
258     }
259 
260     return TRUE;
261 }
262 
263 VOID
MempUnmapPage(PFN_NUMBER Page)264 MempUnmapPage(PFN_NUMBER Page)
265 {
266     PHARDWARE_PTE KernelPT;
267     PFN_NUMBER Entry = (Page >> 10) + (KSEG0_BASE >> 22);
268 
269     /* Don't unmap page directory or HAL entries */
270     if (Entry == SELFMAP_ENTRY || Entry == 1023)
271         return;
272 
273     if (PDE[Entry].Valid)
274     {
275         KernelPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT);
276 
277         if (KernelPT)
278         {
279             KernelPT[Page & 0x3ff].PageFrameNumber = 0;
280             KernelPT[Page & 0x3ff].Valid = 0;
281             KernelPT[Page & 0x3ff].Write = 0;
282         }
283     }
284 }
285 
286 static
287 VOID
WinLdrpMapApic(VOID)288 WinLdrpMapApic(VOID)
289 {
290     BOOLEAN LocalAPIC;
291     LARGE_INTEGER MsrValue;
292     ULONG APICAddress, CpuInfo[4];
293 
294     /* Check if we have a local APIC */
295     __cpuid((int*)CpuInfo, 1);
296     LocalAPIC = (((CpuInfo[3] >> 9) & 1) != 0);
297 
298     /* If there is no APIC, just return */
299     if (!LocalAPIC)
300         return;
301 
302     /* Read the APIC Address */
303     MsrValue.QuadPart = __readmsr(0x1B);
304     APICAddress = (MsrValue.LowPart & 0xFFFFF000);
305 
306     TRACE("Local APIC detected at address 0x%x\n",
307         APICAddress);
308 
309     /* Map it */
310     HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber
311         = APICAddress >> MM_PAGE_SHIFT;
312     HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
313     HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
314     HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].WriteThrough = 1;
315     HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].CacheDisable = 1;
316 }
317 
318 static
319 BOOLEAN
WinLdrMapSpecialPages(void)320 WinLdrMapSpecialPages(void)
321 {
322     TRACE("HalPageTable: 0x%X\n", HalPageTable);
323 
324     /*
325      * The Page Tables have been setup, make special handling
326      * for the boot processor PCR and KI_USER_SHARED_DATA.
327      */
328     HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage+1;
329     HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
330     HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
331 
332     HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage;
333     HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
334     HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
335 
336     /* Map APIC */
337     WinLdrpMapApic();
338 
339     /* Map VGA memory */
340     //VideoMemoryBase = MmMapIoSpace(0xb8000, 4000, MmNonCached);
341     //TRACE("VideoMemoryBase: 0x%X\n", VideoMemoryBase);
342 
343     return TRUE;
344 }
345 
346 #define ExtendedBIOSDataArea ((PULONG)0x740)
347 #define ExtendedBIOSDataSize ((PULONG)0x744)
348 #define RomFontPointers ((PULONG)0x700)
349 
350 static
WinLdrSetupSpecialDataPointers(VOID)351 void WinLdrSetupSpecialDataPointers(VOID)
352 {
353     /* Get the address of the BIOS ROM fonts. Win 2003 videoprt reads these
354        values from address 0x700 .. 0x718 and store them in the registry
355        in HKLM\System\CurrentControlSet\Control\Wow\RomFontPointers */
356     MachVideoGetFontsFromFirmware(RomFontPointers);
357 
358     /* Store address of the extended BIOS data area in 0x740 */
359     MachGetExtendedBIOSData(ExtendedBIOSDataArea, ExtendedBIOSDataSize);
360 
361     if (*ExtendedBIOSDataArea == 0 && *ExtendedBIOSDataSize == 0)
362     {
363         WARN("Couldn't get address of extended BIOS data area\n");
364     }
365     else
366     {
367         TRACE("*ExtendedBIOSDataArea = 0x%lx\n", *ExtendedBIOSDataArea);
368     }
369 }
370 
WinLdrSetupMachineDependent(PLOADER_PARAMETER_BLOCK LoaderBlock)371 void WinLdrSetupMachineDependent(PLOADER_PARAMETER_BLOCK LoaderBlock)
372 {
373     ULONG TssSize;
374     //ULONG TssPages;
375     ULONG_PTR Pcr = 0;
376     ULONG_PTR Tss = 0;
377     ULONG BlockSize, NumPages;
378 
379     LoaderBlock->u.I386.CommonDataArea = NULL; // Force No ABIOS support
380     LoaderBlock->u.I386.MachineType = MACHINE_TYPE_ISA;
381 
382     /* Allocate 2 pages for PCR: one for the boot processor PCR and one for KI_USER_SHARED_DATA */
383     Pcr = (ULONG_PTR)MmAllocateMemoryWithType(2 * MM_PAGE_SIZE, LoaderStartupPcrPage);
384     PcrBasePage = Pcr >> MM_PAGE_SHIFT;
385     if (Pcr == 0)
386     {
387         UiMessageBox("Could not allocate PCR.");
388         return;
389     }
390 
391     /* Allocate TSS */
392     TssSize = (sizeof(KTSS) + MM_PAGE_SIZE) & ~(MM_PAGE_SIZE - 1);
393     //TssPages = TssSize / MM_PAGE_SIZE;
394 
395     Tss = (ULONG_PTR)MmAllocateMemoryWithType(TssSize, LoaderMemoryData);
396     TssBasePage = Tss >> MM_PAGE_SHIFT;
397     if (Tss == 0)
398     {
399         UiMessageBox("Could not allocate TSS.");
400         return;
401     }
402 
403     /* Allocate space for new GDT + IDT */
404     BlockSize = NUM_GDT*sizeof(KGDTENTRY) + NUM_IDT*sizeof(KIDTENTRY);//FIXME: Use GDT/IDT limits here?
405     NumPages = (BlockSize + MM_PAGE_SIZE - 1) >> MM_PAGE_SHIFT;
406     GdtIdt = (PKGDTENTRY)MmAllocateMemoryWithType(NumPages * MM_PAGE_SIZE, LoaderMemoryData);
407     if (GdtIdt == NULL)
408     {
409         UiMessageBox("Could not allocate pages for GDT+IDT!");
410         return;
411     }
412 
413     /* Zero newly prepared GDT+IDT */
414     RtlZeroMemory(GdtIdt, NumPages << MM_PAGE_SHIFT);
415 
416     // Before we start mapping pages, create a block of memory, which will contain
417     // PDE and PTEs
418     if (MempAllocatePageTables() == FALSE)
419     {
420         BugCheck("MempAllocatePageTables failed!\n");
421     }
422 
423     /* Map stuff like PCR, KI_USER_SHARED_DATA and Apic */
424     WinLdrMapSpecialPages();
425 
426     /* Set some special fields */
427     WinLdrSetupSpecialDataPointers();
428 }
429 
430 
431 VOID
WinLdrSetProcessorContext(_In_ USHORT OperatingSystemVersion)432 WinLdrSetProcessorContext(
433     _In_ USHORT OperatingSystemVersion)
434 {
435     GDTIDT GdtDesc, IdtDesc, OldIdt;
436     PKGDTENTRY    pGdt;
437     PKIDTENTRY    pIdt;
438     USHORT Ldt = 0;
439     ULONG Pcr;
440     ULONG Tss;
441     //ULONG i;
442 
443     Pcr = KIP0PCRADDRESS;
444     Tss = KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT);
445 
446     TRACE("GdtIdt %p, Pcr %p, Tss 0x%08x\n",
447           GdtIdt, Pcr, Tss);
448 
449     /* Enable paging */
450     //BS->ExitBootServices(ImageHandle,MapKey);
451 
452     /* Disable Interrupts */
453     _disable();
454 
455     /* Re-initialize EFLAGS */
456     __writeeflags(0);
457 
458     /* Set the PDBR */
459     __writecr3((ULONG_PTR)PDE);
460 
461     /* Enable paging by modifying CR0 */
462     __writecr0(__readcr0() | CR0_PG);
463 
464     /* The Kernel expects the boot processor PCR to be zero-filled on startup */
465     RtlZeroMemory((PVOID)Pcr, MM_PAGE_SIZE);
466 
467     /* Get old values of GDT and IDT */
468     Ke386GetGlobalDescriptorTable(&GdtDesc);
469     __sidt(&IdtDesc);
470 
471     /* Save old IDT */
472     OldIdt.Base  = IdtDesc.Base;
473     OldIdt.Limit = IdtDesc.Limit;
474 
475     /* Prepare new IDT+GDT */
476     GdtDesc.Base  = KSEG0_BASE | (ULONG_PTR)GdtIdt;
477     GdtDesc.Limit = NUM_GDT * sizeof(KGDTENTRY) - 1;
478     IdtDesc.Base  = (ULONG)((PUCHAR)GdtDesc.Base + GdtDesc.Limit + 1);
479     IdtDesc.Limit = NUM_IDT * sizeof(KIDTENTRY) - 1;
480 
481     // ========================
482     // Fill all descriptors now
483     // ========================
484 
485     pGdt = (PKGDTENTRY)GdtDesc.Base;
486     pIdt = (PKIDTENTRY)IdtDesc.Base;
487 
488     /* KGDT_NULL (0x00) Null Selector - Unused */
489     KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_NULL), 0x0000, 0, 0, DPL_SYSTEM, 0);
490     // DumpGDTEntry(GdtDesc.Base, KGDT_NULL);
491 
492     /* KGDT_R0_CODE (0x08) Ring 0 Code selector - Flat 4Gb */
493     KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_R0_CODE), 0x0000, 0xFFFFFFFF,
494                   TYPE_CODE, DPL_SYSTEM, 2);
495     // DumpGDTEntry(GdtDesc.Base, KGDT_R0_CODE);
496 
497     /* KGDT_R0_DATA (0x10) Ring 0 Data selector - Flat 4Gb */
498     KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_R0_DATA), 0x0000, 0xFFFFFFFF,
499                   TYPE_DATA, DPL_SYSTEM, 2);
500     // DumpGDTEntry(GdtDesc.Base, KGDT_R0_DATA);
501 
502     /* KGDT_R3_CODE (0x18) Ring 3 Code Selector - Flat 2Gb */
503     KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_R3_CODE), 0x0000, 0xFFFFFFFF,
504                   TYPE_CODE, DPL_USER, 2);
505     // DumpGDTEntry(GdtDesc.Base, KGDT_R3_CODE);
506 
507     /* KGDT_R3_DATA (0x20) Ring 3 Data Selector - Flat 2Gb */
508     KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_R3_DATA), 0x0000, 0xFFFFFFFF,
509                   TYPE_DATA, DPL_USER, 2);
510     // DumpGDTEntry(GdtDesc.Base, KGDT_R3_DATA);
511 
512     /* KGDT_TSS (0x28) TSS Selector (Ring 0) */
513     KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_TSS), (ULONG32)Tss,
514                   0x78-1 /* FIXME: Check this; would be sizeof(KTSS)-1 */,
515                   TYPE_TSS32A, DPL_SYSTEM, 0);
516     // DumpGDTEntry(GdtDesc.Base, KGDT_TSS);
517 
518     /*
519      * KGDT_R0_PCR (0x30) PCR Selector (Ring 0)
520      *
521      * IMPORTANT COMPATIBILITY NOTE:
522      * Windows <= Server 2003 sets a Base == KIP0PCRADDRESS (0xffdff000 on x86)
523      * with a Limit of 1 page (LimitLow == 1, Granularity == 1, that is interpreted
524      * as a "Limit" == 0x1fff but is incorrect, of course).
525      * On Windows Longhorn/Vista+ however, the Base is not hardcoded to KIP0PCRADDRESS
526      * and the limit is set in bytes (Granularity == 0):
527      * Longhorn/Vista reports LimitLow == 0x0fff == MM_PAGE_SIZE - 1, whereas
528      * Windows 7+ uses larger sizes there (not aligned on a page boundary).
529      */
530     if (OperatingSystemVersion < _WIN32_WINNT_VISTA)
531     {
532         /* Server 2003 way */
533         KiSetGdtEntryEx(KiGetGdtEntry(pGdt, KGDT_R0_PCR), (ULONG32)Pcr, 0x1,
534                         TYPE_DATA, DPL_SYSTEM, TRUE, 2);
535     }
536     else
537     {
538         /* Vista+ way */
539         KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_R0_PCR), (ULONG32)Pcr, MM_PAGE_SIZE - 1,
540                       TYPE_DATA, DPL_SYSTEM, 2);
541     }
542 
543     // DumpGDTEntry(GdtDesc.Base, KGDT_R0_PCR);
544 
545     /* KGDT_R3_TEB (0x38) Thread Environment Block Selector (Ring 3) */
546     KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_R3_TEB), 0x0000, 0x0FFF,
547                   TYPE_DATA | DESCRIPTOR_ACCESSED, DPL_USER, 2);
548     // DumpGDTEntry(GdtDesc.Base, KGDT_R3_TEB);
549 
550     /* KGDT_VDM_TILE (0x40) VDM BIOS Data Area Selector (Ring 3) */
551     KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_VDM_TILE), 0x0400, 0xFFFF,
552                   TYPE_DATA, DPL_USER, 0);
553     // DumpGDTEntry(GdtDesc.Base, KGDT_VDM_TILE);
554 
555     /* KGDT_LDT (0x48) LDT Selector (Reserved) */
556     KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_LDT), 0x0000, 0, 0, DPL_SYSTEM, 0);
557     // DumpGDTEntry(GdtDesc.Base, KGDT_LDT);
558 
559     /* KGDT_DF_TSS (0x50) Double-Fault Task Switch Selector (Ring 0) */
560     KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_DF_TSS), 0x20000 /* FIXME: Not correct! */,
561                   0xFFFF /* FIXME: Not correct! */,
562                   TYPE_TSS32A, DPL_SYSTEM, 0);
563     // DumpGDTEntry(GdtDesc.Base, KGDT_DF_TSS);
564 
565     /* KGDT_NMI_TSS (0x58) NMI Task Switch Selector (Ring 0) */
566     KiSetGdtEntry(KiGetGdtEntry(pGdt, KGDT_NMI_TSS), 0x20000, 0xFFFF,
567                   TYPE_CODE, DPL_SYSTEM, 0);
568     // DumpGDTEntry(GdtDesc.Base, KGDT_NMI_TSS);
569 
570     /* Selector (0x60) - Unused (Reserved) on Windows Longhorn/Vista+ */
571     KiSetGdtEntry(KiGetGdtEntry(pGdt, 0x60), 0x20000 /* FIXME: Maybe not correct, but noone cares */,
572                   0xFFFF, TYPE_DATA, DPL_SYSTEM, 0);
573     // DumpGDTEntry(GdtDesc.Base, 0x60);
574 
575     /* Video Display Buffer Selector (0x68) - Unused (Reserved) on Windows Longhorn/Vista+ */
576     KiSetGdtEntry(KiGetGdtEntry(pGdt, 0x68), 0xB8000, 0x3FFF,
577                   TYPE_DATA, DPL_SYSTEM, 0);
578     // DumpGDTEntry(GdtDesc.Base, 0x68);
579 
580     /*
581      * GDT Alias Selector (points to GDT) (0x70)
582      *
583      * IMPORTANT COMPATIBILITY NOTE:
584      * The Base is not fixed to 0xFFFF7000 on Windows Longhorn/Vista+.
585      */
586     KiSetGdtEntry(KiGetGdtEntry(pGdt, 0x70), 0xFFFF7000 /* GdtDesc.Base ?? */, GdtDesc.Limit,
587                   TYPE_DATA, DPL_SYSTEM, 0);
588     // DumpGDTEntry(GdtDesc.Base, 0x70);
589 
590     /*
591      * Windows <= Server 2003 defines three additional unused but valid
592      * descriptors there, possibly for debugging purposes only.
593      * They are not present on Windows Longhorn/Vista+.
594      */
595     // KiSetGdtEntry(KiGetGdtEntry(pGdt, 0x78), 0x80400000, 0xffff, TYPE_CODE, DPL_SYSTEM, 0);
596     // KiSetGdtEntry(KiGetGdtEntry(pGdt, 0x80), 0x80400000, 0xffff, TYPE_DATA, DPL_SYSTEM, 0);
597     // KiSetGdtEntry(KiGetGdtEntry(pGdt, 0x88), 0x0000, 0, TYPE_DATA, DPL_SYSTEM, 0);
598 
599     /* Copy the old IDT */
600     RtlCopyMemory(pIdt, (PVOID)OldIdt.Base, OldIdt.Limit + 1);
601 
602     /* Mask interrupts */
603     //asm("cli\n"); // they are already masked before enabling paged mode
604 
605     /* Load GDT+IDT */
606     Ke386SetGlobalDescriptorTable(&GdtDesc);
607     __lidt(&IdtDesc);
608 
609     /* Jump to proper CS and clear prefetch queue */
610 #if defined(__GNUC__) || defined(__clang__)
611     asm("ljmp    $0x08, $1f\n"
612         "1:\n");
613 #elif defined(_MSC_VER)
614     /* We cannot express the above in MASM so we use this far return instead */
615     __asm
616     {
617         push 8
618         push offset resume
619         retf
620         resume:
621     };
622 #else
623 #error
624 #endif
625 
626     /* Set SS selector */
627     Ke386SetSs(KGDT_R0_DATA);
628 
629     /* Set DS and ES selectors */
630     Ke386SetDs(KGDT_R0_DATA);
631     Ke386SetEs(KGDT_R0_DATA); // This is vital for rep stosd
632 
633     /* LDT = not used ever, thus set to 0 */
634     Ke386SetLocalDescriptorTable(Ldt);
635 
636     /* Load TSR */
637     Ke386SetTr(KGDT_TSS);
638 
639     /* Clear GS */
640     Ke386SetGs(0);
641 
642     /* Set FS to PCR */
643     Ke386SetFs(KGDT_R0_PCR);
644 
645     // Real end of the function, just for information
646     /* do not uncomment!
647     pop edi;
648     pop esi;
649     pop ebx;
650     mov esp, ebp;
651     pop ebp;
652     ret
653     */
654 }
655 
656 #if DBG
657 VOID
MempDump(VOID)658 MempDump(VOID)
659 {
660     PULONG PDE_Addr=(PULONG)PDE;//0xC0300000;
661     int i, j;
662 
663     TRACE("\nPDE\n");
664 
665     for (i=0; i<128; i++)
666     {
667         TRACE("0x%04X | ", i*8);
668 
669         for (j=0; j<8; j++)
670         {
671             TRACE("0x%08X ", PDE_Addr[i*8+j]);
672         }
673 
674         TRACE("\n");
675     }
676 }
677 #endif
678