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
OslGetLastStatus(ACPI_STATUS DefaultStatus)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
AcpiOsGetTableByAddress(ACPI_PHYSICAL_ADDRESS Address,ACPI_TABLE_HEADER ** Table)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
AcpiOsGetTableByName(char * Signature,UINT32 Instance,ACPI_TABLE_HEADER ** Table,ACPI_PHYSICAL_ADDRESS * Address)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
OslAddTableToList(char * Signature)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
AcpiOsGetTableByIndex(UINT32 Index,ACPI_TABLE_HEADER ** Table,UINT32 * Instance,ACPI_PHYSICAL_ADDRESS * Address)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
OslLoadRsdp(void)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
OslCanUseXsdt(void)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
OslTableInitialize(void)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
OslListBiosTables(void)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
OslGetBiosTable(char * Signature,UINT32 Instance,ACPI_TABLE_HEADER ** Table,ACPI_PHYSICAL_ADDRESS * Address)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
OslMapTable(ACPI_SIZE Address,char * Signature,ACPI_TABLE_HEADER ** Table)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
OslUnmapTable(ACPI_TABLE_HEADER * Table)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
OslTableNameFromFile(char * Filename,char * Signature,UINT32 * Instance)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 *
AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where,ACPI_SIZE Length)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
AcpiOsUnmapMemory(void * LogicalAddress,ACPI_SIZE Size)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