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