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");
405 BOOLEAN LocalAPIC
= FALSE
;
406 ULONG_PTR APICAddress
= 0;
411 /* Check if we have a local APIC */
412 asm(".intel_syntax noprefix\n");
416 asm("and edx, 0x1\n");
417 asm("mov _LocalAPIC, edx\n");
418 asm(".att_syntax\n");
420 /* If there is no APIC, just return */
424 asm(".intel_syntax noprefix\n");
425 asm("mov ecx, 0x1B\n");
427 asm("mov edx, eax\n");
428 asm("and edx, 0xFFFFF000\n");
429 asm("mov _APICAddress, edx");
430 asm(".att_syntax\n");
432 DPRINTM(DPRINT_WINDOWS
, "Local APIC detected at address 0x%x\n",
436 HalPageTable
[(APIC_BASE
- 0xFFC00000) >> MM_PAGE_SHIFT
].PageFrameNumber
437 = APICAddress
>> MM_PAGE_SHIFT
;
438 HalPageTable
[(APIC_BASE
- 0xFFC00000) >> MM_PAGE_SHIFT
].Valid
= 1;
439 HalPageTable
[(APIC_BASE
- 0xFFC00000) >> MM_PAGE_SHIFT
].Write
= 1;
440 HalPageTable
[(APIC_BASE
- 0xFFC00000) >> MM_PAGE_SHIFT
].WriteThrough
= 1;
441 HalPageTable
[(APIC_BASE
- 0xFFC00000) >> MM_PAGE_SHIFT
].CacheDisable
= 1;
447 /* Implement it for another arch */
452 WinLdrTurnOnPaging(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
457 ULONG i
, PagesCount
, MemoryMapSizeInPages
;
458 ULONG LastPageIndex
, LastPageType
, MemoryMapStartPage
;
459 PPAGE_LOOKUP_TABLE_ITEM MemoryMap
;
465 // Creating a suitable memory map for the Windows can be tricky, so let's
466 // give a few advices:
467 // 1) One must not map the whole available memory pages to PDE!
468 // Map only what's needed - 16Mb, 24Mb, 32Mb max I think,
469 // thus occupying 4, 6 or 8 PDE entries for identical mapping,
470 // the same quantity for KSEG0_BASE mapping, one more entry for
471 // hyperspace and one more entry for HAL physical pages mapping.
472 // 2) Memory descriptors must map *the whole* physical memory
473 // showing any memory above 16/24/32 as FirmwareTemporary
475 // 3) Overall memory blocks count must not exceed 30 (?? why?)
479 // During MmInitMachineDependent, the kernel zeroes PDE at the following address
480 // 0xC0300000 - 0xC03007FC
482 // Then it finds the best place for non-paged pool:
483 // StartPde C0300F70, EndPde C0300FF8, NumberOfPages C13, NextPhysPage 3AD
486 // Before we start mapping pages, create a block of memory, which will contain
488 if (MempAllocatePageTables() == FALSE
)
491 // Allocate memory for memory allocation descriptors
492 Mad
= MmHeapAlloc(sizeof(MEMORY_ALLOCATION_DESCRIPTOR
) * 1024);
494 // Setup an entry for each descriptor
495 MemoryMap
= MmGetMemoryMap(&NoEntries
);
496 if (MemoryMap
== NULL
)
498 UiMessageBox("Can not retrieve the current memory map");
502 // Calculate parameters of the memory map
503 MemoryMapStartPage
= (ULONG_PTR
)MemoryMap
>> MM_PAGE_SHIFT
;
504 MemoryMapSizeInPages
= NoEntries
* sizeof(PAGE_LOOKUP_TABLE_ITEM
);
506 DPRINTM(DPRINT_WINDOWS
, "Got memory map with %d entries\n", NoEntries
);
508 // Always contigiously map low 1Mb of memory
509 Status
= MempSetupPaging(0, 0x100);
512 DPRINTM(DPRINT_WINDOWS
, "Error during MempSetupPaging of low 1Mb\n");
516 // Construct a good memory map from what we've got,
517 // but mark entries which the memory allocation bitmap takes
518 // as free entries (this is done in order to have the ability
519 // to place mem alloc bitmap outside lower 16Mb zone)
522 LastPageType
= MemoryMap
[0].PageAllocated
;
523 for(i
=1;i
<NoEntries
;i
++)
525 // Check if its memory map itself
526 if (i
>= MemoryMapStartPage
&&
527 i
< (MemoryMapStartPage
+MemoryMapSizeInPages
))
529 // Exclude it if current page belongs to the memory map
530 MemoryMap
[i
].PageAllocated
= LoaderFree
;
534 if (MemoryMap
[i
].PageAllocated
== LastPageType
&&
541 // Add the resulting region
542 MempAddMemoryBlock(LoaderBlock
, LastPageIndex
, PagesCount
, LastPageType
);
544 // Reset our counter vars
546 LastPageType
= MemoryMap
[i
].PageAllocated
;
552 // adding special reserved memory zones for vmware workstation
555 Mad
[MadCount
].BasePage
= 0xfec00;
556 Mad
[MadCount
].PageCount
= 0x10;
557 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
558 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
561 Mad
[MadCount
].BasePage
= 0xfee00;
562 Mad
[MadCount
].PageCount
= 0x1;
563 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
564 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
567 Mad
[MadCount
].BasePage
= 0xfffe0;
568 Mad
[MadCount
].PageCount
= 0x20;
569 Mad
[MadCount
].MemoryType
= LoaderSpecialMemory
;
570 WinLdrInsertDescriptor(LoaderBlock
, &Mad
[MadCount
]);
575 DPRINTM(DPRINT_WINDOWS
, "MadCount: %d\n", MadCount
);
577 WinLdrpDumpMemoryDescriptors(LoaderBlock
); //FIXME: Delete!
579 // Map our loader image, so we can continue running
580 /*Status = MempSetupPaging(OsLoaderBase >> MM_PAGE_SHIFT, OsLoaderSize >> MM_PAGE_SHIFT);
583 UiMessageBox("Error during MempSetupPaging");
587 //VideoDisplayString(L"Hello from VGA, going into the kernel\n");
588 DPRINTM(DPRINT_WINDOWS
, "HalPageTable: 0x%X\n", HalPageTable
);
590 // Page Tables have been setup, make special handling for PCR and TSS
591 // (which is done in BlSetupFotNt in usual ntldr)
592 HalPageTable
[(KI_USER_SHARED_DATA
- 0xFFC00000) >> MM_PAGE_SHIFT
].PageFrameNumber
= PcrBasePage
+1;
593 HalPageTable
[(KI_USER_SHARED_DATA
- 0xFFC00000) >> MM_PAGE_SHIFT
].Valid
= 1;
594 HalPageTable
[(KI_USER_SHARED_DATA
- 0xFFC00000) >> MM_PAGE_SHIFT
].Write
= 1;
596 HalPageTable
[(KIP0PCRADDRESS
- 0xFFC00000) >> MM_PAGE_SHIFT
].PageFrameNumber
= PcrBasePage
;
597 HalPageTable
[(KIP0PCRADDRESS
- 0xFFC00000) >> MM_PAGE_SHIFT
].Valid
= 1;
598 HalPageTable
[(KIP0PCRADDRESS
- 0xFFC00000) >> MM_PAGE_SHIFT
].Write
= 1;
604 //VideoMemoryBase = MmMapIoSpace(0xb8000, 4000, MmNonCached);
605 //DPRINTM(DPRINT_WINDOWS, "VideoMemoryBase: 0x%X\n", VideoMemoryBase);
607 Tss
= (PKTSS
)(KSEG0_BASE
| (TssBasePage
<< MM_PAGE_SHIFT
));
609 // Unmap what is not needed from kernel page table
612 // Fill the memory descriptor list and
613 //PrepareMemoryDescriptorList();
614 DPRINTM(DPRINT_WINDOWS
, "Memory Descriptor List prepared, printing PDE\n");
615 List_PaToVa(&LoaderBlock
->MemoryDescriptorListHead
);
619 ULONG
*PDE_Addr
=(ULONG
*)PDE
;//0xC0300000;
622 DPRINTM(DPRINT_WINDOWS
, "\nPDE\n");
624 for (i
=0; i
<128; i
++)
626 DPRINTM(DPRINT_WINDOWS
, "0x%04X | ", i
*8);
630 DPRINTM(DPRINT_WINDOWS
, "0x%08X ", PDE_Addr
[i
*8+j
]);
633 DPRINTM(DPRINT_WINDOWS
, "\n");
640 //BS->ExitBootServices(ImageHandle,MapKey);
642 // Disable Interrupts
645 // Re-initalize EFLAGS
649 __writecr3((ULONG_PTR
)PDE
);
651 // Enable paging by modifying CR0
652 __writecr0(__readcr0() | CR0_PG
);
654 // Set processor context
655 WinLdrSetProcessorContext(GdtIdt
, KIP0PCRADDRESS
, KSEG0_BASE
| (TssBasePage
<< MM_PAGE_SHIFT
));
657 // Zero KI_USER_SHARED_DATA page
658 memset((PVOID
)KI_USER_SHARED_DATA
, 0, MM_PAGE_SIZE
);
663 // Two special things this func does: it sorts descriptors,
664 // and it merges free ones
666 WinLdrInsertDescriptor(IN OUT PLOADER_PARAMETER_BLOCK LoaderBlock
,
667 IN PMEMORY_ALLOCATION_DESCRIPTOR NewDescriptor
)
669 PLIST_ENTRY ListHead
= &LoaderBlock
->MemoryDescriptorListHead
;
670 PLIST_ENTRY PreviousEntry
, NextEntry
;
671 PMEMORY_ALLOCATION_DESCRIPTOR PreviousDescriptor
= NULL
, NextDescriptor
= NULL
;
673 DPRINTM(DPRINT_WINDOWS
, "BP=0x%X PC=0x%X %s\n", NewDescriptor
->BasePage
,
674 NewDescriptor
->PageCount
, MemTypeDesc
[NewDescriptor
->MemoryType
]);
676 /* Find a place where to insert the new descriptor to */
677 PreviousEntry
= ListHead
;
678 NextEntry
= ListHead
->Flink
;
679 while (NextEntry
!= ListHead
)
681 NextDescriptor
= CONTAINING_RECORD(NextEntry
,
682 MEMORY_ALLOCATION_DESCRIPTOR
,
684 if (NewDescriptor
->BasePage
< NextDescriptor
->BasePage
)
687 PreviousEntry
= NextEntry
;
688 PreviousDescriptor
= NextDescriptor
;
689 NextEntry
= NextEntry
->Flink
;
692 /* Don't forget about merging free areas */
693 if (NewDescriptor
->MemoryType
!= LoaderFree
)
695 /* Just insert, nothing to merge */
696 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
700 /* Previous block also free? */
701 if ((PreviousEntry
!= ListHead
) && (PreviousDescriptor
->MemoryType
== LoaderFree
) &&
702 ((PreviousDescriptor
->BasePage
+ PreviousDescriptor
->PageCount
) ==
703 NewDescriptor
->BasePage
))
705 /* Just enlarge previous descriptor's PageCount */
706 PreviousDescriptor
->PageCount
+= NewDescriptor
->PageCount
;
707 NewDescriptor
= PreviousDescriptor
;
711 /* Nope, just insert */
712 InsertHeadList(PreviousEntry
, &NewDescriptor
->ListEntry
);
715 /* Next block is free ?*/
716 if ((NextEntry
!= ListHead
) &&
717 (NextDescriptor
->MemoryType
== LoaderFree
) &&
718 ((NewDescriptor
->BasePage
+ NewDescriptor
->PageCount
) == NextDescriptor
->BasePage
))
720 /* Enlarge next descriptor's PageCount */
721 NewDescriptor
->PageCount
+= NextDescriptor
->PageCount
;
722 RemoveEntryList(&NextDescriptor
->ListEntry
);
730 WinLdrSetProcessorContext(PVOID GdtIdt
, IN ULONG Pcr
, IN ULONG Tss
)
732 GDTIDT GdtDesc
, IdtDesc
, OldIdt
;
738 DPRINTM(DPRINT_WINDOWS
, "GDtIdt %p, Pcr %p, Tss 0x%08X\n",
741 // Kernel expects the PCR to be zero-filled on startup
742 // FIXME: Why zero it here when we can zero it right after allocation?
743 RtlZeroMemory((PVOID
)Pcr
, MM_PAGE_SIZE
); //FIXME: Why zero only 1 page when we allocate 2?
745 // Get old values of GDT and IDT
746 Ke386GetGlobalDescriptorTable(GdtDesc
);
747 Ke386GetInterruptDescriptorTable(IdtDesc
);
750 OldIdt
.Base
= IdtDesc
.Base
;
751 OldIdt
.Limit
= IdtDesc
.Limit
;
753 // Prepare new IDT+GDT
754 GdtDesc
.Base
= KSEG0_BASE
| (ULONG_PTR
)GdtIdt
;
755 GdtDesc
.Limit
= NUM_GDT
* sizeof(KGDTENTRY
) - 1;
756 IdtDesc
.Base
= (ULONG
)((PUCHAR
)GdtDesc
.Base
+ GdtDesc
.Limit
+ 1);
757 IdtDesc
.Limit
= NUM_IDT
* sizeof(KIDTENTRY
) - 1;
759 // ========================
760 // Fill all descriptors now
761 // ========================
763 pGdt
= (PKGDTENTRY
)GdtDesc
.Base
;
764 pIdt
= (PKIDTENTRY
)IdtDesc
.Base
;
767 // Code selector (0x8)
770 pGdt
[1].LimitLow
= 0xFFFF;
772 pGdt
[1].HighWord
.Bytes
.BaseMid
= 0;
773 pGdt
[1].HighWord
.Bytes
.Flags1
= 0x9A;
774 pGdt
[1].HighWord
.Bytes
.Flags2
= 0xCF;
775 pGdt
[1].HighWord
.Bytes
.BaseHi
= 0;
778 // Data selector (0x10)
781 pGdt
[2].LimitLow
= 0xFFFF;
783 pGdt
[2].HighWord
.Bytes
.BaseMid
= 0;
784 pGdt
[2].HighWord
.Bytes
.Flags1
= 0x92;
785 pGdt
[2].HighWord
.Bytes
.Flags2
= 0xCF;
786 pGdt
[2].HighWord
.Bytes
.BaseHi
= 0;
792 pGdt
[3].LimitLow
= 0xFFFF;
794 pGdt
[3].HighWord
.Bytes
.BaseMid
= 0;
795 pGdt
[3].HighWord
.Bytes
.Flags1
= 0xFA;
796 pGdt
[3].HighWord
.Bytes
.Flags2
= 0xCF;
797 pGdt
[3].HighWord
.Bytes
.BaseHi
= 0;
803 pGdt
[4].LimitLow
= 0xFFFF;
805 pGdt
[4].HighWord
.Bytes
.BaseMid
= 0;
806 pGdt
[4].HighWord
.Bytes
.Flags1
= 0xF2;
807 pGdt
[4].HighWord
.Bytes
.Flags2
= 0xCF;
808 pGdt
[4].HighWord
.Bytes
.BaseHi
= 0;
811 // TSS Selector (0x28)
813 pGdt
[5].LimitLow
= 0x78-1; //FIXME: Check this
814 pGdt
[5].BaseLow
= (USHORT
)(Tss
& 0xffff);
815 pGdt
[5].HighWord
.Bytes
.BaseMid
= (UCHAR
)((Tss
>> 16) & 0xff);
816 pGdt
[5].HighWord
.Bytes
.Flags1
= 0x89;
817 pGdt
[5].HighWord
.Bytes
.Flags2
= 0x00;
818 pGdt
[5].HighWord
.Bytes
.BaseHi
= (UCHAR
)((Tss
>> 24) & 0xff);
821 // PCR Selector (0x30)
823 pGdt
[6].LimitLow
= 0x01;
824 pGdt
[6].BaseLow
= (USHORT
)(Pcr
& 0xffff);
825 pGdt
[6].HighWord
.Bytes
.BaseMid
= (UCHAR
)((Pcr
>> 16) & 0xff);
826 pGdt
[6].HighWord
.Bytes
.Flags1
= 0x92;
827 pGdt
[6].HighWord
.Bytes
.Flags2
= 0xC0;
828 pGdt
[6].HighWord
.Bytes
.BaseHi
= (UCHAR
)((Pcr
>> 24) & 0xff);
833 pGdt
[7].LimitLow
= 0xFFFF;
835 pGdt
[7].HighWord
.Bytes
.BaseMid
= 0;
836 pGdt
[7].HighWord
.Bytes
.Flags1
= 0xF3;
837 pGdt
[7].HighWord
.Bytes
.Flags2
= 0x40;
838 pGdt
[7].HighWord
.Bytes
.BaseHi
= 0;
841 // Some BIOS stuff (0x40)
843 pGdt
[8].LimitLow
= 0xFFFF;
844 pGdt
[8].BaseLow
= 0x400;
845 pGdt
[8].HighWord
.Bytes
.BaseMid
= 0;
846 pGdt
[8].HighWord
.Bytes
.Flags1
= 0xF2;
847 pGdt
[8].HighWord
.Bytes
.Flags2
= 0x0;
848 pGdt
[8].HighWord
.Bytes
.BaseHi
= 0;
853 pGdt
[9].LimitLow
= 0;
855 pGdt
[9].HighWord
.Bytes
.BaseMid
= 0;
856 pGdt
[9].HighWord
.Bytes
.Flags1
= 0;
857 pGdt
[9].HighWord
.Bytes
.Flags2
= 0;
858 pGdt
[9].HighWord
.Bytes
.BaseHi
= 0;
863 pGdt
[10].LimitLow
= 0xFFFF; //FIXME: Not correct!
864 pGdt
[10].BaseLow
= 0;
865 pGdt
[10].HighWord
.Bytes
.BaseMid
= 0x2;
866 pGdt
[10].HighWord
.Bytes
.Flags1
= 0x89;
867 pGdt
[10].HighWord
.Bytes
.Flags2
= 0;
868 pGdt
[10].HighWord
.Bytes
.BaseHi
= 0;
873 pGdt
[11].LimitLow
= 0xFFFF;
874 pGdt
[11].BaseLow
= 0;
875 pGdt
[11].HighWord
.Bytes
.BaseMid
= 0x2;
876 pGdt
[11].HighWord
.Bytes
.Flags1
= 0x9A;
877 pGdt
[11].HighWord
.Bytes
.Flags2
= 0;
878 pGdt
[11].HighWord
.Bytes
.BaseHi
= 0;
883 pGdt
[12].LimitLow
= 0xFFFF;
884 pGdt
[12].BaseLow
= 0; //FIXME: Maybe not correct, but noone cares
885 pGdt
[12].HighWord
.Bytes
.BaseMid
= 0x2;
886 pGdt
[12].HighWord
.Bytes
.Flags1
= 0x92;
887 pGdt
[12].HighWord
.Bytes
.Flags2
= 0;
888 pGdt
[12].HighWord
.Bytes
.BaseHi
= 0;
891 // Video buffer Selector (0x68)
893 pGdt
[13].LimitLow
= 0x3FFF;
894 pGdt
[13].BaseLow
= 0x8000;
895 pGdt
[13].HighWord
.Bytes
.BaseMid
= 0x0B;
896 pGdt
[13].HighWord
.Bytes
.Flags1
= 0x92;
897 pGdt
[13].HighWord
.Bytes
.Flags2
= 0;
898 pGdt
[13].HighWord
.Bytes
.BaseHi
= 0;
901 // Points to GDT (0x70)
903 pGdt
[14].LimitLow
= NUM_GDT
*sizeof(KGDTENTRY
) - 1;
904 pGdt
[14].BaseLow
= 0x7000;
905 pGdt
[14].HighWord
.Bytes
.BaseMid
= 0xFF;
906 pGdt
[14].HighWord
.Bytes
.Flags1
= 0x92;
907 pGdt
[14].HighWord
.Bytes
.Flags2
= 0;
908 pGdt
[14].HighWord
.Bytes
.BaseHi
= 0xFF;
911 // Some unused descriptors should go here
915 RtlCopyMemory(pIdt
, (PVOID
)OldIdt
.Base
, OldIdt
.Limit
);
918 //asm("cli\n"); // they are already masked before enabling paged mode
921 Ke386SetGlobalDescriptorTable(GdtDesc
);
922 Ke386SetInterruptDescriptorTable(IdtDesc
);
924 // Jump to proper CS and clear prefetch queue
925 asm("ljmp $0x08, $mb1\n"
929 asm(".intel_syntax noprefix\n");
930 asm("mov ax, 0x10\n"); // DataSelector=0x10
932 asm(".att_syntax\n");
934 // Set DS and ES selectors
936 Ke386SetEs(0x10); // this is vital for rep stosd
938 // LDT = not used ever, thus set to 0
939 Ke386SetLocalDescriptorTable(Ldt
);
945 asm(".intel_syntax noprefix\n");
948 asm(".att_syntax\n");
953 // Real end of the function, just for information