[WIN32K]
[reactos.git] / reactos / hal / halx86 / generic / acpi / halacpi.c
1 /*
2 * PROJECT: ReactOS HAL
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: hal/halx86/generic/acpi/halacpi.c
5 * PURPOSE: HAL ACPI Code
6 * PROGRAMMERS: ReactOS Portable Systems Group
7 */
8
9 /* INCLUDES *******************************************************************/
10
11 #include <hal.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS ********************************************************************/
16
17 LIST_ENTRY HalpAcpiTableCacheList;
18 FAST_MUTEX HalpAcpiTableCacheLock;
19
20 BOOLEAN HalpProcessedACPIPhase0;
21 BOOLEAN HalpPhysicalMemoryMayAppearAbove4GB;
22
23 FADT HalpFixedAcpiDescTable;
24 PDEBUG_PORT_TABLE HalpDebugPortTable;
25 PACPI_SRAT HalpAcpiSrat;
26 PBOOT_TABLE HalpSimpleBootFlagTable;
27
28 PHYSICAL_ADDRESS HalpMaxHotPlugMemoryAddress;
29 PHYSICAL_ADDRESS HalpLowStubPhysicalAddress;
30 PHARDWARE_PTE HalpPteForFlush;
31 PVOID HalpVirtAddrForFlush;
32 PVOID HalpLowStub;
33
34 PACPI_BIOS_MULTI_NODE HalpAcpiMultiNode;
35
36 LIST_ENTRY HalpAcpiTableMatchList;
37
38 ULONG HalpInvalidAcpiTable;
39
40 ULONG HalpPicVectorRedirect[] = {0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15};
41
42 /* This determines the HAL type */
43 BOOLEAN HalDisableFirmwareMapper = TRUE;
44 PWCHAR HalHardwareIdString = L"acpipic_up";
45 PWCHAR HalName = L"ACPI Compatible Eisa/Isa HAL";
46
47 /* PRIVATE FUNCTIONS **********************************************************/
48
49 PDESCRIPTION_HEADER
50 NTAPI
51 HalpAcpiGetCachedTable(IN ULONG Signature)
52 {
53 PLIST_ENTRY ListHead, NextEntry;
54 PACPI_CACHED_TABLE CachedTable;
55
56 /* Loop cached tables */
57 ListHead = &HalpAcpiTableCacheList;
58 NextEntry = ListHead->Flink;
59 while (NextEntry != ListHead)
60 {
61 /* Get the table */
62 CachedTable = CONTAINING_RECORD(NextEntry, ACPI_CACHED_TABLE, Links);
63
64 /* Compare signatures */
65 if (CachedTable->Header.Signature == Signature) return &CachedTable->Header;
66
67 /* Keep going */
68 NextEntry = NextEntry->Flink;
69 }
70
71 /* Nothing found */
72 return NULL;
73 }
74
75 VOID
76 NTAPI
77 HalpAcpiCacheTable(IN PDESCRIPTION_HEADER TableHeader)
78 {
79 PACPI_CACHED_TABLE CachedTable;
80
81 /* Get the cached table and link it */
82 CachedTable = CONTAINING_RECORD(TableHeader, ACPI_CACHED_TABLE, Header);
83 InsertTailList(&HalpAcpiTableCacheList, &CachedTable->Links);
84 }
85
86 PVOID
87 NTAPI
88 HalpAcpiCopyBiosTable(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
89 IN PDESCRIPTION_HEADER TableHeader)
90 {
91 ULONG Size;
92 PFN_NUMBER PageCount;
93 PHYSICAL_ADDRESS PhysAddress;
94 PACPI_CACHED_TABLE CachedTable;
95 PDESCRIPTION_HEADER CopiedTable;
96
97 /* Size we'll need for the cached table */
98 Size = TableHeader->Length + FIELD_OFFSET(ACPI_CACHED_TABLE, Header);
99 if (LoaderBlock)
100 {
101 /* Phase 0: Convert to pages and use the HAL heap */
102 PageCount = BYTES_TO_PAGES(Size);
103 PhysAddress.LowPart = HalpAllocPhysicalMemory(LoaderBlock,
104 0x1000000,
105 PageCount,
106 FALSE);
107 if (PhysAddress.LowPart)
108 {
109 /* Map it */
110 CachedTable = HalpMapPhysicalMemory64(PhysAddress, PageCount);
111 }
112 else
113 {
114 /* No memory, so nothing to map */
115 CachedTable = NULL;
116 }
117 }
118 else
119 {
120 /* Use Mm pool */
121 CachedTable = ExAllocatePoolWithTag(NonPagedPool, Size, ' laH');
122 }
123
124 /* Do we have the cached table? */
125 if (CachedTable)
126 {
127 /* Copy the data */
128 CopiedTable = &CachedTable->Header;
129 RtlCopyMemory(CopiedTable, TableHeader, TableHeader->Length);
130 }
131 else
132 {
133 /* Nothing to return */
134 CopiedTable = NULL;
135 }
136
137 /* Return the table */
138 return CopiedTable;
139 }
140
141 PVOID
142 NTAPI
143 HalpAcpiGetTableFromBios(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
144 IN ULONG Signature)
145 {
146 PHYSICAL_ADDRESS PhysicalAddress;
147 PXSDT Xsdt;
148 PRSDT Rsdt;
149 PFADT Fadt;
150 PDESCRIPTION_HEADER Header = NULL;
151 ULONG TableLength;
152 CHAR CheckSum = 0;
153 ULONG Offset;
154 ULONG EntryCount, CurrentEntry;
155 PCHAR CurrentByte;
156 PFN_NUMBER PageCount;
157
158 /* Should not query the RSDT/XSDT by itself */
159 if ((Signature == RSDT_SIGNATURE) || (Signature == XSDT_SIGNATURE)) return NULL;
160
161 /* Special case request for DSDT, because the FADT points to it */
162 if (Signature == DSDT_SIGNATURE)
163 {
164 /* Grab the FADT */
165 Fadt = HalpAcpiGetTable(LoaderBlock, FADT_SIGNATURE);
166 if (Fadt)
167 {
168 /* Grab the DSDT address and assume 2 pages */
169 PhysicalAddress.HighPart = 0;
170 PhysicalAddress.LowPart = Fadt->dsdt;
171 TableLength = 2 * PAGE_SIZE;
172
173 /* Map it */
174 if (LoaderBlock)
175 {
176 /* Phase 0, use HAL heap */
177 Header = HalpMapPhysicalMemory64(PhysicalAddress, 2u);
178 }
179 else
180 {
181 /* Phase 1, use Mm */
182 Header = MmMapIoSpace(PhysicalAddress, 2 * PAGE_SIZE, 0);
183 }
184
185 /* Fail if we couldn't map it */
186 if (!Header)
187 {
188 DPRINT1("HAL: Failed to map ACPI table.\n");
189 return NULL;
190 }
191
192 /* Validate the signature */
193 DPRINT1("ACPI DSDT at 0x%p\n", Header);
194 if (Header->Signature != DSDT_SIGNATURE)
195 {
196 /* Fail and unmap */
197 if (LoaderBlock)
198 {
199 /* Using HAL heap */
200 HalpUnmapVirtualAddress(Header, 2);
201 }
202 else
203 {
204 /* Using Mm */
205 MmUnmapIoSpace(Header, 2 * PAGE_SIZE);
206 }
207
208 /* Didn't find anything */
209 return NULL;
210 }
211 }
212 else
213 {
214 /* Couldn't find it */
215 return NULL;
216 }
217 }
218 else
219 {
220 /* To find tables, we need the RSDT */
221 Rsdt = HalpAcpiGetTable(LoaderBlock, RSDT_SIGNATURE);
222 if (Rsdt)
223 {
224 /* Won't be using the XSDT */
225 Xsdt = NULL;
226 }
227 else
228 {
229 /* Only other choice is to use the XSDT */
230 Xsdt = HalpAcpiGetTable(LoaderBlock, XSDT_SIGNATURE);
231 if (!Xsdt) return NULL;
232
233 /* Won't be using the RSDT */
234 DPRINT1("ACPI XSDT at 0x%p\n", Xsdt);
235 Rsdt = NULL;
236 }
237
238 /* Smallest RSDT/XSDT is one without table entries */
239 Offset = FIELD_OFFSET(RSDT, Tables);
240 if (Xsdt)
241 {
242 /* Figure out total size of table and the offset */
243 TableLength = Xsdt->Header.Length;
244 if (TableLength < Offset) Offset = Xsdt->Header.Length;
245
246 /* The entries are each 64-bits, so count them */
247 EntryCount = (TableLength - Offset) / sizeof(PHYSICAL_ADDRESS);
248 }
249 else
250 {
251 /* Figure out total size of table and the offset */
252 TableLength = Rsdt->Header.Length;
253 if (TableLength < Offset) Offset = Rsdt->Header.Length;
254
255 /* The entries are each 32-bits, so count them */
256 EntryCount = (TableLength - Offset) / sizeof(ULONG);
257 }
258
259 /* Start at the beginning of the array and loop it */
260 for (CurrentEntry = 0; CurrentEntry < EntryCount; CurrentEntry++)
261 {
262 /* Are we using the XSDT? */
263 if (!Xsdt)
264 {
265 /* Read the 32-bit physical address */
266 PhysicalAddress.LowPart = Rsdt->Tables[CurrentEntry];
267 PhysicalAddress.HighPart = 0;
268 }
269 else
270 {
271 /* Read the 64-bit physical address */
272 PhysicalAddress = Xsdt->Tables[CurrentEntry];
273 }
274
275 /* Had we already mapped a table? */
276 if (Header)
277 {
278 /* Yes, unmap it */
279 if (LoaderBlock)
280 {
281 /* Using HAL heap */
282 HalpUnmapVirtualAddress(Header, 2);
283 }
284 else
285 {
286 /* Using Mm */
287 MmUnmapIoSpace(Header, 2 * PAGE_SIZE);
288 }
289 }
290
291 /* Now map this table */
292 if (!LoaderBlock)
293 {
294 /* Phase 1: Use HAL heap */
295 Header = MmMapIoSpace(PhysicalAddress, 2 * PAGE_SIZE, MmNonCached);
296 }
297 else
298 {
299 /* Phase 0: Use Mm */
300 Header = HalpMapPhysicalMemory64(PhysicalAddress, 2);
301 }
302
303 /* Check if we mapped it */
304 if (!Header)
305 {
306 /* Game over */
307 DPRINT1("HAL: Failed to map ACPI table.\n");
308 return NULL;
309 }
310
311 /* We found it, break out */
312 DPRINT("Found ACPI table %c%c%c%c at 0x%p\n",
313 Header->Signature & 0xFF,
314 (Header->Signature & 0xFF00) >> 8,
315 (Header->Signature & 0xFF0000) >> 16,
316 (Header->Signature & 0xFF000000) >> 24,
317 Header);
318 if (Header->Signature == Signature) break;
319 }
320
321 /* Did we end up here back at the last entry? */
322 if (CurrentEntry == EntryCount)
323 {
324 /* Yes, unmap the last table we processed */
325 if (LoaderBlock)
326 {
327 /* Using HAL heap */
328 HalpUnmapVirtualAddress(Header, 2);
329 }
330 else
331 {
332 /* Using Mm */
333 MmUnmapIoSpace(Header, 2 * PAGE_SIZE);
334 }
335
336 /* Didn't find anything */
337 return NULL;
338 }
339 }
340
341 /* Past this point, we assume something was found */
342 ASSERT(Header);
343
344 /* How many pages do we need? */
345 PageCount = BYTES_TO_PAGES(Header->Length);
346 if (PageCount != 2)
347 {
348 /* We assumed two, but this is not the case, free the current mapping */
349 if (LoaderBlock)
350 {
351 /* Using HAL heap */
352 HalpUnmapVirtualAddress(Header, 2);
353 }
354 else
355 {
356 /* Using Mm */
357 MmUnmapIoSpace(Header, 2 * PAGE_SIZE);
358 }
359
360 /* Now map this table using its correct size */
361 if (!LoaderBlock)
362 {
363 /* Phase 1: Use HAL heap */
364 Header = MmMapIoSpace(PhysicalAddress, PageCount << PAGE_SHIFT, MmNonCached);
365 }
366 else
367 {
368 /* Phase 0: Use Mm */
369 Header = HalpMapPhysicalMemory64(PhysicalAddress, PageCount);
370 }
371 }
372
373 /* Fail if the remapped failed */
374 if (!Header) return NULL;
375
376 /* All tables in ACPI 3.0 other than the FACP should have correct checksum */
377 if ((Header->Signature != FADT_SIGNATURE) || (Header->Revision > 2))
378 {
379 /* Go to the end of the table */
380 CheckSum = 0;
381 CurrentByte = (PCHAR)Header + Header->Length;
382 while (CurrentByte-- != (PCHAR)Header)
383 {
384 /* Add this byte */
385 CheckSum += *CurrentByte;
386 }
387
388 /* The correct checksum is always 0, anything else is illegal */
389 if (CheckSum) HalpInvalidAcpiTable = Header->Signature;
390 }
391
392 /* Return the table */
393 return Header;
394 }
395
396 PVOID
397 NTAPI
398 HalpAcpiGetTable(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
399 IN ULONG Signature)
400 {
401 PFN_NUMBER PageCount;
402 PDESCRIPTION_HEADER TableAddress, BiosCopy;
403
404 /* See if we have a cached table? */
405 TableAddress = HalpAcpiGetCachedTable(Signature);
406 if (!TableAddress)
407 {
408 /* No cache, search the BIOS */
409 TableAddress = HalpAcpiGetTableFromBios(LoaderBlock, Signature);
410 if (TableAddress)
411 {
412 /* Found it, copy it into our own memory */
413 BiosCopy = HalpAcpiCopyBiosTable(LoaderBlock, TableAddress);
414
415 /* Get the pages, and unmap the BIOS copy */
416 PageCount = BYTES_TO_PAGES(TableAddress->Length);
417 if (LoaderBlock)
418 {
419 /* Phase 0, use the HAL heap */
420 HalpUnmapVirtualAddress(TableAddress, PageCount);
421 }
422 else
423 {
424 /* Phase 1, use Mm */
425 MmUnmapIoSpace(TableAddress, PageCount << PAGE_SHIFT);
426 }
427
428 /* Cache the bios copy */
429 TableAddress = BiosCopy;
430 if (BiosCopy) HalpAcpiCacheTable(BiosCopy);
431 }
432 }
433
434 /* Return the table */
435 return TableAddress;
436 }
437
438 PVOID
439 NTAPI
440 HalAcpiGetTable(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
441 IN ULONG Signature)
442 {
443 PDESCRIPTION_HEADER TableHeader;
444
445 /* Is this phase0 */
446 if (LoaderBlock)
447 {
448 /* Initialize the cache first */
449 if (!NT_SUCCESS(HalpAcpiTableCacheInit(LoaderBlock))) return NULL;
450 }
451 else
452 {
453 /* Lock the cache */
454 ExAcquireFastMutex(&HalpAcpiTableCacheLock);
455 }
456
457 /* Get the table */
458 TableHeader = HalpAcpiGetTable(LoaderBlock, Signature);
459
460 /* Release the lock in phase 1 */
461 if (!LoaderBlock) ExReleaseFastMutex(&HalpAcpiTableCacheLock);
462
463 /* Return the table */
464 return TableHeader;
465 }
466
467 VOID
468 NTAPI
469 HalpNumaInitializeStaticConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
470 {
471 PACPI_SRAT SratTable;
472
473 /* Get the SRAT, bail out if it doesn't exist */
474 SratTable = HalAcpiGetTable(LoaderBlock, SRAT_SIGNATURE);
475 HalpAcpiSrat = SratTable;
476 if (!SratTable) return;
477 }
478
479 VOID
480 NTAPI
481 HalpGetHotPlugMemoryInfo(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
482 {
483 PACPI_SRAT SratTable;
484
485 /* Get the SRAT, bail out if it doesn't exist */
486 SratTable = HalAcpiGetTable(LoaderBlock, SRAT_SIGNATURE);
487 HalpAcpiSrat = SratTable;
488 if (!SratTable) return;
489 }
490
491 VOID
492 NTAPI
493 HalpDynamicSystemResourceConfiguration(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
494 {
495 /* For this HAL, it means to get hot plug memory information */
496 HalpGetHotPlugMemoryInfo(LoaderBlock);
497 }
498
499 VOID
500 NTAPI
501 HalpAcpiDetectMachineSpecificActions(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
502 IN PFADT DescriptionTable)
503 {
504 /* Does this HAL specify something? */
505 if (HalpAcpiTableMatchList.Flink)
506 {
507 /* Great, but we don't support it */
508 DPRINT1("WARNING: Your HAL has specific ACPI hacks to apply!\n");
509 }
510 }
511
512 VOID
513 NTAPI
514 HalpInitBootTable(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
515 {
516 PBOOT_TABLE BootTable;
517
518 /* Get the boot table */
519 BootTable = HalAcpiGetTable(LoaderBlock, BOOT_SIGNATURE);
520 HalpSimpleBootFlagTable = BootTable;
521 DPRINT1("ACPI BOOT at 0x%p\n", HalpSimpleBootFlagTable);
522
523 /* Validate it */
524 if ((BootTable) &&
525 (BootTable->Header.Length >= sizeof(BOOT_TABLE)) &&
526 (BootTable->CMOSIndex >= 9))
527 {
528 DPRINT1("ACPI Boot table found, but not supported!\n");
529 }
530 else
531 {
532 /* Invalid or doesn't exist, ignore it */
533 HalpSimpleBootFlagTable = 0;
534 }
535
536 /* Install the end of boot handler */
537 // HalEndOfBoot = HalpEndOfBoot;
538 }
539
540 NTSTATUS
541 NTAPI
542 HalpAcpiFindRsdtPhase0(IN PLOADER_PARAMETER_BLOCK LoaderBlock,
543 OUT PACPI_BIOS_MULTI_NODE* AcpiMultiNode)
544 {
545 PCONFIGURATION_COMPONENT_DATA ComponentEntry;
546 PCONFIGURATION_COMPONENT_DATA Next = NULL;
547 PCM_PARTIAL_RESOURCE_LIST ResourceList;
548 PACPI_BIOS_MULTI_NODE NodeData;
549 ULONG NodeLength;
550 PFN_NUMBER PageCount;
551 PVOID MappedAddress;
552 PHYSICAL_ADDRESS PhysicalAddress;
553
554 /* Did we already do this once? */
555 if (HalpAcpiMultiNode)
556 {
557 /* Return what we know */
558 *AcpiMultiNode = HalpAcpiMultiNode;
559 return STATUS_SUCCESS;
560 }
561
562 /* Assume failure */
563 *AcpiMultiNode = NULL;
564
565 /* Find the multi function adapter key */
566 ComponentEntry = KeFindConfigurationNextEntry(LoaderBlock->ConfigurationRoot,
567 AdapterClass,
568 MultiFunctionAdapter,
569 0,
570 &Next);
571 while (ComponentEntry)
572 {
573 /* Find the ACPI BIOS key */
574 if (!_stricmp(ComponentEntry->ComponentEntry.Identifier, "ACPI BIOS"))
575 {
576 /* Found it */
577 break;
578 }
579
580 /* Keep searching */
581 Next = ComponentEntry;
582 ComponentEntry = KeFindConfigurationNextEntry(LoaderBlock->ConfigurationRoot,
583 AdapterClass,
584 MultiFunctionAdapter,
585 NULL,
586 &Next);
587 }
588
589 /* Make sure we found it */
590 if (!ComponentEntry)
591 {
592 DPRINT1("**** HalpAcpiFindRsdtPhase0: did NOT find RSDT\n");
593 return STATUS_NOT_FOUND;
594 }
595
596 /* The configuration data is a resource list, and the BIOS node follows */
597 ResourceList = ComponentEntry->ConfigurationData;
598 NodeData = (PACPI_BIOS_MULTI_NODE)(ResourceList + 1);
599
600 /* How many E820 memory entries are there? */
601 NodeLength = sizeof(ACPI_BIOS_MULTI_NODE) +
602 (NodeData->Count - 1) * sizeof(ACPI_E820_ENTRY);
603
604 /* Convert to pages */
605 PageCount = BYTES_TO_PAGES(NodeLength);
606
607 /* Allocate the memory */
608 PhysicalAddress.HighPart = 0;
609 PhysicalAddress.LowPart = HalpAllocPhysicalMemory(LoaderBlock,
610 0x1000000,
611 PageCount,
612 FALSE);
613 if (PhysicalAddress.LowPart)
614 {
615 /* Map it if the allocation worked */
616 MappedAddress = HalpMapPhysicalMemory64(PhysicalAddress, PageCount);
617 }
618 else
619 {
620 /* Otherwise we'll have to fail */
621 MappedAddress = NULL;
622 }
623
624 /* Save the multi node, bail out if we didn't find it */
625 HalpAcpiMultiNode = MappedAddress;
626 if (!MappedAddress) return STATUS_INSUFFICIENT_RESOURCES;
627
628 /* Copy the multi-node data */
629 RtlCopyMemory(MappedAddress, NodeData, NodeLength);
630
631 /* Return the data */
632 *AcpiMultiNode = HalpAcpiMultiNode;
633 return STATUS_SUCCESS;
634 }
635
636 NTSTATUS
637 NTAPI
638 HalpAcpiTableCacheInit(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
639 {
640 PACPI_BIOS_MULTI_NODE AcpiMultiNode;
641 NTSTATUS Status = STATUS_SUCCESS;
642 PHYSICAL_ADDRESS PhysicalAddress;
643 PVOID MappedAddress;
644 ULONG TableLength;
645 PRSDT Rsdt;
646 PLOADER_PARAMETER_EXTENSION LoaderExtension;
647
648 /* Only initialize once */
649 if (HalpAcpiTableCacheList.Flink) return Status;
650
651 /* Setup the lock and table */
652 ExInitializeFastMutex(&HalpAcpiTableCacheLock);
653 InitializeListHead(&HalpAcpiTableCacheList);
654
655 /* Find the RSDT */
656 Status = HalpAcpiFindRsdtPhase0(LoaderBlock, &AcpiMultiNode);
657 if (!NT_SUCCESS(Status)) return Status;
658
659 PhysicalAddress.QuadPart = AcpiMultiNode->RsdtAddress.QuadPart;
660
661 /* Map the RSDT */
662 if (LoaderBlock)
663 {
664 /* Phase0: Use HAL Heap to map the RSDT, we assume it's about 2 pages */
665 MappedAddress = HalpMapPhysicalMemory64(PhysicalAddress, 2);
666 }
667 else
668 {
669 /* Use an I/O map */
670 MappedAddress = MmMapIoSpace(PhysicalAddress, PAGE_SIZE * 2, MmNonCached);
671 }
672
673 /* Get the RSDT */
674 Rsdt = MappedAddress;
675 if (!MappedAddress)
676 {
677 /* Fail, no memory */
678 DPRINT1("HAL: Failed to map RSDT\n");
679 return STATUS_INSUFFICIENT_RESOURCES;
680 }
681
682 /* Validate it */
683 DPRINT1("ACPI RSDT at 0x%p\n", Rsdt);
684 if ((Rsdt->Header.Signature != RSDT_SIGNATURE) &&
685 (Rsdt->Header.Signature != XSDT_SIGNATURE))
686 {
687 /* Very bad: crash */
688 HalDisplayString("Bad RSDT pointer\n");
689 KeBugCheckEx(MISMATCHED_HAL, 4, __LINE__, 0, 0);
690 }
691
692 /* We assumed two pages -- do we need less or more? */
693 TableLength = ADDRESS_AND_SIZE_TO_SPAN_PAGES(PhysicalAddress.LowPart,
694 Rsdt->Header.Length);
695 if (TableLength != 2)
696 {
697 /* Are we in phase 0 or 1? */
698 if (!LoaderBlock)
699 {
700 /* Unmap the old table, remap the new one, using Mm I/O space */
701 MmUnmapIoSpace(MappedAddress, 2 * PAGE_SIZE);
702 MappedAddress = MmMapIoSpace(PhysicalAddress,
703 TableLength << PAGE_SHIFT,
704 MmNonCached);
705 }
706 else
707 {
708 /* Unmap the old table, remap the new one, using HAL heap */
709 HalpUnmapVirtualAddress(MappedAddress, 2);
710 MappedAddress = HalpMapPhysicalMemory64(PhysicalAddress, TableLength);
711 }
712
713 /* Get the remapped table */
714 Rsdt = MappedAddress;
715 if (!MappedAddress)
716 {
717 /* Fail, no memory */
718 DPRINT1("HAL: Couldn't remap RSDT\n");
719 return STATUS_INSUFFICIENT_RESOURCES;
720 }
721 }
722
723 /* Now take the BIOS copy and make our own local copy */
724 Rsdt = HalpAcpiCopyBiosTable(LoaderBlock, &Rsdt->Header);
725 if (!Rsdt)
726 {
727 /* Fail, no memory */
728 DPRINT1("HAL: Couldn't remap RSDT\n");
729 return STATUS_INSUFFICIENT_RESOURCES;
730 }
731
732 /* Get rid of the BIOS mapping */
733 if (LoaderBlock)
734 {
735 /* Use HAL heap */
736 HalpUnmapVirtualAddress(MappedAddress, TableLength);
737 }
738 else
739 {
740 /* Use Mm */
741 MmUnmapIoSpace(MappedAddress, TableLength << PAGE_SHIFT);
742 }
743
744 /* Cache the RSDT */
745 HalpAcpiCacheTable(&Rsdt->Header);
746
747 /* Check for compatible loader block extension */
748 LoaderExtension = LoaderBlock->Extension;
749 if (LoaderExtension->Size >= 0x58)
750 {
751 /* Compatible loader: did it provide an ACPI table override? */
752 if ((LoaderExtension->AcpiTable) && (LoaderExtension->AcpiTableSize))
753 {
754 /* Great, because we don't support it! */
755 DPRINT1("ACPI Table Overrides Not Supported!\n");
756 }
757 }
758
759 /* Done */
760 return Status;
761 }
762
763 VOID
764 NTAPI
765 HaliAcpiTimerInit(IN ULONG TimerPort,
766 IN ULONG TimerValExt)
767 {
768 PAGED_CODE();
769
770 /* Is this in the init phase? */
771 if (!TimerPort )
772 {
773 /* Get the data from the FADT */
774 TimerPort = HalpFixedAcpiDescTable.pm_tmr_blk_io_port;
775 TimerValExt = HalpFixedAcpiDescTable.flags & ACPI_TMR_VAL_EXT;
776 }
777
778 /* FIXME: Now proceed to the timer initialization */
779 DPRINT1("ACPI Timer at: %Xh (EXT: %d)\n", TimerPort, TimerValExt);
780 //HalaAcpiTimerInit(TimerPort, TimerValExt);
781 }
782
783 NTSTATUS
784 NTAPI
785 HalpSetupAcpiPhase0(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
786 {
787 NTSTATUS Status;
788 PFADT Fadt;
789 ULONG TableLength;
790 PHYSICAL_ADDRESS PhysicalAddress;
791
792 /* Only do this once */
793 DPRINT("You are booting the ACPI HAL!\n");
794 if (HalpProcessedACPIPhase0) return STATUS_SUCCESS;
795
796 /* Setup the ACPI table cache */
797 Status = HalpAcpiTableCacheInit(LoaderBlock);
798 if (!NT_SUCCESS(Status)) return Status;
799
800 /* Grab the FADT */
801 Fadt = HalAcpiGetTable(LoaderBlock, FADT_SIGNATURE);
802 if (!Fadt)
803 {
804 /* Fail */
805 DPRINT1("HAL: Didn't find the FACP\n");
806 return STATUS_NOT_FOUND;
807 }
808
809 /* Assume typical size, otherwise whatever the descriptor table says */
810 DPRINT1("ACPI FACP at 0x%p\n", Fadt);
811 TableLength = sizeof(FADT);
812 if (Fadt->Header.Length < sizeof(FADT)) TableLength = Fadt->Header.Length;
813
814 /* Copy it in the HAL static buffer */
815 RtlCopyMemory(&HalpFixedAcpiDescTable, Fadt, TableLength);
816
817 /* Anything special this HAL needs to do? */
818 HalpAcpiDetectMachineSpecificActions(LoaderBlock, &HalpFixedAcpiDescTable);
819
820 /* Get the debug table for KD */
821 HalpDebugPortTable = HalAcpiGetTable(LoaderBlock, DBGP_SIGNATURE);
822 DPRINT1("ACPI DBGP at 0x%p\n", HalpDebugPortTable);
823
824 /* Initialize NUMA through the SRAT */
825 HalpNumaInitializeStaticConfiguration(LoaderBlock);
826
827 /* Initialize hotplug through the SRAT */
828 HalpDynamicSystemResourceConfiguration(LoaderBlock);
829 DPRINT1("ACPI SRAT at 0x%p\n", HalpAcpiSrat);
830 if (HalpAcpiSrat)
831 {
832 DPRINT1("Your machine has a SRAT, but NUMA/HotPlug are not supported!\n");
833 }
834
835 /* Can there be memory higher than 4GB? */
836 if (HalpMaxHotPlugMemoryAddress.HighPart >= 1)
837 {
838 /* We'll need this for DMA later */
839 HalpPhysicalMemoryMayAppearAbove4GB = TRUE;
840 }
841
842 /* Setup the ACPI timer */
843 HaliAcpiTimerInit(0, 0);
844
845 /* Do we have a low stub address yet? */
846 if (!HalpLowStubPhysicalAddress.LowPart)
847 {
848 /* Allocate it */
849 HalpLowStubPhysicalAddress.LowPart = HalpAllocPhysicalMemory(LoaderBlock,
850 0x100000,
851 1,
852 FALSE);
853 if (HalpLowStubPhysicalAddress.LowPart)
854 {
855 /* Map it */
856 HalpLowStub = HalpMapPhysicalMemory64(HalpLowStubPhysicalAddress, 1);
857 }
858 }
859
860 /* Grab a page for flushes */
861 PhysicalAddress.QuadPart = 0x100000;
862 HalpVirtAddrForFlush = HalpMapPhysicalMemory64(PhysicalAddress, 1);
863 HalpPteForFlush = HalAddressToPte(HalpVirtAddrForFlush);
864
865 /* Don't do this again */
866 HalpProcessedACPIPhase0 = TRUE;
867
868 /* Setup the boot table */
869 HalpInitBootTable(LoaderBlock);
870
871 /* Return success */
872 return STATUS_SUCCESS;
873 }
874
875 VOID
876 NTAPI
877 HalpInitializePciBus(VOID)
878 {
879 /* Setup the PCI stub support */
880 HalpInitializePciStubs();
881
882 /* Set the NMI crash flag */
883 HalpGetNMICrashFlag();
884 }
885
886 VOID
887 NTAPI
888 HalpInitNonBusHandler(VOID)
889 {
890 /* These should be written by the PCI driver later, but we give defaults */
891 HalPciTranslateBusAddress = HalpTranslateBusAddress;
892 HalPciAssignSlotResources = HalpAssignSlotResources;
893 HalFindBusAddressTranslation = HalpFindBusAddressTranslation;
894 }
895
896 VOID
897 NTAPI
898 HalpInitBusHandlers(VOID)
899 {
900 /* On ACPI, we only have a fake PCI bus to worry about */
901 HalpInitNonBusHandler();
902 }
903
904 VOID
905 NTAPI
906 HalpBuildAddressMap(VOID)
907 {
908 /* ACPI is magic baby */
909 }
910
911 BOOLEAN
912 NTAPI
913 HalpGetDebugPortTable(VOID)
914 {
915 return ((HalpDebugPortTable) &&
916 (HalpDebugPortTable->BaseAddress.AddressSpaceID == 1));
917 }
918
919 ULONG
920 NTAPI
921 HalpIs16BitPortDecodeSupported(VOID)
922 {
923 /* All ACPI systems are at least "EISA" so they support this */
924 return CM_RESOURCE_PORT_16_BIT_DECODE;
925 }
926
927 VOID
928 NTAPI
929 HalpAcpiDetectResourceListSize(OUT PULONG ListSize)
930 {
931 PAGED_CODE();
932
933 /* One element if there is a SCI */
934 *ListSize = HalpFixedAcpiDescTable.sci_int_vector ? 1: 0;
935 }
936
937 NTSTATUS
938 NTAPI
939 HalpBuildAcpiResourceList(IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceList)
940 {
941 ULONG Interrupt;
942 PAGED_CODE();
943 ASSERT(ResourceList != NULL);
944
945 /* Initialize the list */
946 ResourceList->BusNumber = -1;
947 ResourceList->AlternativeLists = 1;
948 ResourceList->InterfaceType = PNPBus;
949 ResourceList->List[0].Version = 1;
950 ResourceList->List[0].Revision = 1;
951 ResourceList->List[0].Count = 0;
952
953 /* Is there a SCI? */
954 if (HalpFixedAcpiDescTable.sci_int_vector)
955 {
956 /* Fill out the entry for it */
957 ResourceList->List[0].Descriptors[0].Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
958 ResourceList->List[0].Descriptors[0].Type = CmResourceTypeInterrupt;
959 ResourceList->List[0].Descriptors[0].ShareDisposition = CmResourceShareShared;
960
961 /* Get the interrupt number */
962 Interrupt = HalpPicVectorRedirect[HalpFixedAcpiDescTable.sci_int_vector];
963 ResourceList->List[0].Descriptors[0].u.Interrupt.MinimumVector = Interrupt;
964 ResourceList->List[0].Descriptors[0].u.Interrupt.MaximumVector = Interrupt;
965
966 /* One more */
967 ++ResourceList->List[0].Count;
968 }
969
970 /* All good */
971 return STATUS_SUCCESS;
972 }
973
974 NTSTATUS
975 NTAPI
976 HalpQueryAcpiResourceRequirements(OUT PIO_RESOURCE_REQUIREMENTS_LIST *Requirements)
977 {
978 PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
979 ULONG Count = 0, ListSize;
980 NTSTATUS Status;
981 PAGED_CODE();
982
983 /* Get ACPI resources */
984 HalpAcpiDetectResourceListSize(&Count);
985 DPRINT("Resource count: %d\n", Count);
986
987 /* Compute size of the list and allocate it */
988 ListSize = FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List[0].Descriptors) +
989 (Count * sizeof(IO_RESOURCE_DESCRIPTOR));
990 DPRINT("Resource list size: %d\n", ListSize);
991 RequirementsList = ExAllocatePoolWithTag(PagedPool, ListSize, ' laH');
992 if (RequirementsList)
993 {
994 /* Initialize it */
995 RtlZeroMemory(RequirementsList, ListSize);
996 RequirementsList->ListSize = ListSize;
997
998 /* Build it */
999 Status = HalpBuildAcpiResourceList(RequirementsList);
1000 if (NT_SUCCESS(Status))
1001 {
1002 /* It worked, return it */
1003 *Requirements = RequirementsList;
1004
1005 /* Validate the list */
1006 ASSERT(RequirementsList->List[0].Count == Count);
1007 }
1008 else
1009 {
1010 /* Fail */
1011 ExFreePoolWithTag(RequirementsList, ' laH');
1012 Status = STATUS_NO_SUCH_DEVICE;
1013 }
1014 }
1015 else
1016 {
1017 /* Not enough memory */
1018 Status = STATUS_INSUFFICIENT_RESOURCES;
1019 }
1020
1021 /* Return the status */
1022 return Status;
1023 }
1024
1025 /*
1026 * @implemented
1027 */
1028 VOID
1029 NTAPI
1030 HalReportResourceUsage(VOID)
1031 {
1032 INTERFACE_TYPE InterfaceType;
1033 UNICODE_STRING HalString;
1034
1035 /* FIXME: Initialize DMA 64-bit support */
1036
1037 /* FIXME: Initialize MCA bus */
1038
1039 /* Initialize PCI bus. */
1040 HalpInitializePciBus();
1041
1042 /* What kind of bus is this? */
1043 switch (HalpBusType)
1044 {
1045 /* ISA Machine */
1046 case MACHINE_TYPE_ISA:
1047 InterfaceType = Isa;
1048 break;
1049
1050 /* EISA Machine */
1051 case MACHINE_TYPE_EISA:
1052 InterfaceType = Eisa;
1053 break;
1054
1055 /* MCA Machine */
1056 case MACHINE_TYPE_MCA:
1057 InterfaceType = MicroChannel;
1058 break;
1059
1060 /* Unknown */
1061 default:
1062 InterfaceType = Internal;
1063 break;
1064 }
1065
1066 /* Build HAL usage */
1067 RtlInitUnicodeString(&HalString, HalName);
1068 HalpReportResourceUsage(&HalString, InterfaceType);
1069
1070 /* Setup PCI debugging and Hibernation */
1071 HalpRegisterPciDebuggingDeviceInfo();
1072 }
1073
1074 /* EOF */