9b783a7bda7c9b44cec15589851898e4123e5aab
[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 VOID
405 WinLdrpMapApic()
406 {
407 BOOLEAN LocalAPIC;
408 LARGE_INTEGER MsrValue;
409 ULONG APICAddress, CpuInfo[4];
410
411 /* Check if we have a local APIC */
412 __cpuid((int*)CpuInfo, 1);
413 LocalAPIC = (((CpuInfo[3] >> 9) & 1) != 0);
414
415 /* If there is no APIC, just return */
416 if (!LocalAPIC)
417 return;
418
419 /* Read the APIC Address */
420 MsrValue.QuadPart = __readmsr(0x1B);
421 APICAddress = (MsrValue.LowPart & 0xFFFFF000);
422
423 DPRINTM(DPRINT_WINDOWS, "Local APIC detected at address 0x%x\n",
424 APICAddress);
425
426 /* Map it */
427 HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber
428 = APICAddress >> MM_PAGE_SHIFT;
429 HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
430 HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
431 HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].WriteThrough = 1;
432 HalPageTable[(APIC_BASE - 0xFFC00000) >> MM_PAGE_SHIFT].CacheDisable = 1;
433 }
434 #else
435 VOID
436 WinLdrpMapApic()
437 {
438 /* Implement it for another arch */
439 }
440 #endif
441
442 BOOLEAN
443 WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
444 ULONG PcrBasePage,
445 ULONG TssBasePage,
446 PVOID GdtIdt)
447 {
448 ULONG i, PagesCount, MemoryMapSizeInPages;
449 ULONG LastPageIndex, LastPageType, MemoryMapStartPage;
450 PPAGE_LOOKUP_TABLE_ITEM MemoryMap;
451 ULONG NoEntries;
452 PKTSS Tss;
453 BOOLEAN Status;
454
455 //
456 // Creating a suitable memory map for the Windows can be tricky, so let's
457 // give a few advices:
458 // 1) One must not map the whole available memory pages to PDE!
459 // Map only what's needed - 16Mb, 24Mb, 32Mb max I think,
460 // thus occupying 4, 6 or 8 PDE entries for identical mapping,
461 // the same quantity for KSEG0_BASE mapping, one more entry for
462 // hyperspace and one more entry for HAL physical pages mapping.
463 // 2) Memory descriptors must map *the whole* physical memory
464 // showing any memory above 16/24/32 as FirmwareTemporary
465 //
466 // 3) Overall memory blocks count must not exceed 30 (?? why?)
467 //
468
469 //
470 // During MmInitMachineDependent, the kernel zeroes PDE at the following address
471 // 0xC0300000 - 0xC03007FC
472 //
473 // Then it finds the best place for non-paged pool:
474 // StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD
475 //
476
477 // Before we start mapping pages, create a block of memory, which will contain
478 // PDE and PTEs
479 if (MempAllocatePageTables() == FALSE)
480 return FALSE;
481
482 // Allocate memory for memory allocation descriptors
483 Mad = MmHeapAlloc(sizeof(MEMORY_ALLOCATION_DESCRIPTOR) * 1024);
484
485 // Setup an entry for each descriptor
486 MemoryMap = MmGetMemoryMap(&NoEntries);
487 if (MemoryMap == NULL)
488 {
489 UiMessageBox("Can not retrieve the current memory map");
490 return FALSE;
491 }
492
493 // Calculate parameters of the memory map
494 MemoryMapStartPage = (ULONG_PTR)MemoryMap >> MM_PAGE_SHIFT;
495 MemoryMapSizeInPages = NoEntries * sizeof(PAGE_LOOKUP_TABLE_ITEM);
496
497 DPRINTM(DPRINT_WINDOWS, "Got memory map with %d entries\n", NoEntries);
498
499 // Always contigiously map low 1Mb of memory
500 Status = MempSetupPaging(0, 0x100);
501 if (!Status)
502 {
503 DPRINTM(DPRINT_WINDOWS, "Error during MempSetupPaging of low 1Mb\n");
504 return FALSE;
505 }
506
507 // Construct a good memory map from what we've got,
508 // but mark entries which the memory allocation bitmap takes
509 // as free entries (this is done in order to have the ability
510 // to place mem alloc bitmap outside lower 16Mb zone)
511 PagesCount = 1;
512 LastPageIndex = 0;
513 LastPageType = MemoryMap[0].PageAllocated;
514 for(i=1;i<NoEntries;i++)
515 {
516 // Check if its memory map itself
517 if (i >= MemoryMapStartPage &&
518 i < (MemoryMapStartPage+MemoryMapSizeInPages))
519 {
520 // Exclude it if current page belongs to the memory map
521 MemoryMap[i].PageAllocated = LoaderFree;
522 }
523
524 // Process entry
525 if (MemoryMap[i].PageAllocated == LastPageType &&
526 (i != NoEntries-1) )
527 {
528 PagesCount++;
529 }
530 else
531 {
532 // Add the resulting region
533 MempAddMemoryBlock(LoaderBlock, LastPageIndex, PagesCount, LastPageType);
534
535 // Reset our counter vars
536 LastPageIndex = i;
537 LastPageType = MemoryMap[i].PageAllocated;
538 PagesCount = 1;
539 }
540 }
541
542 // TEMP, DEBUG!
543 // adding special reserved memory zones for vmware workstation
544 #if 0
545 {
546 Mad[MadCount].BasePage = 0xfec00;
547 Mad[MadCount].PageCount = 0x10;
548 Mad[MadCount].MemoryType = LoaderSpecialMemory;
549 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
550 MadCount++;
551
552 Mad[MadCount].BasePage = 0xfee00;
553 Mad[MadCount].PageCount = 0x1;
554 Mad[MadCount].MemoryType = LoaderSpecialMemory;
555 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
556 MadCount++;
557
558 Mad[MadCount].BasePage = 0xfffe0;
559 Mad[MadCount].PageCount = 0x20;
560 Mad[MadCount].MemoryType = LoaderSpecialMemory;
561 WinLdrInsertDescriptor(LoaderBlock, &Mad[MadCount]);
562 MadCount++;
563 }
564 #endif
565
566 DPRINTM(DPRINT_WINDOWS, "MadCount: %d\n", MadCount);
567
568 WinLdrpDumpMemoryDescriptors(LoaderBlock); //FIXME: Delete!
569
570 // Map our loader image, so we can continue running
571 /*Status = MempSetupPaging(OsLoaderBase >> MM_PAGE_SHIFT, OsLoaderSize >> MM_PAGE_SHIFT);
572 if (!Status)
573 {
574 UiMessageBox("Error during MempSetupPaging");
575 return;
576 }*/
577
578 //VideoDisplayString(L"Hello from VGA, going into the kernel\n");
579 DPRINTM(DPRINT_WINDOWS, "HalPageTable: 0x%X\n", HalPageTable);
580
581 // Page Tables have been setup, make special handling for PCR and TSS
582 // (which is done in BlSetupFotNt in usual ntldr)
583 HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage+1;
584 HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
585 HalPageTable[(KI_USER_SHARED_DATA - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
586
587 HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].PageFrameNumber = PcrBasePage;
588 HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Valid = 1;
589 HalPageTable[(KIP0PCRADDRESS - 0xFFC00000) >> MM_PAGE_SHIFT].Write = 1;
590
591 // Map APIC
592 WinLdrpMapApic();
593
594 // Map VGA memory
595 //VideoMemoryBase = MmMapIoSpace(0xb8000, 4000, MmNonCached);
596 //DPRINTM(DPRINT_WINDOWS, "VideoMemoryBase: 0x%X\n", VideoMemoryBase);
597
598 Tss = (PKTSS)(KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT));
599
600 // Unmap what is not needed from kernel page table
601 MempDisablePages();
602
603 // Fill the memory descriptor list and
604 //PrepareMemoryDescriptorList();
605 DPRINTM(DPRINT_WINDOWS, "Memory Descriptor List prepared, printing PDE\n");
606 List_PaToVa(&LoaderBlock->MemoryDescriptorListHead);
607
608 #if DBG
609 {
610 ULONG *PDE_Addr=(ULONG *)PDE;//0xC0300000;
611 int j;
612
613 DPRINTM(DPRINT_WINDOWS, "\nPDE\n");
614
615 for (i=0; i<128; i++)
616 {
617 DPRINTM(DPRINT_WINDOWS, "0x%04X | ", i*8);
618
619 for (j=0; j<8; j++)
620 {
621 DPRINTM(DPRINT_WINDOWS, "0x%08X ", PDE_Addr[i*8+j]);
622 }
623
624 DPRINTM(DPRINT_WINDOWS, "\n");
625 }
626 }
627 #endif
628
629
630 // Enable paging
631 //BS->ExitBootServices(ImageHandle,MapKey);
632
633 // Disable Interrupts
634 _disable();
635
636 // Re-initalize EFLAGS
637 __writeeflags(0);
638
639 // Set the PDBR
640 __writecr3((ULONG_PTR)PDE);
641
642 // Enable paging by modifying CR0
643 __writecr0(__readcr0() | CR0_PG);
644
645 // Set processor context
646 WinLdrSetProcessorContext(GdtIdt, KIP0PCRADDRESS, KSEG0_BASE | (TssBasePage << MM_PAGE_SHIFT));
647
648 // Zero KI_USER_SHARED_DATA page
649 memset((PVOID)KI_USER_SHARED_DATA, 0, MM_PAGE_SIZE);
650
651 return TRUE;
652 }
653
654 // Two special things this func does: it sorts descriptors,
655 // and it merges free ones
656 VOID
657 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock,
658 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor)
659 {
660 PLIST_ENTRY ListHead = &LoaderBlock->MemoryDescriptorListHead;
661 PLIST_ENTRY PreviousEntry, NextEntry;
662 PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor = NULL, NextDescriptor = NULL;
663
664 DPRINTM(DPRINT_WINDOWS, "BP=0x%X PC=0x%X %s\n", NewDescriptor->BasePage,
665 NewDescriptor->PageCount, MemTypeDesc[NewDescriptor->MemoryType]);
666
667 /* Find a place where to insert the new descriptor to */
668 PreviousEntry = ListHead;
669 NextEntry = ListHead->Flink;
670 while (NextEntry != ListHead)
671 {
672 NextDescriptor = CONTAINING_RECORD(NextEntry,
673 MEMORY_ALLOCATION_DESCRIPTOR,
674 ListEntry);
675 if (NewDescriptor->BasePage < NextDescriptor->BasePage)
676 break;
677
678 PreviousEntry = NextEntry;
679 PreviousDescriptor = NextDescriptor;
680 NextEntry = NextEntry->Flink;
681 }
682
683 /* Don't forget about merging free areas */
684 if (NewDescriptor->MemoryType != LoaderFree)
685 {
686 /* Just insert, nothing to merge */
687 InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
688 }
689 else
690 {
691 /* Previous block also free? */
692 if ((PreviousEntry != ListHead) && (PreviousDescriptor->MemoryType == LoaderFree) &&
693 ((PreviousDescriptor->BasePage + PreviousDescriptor->PageCount) ==
694 NewDescriptor->BasePage))
695 {
696 /* Just enlarge previous descriptor's PageCount */
697 PreviousDescriptor->PageCount += NewDescriptor->PageCount;
698 NewDescriptor = PreviousDescriptor;
699 }
700 else
701 {
702 /* Nope, just insert */
703 InsertHeadList(PreviousEntry, &NewDescriptor->ListEntry);
704 }
705
706 /* Next block is free ?*/
707 if ((NextEntry != ListHead) &&
708 (NextDescriptor->MemoryType == LoaderFree) &&
709 ((NewDescriptor->BasePage + NewDescriptor->PageCount) == NextDescriptor->BasePage))
710 {
711 /* Enlarge next descriptor's PageCount */
712 NewDescriptor->PageCount += NextDescriptor->PageCount;
713 RemoveEntryList(&NextDescriptor->ListEntry);
714 }
715 }
716
717 return;
718 }
719
720 VOID
721 WinLdrSetProcessorContext(PVOID GdtIdt, IN ULONG Pcr, IN ULONG Tss)
722 {
723 GDTIDT GdtDesc, IdtDesc, OldIdt;
724 PKGDTENTRY pGdt;
725 PKIDTENTRY pIdt;
726 ULONG Ldt = 0;
727 //ULONG i;
728
729 DPRINTM(DPRINT_WINDOWS, "GDtIdt %p, Pcr %p, Tss 0x%08X\n",
730 GdtIdt, Pcr, Tss);
731
732 // Kernel expects the PCR to be zero-filled on startup
733 // FIXME: Why zero it here when we can zero it right after allocation?
734 RtlZeroMemory((PVOID)Pcr, MM_PAGE_SIZE); //FIXME: Why zero only 1 page when we allocate 2?
735
736 // Get old values of GDT and IDT
737 Ke386GetGlobalDescriptorTable(&GdtDesc);
738 __sidt(&IdtDesc);
739
740 // Save old IDT
741 OldIdt.Base = IdtDesc.Base;
742 OldIdt.Limit = IdtDesc.Limit;
743
744 // Prepare new IDT+GDT
745 GdtDesc.Base = KSEG0_BASE | (ULONG_PTR)GdtIdt;
746 GdtDesc.Limit = NUM_GDT * sizeof(KGDTENTRY) - 1;
747 IdtDesc.Base = (ULONG)((PUCHAR)GdtDesc.Base + GdtDesc.Limit + 1);
748 IdtDesc.Limit = NUM_IDT * sizeof(KIDTENTRY) - 1;
749
750 // ========================
751 // Fill all descriptors now
752 // ========================
753
754 pGdt = (PKGDTENTRY)GdtDesc.Base;
755 pIdt = (PKIDTENTRY)IdtDesc.Base;
756
757 //
758 // Code selector (0x8)
759 // Flat 4Gb
760 //
761 pGdt[1].LimitLow = 0xFFFF;
762 pGdt[1].BaseLow = 0;
763 pGdt[1].HighWord.Bytes.BaseMid = 0;
764 pGdt[1].HighWord.Bytes.Flags1 = 0x9A;
765 pGdt[1].HighWord.Bytes.Flags2 = 0xCF;
766 pGdt[1].HighWord.Bytes.BaseHi = 0;
767
768 //
769 // Data selector (0x10)
770 // Flat 4Gb
771 //
772 pGdt[2].LimitLow = 0xFFFF;
773 pGdt[2].BaseLow = 0;
774 pGdt[2].HighWord.Bytes.BaseMid = 0;
775 pGdt[2].HighWord.Bytes.Flags1 = 0x92;
776 pGdt[2].HighWord.Bytes.Flags2 = 0xCF;
777 pGdt[2].HighWord.Bytes.BaseHi = 0;
778
779 //
780 // Selector (0x18)
781 // Flat 2Gb
782 //
783 pGdt[3].LimitLow = 0xFFFF;
784 pGdt[3].BaseLow = 0;
785 pGdt[3].HighWord.Bytes.BaseMid = 0;
786 pGdt[3].HighWord.Bytes.Flags1 = 0xFA;
787 pGdt[3].HighWord.Bytes.Flags2 = 0xCF;
788 pGdt[3].HighWord.Bytes.BaseHi = 0;
789
790 //
791 // Selector (0x20)
792 // Flat 2Gb
793 //
794 pGdt[4].LimitLow = 0xFFFF;
795 pGdt[4].BaseLow = 0;
796 pGdt[4].HighWord.Bytes.BaseMid = 0;
797 pGdt[4].HighWord.Bytes.Flags1 = 0xF2;
798 pGdt[4].HighWord.Bytes.Flags2 = 0xCF;
799 pGdt[4].HighWord.Bytes.BaseHi = 0;
800
801 //
802 // TSS Selector (0x28)
803 //
804 pGdt[5].LimitLow = 0x78-1; //FIXME: Check this
805 pGdt[5].BaseLow = (USHORT)(Tss & 0xffff);
806 pGdt[5].HighWord.Bytes.BaseMid = (UCHAR)((Tss >> 16) & 0xff);
807 pGdt[5].HighWord.Bytes.Flags1 = 0x89;
808 pGdt[5].HighWord.Bytes.Flags2 = 0x00;
809 pGdt[5].HighWord.Bytes.BaseHi = (UCHAR)((Tss >> 24) & 0xff);
810
811 //
812 // PCR Selector (0x30)
813 //
814 pGdt[6].LimitLow = 0x01;
815 pGdt[6].BaseLow = (USHORT)(Pcr & 0xffff);
816 pGdt[6].HighWord.Bytes.BaseMid = (UCHAR)((Pcr >> 16) & 0xff);
817 pGdt[6].HighWord.Bytes.Flags1 = 0x92;
818 pGdt[6].HighWord.Bytes.Flags2 = 0xC0;
819 pGdt[6].HighWord.Bytes.BaseHi = (UCHAR)((Pcr >> 24) & 0xff);
820
821 //
822 // Selector (0x38)
823 //
824 pGdt[7].LimitLow = 0xFFFF;
825 pGdt[7].BaseLow = 0;
826 pGdt[7].HighWord.Bytes.BaseMid = 0;
827 pGdt[7].HighWord.Bytes.Flags1 = 0xF3;
828 pGdt[7].HighWord.Bytes.Flags2 = 0x40;
829 pGdt[7].HighWord.Bytes.BaseHi = 0;
830
831 //
832 // Some BIOS stuff (0x40)
833 //
834 pGdt[8].LimitLow = 0xFFFF;
835 pGdt[8].BaseLow = 0x400;
836 pGdt[8].HighWord.Bytes.BaseMid = 0;
837 pGdt[8].HighWord.Bytes.Flags1 = 0xF2;
838 pGdt[8].HighWord.Bytes.Flags2 = 0x0;
839 pGdt[8].HighWord.Bytes.BaseHi = 0;
840
841 //
842 // Selector (0x48)
843 //
844 pGdt[9].LimitLow = 0;
845 pGdt[9].BaseLow = 0;
846 pGdt[9].HighWord.Bytes.BaseMid = 0;
847 pGdt[9].HighWord.Bytes.Flags1 = 0;
848 pGdt[9].HighWord.Bytes.Flags2 = 0;
849 pGdt[9].HighWord.Bytes.BaseHi = 0;
850
851 //
852 // Selector (0x50)
853 //
854 pGdt[10].LimitLow = 0xFFFF; //FIXME: Not correct!
855 pGdt[10].BaseLow = 0;
856 pGdt[10].HighWord.Bytes.BaseMid = 0x2;
857 pGdt[10].HighWord.Bytes.Flags1 = 0x89;
858 pGdt[10].HighWord.Bytes.Flags2 = 0;
859 pGdt[10].HighWord.Bytes.BaseHi = 0;
860
861 //
862 // Selector (0x58)
863 //
864 pGdt[11].LimitLow = 0xFFFF;
865 pGdt[11].BaseLow = 0;
866 pGdt[11].HighWord.Bytes.BaseMid = 0x2;
867 pGdt[11].HighWord.Bytes.Flags1 = 0x9A;
868 pGdt[11].HighWord.Bytes.Flags2 = 0;
869 pGdt[11].HighWord.Bytes.BaseHi = 0;
870
871 //
872 // Selector (0x60)
873 //
874 pGdt[12].LimitLow = 0xFFFF;
875 pGdt[12].BaseLow = 0; //FIXME: Maybe not correct, but noone cares
876 pGdt[12].HighWord.Bytes.BaseMid = 0x2;
877 pGdt[12].HighWord.Bytes.Flags1 = 0x92;
878 pGdt[12].HighWord.Bytes.Flags2 = 0;
879 pGdt[12].HighWord.Bytes.BaseHi = 0;
880
881 //
882 // Video buffer Selector (0x68)
883 //
884 pGdt[13].LimitLow = 0x3FFF;
885 pGdt[13].BaseLow = 0x8000;
886 pGdt[13].HighWord.Bytes.BaseMid = 0x0B;
887 pGdt[13].HighWord.Bytes.Flags1 = 0x92;
888 pGdt[13].HighWord.Bytes.Flags2 = 0;
889 pGdt[13].HighWord.Bytes.BaseHi = 0;
890
891 //
892 // Points to GDT (0x70)
893 //
894 pGdt[14].LimitLow = NUM_GDT*sizeof(KGDTENTRY) - 1;
895 pGdt[14].BaseLow = 0x7000;
896 pGdt[14].HighWord.Bytes.BaseMid = 0xFF;
897 pGdt[14].HighWord.Bytes.Flags1 = 0x92;
898 pGdt[14].HighWord.Bytes.Flags2 = 0;
899 pGdt[14].HighWord.Bytes.BaseHi = 0xFF;
900
901 //
902 // Some unused descriptors should go here
903 //
904
905 // Copy the old IDT
906 RtlCopyMemory(pIdt, (PVOID)OldIdt.Base, OldIdt.Limit + 1);
907
908 // Mask interrupts
909 //asm("cli\n"); // they are already masked before enabling paged mode
910
911 // Load GDT+IDT
912 Ke386SetGlobalDescriptorTable(&GdtDesc);
913 __lidt(&IdtDesc);
914
915 // Jump to proper CS and clear prefetch queue
916 #if defined(__GNUC__)
917 asm("ljmp $0x08, $1f\n"
918 "1:\n");
919 #elif defined(_MSC_VER)
920 /* We can't express the above in MASM so we use this far return instead */
921 DbgPrint("WinLdrSetProcessorContext: Performing untested far-return\n");
922 __asm {
923 push 8
924 push offset resume
925 retf
926 resume:
927 };
928 #else
929 #error
930 #endif
931
932 // Set SS selector
933 Ke386SetSs(0x10); // DataSelector=0x10
934
935 // Set DS and ES selectors
936 Ke386SetDs(0x10);
937 Ke386SetEs(0x10); // this is vital for rep stosd
938
939 // LDT = not used ever, thus set to 0
940 Ke386SetLocalDescriptorTable(Ldt);
941
942 // Load TSR
943 Ke386SetTr(0x28);
944
945 // Clear GS
946 Ke386SetGs(0);
947
948 // Set FS to PCR
949 Ke386SetFs(0x30);
950
951 // Real end of the function, just for information
952 /* do not uncomment!
953 pop edi;
954 pop esi;
955 pop ebx;
956 mov esp, ebp;
957 pop ebp;
958 ret
959 */
960 }