0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include "acpidump.h"
0011
0012 #define _COMPONENT ACPI_OS_SERVICES
0013 ACPI_MODULE_NAME("oslinuxtbl")
0014
0015 #ifndef PATH_MAX
0016 #define PATH_MAX 256
0017 #endif
0018
0019 typedef struct osl_table_info {
0020 struct osl_table_info *next;
0021 u32 instance;
0022 char signature[ACPI_NAMESEG_SIZE];
0023
0024 } osl_table_info;
0025
0026
0027
0028 static acpi_status osl_table_initialize(void);
0029
0030 static acpi_status
0031 osl_table_name_from_file(char *filename, char *signature, u32 *instance);
0032
0033 static acpi_status osl_add_table_to_list(char *signature, u32 instance);
0034
0035 static acpi_status
0036 osl_read_table_from_file(char *filename,
0037 acpi_size file_offset,
0038 struct acpi_table_header **table);
0039
0040 static acpi_status
0041 osl_map_table(acpi_size address,
0042 char *signature, struct acpi_table_header **table);
0043
0044 static void osl_unmap_table(struct acpi_table_header *table);
0045
0046 static acpi_physical_address
0047 osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword);
0048
0049 static acpi_physical_address osl_find_rsdp_via_efi(void);
0050
0051 static acpi_status osl_load_rsdp(void);
0052
0053 static acpi_status osl_list_customized_tables(char *directory);
0054
0055 static acpi_status
0056 osl_get_customized_table(char *pathname,
0057 char *signature,
0058 u32 instance,
0059 struct acpi_table_header **table,
0060 acpi_physical_address *address);
0061
0062 static acpi_status osl_list_bios_tables(void);
0063
0064 static acpi_status
0065 osl_get_bios_table(char *signature,
0066 u32 instance,
0067 struct acpi_table_header **table,
0068 acpi_physical_address *address);
0069
0070 static acpi_status osl_get_last_status(acpi_status default_status);
0071
0072
0073
0074 #define DYNAMIC_TABLE_DIR "/sys/firmware/acpi/tables/dynamic"
0075 #define STATIC_TABLE_DIR "/sys/firmware/acpi/tables"
0076 #define EFI_SYSTAB "/sys/firmware/efi/systab"
0077
0078
0079
0080 u8 gbl_dump_dynamic_tables = TRUE;
0081
0082
0083
0084 u8 gbl_table_list_initialized = FALSE;
0085
0086
0087
0088 struct acpi_table_rsdp gbl_rsdp;
0089 struct acpi_table_fadt *gbl_fadt = NULL;
0090 struct acpi_table_rsdt *gbl_rsdt = NULL;
0091 struct acpi_table_xsdt *gbl_xsdt = NULL;
0092
0093
0094
0095 acpi_physical_address gbl_fadt_address = 0;
0096 acpi_physical_address gbl_rsdp_address = 0;
0097
0098
0099
0100 u8 gbl_revision = 0;
0101
0102 struct osl_table_info *gbl_table_list_head = NULL;
0103 u32 gbl_table_count = 0;
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114
0115
0116
0117 static acpi_status osl_get_last_status(acpi_status default_status)
0118 {
0119
0120 switch (errno) {
0121 case EACCES:
0122 case EPERM:
0123
0124 return (AE_ACCESS);
0125
0126 case ENOENT:
0127
0128 return (AE_NOT_FOUND);
0129
0130 case ENOMEM:
0131
0132 return (AE_NO_MEMORY);
0133
0134 default:
0135
0136 return (default_status);
0137 }
0138 }
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149
0150
0151
0152
0153
0154 acpi_status
0155 acpi_os_get_table_by_address(acpi_physical_address address,
0156 struct acpi_table_header **table)
0157 {
0158 u32 table_length;
0159 struct acpi_table_header *mapped_table;
0160 struct acpi_table_header *local_table = NULL;
0161 acpi_status status = AE_OK;
0162
0163
0164
0165 status = osl_table_initialize();
0166 if (ACPI_FAILURE(status)) {
0167 return (status);
0168 }
0169
0170
0171
0172 status = osl_map_table(address, NULL, &mapped_table);
0173 if (ACPI_FAILURE(status)) {
0174 return (status);
0175 }
0176
0177
0178
0179 table_length = ap_get_table_length(mapped_table);
0180 if (table_length == 0) {
0181 status = AE_BAD_HEADER;
0182 goto exit;
0183 }
0184
0185 local_table = calloc(1, table_length);
0186 if (!local_table) {
0187 status = AE_NO_MEMORY;
0188 goto exit;
0189 }
0190
0191 memcpy(local_table, mapped_table, table_length);
0192
0193 exit:
0194 osl_unmap_table(mapped_table);
0195 *table = local_table;
0196 return (status);
0197 }
0198
0199
0200
0201
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218 acpi_status
0219 acpi_os_get_table_by_name(char *signature,
0220 u32 instance,
0221 struct acpi_table_header **table,
0222 acpi_physical_address *address)
0223 {
0224 acpi_status status;
0225
0226
0227
0228 status = osl_table_initialize();
0229 if (ACPI_FAILURE(status)) {
0230 return (status);
0231 }
0232
0233
0234
0235 if (!gbl_dump_customized_tables) {
0236
0237
0238
0239 status =
0240 osl_get_bios_table(signature, instance, table, address);
0241 } else {
0242
0243
0244 status = osl_get_customized_table(STATIC_TABLE_DIR, signature,
0245 instance, table, address);
0246 }
0247
0248 if (ACPI_FAILURE(status) && status == AE_LIMIT) {
0249 if (gbl_dump_dynamic_tables) {
0250
0251
0252
0253 status =
0254 osl_get_customized_table(DYNAMIC_TABLE_DIR,
0255 signature, instance, table,
0256 address);
0257 }
0258 }
0259
0260 return (status);
0261 }
0262
0263
0264
0265
0266
0267
0268
0269
0270
0271
0272
0273
0274
0275
0276
0277 static acpi_status osl_add_table_to_list(char *signature, u32 instance)
0278 {
0279 struct osl_table_info *new_info;
0280 struct osl_table_info *next;
0281 u32 next_instance = 0;
0282 u8 found = FALSE;
0283
0284 new_info = calloc(1, sizeof(struct osl_table_info));
0285 if (!new_info) {
0286 return (AE_NO_MEMORY);
0287 }
0288
0289 ACPI_COPY_NAMESEG(new_info->signature, signature);
0290
0291 if (!gbl_table_list_head) {
0292 gbl_table_list_head = new_info;
0293 } else {
0294 next = gbl_table_list_head;
0295 while (1) {
0296 if (ACPI_COMPARE_NAMESEG(next->signature, signature)) {
0297 if (next->instance == instance) {
0298 found = TRUE;
0299 }
0300 if (next->instance >= next_instance) {
0301 next_instance = next->instance + 1;
0302 }
0303 }
0304
0305 if (!next->next) {
0306 break;
0307 }
0308 next = next->next;
0309 }
0310 next->next = new_info;
0311 }
0312
0313 if (found) {
0314 if (instance) {
0315 fprintf(stderr,
0316 "%4.4s: Warning unmatched table instance %d, expected %d\n",
0317 signature, instance, next_instance);
0318 }
0319 instance = next_instance;
0320 }
0321
0322 new_info->instance = instance;
0323 gbl_table_count++;
0324
0325 return (AE_OK);
0326 }
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338
0339
0340
0341
0342
0343
0344
0345
0346
0347 acpi_status
0348 acpi_os_get_table_by_index(u32 index,
0349 struct acpi_table_header **table,
0350 u32 *instance, acpi_physical_address *address)
0351 {
0352 struct osl_table_info *info;
0353 acpi_status status;
0354 u32 i;
0355
0356
0357
0358 status = osl_table_initialize();
0359 if (ACPI_FAILURE(status)) {
0360 return (status);
0361 }
0362
0363
0364
0365 if (index >= gbl_table_count) {
0366 return (AE_LIMIT);
0367 }
0368
0369
0370
0371 info = gbl_table_list_head;
0372 for (i = 0; i < index; i++) {
0373 info = info->next;
0374 }
0375
0376
0377
0378 status = acpi_os_get_table_by_name(info->signature, info->instance,
0379 table, address);
0380
0381 if (ACPI_SUCCESS(status)) {
0382 *instance = info->instance;
0383 }
0384 return (status);
0385 }
0386
0387
0388
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401 static acpi_physical_address
0402 osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword)
0403 {
0404 char buffer[80];
0405 unsigned long long address = 0;
0406 char format[32];
0407
0408 snprintf(format, 32, "%s=%s", keyword, "%llx");
0409 fseek(file, 0, SEEK_SET);
0410 while (fgets(buffer, 80, file)) {
0411 if (sscanf(buffer, format, &address) == 1) {
0412 break;
0413 }
0414 }
0415
0416 return ((acpi_physical_address)(address));
0417 }
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431 static acpi_physical_address osl_find_rsdp_via_efi(void)
0432 {
0433 FILE *file;
0434 acpi_physical_address address = 0;
0435
0436 file = fopen(EFI_SYSTAB, "r");
0437 if (file) {
0438 address = osl_find_rsdp_via_efi_by_keyword(file, "ACPI20");
0439 if (!address) {
0440 address =
0441 osl_find_rsdp_via_efi_by_keyword(file, "ACPI");
0442 }
0443 fclose(file);
0444 }
0445
0446 return (address);
0447 }
0448
0449
0450
0451
0452
0453
0454
0455
0456
0457
0458
0459
0460
0461 static acpi_status osl_load_rsdp(void)
0462 {
0463 struct acpi_table_header *mapped_table;
0464 u8 *rsdp_address;
0465 acpi_physical_address rsdp_base;
0466 acpi_size rsdp_size;
0467
0468
0469
0470 rsdp_size = sizeof(struct acpi_table_rsdp);
0471 if (gbl_rsdp_base) {
0472 rsdp_base = gbl_rsdp_base;
0473 } else {
0474 rsdp_base = osl_find_rsdp_via_efi();
0475 }
0476
0477 if (!rsdp_base) {
0478 rsdp_base = ACPI_HI_RSDP_WINDOW_BASE;
0479 rsdp_size = ACPI_HI_RSDP_WINDOW_SIZE;
0480 }
0481
0482 rsdp_address = acpi_os_map_memory(rsdp_base, rsdp_size);
0483 if (!rsdp_address) {
0484 return (osl_get_last_status(AE_BAD_ADDRESS));
0485 }
0486
0487
0488
0489 mapped_table = ACPI_CAST_PTR(struct acpi_table_header,
0490 acpi_tb_scan_memory_for_rsdp(rsdp_address,
0491 rsdp_size));
0492 if (!mapped_table) {
0493 acpi_os_unmap_memory(rsdp_address, rsdp_size);
0494 return (AE_NOT_FOUND);
0495 }
0496
0497 gbl_rsdp_address =
0498 rsdp_base + (ACPI_CAST8(mapped_table) - rsdp_address);
0499
0500 memcpy(&gbl_rsdp, mapped_table, sizeof(struct acpi_table_rsdp));
0501 acpi_os_unmap_memory(rsdp_address, rsdp_size);
0502
0503 return (AE_OK);
0504 }
0505
0506
0507
0508
0509
0510
0511
0512
0513
0514
0515
0516
0517
0518
0519 static u8 osl_can_use_xsdt(void)
0520 {
0521 if (gbl_revision && !acpi_gbl_do_not_use_xsdt) {
0522 return (TRUE);
0523 } else {
0524 return (FALSE);
0525 }
0526 }
0527
0528
0529
0530
0531
0532
0533
0534
0535
0536
0537
0538
0539
0540
0541
0542 static acpi_status osl_table_initialize(void)
0543 {
0544 acpi_status status;
0545 acpi_physical_address address;
0546
0547 if (gbl_table_list_initialized) {
0548 return (AE_OK);
0549 }
0550
0551 if (!gbl_dump_customized_tables) {
0552
0553
0554
0555 status = osl_load_rsdp();
0556 if (ACPI_FAILURE(status)) {
0557 return (status);
0558 }
0559
0560
0561
0562 if (gbl_rsdp.revision && !gbl_do_not_dump_xsdt) {
0563 if (gbl_xsdt) {
0564 free(gbl_xsdt);
0565 gbl_xsdt = NULL;
0566 }
0567
0568 gbl_revision = 2;
0569 status = osl_get_bios_table(ACPI_SIG_XSDT, 0,
0570 ACPI_CAST_PTR(struct
0571 acpi_table_header
0572 *, &gbl_xsdt),
0573 &address);
0574 if (ACPI_FAILURE(status)) {
0575 return (status);
0576 }
0577 }
0578
0579
0580
0581 if (gbl_rsdp.rsdt_physical_address) {
0582 if (gbl_rsdt) {
0583 free(gbl_rsdt);
0584 gbl_rsdt = NULL;
0585 }
0586
0587 status = osl_get_bios_table(ACPI_SIG_RSDT, 0,
0588 ACPI_CAST_PTR(struct
0589 acpi_table_header
0590 *, &gbl_rsdt),
0591 &address);
0592 if (ACPI_FAILURE(status)) {
0593 return (status);
0594 }
0595 }
0596
0597
0598
0599 if (gbl_fadt) {
0600 free(gbl_fadt);
0601 gbl_fadt = NULL;
0602 }
0603
0604 status = osl_get_bios_table(ACPI_SIG_FADT, 0,
0605 ACPI_CAST_PTR(struct
0606 acpi_table_header *,
0607 &gbl_fadt),
0608 &gbl_fadt_address);
0609 if (ACPI_FAILURE(status)) {
0610 return (status);
0611 }
0612
0613
0614
0615 status = osl_add_table_to_list(ACPI_RSDP_NAME, 0);
0616 if (ACPI_FAILURE(status)) {
0617 return (status);
0618 }
0619
0620 status = osl_add_table_to_list(ACPI_SIG_RSDT, 0);
0621 if (ACPI_FAILURE(status)) {
0622 return (status);
0623 }
0624
0625 if (gbl_revision == 2) {
0626 status = osl_add_table_to_list(ACPI_SIG_XSDT, 0);
0627 if (ACPI_FAILURE(status)) {
0628 return (status);
0629 }
0630 }
0631
0632 status = osl_add_table_to_list(ACPI_SIG_DSDT, 0);
0633 if (ACPI_FAILURE(status)) {
0634 return (status);
0635 }
0636
0637 status = osl_add_table_to_list(ACPI_SIG_FACS, 0);
0638 if (ACPI_FAILURE(status)) {
0639 return (status);
0640 }
0641
0642
0643
0644 status = osl_list_bios_tables();
0645 if (ACPI_FAILURE(status)) {
0646 return (status);
0647 }
0648 } else {
0649
0650
0651 status = osl_list_customized_tables(STATIC_TABLE_DIR);
0652 if (ACPI_FAILURE(status)) {
0653 return (status);
0654 }
0655 }
0656
0657 if (gbl_dump_dynamic_tables) {
0658
0659
0660
0661 status = osl_list_customized_tables(DYNAMIC_TABLE_DIR);
0662 if (ACPI_FAILURE(status)) {
0663 return (status);
0664 }
0665 }
0666
0667 gbl_table_list_initialized = TRUE;
0668 return (AE_OK);
0669 }
0670
0671
0672
0673
0674
0675
0676
0677
0678
0679
0680
0681
0682
0683
0684
0685
0686 static acpi_status osl_list_bios_tables(void)
0687 {
0688 struct acpi_table_header *mapped_table = NULL;
0689 u8 *table_data;
0690 u8 number_of_tables;
0691 u8 item_size;
0692 acpi_physical_address table_address = 0;
0693 acpi_status status = AE_OK;
0694 u32 i;
0695
0696 if (osl_can_use_xsdt()) {
0697 item_size = sizeof(u64);
0698 table_data =
0699 ACPI_CAST8(gbl_xsdt) + sizeof(struct acpi_table_header);
0700 number_of_tables =
0701 (u8)((gbl_xsdt->header.length -
0702 sizeof(struct acpi_table_header))
0703 / item_size);
0704 } else {
0705
0706 item_size = sizeof(u32);
0707 table_data =
0708 ACPI_CAST8(gbl_rsdt) + sizeof(struct acpi_table_header);
0709 number_of_tables =
0710 (u8)((gbl_rsdt->header.length -
0711 sizeof(struct acpi_table_header))
0712 / item_size);
0713 }
0714
0715
0716
0717 for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
0718 if (osl_can_use_xsdt()) {
0719 table_address =
0720 (acpi_physical_address)(*ACPI_CAST64(table_data));
0721 } else {
0722 table_address =
0723 (acpi_physical_address)(*ACPI_CAST32(table_data));
0724 }
0725
0726
0727
0728 if (table_address == 0) {
0729 continue;
0730 }
0731
0732 status = osl_map_table(table_address, NULL, &mapped_table);
0733 if (ACPI_FAILURE(status)) {
0734 return (status);
0735 }
0736
0737 osl_add_table_to_list(mapped_table->signature, 0);
0738 osl_unmap_table(mapped_table);
0739 }
0740
0741 return (AE_OK);
0742 }
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753
0754
0755
0756
0757
0758
0759
0760
0761
0762
0763
0764
0765 static acpi_status
0766 osl_get_bios_table(char *signature,
0767 u32 instance,
0768 struct acpi_table_header **table,
0769 acpi_physical_address *address)
0770 {
0771 struct acpi_table_header *local_table = NULL;
0772 struct acpi_table_header *mapped_table = NULL;
0773 u8 *table_data;
0774 u8 number_of_tables;
0775 u8 item_size;
0776 u32 current_instance = 0;
0777 acpi_physical_address table_address;
0778 acpi_physical_address first_table_address = 0;
0779 u32 table_length = 0;
0780 acpi_status status = AE_OK;
0781 u32 i;
0782
0783
0784
0785 if (ACPI_COMPARE_NAMESEG(signature, ACPI_RSDP_NAME) ||
0786 ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_RSDT) ||
0787 ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_XSDT) ||
0788 ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_DSDT) ||
0789 ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_FACS)) {
0790
0791 find_next_instance:
0792
0793 table_address = 0;
0794
0795
0796
0797
0798
0799
0800 if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_DSDT)) {
0801 if (current_instance < 2) {
0802 if ((gbl_fadt->header.length >=
0803 MIN_FADT_FOR_XDSDT) && gbl_fadt->Xdsdt
0804 && current_instance == 0) {
0805 table_address =
0806 (acpi_physical_address)gbl_fadt->
0807 Xdsdt;
0808 } else
0809 if ((gbl_fadt->header.length >=
0810 MIN_FADT_FOR_DSDT)
0811 && gbl_fadt->dsdt !=
0812 first_table_address) {
0813 table_address =
0814 (acpi_physical_address)gbl_fadt->
0815 dsdt;
0816 }
0817 }
0818 } else if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_FACS)) {
0819 if (current_instance < 2) {
0820 if ((gbl_fadt->header.length >=
0821 MIN_FADT_FOR_XFACS) && gbl_fadt->Xfacs
0822 && current_instance == 0) {
0823 table_address =
0824 (acpi_physical_address)gbl_fadt->
0825 Xfacs;
0826 } else
0827 if ((gbl_fadt->header.length >=
0828 MIN_FADT_FOR_FACS)
0829 && gbl_fadt->facs !=
0830 first_table_address) {
0831 table_address =
0832 (acpi_physical_address)gbl_fadt->
0833 facs;
0834 }
0835 }
0836 } else if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_XSDT)) {
0837 if (!gbl_revision) {
0838 return (AE_BAD_SIGNATURE);
0839 }
0840 if (current_instance == 0) {
0841 table_address =
0842 (acpi_physical_address)gbl_rsdp.
0843 xsdt_physical_address;
0844 }
0845 } else if (ACPI_COMPARE_NAMESEG(signature, ACPI_SIG_RSDT)) {
0846 if (current_instance == 0) {
0847 table_address =
0848 (acpi_physical_address)gbl_rsdp.
0849 rsdt_physical_address;
0850 }
0851 } else {
0852 if (current_instance == 0) {
0853 table_address =
0854 (acpi_physical_address)gbl_rsdp_address;
0855 signature = ACPI_SIG_RSDP;
0856 }
0857 }
0858
0859 if (table_address == 0) {
0860 goto exit_find_table;
0861 }
0862
0863
0864
0865 status = osl_map_table(table_address, signature, &mapped_table);
0866 if (ACPI_FAILURE(status)) {
0867 return (status);
0868 }
0869
0870 table_length = ap_get_table_length(mapped_table);
0871 if (first_table_address == 0) {
0872 first_table_address = table_address;
0873 }
0874
0875
0876
0877 if (current_instance != instance) {
0878 osl_unmap_table(mapped_table);
0879 mapped_table = NULL;
0880 current_instance++;
0881 goto find_next_instance;
0882 }
0883 } else {
0884
0885 if (osl_can_use_xsdt()) {
0886 item_size = sizeof(u64);
0887 table_data =
0888 ACPI_CAST8(gbl_xsdt) +
0889 sizeof(struct acpi_table_header);
0890 number_of_tables =
0891 (u8)((gbl_xsdt->header.length -
0892 sizeof(struct acpi_table_header))
0893 / item_size);
0894 } else {
0895
0896 item_size = sizeof(u32);
0897 table_data =
0898 ACPI_CAST8(gbl_rsdt) +
0899 sizeof(struct acpi_table_header);
0900 number_of_tables =
0901 (u8)((gbl_rsdt->header.length -
0902 sizeof(struct acpi_table_header))
0903 / item_size);
0904 }
0905
0906
0907
0908 for (i = 0; i < number_of_tables; ++i, table_data += item_size) {
0909 if (osl_can_use_xsdt()) {
0910 table_address =
0911 (acpi_physical_address)(*ACPI_CAST64
0912 (table_data));
0913 } else {
0914 table_address =
0915 (acpi_physical_address)(*ACPI_CAST32
0916 (table_data));
0917 }
0918
0919
0920
0921 if (table_address == 0) {
0922 continue;
0923 }
0924
0925 status =
0926 osl_map_table(table_address, NULL, &mapped_table);
0927 if (ACPI_FAILURE(status)) {
0928 return (status);
0929 }
0930 table_length = mapped_table->length;
0931
0932
0933
0934 if (!ACPI_COMPARE_NAMESEG
0935 (mapped_table->signature, signature)) {
0936 osl_unmap_table(mapped_table);
0937 mapped_table = NULL;
0938 continue;
0939 }
0940
0941
0942
0943 if (current_instance != instance) {
0944 osl_unmap_table(mapped_table);
0945 mapped_table = NULL;
0946 current_instance++;
0947 continue;
0948 }
0949
0950 break;
0951 }
0952 }
0953
0954 exit_find_table:
0955
0956 if (!mapped_table) {
0957 return (AE_LIMIT);
0958 }
0959
0960 if (table_length == 0) {
0961 status = AE_BAD_HEADER;
0962 goto exit;
0963 }
0964
0965
0966
0967 local_table = calloc(1, table_length);
0968 if (!local_table) {
0969 status = AE_NO_MEMORY;
0970 goto exit;
0971 }
0972
0973 memcpy(local_table, mapped_table, table_length);
0974 *address = table_address;
0975 *table = local_table;
0976
0977 exit:
0978 osl_unmap_table(mapped_table);
0979 return (status);
0980 }
0981
0982
0983
0984
0985
0986
0987
0988
0989
0990
0991
0992
0993
0994 static acpi_status osl_list_customized_tables(char *directory)
0995 {
0996 void *table_dir;
0997 u32 instance;
0998 char temp_name[ACPI_NAMESEG_SIZE];
0999 char *filename;
1000 acpi_status status = AE_OK;
1001
1002
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
1010
1011 while ((filename = acpi_os_get_next_filename(table_dir))) {
1012
1013
1014
1015 status =
1016 osl_table_name_from_file(filename, temp_name, &instance);
1017
1018
1019
1020 if (ACPI_FAILURE(status)) {
1021 continue;
1022 }
1023
1024
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
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
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
1066
1067
1068
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
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
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
1122
1123
1124
1125
1126
1127
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
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155 static acpi_status
1156 osl_table_name_from_file(char *filename, char *signature, u32 *instance)
1157 {
1158
1159
1160
1161 if (strlen(filename) < ACPI_NAMESEG_SIZE) {
1162 return (AE_BAD_SIGNATURE);
1163 }
1164
1165
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
1176
1177 ACPI_COPY_NAMESEG(signature, filename);
1178 return (AE_OK);
1179 }
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
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
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
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
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
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
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
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
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
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
1328
1329 while ((filename = acpi_os_get_next_filename(table_dir))) {
1330
1331
1332
1333 if (!ACPI_COMPARE_NAMESEG(filename, signature)) {
1334 continue;
1335 }
1336
1337
1338
1339 status =
1340 osl_table_name_from_file(filename, temp_name,
1341 ¤t_instance);
1342
1343
1344
1345 if (ACPI_FAILURE(status) || current_instance != instance) {
1346 continue;
1347 }
1348
1349
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
1368
1369 *address = 0;
1370 status = osl_read_table_from_file(table_filename, 0, table);
1371
1372 return (status);
1373 }