xref: /reactos/hal/halx86/acpi/halacpi.c (revision c2c66aff)
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 NTSTATUS
790 NTAPI
791 HalpSetupAcpiPhase0(IN PLOADER_PARAMETER_BLOCK LoaderBlock)
792 {
793     NTSTATUS Status;
794     PFADT Fadt;
795     ULONG TableLength;
796     PHYSICAL_ADDRESS PhysicalAddress;
797 
798     /* Only do this once */
799     if (HalpProcessedACPIPhase0) return STATUS_SUCCESS;
800 
801     /* Setup the ACPI table cache */
802     Status = HalpAcpiTableCacheInit(LoaderBlock);
803     if (!NT_SUCCESS(Status)) return Status;
804 
805     /* Grab the FADT */
806     Fadt = HalAcpiGetTable(LoaderBlock, FADT_SIGNATURE);
807     if (!Fadt)
808     {
809         /* Fail */
810         DPRINT1("HAL: Didn't find the FACP\n");
811         return STATUS_NOT_FOUND;
812     }
813 
814     /* Assume typical size, otherwise whatever the descriptor table says */
815     TableLength = sizeof(FADT);
816     if (Fadt->Header.Length < sizeof(FADT)) TableLength = Fadt->Header.Length;
817 
818     /* Copy it in the HAL static buffer */
819     RtlCopyMemory(&HalpFixedAcpiDescTable, Fadt, TableLength);
820 
821     /* Anything special this HAL needs to do? */
822     HalpAcpiDetectMachineSpecificActions(LoaderBlock, &HalpFixedAcpiDescTable);
823 
824     /* Get the debug table for KD */
825     HalpDebugPortTable = HalAcpiGetTable(LoaderBlock, DBGP_SIGNATURE);
826 
827     /* Initialize NUMA through the SRAT */
828     HalpNumaInitializeStaticConfiguration(LoaderBlock);
829 
830     /* Initialize hotplug through the SRAT */
831     HalpDynamicSystemResourceConfiguration(LoaderBlock);
832     if (HalpAcpiSrat)
833     {
834         DPRINT1("Your machine has a SRAT, but NUMA/HotPlug are not supported!\n");
835     }
836 
837     /* Can there be memory higher than 4GB? */
838     if (HalpMaxHotPlugMemoryAddress.HighPart >= 1)
839     {
840         /* We'll need this for DMA later */
841         HalpPhysicalMemoryMayAppearAbove4GB = TRUE;
842     }
843 
844     /* Setup the ACPI timer */
845     HaliAcpiTimerInit(0, 0);
846 
847     /* Do we have a low stub address yet? */
848     if (!HalpLowStubPhysicalAddress.QuadPart)
849     {
850         /* Allocate it */
851         HalpLowStubPhysicalAddress.QuadPart = HalpAllocPhysicalMemory(LoaderBlock,
852                                                                       0x100000,
853                                                                       1,
854                                                                       FALSE);
855         if (HalpLowStubPhysicalAddress.QuadPart)
856         {
857             /* Map it */
858             HalpLowStub = HalpMapPhysicalMemory64(HalpLowStubPhysicalAddress, 1);
859         }
860     }
861 
862     /* Grab a page for flushes */
863     PhysicalAddress.QuadPart = 0x100000;
864     HalpVirtAddrForFlush = HalpMapPhysicalMemory64(PhysicalAddress, 1);
865     HalpPteForFlush = HalAddressToPte(HalpVirtAddrForFlush);
866 
867     /* Don't do this again */
868     HalpProcessedACPIPhase0 = TRUE;
869 
870     /* Setup the boot table */
871     HalpInitBootTable(LoaderBlock);
872 
873     /* Debugging code */
874     {
875         PLIST_ENTRY ListHead, NextEntry;
876         PACPI_CACHED_TABLE CachedTable;
877 
878         /* Loop cached tables */
879         ListHead = &HalpAcpiTableCacheList;
880         NextEntry = ListHead->Flink;
881         while (NextEntry != ListHead)
882         {
883             /* Get the table */
884             CachedTable = CONTAINING_RECORD(NextEntry, ACPI_CACHED_TABLE, Links);
885 
886             /* Compare signatures */
887             if ((CachedTable->Header.Signature == RSDT_SIGNATURE) ||
888                 (CachedTable->Header.Signature == XSDT_SIGNATURE))
889             {
890                 DPRINT1("ACPI %d.0 Detected. Tables: ", (CachedTable->Header.Revision + 1));
891             }
892 
893             DbgPrint("[%c%c%c%c] ",
894                     (CachedTable->Header.Signature & 0xFF),
895                     (CachedTable->Header.Signature & 0xFF00) >> 8,
896                     (CachedTable->Header.Signature & 0xFF0000) >> 16,
897                     (CachedTable->Header.Signature & 0xFF000000) >> 24);
898 
899             /* Keep going */
900             NextEntry = NextEntry->Flink;
901         }
902         DbgPrint("\n");
903     }
904 
905     /* Return success */
906     return STATUS_SUCCESS;
907 }
908 
909 VOID
910 NTAPI
911 HalpInitializePciBus(VOID)
912 {
913     /* Setup the PCI stub support */
914     HalpInitializePciStubs();
915 
916     /* Set the NMI crash flag */
917     HalpGetNMICrashFlag();
918 }
919 
920 VOID
921 NTAPI
922 HalpInitNonBusHandler(VOID)
923 {
924     /* These should be written by the PCI driver later, but we give defaults */
925     HalPciTranslateBusAddress = HalpTranslateBusAddress;
926     HalPciAssignSlotResources = HalpAssignSlotResources;
927     HalFindBusAddressTranslation = HalpFindBusAddressTranslation;
928 }
929 
930 VOID
931 NTAPI
932 HalpInitBusHandlers(VOID)
933 {
934     /* On ACPI, we only have a fake PCI bus to worry about */
935     HalpInitNonBusHandler();
936 }
937 
938 VOID
939 NTAPI
940 HalpBuildAddressMap(VOID)
941 {
942     /* ACPI is magic baby */
943 }
944 
945 BOOLEAN
946 NTAPI
947 HalpGetDebugPortTable(VOID)
948 {
949     return ((HalpDebugPortTable) &&
950             (HalpDebugPortTable->BaseAddress.AddressSpaceID == 1));
951 }
952 
953 ULONG
954 NTAPI
955 HalpIs16BitPortDecodeSupported(VOID)
956 {
957     /* All ACPI systems are at least "EISA" so they support this */
958     return CM_RESOURCE_PORT_16_BIT_DECODE;
959 }
960 
961 VOID
962 NTAPI
963 HalpAcpiDetectResourceListSize(OUT PULONG ListSize)
964 {
965     PAGED_CODE();
966 
967     /* One element if there is a SCI */
968     *ListSize = HalpFixedAcpiDescTable.sci_int_vector ? 1: 0;
969 }
970 
971 NTSTATUS
972 NTAPI
973 HalpBuildAcpiResourceList(IN PIO_RESOURCE_REQUIREMENTS_LIST ResourceList)
974 {
975     ULONG Interrupt;
976     PAGED_CODE();
977     ASSERT(ResourceList != NULL);
978 
979     /* Initialize the list */
980     ResourceList->BusNumber = -1;
981     ResourceList->AlternativeLists = 1;
982     ResourceList->InterfaceType = PNPBus;
983     ResourceList->List[0].Version = 1;
984     ResourceList->List[0].Revision = 1;
985     ResourceList->List[0].Count = 0;
986 
987     /* Is there a SCI? */
988     if (HalpFixedAcpiDescTable.sci_int_vector)
989     {
990         /* Fill out the entry for it */
991         ResourceList->List[0].Descriptors[0].Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
992         ResourceList->List[0].Descriptors[0].Type = CmResourceTypeInterrupt;
993         ResourceList->List[0].Descriptors[0].ShareDisposition = CmResourceShareShared;
994 
995         /* Get the interrupt number */
996         Interrupt = HalpPicVectorRedirect[HalpFixedAcpiDescTable.sci_int_vector];
997         ResourceList->List[0].Descriptors[0].u.Interrupt.MinimumVector = Interrupt;
998         ResourceList->List[0].Descriptors[0].u.Interrupt.MaximumVector = Interrupt;
999 
1000         /* One more */
1001         ++ResourceList->List[0].Count;
1002     }
1003 
1004     /* All good */
1005     return STATUS_SUCCESS;
1006 }
1007 
1008 NTSTATUS
1009 NTAPI
1010 HalpQueryAcpiResourceRequirements(OUT PIO_RESOURCE_REQUIREMENTS_LIST *Requirements)
1011 {
1012     PIO_RESOURCE_REQUIREMENTS_LIST RequirementsList;
1013     ULONG Count = 0, ListSize;
1014     NTSTATUS Status;
1015     PAGED_CODE();
1016 
1017     /* Get ACPI resources */
1018     HalpAcpiDetectResourceListSize(&Count);
1019     DPRINT("Resource count: %d\n", Count);
1020 
1021     /* Compute size of the list and allocate it */
1022     ListSize = FIELD_OFFSET(IO_RESOURCE_REQUIREMENTS_LIST, List[0].Descriptors) +
1023                (Count * sizeof(IO_RESOURCE_DESCRIPTOR));
1024     DPRINT("Resource list size: %d\n", ListSize);
1025     RequirementsList = ExAllocatePoolWithTag(PagedPool, ListSize, TAG_HAL);
1026     if (RequirementsList)
1027     {
1028         /* Initialize it */
1029         RtlZeroMemory(RequirementsList, ListSize);
1030         RequirementsList->ListSize = ListSize;
1031 
1032         /* Build it */
1033         Status = HalpBuildAcpiResourceList(RequirementsList);
1034         if (NT_SUCCESS(Status))
1035         {
1036             /* It worked, return it */
1037             *Requirements = RequirementsList;
1038 
1039             /* Validate the list */
1040             ASSERT(RequirementsList->List[0].Count == Count);
1041         }
1042         else
1043         {
1044             /* Fail */
1045             ExFreePoolWithTag(RequirementsList, TAG_HAL);
1046             Status = STATUS_NO_SUCH_DEVICE;
1047         }
1048     }
1049     else
1050     {
1051         /* Not enough memory */
1052         Status = STATUS_INSUFFICIENT_RESOURCES;
1053     }
1054 
1055     /* Return the status */
1056     return Status;
1057 }
1058 
1059 /*
1060  * @implemented
1061  */
1062 VOID
1063 NTAPI
1064 HalReportResourceUsage(VOID)
1065 {
1066     INTERFACE_TYPE InterfaceType;
1067     UNICODE_STRING HalString;
1068 
1069     /* FIXME: Initialize DMA 64-bit support */
1070 
1071     /* FIXME: Initialize MCA bus */
1072 
1073     /* Initialize PCI bus. */
1074     HalpInitializePciBus();
1075 
1076     /* What kind of bus is this? */
1077     switch (HalpBusType)
1078     {
1079         /* ISA Machine */
1080         case MACHINE_TYPE_ISA:
1081             InterfaceType = Isa;
1082             break;
1083 
1084         /* EISA Machine */
1085         case MACHINE_TYPE_EISA:
1086             InterfaceType = Eisa;
1087             break;
1088 
1089         /* MCA Machine */
1090         case MACHINE_TYPE_MCA:
1091             InterfaceType = MicroChannel;
1092             break;
1093 
1094         /* Unknown */
1095         default:
1096             InterfaceType = Internal;
1097             break;
1098     }
1099 
1100     /* Build HAL usage */
1101     RtlInitUnicodeString(&HalString, HalName);
1102     HalpReportResourceUsage(&HalString, InterfaceType);
1103 
1104     /* Setup PCI debugging and Hibernation */
1105     HalpRegisterPciDebuggingDeviceInfo();
1106 }
1107 
1108 /* EOF */
1109