Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
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 /* List of information about obtained ACPI tables */
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 /* Local prototypes */
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 /* File locations */
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 /* Should we get dynamically loaded SSDTs from DYNAMIC_TABLE_DIR? */
0079 
0080 u8 gbl_dump_dynamic_tables = TRUE;
0081 
0082 /* Initialization flags */
0083 
0084 u8 gbl_table_list_initialized = FALSE;
0085 
0086 /* Local copies of main ACPI tables */
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 /* Table addresses */
0094 
0095 acpi_physical_address gbl_fadt_address = 0;
0096 acpi_physical_address gbl_rsdp_address = 0;
0097 
0098 /* Revision of RSD PTR */
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  * FUNCTION:    osl_get_last_status
0108  *
0109  * PARAMETERS:  default_status  - Default error status to return
0110  *
0111  * RETURN:      Status; Converted from errno.
0112  *
0113  * DESCRIPTION: Get last errno and convert it to acpi_status.
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  * FUNCTION:    acpi_os_get_table_by_address
0143  *
0144  * PARAMETERS:  address         - Physical address of the ACPI table
0145  *              table           - Where a pointer to the table is returned
0146  *
0147  * RETURN:      Status; Table buffer is returned if AE_OK.
0148  *              AE_NOT_FOUND: A valid table was not found at the address
0149  *
0150  * DESCRIPTION: Get an ACPI table via a physical memory address.
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     /* Get main ACPI tables from memory on first invocation of this function */
0164 
0165     status = osl_table_initialize();
0166     if (ACPI_FAILURE(status)) {
0167         return (status);
0168     }
0169 
0170     /* Map the table and validate it */
0171 
0172     status = osl_map_table(address, NULL, &mapped_table);
0173     if (ACPI_FAILURE(status)) {
0174         return (status);
0175     }
0176 
0177     /* Copy table to local buffer and return it */
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  * FUNCTION:    acpi_os_get_table_by_name
0202  *
0203  * PARAMETERS:  signature       - ACPI Signature for desired table. Must be
0204  *                                a null terminated 4-character string.
0205  *              instance        - Multiple table support for SSDT/UEFI (0...n)
0206  *                                Must be 0 for other tables.
0207  *              table           - Where a pointer to the table is returned
0208  *              address         - Where the table physical address is returned
0209  *
0210  * RETURN:      Status; Table buffer and physical address returned if AE_OK.
0211  *              AE_LIMIT: Instance is beyond valid limit
0212  *              AE_NOT_FOUND: A table with the signature was not found
0213  *
0214  * NOTE:        Assumes the input signature is uppercase.
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     /* Get main ACPI tables from memory on first invocation of this function */
0227 
0228     status = osl_table_initialize();
0229     if (ACPI_FAILURE(status)) {
0230         return (status);
0231     }
0232 
0233     /* Not a main ACPI table, attempt to extract it from the RSDT/XSDT */
0234 
0235     if (!gbl_dump_customized_tables) {
0236 
0237         /* Attempt to get the table from the memory */
0238 
0239         status =
0240             osl_get_bios_table(signature, instance, table, address);
0241     } else {
0242         /* Attempt to get the table from the static directory */
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             /* Attempt to get a dynamic table */
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  * FUNCTION:    osl_add_table_to_list
0266  *
0267  * PARAMETERS:  signature       - Table signature
0268  *              instance        - Table instance
0269  *
0270  * RETURN:      Status; Successfully added if AE_OK.
0271  *              AE_NO_MEMORY: Memory allocation error
0272  *
0273  * DESCRIPTION: Insert a table structure into OSL table list.
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  * FUNCTION:    acpi_os_get_table_by_index
0331  *
0332  * PARAMETERS:  index           - Which table to get
0333  *              table           - Where a pointer to the table is returned
0334  *              instance        - Where a pointer to the table instance no. is
0335  *                                returned
0336  *              address         - Where the table physical address is returned
0337  *
0338  * RETURN:      Status; Table buffer and physical address returned if AE_OK.
0339  *              AE_LIMIT: Index is beyond valid limit
0340  *
0341  * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns
0342  *              AE_LIMIT when an invalid index is reached. Index is not
0343  *              necessarily an index into the RSDT/XSDT.
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     /* Get main ACPI tables from memory on first invocation of this function */
0357 
0358     status = osl_table_initialize();
0359     if (ACPI_FAILURE(status)) {
0360         return (status);
0361     }
0362 
0363     /* Validate Index */
0364 
0365     if (index >= gbl_table_count) {
0366         return (AE_LIMIT);
0367     }
0368 
0369     /* Point to the table list entry specified by the Index argument */
0370 
0371     info = gbl_table_list_head;
0372     for (i = 0; i < index; i++) {
0373         info = info->next;
0374     }
0375 
0376     /* Now we can just get the table via the signature */
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  * FUNCTION:    osl_find_rsdp_via_efi_by_keyword
0390  *
0391  * PARAMETERS:  keyword         - Character string indicating ACPI GUID version
0392  *                                in the EFI table
0393  *
0394  * RETURN:      RSDP address if found
0395  *
0396  * DESCRIPTION: Find RSDP address via EFI using keyword indicating the ACPI
0397  *              GUID version.
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  * FUNCTION:    osl_find_rsdp_via_efi
0422  *
0423  * PARAMETERS:  None
0424  *
0425  * RETURN:      RSDP address if found
0426  *
0427  * DESCRIPTION: Find RSDP address via EFI.
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  * FUNCTION:    osl_load_rsdp
0452  *
0453  * PARAMETERS:  None
0454  *
0455  * RETURN:      Status
0456  *
0457  * DESCRIPTION: Scan and load RSDP.
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     /* Get RSDP from memory */
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     /* Search low memory for the RSDP */
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  * FUNCTION:    osl_can_use_xsdt
0509  *
0510  * PARAMETERS:  None
0511  *
0512  * RETURN:      TRUE if XSDT is allowed to be used.
0513  *
0514  * DESCRIPTION: This function collects logic that can be used to determine if
0515  *              XSDT should be used instead of RSDT.
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  * FUNCTION:    osl_table_initialize
0531  *
0532  * PARAMETERS:  None
0533  *
0534  * RETURN:      Status
0535  *
0536  * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to
0537  *              local variables. Main ACPI tables include RSDT, FADT, RSDT,
0538  *              and/or XSDT.
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         /* Get RSDP from memory */
0554 
0555         status = osl_load_rsdp();
0556         if (ACPI_FAILURE(status)) {
0557             return (status);
0558         }
0559 
0560         /* Get XSDT from memory */
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         /* Get RSDT from memory */
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         /* Get FADT from memory */
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         /* Add mandatory tables to global table list first */
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         /* Add all tables found in the memory */
0643 
0644         status = osl_list_bios_tables();
0645         if (ACPI_FAILURE(status)) {
0646             return (status);
0647         }
0648     } else {
0649         /* Add all tables found in the static directory */
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         /* Add all dynamically loaded tables in the dynamic directory */
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  * FUNCTION:    osl_list_bios_tables
0674  *
0675  * PARAMETERS:  None
0676  *
0677  * RETURN:      Status; Table list is initialized if AE_OK.
0678  *
0679  * DESCRIPTION: Add ACPI tables to the table list from memory.
0680  *
0681  * NOTE:        This works on Linux as table customization does not modify the
0682  *              addresses stored in RSDP/RSDT/XSDT/FADT.
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 {        /* Use RSDT if XSDT is not available */
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     /* Search RSDT/XSDT for the requested table */
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         /* Skip NULL entries in RSDT/XSDT */
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  * FUNCTION:    osl_get_bios_table
0747  *
0748  * PARAMETERS:  signature       - ACPI Signature for common table. Must be
0749  *                                a null terminated 4-character string.
0750  *              instance        - Multiple table support for SSDT/UEFI (0...n)
0751  *                                Must be 0 for other tables.
0752  *              table           - Where a pointer to the table is returned
0753  *              address         - Where the table physical address is returned
0754  *
0755  * RETURN:      Status; Table buffer and physical address returned if AE_OK.
0756  *              AE_LIMIT: Instance is beyond valid limit
0757  *              AE_NOT_FOUND: A table with the signature was not found
0758  *
0759  * DESCRIPTION: Get a BIOS provided ACPI table
0760  *
0761  * NOTE:        Assumes the input signature is uppercase.
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     /* Handle special tables whose addresses are not in RSDT/XSDT */
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          * Get the appropriate address, either 32-bit or 64-bit. Be very
0797          * careful about the FADT length and validate table addresses.
0798          * Note: The 64-bit addresses have priority.
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         /* Now we can get the requested special table */
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         /* Match table instance */
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 {        /* Case for a normal ACPI table */
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 {    /* Use RSDT if XSDT is not available */
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         /* Search RSDT/XSDT for the requested table */
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             /* Skip NULL entries in RSDT/XSDT */
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             /* Does this table match the requested signature? */
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             /* Match table instance (for SSDT/UEFI tables) */
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     /* Copy table to local buffer and return it */
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  * FUNCTION:    osl_list_customized_tables
0985  *
0986  * PARAMETERS:  directory           - Directory that contains the tables
0987  *
0988  * RETURN:      Status; Table list is initialized if AE_OK.
0989  *
0990  * DESCRIPTION: Add ACPI tables to the table list from a directory.
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     /* 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 }