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 // this is needed for new IDT filling
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
101 /* GLOBALS ***************************************************************/
104 PHARDWARE_PTE HalPageTable
;
106 PUCHAR PhysicalPageTablesBuffer
;
107 PUCHAR KernelPageTablesBuffer
;
108 ULONG PhysicalPageTables
;
109 ULONG KernelPageTables
;
111 MEMORY_ALLOCATION_DESCRIPTOR
*Mad
;
115 /* FUNCTIONS **************************************************************/
118 MempAllocatePageTables()
120 ULONG NumPageTables
, TotalSize
;
122 // It's better to allocate PDE + PTEs contigiuos
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;
129 DPRINTM(DPRINT_WINDOWS
, "NumPageTables = %d\n", NumPageTables
);
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
;
135 // PDE+HAL+KernelPTEs == MemoryData
136 Buffer
= MmAllocateMemoryWithType(TotalSize
, LoaderMemoryData
);
138 // Physical PTEs = FirmwareTemporary
139 PhysicalPageTablesBuffer
= (PUCHAR
)Buffer
+ TotalSize
- NumPageTables
*MM_PAGE_SIZE
;
140 MmSetMemoryType(PhysicalPageTablesBuffer
,
141 NumPageTables
*MM_PAGE_SIZE
,
142 LoaderFirmwareTemporary
);
144 // This check is now redundant
145 if (Buffer
+ (TotalSize
- NumPageTables
*MM_PAGE_SIZE
) !=
146 PhysicalPageTablesBuffer
)
148 DPRINTM(DPRINT_WINDOWS
, "There was a problem allocating two adjacent blocks of memory!");
151 if (Buffer
== NULL
|| PhysicalPageTablesBuffer
== NULL
)
153 UiMessageBox("Impossible to allocate memory block for page tables!");
157 // Zero all this memory block
158 RtlZeroMemory(Buffer
, TotalSize
);
160 // Set up pointers correctly now
161 PDE
= (PHARDWARE_PTE
)Buffer
;
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;
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];
172 PDE
[1023].PageFrameNumber
= (ULONG
)HalPageTable
>> MM_PAGE_SHIFT
;
176 // Store pointer to the table for easier access
177 KernelPageTablesBuffer
= &Buffer
[MM_PAGE_SIZE
*2];
179 // Zero counters of page tables used
180 PhysicalPageTables
= 0;
181 KernelPageTables
= 0;
187 MempAllocatePTE(ULONG Entry
, PHARDWARE_PTE
*PhysicalPT
, PHARDWARE_PTE
*KernelPT
)
189 //Print(L"Creating PDE Entry %X\n", Entry);
192 *PhysicalPT
= (PHARDWARE_PTE
)&PhysicalPageTablesBuffer
[PhysicalPageTables
*MM_PAGE_SIZE
];
193 PhysicalPageTables
++;
195 PDE
[Entry
].PageFrameNumber
= (ULONG
)*PhysicalPT
>> MM_PAGE_SHIFT
;
196 PDE
[Entry
].Valid
= 1;
197 PDE
[Entry
].Write
= 1;
199 if (Entry
+(KSEG0_BASE
>> 22) > 1023)
201 DPRINTM(DPRINT_WINDOWS
, "WARNING! Entry: %X > 1023\n", Entry
+(KSEG0_BASE
>> 22));
204 // Kernel-mode mapping
205 *KernelPT
= (PHARDWARE_PTE
)&KernelPageTablesBuffer
[KernelPageTables
*MM_PAGE_SIZE
];
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;
214 MempSetupPaging(IN ULONG StartPage
,
215 IN ULONG NumberOfPages
)
217 PHARDWARE_PTE PhysicalPT
;
218 PHARDWARE_PTE KernelPT
;
221 //Print(L"MempSetupPaging: SP 0x%X, Number: 0x%X\n", StartPage, NumberOfPages);
224 if (StartPage
+NumberOfPages
>= 0x80000)
227 // We can't map this as it requires more than 1 PDE
228 // and in fact it's not possible at all ;)
230 //Print(L"skipping...\n");
235 // Now actually set up the page tables for identity mapping
237 for (Page
=StartPage
; Page
< StartPage
+NumberOfPages
; Page
++)
241 if (((PULONG
)PDE
)[Entry
] == 0)
243 MempAllocatePTE(Entry
, &PhysicalPT
, &KernelPT
);
247 PhysicalPT
= (PHARDWARE_PTE
)(PDE
[Entry
].PageFrameNumber
<< MM_PAGE_SHIFT
);
248 KernelPT
= (PHARDWARE_PTE
)(PDE
[Entry
+(KSEG0_BASE
>> 22)].PageFrameNumber
<< MM_PAGE_SHIFT
);
253 PhysicalPT
[Page
& 0x3ff].PageFrameNumber
= Page
;
254 PhysicalPT
[Page
& 0x3ff].Valid
= 0;
255 PhysicalPT
[Page
& 0x3ff].Write
= 0;
257 KernelPT
[Page
& 0x3ff].PageFrameNumber
= Page
;
258 KernelPT
[Page
& 0x3ff].Valid
= 0;
259 KernelPT
[Page
& 0x3ff].Write
= 0;
263 PhysicalPT
[Page
& 0x3ff].PageFrameNumber
= Page
;
264 PhysicalPT
[Page
& 0x3ff].Valid
= 1;
265 PhysicalPT
[Page
& 0x3ff].Write
= 1;
267 KernelPT
[Page
& 0x3ff].PageFrameNumber
= Page
;
268 KernelPT
[Page
& 0x3ff].Valid
= 1;
269 KernelPT
[Page
& 0x3ff].Write
= 1;
282 // We need to delete kernel mapping from memory areas which are
283 // marked as Special or Permanent memory (thus non-accessible)
286 for (i
=0; i
<MadCount
; i
++)
288 ULONG StartPage
, EndPage
, Page
;
290 StartPage
= Mad
[i
].BasePage
;
291 EndPage
= Mad
[i
].BasePage
+ Mad
[i
].PageCount
;
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
)
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
)
307 if (StartPage
< 0x100)
310 if (EndPage
> LoaderPagesSpanned
)
311 EndPage
= LoaderPagesSpanned
;
314 for (Page
= StartPage
; Page
< EndPage
; Page
++)
316 PHARDWARE_PTE KernelPT
;
317 ULONG Entry
= (Page
>> 10) + (KSEG0_BASE
>> 22);
319 if (PDE
[Entry
].Valid
)
321 KernelPT
= (PHARDWARE_PTE
)(PDE
[Entry
].PageFrameNumber
<< MM_PAGE_SHIFT
);
325 KernelPT
[Page
& 0x3ff].PageFrameNumber
= 0;
326 KernelPT
[Page
& 0x3ff].Valid
= 0;
327 KernelPT
[Page
& 0x3ff].Write
= 0;
336 MempAddMemoryBlock(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
344 // Check for some weird stuff at the top
346 if (BasePage
+ PageCount
> 0xF0000)
349 // Just skip this, without even adding to MAD list
355 // Set Base page, page count and type
357 Mad
[MadCount
].BasePage
= BasePage
;
358 Mad
[MadCount
].PageCount
= PageCount
;
359 Mad
[MadCount
].MemoryType
= Type
;
362 // Check if it's more than the allowed for OS loader
363 // if yes - don't map the pages, just add as FirmwareTemporary
365 if (BasePage
+ PageCount
> LoaderPagesSpanned
)
367 if (Mad
[MadCount
].MemoryType
!= LoaderSpecialMemory
&&
368 Mad
[MadCount
].MemoryType
!= LoaderFirmwarePermanent
&&
369 Mad
[MadCount
].MemoryType
!= LoaderFree
)
371 DPRINTM(DPRINT_WINDOWS
, "Setting page %x %x to Temporary from %d\n",
372 BasePage
, PageCount
, Mad
[MadCount
].MemoryType
);
373 Mad
[MadCount
].MemoryType
= LoaderFirmwareTemporary
;
376 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
385 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
389 // Map it (don't map low 1Mb because it was already contigiously
390 // mapped in WinLdrTurnOnPaging)
392 if (BasePage
>= 0x100)
394 Status
= MempSetupPaging(BasePage
, PageCount
);
397 DPRINTM(DPRINT_WINDOWS
, "Error during MempSetupPaging\n");
408 LARGE_INTEGER MsrValue
;
409 ULONG APICAddress
, CpuInfo
[4];
411 /* Check if we have a local APIC */
412 __cpuid((int*)CpuInfo
, 1);
413 LocalAPIC
= (((CpuInfo
[3] >> 9) & 1) != 0);
415 /* If there is no APIC, just return */
419 /* Read the APIC Address */
420 MsrValue
.QuadPart
= __readmsr(0x1B);
421 APICAddress
= (MsrValue
.LowPart
& 0xFFFFF000);
423 DPRINTM(DPRINT_WINDOWS
, "Local APIC detected at address 0x%x\n",
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;
438 /* Implement it for another arch */
443 WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
448 ULONG i
, PagesCount
, MemoryMapSizeInPages
;
449 ULONG LastPageIndex
, LastPageType
, MemoryMapStartPage
;
450 PPAGE_LOOKUP_TABLE_ITEM MemoryMap
;
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
466 // 3) Overall memory blocks count must not exceed 30 (?? why?)
470 // During MmInitMachineDependent, the kernel zeroes PDE at the following address
471 // 0xC0300000 - 0xC03007FC
473 // Then it finds the best place for non-paged pool:
474 // StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD
477 // Before we start mapping pages, create a block of memory, which will contain
479 if (MempAllocatePageTables() == FALSE
)
482 // Allocate memory for memory allocation descriptors
483 Mad
= MmHeapAlloc(sizeof(MEMORY_ALLOCATION_DESCRIPTOR
) * 1024);
485 // Setup an entry for each descriptor
486 MemoryMap
= MmGetMemoryMap(&NoEntries
);
487 if (MemoryMap
== NULL
)
489 UiMessageBox("Can not retrieve the current memory map");
493 // Calculate parameters of the memory map
494 MemoryMapStartPage
= (ULONG_PTR
)MemoryMap
>> MM_PAGE_SHIFT
;
495 MemoryMapSizeInPages
= NoEntries
* sizeof(PAGE_LOOKUP_TABLE_ITEM
);
497 DPRINTM(DPRINT_WINDOWS
, "Got memory map with %d entries\n", NoEntries
);
499 // Always contigiously map low 1Mb of memory
500 Status
= MempSetupPaging(0, 0x100);
503 DPRINTM(DPRINT_WINDOWS
, "Error during MempSetupPaging of low 1Mb\n");
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)
513 LastPageType
= MemoryMap
[0].PageAllocated
;
514 for(i
=1;i
<NoEntries
;i
++)
516 // Check if its memory map itself
517 if (i
>= MemoryMapStartPage
&&
518 i
< (MemoryMapStartPage
+MemoryMapSizeInPages
))
520 // Exclude it if current page belongs to the memory map
521 MemoryMap
[i
].PageAllocated
= LoaderFree
;
525 if (MemoryMap
[i
].PageAllocated
== LastPageType
&&
532 // Add the resulting region
533 MempAddMemoryBlock(LoaderBlock
, LastPageIndex
, PagesCount
, LastPageType
);
535 // Reset our counter vars
537 LastPageType
= MemoryMap
[i
].PageAllocated
;
543 // adding special reserved memory zones for vmware workstation
546 Mad
[MadCount
].BasePage
= 0xfec00;
547 Mad
[MadCount
].PageCount
= 0x10;
548 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
549 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
552 Mad
[MadCount
].BasePage
= 0xfee00;
553 Mad
[MadCount
].PageCount
= 0x1;
554 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
555 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
558 Mad
[MadCount
].BasePage
= 0xfffe0;
559 Mad
[MadCount
].PageCount
= 0x20;
560 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
561 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
566 DPRINTM(DPRINT_WINDOWS
, "MadCount: %d\n", MadCount
);
568 WinLdrpDumpMemoryDescriptors(LoaderBlock
); //FIXME: Delete!
570 // Map our loader image, so we can continue running
571 /*Status = MempSetupPaging(OsLoaderBase >> MM_PAGE_SHIFT, OsLoaderSize >> MM_PAGE_SHIFT);
574 UiMessageBox("Error during MempSetupPaging");
578 //VideoDisplayString(L"Hello from VGA, going into the kernel\n");
579 DPRINTM(DPRINT_WINDOWS
, "HalPageTable: 0x%X\n", HalPageTable
);
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;
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;
595 //VideoMemoryBase = MmMapIoSpace(0xb8000, 4000, MmNonCached);
596 //DPRINTM(DPRINT_WINDOWS, "VideoMemoryBase: 0x%X\n", VideoMemoryBase);
598 Tss
= (PKTSS
)(KSEG0_BASE
| (TssBasePage
<< MM_PAGE_SHIFT
));
600 // Unmap what is not needed from kernel page table
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
);
610 ULONG
*PDE_Addr
=(ULONG
*)PDE
;//0xC0300000;
613 DPRINTM(DPRINT_WINDOWS
, "\nPDE\n");
615 for (i
=0; i
<128; i
++)
617 DPRINTM(DPRINT_WINDOWS
, "0x%04X | ", i
*8);
621 DPRINTM(DPRINT_WINDOWS
, "0x%08X ", PDE_Addr
[i
*8+j
]);
624 DPRINTM(DPRINT_WINDOWS
, "\n");
631 //BS->ExitBootServices(ImageHandle,MapKey);
633 // Disable Interrupts
636 // Re-initalize EFLAGS
640 __writecr3((ULONG_PTR
)PDE
);
642 // Enable paging by modifying CR0
643 __writecr0(__readcr0() | CR0_PG
);
645 // Set processor context
646 WinLdrSetProcessorContext(GdtIdt
, KIP0PCRADDRESS
, KSEG0_BASE
| (TssBasePage
<< MM_PAGE_SHIFT
));
648 // Zero KI_USER_SHARED_DATA page
649 memset((PVOID
)KI_USER_SHARED_DATA
, 0, MM_PAGE_SIZE
);
654 // Two special things this func does: it sorts descriptors,
655 // and it merges free ones
657 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
658 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
)
660 PLIST_ENTRY ListHead
= &LoaderBlock
->MemoryDescriptorListHead
;
661 PLIST_ENTRY PreviousEntry
, NextEntry
;
662 PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor
= NULL
, NextDescriptor
= NULL
;
664 DPRINTM(DPRINT_WINDOWS
, "BP=0x%X PC=0x%X %s\n", NewDescriptor
->BasePage
,
665 NewDescriptor
->PageCount
, MemTypeDesc
[NewDescriptor
->MemoryType
]);
667 /* Find a place where to insert the new descriptor to */
668 PreviousEntry
= ListHead
;
669 NextEntry
= ListHead
->Flink
;
670 while (NextEntry
!= ListHead
)
672 NextDescriptor
= CONTAINING_RECORD(NextEntry
,
673 MEMORY_ALLOCATION_DESCRIPTOR
,
675 if (NewDescriptor
->BasePage
< NextDescriptor
->BasePage
)
678 PreviousEntry
= NextEntry
;
679 PreviousDescriptor
= NextDescriptor
;
680 NextEntry
= NextEntry
->Flink
;
683 /* Don't forget about merging free areas */
684 if (NewDescriptor
->MemoryType
!= LoaderFree
)
686 /* Just insert, nothing to merge */
687 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
691 /* Previous block also free? */
692 if ((PreviousEntry
!= ListHead
) && (PreviousDescriptor
->MemoryType
== LoaderFree
) &&
693 ((PreviousDescriptor
->BasePage
+ PreviousDescriptor
->PageCount
) ==
694 NewDescriptor
->BasePage
))
696 /* Just enlarge previous descriptor's PageCount */
697 PreviousDescriptor
->PageCount
+= NewDescriptor
->PageCount
;
698 NewDescriptor
= PreviousDescriptor
;
702 /* Nope, just insert */
703 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
706 /* Next block is free ?*/
707 if ((NextEntry
!= ListHead
) &&
708 (NextDescriptor
->MemoryType
== LoaderFree
) &&
709 ((NewDescriptor
->BasePage
+ NewDescriptor
->PageCount
) == NextDescriptor
->BasePage
))
711 /* Enlarge next descriptor's PageCount */
712 NewDescriptor
->PageCount
+= NextDescriptor
->PageCount
;
713 RemoveEntryList(&NextDescriptor
->ListEntry
);
721 WinLdrSetProcessorContext(PVOID GdtIdt
, IN ULONG Pcr
, IN ULONG Tss
)
723 GDTIDT GdtDesc
, IdtDesc
, OldIdt
;
729 DPRINTM(DPRINT_WINDOWS
, "GDtIdt %p, Pcr %p, Tss 0x%08X\n",
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?
736 // Get old values of GDT and IDT
737 Ke386GetGlobalDescriptorTable(&GdtDesc
);
741 OldIdt
.Base
= IdtDesc
.Base
;
742 OldIdt
.Limit
= IdtDesc
.Limit
;
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;
750 // ========================
751 // Fill all descriptors now
752 // ========================
754 pGdt
= (PKGDTENTRY
)GdtDesc
.Base
;
755 pIdt
= (PKIDTENTRY
)IdtDesc
.Base
;
758 // Code selector (0x8)
761 pGdt
[1].LimitLow
= 0xFFFF;
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;
769 // Data selector (0x10)
772 pGdt
[2].LimitLow
= 0xFFFF;
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;
783 pGdt
[3].LimitLow
= 0xFFFF;
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;
794 pGdt
[4].LimitLow
= 0xFFFF;
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;
802 // TSS Selector (0x28)
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);
812 // PCR Selector (0x30)
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);
824 pGdt
[7].LimitLow
= 0xFFFF;
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;
832 // Some BIOS stuff (0x40)
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;
844 pGdt
[9].LimitLow
= 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;
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;
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;
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;
882 // Video buffer Selector (0x68)
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;
892 // Points to GDT (0x70)
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;
902 // Some unused descriptors should go here
906 RtlCopyMemory(pIdt
, (PVOID
)OldIdt
.Base
, OldIdt
.Limit
+ 1);
909 //asm("cli\n"); // they are already masked before enabling paged mode
912 Ke386SetGlobalDescriptorTable(&GdtDesc
);
915 // Jump to proper CS and clear prefetch queue
916 #if defined(__GNUC__)
917 asm("ljmp $0x08, $1f\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");
933 Ke386SetSs(0x10); // DataSelector=0x10
935 // Set DS and ES selectors
937 Ke386SetEs(0x10); // this is vital for rep stosd
939 // LDT = not used ever, thus set to 0
940 Ke386SetLocalDescriptorTable(Ldt
);
951 // Real end of the function, just for information