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 2016 Joyent, Inc.
47 */
48
49 #include <stdarg.h>
50 #include <string.h>
51 #include <stdlib.h>
52 #include <unistd.h>
53 #include "acpidump.h"
54
55 #define _COMPONENT ACPI_OS_SERVICES
56 ACPI_MODULE_NAME("osillumostbl")
57
58 /* List of information about obtained ACPI tables */
59
60 typedef struct osl_table_info
61 {
62 struct osl_table_info *Next;
63 UINT32 Instance;
64 char Signature[ACPI_NAME_SIZE];
65 } OSL_TABLE_INFO;
66
67 /* Local prototypes */
68 static ACPI_STATUS
69 OslTableInitialize(void);
70 static ACPI_STATUS OslTableNameFromFile(char *, char *, UINT32 *);
71 static ACPI_STATUS OslAddTableToList(char *);
72 static ACPI_STATUS OslMapTable(ACPI_SIZE, char *, ACPI_TABLE_HEADER **);
73 static void OslUnmapTable(ACPI_TABLE_HEADER *);
74 static ACPI_STATUS OslLoadRsdp(void);
75 static ACPI_STATUS OslListBiosTables(void);
76 static ACPI_STATUS OslGetBiosTable(char *, UINT32, ACPI_TABLE_HEADER **,
77 ACPI_PHYSICAL_ADDRESS *);
78 static ACPI_STATUS OslGetLastStatus(ACPI_STATUS);
79
80 static int pagesize;
81
82 /* Initialization flags */
83 UINT8 Gbl_TableListInitialized = FALSE;
84
85 /* Local copies of main ACPI tables */
86 ACPI_TABLE_RSDP Gbl_Rsdp;
87 ACPI_TABLE_FADT *Gbl_Fadt = NULL;
88 ACPI_TABLE_RSDT *Gbl_Rsdt = NULL;
89 ACPI_TABLE_XSDT *Gbl_Xsdt = NULL;
90
91 /* Table addresses */
92 ACPI_PHYSICAL_ADDRESS Gbl_FadtAddress = 0;
93 ACPI_PHYSICAL_ADDRESS Gbl_RsdpAddress = 0;
94
95 /* Revision of RSD PTR */
96 UINT8 Gbl_Revision = 0;
97
98 OSL_TABLE_INFO *Gbl_TableListHead = NULL;
99 UINT32 Gbl_TableCount = 0;
100
101 /*
102 *
103 * FUNCTION: OslGetLastStatus
104 *
105 * PARAMETERS: DefaultStatus - Default error status to return
106 *
107 * RETURN: Status; Converted from errno.
108 *
109 * DESCRIPTION: Get last errno and conver it to ACPI_STATUS.
110 *
111 */
112 static ACPI_STATUS
OslGetLastStatus(ACPI_STATUS DefaultStatus)113 OslGetLastStatus(ACPI_STATUS DefaultStatus)
114 {
115 switch (errno) {
116 case EACCES:
117 case EPERM:
118 return (AE_ACCESS);
119
120 case ENOENT:
121 return (AE_NOT_FOUND);
122
123 case ENOMEM:
124 return (AE_NO_MEMORY);
125
126 default:
127 return (DefaultStatus);
128 }
129 }
130
131 /*
132 *
133 * FUNCTION: AcpiOsGetTableByAddress
134 *
135 * PARAMETERS: Address - Physical address of the ACPI table
136 * Table - Where a pointer to the table is returned
137 *
138 * RETURN: Status; Table buffer is returned if AE_OK.
139 * AE_NOT_FOUND: A valid table was not found at the address
140 *
141 * DESCRIPTION: Get an ACPI table via a physical memory address.
142 *
143 */
144 ACPI_STATUS
AcpiOsGetTableByAddress(ACPI_PHYSICAL_ADDRESS Address,ACPI_TABLE_HEADER ** Table)145 AcpiOsGetTableByAddress(ACPI_PHYSICAL_ADDRESS Address,
146 ACPI_TABLE_HEADER **Table)
147 {
148 UINT32 TableLength;
149 ACPI_TABLE_HEADER *MappedTable;
150 ACPI_TABLE_HEADER *LocalTable = NULL;
151 ACPI_STATUS Status = AE_OK;
152
153 /*
154 * Get main ACPI tables from memory on first invocation of this
155 * function
156 */
157 Status = OslTableInitialize();
158 if (ACPI_FAILURE(Status)) {
159 return (Status);
160 }
161
162 /* Map the table and validate it */
163
164 Status = OslMapTable(Address, NULL, &MappedTable);
165 if (ACPI_FAILURE(Status)) {
166 return (Status);
167 }
168
169 /* Copy table to local buffer and return it */
170
171 TableLength = ApGetTableLength(MappedTable);
172 if (TableLength == 0) {
173 Status = AE_BAD_HEADER;
174 goto Exit;
175 }
176
177 LocalTable = calloc(1, TableLength);
178 if (!LocalTable) {
179 Status = AE_NO_MEMORY;
180 goto Exit;
181 }
182
183 memcpy(LocalTable, MappedTable, TableLength);
184
185 Exit:
186 OslUnmapTable(MappedTable);
187 *Table = LocalTable;
188 return (Status);
189 }
190
191 /*
192 *
193 * FUNCTION: AcpiOsGetTableByName
194 *
195 * PARAMETERS: Signature - ACPI Signature for desired table. Must be
196 * a null terminated 4-character string.
197 * Instance - Multiple table support for SSDT/UEFI (0...n)
198 * Must be 0 for other tables.
199 * Table - Where a pointer to the table is returned
200 * Address - Where the table physical address is returned
201 *
202 * RETURN: Status; Table buffer and physical address returned if AE_OK.
203 * AE_LIMIT: Instance is beyond valid limit
204 * AE_NOT_FOUND: A table with the signature was not found
205 *
206 * NOTE: Assumes the input signature is uppercase.
207 *
208 */
209 ACPI_STATUS
AcpiOsGetTableByName(char * Signature,UINT32 Instance,ACPI_TABLE_HEADER ** Table,ACPI_PHYSICAL_ADDRESS * Address)210 AcpiOsGetTableByName(char *Signature, UINT32 Instance,
211 ACPI_TABLE_HEADER **Table, ACPI_PHYSICAL_ADDRESS *Address)
212 {
213 ACPI_STATUS Status;
214
215 /*
216 * Get main ACPI tables from memory on first invocation of this
217 * function
218 */
219 Status = OslTableInitialize();
220 if (ACPI_FAILURE(Status)) {
221 return (Status);
222 }
223
224 /* attempt to extract it from the RSDT/XSDT */
225 Status = OslGetBiosTable(Signature, Instance, Table, Address);
226
227 return (Status);
228 }
229
230 /*
231 *
232 * FUNCTION: OslAddTableToList
233 *
234 * PARAMETERS: Signature - Table signature
235 *
236 * RETURN: Status; Successfully added if AE_OK.
237 * AE_NO_MEMORY: Memory allocation error
238 *
239 * DESCRIPTION: Insert a table structure into OSL table list.
240 *
241 */
242 static ACPI_STATUS
OslAddTableToList(char * Signature)243 OslAddTableToList(char *Signature)
244 {
245 OSL_TABLE_INFO *NewInfo;
246 OSL_TABLE_INFO *Next;
247 UINT32 NextInstance = 0;
248 UINT32 Instance = 0;
249 BOOLEAN Found = FALSE;
250
251 NewInfo = calloc(1, sizeof (OSL_TABLE_INFO));
252 if (NewInfo == NULL) {
253 return (AE_NO_MEMORY);
254 }
255
256 ACPI_MOVE_NAME(NewInfo->Signature, Signature);
257
258 if (!Gbl_TableListHead) {
259 Gbl_TableListHead = NewInfo;
260 } else {
261 Next = Gbl_TableListHead;
262
263 while (1) {
264 if (ACPI_COMPARE_NAME(Next->Signature, Signature)) {
265 if (Next->Instance == 0) {
266 Found = TRUE;
267 }
268 if (Next->Instance >= NextInstance) {
269 NextInstance = Next->Instance + 1;
270 }
271 }
272
273 if (!Next->Next) {
274 break;
275 }
276 Next = Next->Next;
277 }
278 Next->Next = NewInfo;
279 }
280
281 if (Found) {
282 Instance = NextInstance;
283 }
284
285 NewInfo->Instance = Instance;
286 Gbl_TableCount++;
287
288 return (AE_OK);
289 }
290
291 /*
292 *
293 * FUNCTION: AcpiOsGetTableByIndex
294 *
295 * PARAMETERS: Index - Which table to get
296 * Table - Where a pointer to the table is returned
297 * Instance - Where a pointer to the table instance no. is
298 * returned
299 * Address - Where the table physical address is returned
300 *
301 * RETURN: Status; Table buffer and physical address returned if AE_OK.
302 * AE_LIMIT: Index is beyond valid limit
303 *
304 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
305 * AE_LIMIT when an invalid index is reached. Index is not
306 * necessarily an index into the RSDT/XSDT.
307 *
308 */
309 ACPI_STATUS
AcpiOsGetTableByIndex(UINT32 Index,ACPI_TABLE_HEADER ** Table,UINT32 * Instance,ACPI_PHYSICAL_ADDRESS * Address)310 AcpiOsGetTableByIndex(UINT32 Index, ACPI_TABLE_HEADER **Table,
311 UINT32 *Instance, ACPI_PHYSICAL_ADDRESS *Address)
312 {
313 OSL_TABLE_INFO *Info;
314 ACPI_STATUS Status;
315 UINT32 i;
316
317 /*
318 * Get main ACPI tables from memory on first invocation of this
319 * function.
320 */
321
322 Status = OslTableInitialize();
323 if (ACPI_FAILURE(Status)) {
324 return (Status);
325 }
326
327 /* Validate Index */
328
329 if (Index >= Gbl_TableCount) {
330 return (AE_LIMIT);
331 }
332
333 /* Point to the table list entry specified by the Index argument */
334
335 Info = Gbl_TableListHead;
336 for (i = 0; i < Index; i++) {
337 Info = Info->Next;
338 }
339
340 /* Now we can just get the table via the signature */
341
342 Status = AcpiOsGetTableByName(Info->Signature, Info->Instance,
343 Table, Address);
344
345 if (ACPI_SUCCESS(Status)) {
346 *Instance = Info->Instance;
347 }
348 return (Status);
349 }
350
351 /*
352 *
353 * FUNCTION: OslLoadRsdp
354 *
355 * PARAMETERS: None
356 *
357 * RETURN: Status
358 *
359 * DESCRIPTION: Scan and load RSDP.
360 * See the find_rsdp() function in usr/src/uts/i86pc/os/fakebop.c, which is how
361 * the kernel finds the RSDP. That algorithm matches AcpiFindRootPointer().
362 * The code here is derived from AcpiFindRootPointer, except that we will try
363 * the BIOS if the EBDA fails, and we will copy the table if found.
364 */
365 static ACPI_STATUS
OslLoadRsdp(void)366 OslLoadRsdp(void)
367 {
368 UINT8 *mapp;
369 ACPI_TABLE_HEADER *tblp;
370 ACPI_SIZE mapsize;
371 ACPI_PHYSICAL_ADDRESS physaddr;
372
373 /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
374 mapp = AcpiOsMapMemory((ACPI_PHYSICAL_ADDRESS)ACPI_EBDA_PTR_LOCATION,
375 ACPI_EBDA_PTR_LENGTH);
376 if (mapp == NULL)
377 goto try_bios;
378
379 ACPI_MOVE_16_TO_32(&physaddr, mapp);
380
381 /* Convert segment part to physical address */
382 physaddr <<= 4;
383 AcpiOsUnmapMemory(mapp, ACPI_EBDA_PTR_LENGTH);
384
385 /* EBDA present? */
386 if (physaddr <= 0x400)
387 goto try_bios;
388
389 /*
390 * 1b) Search EBDA paragraphs (EBDA is required to be a minimum of 1K
391 * length)
392 */
393 mapp = AcpiOsMapMemory(physaddr, ACPI_EBDA_WINDOW_SIZE);
394 if (mapp == NULL) {
395 (void) fprintf(stderr, "EBDA (0x%p) found, but is not "
396 "mappable\n", physaddr);
397 goto try_bios;
398 }
399
400 tblp = ACPI_CAST_PTR(ACPI_TABLE_HEADER,
401 AcpiTbScanMemoryForRsdp(mapp, ACPI_EBDA_WINDOW_SIZE));
402 if (tblp != NULL) {
403 physaddr += (ACPI_PHYSICAL_ADDRESS) ACPI_PTR_DIFF(tblp, mapp);
404 Gbl_RsdpAddress = physaddr;
405 memcpy(&Gbl_Rsdp, tblp, sizeof (ACPI_TABLE_RSDP));
406 AcpiOsUnmapMemory(mapp, ACPI_EBDA_WINDOW_SIZE);
407
408 return (AE_OK);
409 }
410 AcpiOsUnmapMemory(mapp, ACPI_EBDA_WINDOW_SIZE);
411
412 try_bios:
413 /* Try to get RSDP from BIOS memory */
414 if (Gbl_RsdpBase != NULL) {
415 physaddr = Gbl_RsdpBase;
416 mapsize = sizeof (ACPI_TABLE_RSDP);
417 } else {
418 physaddr = ACPI_HI_RSDP_WINDOW_BASE;
419 mapsize = ACPI_HI_RSDP_WINDOW_SIZE;
420 }
421
422 mapp = AcpiOsMapMemory(physaddr, mapsize);
423 if (mapp == NULL)
424 return (OslGetLastStatus(AE_BAD_ADDRESS));
425
426 /* Search low memory for the RSDP */
427 tblp = ACPI_CAST_PTR(ACPI_TABLE_HEADER,
428 AcpiTbScanMemoryForRsdp(mapp, mapsize));
429 if (tblp == NULL) {
430 AcpiOsUnmapMemory(mapp, mapsize);
431 return (AE_NOT_FOUND);
432 }
433
434 physaddr += (ACPI_PHYSICAL_ADDRESS) ACPI_PTR_DIFF(tblp, mapp);
435 Gbl_RsdpAddress = physaddr;
436 memcpy(&Gbl_Rsdp, tblp, sizeof (ACPI_TABLE_RSDP));
437 AcpiOsUnmapMemory(mapp, mapsize);
438
439 return (AE_OK);
440 }
441
442 /*
443 *
444 * FUNCTION: OslCanUseXsdt
445 *
446 * PARAMETERS: None
447 *
448 * RETURN: TRUE if XSDT is allowed to be used.
449 *
450 * DESCRIPTION: This function collects logic that can be used to determine if
451 * XSDT should be used instead of RSDT.
452 *
453 */
454 static BOOLEAN
OslCanUseXsdt(void)455 OslCanUseXsdt(void)
456 {
457 if (Gbl_Revision && !AcpiGbl_DoNotUseXsdt) {
458 return (TRUE);
459 } else {
460 return (FALSE);
461 }
462 }
463
464 /*
465 *
466 * FUNCTION: OslTableInitialize
467 *
468 * PARAMETERS: None
469 *
470 * RETURN: Status
471 *
472 * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
473 * local variables. Main ACPI tables include RSDT, FADT, RSDT,
474 * and/or XSDT.
475 *
476 */
477 static ACPI_STATUS
OslTableInitialize(void)478 OslTableInitialize(void)
479 {
480 ACPI_STATUS Status;
481 ACPI_PHYSICAL_ADDRESS Address;
482
483 if (Gbl_TableListInitialized) {
484 return (AE_OK);
485 }
486
487 /* Get RSDP from memory */
488
489 Status = OslLoadRsdp();
490 if (ACPI_FAILURE(Status)) {
491 return (Status);
492 }
493
494 /* Get XSDT from memory */
495
496 if (Gbl_Rsdp.Revision && !Gbl_DoNotDumpXsdt) {
497 if (Gbl_Xsdt) {
498 free(Gbl_Xsdt);
499 Gbl_Xsdt = NULL;
500 }
501
502 Gbl_Revision = 2;
503 Status = OslGetBiosTable(ACPI_SIG_XSDT, 0,
504 ACPI_CAST_PTR(ACPI_TABLE_HEADER *, &Gbl_Xsdt), &Address);
505 if (ACPI_FAILURE(Status)) {
506 return (Status);
507 }
508 }
509
510 /* Get RSDT from memory */
511
512 if (Gbl_Rsdp.RsdtPhysicalAddress) {
513 if (Gbl_Rsdt) {
514 free(Gbl_Rsdt);
515 Gbl_Rsdt = NULL;
516 }
517
518 Status = OslGetBiosTable(ACPI_SIG_RSDT, 0,
519 ACPI_CAST_PTR(ACPI_TABLE_HEADER *, &Gbl_Rsdt), &Address);
520 if (ACPI_FAILURE(Status)) {
521 return (Status);
522 }
523 }
524
525 /* Get FADT from memory */
526
527 if (Gbl_Fadt) {
528 free(Gbl_Fadt);
529 Gbl_Fadt = NULL;
530 }
531
532 Status = OslGetBiosTable(ACPI_SIG_FADT, 0,
533 ACPI_CAST_PTR(ACPI_TABLE_HEADER *, &Gbl_Fadt), &Gbl_FadtAddress);
534 if (ACPI_FAILURE(Status)) {
535 return (Status);
536 }
537
538 /* Add mandatory tables to global table list first */
539
540 Status = OslAddTableToList(ACPI_RSDP_NAME);
541 if (ACPI_FAILURE(Status)) {
542 return (Status);
543 }
544
545 Status = OslAddTableToList(ACPI_SIG_RSDT);
546 if (ACPI_FAILURE(Status)) {
547 return (Status);
548 }
549
550 if (Gbl_Revision == 2) {
551 Status = OslAddTableToList(ACPI_SIG_XSDT);
552 if (ACPI_FAILURE(Status)) {
553 return (Status);
554 }
555 }
556
557 Status = OslAddTableToList(ACPI_SIG_DSDT);
558 if (ACPI_FAILURE(Status)) {
559 return (Status);
560 }
561
562 Status = OslAddTableToList(ACPI_SIG_FACS);
563 if (ACPI_FAILURE(Status)) {
564 return (Status);
565 }
566
567 /* Add all tables found in the memory */
568
569 Status = OslListBiosTables();
570 if (ACPI_FAILURE(Status)) {
571 return (Status);
572 }
573
574 Gbl_TableListInitialized = TRUE;
575 return (AE_OK);
576 }
577
578
579 /*
580 *
581 * FUNCTION: OslListBiosTables
582 *
583 * PARAMETERS: None
584 *
585 * RETURN: Status; Table list is initialized if AE_OK.
586 *
587 * DESCRIPTION: Add ACPI tables to the table list from memory.
588 */
589 static ACPI_STATUS
OslListBiosTables(void)590 OslListBiosTables(void)
591 {
592 ACPI_TABLE_HEADER *MappedTable = NULL;
593 UINT8 *TableData;
594 UINT32 NumberOfTables;
595 UINT8 ItemSize;
596 ACPI_PHYSICAL_ADDRESS TableAddress = 0;
597 ACPI_STATUS Status = AE_OK;
598 UINT32 i;
599
600 if (OslCanUseXsdt()) {
601 ItemSize = sizeof (UINT64);
602 TableData = ACPI_CAST8(Gbl_Xsdt) + sizeof (ACPI_TABLE_HEADER);
603 NumberOfTables = (UINT32)
604 ((Gbl_Xsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
605 / ItemSize);
606
607 } else {
608 /* Use RSDT if XSDT is not available */
609 ItemSize = sizeof (UINT32);
610 TableData = ACPI_CAST8(Gbl_Rsdt) + sizeof (ACPI_TABLE_HEADER);
611 NumberOfTables = (UINT32)
612 ((Gbl_Rsdt->Header.Length - sizeof (ACPI_TABLE_HEADER))
613 / ItemSize);
614 }
615
616 /* Search RSDT/XSDT for the requested table */
617
618 for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) {
619 if (OslCanUseXsdt()) {
620 TableAddress =
621 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST64(TableData));
622 } else {
623 TableAddress =
624 (ACPI_PHYSICAL_ADDRESS) (*ACPI_CAST32(TableData));
625 }
626
627 /* Skip NULL entries in RSDT/XSDT */
628 if (TableAddress == NULL) {
629 continue;
630 }
631
632 Status = OslMapTable(TableAddress, NULL, &MappedTable);
633 if (ACPI_FAILURE(Status)) {
634 return (Status);
635 }
636
637 OslAddTableToList(MappedTable->Signature);
638 OslUnmapTable(MappedTable);
639 }
640
641 return (AE_OK);
642 }
643
644 /*
645 *
646 * FUNCTION: OslGetBiosTable
647 *
648 * PARAMETERS: Signature - ACPI Signature for common table. Must be
649 * a null terminated 4-character string.
650 * Instance - Multiple table support for SSDT/UEFI (0...n)
651 * Must be 0 for other tables.
652 * Table - Where a pointer to the table is returned
653 * Address - Where the table physical address is returned
654 *
655 * RETURN: Status; Table buffer and physical address returned if AE_OK.
656 * AE_LIMIT: Instance is beyond valid limit
657 * AE_NOT_FOUND: A table with the signature was not found
658 *
659 * DESCRIPTION: Get a BIOS provided ACPI table
660 *
661 * NOTE: Assumes the input signature is uppercase.
662 *
663 */
664 static ACPI_STATUS
OslGetBiosTable(char * Signature,UINT32 Instance,ACPI_TABLE_HEADER ** Table,ACPI_PHYSICAL_ADDRESS * Address)665 OslGetBiosTable(char *Signature, UINT32 Instance, ACPI_TABLE_HEADER **Table,
666 ACPI_PHYSICAL_ADDRESS *Address)
667 {
668 ACPI_TABLE_HEADER *LocalTable = NULL;
669 ACPI_TABLE_HEADER *MappedTable = NULL;
670 UINT8 *TableData;
671 UINT8 NumberOfTables;
672 UINT8 ItemSize;
673 UINT32 CurrentInstance = 0;
674 ACPI_PHYSICAL_ADDRESS TableAddress = 0;
675 UINT32 TableLength = 0;
676 ACPI_STATUS Status = AE_OK;
677 UINT32 i;
678
679 /* Handle special tables whose addresses are not in RSDT/XSDT */
680
681 if (ACPI_COMPARE_NAME(Signature, ACPI_RSDP_NAME) ||
682 ACPI_COMPARE_NAME(Signature, ACPI_SIG_RSDT) ||
683 ACPI_COMPARE_NAME(Signature, ACPI_SIG_XSDT) ||
684 ACPI_COMPARE_NAME(Signature, ACPI_SIG_DSDT) ||
685 ACPI_COMPARE_NAME(Signature, ACPI_SIG_FACS)) {
686 if (Instance > 0) {
687 return (AE_LIMIT);
688 }
689
690 /*
691 * Get the appropriate address, either 32-bit or 64-bit. Be very
692 * careful about the FADT length and validate table addresses.
693 * Note: The 64-bit addresses have priority.
694 */
695 if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_DSDT)) {
696 if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XDSDT) &&
697 Gbl_Fadt->XDsdt) {
698 TableAddress =
699 (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XDsdt;
700
701 } else if (Gbl_Fadt->Header.Length >=
702 MIN_FADT_FOR_DSDT && Gbl_Fadt->Dsdt) {
703 TableAddress =
704 (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Dsdt;
705 }
706
707 } else if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_FACS)) {
708 if ((Gbl_Fadt->Header.Length >= MIN_FADT_FOR_XFACS) &&
709 Gbl_Fadt->XFacs) {
710 TableAddress =
711 (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->XFacs;
712
713 } else if (Gbl_Fadt->Header.Length >=
714 MIN_FADT_FOR_FACS && Gbl_Fadt->Facs) {
715 TableAddress =
716 (ACPI_PHYSICAL_ADDRESS) Gbl_Fadt->Facs;
717 }
718
719 } else if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_XSDT)) {
720 if (!Gbl_Revision) {
721 return (AE_BAD_SIGNATURE);
722 }
723 TableAddress = (ACPI_PHYSICAL_ADDRESS)
724 Gbl_Rsdp.XsdtPhysicalAddress;
725
726 } else if (ACPI_COMPARE_NAME(Signature, ACPI_SIG_RSDT)) {
727 TableAddress = (ACPI_PHYSICAL_ADDRESS)
728 Gbl_Rsdp.RsdtPhysicalAddress;
729
730 } else {
731 TableAddress = (ACPI_PHYSICAL_ADDRESS) Gbl_RsdpAddress;
732 Signature = ACPI_SIG_RSDP;
733 }
734
735 /* Now we can get the requested special table */
736
737 Status = OslMapTable(TableAddress, Signature, &MappedTable);
738 if (ACPI_FAILURE(Status)) {
739 return (Status);
740 }
741
742 TableLength = ApGetTableLength(MappedTable);
743
744 } else {
745 /* Case for a normal ACPI table */
746 if (OslCanUseXsdt()) {
747 ItemSize = sizeof (UINT64);
748 TableData = ACPI_CAST8(Gbl_Xsdt) +
749 sizeof (ACPI_TABLE_HEADER);
750 NumberOfTables = (UINT8) ((Gbl_Xsdt->Header.Length -
751 sizeof (ACPI_TABLE_HEADER))
752 / ItemSize);
753
754 } else {
755 /* Use RSDT if XSDT is not available */
756 ItemSize = sizeof (UINT32);
757 TableData = ACPI_CAST8(Gbl_Rsdt) +
758 sizeof (ACPI_TABLE_HEADER);
759 NumberOfTables = (UINT8) ((Gbl_Rsdt->Header.Length -
760 sizeof (ACPI_TABLE_HEADER))
761 / ItemSize);
762 }
763
764 /* Search RSDT/XSDT for the requested table */
765
766 for (i = 0; i < NumberOfTables; ++i, TableData += ItemSize) {
767 if (OslCanUseXsdt()) {
768 TableAddress = (ACPI_PHYSICAL_ADDRESS)
769 (*ACPI_CAST64(TableData));
770 } else {
771 TableAddress = (ACPI_PHYSICAL_ADDRESS)
772 (*ACPI_CAST32(TableData));
773 }
774
775 /* Skip NULL entries in RSDT/XSDT */
776
777 if (TableAddress == NULL) {
778 continue;
779 }
780
781 Status = OslMapTable(TableAddress, NULL, &MappedTable);
782 if (ACPI_FAILURE(Status)) {
783 return (Status);
784 }
785 TableLength = MappedTable->Length;
786
787 /* Does this table match the requested signature? */
788
789 if (!ACPI_COMPARE_NAME(MappedTable->Signature,
790 Signature)) {
791 OslUnmapTable(MappedTable);
792 MappedTable = NULL;
793 continue;
794 }
795
796 /* Match table instance (for SSDT/UEFI tables) */
797
798 if (CurrentInstance != Instance) {
799 OslUnmapTable(MappedTable);
800 MappedTable = NULL;
801 CurrentInstance++;
802 continue;
803 }
804
805 break;
806 }
807 }
808
809 if (MappedTable == NULL) {
810 return (AE_LIMIT);
811 }
812
813 if (TableLength == 0) {
814 Status = AE_BAD_HEADER;
815 goto Exit;
816 }
817
818 /* Copy table to local buffer and return it */
819
820 LocalTable = calloc(1, TableLength);
821 if (LocalTable == NULL) {
822 Status = AE_NO_MEMORY;
823 goto Exit;
824 }
825
826 memcpy(LocalTable, MappedTable, TableLength);
827 *Address = TableAddress;
828 *Table = LocalTable;
829
830 Exit:
831 OslUnmapTable(MappedTable);
832 return (Status);
833 }
834
835 /*
836 *
837 * FUNCTION: OslMapTable
838 *
839 * PARAMETERS: Address - Address of the table in memory
840 * Signature - Optional ACPI Signature for desired table.
841 * Null terminated 4-character string.
842 * Table - Where a pointer to the mapped table is
843 * returned
844 *
845 * RETURN: Status; Mapped table is returned if AE_OK.
846 * AE_NOT_FOUND: A valid table was not found at the address
847 *
848 * DESCRIPTION: Map entire ACPI table into caller's address space.
849 *
850 */
851 static ACPI_STATUS
OslMapTable(ACPI_SIZE Address,char * Signature,ACPI_TABLE_HEADER ** Table)852 OslMapTable(ACPI_SIZE Address, char *Signature, ACPI_TABLE_HEADER **Table)
853 {
854 ACPI_TABLE_HEADER *MappedTable;
855 UINT32 Length;
856
857 if (Address == NULL) {
858 return (AE_BAD_ADDRESS);
859 }
860
861 /*
862 * Map the header so we can get the table length.
863 * Use sizeof (ACPI_TABLE_HEADER) as:
864 * 1. it is bigger than 24 to include RSDP->Length
865 * 2. it is smaller than sizeof (ACPI_TABLE_RSDP)
866 */
867 MappedTable = AcpiOsMapMemory(Address, sizeof (ACPI_TABLE_HEADER));
868 if (MappedTable == NULL) {
869 (void) fprintf(stderr, "Could not map table header at "
870 "0x%8.8X%8.8X\n", ACPI_FORMAT_UINT64(Address));
871 return (OslGetLastStatus(AE_BAD_ADDRESS));
872 }
873
874 /* If specified, signature must match */
875
876 if (Signature != NULL) {
877 if (ACPI_VALIDATE_RSDP_SIG(Signature)) {
878 if (!ACPI_VALIDATE_RSDP_SIG(MappedTable->Signature)) {
879 AcpiOsUnmapMemory(MappedTable,
880 sizeof (ACPI_TABLE_HEADER));
881 return (AE_BAD_SIGNATURE);
882 }
883 } else if (!ACPI_COMPARE_NAME(Signature,
884 MappedTable->Signature)) {
885 AcpiOsUnmapMemory(MappedTable,
886 sizeof (ACPI_TABLE_HEADER));
887 return (AE_BAD_SIGNATURE);
888 }
889 }
890
891 /* Map the entire table */
892
893 Length = ApGetTableLength(MappedTable);
894 AcpiOsUnmapMemory(MappedTable, sizeof (ACPI_TABLE_HEADER));
895 if (Length == 0) {
896 return (AE_BAD_HEADER);
897 }
898
899 MappedTable = AcpiOsMapMemory(Address, Length);
900 if (MappedTable == NULL) {
901 (void) fprintf(stderr, "Could not map table at 0x%8.8X%8.8X "
902 "length %8.8X\n", ACPI_FORMAT_UINT64(Address), Length);
903 return (OslGetLastStatus(AE_INVALID_TABLE_LENGTH));
904 }
905
906 (void) ApIsValidChecksum(MappedTable);
907
908 *Table = MappedTable;
909 return (AE_OK);
910 }
911
912
913 /*
914 *
915 * FUNCTION: OslUnmapTable
916 *
917 * PARAMETERS: Table - A pointer to the mapped table
918 *
919 * RETURN: None
920 *
921 * DESCRIPTION: Unmap entire ACPI table.
922 *
923 */
924 static void
OslUnmapTable(ACPI_TABLE_HEADER * Table)925 OslUnmapTable(ACPI_TABLE_HEADER *Table)
926 {
927 if (Table != NULL) {
928 AcpiOsUnmapMemory(Table, ApGetTableLength(Table));
929 }
930 }
931
932 /*
933 *
934 * FUNCTION: OslTableNameFromFile
935 *
936 * PARAMETERS: Filename - File that contains the desired table
937 * Signature - Pointer to 4-character buffer to store
938 * extracted table signature.
939 * Instance - Pointer to integer to store extracted
940 * table instance number.
941 *
942 * RETURN: Status; Table name is extracted if AE_OK.
943 *
944 * DESCRIPTION: Extract table signature and instance number from a table file
945 * name.
946 *
947 */
948 static ACPI_STATUS
OslTableNameFromFile(char * Filename,char * Signature,UINT32 * Instance)949 OslTableNameFromFile(char *Filename, char *Signature, UINT32 *Instance)
950 {
951 /* Ignore meaningless files */
952
953 if (strlen(Filename) < ACPI_NAME_SIZE) {
954 return (AE_BAD_SIGNATURE);
955 }
956
957 /* Extract instance number */
958
959 if (isdigit((int)Filename[ACPI_NAME_SIZE])) {
960 sscanf(&Filename[ACPI_NAME_SIZE], "%u", Instance);
961 } else if (strlen(Filename) != ACPI_NAME_SIZE) {
962 return (AE_BAD_SIGNATURE);
963 } else {
964 *Instance = 0;
965 }
966
967 /* Extract signature */
968
969 ACPI_MOVE_NAME(Signature, Filename);
970 return (AE_OK);
971 }
972
973 UINT32
CmGetFileSize(ACPI_FILE File)974 CmGetFileSize(ACPI_FILE File)
975 {
976 int fd;
977 struct stat sb;
978
979 fd = fileno(File);
980 if (fstat(fd, &sb) != 0)
981 return (ACPI_UINT32_MAX);
982 return ((UINT32)sb.st_size);
983 }
984
985 void *
AcpiOsAllocateZeroed(ACPI_SIZE Size)986 AcpiOsAllocateZeroed(ACPI_SIZE Size)
987 {
988 return (calloc(1, Size));
989 }
990
991 void
AcpiOsFree(void * p)992 AcpiOsFree(void *p)
993 {
994 free(p);
995 }
996
997 ACPI_FILE
AcpiOsOpenFile(const char * Path,UINT8 Modes)998 AcpiOsOpenFile(const char *Path, UINT8 Modes)
999 {
1000 char mode[3];
1001
1002 bzero(mode, sizeof (mode));
1003 if ((Modes & ACPI_FILE_READING) != 0)
1004 (void) strlcat(mode, "r", sizeof (mode));
1005
1006 if ((Modes & ACPI_FILE_WRITING) != 0)
1007 (void) strlcat(mode, "w", sizeof (mode));
1008
1009 return (fopen(Path, mode));
1010 }
1011
1012 void
AcpiOsCloseFile(ACPI_FILE File)1013 AcpiOsCloseFile(ACPI_FILE File)
1014 {
1015 fclose(File);
1016 }
1017
1018 int
AcpiOsReadFile(ACPI_FILE File,void * Buffer,ACPI_SIZE Size,ACPI_SIZE Count)1019 AcpiOsReadFile(ACPI_FILE File, void *Buffer, ACPI_SIZE Size, ACPI_SIZE Count)
1020 {
1021 return (fread(Buffer, Size, Count, File));
1022 }
1023
1024 void *
AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where,ACPI_SIZE Length)1025 AcpiOsMapMemory(ACPI_PHYSICAL_ADDRESS Where, ACPI_SIZE Length)
1026 {
1027 int fd;
1028 void *p;
1029 ulong_t offset;
1030
1031 if ((fd = open("/dev/xsvc", O_RDONLY)) < 0)
1032 return (NULL);
1033
1034 if (pagesize == 0) {
1035 pagesize = getpagesize();
1036 }
1037
1038 offset = Where % pagesize;
1039 p = mmap(NULL, Length + offset, PROT_READ, MAP_SHARED | MAP_NORESERVE,
1040 fd, Where - offset);
1041
1042 (void) close(fd);
1043
1044 if (p == MAP_FAILED)
1045 return (NULL);
1046 p = (char *)p + offset;
1047 return (p);
1048 }
1049
1050 void
AcpiOsUnmapMemory(void * LogicalAddress,ACPI_SIZE Size)1051 AcpiOsUnmapMemory(void *LogicalAddress, ACPI_SIZE Size)
1052 {
1053 ulong_t offset;
1054 void *p;
1055
1056 offset = (ulong_t)LogicalAddress % pagesize;
1057 p = (void *)((char *)LogicalAddress - offset);
1058
1059 (void) munmap(p, Size + offset);
1060 }
1061