2 * PROJECT: EFI Windows Loader
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: freeldr/winldr/i386/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 // This is needed only for SetProcessorContext routine
34 /* GLOBALS ***************************************************************/
37 PHARDWARE_PTE HalPageTable
;
39 PUCHAR PhysicalPageTablesBuffer
;
40 PUCHAR KernelPageTablesBuffer
;
41 ULONG PhysicalPageTables
;
42 ULONG KernelPageTables
;
44 /* FUNCTIONS **************************************************************/
47 MempAllocatePageTables()
49 ULONG NumPageTables
, TotalSize
;
51 // It's better to allocate PDE + PTEs contigiuos
53 // Max number of entries = MaxPageNum >> 10
54 // FIXME: This is a number to describe ALL physical memory
55 // and windows doesn't expect ALL memory mapped...
56 NumPageTables
= TotalPagesInLookupTable
>> 10;
58 DPRINTM(DPRINT_WINDOWS
, "NumPageTables = %d\n", NumPageTables
);
60 // Allocate memory block for all these things:
61 // PDE, HAL mapping page table, physical mapping, kernel mapping
62 TotalSize
= (1 + 1 + NumPageTables
* 2) * MM_PAGE_SIZE
;
64 // PDE+HAL+KernelPTEs == MemoryData
65 Buffer
= MmAllocateMemoryWithType(TotalSize
, LoaderMemoryData
);
67 // Physical PTEs = FirmwareTemporary
68 PhysicalPageTablesBuffer
= (PUCHAR
)Buffer
+ TotalSize
- NumPageTables
*MM_PAGE_SIZE
;
69 MmSetMemoryType(PhysicalPageTablesBuffer
,
70 NumPageTables
*MM_PAGE_SIZE
,
71 LoaderFirmwareTemporary
);
73 // This check is now redundant
74 if (Buffer
+ (TotalSize
- NumPageTables
*MM_PAGE_SIZE
) !=
75 PhysicalPageTablesBuffer
)
77 DPRINTM(DPRINT_WINDOWS
, "There was a problem allocating two adjacent blocks of memory!");
80 if (Buffer
== NULL
|| PhysicalPageTablesBuffer
== NULL
)
82 UiMessageBox("Impossible to allocate memory block for page tables!");
86 // Zero all this memory block
87 RtlZeroMemory(Buffer
, TotalSize
);
89 // Set up pointers correctly now
90 PDE
= (PHARDWARE_PTE
)Buffer
;
92 // Map the page directory at 0xC0000000 (maps itself)
93 PDE
[HYPER_SPACE_ENTRY
].PageFrameNumber
= (ULONG
)PDE
>> MM_PAGE_SHIFT
;
94 PDE
[HYPER_SPACE_ENTRY
].Valid
= 1;
95 PDE
[HYPER_SPACE_ENTRY
].Write
= 1;
97 // The last PDE slot is allocated for HAL's memory mapping (Virtual Addresses 0xFFC00000 - 0xFFFFFFFF)
98 HalPageTable
= (PHARDWARE_PTE
)&Buffer
[MM_PAGE_SIZE
*1];
101 PDE
[1023].PageFrameNumber
= (ULONG
)HalPageTable
>> MM_PAGE_SHIFT
;
105 // Store pointer to the table for easier access
106 KernelPageTablesBuffer
= &Buffer
[MM_PAGE_SIZE
*2];
108 // Zero counters of page tables used
109 PhysicalPageTables
= 0;
110 KernelPageTables
= 0;
116 MempAllocatePTE(ULONG Entry
, PHARDWARE_PTE
*PhysicalPT
, PHARDWARE_PTE
*KernelPT
)
118 //Print(L"Creating PDE Entry %X\n", Entry);
121 *PhysicalPT
= (PHARDWARE_PTE
)&PhysicalPageTablesBuffer
[PhysicalPageTables
*MM_PAGE_SIZE
];
122 PhysicalPageTables
++;
124 PDE
[Entry
].PageFrameNumber
= (ULONG
)*PhysicalPT
>> MM_PAGE_SHIFT
;
125 PDE
[Entry
].Valid
= 1;
126 PDE
[Entry
].Write
= 1;
128 if (Entry
+(KSEG0_BASE
>> 22) > 1023)
130 DPRINTM(DPRINT_WINDOWS
, "WARNING! Entry: %X > 1023\n", Entry
+(KSEG0_BASE
>> 22));
133 // Kernel-mode mapping
134 *KernelPT
= (PHARDWARE_PTE
)&KernelPageTablesBuffer
[KernelPageTables
*MM_PAGE_SIZE
];
137 PDE
[Entry
+(KSEG0_BASE
>> 22)].PageFrameNumber
= ((ULONG
)*KernelPT
>> MM_PAGE_SHIFT
);
138 PDE
[Entry
+(KSEG0_BASE
>> 22)].Valid
= 1;
139 PDE
[Entry
+(KSEG0_BASE
>> 22)].Write
= 1;
143 MempSetupPaging(IN ULONG StartPage
,
144 IN ULONG NumberOfPages
)
146 PHARDWARE_PTE PhysicalPT
;
147 PHARDWARE_PTE KernelPT
;
150 //Print(L"MempSetupPaging: SP 0x%X, Number: 0x%X\n", StartPage, NumberOfPages);
153 if (StartPage
+NumberOfPages
>= 0x80000)
156 // We can't map this as it requires more than 1 PDE
157 // and in fact it's not possible at all ;)
159 //Print(L"skipping...\n");
164 // Now actually set up the page tables for identity mapping
166 for (Page
= StartPage
; Page
< StartPage
+ NumberOfPages
; Page
++)
170 if (((PULONG
)PDE
)[Entry
] == 0)
172 MempAllocatePTE(Entry
, &PhysicalPT
, &KernelPT
);
176 PhysicalPT
= (PHARDWARE_PTE
)(PDE
[Entry
].PageFrameNumber
<< MM_PAGE_SHIFT
);
177 KernelPT
= (PHARDWARE_PTE
)(PDE
[Entry
+(KSEG0_BASE
>> 22)].PageFrameNumber
<< MM_PAGE_SHIFT
);
180 PhysicalPT
[Page
& 0x3ff].PageFrameNumber
= Page
;
181 PhysicalPT
[Page
& 0x3ff].Valid
= (Page
!= 0);
182 PhysicalPT
[Page
& 0x3ff].Write
= (Page
!= 0);
184 KernelPT
[Page
& 0x3ff].PageFrameNumber
= Page
;
185 KernelPT
[Page
& 0x3ff].Valid
= (Page
!= 0);
186 KernelPT
[Page
& 0x3ff].Write
= (Page
!= 0);
193 MempUnmapPage(ULONG Page
)
195 PHARDWARE_PTE KernelPT
;
196 ULONG Entry
= (Page
>> 10) + (KSEG0_BASE
>> 22);
198 /* Don't unmap hyperspace or HAL entries */
199 if (Entry
== HYPER_SPACE_ENTRY
|| Entry
== 1023)
202 if (PDE
[Entry
].Valid
)
204 KernelPT
= (PHARDWARE_PTE
)(PDE
[Entry
].PageFrameNumber
<< MM_PAGE_SHIFT
);
208 KernelPT
[Page
& 0x3ff].PageFrameNumber
= 0;
209 KernelPT
[Page
& 0x3ff].Valid
= 0;
210 KernelPT
[Page
& 0x3ff].Write
= 0;
219 LARGE_INTEGER MsrValue
;
220 ULONG APICAddress
, CpuInfo
[4];
222 /* Check if we have a local APIC */
223 __cpuid((int*)CpuInfo
, 1);
224 LocalAPIC
= (((CpuInfo
[3] >> 9) & 1) != 0);
226 /* If there is no APIC, just return */
230 /* Read the APIC Address */
231 MsrValue
.QuadPart
= __readmsr(0x1B);
232 APICAddress
= (MsrValue
.LowPart
& 0xFFFFF000);
234 DPRINTM(DPRINT_WINDOWS
, "Local APIC detected at address 0x%x\n",
238 HalPageTable
[(APIC_BASE
- 0xFFC00000) >> MM_PAGE_SHIFT
].PageFrameNumber
239 = APICAddress
>> MM_PAGE_SHIFT
;
240 HalPageTable
[(APIC_BASE
- 0xFFC00000) >> MM_PAGE_SHIFT
].Valid
= 1;
241 HalPageTable
[(APIC_BASE
- 0xFFC00000) >> MM_PAGE_SHIFT
].Write
= 1;
242 HalPageTable
[(APIC_BASE
- 0xFFC00000) >> MM_PAGE_SHIFT
].WriteThrough
= 1;
243 HalPageTable
[(APIC_BASE
- 0xFFC00000) >> MM_PAGE_SHIFT
].CacheDisable
= 1;
247 WinLdrMapSpecialPages(ULONG PcrBasePage
)
250 //VideoDisplayString(L"Hello from VGA, going into the kernel\n");
251 DPRINTM(DPRINT_WINDOWS
, "HalPageTable: 0x%X\n", HalPageTable
);
253 // Page Tables have been setup, make special handling for PCR and TSS
254 // (which is done in BlSetupFotNt in usual ntldr)
255 HalPageTable
[(KI_USER_SHARED_DATA
- 0xFFC00000) >> MM_PAGE_SHIFT
].PageFrameNumber
= PcrBasePage
+1;
256 HalPageTable
[(KI_USER_SHARED_DATA
- 0xFFC00000) >> MM_PAGE_SHIFT
].Valid
= 1;
257 HalPageTable
[(KI_USER_SHARED_DATA
- 0xFFC00000) >> MM_PAGE_SHIFT
].Write
= 1;
259 HalPageTable
[(KIP0PCRADDRESS
- 0xFFC00000) >> MM_PAGE_SHIFT
].PageFrameNumber
= PcrBasePage
;
260 HalPageTable
[(KIP0PCRADDRESS
- 0xFFC00000) >> MM_PAGE_SHIFT
].Valid
= 1;
261 HalPageTable
[(KIP0PCRADDRESS
- 0xFFC00000) >> MM_PAGE_SHIFT
].Write
= 1;
267 //VideoMemoryBase = MmMapIoSpace(0xb8000, 4000, MmNonCached);
268 //DPRINTM(DPRINT_WINDOWS, "VideoMemoryBase: 0x%X\n", VideoMemoryBase);
275 WinLdrSetProcessorContext(PVOID GdtIdt
, IN ULONG Pcr
, IN ULONG Tss
)
277 GDTIDT GdtDesc
, IdtDesc
, OldIdt
;
283 DPRINTM(DPRINT_WINDOWS
, "GDtIdt %p, Pcr %p, Tss 0x%08X\n",
287 //BS->ExitBootServices(ImageHandle,MapKey);
289 // Disable Interrupts
292 // Re-initalize EFLAGS
296 __writecr3((ULONG_PTR
)PDE
);
298 // Enable paging by modifying CR0
299 __writecr0(__readcr0() | CR0_PG
);
301 // Kernel expects the PCR to be zero-filled on startup
302 // FIXME: Why zero it here when we can zero it right after allocation?
303 RtlZeroMemory((PVOID
)Pcr
, MM_PAGE_SIZE
); //FIXME: Why zero only 1 page when we allocate 2?
305 // Get old values of GDT and IDT
306 Ke386GetGlobalDescriptorTable(&GdtDesc
);
310 OldIdt
.Base
= IdtDesc
.Base
;
311 OldIdt
.Limit
= IdtDesc
.Limit
;
313 // Prepare new IDT+GDT
314 GdtDesc
.Base
= KSEG0_BASE
| (ULONG_PTR
)GdtIdt
;
315 GdtDesc
.Limit
= NUM_GDT
* sizeof(KGDTENTRY
) - 1;
316 IdtDesc
.Base
= (ULONG
)((PUCHAR
)GdtDesc
.Base
+ GdtDesc
.Limit
+ 1);
317 IdtDesc
.Limit
= NUM_IDT
* sizeof(KIDTENTRY
) - 1;
319 // ========================
320 // Fill all descriptors now
321 // ========================
323 pGdt
= (PKGDTENTRY
)GdtDesc
.Base
;
324 pIdt
= (PKIDTENTRY
)IdtDesc
.Base
;
327 // Code selector (0x8)
330 pGdt
[1].LimitLow
= 0xFFFF;
332 pGdt
[1].HighWord
.Bytes
.BaseMid
= 0;
333 pGdt
[1].HighWord
.Bytes
.Flags1
= 0x9A;
334 pGdt
[1].HighWord
.Bytes
.Flags2
= 0xCF;
335 pGdt
[1].HighWord
.Bytes
.BaseHi
= 0;
338 // Data selector (0x10)
341 pGdt
[2].LimitLow
= 0xFFFF;
343 pGdt
[2].HighWord
.Bytes
.BaseMid
= 0;
344 pGdt
[2].HighWord
.Bytes
.Flags1
= 0x92;
345 pGdt
[2].HighWord
.Bytes
.Flags2
= 0xCF;
346 pGdt
[2].HighWord
.Bytes
.BaseHi
= 0;
352 pGdt
[3].LimitLow
= 0xFFFF;
354 pGdt
[3].HighWord
.Bytes
.BaseMid
= 0;
355 pGdt
[3].HighWord
.Bytes
.Flags1
= 0xFA;
356 pGdt
[3].HighWord
.Bytes
.Flags2
= 0xCF;
357 pGdt
[3].HighWord
.Bytes
.BaseHi
= 0;
363 pGdt
[4].LimitLow
= 0xFFFF;
365 pGdt
[4].HighWord
.Bytes
.BaseMid
= 0;
366 pGdt
[4].HighWord
.Bytes
.Flags1
= 0xF2;
367 pGdt
[4].HighWord
.Bytes
.Flags2
= 0xCF;
368 pGdt
[4].HighWord
.Bytes
.BaseHi
= 0;
371 // TSS Selector (0x28)
373 pGdt
[5].LimitLow
= 0x78-1; //FIXME: Check this
374 pGdt
[5].BaseLow
= (USHORT
)(Tss
& 0xffff);
375 pGdt
[5].HighWord
.Bytes
.BaseMid
= (UCHAR
)((Tss
>> 16) & 0xff);
376 pGdt
[5].HighWord
.Bytes
.Flags1
= 0x89;
377 pGdt
[5].HighWord
.Bytes
.Flags2
= 0x00;
378 pGdt
[5].HighWord
.Bytes
.BaseHi
= (UCHAR
)((Tss
>> 24) & 0xff);
381 // PCR Selector (0x30)
383 pGdt
[6].LimitLow
= 0x01;
384 pGdt
[6].BaseLow
= (USHORT
)(Pcr
& 0xffff);
385 pGdt
[6].HighWord
.Bytes
.BaseMid
= (UCHAR
)((Pcr
>> 16) & 0xff);
386 pGdt
[6].HighWord
.Bytes
.Flags1
= 0x92;
387 pGdt
[6].HighWord
.Bytes
.Flags2
= 0xC0;
388 pGdt
[6].HighWord
.Bytes
.BaseHi
= (UCHAR
)((Pcr
>> 24) & 0xff);
393 pGdt
[7].LimitLow
= 0xFFFF;
395 pGdt
[7].HighWord
.Bytes
.BaseMid
= 0;
396 pGdt
[7].HighWord
.Bytes
.Flags1
= 0xF3;
397 pGdt
[7].HighWord
.Bytes
.Flags2
= 0x40;
398 pGdt
[7].HighWord
.Bytes
.BaseHi
= 0;
401 // Some BIOS stuff (0x40)
403 pGdt
[8].LimitLow
= 0xFFFF;
404 pGdt
[8].BaseLow
= 0x400;
405 pGdt
[8].HighWord
.Bytes
.BaseMid
= 0;
406 pGdt
[8].HighWord
.Bytes
.Flags1
= 0xF2;
407 pGdt
[8].HighWord
.Bytes
.Flags2
= 0x0;
408 pGdt
[8].HighWord
.Bytes
.BaseHi
= 0;
413 pGdt
[9].LimitLow
= 0;
415 pGdt
[9].HighWord
.Bytes
.BaseMid
= 0;
416 pGdt
[9].HighWord
.Bytes
.Flags1
= 0;
417 pGdt
[9].HighWord
.Bytes
.Flags2
= 0;
418 pGdt
[9].HighWord
.Bytes
.BaseHi
= 0;
423 pGdt
[10].LimitLow
= 0xFFFF; //FIXME: Not correct!
424 pGdt
[10].BaseLow
= 0;
425 pGdt
[10].HighWord
.Bytes
.BaseMid
= 0x2;
426 pGdt
[10].HighWord
.Bytes
.Flags1
= 0x89;
427 pGdt
[10].HighWord
.Bytes
.Flags2
= 0;
428 pGdt
[10].HighWord
.Bytes
.BaseHi
= 0;
433 pGdt
[11].LimitLow
= 0xFFFF;
434 pGdt
[11].BaseLow
= 0;
435 pGdt
[11].HighWord
.Bytes
.BaseMid
= 0x2;
436 pGdt
[11].HighWord
.Bytes
.Flags1
= 0x9A;
437 pGdt
[11].HighWord
.Bytes
.Flags2
= 0;
438 pGdt
[11].HighWord
.Bytes
.BaseHi
= 0;
443 pGdt
[12].LimitLow
= 0xFFFF;
444 pGdt
[12].BaseLow
= 0; //FIXME: Maybe not correct, but noone cares
445 pGdt
[12].HighWord
.Bytes
.BaseMid
= 0x2;
446 pGdt
[12].HighWord
.Bytes
.Flags1
= 0x92;
447 pGdt
[12].HighWord
.Bytes
.Flags2
= 0;
448 pGdt
[12].HighWord
.Bytes
.BaseHi
= 0;
451 // Video buffer Selector (0x68)
453 pGdt
[13].LimitLow
= 0x3FFF;
454 pGdt
[13].BaseLow
= 0x8000;
455 pGdt
[13].HighWord
.Bytes
.BaseMid
= 0x0B;
456 pGdt
[13].HighWord
.Bytes
.Flags1
= 0x92;
457 pGdt
[13].HighWord
.Bytes
.Flags2
= 0;
458 pGdt
[13].HighWord
.Bytes
.BaseHi
= 0;
461 // Points to GDT (0x70)
463 pGdt
[14].LimitLow
= NUM_GDT
*sizeof(KGDTENTRY
) - 1;
464 pGdt
[14].BaseLow
= 0x7000;
465 pGdt
[14].HighWord
.Bytes
.BaseMid
= 0xFF;
466 pGdt
[14].HighWord
.Bytes
.Flags1
= 0x92;
467 pGdt
[14].HighWord
.Bytes
.Flags2
= 0;
468 pGdt
[14].HighWord
.Bytes
.BaseHi
= 0xFF;
471 // Some unused descriptors should go here
475 RtlCopyMemory(pIdt
, (PVOID
)OldIdt
.Base
, OldIdt
.Limit
+ 1);
478 //asm("cli\n"); // they are already masked before enabling paged mode
481 Ke386SetGlobalDescriptorTable(&GdtDesc
);
484 // Jump to proper CS and clear prefetch queue
485 #if defined(__GNUC__)
486 asm("ljmp $0x08, $1f\n"
488 #elif defined(_MSC_VER)
489 /* We can't express the above in MASM so we use this far return instead */
490 DbgPrint("WinLdrSetProcessorContext: Performing untested far-return\n");
502 Ke386SetSs(0x10); // DataSelector=0x10
504 // Set DS and ES selectors
506 Ke386SetEs(0x10); // this is vital for rep stosd
508 // LDT = not used ever, thus set to 0
509 Ke386SetLocalDescriptorTable(Ldt
);
512 Ke386SetTr(KGDT_TSS
);
520 // Real end of the function, just for information
535 ULONG
*PDE_Addr
=(ULONG
*)PDE
;//0xC0300000;
538 DPRINTM(DPRINT_WINDOWS
, "\nPDE\n");
540 for (i
=0; i
<128; i
++)
542 DPRINTM(DPRINT_WINDOWS
, "0x%04X | ", i
*8);
546 DPRINTM(DPRINT_WINDOWS
, "0x%08X ", PDE_Addr
[i
*8+j
]);
549 DPRINTM(DPRINT_WINDOWS
, "\n");