~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 - 2023, 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];
 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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php