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