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