db54eb59d634934b8ca5eadcd82429ecb23eecc6
[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 VirtualAddress = BaseAddress;
149
150 /* Loop until we have all the pages required */
151 while (UsedPages < PageCount)
152 {
153 /* If this overflows past the HAL heap, it means there's no space */
154 if (VirtualAddress == NULL) return NULL;
155
156 /* Get the PTE for this address */
157 PointerPte = HalAddressToPte(VirtualAddress);
158
159 /* Go to the next page */
160 VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress + PAGE_SIZE);
161
162 /* Check if the page is available */
163 if (PointerPte->Valid)
164 {
165 /* PTE has data, skip it and start with a new base address */
166 BaseAddress = VirtualAddress;
167 UsedPages = 0;
168 continue;
169 }
170
171 /* PTE is available, keep going on this run */
172 UsedPages++;
173 }
174
175 /* Take the base address of the page plus the actual offset in the address */
176 VirtualAddress = (PVOID)((ULONG_PTR)BaseAddress +
177 BYTE_OFFSET(PhysicalAddress.LowPart));
178
179 /* If we are starting at the heap, move the heap */
180 if (BaseAddress == HalpHeapStart)
181 {
182 /* Past this allocation */
183 HalpHeapStart = (PVOID)((ULONG_PTR)BaseAddress + (PageCount * PAGE_SIZE));
184 }
185
186 /* Loop pages that can be mapped */
187 while (UsedPages--)
188 {
189 /* Fill out the PTE */
190 PointerPte = HalAddressToPte(BaseAddress);
191 PointerPte->PageFrameNumber = PhysicalAddress.QuadPart >> PAGE_SHIFT;
192 PointerPte->Valid = 1;
193 PointerPte->Write = 1;
194
195 /* Move to the next address */
196 PhysicalAddress.QuadPart += PAGE_SIZE;
197 BaseAddress = (PVOID)((ULONG_PTR)BaseAddress + PAGE_SIZE);
198 }
199
200 /* Flush the TLB and return the address */
201 HalpFlushTLB();
202 return VirtualAddress;
203 }
204
205 VOID
206 NTAPI
207 HalpUnmapVirtualAddress(IN PVOID VirtualAddress,
208 IN ULONG PageCount)
209 {
210 PHARDWARE_PTE PointerPte;
211 ULONG i;
212
213 /* Only accept valid addresses */
214 if (VirtualAddress < MM_HAL_VA_START) return;
215
216 /* Align it down to page size */
217 VirtualAddress = (PVOID)((ULONG_PTR)VirtualAddress & ~(PAGE_SIZE - 1));
218
219 /* Loop PTEs */
220 PointerPte = HalAddressToPte(VirtualAddress);
221 for (i = 0; i < PageCount; i++)
222 {
223 *(PULONG)PointerPte = 0;
224 PointerPte++;
225 }
226
227 /* Flush the TLB */
228 HalpFlushTLB();
229
230 /* Put the heap back */
231 if (HalpHeapStart > VirtualAddress) HalpHeapStart = VirtualAddress;
232 }
233
234 VOID
235 NTAPI
236 HalpGetParameters(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
237 {
238 PCHAR CommandLine;
239
240 /* Make sure we have a loader block and command line */
241 if ((LoaderBlock) && (LoaderBlock->LoadOptions))
242 {
243 /* Read the command line */
244 CommandLine = LoaderBlock->LoadOptions;
245
246 /* Check if PCI is locked */
247 if (strstr(CommandLine, "PCILOCK")) HalpPciLockSettings = TRUE;
248
249 /* Check for initial breakpoint */
250 if (strstr(CommandLine, "BREAK")) DbgBreakPoint();
251 }
252 }
253
254 /* FUNCTIONS *****************************************************************/
255
256 /*
257 * @implemented
258 */
259 BOOLEAN
260 NTAPI
261 HalInitSystem(IN ULONG BootPhase,
262 IN PLOADER_PARAMETER_BLOCK LoaderBlock)
263 {
264 PKPRCB Prcb = KeGetCurrentPrcb();
265
266 /* Check the boot phase */
267 if (!BootPhase)
268 {
269 /* Phase 0... save bus type */
270 HalpBusType = LoaderBlock->u.I386.MachineType & 0xFF;
271
272 /* Get command-line parameters */
273 HalpGetParameters(LoaderBlock);
274
275 /* Checked HAL requires checked kernel */
276 #if DBG
277 if (!(Prcb->BuildType & PRCB_BUILD_DEBUG))
278 {
279 /* No match, bugcheck */
280 KeBugCheckEx(MISMATCHED_HAL, 2, Prcb->BuildType, 1, 0);
281 }
282 #else
283 /* Release build requires release HAL */
284 if (Prcb->BuildType & PRCB_BUILD_DEBUG)
285 {
286 /* No match, bugcheck */
287 KeBugCheckEx(MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0);
288 }
289 #endif
290
291 #ifdef CONFIG_SMP
292 /* SMP HAL requires SMP kernel */
293 if (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR)
294 {
295 /* No match, bugcheck */
296 KeBugCheckEx(MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0);
297 }
298 #endif
299
300 /* Validate the PRCB */
301 if (Prcb->MajorVersion != PRCB_MAJOR_VERSION)
302 {
303 /* Validation failed, bugcheck */
304 KeBugCheckEx(MISMATCHED_HAL, 1, Prcb->MajorVersion, 1, 0);
305 }
306
307 #ifndef _MINIHAL_
308 /* Initialize ACPI */
309 HalpSetupAcpiPhase0(LoaderBlock);
310
311 /* Initialize the PICs */
312 HalpInitializePICs(TRUE);
313 #endif
314
315 /* Force initial PIC state */
316 KfRaiseIrql(KeGetCurrentIrql());
317
318 /* Initialize CMOS lock */
319 KeInitializeSpinLock(&HalpSystemHardwareLock);
320
321 /* Initialize CMOS */
322 HalpInitializeCmos();
323
324 /* Fill out the dispatch tables */
325 HalQuerySystemInformation = HaliQuerySystemInformation;
326 HalSetSystemInformation = HaliSetSystemInformation;
327 HalInitPnpDriver = NULL; // FIXME: TODO
328 #ifndef _MINIHAL_
329 HalGetDmaAdapter = HalpGetDmaAdapter;
330 #else
331 HalGetDmaAdapter = NULL;
332 #endif
333 HalGetInterruptTranslator = NULL; // FIXME: TODO
334 #ifndef _MINIHAL_
335 HalResetDisplay = HalpBiosDisplayReset;
336 #else
337 HalResetDisplay = NULL;
338 #endif
339 HalHaltSystem = HaliHaltSystem;
340
341 /* Register IRQ 2 */
342 HalpRegisterVector(IDT_INTERNAL,
343 PRIMARY_VECTOR_BASE + 2,
344 PRIMARY_VECTOR_BASE + 2,
345 HIGH_LEVEL);
346
347 /* Setup I/O space */
348 HalpDefaultIoSpace.Next = HalpAddressUsageList;
349 HalpAddressUsageList = &HalpDefaultIoSpace;
350
351 /* Setup busy waiting */
352 HalpCalibrateStallExecution();
353
354 #ifndef _MINIHAL_
355 /* Initialize the clock */
356 HalpInitializeClock();
357 #endif
358
359 /*
360 * We could be rebooting with a pending profile interrupt,
361 * so clear it here before interrupts are enabled
362 */
363 HalStopProfileInterrupt(ProfileTime);
364
365 /* Do some HAL-specific initialization */
366 HalpInitPhase0(LoaderBlock);
367 }
368 else if (BootPhase == 1)
369 {
370 /* Initialize bus handlers */
371 HalpInitBusHandler();
372
373 #ifndef _MINIHAL_
374 /* Enable IRQ 0 */
375 HalpEnableInterruptHandler(IDT_DEVICE,
376 0,
377 PRIMARY_VECTOR_BASE,
378 CLOCK2_LEVEL,
379 HalpClockInterrupt,
380 Latched);
381
382 /* Enable IRQ 8 */
383 HalpEnableInterruptHandler(IDT_DEVICE,
384 0,
385 PRIMARY_VECTOR_BASE + 8,
386 PROFILE_LEVEL,
387 HalpProfileInterrupt,
388 Latched);
389
390 /* Initialize DMA. NT does this in Phase 0 */
391 HalpInitDma();
392 #endif
393
394 /* Do some HAL-specific initialization */
395 HalpInitPhase1();
396 }
397
398 /* All done, return */
399 return TRUE;
400 }