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)
9 /* INCLUDES ***************************************************************/
16 extern ULONG TotalNLSSize
;
17 extern ULONG LoaderPagesSpanned
;
19 // This is needed because headers define wrong one for ReactOS
21 #define KIP0PCRADDRESS 0xffdff000
23 #define HYPER_SPACE_ENTRY 0x300
25 PCHAR MemTypeDesc
[] = {
26 "ExceptionBlock ", // ?
30 "LoadedProgram ", // == Free
31 "FirmwareTemporary ", // == Free
32 "FirmwarePermanent ", // == Bad
33 "OsloaderHeap ", // used
34 "OsloaderStack ", // == Free
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
48 "SpecialMemory ", // == Bad
49 "BBTMemory " // == Bad
53 WinLdrpDumpMemoryDescriptors(PLOADER_PARAMETER_BLOCK LoaderBlock
);
57 MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
62 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
63 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
);
66 WinLdrRemoveDescriptor(IN PMEMORY_ALLOCATION_DESCRIPTOR Descriptor
);
69 WinLdrSetProcessorContext(PVOID GdtIdt
, IN ULONG Pcr
, IN ULONG Tss
);
71 // This is needed only for SetProcessorContext routine
80 /* GLOBALS ***************************************************************/
83 PHARDWARE_PTE HalPageTable
;
85 PUCHAR PhysicalPageTablesBuffer
;
86 PUCHAR KernelPageTablesBuffer
;
87 ULONG PhysicalPageTables
;
88 ULONG KernelPageTables
;
90 MEMORY_ALLOCATION_DESCRIPTOR
*Mad
;
94 /* FUNCTIONS **************************************************************/
97 MempAllocatePageTables()
99 ULONG NumPageTables
, TotalSize
;
101 // It's better to allocate PDE + PTEs contigiuos
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;
108 DPRINTM(DPRINT_WINDOWS
, "NumPageTables = %d\n", NumPageTables
);
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
;
114 // PDE+HAL+KernelPTEs == MemoryData
115 Buffer
= MmAllocateMemoryWithType(TotalSize
, LoaderMemoryData
);
117 // Physical PTEs = FirmwareTemporary
118 PhysicalPageTablesBuffer
= (PUCHAR
)Buffer
+ TotalSize
- NumPageTables
*MM_PAGE_SIZE
;
119 MmSetMemoryType(PhysicalPageTablesBuffer
,
120 NumPageTables
*MM_PAGE_SIZE
,
121 LoaderFirmwareTemporary
);
123 // This check is now redundant
124 if (Buffer
+ (TotalSize
- NumPageTables
*MM_PAGE_SIZE
) !=
125 PhysicalPageTablesBuffer
)
127 DPRINTM(DPRINT_WINDOWS
, "There was a problem allocating two adjacent blocks of memory!");
130 if (Buffer
== NULL
|| PhysicalPageTablesBuffer
== NULL
)
132 UiMessageBox("Impossible to allocate memory block for page tables!");
136 // Zero all this memory block
137 RtlZeroMemory(Buffer
, TotalSize
);
139 // Set up pointers correctly now
140 PDE
= (PHARDWARE_PTE
)Buffer
;
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;
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];
151 PDE
[1023].PageFrameNumber
= (ULONG
)HalPageTable
>> MM_PAGE_SHIFT
;
155 // Store pointer to the table for easier access
156 KernelPageTablesBuffer
= &Buffer
[MM_PAGE_SIZE
*2];
158 // Zero counters of page tables used
159 PhysicalPageTables
= 0;
160 KernelPageTables
= 0;
166 MempAllocatePTE(ULONG Entry
, PHARDWARE_PTE
*PhysicalPT
, PHARDWARE_PTE
*KernelPT
)
168 //Print(L"Creating PDE Entry %X\n", Entry);
171 *PhysicalPT
= (PHARDWARE_PTE
)&PhysicalPageTablesBuffer
[PhysicalPageTables
*MM_PAGE_SIZE
];
172 PhysicalPageTables
++;
174 PDE
[Entry
].PageFrameNumber
= (ULONG
)*PhysicalPT
>> MM_PAGE_SHIFT
;
175 PDE
[Entry
].Valid
= 1;
176 PDE
[Entry
].Write
= 1;
178 if (Entry
+(KSEG0_BASE
>> 22) > 1023)
180 DPRINTM(DPRINT_WINDOWS
, "WARNING! Entry: %X > 1023\n", Entry
+(KSEG0_BASE
>> 22));
183 // Kernel-mode mapping
184 *KernelPT
= (PHARDWARE_PTE
)&KernelPageTablesBuffer
[KernelPageTables
*MM_PAGE_SIZE
];
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;
193 MempSetupPaging(IN ULONG StartPage
,
194 IN ULONG NumberOfPages
)
196 PHARDWARE_PTE PhysicalPT
;
197 PHARDWARE_PTE KernelPT
;
200 //Print(L"MempSetupPaging: SP 0x%X, Number: 0x%X\n", StartPage, NumberOfPages);
203 if (StartPage
+NumberOfPages
>= 0x80000)
206 // We can't map this as it requires more than 1 PDE
207 // and in fact it's not possible at all ;)
209 //Print(L"skipping...\n");
214 // Now actually set up the page tables for identity mapping
216 for (Page
=StartPage
; Page
< StartPage
+NumberOfPages
; Page
++)
220 if (((PULONG
)PDE
)[Entry
] == 0)
222 MempAllocatePTE(Entry
, &PhysicalPT
, &KernelPT
);
226 PhysicalPT
= (PHARDWARE_PTE
)(PDE
[Entry
].PageFrameNumber
<< MM_PAGE_SHIFT
);
227 KernelPT
= (PHARDWARE_PTE
)(PDE
[Entry
+(KSEG0_BASE
>> 22)].PageFrameNumber
<< MM_PAGE_SHIFT
);
232 PhysicalPT
[Page
& 0x3ff].PageFrameNumber
= Page
;
233 PhysicalPT
[Page
& 0x3ff].Valid
= 0;
234 PhysicalPT
[Page
& 0x3ff].Write
= 0;
236 KernelPT
[Page
& 0x3ff].PageFrameNumber
= Page
;
237 KernelPT
[Page
& 0x3ff].Valid
= 0;
238 KernelPT
[Page
& 0x3ff].Write
= 0;
242 PhysicalPT
[Page
& 0x3ff].PageFrameNumber
= Page
;
243 PhysicalPT
[Page
& 0x3ff].Valid
= 1;
244 PhysicalPT
[Page
& 0x3ff].Write
= 1;
246 KernelPT
[Page
& 0x3ff].PageFrameNumber
= Page
;
247 KernelPT
[Page
& 0x3ff].Valid
= 1;
248 KernelPT
[Page
& 0x3ff].Write
= 1;
261 // We need to delete kernel mapping from memory areas which are
262 // marked as Special or Permanent memory (thus non-accessible)
265 for (i
=0; i
<MadCount
; i
++)
267 ULONG StartPage
, EndPage
, Page
;
269 StartPage
= Mad
[i
].BasePage
;
270 EndPage
= Mad
[i
].BasePage
+ Mad
[i
].PageCount
;
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
)
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
)
286 if (StartPage
< 0x100)
289 if (EndPage
> LoaderPagesSpanned
)
290 EndPage
= LoaderPagesSpanned
;
293 for (Page
= StartPage
; Page
< EndPage
; Page
++)
295 PHARDWARE_PTE KernelPT
;
296 ULONG Entry
= (Page
>> 10) + (KSEG0_BASE
>> 22);
298 if (PDE
[Entry
].Valid
)
300 KernelPT
= (PHARDWARE_PTE
)(PDE
[Entry
].PageFrameNumber
<< MM_PAGE_SHIFT
);
304 KernelPT
[Page
& 0x3ff].PageFrameNumber
= 0;
305 KernelPT
[Page
& 0x3ff].Valid
= 0;
306 KernelPT
[Page
& 0x3ff].Write
= 0;
315 MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
323 // Check for some weird stuff at the top
325 if (BasePage
+ PageCount
> 0xF0000)
328 // Just skip this, without even adding to MAD list
334 // Set Base page, page count and type
336 Mad
[MadCount
].BasePage
= BasePage
;
337 Mad
[MadCount
].PageCount
= PageCount
;
338 Mad
[MadCount
].MemoryType
= Type
;
341 // Check if it's more than the allowed for OS loader
342 // if yes - don't map the pages, just add as FirmwareTemporary
344 if (BasePage
+ PageCount
> LoaderPagesSpanned
)
346 if (Mad
[MadCount
].MemoryType
!= LoaderSpecialMemory
&&
347 Mad
[MadCount
].MemoryType
!= LoaderFirmwarePermanent
&&
348 Mad
[MadCount
].MemoryType
!= LoaderFree
)
350 DPRINTM(DPRINT_WINDOWS
, "Setting page %x %x to Temporary from %d\n",
351 BasePage
, PageCount
, Mad
[MadCount
].MemoryType
);
352 Mad
[MadCount
].MemoryType
= LoaderFirmwareTemporary
;
355 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
364 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
368 // Map it (don't map low 1Mb because it was already contigiously
369 // mapped in WinLdrTurnOnPaging)
371 if (BasePage
>= 0x100)
373 Status
= MempSetupPaging(BasePage
, PageCount
);
376 DPRINTM(DPRINT_WINDOWS
, "Error during MempSetupPaging\n");
387 LARGE_INTEGER MsrValue
;
388 ULONG APICAddress
, CpuInfo
[4];
390 /* Check if we have a local APIC */
391 __cpuid((int*)CpuInfo
, 1);
392 LocalAPIC
= (((CpuInfo
[3] >> 9) & 1) != 0);
394 /* If there is no APIC, just return */
398 /* Read the APIC Address */
399 MsrValue
.QuadPart
= __readmsr(0x1B);
400 APICAddress
= (MsrValue
.LowPart
& 0xFFFFF000);
402 DPRINTM(DPRINT_WINDOWS
, "Local APIC detected at address 0x%x\n",
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;
417 /* Implement it for another arch */
422 WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
427 ULONG i
, PagesCount
, MemoryMapSizeInPages
;
428 ULONG LastPageIndex
, LastPageType
, MemoryMapStartPage
;
429 PPAGE_LOOKUP_TABLE_ITEM MemoryMap
;
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
445 // 3) Overall memory blocks count must not exceed 30 (?? why?)
449 // During MmInitMachineDependent, the kernel zeroes PDE at the following address
450 // 0xC0300000 - 0xC03007FC
452 // Then it finds the best place for non-paged pool:
453 // StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD
456 // Before we start mapping pages, create a block of memory, which will contain
458 if (MempAllocatePageTables() == FALSE
)
461 // Allocate memory for memory allocation descriptors
462 Mad
= MmHeapAlloc(sizeof(MEMORY_ALLOCATION_DESCRIPTOR
) * 1024);
464 // Setup an entry for each descriptor
465 MemoryMap
= MmGetMemoryMap(&NoEntries
);
466 if (MemoryMap
== NULL
)
468 UiMessageBox("Can not retrieve the current memory map");
472 // Calculate parameters of the memory map
473 MemoryMapStartPage
= (ULONG_PTR
)MemoryMap
>> MM_PAGE_SHIFT
;
474 MemoryMapSizeInPages
= NoEntries
* sizeof(PAGE_LOOKUP_TABLE_ITEM
);
476 DPRINTM(DPRINT_WINDOWS
, "Got memory map with %d entries\n", NoEntries
);
478 // Always contigiously map low 1Mb of memory
479 Status
= MempSetupPaging(0, 0x100);
482 DPRINTM(DPRINT_WINDOWS
, "Error during MempSetupPaging of low 1Mb\n");
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)
492 LastPageType
= MemoryMap
[0].PageAllocated
;
493 for(i
=1;i
<NoEntries
;i
++)
495 // Check if its memory map itself
496 if (i
>= MemoryMapStartPage
&&
497 i
< (MemoryMapStartPage
+MemoryMapSizeInPages
))
499 // Exclude it if current page belongs to the memory map
500 MemoryMap
[i
].PageAllocated
= LoaderFree
;
504 if (MemoryMap
[i
].PageAllocated
== LastPageType
&&
511 // Add the resulting region
512 MempAddMemoryBlock(LoaderBlock
, LastPageIndex
, PagesCount
, LastPageType
);
514 // Reset our counter vars
516 LastPageType
= MemoryMap
[i
].PageAllocated
;
522 // adding special reserved memory zones for vmware workstation
525 Mad
[MadCount
].BasePage
= 0xfec00;
526 Mad
[MadCount
].PageCount
= 0x10;
527 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
528 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
531 Mad
[MadCount
].BasePage
= 0xfee00;
532 Mad
[MadCount
].PageCount
= 0x1;
533 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
534 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
537 Mad
[MadCount
].BasePage
= 0xfffe0;
538 Mad
[MadCount
].PageCount
= 0x20;
539 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
540 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
545 DPRINTM(DPRINT_WINDOWS
, "MadCount: %d\n", MadCount
);
547 WinLdrpDumpMemoryDescriptors(LoaderBlock
); //FIXME: Delete!
549 // Map our loader image, so we can continue running
550 /*Status = MempSetupPaging(OsLoaderBase >> MM_PAGE_SHIFT, OsLoaderSize >> MM_PAGE_SHIFT);
553 UiMessageBox("Error during MempSetupPaging");
557 //VideoDisplayString(L"Hello from VGA, going into the kernel\n");
558 DPRINTM(DPRINT_WINDOWS
, "HalPageTable: 0x%X\n", HalPageTable
);
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;
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;
574 //VideoMemoryBase = MmMapIoSpace(0xb8000, 4000, MmNonCached);
575 //DPRINTM(DPRINT_WINDOWS, "VideoMemoryBase: 0x%X\n", VideoMemoryBase);
577 Tss
= (PKTSS
)(KSEG0_BASE
| (TssBasePage
<< MM_PAGE_SHIFT
));
579 // Unmap what is not needed from kernel page table
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
);
589 ULONG
*PDE_Addr
=(ULONG
*)PDE
;//0xC0300000;
592 DPRINTM(DPRINT_WINDOWS
, "\nPDE\n");
594 for (i
=0; i
<128; i
++)
596 DPRINTM(DPRINT_WINDOWS
, "0x%04X | ", i
*8);
600 DPRINTM(DPRINT_WINDOWS
, "0x%08X ", PDE_Addr
[i
*8+j
]);
603 DPRINTM(DPRINT_WINDOWS
, "\n");
610 //BS->ExitBootServices(ImageHandle,MapKey);
612 // Disable Interrupts
615 // Re-initalize EFLAGS
619 __writecr3((ULONG_PTR
)PDE
);
621 // Enable paging by modifying CR0
622 __writecr0(__readcr0() | CR0_PG
);
624 // Set processor context
625 WinLdrSetProcessorContext(GdtIdt
, KIP0PCRADDRESS
, KSEG0_BASE
| (TssBasePage
<< MM_PAGE_SHIFT
));
627 // Zero KI_USER_SHARED_DATA page
628 memset((PVOID
)KI_USER_SHARED_DATA
, 0, MM_PAGE_SIZE
);
633 // Two special things this func does: it sorts descriptors,
634 // and it merges free ones
636 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
637 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
)
639 PLIST_ENTRY ListHead
= &LoaderBlock
->MemoryDescriptorListHead
;
640 PLIST_ENTRY PreviousEntry
, NextEntry
;
641 PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor
= NULL
, NextDescriptor
= NULL
;
643 DPRINTM(DPRINT_WINDOWS
, "BP=0x%X PC=0x%X %s\n", NewDescriptor
->BasePage
,
644 NewDescriptor
->PageCount
, MemTypeDesc
[NewDescriptor
->MemoryType
]);
646 /* Find a place where to insert the new descriptor to */
647 PreviousEntry
= ListHead
;
648 NextEntry
= ListHead
->Flink
;
649 while (NextEntry
!= ListHead
)
651 NextDescriptor
= CONTAINING_RECORD(NextEntry
,
652 MEMORY_ALLOCATION_DESCRIPTOR
,
654 if (NewDescriptor
->BasePage
< NextDescriptor
->BasePage
)
657 PreviousEntry
= NextEntry
;
658 PreviousDescriptor
= NextDescriptor
;
659 NextEntry
= NextEntry
->Flink
;
662 /* Don't forget about merging free areas */
663 if (NewDescriptor
->MemoryType
!= LoaderFree
)
665 /* Just insert, nothing to merge */
666 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
670 /* Previous block also free? */
671 if ((PreviousEntry
!= ListHead
) && (PreviousDescriptor
->MemoryType
== LoaderFree
) &&
672 ((PreviousDescriptor
->BasePage
+ PreviousDescriptor
->PageCount
) ==
673 NewDescriptor
->BasePage
))
675 /* Just enlarge previous descriptor's PageCount */
676 PreviousDescriptor
->PageCount
+= NewDescriptor
->PageCount
;
677 NewDescriptor
= PreviousDescriptor
;
681 /* Nope, just insert */
682 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
685 /* Next block is free ?*/
686 if ((NextEntry
!= ListHead
) &&
687 (NextDescriptor
->MemoryType
== LoaderFree
) &&
688 ((NewDescriptor
->BasePage
+ NewDescriptor
->PageCount
) == NextDescriptor
->BasePage
))
690 /* Enlarge next descriptor's PageCount */
691 NewDescriptor
->PageCount
+= NextDescriptor
->PageCount
;
692 RemoveEntryList(&NextDescriptor
->ListEntry
);
700 WinLdrSetProcessorContext(PVOID GdtIdt
, IN ULONG Pcr
, IN ULONG Tss
)
702 GDTIDT GdtDesc
, IdtDesc
, OldIdt
;
708 DPRINTM(DPRINT_WINDOWS
, "GDtIdt %p, Pcr %p, Tss 0x%08X\n",
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?
715 // Get old values of GDT and IDT
716 Ke386GetGlobalDescriptorTable(&GdtDesc
);
720 OldIdt
.Base
= IdtDesc
.Base
;
721 OldIdt
.Limit
= IdtDesc
.Limit
;
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;
729 // ========================
730 // Fill all descriptors now
731 // ========================
733 pGdt
= (PKGDTENTRY
)GdtDesc
.Base
;
734 pIdt
= (PKIDTENTRY
)IdtDesc
.Base
;
737 // Code selector (0x8)
740 pGdt
[1].LimitLow
= 0xFFFF;
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;
748 // Data selector (0x10)
751 pGdt
[2].LimitLow
= 0xFFFF;
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;
762 pGdt
[3].LimitLow
= 0xFFFF;
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;
773 pGdt
[4].LimitLow
= 0xFFFF;
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;
781 // TSS Selector (0x28)
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);
791 // PCR Selector (0x30)
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);
803 pGdt
[7].LimitLow
= 0xFFFF;
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;
811 // Some BIOS stuff (0x40)
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;
823 pGdt
[9].LimitLow
= 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;
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;
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;
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;
861 // Video buffer Selector (0x68)
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;
871 // Points to GDT (0x70)
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;
881 // Some unused descriptors should go here
885 RtlCopyMemory(pIdt
, (PVOID
)OldIdt
.Base
, OldIdt
.Limit
+ 1);
888 //asm("cli\n"); // they are already masked before enabling paged mode
891 Ke386SetGlobalDescriptorTable(&GdtDesc
);
894 // Jump to proper CS and clear prefetch queue
895 #if defined(__GNUC__)
896 asm("ljmp $0x08, $1f\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");
912 Ke386SetSs(0x10); // DataSelector=0x10
914 // Set DS and ES selectors
916 Ke386SetEs(0x10); // this is vital for rep stosd
918 // LDT = not used ever, thus set to 0
919 Ke386SetLocalDescriptorTable(Ldt
);
922 Ke386SetTr(KGDT_TSS
);
930 // Real end of the function, just for information