aboutsummaryrefslogtreecommitdiffstats
path: root/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/power/acpi/os_specific/service_layers/oslinuxtbl.c')
-rw-r--r--tools/power/acpi/os_specific/service_layers/oslinuxtbl.c1329
1 files changed, 1329 insertions, 0 deletions
diff --git a/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
new file mode 100644
index 000000000000..28c52008e854
--- /dev/null
+++ b/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c
@@ -0,0 +1,1329 @@
1/******************************************************************************
2 *
3 * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2014, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44#include "acpidump.h"
45
46#define _COMPONENT ACPI_OS_SERVICES
47ACPI_MODULE_NAME("oslinuxtbl")
48
49#ifndef PATH_MAX
50#define PATH_MAX 256
51#endif
52/* List of information about obtained ACPI tables */
53typedef struct osl_table_info {
54 struct osl_table_info *next;
55 u32 instance;
56 char signature[ACPI_NAME_SIZE];
57
58} osl_table_info;
59
60/* Local prototypes */
61
62static acpi_status osl_table_initialize(void);
63
64static acpi_status
65osl_table_name_from_file(char *filename, char *signature, u32 *instance);
66
67static acpi_status osl_add_table_to_list(char *signature, u32 instance);
68
69static acpi_status
70osl_read_table_from_file(char *filename,
71 acpi_size file_offset,
72 char *signature, struct acpi_table_header **table);
73
74static acpi_status
75osl_map_table(acpi_size address,
76 char *signature, struct acpi_table_header **table);
77
78static void osl_unmap_table(struct acpi_table_header *table);
79
80static acpi_physical_address osl_find_rsdp_via_efi(void);
81
82static acpi_status osl_load_rsdp(void);
83
84static acpi_status osl_list_customized_tables(char *directory);
85
86static acpi_status
87osl_get_customized_table(char *pathname,
88 char *signature,
89 u32 instance,
90 struct acpi_table_header **table,
91 acpi_physical_address * address);
92
93static acpi_status osl_list_bios_tables(void);
94
95static acpi_status
96osl_get_bios_table(char *signature,
97 u32 instance,
98 struct acpi_table_header **table,
99 acpi_physical_address * address);
100
101static acpi_status osl_get_last_status(acpi_status default_status);
102
103/* File locations */
104
105#define DYNAMIC_TABLE_DIR "/sys/firmware/acpi/tables/dynamic"
106#define STATIC_TABLE_DIR "/sys/firmware/acpi/tables"
107#define EFI_SYSTAB "/sys/firmware/efi/systab"
108
109/* Should we get dynamically loaded SSDTs from DYNAMIC_TABLE_DIR? */
110
111u8 gbl_dump_dynamic_tables = TRUE;
112
113/* Initialization flags */
114
115u8 gbl_table_list_initialized = FALSE;
116
117/* Local copies of main ACPI tables */
118
119struct acpi_table_rsdp gbl_rsdp;
120struct acpi_table_fadt *gbl_fadt = NULL;
121struct acpi_table_rsdt *gbl_rsdt = NULL;
122struct acpi_table_xsdt *gbl_xsdt = NULL;
123
124/* Table addresses */
125
126acpi_physical_address gbl_fadt_address = 0;
127acpi_physical_address gbl_rsdp_address = 0;
128
129/* Revision of RSD PTR */
130
131u8 gbl_revision = 0;
132
133struct osl_table_info *gbl_table_list_head = NULL;
134u32 gbl_table_count = 0;
135
136/******************************************************************************
137 *
138 * FUNCTION: osl_get_last_status
139 *
140 * PARAMETERS: default_status - Default error status to return
141 *
142 * RETURN: Status; Converted from errno.
143 *
144 * DESCRIPTION: Get last errno and conver it to acpi_status.
145 *
146 *****************************************************************************/
147
148static acpi_status osl_get_last_status(acpi_status default_status)
149{
150
151 switch (errno) {
152 case EACCES:
153 case EPERM:
154
155 return (AE_ACCESS);
156
157 case ENOENT:
158
159 return (AE_NOT_FOUND);
160
161 case ENOMEM:
162
163 return (AE_NO_MEMORY);
164
165 default:
166
167 return (default_status);
168 }
169}
170
171/******************************************************************************
172 *
173 * FUNCTION: acpi_os_get_table_by_address
174 *
175 * PARAMETERS: address - Physical address of the ACPI table
176 * table - Where a pointer to the table is returned
177 *
178 * RETURN: Status; Table buffer is returned if AE_OK.
179 * AE_NOT_FOUND: A valid table was not found at the address
180 *
181 * DESCRIPTION: Get an ACPI table via a physical memory address.
182 *
183 *****************************************************************************/
184
185acpi_status
186acpi_os_get_table_by_address(acpi_physical_address address,
187 struct acpi_table_header ** table)
188{
189 u32 table_length;
190 struct acpi_table_header *mapped_table;
191 struct acpi_table_header *local_table = NULL;
192 acpi_status status = AE_OK;
193
194 /* Get main ACPI tables from memory on first invocation of this function */
195
196 status = osl_table_initialize();
197 if (ACPI_FAILURE(status)) {
198 return (status);
199 }
200
201 /* Map the table and validate it */
202
203 status = osl_map_table(address, NULL, &mapped_table);
204 if (ACPI_FAILURE(status)) {
205 return (status);
206 }
207
208 /* Copy table to local buffer and return it */
209
210 table_length = ap_get_table_length(mapped_table);
211 if (table_length == 0) {
212 status = AE_BAD_HEADER;
213 goto exit;
214 }
215
216 local_table = calloc(1, table_length);
217 if (!local_table) {
218 status = AE_NO_MEMORY;
219 goto exit;
220 }
221
222 ACPI_MEMCPY(local_table, mapped_table, table_length);
223
224exit:
225 osl_unmap_table(mapped_table);
226 *table = local_table;
227 return (status);
228}
229
230/******************************************************************************
231 *
232 * FUNCTION: acpi_os_get_table_by_name
233 *
234 * PARAMETERS: signature - ACPI Signature for desired table. Must be
235 * a null terminated 4-character string.
236 * instance - Multiple table support for SSDT/UEFI (0...n)
237 * Must be 0 for other tables.
238 * table - Where a pointer to the table is returned
239 * address - Where the table physical address is returned
240 *
241 * RETURN: Status; Table buffer and physical address returned if AE_OK.
242 * AE_LIMIT: Instance is beyond valid limit
243 * AE_NOT_FOUND: A table with the signature was not found
244 *
245 * NOTE: Assumes the input signature is uppercase.
246 *
247 *****************************************************************************/
248
249acpi_status
250acpi_os_get_table_by_name(char *signature,
251 u32 instance,
252 struct acpi_table_header ** table,
253 acpi_physical_address * address)
254{
255 acpi_status status;
256
257 /* Get main ACPI tables from memory on first invocation of this function */
258
259 status = osl_table_initialize();
260 if (ACPI_FAILURE(status)) {
261 return (status);
262 }
263
264 /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */
265
266 if (!gbl_dump_customized_tables) {
267
268 /* Attempt to get the table from the memory */
269
270 status =
271 osl_get_bios_table(signature, instance, table, address);
272 } else {
273 /* Attempt to get the table from the static directory */
274
275 status = osl_get_customized_table(STATIC_TABLE_DIR, signature,
276 instance, table, address);
277 }
278
279 if (ACPI_FAILURE(status) && status == AE_LIMIT) {
280 if (gbl_dump_dynamic_tables) {
281
282 /* Attempt to get a dynamic table */
283
284 status =
285 osl_get_customized_table(DYNAMIC_TABLE_DIR,
286 signature, instance, table,
287 address);
288 }
289 }
290
291 return (status);
292}
293
294/******************************************************************************
295 *
296 * FUNCTION: osl_add_table_to_list
297 *
298 * PARAMETERS: signature - Table signature
299 * instance - Table instance
300 *
301 * RETURN: Status; Successfully added if AE_OK.
302 * AE_NO_MEMORY: Memory allocation error
303 *
304 * DESCRIPTION: Insert a table structure into OSL table list.
305 *
306 *****************************************************************************/
307
308static acpi_status osl_add_table_to_list(char *signature, u32 instance)
309{
310 struct osl_table_info *new_info;
311 struct osl_table_info *next;
312 u32 next_instance = 0;
313 u8 found = FALSE;
314
315 new_info = calloc(1, sizeof(struct osl_table_info));
316 if (!new_info) {
317 return (AE_NO_MEMORY);
318 }
319
320 ACPI_MOVE_NAME(new_info->signature, signature);
321
322 if (!gbl_table_list_head) {
323 gbl_table_list_head = new_info;
324 } else {
325 next = gbl_table_list_head;
326 while (1) {
327 if (ACPI_COMPARE_NAME(next->signature, signature)) {
328 if (next->instance == instance) {
329 found = TRUE;
330 }
331 if (next->instance >= next_instance) {
332 next_instance = next->instance + 1;
333 }
334 }
335
336 if (!next->next) {
337 break;
338 }
339 next = next->next;
340 }
341 next->next = new_info;
342 }
343
344 if (found) {
345 if (instance) {
346 fprintf(stderr,
347 "%4.4s: Warning unmatched table instance %d, expected %d\n",
348 signature, instance, next_instance);
349 }
350 instance = next_instance;
351 }
352
353 new_info->instance = instance;
354 gbl_table_count++;
355
356 return (AE_OK);
357}
358
359/******************************************************************************
360 *
361 * FUNCTION: acpi_os_get_table_by_index
362 *
363 * PARAMETERS: index - Which table to get
364 * table - Where a pointer to the table is returned
365 * instance - Where a pointer to the table instance no. is
366 * returned
367 * address - Where the table physical address is returned
368 *
369 * RETURN: Status; Table buffer and physical address returned if AE_OK.
370 * AE_LIMIT: Index is beyond valid limit
371 *
372 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
373 * AE_LIMIT when an invalid index is reached. Index is not
374 * necessarily an index into the RSDT/XSDT.
375 *
376 *****************************************************************************/
377
378acpi_status
379acpi_os_get_table_by_index(u32 index,
380 struct acpi_table_header ** table,
381 u32 *instance, acpi_physical_address * address)
382{
383 struct osl_table_info *info;
384 acpi_status status;
385 u32 i;
386
387 /* Get main ACPI tables from memory on first invocation of this function */
388
389 status = osl_table_initialize();
390 if (ACPI_FAILURE(status)) {
391 return (status);
392 }
393
394 /* Validate Index */
395
396 if (index >= gbl_table_count) {
397 return (AE_LIMIT);
398 }
399
400 /* Point to the table list entry specified by the Index argument */
401
402 info = gbl_table_list_head;
403 for (i = 0; i < index; i++) {
404 info = info->next;
405 }
406
407 /* Now we can just get the table via the signature */
408
409 status = acpi_os_get_table_by_name(info->signature, info->instance,
410 table, address);
411
412 if (ACPI_SUCCESS(status)) {
413 *instance = info->instance;
414 }
415 return (status);
416}
417
418/******************************************************************************
419 *
420 * FUNCTION: osl_find_rsdp_via_efi
421 *
422 * PARAMETERS: None
423 *
424 * RETURN: RSDP address if found
425 *
426 * DESCRIPTION: Find RSDP address via EFI.
427 *
428 *****************************************************************************/
429
430static acpi_physical_address osl_find_rsdp_via_efi(void)
431{
432 FILE *file;
433 char buffer[80];
434 unsigned long address = 0;
435
436 file = fopen(EFI_SYSTAB, "r");
437 if (file) {
438 while (fgets(buffer, 80, file)) {
439 if (sscanf(buffer, "ACPI20=0x%lx", &address) == 1) {
440 break;
441 }
442 }
443 fclose(file);
444 }
445
446 return ((acpi_physical_address) (address));
447}
448
449/******************************************************************************
450 *
451 * FUNCTION: osl_load_rsdp
452 *
453 * PARAMETERS: None
454 *
455 * RETURN: Status
456 *
457 * DESCRIPTION: Scan and load RSDP.
458 *
459 *****************************************************************************/
460
461static acpi_status osl_load_rsdp(void)
462{
463 struct acpi_table_header *mapped_table;
464 u8 *rsdp_address;
465 acpi_physical_address rsdp_base;
466 acpi_size rsdp_size;
467
468 /* Get RSDP from memory */
469
470 rsdp_size = sizeof(struct acpi_table_rsdp);
471 if (gbl_rsdp_base) {
472 rsdp_base = gbl_rsdp_base;
473 } else {
474 rsdp_base = osl_find_rsdp_via_efi();
475 }
476
477 if (!rsdp_base) {
478 rsdp_base = ACPI_HI_RSDP_WINDOW_BASE;
479 rsdp_size = ACPI_HI_RSDP_WINDOW_SIZE;
480 }
481
482 rsdp_address = acpi_os_map_memory(rsdp_base, rsdp_size);
483 if (!rsdp_address) {
484 return (osl_get_last_status(AE_BAD_ADDRESS));
485 }
486
487 /* Search low memory for the RSDP */
488
489 mapped_table = ACPI_CAST_PTR(struct acpi_table_header,
490 acpi_tb_scan_memory_for_rsdp(rsdp_address,
491 rsdp_size));
492 if (!mapped_table) {
493 acpi_os_unmap_memory(rsdp_address, rsdp_size);
494 return (AE_NOT_FOUND);
495 }
496
497 gbl_rsdp_address =
498 rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address);
499
500 ACPI_MEMCPY(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp));
501 acpi_os_unmap_memory(rsdp_address, rsdp_size);
502
503 return (AE_OK);
504}
505
506/******************************************************************************
507 *
508 * FUNCTION: osl_can_use_xsdt
509 *
510 * PARAMETERS: None
511 *
512 * RETURN: TRUE if XSDT is allowed to be used.
513 *
514 * DESCRIPTION: This function collects logic that can be used to determine if
515 * XSDT should be used instead of RSDT.
516 *
517 *****************************************************************************/
518
519static u8 osl_can_use_xsdt(void)
520{
521 if (gbl_revision && !acpi_gbl_do_not_use_xsdt) {
522 return (TRUE);
523 } else {
524 return (FALSE);
525 }
526}
527
528/******************************************************************************
529 *
530 * FUNCTION: osl_table_initialize
531 *
532 * PARAMETERS: None
533 *
534 * RETURN: Status
535 *
536 * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
537 * local variables. Main ACPI tables include RSDT, FADT, RSDT,
538 * and/or XSDT.
539 *
540 *****************************************************************************/
541
542static acpi_status osl_table_initialize(void)
543{
544 acpi_status status;
545 acpi_physical_address address;
546
547 if (gbl_table_list_initialized) {
548 return (AE_OK);
549 }
550
551 /* Get RSDP from memory */
552
553 status = osl_load_rsdp();
554 if (ACPI_FAILURE(status)) {
555 return (status);
556 }
557
558 /* Get XSDT from memory */
559
560 if (gbl_rsdp.revision && !gbl_do_not_dump_xsdt) {
561 if (gbl_xsdt) {
562 free(gbl_xsdt);
563 gbl_xsdt = NULL;
564 }
565
566 gbl_revision = 2;
567 status = osl_get_bios_table(ACPI_SIG_XSDT, 0,
568 ACPI_CAST_PTR(struct
569 acpi_table_header *,
570 &gbl_xsdt), &address);
571 if (ACPI_FAILURE(status)) {
572 return (status);
573 }
574 }
575
576 /* Get RSDT from memory */
577
578 if (gbl_rsdp.rsdt_physical_address) {
579 if (gbl_rsdt) {
580 free(gbl_rsdt);
581 gbl_rsdt = NULL;
582 }
583
584 status = osl_get_bios_table(ACPI_SIG_RSDT, 0,
585 ACPI_CAST_PTR(struct
586 acpi_table_header *,
587 &gbl_rsdt), &address);
588 if (ACPI_FAILURE(status)) {
589 return (status);
590 }
591 }
592
593 /* Get FADT from memory */
594
595 if (gbl_fadt) {
596 free(gbl_fadt);
597 gbl_fadt = NULL;
598 }
599
600 status = osl_get_bios_table(ACPI_SIG_FADT, 0,
601 ACPI_CAST_PTR(struct acpi_table_header *,
602 &gbl_fadt),
603 &gbl_fadt_address);
604 if (ACPI_FAILURE(status)) {
605 return (status);
606 }
607
608 if (!gbl_dump_customized_tables) {
609
610 /* Add mandatory tables to global table list first */
611
612 status = osl_add_table_to_list(ACPI_RSDP_NAME, 0);
613 if (ACPI_FAILURE(status)) {
614 return (status);
615 }
616
617 status = osl_add_table_to_list(ACPI_SIG_RSDT, 0);
618 if (ACPI_FAILURE(status)) {
619 return (status);
620 }
621
622 if (gbl_revision == 2) {
623 status = osl_add_table_to_list(ACPI_SIG_XSDT, 0);
624 if (ACPI_FAILURE(status)) {
625 return (status);
626 }
627 }
628
629 status = osl_add_table_to_list(ACPI_SIG_DSDT, 0);
630 if (ACPI_FAILURE(status)) {
631 return (status);
632 }
633
634 status = osl_add_table_to_list(ACPI_SIG_FACS, 0);
635 if (ACPI_FAILURE(status)) {
636 return (status);
637 }
638
639 /* Add all tables found in the memory */
640
641 status = osl_list_bios_tables();
642 if (ACPI_FAILURE(status)) {
643 return (status);
644 }
645 } else {
646 /* Add all tables found in the static directory */
647
648 status = osl_list_customized_tables(STATIC_TABLE_DIR);
649 if (ACPI_FAILURE(status)) {
650 return (status);
651 }
652 }
653
654 if (gbl_dump_dynamic_tables) {
655
656 /* Add all dynamically loaded tables in the dynamic directory */
657
658 status = osl_list_customized_tables(DYNAMIC_TABLE_DIR);
659 if (ACPI_FAILURE(status)) {
660 return (status);
661 }
662 }
663
664 gbl_table_list_initialized = TRUE;
665 return (AE_OK);
666}
667
668/******************************************************************************
669 *
670 * FUNCTION: osl_list_bios_tables
671 *
672 * PARAMETERS: None
673 *
674 * RETURN: Status; Table list is initialized if AE_OK.
675 *
676 * DESCRIPTION: Add ACPI tables to the table list from memory.
677 *
678 * NOTE: This works on Linux as table customization does not modify the
679 * addresses stored in RSDP/RSDT/XSDT/FADT.
680 *
681 *****************************************************************************/
682
683static acpi_status osl_list_bios_tables(void)
684{
685 struct acpi_table_header *mapped_table = NULL;
686 u8 *table_data;
687 u8 number_of_tables;
688 u8 item_size;
689 acpi_physical_address table_address = 0;
690 acpi_status status = AE_OK;
691 u32 i;
692
693 if (osl_can_use_xsdt()) {
694 item_size = sizeof(u64);
695 table_data =
696 ACPI_CAST8(gbl_xsdt) + sizeof(struct acpi_table_header);
697 number_of_tables =
698 (u8)((gbl_xsdt->header.length -
699 sizeof(struct acpi_table_header))
700 / item_size);
701 } else { /* Use RSDT if XSDT is not available */
702
703 item_size = sizeof(u32);
704 table_data =
705 ACPI_CAST8(gbl_rsdt) + sizeof(struct acpi_table_header);
706 number_of_tables =
707 (u8)((gbl_rsdt->header.length -
708 sizeof(struct acpi_table_header))
709 / item_size);
710 }
711
712 /* Search RSDT/XSDT for the requested table */
713
714 for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
715 if (osl_can_use_xsdt()) {
716 table_address =
717 (acpi_physical_address) (*ACPI_CAST64(table_data));
718 } else {
719 table_address =
720 (acpi_physical_address) (*ACPI_CAST32(table_data));
721 }
722
723 /* Skip NULL entries in RSDT/XSDT */
724
725 if (!table_address) {
726 continue;
727 }
728
729 status = osl_map_table(table_address, NULL, &mapped_table);
730 if (ACPI_FAILURE(status)) {
731 return (status);
732 }
733
734 osl_add_table_to_list(mapped_table->signature, 0);
735 osl_unmap_table(mapped_table);
736 }
737
738 return (AE_OK);
739}
740
741/******************************************************************************
742 *
743 * FUNCTION: osl_get_bios_table
744 *
745 * PARAMETERS: signature - ACPI Signature for common table. Must be
746 * a null terminated 4-character string.
747 * instance - Multiple table support for SSDT/UEFI (0...n)
748 * Must be 0 for other tables.
749 * table - Where a pointer to the table is returned
750 * address - Where the table physical address is returned
751 *
752 * RETURN: Status; Table buffer and physical address returned if AE_OK.
753 * AE_LIMIT: Instance is beyond valid limit
754 * AE_NOT_FOUND: A table with the signature was not found
755 *
756 * DESCRIPTION: Get a BIOS provided ACPI table
757 *
758 * NOTE: Assumes the input signature is uppercase.
759 *
760 *****************************************************************************/
761
762static acpi_status
763osl_get_bios_table(char *signature,
764 u32 instance,
765 struct acpi_table_header **table,
766 acpi_physical_address * address)
767{
768 struct acpi_table_header *local_table = NULL;
769 struct acpi_table_header *mapped_table = NULL;
770 u8 *table_data;
771 u8 number_of_tables;
772 u8 item_size;
773 u32 current_instance = 0;
774 acpi_physical_address table_address = 0;
775 u32 table_length = 0;
776 acpi_status status = AE_OK;
777 u32 i;
778
779 /* Handle special tables whose addresses are not in RSDT/XSDT */
780
781 if (ACPI_COMPARE_NAME(signature, ACPI_RSDP_NAME) ||
782 ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT) ||
783 ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT) ||
784 ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT) ||
785 ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) {
786 if (instance > 0) {
787 return (AE_LIMIT);
788 }
789
790 /*
791 * Get the appropriate address, either 32-bit or 64-bit. Be very
792 * careful about the FADT length and validate table addresses.
793 * Note: The 64-bit addresses have priority.
794 */
795 if (ACPI_COMPARE_NAME(signature, ACPI_SIG_DSDT)) {
796 if ((gbl_fadt->header.length >= MIN_FADT_FOR_XDSDT) &&
797 gbl_fadt->Xdsdt) {
798 table_address =
799 (acpi_physical_address) gbl_fadt->Xdsdt;
800 } else
801 if ((gbl_fadt->header.length >= MIN_FADT_FOR_DSDT)
802 && gbl_fadt->dsdt) {
803 table_address =
804 (acpi_physical_address) gbl_fadt->dsdt;
805 }
806 } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_FACS)) {
807 if ((gbl_fadt->header.length >= MIN_FADT_FOR_XFACS) &&
808 gbl_fadt->Xfacs) {
809 table_address =
810 (acpi_physical_address) gbl_fadt->Xfacs;
811 } else
812 if ((gbl_fadt->header.length >= MIN_FADT_FOR_FACS)
813 && gbl_fadt->facs) {
814 table_address =
815 (acpi_physical_address) gbl_fadt->facs;
816 }
817 } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_XSDT)) {
818 if (!gbl_revision) {
819 return (AE_BAD_SIGNATURE);
820 }
821 table_address =
822 (acpi_physical_address) gbl_rsdp.
823 xsdt_physical_address;
824 } else if (ACPI_COMPARE_NAME(signature, ACPI_SIG_RSDT)) {
825 table_address =
826 (acpi_physical_address) gbl_rsdp.
827 rsdt_physical_address;
828 } else {
829 table_address =
830 (acpi_physical_address) gbl_rsdp_address;
831 signature = ACPI_SIG_RSDP;
832 }
833
834 /* Now we can get the requested special table */
835
836 status = osl_map_table(table_address, signature, &mapped_table);
837 if (ACPI_FAILURE(status)) {
838 return (status);
839 }
840
841 table_length = ap_get_table_length(mapped_table);
842 } else { /* Case for a normal ACPI table */
843
844 if (osl_can_use_xsdt()) {
845 item_size = sizeof(u64);
846 table_data =
847 ACPI_CAST8(gbl_xsdt) +
848 sizeof(struct acpi_table_header);
849 number_of_tables =
850 (u8)((gbl_xsdt->header.length -
851 sizeof(struct acpi_table_header))
852 / item_size);
853 } else { /* Use RSDT if XSDT is not available */
854
855 item_size = sizeof(u32);
856 table_data =
857 ACPI_CAST8(gbl_rsdt) +
858 sizeof(struct acpi_table_header);
859 number_of_tables =
860 (u8)((gbl_rsdt->header.length -
861 sizeof(struct acpi_table_header))
862 / item_size);
863 }
864
865 /* Search RSDT/XSDT for the requested table */
866
867 for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
868 if (osl_can_use_xsdt()) {
869 table_address =
870 (acpi_physical_address) (*ACPI_CAST64
871 (table_data));
872 } else {
873 table_address =
874 (acpi_physical_address) (*ACPI_CAST32
875 (table_data));
876 }
877
878 /* Skip NULL entries in RSDT/XSDT */
879
880 if (!table_address) {
881 continue;
882 }
883
884 status =
885 osl_map_table(table_address, NULL, &mapped_table);
886 if (ACPI_FAILURE(status)) {
887 return (status);
888 }
889 table_length = mapped_table->length;
890
891 /* Does this table match the requested signature? */
892
893 if (!ACPI_COMPARE_NAME
894 (mapped_table->signature, signature)) {
895 osl_unmap_table(mapped_table);
896 mapped_table = NULL;
897 continue;
898 }
899
900 /* Match table instance (for SSDT/UEFI tables) */
901
902 if (current_instance != instance) {
903 osl_unmap_table(mapped_table);
904 mapped_table = NULL;
905 current_instance++;
906 continue;
907 }
908
909 break;
910 }
911 }
912
913 if (!mapped_table) {
914 return (AE_LIMIT);
915 }
916
917 if (table_length == 0) {
918 status = AE_BAD_HEADER;
919 goto exit;
920 }
921
922 /* Copy table to local buffer and return it */
923
924 local_table = calloc(1, table_length);
925 if (!local_table) {
926 status = AE_NO_MEMORY;
927 goto exit;
928 }
929
930 ACPI_MEMCPY(local_table, mapped_table, table_length);
931 *address = table_address;
932 *table = local_table;
933
934exit:
935 osl_unmap_table(mapped_table);
936 return (status);
937}
938
939/******************************************************************************
940 *
941 * FUNCTION: osl_list_customized_tables
942 *
943 * PARAMETERS: directory - Directory that contains the tables
944 *
945 * RETURN: Status; Table list is initialized if AE_OK.
946 *
947 * DESCRIPTION: Add ACPI tables to the table list from a directory.
948 *
949 *****************************************************************************/
950
951static acpi_status osl_list_customized_tables(char *directory)
952{
953 void *table_dir;
954 u32 instance;
955 char temp_name[ACPI_NAME_SIZE];
956 char *filename;
957 acpi_status status = AE_OK;
958
959 /* Open the requested directory */
960
961 table_dir = acpi_os_open_directory(directory, "*", REQUEST_FILE_ONLY);
962 if (!table_dir) {
963 return (osl_get_last_status(AE_NOT_FOUND));
964 }
965
966 /* Examine all entries in this directory */
967
968 while ((filename = acpi_os_get_next_filename(table_dir))) {
969
970 /* Extract table name and instance number */
971
972 status =
973 osl_table_name_from_file(filename, temp_name, &instance);
974
975 /* Ignore meaningless files */
976
977 if (ACPI_FAILURE(status)) {
978 continue;
979 }
980
981 /* Add new info node to global table list */
982
983 status = osl_add_table_to_list(temp_name, instance);
984 if (ACPI_FAILURE(status)) {
985 break;
986 }
987 }
988
989 acpi_os_close_directory(table_dir);
990 return (status);
991}
992
993/******************************************************************************
994 *
995 * FUNCTION: osl_map_table
996 *
997 * PARAMETERS: address - Address of the table in memory
998 * signature - Optional ACPI Signature for desired table.
999 * Null terminated 4-character string.
1000 * table - Where a pointer to the mapped table is
1001 * returned
1002 *
1003 * RETURN: Status; Mapped table is returned if AE_OK.
1004 * AE_NOT_FOUND: A valid table was not found at the address
1005 *
1006 * DESCRIPTION: Map entire ACPI table into caller's address space.
1007 *
1008 *****************************************************************************/
1009
1010static acpi_status
1011osl_map_table(acpi_size address,
1012 char *signature, struct acpi_table_header **table)
1013{
1014 struct acpi_table_header *mapped_table;
1015 u32 length;
1016
1017 if (!address) {
1018 return (AE_BAD_ADDRESS);
1019 }
1020
1021 /*
1022 * Map the header so we can get the table length.
1023 * Use sizeof (struct acpi_table_header) as:
1024 * 1. it is bigger than 24 to include RSDP->Length
1025 * 2. it is smaller than sizeof (struct acpi_table_rsdp)
1026 */
1027 mapped_table =
1028 acpi_os_map_memory(address, sizeof(struct acpi_table_header));
1029 if (!mapped_table) {
1030 fprintf(stderr, "Could not map table header at 0x%8.8X%8.8X\n",
1031 ACPI_FORMAT_UINT64(address));
1032 return (osl_get_last_status(AE_BAD_ADDRESS));
1033 }
1034
1035 /* If specified, signature must match */
1036
1037 if (signature) {
1038 if (ACPI_VALIDATE_RSDP_SIG(signature)) {
1039 if (!ACPI_VALIDATE_RSDP_SIG(mapped_table->signature)) {
1040 acpi_os_unmap_memory(mapped_table,
1041 sizeof(struct
1042 acpi_table_header));
1043 return (AE_BAD_SIGNATURE);
1044 }
1045 } else
1046 if (!ACPI_COMPARE_NAME(signature, mapped_table->signature))
1047 {
1048 acpi_os_unmap_memory(mapped_table,
1049 sizeof(struct acpi_table_header));
1050 return (AE_BAD_SIGNATURE);
1051 }
1052 }
1053
1054 /* Map the entire table */
1055
1056 length = ap_get_table_length(mapped_table);
1057 acpi_os_unmap_memory(mapped_table, sizeof(struct acpi_table_header));
1058 if (length == 0) {
1059 return (AE_BAD_HEADER);
1060 }
1061
1062 mapped_table = acpi_os_map_memory(address, length);
1063 if (!mapped_table) {
1064 fprintf(stderr,
1065 "Could not map table at 0x%8.8X%8.8X length %8.8X\n",
1066 ACPI_FORMAT_UINT64(address), length);
1067 return (osl_get_last_status(AE_INVALID_TABLE_LENGTH));
1068 }
1069
1070 (void)ap_is_valid_checksum(mapped_table);
1071
1072 *table = mapped_table;
1073 return (AE_OK);
1074}
1075
1076/******************************************************************************
1077 *
1078 * FUNCTION: osl_unmap_table
1079 *
1080 * PARAMETERS: table - A pointer to the mapped table
1081 *
1082 * RETURN: None
1083 *
1084 * DESCRIPTION: Unmap entire ACPI table.
1085 *
1086 *****************************************************************************/
1087
1088static void osl_unmap_table(struct acpi_table_header *table)
1089{
1090 if (table) {
1091 acpi_os_unmap_memory(table, ap_get_table_length(table));
1092 }
1093}
1094
1095/******************************************************************************
1096 *
1097 * FUNCTION: osl_table_name_from_file
1098 *
1099 * PARAMETERS: filename - File that contains the desired table
1100 * signature - Pointer to 4-character buffer to store
1101 * extracted table signature.
1102 * instance - Pointer to integer to store extracted
1103 * table instance number.
1104 *
1105 * RETURN: Status; Table name is extracted if AE_OK.
1106 *
1107 * DESCRIPTION: Extract table signature and instance number from a table file
1108 * name.
1109 *
1110 *****************************************************************************/
1111
1112static acpi_status
1113osl_table_name_from_file(char *filename, char *signature, u32 *instance)
1114{
1115
1116 /* Ignore meaningless files */
1117
1118 if (strlen(filename) < ACPI_NAME_SIZE) {
1119 return (AE_BAD_SIGNATURE);
1120 }
1121
1122 /* Extract instance number */
1123
1124 if (isdigit((int)filename[ACPI_NAME_SIZE])) {
1125 sscanf(&filename[ACPI_NAME_SIZE], "%d", instance);
1126 } else if (strlen(filename) != ACPI_NAME_SIZE) {
1127 return (AE_BAD_SIGNATURE);
1128 } else {
1129 *instance = 0;
1130 }
1131
1132 /* Extract signature */
1133
1134 ACPI_MOVE_NAME(signature, filename);
1135 return (AE_OK);
1136}
1137
1138/******************************************************************************
1139 *
1140 * FUNCTION: osl_read_table_from_file
1141 *
1142 * PARAMETERS: filename - File that contains the desired table
1143 * file_offset - Offset of the table in file
1144 * signature - Optional ACPI Signature for desired table.
1145 * A null terminated 4-character string.
1146 * table - Where a pointer to the table is returned
1147 *
1148 * RETURN: Status; Table buffer is returned if AE_OK.
1149 *
1150 * DESCRIPTION: Read a ACPI table from a file.
1151 *
1152 *****************************************************************************/
1153
1154static acpi_status
1155osl_read_table_from_file(char *filename,
1156 acpi_size file_offset,
1157 char *signature, struct acpi_table_header **table)
1158{
1159 FILE *table_file;
1160 struct acpi_table_header header;
1161 struct acpi_table_header *local_table = NULL;
1162 u32 table_length;
1163 s32 count;
1164 acpi_status status = AE_OK;
1165
1166 /* Open the file */
1167
1168 table_file = fopen(filename, "rb");
1169 if (table_file == NULL) {
1170 fprintf(stderr, "Could not open table file: %s\n", filename);
1171 return (osl_get_last_status(AE_NOT_FOUND));
1172 }
1173
1174 fseek(table_file, file_offset, SEEK_SET);
1175
1176 /* Read the Table header to get the table length */
1177
1178 count = fread(&header, 1, sizeof(struct acpi_table_header), table_file);
1179 if (count != sizeof(struct acpi_table_header)) {
1180 fprintf(stderr, "Could not read table header: %s\n", filename);
1181 status = AE_BAD_HEADER;
1182 goto exit;
1183 }
1184
1185 /* If signature is specified, it must match the table */
1186
1187 if (signature) {
1188 if (ACPI_VALIDATE_RSDP_SIG(signature)) {
1189 if (!ACPI_VALIDATE_RSDP_SIG(header.signature)) {
1190 fprintf(stderr,
1191 "Incorrect RSDP signature: found %8.8s\n",
1192 header.signature);
1193 status = AE_BAD_SIGNATURE;
1194 goto exit;
1195 }
1196 } else if (!ACPI_COMPARE_NAME(signature, header.signature)) {
1197 fprintf(stderr,
1198 "Incorrect signature: Expecting %4.4s, found %4.4s\n",
1199 signature, header.signature);
1200 status = AE_BAD_SIGNATURE;
1201 goto exit;
1202 }
1203 }
1204
1205 table_length = ap_get_table_length(&header);
1206 if (table_length == 0) {
1207 status = AE_BAD_HEADER;
1208 goto exit;
1209 }
1210
1211 /* Read the entire table into a local buffer */
1212
1213 local_table = calloc(1, table_length);
1214 if (!local_table) {
1215 fprintf(stderr,
1216 "%4.4s: Could not allocate buffer for table of length %X\n",
1217 header.signature, table_length);
1218 status = AE_NO_MEMORY;
1219 goto exit;
1220 }
1221
1222 fseek(table_file, file_offset, SEEK_SET);
1223
1224 count = fread(local_table, 1, table_length, table_file);
1225 if (count != table_length) {
1226 fprintf(stderr, "%4.4s: Could not read table content\n",
1227 header.signature);
1228 status = AE_INVALID_TABLE_LENGTH;
1229 goto exit;
1230 }
1231
1232 /* Validate checksum */
1233
1234 (void)ap_is_valid_checksum(local_table);
1235
1236exit:
1237 fclose(table_file);
1238 *table = local_table;
1239 return (status);
1240}
1241
1242/******************************************************************************
1243 *
1244 * FUNCTION: osl_get_customized_table
1245 *
1246 * PARAMETERS: pathname - Directory to find Linux customized table
1247 * signature - ACPI Signature for desired table. Must be
1248 * a null terminated 4-character string.
1249 * instance - Multiple table support for SSDT/UEFI (0...n)
1250 * Must be 0 for other tables.
1251 * table - Where a pointer to the table is returned
1252 * address - Where the table physical address is returned
1253 *
1254 * RETURN: Status; Table buffer is returned if AE_OK.
1255 * AE_LIMIT: Instance is beyond valid limit
1256 * AE_NOT_FOUND: A table with the signature was not found
1257 *
1258 * DESCRIPTION: Get an OS customized table.
1259 *
1260 *****************************************************************************/
1261
1262static acpi_status
1263osl_get_customized_table(char *pathname,
1264 char *signature,
1265 u32 instance,
1266 struct acpi_table_header **table,
1267 acpi_physical_address * address)
1268{
1269 void *table_dir;
1270 u32 current_instance = 0;
1271 char temp_name[ACPI_NAME_SIZE];
1272 char table_filename[PATH_MAX];
1273 char *filename;
1274 acpi_status status;
1275
1276 /* Open the directory for customized tables */
1277
1278 table_dir = acpi_os_open_directory(pathname, "*", REQUEST_FILE_ONLY);
1279 if (!table_dir) {
1280 return (osl_get_last_status(AE_NOT_FOUND));
1281 }
1282
1283 /* Attempt to find the table in the directory */
1284
1285 while ((filename = acpi_os_get_next_filename(table_dir))) {
1286
1287 /* Ignore meaningless files */
1288
1289 if (!ACPI_COMPARE_NAME(filename, signature)) {
1290 continue;
1291 }
1292
1293 /* Extract table name and instance number */
1294
1295 status =
1296 osl_table_name_from_file(filename, temp_name,
1297 &current_instance);
1298
1299 /* Ignore meaningless files */
1300
1301 if (ACPI_FAILURE(status) || current_instance != instance) {
1302 continue;
1303 }
1304
1305 /* Create the table pathname */
1306
1307 if (instance != 0) {
1308 sprintf(table_filename, "%s/%4.4s%d", pathname,
1309 temp_name, instance);
1310 } else {
1311 sprintf(table_filename, "%s/%4.4s", pathname,
1312 temp_name);
1313 }
1314 break;
1315 }
1316
1317 acpi_os_close_directory(table_dir);
1318
1319 if (!filename) {
1320 return (AE_LIMIT);
1321 }
1322
1323 /* There is no physical address saved for customized tables, use zero */
1324
1325 *address = 0;
1326 status = osl_read_table_from_file(table_filename, 0, NULL, table);
1327
1328 return (status);
1329}