Merge illumos-gate
[unleashed/lotheac.git] / usr / src / cmd / acpi / acpidump / osillumostbl.c
blob26fb8d75774998ab666ff521bef9e7e4aa66fc0a
1 /*
3 * Module Name: osillumostbl - illumos OSL for obtaining ACPI tables
4 * This file is derived from the Intel oslinuxtbl source file.
6 */
8 /*
9 * Copyright (C) 2000 - 2016, Intel Corp.
10 * All rights reserved.
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions, and the following disclaimer,
17 * without modification.
18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19 * substantially similar to the "NO WARRANTY" disclaimer below
20 * ("Disclaimer") and any redistribution must be conditioned upon
21 * including a substantially similar Disclaimer requirement for further
22 * binary redistribution.
23 * 3. Neither the names of the above-listed copyright holders nor the names
24 * of any contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
27 * Alternatively, this software may be distributed under the terms of the
28 * GNU General Public License ("GPL") version 2 as published by the Free
29 * Software Foundation.
31 * NO WARRANTY
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 * POSSIBILITY OF SUCH DAMAGES.
46 * Copyright (c) 2018, Joyent, Inc.
49 #include <stdarg.h>
50 #include <string.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include <libdevinfo.h>
54 #include "acpidump.h"
56 #define _COMPONENT ACPI_OS_SERVICES
57 ACPI_MODULE_NAME("osillumostbl")
59 /* List of information about obtained ACPI tables */
61 typedef struct osl_table_info
63 struct osl_table_info *Next;
64 UINT32 Instance;
65 char Signature[ACPI_NAME_SIZE];
66 } OSL_TABLE_INFO;
68 /* Local prototypes */
69 static ACPI_STATUS
70 OslTableInitialize(void);
71 static ACPI_STATUS OslTableNameFromFile(char *, char *, UINT32 *);
72 static ACPI_STATUS OslAddTableToList(char *);
73 static ACPI_STATUS OslMapTable(ACPI_SIZE, char *, ACPI_TABLE_HEADER **);
74 static void OslUnmapTable(ACPI_TABLE_HEADER *);
75 static ACPI_STATUS OslLoadRsdp(void);
76 static ACPI_STATUS OslListBiosTables(void);
77 static ACPI_STATUS OslGetBiosTable(char *, UINT32, ACPI_TABLE_HEADER **,
78 ACPI_PHYSICAL_ADDRESS *);
79 static ACPI_STATUS OslGetLastStatus(ACPI_STATUS);
81 static int pagesize;
83 /* Initialization flags */
84 UINT8 Gbl_TableListInitialized = FALSE;
86 /* Local copies of main ACPI tables */
87 ACPI_TABLE_RSDP Gbl_Rsdp;
88 ACPI_TABLE_FADT *Gbl_Fadt = NULL;
89 ACPI_TABLE_RSDT *Gbl_Rsdt = NULL;
90 ACPI_TABLE_XSDT *Gbl_Xsdt = NULL;
92 /* Table addresses */
93 ACPI_PHYSICAL_ADDRESS Gbl_FadtAddress = 0;
94 ACPI_PHYSICAL_ADDRESS Gbl_RsdpAddress = 0;
96 /* Revision of RSD PTR */
97 UINT8 Gbl_Revision = 0;
99 OSL_TABLE_INFO *Gbl_TableListHead = NULL;
100 UINT32 Gbl_TableCount = 0;
104 * FUNCTION: OslGetLastStatus
106 * PARAMETERS: DefaultStatus - Default error status to return
108 * RETURN: Status; Converted from errno.
110 * DESCRIPTION: Get last errno and conver it to ACPI_STATUS.
113 static ACPI_STATUS
114 OslGetLastStatus(ACPI_STATUS DefaultStatus)
116 switch (errno) {
117 case EACCES:
118 case EPERM:
119 return (AE_ACCESS);
121 case ENOENT:
122 return (AE_NOT_FOUND);
124 case ENOMEM:
125 return (AE_NO_MEMORY);
127 default:
128 return (DefaultStatus);
134 * FUNCTION: AcpiOsGetTableByAddress
136 * PARAMETERS: Address - Physical address of the ACPI table
137 * Table - Where a pointer to the table is returned
139 * RETURN: Status; Table buffer is returned if AE_OK.
140 * AE_NOT_FOUND: A valid table was not found at the address
142 * DESCRIPTION: Get an ACPI table via a physical memory address.
145 ACPI_STATUS
146 AcpiOsGetTableByAddress(ACPI_PHYSICAL_ADDRESS Address,
147 ACPI_TABLE_HEADER **Table)
149 UINT32 TableLength;
150 ACPI_TABLE_HEADER *MappedTable;
151 ACPI_TABLE_HEADER *LocalTable = NULL;
152 ACPI_STATUS Status = AE_OK;
155 * Get main ACPI tables from memory on first invocation of this
156 * function
158 Status = OslTableInitialize();
159 if (ACPI_FAILURE(Status)) {
160 return (Status);
163 /* Map the table and validate it */
165 Status = OslMapTable(Address, NULL, &MappedTable);
166 if (ACPI_FAILURE(Status)) {
167 return (Status);
170 /* Copy table to local buffer and return it */
172 TableLength = ApGetTableLength(MappedTable);
173 if (TableLength == 0) {
174 Status = AE_BAD_HEADER;
175 goto Exit;
178 LocalTable = calloc(1, TableLength);
179 if (!LocalTable) {
180 Status = AE_NO_MEMORY;
181 goto Exit;
184 memcpy(LocalTable, MappedTable, TableLength);
186 Exit:
187 OslUnmapTable(MappedTable);
188 *Table = LocalTable;
189 return (Status);
194 * FUNCTION: AcpiOsGetTableByName
196 * PARAMETERS: Signature - ACPI Signature for desired table. Must be
197 * a null terminated 4-character string.
198 * Instance - Multiple table support for SSDT/UEFI (0...n)
199 * Must be 0 for other tables.
200 * Table - Where a pointer to the table is returned
201 * Address - Where the table physical address is returned
203 * RETURN: Status; Table buffer and physical address returned if AE_OK.
204 * AE_LIMIT: Instance is beyond valid limit
205 * AE_NOT_FOUND: A table with the signature was not found
207 * NOTE: Assumes the input signature is uppercase.
210 ACPI_STATUS
211 AcpiOsGetTableByName(char *Signature, UINT32 Instance,
212 ACPI_TABLE_HEADER **Table, ACPI_PHYSICAL_ADDRESS *Address)
214 ACPI_STATUS Status;
217 * Get main ACPI tables from memory on first invocation of this
218 * function
220 Status = OslTableInitialize();
221 if (ACPI_FAILURE(Status)) {
222 return (Status);
225 /* attempt to extract it from the RSDT/XSDT */
226 Status = OslGetBiosTable(Signature, Instance, Table, Address);
228 return (Status);
233 * FUNCTION: OslAddTableToList
235 * PARAMETERS: Signature - Table signature
237 * RETURN: Status; Successfully added if AE_OK.
238 * AE_NO_MEMORY: Memory allocation error
240 * DESCRIPTION: Insert a table structure into OSL table list.
243 static ACPI_STATUS
244 OslAddTableToList(char *Signature)
246 OSL_TABLE_INFO *NewInfo;
247 OSL_TABLE_INFO *Next;
248 UINT32 NextInstance = 0;
249 UINT32 Instance = 0;
250 BOOLEAN Found = FALSE;
252 NewInfo = calloc(1, sizeof (OSL_TABLE_INFO));
253 if (NewInfo == NULL) {
254 return (AE_NO_MEMORY);
257 ACPI_MOVE_NAME(NewInfo->Signature, Signature);
259 if (!Gbl_TableListHead) {
260 Gbl_TableListHead = NewInfo;
261 } else {
262 Next = Gbl_TableListHead;
264 while (1) {
265 if (ACPI_COMPARE_NAME(Next->Signature, Signature)) {
266 if (Next->Instance == 0) {
267 Found = TRUE;
269 if (Next->Instance >= NextInstance) {
270 NextInstance = Next->Instance + 1;
274 if (!Next->Next) {
275 break;
277 Next = Next->Next;
279 Next->Next = NewInfo;
282 if (Found) {
283 Instance = NextInstance;
286 NewInfo->Instance = Instance;
287 Gbl_TableCount++;
289 return (AE_OK);
294 * FUNCTION: AcpiOsGetTableByIndex
296 * PARAMETERS: Index - Which table to get
297 * Table - Where a pointer to the table is returned
298 * Instance - Where a pointer to the table instance no. is
299 * returned
300 * Address - Where the table physical address is returned
302 * RETURN: Status; Table buffer and physical address returned if AE_OK.
303 * AE_LIMIT: Index is beyond valid limit
305 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
306 * AE_LIMIT when an invalid index is reached. Index is not
307 * necessarily an index into the RSDT/XSDT.
310 ACPI_STATUS
311 AcpiOsGetTableByIndex(UINT32 Index, ACPI_TABLE_HEADER **Table,
312 UINT32 *Instance, ACPI_PHYSICAL_ADDRESS *Address)
314 OSL_TABLE_INFO *Info;
315 ACPI_STATUS Status;
316 UINT32 i;
319 * Get main ACPI tables from memory on first invocation of this
320 * function.
323 Status = OslTableInitialize();
324 if (ACPI_FAILURE(Status)) {
325 return (Status);
328 /* Validate Index */
330 if (Index >= Gbl_TableCount) {
331 return (AE_LIMIT);
334 /* Point to the table list entry specified by the Index argument */
336 Info = Gbl_TableListHead;
337 for (i = 0; i < Index; i++) {
338 Info = Info->Next;
341 /* Now we can just get the table via the signature */
343 Status = AcpiOsGetTableByName(Info->Signature, Info->Instance,
344 Table, Address);
346 if (ACPI_SUCCESS(Status)) {
347 *Instance = Info->Instance;
349 return (Status);
354 * FUNCTION: OslLoadRsdp
356 * PARAMETERS: None
358 * RETURN: Status
360 * DESCRIPTION: Scan and load RSDP.
361 * See the find_rsdp() function in usr/src/uts/i86pc/os/fakebop.c, which is how
362 * the kernel finds the RSDP. That algorithm matches AcpiFindRootPointer().
364 * If the system is not using BIOS, and ACPI information was passed to the
365 * system from the boot loader, then the RSDP is recorded in the "acpi-root-tab"
366 * property.
368 * The code here is derived from AcpiFindRootPointer, except that we will
369 * try the "acpi-root-tab" property first. If the property does not exist or
370 * we do not find the root, then we scan the EBDA. Finally, we will search
371 * the BIOS and copy the table if found.
373 static ACPI_STATUS
374 OslLoadRsdp(void)
376 UINT8 *mapp = NULL;
377 ACPI_TABLE_HEADER *tblp;
378 ACPI_SIZE mapsize = sizeof (ACPI_TABLE_RSDP);
379 ACPI_PHYSICAL_ADDRESS physaddr;
380 di_node_t root;
381 int64_t *val64;
383 if ((root = di_init("/", DINFOPROP)) != DI_NODE_NIL) {
384 if (di_prop_lookup_int64(DDI_DEV_T_ANY, root,
385 "acpi-root-tab", &val64) == 1) {
386 physaddr = (ACPI_PHYSICAL_ADDRESS)*val64;
387 mapp = AcpiOsMapMemory(physaddr, mapsize);
389 di_fini(root);
392 if (mapp != NULL) {
393 tblp = ACPI_CAST_PTR(ACPI_TABLE_HEADER,
394 AcpiTbScanMemoryForRsdp(mapp, mapsize));
395 if (tblp != NULL) {
396 physaddr += (ACPI_PHYSICAL_ADDRESS)
397 ACPI_PTR_DIFF(tblp, mapp);
398 Gbl_RsdpAddress = physaddr;
399 memcpy(&Gbl_Rsdp, tblp, sizeof (ACPI_TABLE_RSDP));
400 AcpiOsUnmapMemory(mapp, mapsize);
401 return (AE_OK);
403 AcpiOsUnmapMemory(mapp, mapsize);
406 /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
407 mapp = AcpiOsMapMemory((ACPI_PHYSICAL_ADDRESS)ACPI_EBDA_PTR_LOCATION,
408 ACPI_EBDA_PTR_LENGTH);
409 if (mapp == NULL)
410 goto try_bios;
412 ACPI_MOVE_16_TO_32(&physaddr, mapp);
414 /* Convert segment part to physical address */
415 physaddr <<= 4;
416 AcpiOsUnmapMemory(mapp, ACPI_EBDA_PTR_LENGTH);
418 /* EBDA present? */
419 if (physaddr <= 0x400)
420 goto try_bios;
423 * 1b) Search EBDA paragraphs (EBDA is required to be a minimum of 1K
424 * length)
426 mapp = AcpiOsMapMemory(physaddr, ACPI_EBDA_WINDOW_SIZE);
427 if (mapp == NULL) {
428 (void) fprintf(stderr, "EBDA (0x%p) found, but is not "
429 "mappable\n", physaddr);
430 goto try_bios;
433 tblp = ACPI_CAST_PTR(ACPI_TABLE_HEADER,
434 AcpiTbScanMemoryForRsdp(mapp, ACPI_EBDA_WINDOW_SIZE));
435 if (tblp != NULL) {
436 physaddr += (ACPI_PHYSICAL_ADDRESS) ACPI_PTR_DIFF(tblp, mapp);
437 Gbl_RsdpAddress = physaddr;
438 memcpy(&Gbl_Rsdp, tblp, sizeof (ACPI_TABLE_RSDP));
439 AcpiOsUnmapMemory(mapp, ACPI_EBDA_WINDOW_SIZE);
441 return (AE_OK);
443 AcpiOsUnmapMemory(mapp, ACPI_EBDA_WINDOW_SIZE);
445 try_bios:
446 /* Try to get RSDP from BIOS memory */
447 if (Gbl_RsdpBase != 0) {
448 physaddr = Gbl_RsdpBase;
449 mapsize = sizeof (ACPI_TABLE_RSDP);
450 } else {
451 physaddr = ACPI_HI_RSDP_WINDOW_BASE;
452 mapsize = ACPI_HI_RSDP_WINDOW_SIZE;
455 mapp = AcpiOsMapMemory(physaddr, mapsize);
456 if (mapp == NULL)
457 return (OslGetLastStatus(AE_BAD_ADDRESS));
459 /* Search low memory for the RSDP */
460 tblp = ACPI_CAST_PTR(ACPI_TABLE_HEADER,
461 AcpiTbScanMemoryForRsdp(mapp, mapsize));
462 if (tblp == NULL) {
463 AcpiOsUnmapMemory(mapp, mapsize);
464 return (AE_NOT_FOUND);
467 physaddr += (ACPI_PHYSICAL_ADDRESS) ACPI_PTR_DIFF(tblp, mapp);
468 Gbl_RsdpAddress = physaddr;
469 memcpy(&Gbl_Rsdp, tblp, sizeof (ACPI_TABLE_RSDP));
470 AcpiOsUnmapMemory(mapp, mapsize);
472 return (AE_OK);
477 * FUNCTION: OslCanUseXsdt
479 * PARAMETERS: None
481 * RETURN: TRUE if XSDT is allowed to be used.
483 * DESCRIPTION: This function collects logic that can be used to determine if
484 * XSDT should be used instead of RSDT.
487 static BOOLEAN
488 OslCanUseXsdt(void)
490 if (Gbl_Revision && !AcpiGbl_DoNotUseXsdt) {
491 return (TRUE);
492 } else {
493 return (FALSE);
499 * FUNCTION: OslTableInitialize
501 * PARAMETERS: None
503 * RETURN: Status
505 * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
506 * local variables. Main ACPI tables include RSDT, FADT, RSDT,
507 * and/or XSDT.
510 static ACPI_STATUS
511 OslTableInitialize(void)
513 ACPI_STATUS Status;
514 ACPI_PHYSICAL_ADDRESS Address;
516 if (Gbl_TableListInitialized) {
517 return (AE_OK);
520 /* Get RSDP from memory */
522 Status = OslLoadRsdp();
523 if (ACPI_FAILURE(Status)) {
524 return (Status);
527 /* Get XSDT from memory */
529 if (Gbl_Rsdp.Revision && !Gbl_DoNotDumpXsdt) {
530 if (Gbl_Xsdt) {
531 free(Gbl_Xsdt);
532 Gbl_Xsdt = NULL;
535 Gbl_Revision = 2;
536 Status = OslGetBiosTable(ACPI_SIG_XSDT, 0,
537 ACPI_CAST_PTR(ACPI_TABLE_HEADER *, &Gbl_Xsdt), &Address);
538 if (ACPI_FAILURE(Status)) {
539 return (Status);
543 /* Get RSDT from memory */
545 if (Gbl_Rsdp.RsdtPhysicalAddress) {
546 if (Gbl_Rsdt) {
547 free(Gbl_Rsdt);
548 Gbl_Rsdt = NULL;
551 Status = OslGetBiosTable(ACPI_SIG_RSDT, 0,
552 ACPI_CAST_PTR(ACPI_TABLE_HEADER *, &Gbl_Rsdt), &Address);
553 if (ACPI_FAILURE(Status)) {
554 return (Status);
558 /* Get FADT from memory */
560 if (Gbl_Fadt) {
561 free(Gbl_Fadt);
562 Gbl_Fadt = NULL;
565 Status = OslGetBiosTable(ACPI_SIG_FADT, 0,
566 ACPI_CAST_PTR(ACPI_TABLE_HEADER *, &Gbl_Fadt), &Gbl_FadtAddress);
567 if (ACPI_FAILURE(Status)) {
568 return (Status);
571 /* Add mandatory tables to global table list first */
573 Status = OslAddTableToList(ACPI_RSDP_NAME);
574 if (ACPI_FAILURE(Status)) {
575 return (Status);
578 Status = OslAddTableToList(ACPI_SIG_RSDT);
579 if (ACPI_FAILURE(Status)) {
580 return (Status);
583 if (Gbl_Revision == 2) {
584 Status = OslAddTableToList(ACPI_SIG_XSDT);
585 if (ACPI_FAILURE(Status)) {
586 return (Status);
590 Status = OslAddTableToList(ACPI_SIG_DSDT);
591 if (ACPI_FAILURE(Status)) {
592 return (Status);
595 Status = OslAddTableToList(ACPI_SIG_FACS);
596 if (ACPI_FAILURE(Status)) {
597 return (Status);
600 /* Add all tables found in the memory */
602 Status = OslListBiosTables();
603 if (ACPI_FAILURE(Status)) {
604 return (Status);
607 Gbl_TableListInitialized = TRUE;
608 return (AE_OK);
614 * FUNCTION: OslListBiosTables
616 * PARAMETERS: None
618 * RETURN: Status; Table list is initialized if AE_OK.
620 * DESCRIPTION: Add ACPI tables to the table list from memory.
622 static ACPI_STATUS
623 OslListBiosTables(void)
625 ACPI_TABLE_HEADER *MappedTable = NULL;
626 UINT8 *TableData;
627 UINT32 NumberOfTables;
628 UINT8 ItemSize;
629 ACPI_PHYSICAL_ADDRESS TableAddress = 0;
630 ACPI_STATUS Status = AE_OK;
631 UINT32 i;
633 if (OslCanUseXsdt()) {
634 ItemSize = sizeof (UINT64);
635 TableData = ACPI_CAST8(Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER);
636 NumberOfTables = (UINT32)
637 ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
638 / ItemSize);
640 } else {
641 /* Use RSDT if XSDT is not available */
642 ItemSize = sizeof (UINT32);
643 TableData = ACPI_CAST8(Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER);
644 NumberOfTables = (UINT32)
645 ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
646 / ItemSize);
649 /* Search RSDT/XSDT for the requested table */
651 for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) {
652 if (OslCanUseXsdt()) {
653 TableAddress =
654 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64(TableData));
655 } else {
656 TableAddress =
657 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32(TableData));
660 /* Skip NULL entries in RSDT/XSDT */
661 if (TableAddress == 0) {
662 continue;
665 Status = OslMapTable(TableAddress, NULL, &MappedTable);
666 if (ACPI_FAILURE(Status)) {
667 return (Status);
670 OslAddTableToList(MappedTable->Signature);
671 OslUnmapTable(MappedTable);
674 return (AE_OK);
679 * FUNCTION: OslGetBiosTable
681 * PARAMETERS: Signature - ACPI Signature for common table. Must be
682 * a null terminated 4-character string.
683 * Instance - Multiple table support for SSDT/UEFI (0...n)
684 * Must be 0 for other tables.
685 * Table - Where a pointer to the table is returned
686 * Address - Where the table physical address is returned
688 * RETURN: Status; Table buffer and physical address returned if AE_OK.
689 * AE_LIMIT: Instance is beyond valid limit
690 * AE_NOT_FOUND: A table with the signature was not found
692 * DESCRIPTION: Get a BIOS provided ACPI table
694 * NOTE: Assumes the input signature is uppercase.
697 static ACPI_STATUS
698 OslGetBiosTable(char *Signature, UINT32 Instance, ACPI_TABLE_HEADER **Table,
699 ACPI_PHYSICAL_ADDRESS *Address)
701 ACPI_TABLE_HEADER *LocalTable = NULL;
702 ACPI_TABLE_HEADER *MappedTable = NULL;
703 UINT8 *TableData;
704 UINT8 NumberOfTables;
705 UINT8 ItemSize;
706 UINT32 CurrentInstance = 0;
707 ACPI_PHYSICAL_ADDRESS TableAddress = 0;
708 UINT32 TableLength = 0;
709 ACPI_STATUS Status = AE_OK;
710 UINT32 i;
712 /* Handle special tables whose addresses are not in RSDT/XSDT */
714 if (ACPI_COMPARE_NAME(Signature, ACPI_RSDP_NAME) ||
715 ACPI_COMPARE_NAME(Signature, ACPI_SIG_RSDT) ||
716 ACPI_COMPARE_NAME(Signature, ACPI_SIG_XSDT) ||
717 ACPI_COMPARE_NAME(Signature, ACPI_SIG_DSDT) ||
718 ACPI_COMPARE_NAME(Signature, ACPI_SIG_FACS)) {
719 if (Instance > 0) {
720 return (AE_LIMIT);
724 * Get the appropriate address, either 32-bit or 64-bit. Be very
725 * careful about the FADT length and validate table addresses.
726 * Note: The 64-bit addresses have priority.
728 if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_DSDT)) {
729 if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) &&
730 Gbl_Fadt->XDsdt) {
731 TableAddress =
732 (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt;
734 } else if (Gbl_Fadt->Header.Length >=
735 MIN_FADT_FOR_DSDT && Gbl_Fadt->Dsdt) {
736 TableAddress =
737 (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt;
740 } else if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_FACS)) {
741 if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) &&
742 Gbl_Fadt->XFacs) {
743 TableAddress =
744 (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs;
746 } else if (Gbl_Fadt->Header.Length >=
747 MIN_FADT_FOR_FACS && Gbl_Fadt->Facs) {
748 TableAddress =
749 (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs;
752 } else if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_XSDT)) {
753 if (!Gbl_Revision) {
754 return (AE_BAD_SIGNATURE);
756 TableAddress = (ACPI_PHYSICAL_ADDRESS)
757 Gbl_Rsdp.XsdtPhysicalAddress;
759 } else if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_RSDT)) {
760 TableAddress = (ACPI_PHYSICAL_ADDRESS)
761 Gbl_Rsdp.RsdtPhysicalAddress;
763 } else {
764 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_RsdpAddress;
765 Signature = ACPI_SIG_RSDP;
768 /* Now we can get the requested special table */
770 Status = OslMapTable(TableAddress, Signature, &MappedTable);
771 if (ACPI_FAILURE(Status)) {
772 return (Status);
775 TableLength = ApGetTableLength(MappedTable);
777 } else {
778 /* Case for a normal ACPI table */
779 if (OslCanUseXsdt()) {
780 ItemSize = sizeof (UINT64);
781 TableData = ACPI_CAST8(Gbl_Xsdt) +
782 sizeof (ACPI_TABLE_HEADER);
783 NumberOfTables = (UINT8) ((Gbl_Xsdt->Header.Length -
784 sizeof (ACPI_TABLE_HEADER))
785 / ItemSize);
787 } else {
788 /* Use RSDT if XSDT is not available */
789 ItemSize = sizeof (UINT32);
790 TableData = ACPI_CAST8(Gbl_Rsdt) +
791 sizeof (ACPI_TABLE_HEADER);
792 NumberOfTables = (UINT8) ((Gbl_Rsdt->Header.Length -
793 sizeof (ACPI_TABLE_HEADER))
794 / ItemSize);
797 /* Search RSDT/XSDT for the requested table */
799 for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) {
800 if (OslCanUseXsdt()) {
801 TableAddress = (ACPI_PHYSICAL_ADDRESS)
802 (*ACPI_CAST64(TableData));
803 } else {
804 TableAddress = (ACPI_PHYSICAL_ADDRESS)
805 (*ACPI_CAST32(TableData));
808 /* Skip NULL entries in RSDT/XSDT */
810 if (TableAddress == 0) {
811 continue;
814 Status = OslMapTable(TableAddress, NULL, &MappedTable);
815 if (ACPI_FAILURE(Status)) {
816 return (Status);
818 TableLength = MappedTable->Length;
820 /* Does this table match the requested signature? */
822 if (!ACPI_COMPARE_NAME(MappedTable->Signature,
823 Signature)) {
824 OslUnmapTable(MappedTable);
825 MappedTable = NULL;
826 continue;
829 /* Match table instance (for SSDT/UEFI tables) */
831 if (CurrentInstance != Instance) {
832 OslUnmapTable(MappedTable);
833 MappedTable = NULL;
834 CurrentInstance++;
835 continue;
838 break;
842 if (MappedTable == NULL) {
843 return (AE_LIMIT);
846 if (TableLength == 0) {
847 Status = AE_BAD_HEADER;
848 goto Exit;
851 /* Copy table to local buffer and return it */
853 LocalTable = calloc(1, TableLength);
854 if (LocalTable == NULL) {
855 Status = AE_NO_MEMORY;
856 goto Exit;
859 memcpy(LocalTable, MappedTable, TableLength);
860 *Address = TableAddress;
861 *Table = LocalTable;
863 Exit:
864 OslUnmapTable(MappedTable);
865 return (Status);
870 * FUNCTION: OslMapTable
872 * PARAMETERS: Address - Address of the table in memory
873 * Signature - Optional ACPI Signature for desired table.
874 * Null terminated 4-character string.
875 * Table - Where a pointer to the mapped table is
876 * returned
878 * RETURN: Status; Mapped table is returned if AE_OK.
879 * AE_NOT_FOUND: A valid table was not found at the address
881 * DESCRIPTION: Map entire ACPI table into caller's address space.
884 static ACPI_STATUS
885 OslMapTable(ACPI_SIZE Address, char *Signature, ACPI_TABLE_HEADER **Table)
887 ACPI_TABLE_HEADER *MappedTable;
888 UINT32 Length;
890 if (Address == 0) {
891 return (AE_BAD_ADDRESS);
895 * Map the header so we can get the table length.
896 * Use sizeof (ACPI_TABLE_HEADER) as:
897 * 1. it is bigger than 24 to include RSDP->Length
898 * 2. it is smaller than sizeof (ACPI_TABLE_RSDP)
900 MappedTable = AcpiOsMapMemory(Address, sizeof (ACPI_TABLE_HEADER));
901 if (MappedTable == NULL) {
902 (void) fprintf(stderr, "Could not map table header at "
903 "0x%8.8X%8.8X\n", ACPI_FORMAT_UINT64(Address));
904 return (OslGetLastStatus(AE_BAD_ADDRESS));
907 /* If specified, signature must match */
909 if (Signature != NULL) {
910 if (ACPI_VALIDATE_RSDP_SIG(Signature)) {
911 if (!ACPI_VALIDATE_RSDP_SIG(MappedTable->Signature)) {
912 AcpiOsUnmapMemory(MappedTable,
913 sizeof (ACPI_TABLE_HEADER));
914 return (AE_BAD_SIGNATURE);
916 } else if (!ACPI_COMPARE_NAME(Signature,
917 MappedTable->Signature)) {
918 AcpiOsUnmapMemory(MappedTable,
919 sizeof (ACPI_TABLE_HEADER));
920 return (AE_BAD_SIGNATURE);
924 /* Map the entire table */
926 Length = ApGetTableLength(MappedTable);
927 AcpiOsUnmapMemory(MappedTable, sizeof (ACPI_TABLE_HEADER));
928 if (Length == 0) {
929 return (AE_BAD_HEADER);
932 MappedTable = AcpiOsMapMemory(Address, Length);
933 if (MappedTable == NULL) {
934 (void) fprintf(stderr, "Could not map table at 0x%8.8X%8.8X "
935 "length %8.8X\n", ACPI_FORMAT_UINT64(Address), Length);
936 return (OslGetLastStatus(AE_INVALID_TABLE_LENGTH));
939 (void) ApIsValidChecksum(MappedTable);
941 *Table = MappedTable;
942 return (AE_OK);
948 * FUNCTION: OslUnmapTable
950 * PARAMETERS: Table - A pointer to the mapped table
952 * RETURN: None
954 * DESCRIPTION: Unmap entire ACPI table.
957 static void
958 OslUnmapTable(ACPI_TABLE_HEADER *Table)
960 if (Table != NULL) {
961 AcpiOsUnmapMemory(Table, ApGetTableLength(Table));
967 * FUNCTION: OslTableNameFromFile
969 * PARAMETERS: Filename - File that contains the desired table
970 * Signature - Pointer to 4-character buffer to store
971 * extracted table signature.
972 * Instance - Pointer to integer to store extracted
973 * table instance number.
975 * RETURN: Status; Table name is extracted if AE_OK.
977 * DESCRIPTION: Extract table signature and instance number from a table file
978 * name.
981 static ACPI_STATUS
982 OslTableNameFromFile(char *Filename, char *Signature, UINT32 *Instance)
984 /* Ignore meaningless files */
986 if (strlen(Filename) < ACPI_NAME_SIZE) {
987 return (AE_BAD_SIGNATURE);
990 /* Extract instance number */
992 if (isdigit((int)Filename[ACPI_NAME_SIZE])) {
993 sscanf(&Filename[ACPI_NAME_SIZE], "%u", Instance);
994 } else if (strlen(Filename) != ACPI_NAME_SIZE) {
995 return (AE_BAD_SIGNATURE);
996 } else {
997 *Instance = 0;
1000 /* Extract signature */
1002 ACPI_MOVE_NAME(Signature, Filename);
1003 return (AE_OK);
1006 void *
1007 AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where, ACPI_SIZE Length)
1009 int fd;
1010 void *p;
1011 ulong_t offset;
1013 if ((fd = open("/dev/xsvc", O_RDONLY)) < 0)
1014 return (NULL);
1016 if (pagesize == 0) {
1017 pagesize = getpagesize();
1020 offset = Where % pagesize;
1021 p = mmap(NULL, Length + offset, PROT_READ, MAP_SHARED | MAP_NORESERVE,
1022 fd, Where - offset);
1024 (void) close(fd);
1026 if (p == MAP_FAILED)
1027 return (NULL);
1028 p = (char *)p + offset;
1029 return (p);
1032 void
1033 AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Size)
1035 ulong_t offset;
1036 void *p;
1038 offset = (ulong_t)LogicalAddress % pagesize;
1039 p = (void *)((char *)LogicalAddress - offset);
1041 (void) munmap(p, Size + offset);