1
2
3
4
5
6
7
8
9
10#include "acpidump.h"
11
12#define _COMPONENT ACPI_OS_SERVICES
13ACPI_MODULE_NAME("oslinuxtbl")
14
15#ifndef PATH_MAX
16#define PATH_MAX 256
17#endif
18
19typedef struct osl_table_info {
20 struct osl_table_info *next;
21 u32 instance;
22 char signature[ACPI_NAMESEG_SIZE];
23
24} osl_table_info;
25
26
27
28static acpi_status osl_table_initialize(void);
29
30static acpi_status
31osl_table_name_from_file(char *filename, char *signature, u32 *instance);
32
33static acpi_status osl_add_table_to_list(char *signature, u32 instance);
34
35static acpi_status
36osl_read_table_from_file(char *filename,
37 acpi_size file_offset,
38 char *signature, struct acpi_table_header **table);
39
40static acpi_status
41osl_map_table(acpi_size address,
42 char *signature, struct acpi_table_header **table);
43
44static void osl_unmap_table(struct acpi_table_header *table);
45
46static acpi_physical_address
47osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword);
48
49static acpi_physical_address osl_find_rsdp_via_efi(void);
50
51static acpi_status osl_load_rsdp(void);
52
53static acpi_status osl_list_customized_tables(char *directory);
54
55static acpi_status
56osl_get_customized_table(char *pathname,
57 char *signature,
58 u32 instance,
59 struct acpi_table_header **table,
60 acpi_physical_address *address);
61
62static acpi_status osl_list_bios_tables(void);
63
64static acpi_status
65osl_get_bios_table(char *signature,
66 u32 instance,
67 struct acpi_table_header **table,
68 acpi_physical_address *address);
69
70static acpi_status osl_get_last_status(acpi_status default_status);
71
72
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
79
80u8 gbl_dump_dynamic_tables = TRUE;
81
82
83
84u8 gbl_table_list_initialized = FALSE;
85
86
87
88struct acpi_table_rsdp gbl_rsdp;
89struct acpi_table_fadt *gbl_fadt = NULL;
90struct acpi_table_rsdt *gbl_rsdt = NULL;
91struct acpi_table_xsdt *gbl_xsdt = NULL;
92
93
94
95acpi_physical_address gbl_fadt_address = 0;
96acpi_physical_address gbl_rsdp_address = 0;
97
98
99
100u8 gbl_revision = 0;
101
102struct osl_table_info *gbl_table_list_head = NULL;
103u32 gbl_table_count = 0;
104
105
106
107
108
109
110
111
112
113
114
115
116
117static 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
143
144
145
146
147
148
149
150
151
152
153
154acpi_status
155acpi_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
164
165 status = osl_table_initialize();
166 if (ACPI_FAILURE(status)) {
167 return (status);
168 }
169
170
171
172 status = osl_map_table(address, NULL, &mapped_table);
173 if (ACPI_FAILURE(status)) {
174 return (status);
175 }
176
177
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
193exit:
194 osl_unmap_table(mapped_table);
195 *table = local_table;
196 return (status);
197}
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218acpi_status
219acpi_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
227
228 status = osl_table_initialize();
229 if (ACPI_FAILURE(status)) {
230 return (status);
231 }
232
233
234
235 if (!gbl_dump_customized_tables) {
236
237
238
239 status =
240 osl_get_bios_table(signature, instance, table, address);
241 } else {
242
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
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
266
267
268
269
270
271
272
273
274
275
276
277static 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
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347acpi_status
348acpi_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
357
358 status = osl_table_initialize();
359 if (ACPI_FAILURE(status)) {
360 return (status);
361 }
362
363
364
365 if (index >= gbl_table_count) {
366 return (AE_LIMIT);
367 }
368
369
370
371 info = gbl_table_list_head;
372 for (i = 0; i < index; i++) {
373 info = info->next;
374 }
375
376
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
390
391
392
393
394
395
396
397
398
399
400
401static acpi_physical_address
402osl_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
422
423
424
425
426
427
428
429
430
431static 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
452
453
454
455
456
457
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
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
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
509
510
511
512
513
514
515
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
531
532
533
534
535
536
537
538
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 if (!gbl_dump_customized_tables) {
552
553
554
555 status = osl_load_rsdp();
556 if (ACPI_FAILURE(status)) {
557 return (status);
558 }
559
560
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
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
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
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
643
644 status = osl_list_bios_tables();
645 if (ACPI_FAILURE(status)) {
646 return (status);
647 }
648 } else {
649
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
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
674
675
676
677
678
679
680
681
682
683
684
685
686static 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 {
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
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
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
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765static acpi_status
766osl_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
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
791find_next_instance:
792
793 table_address = 0;
794
795
796
797
798
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
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
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 {
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 {
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
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
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
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
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
954exit_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
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
977exit:
978 osl_unmap_table(mapped_table);
979 return (status);
980}
981
982
983
984
985
986
987
988
989
990
991
992
993
994static 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
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
1053static acpi_status
1054osl_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
1131static 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
1155static acpi_status
1156osl_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
1196
1197static acpi_status
1198osl_read_table_from_file(char *filename,
1199 acpi_size file_offset,
1200 char *signature, struct acpi_table_header **table)
1201{
1202 FILE *table_file;
1203 struct acpi_table_header header;
1204 struct acpi_table_header *local_table = NULL;
1205 u32 table_length;
1206 s32 count;
1207 acpi_status status = AE_OK;
1208
1209
1210
1211 table_file = fopen(filename, "rb");
1212 if (table_file == NULL) {
1213 fprintf(stderr, "Could not open table file: %s\n", filename);
1214 return (osl_get_last_status(AE_NOT_FOUND));
1215 }
1216
1217 fseek(table_file, file_offset, SEEK_SET);
1218
1219
1220
1221 count = fread(&header, 1, sizeof(struct acpi_table_header), table_file);
1222 if (count != sizeof(struct acpi_table_header)) {
1223 fprintf(stderr, "Could not read table header: %s\n", filename);
1224 status = AE_BAD_HEADER;
1225 goto exit;
1226 }
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
1248 table_length = ap_get_table_length(&header);
1249 if (table_length == 0) {
1250 status = AE_BAD_HEADER;
1251 goto exit;
1252 }
1253
1254
1255
1256 local_table = calloc(1, table_length);
1257 if (!local_table) {
1258 fprintf(stderr,
1259 "%4.4s: Could not allocate buffer for table of length %X\n",
1260 header.signature, table_length);
1261 status = AE_NO_MEMORY;
1262 goto exit;
1263 }
1264
1265 fseek(table_file, file_offset, SEEK_SET);
1266
1267 count = fread(local_table, 1, table_length, table_file);
1268 if (count != table_length) {
1269 fprintf(stderr, "%4.4s: Could not read table content\n",
1270 header.signature);
1271 status = AE_INVALID_TABLE_LENGTH;
1272 goto exit;
1273 }
1274
1275
1276
1277 (void)ap_is_valid_checksum(local_table);
1278
1279exit:
1280 fclose(table_file);
1281 *table = local_table;
1282 return (status);
1283}
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305static acpi_status
1306osl_get_customized_table(char *pathname,
1307 char *signature,
1308 u32 instance,
1309 struct acpi_table_header **table,
1310 acpi_physical_address *address)
1311{
1312 void *table_dir;
1313 u32 current_instance = 0;
1314 char temp_name[ACPI_NAMESEG_SIZE];
1315 char table_filename[PATH_MAX];
1316 char *filename;
1317 acpi_status status;
1318
1319
1320
1321 table_dir = acpi_os_open_directory(pathname, "*", REQUEST_FILE_ONLY);
1322 if (!table_dir) {
1323 return (osl_get_last_status(AE_NOT_FOUND));
1324 }
1325
1326
1327
1328 while ((filename = acpi_os_get_next_filename(table_dir))) {
1329
1330
1331
1332 if (!ACPI_COMPARE_NAMESEG(filename, signature)) {
1333 continue;
1334 }
1335
1336
1337
1338 status =
1339 osl_table_name_from_file(filename, temp_name,
1340 ¤t_instance);
1341
1342
1343
1344 if (ACPI_FAILURE(status) || current_instance != instance) {
1345 continue;
1346 }
1347
1348
1349
1350 if (instance != 0) {
1351 sprintf(table_filename, "%s/%4.4s%d", pathname,
1352 temp_name, instance);
1353 } else {
1354 sprintf(table_filename, "%s/%4.4s", pathname,
1355 temp_name);
1356 }
1357 break;
1358 }
1359
1360 acpi_os_close_directory(table_dir);
1361
1362 if (!filename) {
1363 return (AE_LIMIT);
1364 }
1365
1366
1367
1368 *address = 0;
1369 status = osl_read_table_from_file(table_filename, 0, NULL, table);
1370
1371 return (status);
1372}
1373