[HAL]: Add Phase 0 HAL Heap Allocation/Mapping/Unmapping APIs, remove current broken...
[reactos.git] / reactos / hal / halx86 / generic / halinit.c
1 /*
2 * PROJECT: ReactOS HAL
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: hal/halx86/generic/halinit.c
5 * PURPOSE: HAL Entrypoint and Initialization
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <hal.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16
17 /* Share with Mm headers? */
18 #define MM_HAL_VA_START (PVOID)0xFFC00000
19 #define MM_HAL_HEAP_START (PVOID)((ULONG_PTR)MM_HAL_VA_START + (1024 * 1024))
20
21 BOOLEAN HalpPciLockSettings;
22 ULONG HalpUsedAllocDescriptors;
23 MEMORY_ALLOCATION_DESCRIPTOR HalpAllocationDescriptorArray[64];
24 PVOID HalpHeapStart = MM_HAL_HEAP_START;
25
26 /* PRIVATE FUNCTIONS *********************************************************/
27
28 ULONG
29 NTAPI
30 HalpAllocPhysicalMemory(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
31 IN ULONG MaxAddress,
32 IN ULONG PageCount,
33 IN BOOLEAN Aligned)
34 {
35 ULONG UsedDescriptors, Alignment, PhysicalAddress;
36 PFN_NUMBER MaxPage, BasePage;
37 PLIST_ENTRY NextEntry;
38 PMEMORY_ALLOCATION_DESCRIPTOR MdBlock, NewBlock, FreeBlock;
39
40 /* Highest page we'll go */
41 MaxPage = MaxAddress >> PAGE_SHIFT;
42
43 /* We need at least two blocks */
44 if ((HalpUsedAllocDescriptors + 2) > 64) return 0;
45
46 /* Remember how many we have now */
47 UsedDescriptors = HalpUsedAllocDescriptors;
48
49 /* Loop the loader block memory descriptors */
50 NextEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
51 while (NextEntry != &LoaderBlock->MemoryDescriptorListHead)
52 {
53 /* Get the block */
54 MdBlock = CONTAINING_RECORD(NextEntry,
55 MEMORY_ALLOCATION_DESCRIPTOR,
56 ListEntry);
57
58 /* No alignment by default */
59 Alignment = 0;
60
61 /* Unless requested, in which case we use a 64KB block alignment */
62 if (Aligned) Alignment = ((MdBlock->BasePage + 0x0F) & ~0x0F) - MdBlock->BasePage;
63
64 /* Search for free memory */
65 if ((MdBlock->MemoryType == LoaderFree) ||
66 (MdBlock->MemoryType == MemoryFirmwareTemporary))
67 {
68 /* Make sure the page is within bounds, including alignment */
69 BasePage = MdBlock->BasePage;
70 if ((BasePage) &&
71 (MdBlock->PageCount >= PageCount + Alignment) &&
72 (BasePage + PageCount + Alignment < MaxPage))
73 {
74
75 /* We found an address */
76 PhysicalAddress = (BasePage + Alignment) << PAGE_SHIFT;
77 break;
78 }
79 }
80
81 /* Keep trying */
82 NextEntry = NextEntry->Flink;
83 }
84
85 /* If we didn't find anything, get out of here */
86 if (NextEntry == &LoaderBlock->MemoryDescriptorListHead) return 0;
87
88 /* Okay, now get a descriptor */
89 NewBlock = &HalpAllocationDescriptorArray[HalpUsedAllocDescriptors];
90 NewBlock->PageCount = PageCount;
91 NewBlock->BasePage = MdBlock->BasePage + Alignment;
92 NewBlock->MemoryType = LoaderHALCachedMemory;
93
94 /* Update count */
95 UsedDescriptors++;
96 HalpUsedAllocDescriptors = UsedDescriptors;
97
98 /* Check if we had any alignment */
99 if (Alignment)
100 {
101 /* Check if we had leftovers */
102 if ((MdBlock->PageCount - Alignment) != PageCount)
103 {
104 /* Get the next descriptor */
105 FreeBlock = &HalpAllocationDescriptorArray[UsedDescriptors];
106 FreeBlock->PageCount = MdBlock->PageCount - Alignment - PageCount;
107 FreeBlock->BasePage = MdBlock->BasePage + Alignment + PageCount;
108
109 /* One more */
110 HalpUsedAllocDescriptors++;
111
112 /* Insert it into the list */
113 InsertHeadList(&MdBlock->ListEntry, &FreeBlock->ListEntry);
114 }
115
116 /* Use this descriptor */
117 NewBlock->PageCount = Alignment;
118 InsertHeadList(&MdBlock->ListEntry, &NewBlock->ListEntry);
119 }
120 else
121 {
122 /* Consume memory from this block */
123 MdBlock->BasePage += PageCount;
124 MdBlock->PageCount -= PageCount;
125
126 /* Insert the descriptor */
127 InsertTailList(&MdBlock->ListEntry, &NewBlock->ListEntry);
128
129 /* Remove the entry if the whole block was allocated */
130 if (!MdBlock->PageCount == 0) RemoveEntryList(&MdBlock->ListEntry);
131 }
132
133 /* Return the address */
134 return PhysicalAddress;
135 }
136
137 PVOID
138 NTAPI
139 HalpMapPhysicalMemory64(IN PHYSICAL_ADDRESS PhysicalAddress,
140 IN ULONG PageCount)
141 {
142 PHARDWARE_PTE PointerPte;
143 ULONG UsedPages = 0;
144 PVOID VirtualAddress, BaseAddress;
145
146 /* Start at the current HAL heap base */
147 BaseAddress = HalpHeapStart;
148
149 /* Loop until we have all the pages required */
150 while (UsedPages < PageCount)
151 {
152 /* Begin a new loop cycle */
153 UsedPages = 0;
154 VirtualAddress = BaseAddress;
155
156 /* If this overflows past the HAL heap, it means there's no space */
157 if (BaseAddress == NULL) return NULL;
158
159 /* Loop until we have all the pages required in a single run */
160 while (UsedPages < PageCount)
161 {
162 /* Get the PTE for this address and check if it's available */
163 PointerPte = HalAddressToPte(VirtualAddress);
164 if (*(PULONG)PointerPte)
165 {
166 /* PTE has data, skip it and start with a new base address */
167 BaseAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
168 break;
169 }
170
171 /* PTE is available, keep going on this run */
172 VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
173 UsedPages++;
174 }
175 }
176
177 /* Take the base address of the page plus the actual offset in the address */
178 VirtualAddress = (PVOID)((ULONG_PTR)BaseAddress +
179 BYTE_OFFSET(PhysicalAddress.LowPart));
180
181 /* If we are starting at the heap, move the heap */
182 if (BaseAddress == HalpHeapStart)
183 {
184 /* Past this allocation */
185 HalpHeapStart = (PVOID)((ULONG_PTR)BaseAddress + (PageCount * PAGE_SIZE));
186 }
187
188 /* Loop pages that can be mapped */
189 while (UsedPages--)
190 {
191 /* Fill out the PTE */
192 PointerPte = HalAddressToPte(BaseAddress);
193 PointerPte->PageFrameNumber = PhysicalAddress.QuadPart >> PAGE_SHIFT;
194 PointerPte->Valid = 1;
195 PointerPte->Write = 1;
196
197 /* Move to the next address */
198 PhysicalAddress.QuadPart += PAGE_SIZE;
199 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PAGE_SIZE);
200 }
201
202 /* Flush the TLB and return the address */
203 HalpFlushTLB();
204 return VirtualAddress;
205 }
206
207 VOID
208 NTAPI
209 HalpUnmapVirtualAddress(IN PVOID VirtualAddress,
210 IN ULONG PageCount)
211 {
212 PHARDWARE_PTE PointerPte;
213 ULONG i;
214
215 /* Only accept valid addresses */
216 if (VirtualAddress < MM_HAL_VA_START) return;
217
218 /* Align it down to page size */
219 VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress & ~(PAGE_SIZE - 1));
220
221 /* Loop PTEs */
222 PointerPte = HalAddressToPte(VirtualAddress);
223 for (i = 0; i < PageCount; i++)
224 {
225 *(PULONG)PointerPte = 0;
226 PointerPte++;
227 }
228
229 /* Flush the TLB */
230 HalpFlushTLB();
231
232 /* Put the heap back */
233 if (HalpHeapStart > VirtualAddress) HalpHeapStart = VirtualAddress;
234 }
235
236 VOID
237 NTAPI
238 HalpGetParameters(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
239 {
240 PCHAR CommandLine;
241
242 /* Make sure we have a loader block and command line */
243 if ((LoaderBlock) && (LoaderBlock->LoadOptions))
244 {
245 /* Read the command line */
246 CommandLine = LoaderBlock->LoadOptions;
247
248 /* Check if PCI is locked */
249 if (strstr(CommandLine, "PCILOCK")) HalpPciLockSettings = TRUE;
250
251 /* Check for initial breakpoint */
252 if (strstr(CommandLine, "BREAK")) DbgBreakPoint();
253 }
254 }
255
256 /* FUNCTIONS *****************************************************************/
257
258 /*
259 * @implemented
260 */
261 BOOLEAN
262 NTAPI
263 HalInitSystem(IN ULONG BootPhase,
264 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
265 {
266 PKPRCB Prcb = KeGetCurrentPrcb();
267
268 /* Check the boot phase */
269 if (!BootPhase)
270 {
271 /* Phase 0... save bus type */
272 HalpBusType = LoaderBlock->u.I386.MachineType & 0xFF;
273
274 /* Get command-line parameters */
275 HalpGetParameters(LoaderBlock);
276
277 /* Checked HAL requires checked kernel */
278 #if DBG
279 if (!(Prcb->BuildType & PRCB_BUILD_DEBUG))
280 {
281 /* No match, bugcheck */
282 KeBugCheckEx(MISMATCHED_HAL, 2, Prcb->BuildType, 1, 0);
283 }
284 #else
285 /* Release build requires release HAL */
286 if (Prcb->BuildType & PRCB_BUILD_DEBUG)
287 {
288 /* No match, bugcheck */
289 KeBugCheckEx(MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0);
290 }
291 #endif
292
293 #ifdef CONFIG_SMP
294 /* SMP HAL requires SMP kernel */
295 if (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR)
296 {
297 /* No match, bugcheck */
298 KeBugCheckEx(MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0);
299 }
300 #endif
301
302 /* Validate the PRCB */
303 if (Prcb->MajorVersion != PRCB_MAJOR_VERSION)
304 {
305 /* Validation failed, bugcheck */
306 KeBugCheckEx(MISMATCHED_HAL, 1, Prcb->MajorVersion, 1, 0);
307 }
308
309 #ifndef _MINIHAL_
310 /* Initialize the PICs */
311 HalpInitializePICs(TRUE);
312 #endif
313
314 /* Force initial PIC state */
315 KfRaiseIrql(KeGetCurrentIrql());
316
317 /* Initialize CMOS lock */
318 KeInitializeSpinLock(&HalpSystemHardwareLock);
319
320 /* Initialize CMOS */
321 HalpInitializeCmos();
322
323 /* Fill out the dispatch tables */
324 HalQuerySystemInformation = HaliQuerySystemInformation;
325 HalSetSystemInformation = HaliSetSystemInformation;
326 HalInitPnpDriver = NULL; // FIXME: TODO
327 #ifndef _MINIHAL_
328 HalGetDmaAdapter = HalpGetDmaAdapter;
329 #else
330 HalGetDmaAdapter = NULL;
331 #endif
332 HalGetInterruptTranslator = NULL; // FIXME: TODO
333 #ifndef _MINIHAL_
334 HalResetDisplay = HalpBiosDisplayReset;
335 #else
336 HalResetDisplay = NULL;
337 #endif
338 HalHaltSystem = HaliHaltSystem;
339
340 /* Register IRQ 2 */
341 HalpRegisterVector(IDT_INTERNAL,
342 PRIMARY_VECTOR_BASE + 2,
343 PRIMARY_VECTOR_BASE + 2,
344 HIGH_LEVEL);
345
346 /* Setup I/O space */
347 HalpDefaultIoSpace.Next = HalpAddressUsageList;
348 HalpAddressUsageList = &HalpDefaultIoSpace;
349
350 /* Setup busy waiting */
351 HalpCalibrateStallExecution();
352
353 #ifndef _MINIHAL_
354 /* Initialize the clock */
355 HalpInitializeClock();
356 #endif
357
358 /*
359 * We could be rebooting with a pending profile interrupt,
360 * so clear it here before interrupts are enabled
361 */
362 HalStopProfileInterrupt(ProfileTime);
363
364 /* Do some HAL-specific initialization */
365 HalpInitPhase0(LoaderBlock);
366 }
367 else if (BootPhase == 1)
368 {
369 /* Initialize bus handlers */
370 HalpInitBusHandler();
371
372 #ifndef _MINIHAL_
373 /* Enable IRQ 0 */
374 HalpEnableInterruptHandler(IDT_DEVICE,
375 0,
376 PRIMARY_VECTOR_BASE,
377 CLOCK2_LEVEL,
378 HalpClockInterrupt,
379 Latched);
380
381 /* Enable IRQ 8 */
382 HalpEnableInterruptHandler(IDT_DEVICE,
383 0,
384 PRIMARY_VECTOR_BASE + 8,
385 PROFILE_LEVEL,
386 HalpProfileInterrupt,
387 Latched);
388
389 /* Initialize DMA. NT does this in Phase 0 */
390 HalpInitDma();
391 #endif
392
393 /* Do some HAL-specific initialization */
394 HalpInitPhase1();
395 }
396
397 /* All done, return */
398 return TRUE;
399 }