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