xref: /illumos-gate/usr/src/cmd/acpi/acpidump/osillumostbl.c (revision 45ede40b2394db7967e59f19288fae9b62efd4aa)
1 /*
2  *
3  * Module Name: osillumostbl - illumos OSL for obtaining ACPI tables
4  * This file is derived from the Intel oslinuxtbl source file.
5  *
6  */
7 
8 /*
9  * Copyright (C) 2000 - 2016, Intel Corp.
10  * All rights reserved.
11  *
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.
26  *
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.
30  *
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.
43  */
44 
45 /*
46  * Copyright (c) 2018, Joyent, Inc.
47  */
48 
49 #include <stdarg.h>
50 #include <string.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include <libdevinfo.h>
54 #include "acpidump.h"
55 
56 #define	_COMPONENT	ACPI_OS_SERVICES
57     ACPI_MODULE_NAME("osillumostbl")
58 
59 /* List of information about obtained ACPI tables */
60 
61 typedef struct osl_table_info
62 {
63 	struct osl_table_info	*Next;
64 	UINT32			Instance;
65 	char			Signature[ACPI_NAME_SIZE];
66 } OSL_TABLE_INFO;
67 
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);
80 
81 static int pagesize;
82 
83 /* Initialization flags */
84 UINT8			Gbl_TableListInitialized = FALSE;
85 
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;
91 
92 /* Table addresses */
93 ACPI_PHYSICAL_ADDRESS	Gbl_FadtAddress = 0;
94 ACPI_PHYSICAL_ADDRESS	Gbl_RsdpAddress = 0;
95 
96 /* Revision of RSD PTR */
97 UINT8			Gbl_Revision = 0;
98 
99 OSL_TABLE_INFO		*Gbl_TableListHead = NULL;
100 UINT32			Gbl_TableCount = 0;
101 
102 /*
103  *
104  * FUNCTION:    OslGetLastStatus
105  *
106  * PARAMETERS:  DefaultStatus   - Default error status to return
107  *
108  * RETURN:      Status; Converted from errno.
109  *
110  * DESCRIPTION: Get last errno and conver it to ACPI_STATUS.
111  *
112  */
113 static ACPI_STATUS
114 OslGetLastStatus(ACPI_STATUS DefaultStatus)
115 {
116 	switch (errno) {
117 	case EACCES:
118 	case EPERM:
119 		return (AE_ACCESS);
120 
121 	case ENOENT:
122 		return (AE_NOT_FOUND);
123 
124 	case ENOMEM:
125 		return (AE_NO_MEMORY);
126 
127 	default:
128 		return (DefaultStatus);
129 	}
130 }
131 
132 /*
133  *
134  * FUNCTION:    AcpiOsGetTableByAddress
135  *
136  * PARAMETERS:  Address         - Physical address of the ACPI table
137  *              Table           - Where a pointer to the table is returned
138  *
139  * RETURN:      Status; Table buffer is returned if AE_OK.
140  *              AE_NOT_FOUND: A valid table was not found at the address
141  *
142  * DESCRIPTION: Get an ACPI table via a physical memory address.
143  *
144  */
145 ACPI_STATUS
146 AcpiOsGetTableByAddress(ACPI_PHYSICAL_ADDRESS Address,
147     ACPI_TABLE_HEADER **Table)
148 {
149 	UINT32			TableLength;
150 	ACPI_TABLE_HEADER	*MappedTable;
151 	ACPI_TABLE_HEADER	*LocalTable = NULL;
152 	ACPI_STATUS		Status = AE_OK;
153 
154 	/*
155 	 * Get main ACPI tables from memory on first invocation of this
156 	 * function
157 	 */
158 	Status = OslTableInitialize();
159 	if (ACPI_FAILURE(Status)) {
160 		return (Status);
161 	}
162 
163 	/* Map the table and validate it */
164 
165 	Status = OslMapTable(Address, NULL, &MappedTable);
166 	if (ACPI_FAILURE(Status)) {
167 		return (Status);
168 	}
169 
170 	/* Copy table to local buffer and return it */
171 
172 	TableLength = ApGetTableLength(MappedTable);
173 	if (TableLength == 0) {
174 		Status = AE_BAD_HEADER;
175 		goto Exit;
176 	}
177 
178 	LocalTable = calloc(1, TableLength);
179 	if (!LocalTable) {
180 		Status = AE_NO_MEMORY;
181 		goto Exit;
182 	}
183 
184 	memcpy(LocalTable, MappedTable, TableLength);
185 
186 Exit:
187 	OslUnmapTable(MappedTable);
188 	*Table = LocalTable;
189 	return (Status);
190 }
191 
192 /*
193  *
194  * FUNCTION:    AcpiOsGetTableByName
195  *
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
202  *
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
206  *
207  * NOTE:        Assumes the input signature is uppercase.
208  *
209  */
210 ACPI_STATUS
211 AcpiOsGetTableByName(char *Signature, UINT32 Instance,
212     ACPI_TABLE_HEADER **Table, ACPI_PHYSICAL_ADDRESS *Address)
213 {
214 	ACPI_STATUS	Status;
215 
216 	/*
217 	 * Get main ACPI tables from memory on first invocation of this
218 	 * function
219 	 */
220 	Status = OslTableInitialize();
221 	if (ACPI_FAILURE(Status)) {
222 		return (Status);
223 	}
224 
225 	/* attempt to extract it from the RSDT/XSDT */
226 	Status = OslGetBiosTable(Signature, Instance, Table, Address);
227 
228 	return (Status);
229 }
230 
231 /*
232  *
233  * FUNCTION:    OslAddTableToList
234  *
235  * PARAMETERS:  Signature       - Table signature
236  *
237  * RETURN:      Status; Successfully added if AE_OK.
238  *              AE_NO_MEMORY: Memory allocation error
239  *
240  * DESCRIPTION: Insert a table structure into OSL table list.
241  *
242  */
243 static ACPI_STATUS
244 OslAddTableToList(char *Signature)
245 {
246 	OSL_TABLE_INFO	*NewInfo;
247 	OSL_TABLE_INFO	*Next;
248 	UINT32		NextInstance = 0;
249 	UINT32		Instance = 0;
250 	BOOLEAN		Found = FALSE;
251 
252 	NewInfo = calloc(1, sizeof (OSL_TABLE_INFO));
253 	if (NewInfo == NULL) {
254 		return (AE_NO_MEMORY);
255 	}
256 
257 	ACPI_MOVE_NAME(NewInfo->Signature, Signature);
258 
259 	if (!Gbl_TableListHead) {
260 		Gbl_TableListHead = NewInfo;
261 	} else {
262 		Next = Gbl_TableListHead;
263 
264 		while (1) {
265 			if (ACPI_COMPARE_NAME(Next->Signature, Signature)) {
266 				if (Next->Instance == 0) {
267 					Found = TRUE;
268 				}
269 				if (Next->Instance >= NextInstance) {
270 					NextInstance = Next->Instance + 1;
271 				}
272 			}
273 
274 			if (!Next->Next) {
275 				break;
276 			}
277 			Next = Next->Next;
278 		}
279 		Next->Next = NewInfo;
280 	}
281 
282 	if (Found) {
283 		Instance = NextInstance;
284 	}
285 
286 	NewInfo->Instance = Instance;
287 	Gbl_TableCount++;
288 
289 	return (AE_OK);
290 }
291 
292 /*
293  *
294  * FUNCTION:    AcpiOsGetTableByIndex
295  *
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
301  *
302  * RETURN:      Status; Table buffer and physical address returned if AE_OK.
303  *              AE_LIMIT: Index is beyond valid limit
304  *
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.
308  *
309  */
310 ACPI_STATUS
311 AcpiOsGetTableByIndex(UINT32 Index, ACPI_TABLE_HEADER **Table,
312     UINT32 *Instance, ACPI_PHYSICAL_ADDRESS *Address)
313 {
314 	OSL_TABLE_INFO	*Info;
315 	ACPI_STATUS	Status;
316 	UINT32		i;
317 
318 	/*
319 	 * Get main ACPI tables from memory on first invocation of this
320 	 * function.
321 	 */
322 
323 	Status = OslTableInitialize();
324 	if (ACPI_FAILURE(Status)) {
325 		return (Status);
326 	}
327 
328 	/* Validate Index */
329 
330 	if (Index >= Gbl_TableCount) {
331 		return (AE_LIMIT);
332 	}
333 
334 	/* Point to the table list entry specified by the Index argument */
335 
336 	Info = Gbl_TableListHead;
337 	for (i = 0; i < Index; i++) {
338 		Info = Info->Next;
339 	}
340 
341 	/* Now we can just get the table via the signature */
342 
343 	Status = AcpiOsGetTableByName(Info->Signature, Info->Instance,
344 	    Table, Address);
345 
346 	if (ACPI_SUCCESS(Status)) {
347 		*Instance = Info->Instance;
348 	}
349 	return (Status);
350 }
351 
352 /*
353  *
354  * FUNCTION:    OslLoadRsdp
355  *
356  * PARAMETERS:  None
357  *
358  * RETURN:      Status
359  *
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().
363  *
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.
367  *
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.
372  */
373 static ACPI_STATUS
374 OslLoadRsdp(void)
375 {
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;
382 
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);
388 		}
389 		di_fini(root);
390 	}
391 
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);
402 		}
403 		AcpiOsUnmapMemory(mapp, mapsize);
404 	}
405 
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;
411 
412 	ACPI_MOVE_16_TO_32(&physaddr, mapp);
413 
414 	/* Convert segment part to physical address */
415 	physaddr <<= 4;
416 	AcpiOsUnmapMemory(mapp, ACPI_EBDA_PTR_LENGTH);
417 
418 	/* EBDA present? */
419 	if (physaddr <= 0x400)
420 		goto try_bios;
421 
422 	/*
423 	 * 1b) Search EBDA paragraphs (EBDA is required to be a minimum of 1K
424 	 * length)
425 	 */
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;
431 	}
432 
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);
440 
441 		return (AE_OK);
442 	}
443 	AcpiOsUnmapMemory(mapp, ACPI_EBDA_WINDOW_SIZE);
444 
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;
453 	}
454 
455 	mapp = AcpiOsMapMemory(physaddr, mapsize);
456 	if (mapp == NULL)
457 		return (OslGetLastStatus(AE_BAD_ADDRESS));
458 
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);
465 	}
466 
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);
471 
472 	return (AE_OK);
473 }
474 
475 /*
476  *
477  * FUNCTION:    OslCanUseXsdt
478  *
479  * PARAMETERS:  None
480  *
481  * RETURN:      TRUE if XSDT is allowed to be used.
482  *
483  * DESCRIPTION: This function collects logic that can be used to determine if
484  *              XSDT should be used instead of RSDT.
485  *
486  */
487 static BOOLEAN
488 OslCanUseXsdt(void)
489 {
490 	if (Gbl_Revision && !AcpiGbl_DoNotUseXsdt) {
491 		return (TRUE);
492 	} else {
493 		return (FALSE);
494 	}
495 }
496 
497 /*
498  *
499  * FUNCTION:    OslTableInitialize
500  *
501  * PARAMETERS:  None
502  *
503  * RETURN:      Status
504  *
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.
508  *
509  */
510 static ACPI_STATUS
511 OslTableInitialize(void)
512 {
513 	ACPI_STATUS		Status;
514 	ACPI_PHYSICAL_ADDRESS	Address;
515 
516 	if (Gbl_TableListInitialized) {
517 		return (AE_OK);
518 	}
519 
520 	/* Get RSDP from memory */
521 
522 	Status = OslLoadRsdp();
523 	if (ACPI_FAILURE(Status)) {
524 		return (Status);
525 	}
526 
527 	/* Get XSDT from memory */
528 
529 	if (Gbl_Rsdp.Revision && !Gbl_DoNotDumpXsdt) {
530 		if (Gbl_Xsdt) {
531 			free(Gbl_Xsdt);
532 			Gbl_Xsdt = NULL;
533 		}
534 
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);
540 		}
541 	}
542 
543 	/* Get RSDT from memory */
544 
545 	if (Gbl_Rsdp.RsdtPhysicalAddress) {
546 		if (Gbl_Rsdt) {
547 			free(Gbl_Rsdt);
548 			Gbl_Rsdt = NULL;
549 		}
550 
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);
555 		}
556 	}
557 
558 	/* Get FADT from memory */
559 
560 	if (Gbl_Fadt) {
561 		free(Gbl_Fadt);
562 		Gbl_Fadt = NULL;
563 	}
564 
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);
569 	}
570 
571 	/* Add mandatory tables to global table list first */
572 
573 	Status = OslAddTableToList(ACPI_RSDP_NAME);
574 	if (ACPI_FAILURE(Status)) {
575 		return (Status);
576 	}
577 
578 	Status = OslAddTableToList(ACPI_SIG_RSDT);
579 	if (ACPI_FAILURE(Status)) {
580 		return (Status);
581 	}
582 
583 	if (Gbl_Revision == 2) {
584 		Status = OslAddTableToList(ACPI_SIG_XSDT);
585 		if (ACPI_FAILURE(Status)) {
586 			return (Status);
587 		}
588 	}
589 
590 	Status = OslAddTableToList(ACPI_SIG_DSDT);
591 	if (ACPI_FAILURE(Status)) {
592 		return (Status);
593 	}
594 
595 	Status = OslAddTableToList(ACPI_SIG_FACS);
596 	if (ACPI_FAILURE(Status)) {
597 		return (Status);
598 	}
599 
600 	/* Add all tables found in the memory */
601 
602 	Status = OslListBiosTables();
603 	if (ACPI_FAILURE(Status)) {
604 		return (Status);
605 	}
606 
607 	Gbl_TableListInitialized = TRUE;
608 	return (AE_OK);
609 }
610 
611 
612 /*
613  *
614  * FUNCTION:    OslListBiosTables
615  *
616  * PARAMETERS:  None
617  *
618  * RETURN:      Status; Table list is initialized if AE_OK.
619  *
620  * DESCRIPTION: Add ACPI tables to the table list from memory.
621  */
622 static ACPI_STATUS
623 OslListBiosTables(void)
624 {
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;
632 
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);
639 
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);
647 	}
648 
649 	/* Search RSDT/XSDT for the requested table */
650 
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));
658 		}
659 
660 		/* Skip NULL entries in RSDT/XSDT */
661 		if (TableAddress == 0) {
662 			continue;
663 		}
664 
665 		Status = OslMapTable(TableAddress, NULL, &MappedTable);
666 		if (ACPI_FAILURE(Status)) {
667 			return (Status);
668 		}
669 
670 		OslAddTableToList(MappedTable->Signature);
671 		OslUnmapTable(MappedTable);
672 	}
673 
674 	return (AE_OK);
675 }
676 
677 /*
678  *
679  * FUNCTION:    OslGetBiosTable
680  *
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
687  *
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
691  *
692  * DESCRIPTION: Get a BIOS provided ACPI table
693  *
694  * NOTE:        Assumes the input signature is uppercase.
695  *
696  */
697 static ACPI_STATUS
698 OslGetBiosTable(char *Signature, UINT32 Instance, ACPI_TABLE_HEADER **Table,
699     ACPI_PHYSICAL_ADDRESS *Address)
700 {
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;
711 
712 	/* Handle special tables whose addresses are not in RSDT/XSDT */
713 
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);
721 		}
722 
723 		/*
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.
727 		 */
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;
733 
734 			} else if (Gbl_Fadt->Header.Length >=
735 			    MIN_FADT_FOR_DSDT && Gbl_Fadt->Dsdt) {
736 				TableAddress =
737 				    (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt;
738 			}
739 
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;
745 
746 			} else if (Gbl_Fadt->Header.Length >=
747 			    MIN_FADT_FOR_FACS && Gbl_Fadt->Facs) {
748 				TableAddress =
749 				    (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs;
750 			}
751 
752 		} else if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_XSDT)) {
753 			if (!Gbl_Revision) {
754 				return (AE_BAD_SIGNATURE);
755 			}
756 			TableAddress = (ACPI_PHYSICAL_ADDRESS)
757 			    Gbl_Rsdp.XsdtPhysicalAddress;
758 
759 		} else if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_RSDT)) {
760 			TableAddress = (ACPI_PHYSICAL_ADDRESS)
761 			    Gbl_Rsdp.RsdtPhysicalAddress;
762 
763 		} else {
764 			TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_RsdpAddress;
765 			Signature = ACPI_SIG_RSDP;
766 		}
767 
768 		/* Now we can get the requested special table */
769 
770 		Status = OslMapTable(TableAddress, Signature, &MappedTable);
771 		if (ACPI_FAILURE(Status)) {
772 			return (Status);
773 		}
774 
775 		TableLength = ApGetTableLength(MappedTable);
776 
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);
786 
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);
795 		}
796 
797 		/* Search RSDT/XSDT for the requested table */
798 
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));
806 			}
807 
808 			/* Skip NULL entries in RSDT/XSDT */
809 
810 			if (TableAddress == 0) {
811 				continue;
812 			}
813 
814 			Status = OslMapTable(TableAddress, NULL, &MappedTable);
815 			if (ACPI_FAILURE(Status)) {
816 				return (Status);
817 			}
818 			TableLength = MappedTable->Length;
819 
820 			/* Does this table match the requested signature? */
821 
822 			if (!ACPI_COMPARE_NAME(MappedTable->Signature,
823 			    Signature)) {
824 				OslUnmapTable(MappedTable);
825 				MappedTable = NULL;
826 				continue;
827 			}
828 
829 			/* Match table instance (for SSDT/UEFI tables) */
830 
831 			if (CurrentInstance != Instance) {
832 				OslUnmapTable(MappedTable);
833 				MappedTable = NULL;
834 				CurrentInstance++;
835 				continue;
836 			}
837 
838 			break;
839 		}
840 	}
841 
842 	if (MappedTable == NULL) {
843 		return (AE_LIMIT);
844 	}
845 
846 	if (TableLength == 0) {
847 		Status = AE_BAD_HEADER;
848 		goto Exit;
849 	}
850 
851 	/* Copy table to local buffer and return it */
852 
853 	LocalTable = calloc(1, TableLength);
854 	if (LocalTable == NULL) {
855 		Status = AE_NO_MEMORY;
856 		goto Exit;
857 	}
858 
859 	memcpy(LocalTable, MappedTable, TableLength);
860 	*Address = TableAddress;
861 	*Table = LocalTable;
862 
863 Exit:
864 	OslUnmapTable(MappedTable);
865 	return (Status);
866 }
867 
868 /*
869  *
870  * FUNCTION:    OslMapTable
871  *
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
877  *
878  * RETURN:      Status; Mapped table is returned if AE_OK.
879  *              AE_NOT_FOUND: A valid table was not found at the address
880  *
881  * DESCRIPTION: Map entire ACPI table into caller's address space.
882  *
883  */
884 static ACPI_STATUS
885 OslMapTable(ACPI_SIZE Address, char *Signature, ACPI_TABLE_HEADER **Table)
886 {
887 	ACPI_TABLE_HEADER	*MappedTable;
888 	UINT32			Length;
889 
890 	if (Address == 0) {
891 		return (AE_BAD_ADDRESS);
892 	}
893 
894 	/*
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)
899 	 */
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));
905 	}
906 
907 	/* If specified, signature must match */
908 
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);
915 			}
916 		} else if (!ACPI_COMPARE_NAME(Signature,
917 		    MappedTable->Signature)) {
918 			AcpiOsUnmapMemory(MappedTable,
919 			    sizeof (ACPI_TABLE_HEADER));
920 			return (AE_BAD_SIGNATURE);
921 		}
922 	}
923 
924 	/* Map the entire table */
925 
926 	Length = ApGetTableLength(MappedTable);
927 	AcpiOsUnmapMemory(MappedTable, sizeof (ACPI_TABLE_HEADER));
928 	if (Length == 0) {
929 		return (AE_BAD_HEADER);
930 	}
931 
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));
937 	}
938 
939 	(void) ApIsValidChecksum(MappedTable);
940 
941 	*Table = MappedTable;
942 	return (AE_OK);
943 }
944 
945 
946 /*
947  *
948  * FUNCTION:    OslUnmapTable
949  *
950  * PARAMETERS:  Table               - A pointer to the mapped table
951  *
952  * RETURN:      None
953  *
954  * DESCRIPTION: Unmap entire ACPI table.
955  *
956  */
957 static void
958 OslUnmapTable(ACPI_TABLE_HEADER *Table)
959 {
960 	if (Table != NULL) {
961 		AcpiOsUnmapMemory(Table, ApGetTableLength(Table));
962 	}
963 }
964 
965 /*
966  *
967  * FUNCTION:    OslTableNameFromFile
968  *
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.
974  *
975  * RETURN:      Status; Table name is extracted if AE_OK.
976  *
977  * DESCRIPTION: Extract table signature and instance number from a table file
978  *              name.
979  *
980  */
981 static ACPI_STATUS
982 OslTableNameFromFile(char *Filename, char *Signature, UINT32 *Instance)
983 {
984 	/* Ignore meaningless files */
985 
986 	if (strlen(Filename) < ACPI_NAME_SIZE) {
987 		return (AE_BAD_SIGNATURE);
988 	}
989 
990 	/* Extract instance number */
991 
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;
998 	}
999 
1000 	/* Extract signature */
1001 
1002 	ACPI_MOVE_NAME(Signature, Filename);
1003 	return (AE_OK);
1004 }
1005 
1006 void *
1007 AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where, ACPI_SIZE Length)
1008 {
1009 	int fd;
1010 	void *p;
1011 	ulong_t offset;
1012 
1013 	if ((fd = open("/dev/xsvc", O_RDONLY)) < 0)
1014 		return (NULL);
1015 
1016 	if (pagesize == 0) {
1017 		pagesize = getpagesize();
1018 	}
1019 
1020 	offset = Where % pagesize;
1021 	p = mmap(NULL, Length + offset, PROT_READ, MAP_SHARED | MAP_NORESERVE,
1022 	    fd, Where - offset);
1023 
1024 	(void) close(fd);
1025 
1026 	if (p == MAP_FAILED)
1027 		return (NULL);
1028 	p = (char *)p + offset;
1029 	return (p);
1030 }
1031 
1032 void
1033 AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Size)
1034 {
1035 	ulong_t offset;
1036 	void *p;
1037 
1038 	offset = (ulong_t)LogicalAddress % pagesize;
1039 	p = (void *)((char *)LogicalAddress - offset);
1040 
1041 	(void) munmap(p, Size + offset);
1042 }
1043