Merge freeldr from amd64 branch:
[reactos.git] / reactos / boot / freeldr / freeldr / windows / wlmemory.c
1 /*
2 * PROJECT: EFI Windows Loader
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: freeldr/winldr/wlmemory.c
5 * PURPOSE: Memory related routines
6 * PROGRAMMERS: Aleksey Bragin (aleksey@reactos.org)
7 */
8
9 /* INCLUDES ***************************************************************/
10
11 #include <freeldr.h>
12
13 #include <ndk/asm.h>
14 #include <debug.h>
15
16 extern ULONG TotalNLSSize;
17 extern ULONG LoaderPagesSpanned;
18
19 // This is needed because headers define wrong one for ReactOS
20 #undef KIP0PCRADDRESS
21 #define KIP0PCRADDRESS 0xffdff000
22
23 #define HYPER_SPACE_ENTRY 0x300
24
25 PCHAR MemTypeDesc[] = {
26 "ExceptionBlock ", // ?
27 "SystemBlock ", // ?
28 "Free ",
29 "Bad ", // used
30 "LoadedProgram ", // == Free
31 "FirmwareTemporary ", // == Free
32 "FirmwarePermanent ", // == Bad
33 "OsloaderHeap ", // used
34 "OsloaderStack ", // == Free
35 "SystemCode ",
36 "HalCode ",
37 "BootDriver ", // not used
38 "ConsoleInDriver ", // ?
39 "ConsoleOutDriver ", // ?
40 "StartupDpcStack ", // ?
41 "StartupKernelStack", // ?
42 "StartupPanicStack ", // ?
43 "StartupPcrPage ", // ?
44 "StartupPdrPage ", // ?
45 "RegistryData ", // used
46 "MemoryData ", // not used
47 "NlsData ", // used
48 "SpecialMemory ", // == Bad
49 "BBTMemory " // == Bad
50 };
51
52 VOID
53 WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock);
54
55
56 VOID
57 MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
58 ULONG BasePage,
59 ULONG PageCount,
60 ULONG Type);
61 VOID
62 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
63 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor);
64
65 VOID
66 WinLdrRemoveDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR Descriptor);
67
68 VOID
69 WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss);
70
71 // This is needed only for SetProcessorContext routine
72 #pragma pack(2)
73 typedef struct
74 {
75 USHORT Limit;
76 ULONG Base;
77 } GDTIDT;
78 #pragma pack(4)
79
80 // this is needed for new IDT filling
81 #if 0
82 extern ULONG_PTR i386DivideByZero;
83 extern ULONG_PTR i386DebugException;
84 extern ULONG_PTR i386NMIException;
85 extern ULONG_PTR i386Breakpoint;
86 extern ULONG_PTR i386Overflow;
87 extern ULONG_PTR i386BoundException;
88 extern ULONG_PTR i386InvalidOpcode;
89 extern ULONG_PTR i386FPUNotAvailable;
90 extern ULONG_PTR i386DoubleFault;
91 extern ULONG_PTR i386CoprocessorSegment;
92 extern ULONG_PTR i386InvalidTSS;
93 extern ULONG_PTR i386SegmentNotPresent;
94 extern ULONG_PTR i386StackException;
95 extern ULONG_PTR i386GeneralProtectionFault;
96 extern ULONG_PTR i386PageFault; // exc 14
97 extern ULONG_PTR i386CoprocessorError; // exc 16
98 extern ULONG_PTR i386AlignmentCheck; // exc 17
99 #endif
100
101 /* GLOBALS ***************************************************************/
102
103 PHARDWARE_PTE PDE;
104 PHARDWARE_PTE HalPageTable;
105
106 PUCHAR PhysicalPageTablesBuffer;
107 PUCHAR KernelPageTablesBuffer;
108 ULONG PhysicalPageTables;
109 ULONG KernelPageTables;
110
111 MEMORY_ALLOCATION_DESCRIPTOR *Mad;
112 ULONG MadCount = 0;
113
114
115 /* FUNCTIONS **************************************************************/
116
117 BOOLEAN
118 MempAllocatePageTables()
119 {
120 ULONG NumPageTables, TotalSize;
121 PUCHAR Buffer;
122 // It's better to allocate PDE + PTEs contigiuos
123
124 // Max number of entries = MaxPageNum >> 10
125 // FIXME: This is a number to describe ALL physical memory
126 // and windows doesn't expect ALL memory mapped...
127 NumPageTables = (GetSystemMemorySize() >> MM_PAGE_SHIFT) >> 10;
128
129 DPRINTM(DPRINT_WINDOWS, "NumPageTables = %d\n", NumPageTables);
130
131 // Allocate memory block for all these things:
132 // PDE, HAL mapping page table, physical mapping, kernel mapping
133 TotalSize = (1+1+NumPageTables*2)*MM_PAGE_SIZE;
134
135 // PDE+HAL+KernelPTEs == MemoryData
136 Buffer = MmAllocateMemoryWithType(TotalSize, LoaderMemoryData);
137
138 // Physical PTEs = FirmwareTemporary
139 PhysicalPageTablesBuffer = (PUCHAR)Buffer + TotalSize - NumPageTables*MM_PAGE_SIZE;
140 MmSetMemoryType(PhysicalPageTablesBuffer,
141 NumPageTables*MM_PAGE_SIZE,
142 LoaderFirmwareTemporary);
143
144 // This check is now redundant
145 if (Buffer + (TotalSize - NumPageTables*MM_PAGE_SIZE) !=
146 PhysicalPageTablesBuffer)
147 {
148 DPRINTM(DPRINT_WINDOWS, "There was a problem allocating two adjacent blocks of memory!");
149 }
150
151 if (Buffer == NULL || PhysicalPageTablesBuffer == NULL)
152 {
153 UiMessageBox("Impossible to allocate memory block for page tables!");
154 return FALSE;
155 }
156
157 // Zero all this memory block
158 RtlZeroMemory(Buffer, TotalSize);
159
160 // Set up pointers correctly now
161 PDE = (PHARDWARE_PTE)Buffer;
162
163 // Map the page directory at 0xC0000000 (maps itself)
164 PDE[HYPER_SPACE_ENTRY].PageFrameNumber = (ULONG)PDE >> MM_PAGE_SHIFT;
165 PDE[HYPER_SPACE_ENTRY].Valid = 1;
166 PDE[HYPER_SPACE_ENTRY].Write = 1;
167
168 // The last PDE slot is allocated for HAL's memory mapping (Virtual Addresses 0xFFC00000 - 0xFFFFFFFF)
169 HalPageTable = (PHARDWARE_PTE)&Buffer[MM_PAGE_SIZE*1];
170
171 // Map it
172 PDE[1023].PageFrameNumber = (ULONG)HalPageTable >> MM_PAGE_SHIFT;
173 PDE[1023].Valid = 1;
174 PDE[1023].Write = 1;
175
176 // Store pointer to the table for easier access
177 KernelPageTablesBuffer = &Buffer[MM_PAGE_SIZE*2];
178
179 // Zero counters of page tables used
180 PhysicalPageTables = 0;
181 KernelPageTables = 0;
182
183 return TRUE;
184 }
185
186 VOID
187 MempAllocatePTE(ULONG Entry, PHARDWARE_PTE *PhysicalPT, PHARDWARE_PTE *KernelPT)
188 {
189 //Print(L"Creating PDE Entry %X\n", Entry);
190
191 // Identity mapping
192 *PhysicalPT = (PHARDWARE_PTE)&PhysicalPageTablesBuffer[PhysicalPageTables*MM_PAGE_SIZE];
193 PhysicalPageTables++;
194
195 PDE[Entry].PageFrameNumber = (ULONG)*PhysicalPT >> MM_PAGE_SHIFT;
196 PDE[Entry].Valid = 1;
197 PDE[Entry].Write = 1;
198
199 if (Entry+(KSEG0_BASE >> 22) > 1023)
200 {
201 DPRINTM(DPRINT_WINDOWS, "WARNING! Entry: %X > 1023\n", Entry+(KSEG0_BASE >> 22));
202 }
203
204 // Kernel-mode mapping
205 *KernelPT = (PHARDWARE_PTE)&KernelPageTablesBuffer[KernelPageTables*MM_PAGE_SIZE];
206 KernelPageTables++;
207
208 PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber = ((ULONG)*KernelPT >> MM_PAGE_SHIFT);
209 PDE[Entry+(KSEG0_BASE >> 22)].Valid = 1;
210 PDE[Entry+(KSEG0_BASE >> 22)].Write = 1;
211 }
212
213 BOOLEAN
214 MempSetupPaging(IN ULONG StartPage,
215 IN ULONG NumberOfPages)
216 {
217 PHARDWARE_PTE PhysicalPT;
218 PHARDWARE_PTE KernelPT;
219 ULONG Entry, Page;
220
221 //Print(L"MempSetupPaging: SP 0x%X, Number: 0x%X\n", StartPage, NumberOfPages);
222
223 // HACK
224 if (StartPage+NumberOfPages >= 0x80000)
225 {
226 //
227 // We can't map this as it requires more than 1 PDE
228 // and in fact it's not possible at all ;)
229 //
230 //Print(L"skipping...\n");
231 return TRUE;
232 }
233
234 //
235 // Now actually set up the page tables for identity mapping
236 //
237 for (Page=StartPage; Page < StartPage+NumberOfPages; Page++)
238 {
239 Entry = Page >> 10;
240
241 if (((PULONG)PDE)[Entry] == 0)
242 {
243 MempAllocatePTE(Entry, &PhysicalPT, &KernelPT);
244 }
245 else
246 {
247 PhysicalPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT);
248 KernelPT = (PHARDWARE_PTE)(PDE[Entry+(KSEG0_BASE >> 22)].PageFrameNumber << MM_PAGE_SHIFT);
249 }
250
251 if (Page == 0)
252 {
253 PhysicalPT[Page & 0x3ff].PageFrameNumber = Page;
254 PhysicalPT[Page & 0x3ff].Valid = 0;
255 PhysicalPT[Page & 0x3ff].Write = 0;
256
257 KernelPT[Page & 0x3ff].PageFrameNumber = Page;
258 KernelPT[Page & 0x3ff].Valid = 0;
259 KernelPT[Page & 0x3ff].Write = 0;
260 }
261 else
262 {
263 PhysicalPT[Page & 0x3ff].PageFrameNumber = Page;
264 PhysicalPT[Page & 0x3ff].Valid = 1;
265 PhysicalPT[Page & 0x3ff].Write = 1;
266
267 KernelPT[Page & 0x3ff].PageFrameNumber = Page;
268 KernelPT[Page & 0x3ff].Valid = 1;
269 KernelPT[Page & 0x3ff].Write = 1;
270 }
271 }
272
273 return TRUE;
274 }
275
276 VOID
277 MempDisablePages()
278 {
279 ULONG i;
280
281 //
282 // We need to delete kernel mapping from memory areas which are
283 // marked as Special or Permanent memory (thus non-accessible)
284 //
285
286 for (i=0; i<MadCount; i++)
287 {
288 ULONG StartPage, EndPage, Page;
289
290 StartPage = Mad[i].BasePage;
291 EndPage = Mad[i].BasePage + Mad[i].PageCount;
292
293 if (Mad[i].MemoryType == LoaderFirmwarePermanent ||
294 Mad[i].MemoryType == LoaderSpecialMemory ||
295 Mad[i].MemoryType == LoaderFree ||
296 (Mad[i].MemoryType == LoaderFirmwareTemporary && EndPage <= LoaderPagesSpanned) ||
297 Mad[i].MemoryType == LoaderOsloaderStack ||
298 Mad[i].MemoryType == LoaderLoadedProgram)
299 {
300 //
301 // But, the first megabyte of memory always stays!
302 // And, to tell the truth, we don't care about what's higher
303 // than LoaderPagesSpanned
304 if (Mad[i].MemoryType == LoaderFirmwarePermanent ||
305 Mad[i].MemoryType == LoaderSpecialMemory)
306 {
307 if (StartPage < 0x100)
308 StartPage = 0x100;
309
310 if (EndPage > LoaderPagesSpanned)
311 EndPage = LoaderPagesSpanned;
312 }
313
314 for (Page = StartPage; Page < EndPage; Page++)
315 {
316 PHARDWARE_PTE KernelPT;
317 ULONG Entry = (Page >> 10) + (KSEG0_BASE >> 22);
318
319 if (PDE[Entry].Valid)
320 {
321 KernelPT = (PHARDWARE_PTE)(PDE[Entry].PageFrameNumber << MM_PAGE_SHIFT);
322
323 if (KernelPT)
324 {
325 KernelPT[Page & 0x3ff].PageFrameNumber = 0;
326 KernelPT[Page & 0x3ff].Valid = 0;
327 KernelPT[Page & 0x3ff].Write = 0;
328 }
329 }
330 }
331 }
332 }
333 }
334
335 VOID
336 MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
337 ULONG BasePage,
338 ULONG PageCount,
339 ULONG Type)
340 {
341 BOOLEAN Status;
342
343 //
344 // Check for some weird stuff at the top
345 //
346 if (BasePage + PageCount > 0xF0000)
347 {
348 //
349 // Just skip this, without even adding to MAD list
350 //
351 return;
352 }
353
354 //
355 // Set Base page, page count and type
356 //
357 Mad[MadCount].BasePage = BasePage;
358 Mad[MadCount].PageCount = PageCount;
359 Mad[MadCount].MemoryType = Type;
360
361 //
362 // Check if it's more than the allowed for OS loader
363 // if yes - don't map the pages, just add as FirmwareTemporary
364 //
365 if (BasePage + PageCount > LoaderPagesSpanned)
366 {
367 if (Mad[MadCount].MemoryType != LoaderSpecialMemory &&
368 Mad[MadCount].MemoryType != LoaderFirmwarePermanent &&
369 Mad[MadCount].MemoryType != LoaderFree)
370 {
371 DPRINTM(DPRINT_WINDOWS, "Setting page %x %x to Temporary from %d\n",
372 BasePage, PageCount, Mad[MadCount].MemoryType);
373 Mad[MadCount].MemoryType = LoaderFirmwareTemporary;
374 }
375
376 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
377 MadCount++;
378
379 return;
380 }
381
382 //
383 // Add descriptor
384 //
385 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
386 MadCount++;
387
388 //
389 // Map it (don't map low 1Mb because it was already contigiously
390 // mapped in WinLdrTurnOnPaging)
391 //
392 if (BasePage >= 0x100)
393 {
394 Status = MempSetupPaging(BasePage, PageCount);
395 if (!Status)
396 {
397 DPRINTM(DPRINT_WINDOWS, "Error during MempSetupPaging\n");
398 return;
399 }
400 }
401 }
402
403 #ifdef _M_IX86
404
405 BOOLEAN LocalAPIC = FALSE;
406 ULONG_PTR APICAddress = 0;
407
408 VOID
409 WinLdrpMapApic()
410 {
411 /* Check if we have a local APIC */
412 asm(".intel_syntax noprefix\n");
413 asm("mov eax, 1\n");
414 asm("cpuid\n");
415 asm("shr edx, 9\n");
416 asm("and edx, 0x1\n");
417 asm("mov _LocalAPIC, edx\n");
418 asm(".att_syntax\n");
419
420 /* If there is no APIC, just return */
421 if (!LocalAPIC)
422 return;
423
424 asm(".intel_syntax noprefix\n");
425 asm("mov ecx, 0x1B\n");
426 asm("rdmsr\n");
427 asm("mov edx, eax\n");
428 asm("and edx, 0xFFFFF000\n");
429 asm("mov _APICAddress, edx");
430 asm(".att_syntax\n");
431
432 DPRINTM(DPRINT_WINDOWS, "Local APIC detected at address 0x%x\n",
433 APICAddress);
434
435 /* Map it */
436 HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber
437 = APICAddress >> MM_PAGE_SHIFT;
438 HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
439 HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
440 HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].WriteThrough = 1;
441 HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].CacheDisable = 1;
442 }
443 #else
444 VOID
445 WinLdrpMapApic()
446 {
447 /* Implement it for another arch */
448 }
449 #endif
450
451 BOOLEAN
452 WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
453 ULONG PcrBasePage,
454 ULONG TssBasePage,
455 PVOID GdtIdt)
456 {
457 ULONG i, PagesCount, MemoryMapSizeInPages;
458 ULONG LastPageIndex, LastPageType, MemoryMapStartPage;
459 PPAGE_LOOKUP_TABLE_ITEM MemoryMap;
460 ULONG NoEntries;
461 PKTSS Tss;
462 BOOLEAN Status;
463
464 //
465 // Creating a suitable memory map for the Windows can be tricky, so let's
466 // give a few advices:
467 // 1) One must not map the whole available memory pages to PDE!
468 // Map only what's needed - 16Mb, 24Mb, 32Mb max I think,
469 // thus occupying 4, 6 or 8 PDE entries for identical mapping,
470 // the same quantity for KSEG0_BASE mapping, one more entry for
471 // hyperspace and one more entry for HAL physical pages mapping.
472 // 2) Memory descriptors must map *the whole* physical memory
473 // showing any memory above 16/24/32 as FirmwareTemporary
474 //
475 // 3) Overall memory blocks count must not exceed 30 (?? why?)
476 //
477
478 //
479 // During MmInitMachineDependent, the kernel zeroes PDE at the following address
480 // 0xC0300000 - 0xC03007FC
481 //
482 // Then it finds the best place for non-paged pool:
483 // StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD
484 //
485
486 // Before we start mapping pages, create a block of memory, which will contain
487 // PDE and PTEs
488 if (MempAllocatePageTables() == FALSE)
489 return FALSE;
490
491 // Allocate memory for memory allocation descriptors
492 Mad = MmHeapAlloc(sizeof(MEMORY_ALLOCATION_DESCRIPTOR) * 1024);
493
494 // Setup an entry for each descriptor
495 MemoryMap = MmGetMemoryMap(&NoEntries);
496 if (MemoryMap == NULL)
497 {
498 UiMessageBox("Can not retrieve the current memory map");
499 return FALSE;
500 }
501
502 // Calculate parameters of the memory map
503 MemoryMapStartPage = (ULONG_PTR)MemoryMap >> MM_PAGE_SHIFT;
504 MemoryMapSizeInPages = NoEntries * sizeof(PAGE_LOOKUP_TABLE_ITEM);
505
506 DPRINTM(DPRINT_WINDOWS, "Got memory map with %d entries\n", NoEntries);
507
508 // Always contigiously map low 1Mb of memory
509 Status = MempSetupPaging(0, 0x100);
510 if (!Status)
511 {
512 DPRINTM(DPRINT_WINDOWS, "Error during MempSetupPaging of low 1Mb\n");
513 return FALSE;
514 }
515
516 // Construct a good memory map from what we've got,
517 // but mark entries which the memory allocation bitmap takes
518 // as free entries (this is done in order to have the ability
519 // to place mem alloc bitmap outside lower 16Mb zone)
520 PagesCount = 1;
521 LastPageIndex = 0;
522 LastPageType = MemoryMap[0].PageAllocated;
523 for(i=1;i<NoEntries;i++)
524 {
525 // Check if its memory map itself
526 if (i >= MemoryMapStartPage &&
527 i < (MemoryMapStartPage+MemoryMapSizeInPages))
528 {
529 // Exclude it if current page belongs to the memory map
530 MemoryMap[i].PageAllocated = LoaderFree;
531 }
532
533 // Process entry
534 if (MemoryMap[i].PageAllocated == LastPageType &&
535 (i != NoEntries-1) )
536 {
537 PagesCount++;
538 }
539 else
540 {
541 // Add the resulting region
542 MempAddMemoryBlock(LoaderBlock, LastPageIndex, PagesCount, LastPageType);
543
544 // Reset our counter vars
545 LastPageIndex = i;
546 LastPageType = MemoryMap[i].PageAllocated;
547 PagesCount = 1;
548 }
549 }
550
551 // TEMP, DEBUG!
552 // adding special reserved memory zones for vmware workstation
553 #if 0
554 {
555 Mad[MadCount].BasePage = 0xfec00;
556 Mad[MadCount].PageCount = 0x10;
557 Mad[MadCount].MemoryType = LoaderSpecialMemory;
558 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
559 MadCount++;
560
561 Mad[MadCount].BasePage = 0xfee00;
562 Mad[MadCount].PageCount = 0x1;
563 Mad[MadCount].MemoryType = LoaderSpecialMemory;
564 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
565 MadCount++;
566
567 Mad[MadCount].BasePage = 0xfffe0;
568 Mad[MadCount].PageCount = 0x20;
569 Mad[MadCount].MemoryType = LoaderSpecialMemory;
570 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
571 MadCount++;
572 }
573 #endif
574
575 DPRINTM(DPRINT_WINDOWS, "MadCount: %d\n", MadCount);
576
577 WinLdrpDumpMemoryDescriptors(LoaderBlock); //FIXME: Delete!
578
579 // Map our loader image, so we can continue running
580 /*Status = MempSetupPaging(OsLoaderBase >> MM_PAGE_SHIFT, OsLoaderSize >> MM_PAGE_SHIFT);
581 if (!Status)
582 {
583 UiMessageBox("Error during MempSetupPaging");
584 return;
585 }*/
586
587 //VideoDisplayString(L"Hello from VGA, going into the kernel\n");
588 DPRINTM(DPRINT_WINDOWS, "HalPageTable: 0x%X\n", HalPageTable);
589
590 // Page Tables have been setup, make special handling for PCR and TSS
591 // (which is done in BlSetupFotNt in usual ntldr)
592 HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage+1;
593 HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
594 HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
595
596 HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage;
597 HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
598 HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
599
600 // Map APIC
601 WinLdrpMapApic();
602
603 // Map VGA memory
604 //VideoMemoryBase = MmMapIoSpace(0xb8000, 4000, MmNonCached);
605 //DPRINTM(DPRINT_WINDOWS, "VideoMemoryBase: 0x%X\n", VideoMemoryBase);
606
607 Tss = (PKTSS)(KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT));
608
609 // Unmap what is not needed from kernel page table
610 MempDisablePages();
611
612 // Fill the memory descriptor list and
613 //PrepareMemoryDescriptorList();
614 DPRINTM(DPRINT_WINDOWS, "Memory Descriptor List prepared, printing PDE\n");
615 List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);
616
617 #ifdef DBG
618 {
619 ULONG *PDE_Addr=(ULONG *)PDE;//0xC0300000;
620 int j;
621
622 DPRINTM(DPRINT_WINDOWS, "\nPDE\n");
623
624 for (i=0; i<128; i++)
625 {
626 DPRINTM(DPRINT_WINDOWS, "0x%04X | ", i*8);
627
628 for (j=0; j<8; j++)
629 {
630 DPRINTM(DPRINT_WINDOWS, "0x%08X ", PDE_Addr[i*8+j]);
631 }
632
633 DPRINTM(DPRINT_WINDOWS, "\n");
634 }
635 }
636 #endif
637
638
639 // Enable paging
640 //BS->ExitBootServices(ImageHandle,MapKey);
641
642 // Disable Interrupts
643 _disable();
644
645 // Re-initalize EFLAGS
646 Ke386EraseFlags();
647
648 // Set the PDBR
649 __writecr3((ULONG_PTR)PDE);
650
651 // Enable paging by modifying CR0
652 __writecr0(__readcr0() | CR0_PG);
653
654 // Set processor context
655 WinLdrSetProcessorContext(GdtIdt, KIP0PCRADDRESS, KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT));
656
657 // Zero KI_USER_SHARED_DATA page
658 memset((PVOID)KI_USER_SHARED_DATA, 0, MM_PAGE_SIZE);
659
660 return TRUE;
661 }
662
663 // Two special things this func does: it sorts descriptors,
664 // and it merges free ones
665 VOID
666 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
667 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor)
668 {
669 PLIST_ENTRY ListHead = &LoaderBlock->MemoryDescriptorListHead;
670 PLIST_ENTRY PreviousEntry, NextEntry;
671 PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor = NULL, NextDescriptor = NULL;
672
673 DPRINTM(DPRINT_WINDOWS, "BP=0x%X PC=0x%X %s\n", NewDescriptor->BasePage,
674 NewDescriptor->PageCount, MemTypeDesc[NewDescriptor->MemoryType]);
675
676 /* Find a place where to insert the new descriptor to */
677 PreviousEntry = ListHead;
678 NextEntry = ListHead->Flink;
679 while (NextEntry != ListHead)
680 {
681 NextDescriptor = CONTAINING_RECORD(NextEntry,
682 MEMORY_ALLOCATION_DESCRIPTOR,
683 ListEntry);
684 if (NewDescriptor->BasePage < NextDescriptor->BasePage)
685 break;
686
687 PreviousEntry = NextEntry;
688 PreviousDescriptor = NextDescriptor;
689 NextEntry = NextEntry->Flink;
690 }
691
692 /* Don't forget about merging free areas */
693 if (NewDescriptor->MemoryType != LoaderFree)
694 {
695 /* Just insert, nothing to merge */
696 InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
697 }
698 else
699 {
700 /* Previous block also free? */
701 if ((PreviousEntry != ListHead) && (PreviousDescriptor->MemoryType == LoaderFree) &&
702 ((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) ==
703 NewDescriptor->BasePage))
704 {
705 /* Just enlarge previous descriptor's PageCount */
706 PreviousDescriptor->PageCount += NewDescriptor->PageCount;
707 NewDescriptor = PreviousDescriptor;
708 }
709 else
710 {
711 /* Nope, just insert */
712 InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
713 }
714
715 /* Next block is free ?*/
716 if ((NextEntry != ListHead) &&
717 (NextDescriptor->MemoryType == LoaderFree) &&
718 ((NewDescriptor->BasePage + NewDescriptor->PageCount) == NextDescriptor->BasePage))
719 {
720 /* Enlarge next descriptor's PageCount */
721 NewDescriptor->PageCount += NextDescriptor->PageCount;
722 RemoveEntryList(&NextDescriptor->ListEntry);
723 }
724 }
725
726 return;
727 }
728
729 VOID
730 WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss)
731 {
732 GDTIDT GdtDesc, IdtDesc, OldIdt;
733 PKGDTENTRY pGdt;
734 PKIDTENTRY pIdt;
735 ULONG Ldt = 0;
736 //ULONG i;
737
738 DPRINTM(DPRINT_WINDOWS, "GDtIdt %p, Pcr %p, Tss 0x%08X\n",
739 GdtIdt, Pcr, Tss);
740
741 // Kernel expects the PCR to be zero-filled on startup
742 // FIXME: Why zero it here when we can zero it right after allocation?
743 RtlZeroMemory((PVOID)Pcr, MM_PAGE_SIZE); //FIXME: Why zero only 1 page when we allocate 2?
744
745 // Get old values of GDT and IDT
746 Ke386GetGlobalDescriptorTable(GdtDesc);
747 Ke386GetInterruptDescriptorTable(IdtDesc);
748
749 // Save old IDT
750 OldIdt.Base = IdtDesc.Base;
751 OldIdt.Limit = IdtDesc.Limit;
752
753 // Prepare new IDT+GDT
754 GdtDesc.Base = KSEG0_BASE | (ULONG_PTR)GdtIdt;
755 GdtDesc.Limit = NUM_GDT * sizeof(KGDTENTRY) - 1;
756 IdtDesc.Base = (ULONG)((PUCHAR)GdtDesc.Base + GdtDesc.Limit + 1);
757 IdtDesc.Limit = NUM_IDT * sizeof(KIDTENTRY) - 1;
758
759 // ========================
760 // Fill all descriptors now
761 // ========================
762
763 pGdt = (PKGDTENTRY)GdtDesc.Base;
764 pIdt = (PKIDTENTRY)IdtDesc.Base;
765
766 //
767 // Code selector (0x8)
768 // Flat 4Gb
769 //
770 pGdt[1].LimitLow = 0xFFFF;
771 pGdt[1].BaseLow = 0;
772 pGdt[1].HighWord.Bytes.BaseMid = 0;
773 pGdt[1].HighWord.Bytes.Flags1 = 0x9A;
774 pGdt[1].HighWord.Bytes.Flags2 = 0xCF;
775 pGdt[1].HighWord.Bytes.BaseHi = 0;
776
777 //
778 // Data selector (0x10)
779 // Flat 4Gb
780 //
781 pGdt[2].LimitLow = 0xFFFF;
782 pGdt[2].BaseLow = 0;
783 pGdt[2].HighWord.Bytes.BaseMid = 0;
784 pGdt[2].HighWord.Bytes.Flags1 = 0x92;
785 pGdt[2].HighWord.Bytes.Flags2 = 0xCF;
786 pGdt[2].HighWord.Bytes.BaseHi = 0;
787
788 //
789 // Selector (0x18)
790 // Flat 2Gb
791 //
792 pGdt[3].LimitLow = 0xFFFF;
793 pGdt[3].BaseLow = 0;
794 pGdt[3].HighWord.Bytes.BaseMid = 0;
795 pGdt[3].HighWord.Bytes.Flags1 = 0xFA;
796 pGdt[3].HighWord.Bytes.Flags2 = 0xCF;
797 pGdt[3].HighWord.Bytes.BaseHi = 0;
798
799 //
800 // Selector (0x20)
801 // Flat 2Gb
802 //
803 pGdt[4].LimitLow = 0xFFFF;
804 pGdt[4].BaseLow = 0;
805 pGdt[4].HighWord.Bytes.BaseMid = 0;
806 pGdt[4].HighWord.Bytes.Flags1 = 0xF2;
807 pGdt[4].HighWord.Bytes.Flags2 = 0xCF;
808 pGdt[4].HighWord.Bytes.BaseHi = 0;
809
810 //
811 // TSS Selector (0x28)
812 //
813 pGdt[5].LimitLow = 0x78-1; //FIXME: Check this
814 pGdt[5].BaseLow = (USHORT)(Tss & 0xffff);
815 pGdt[5].HighWord.Bytes.BaseMid = (UCHAR)((Tss >> 16) & 0xff);
816 pGdt[5].HighWord.Bytes.Flags1 = 0x89;
817 pGdt[5].HighWord.Bytes.Flags2 = 0x00;
818 pGdt[5].HighWord.Bytes.BaseHi = (UCHAR)((Tss >> 24) & 0xff);
819
820 //
821 // PCR Selector (0x30)
822 //
823 pGdt[6].LimitLow = 0x01;
824 pGdt[6].BaseLow = (USHORT)(Pcr & 0xffff);
825 pGdt[6].HighWord.Bytes.BaseMid = (UCHAR)((Pcr >> 16) & 0xff);
826 pGdt[6].HighWord.Bytes.Flags1 = 0x92;
827 pGdt[6].HighWord.Bytes.Flags2 = 0xC0;
828 pGdt[6].HighWord.Bytes.BaseHi = (UCHAR)((Pcr >> 24) & 0xff);
829
830 //
831 // Selector (0x38)
832 //
833 pGdt[7].LimitLow = 0xFFFF;
834 pGdt[7].BaseLow = 0;
835 pGdt[7].HighWord.Bytes.BaseMid = 0;
836 pGdt[7].HighWord.Bytes.Flags1 = 0xF3;
837 pGdt[7].HighWord.Bytes.Flags2 = 0x40;
838 pGdt[7].HighWord.Bytes.BaseHi = 0;
839
840 //
841 // Some BIOS stuff (0x40)
842 //
843 pGdt[8].LimitLow = 0xFFFF;
844 pGdt[8].BaseLow = 0x400;
845 pGdt[8].HighWord.Bytes.BaseMid = 0;
846 pGdt[8].HighWord.Bytes.Flags1 = 0xF2;
847 pGdt[8].HighWord.Bytes.Flags2 = 0x0;
848 pGdt[8].HighWord.Bytes.BaseHi = 0;
849
850 //
851 // Selector (0x48)
852 //
853 pGdt[9].LimitLow = 0;
854 pGdt[9].BaseLow = 0;
855 pGdt[9].HighWord.Bytes.BaseMid = 0;
856 pGdt[9].HighWord.Bytes.Flags1 = 0;
857 pGdt[9].HighWord.Bytes.Flags2 = 0;
858 pGdt[9].HighWord.Bytes.BaseHi = 0;
859
860 //
861 // Selector (0x50)
862 //
863 pGdt[10].LimitLow = 0xFFFF; //FIXME: Not correct!
864 pGdt[10].BaseLow = 0;
865 pGdt[10].HighWord.Bytes.BaseMid = 0x2;
866 pGdt[10].HighWord.Bytes.Flags1 = 0x89;
867 pGdt[10].HighWord.Bytes.Flags2 = 0;
868 pGdt[10].HighWord.Bytes.BaseHi = 0;
869
870 //
871 // Selector (0x58)
872 //
873 pGdt[11].LimitLow = 0xFFFF;
874 pGdt[11].BaseLow = 0;
875 pGdt[11].HighWord.Bytes.BaseMid = 0x2;
876 pGdt[11].HighWord.Bytes.Flags1 = 0x9A;
877 pGdt[11].HighWord.Bytes.Flags2 = 0;
878 pGdt[11].HighWord.Bytes.BaseHi = 0;
879
880 //
881 // Selector (0x60)
882 //
883 pGdt[12].LimitLow = 0xFFFF;
884 pGdt[12].BaseLow = 0; //FIXME: Maybe not correct, but noone cares
885 pGdt[12].HighWord.Bytes.BaseMid = 0x2;
886 pGdt[12].HighWord.Bytes.Flags1 = 0x92;
887 pGdt[12].HighWord.Bytes.Flags2 = 0;
888 pGdt[12].HighWord.Bytes.BaseHi = 0;
889
890 //
891 // Video buffer Selector (0x68)
892 //
893 pGdt[13].LimitLow = 0x3FFF;
894 pGdt[13].BaseLow = 0x8000;
895 pGdt[13].HighWord.Bytes.BaseMid = 0x0B;
896 pGdt[13].HighWord.Bytes.Flags1 = 0x92;
897 pGdt[13].HighWord.Bytes.Flags2 = 0;
898 pGdt[13].HighWord.Bytes.BaseHi = 0;
899
900 //
901 // Points to GDT (0x70)
902 //
903 pGdt[14].LimitLow = NUM_GDT*sizeof(KGDTENTRY) - 1;
904 pGdt[14].BaseLow = 0x7000;
905 pGdt[14].HighWord.Bytes.BaseMid = 0xFF;
906 pGdt[14].HighWord.Bytes.Flags1 = 0x92;
907 pGdt[14].HighWord.Bytes.Flags2 = 0;
908 pGdt[14].HighWord.Bytes.BaseHi = 0xFF;
909
910 //
911 // Some unused descriptors should go here
912 //
913
914 // Copy the old IDT
915 RtlCopyMemory(pIdt, (PVOID)OldIdt.Base, OldIdt.Limit);
916
917 // Mask interrupts
918 //asm("cli\n"); // they are already masked before enabling paged mode
919
920 // Load GDT+IDT
921 Ke386SetGlobalDescriptorTable(GdtDesc);
922 Ke386SetInterruptDescriptorTable(IdtDesc);
923
924 // Jump to proper CS and clear prefetch queue
925 asm("ljmp $0x08, $mb1\n"
926 "mb1:\n");
927
928 // Set SS selector
929 asm(".intel_syntax noprefix\n");
930 asm("mov ax, 0x10\n"); // DataSelector=0x10
931 asm("mov ss, ax\n");
932 asm(".att_syntax\n");
933
934 // Set DS and ES selectors
935 Ke386SetDs(0x10);
936 Ke386SetEs(0x10); // this is vital for rep stosd
937
938 // LDT = not used ever, thus set to 0
939 Ke386SetLocalDescriptorTable(Ldt);
940
941 // Load TSR
942 Ke386SetTr(0x28);
943
944 // Clear GS
945 asm(".intel_syntax noprefix\n");
946 asm("push 0\n");
947 asm("pop gs\n");
948 asm(".att_syntax\n");
949
950 // Set FS to PCR
951 Ke386SetFs(0x30);
952
953 // Real end of the function, just for information
954 /* do not uncomment!
955 pop edi;
956 pop esi;
957 pop ebx;
958 mov esp, ebp;
959 pop ebp;
960 ret
961 */
962 }