cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

oslinuxtbl.c (35374B)


      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 - 2022, Intel Corp.
      7 *
      8 *****************************************************************************/
      9
     10#include "acpidump.h"
     11
     12#define _COMPONENT          ACPI_OS_SERVICES
     13ACPI_MODULE_NAME("oslinuxtbl")
     14
     15#ifndef PATH_MAX
     16#define PATH_MAX 256
     17#endif
     18/* List of information about obtained ACPI tables */
     19typedef struct osl_table_info {
     20	struct osl_table_info *next;
     21	u32 instance;
     22	char signature[ACPI_NAMESEG_SIZE];
     23
     24} osl_table_info;
     25
     26/* Local prototypes */
     27
     28static acpi_status osl_table_initialize(void);
     29
     30static acpi_status
     31osl_table_name_from_file(char *filename, char *signature, u32 *instance);
     32
     33static acpi_status osl_add_table_to_list(char *signature, u32 instance);
     34
     35static acpi_status
     36osl_read_table_from_file(char *filename,
     37			 acpi_size file_offset,
     38			 struct acpi_table_header **table);
     39
     40static acpi_status
     41osl_map_table(acpi_size address,
     42	      char *signature, struct acpi_table_header **table);
     43
     44static void osl_unmap_table(struct acpi_table_header *table);
     45
     46static acpi_physical_address
     47osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword);
     48
     49static acpi_physical_address osl_find_rsdp_via_efi(void);
     50
     51static acpi_status osl_load_rsdp(void);
     52
     53static acpi_status osl_list_customized_tables(char *directory);
     54
     55static acpi_status
     56osl_get_customized_table(char *pathname,
     57			 char *signature,
     58			 u32 instance,
     59			 struct acpi_table_header **table,
     60			 acpi_physical_address *address);
     61
     62static acpi_status osl_list_bios_tables(void);
     63
     64static acpi_status
     65osl_get_bios_table(char *signature,
     66		   u32 instance,
     67		   struct acpi_table_header **table,
     68		   acpi_physical_address *address);
     69
     70static acpi_status osl_get_last_status(acpi_status default_status);
     71
     72/* 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
     80u8 gbl_dump_dynamic_tables = TRUE;
     81
     82/* Initialization flags */
     83
     84u8 gbl_table_list_initialized = FALSE;
     85
     86/* Local copies of main ACPI tables */
     87
     88struct acpi_table_rsdp gbl_rsdp;
     89struct acpi_table_fadt *gbl_fadt = NULL;
     90struct acpi_table_rsdt *gbl_rsdt = NULL;
     91struct acpi_table_xsdt *gbl_xsdt = NULL;
     92
     93/* Table addresses */
     94
     95acpi_physical_address gbl_fadt_address = 0;
     96acpi_physical_address gbl_rsdp_address = 0;
     97
     98/* Revision of RSD PTR */
     99
    100u8 gbl_revision = 0;
    101
    102struct osl_table_info *gbl_table_list_head = NULL;
    103u32 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
    117static acpi_status osl_get_last_status(acpi_status default_status)
    118{
    119
    120	switch (errno) {
    121	case EACCES:
    122	case EPERM:
    123
    124		return (AE_ACCESS);
    125
    126	case ENOENT:
    127
    128		return (AE_NOT_FOUND);
    129
    130	case ENOMEM:
    131
    132		return (AE_NO_MEMORY);
    133
    134	default:
    135
    136		return (default_status);
    137	}
    138}
    139
    140/******************************************************************************
    141 *
    142 * 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
    154acpi_status
    155acpi_os_get_table_by_address(acpi_physical_address address,
    156			     struct acpi_table_header **table)
    157{
    158	u32 table_length;
    159	struct acpi_table_header *mapped_table;
    160	struct acpi_table_header *local_table = NULL;
    161	acpi_status status = AE_OK;
    162
    163	/* 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
    193exit:
    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
    218acpi_status
    219acpi_os_get_table_by_name(char *signature,
    220			  u32 instance,
    221			  struct acpi_table_header **table,
    222			  acpi_physical_address *address)
    223{
    224	acpi_status status;
    225
    226	/* 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
    277static acpi_status osl_add_table_to_list(char *signature, u32 instance)
    278{
    279	struct osl_table_info *new_info;
    280	struct osl_table_info *next;
    281	u32 next_instance = 0;
    282	u8 found = FALSE;
    283
    284	new_info = calloc(1, sizeof(struct osl_table_info));
    285	if (!new_info) {
    286		return (AE_NO_MEMORY);
    287	}
    288
    289	ACPI_COPY_NAMESEG(new_info->signature, signature);
    290
    291	if (!gbl_table_list_head) {
    292		gbl_table_list_head = new_info;
    293	} else {
    294		next = gbl_table_list_head;
    295		while (1) {
    296			if (ACPI_COMPARE_NAMESEG(next->signature, signature)) {
    297				if (next->instance == instance) {
    298					found = TRUE;
    299				}
    300				if (next->instance >= next_instance) {
    301					next_instance = next->instance + 1;
    302				}
    303			}
    304
    305			if (!next->next) {
    306				break;
    307			}
    308			next = next->next;
    309		}
    310		next->next = new_info;
    311	}
    312
    313	if (found) {
    314		if (instance) {
    315			fprintf(stderr,
    316				"%4.4s: Warning unmatched table instance %d, expected %d\n",
    317				signature, instance, next_instance);
    318		}
    319		instance = next_instance;
    320	}
    321
    322	new_info->instance = instance;
    323	gbl_table_count++;
    324
    325	return (AE_OK);
    326}
    327
    328/******************************************************************************
    329 *
    330 * 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
    347acpi_status
    348acpi_os_get_table_by_index(u32 index,
    349			   struct acpi_table_header **table,
    350			   u32 *instance, acpi_physical_address *address)
    351{
    352	struct osl_table_info *info;
    353	acpi_status status;
    354	u32 i;
    355
    356	/* 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
    401static acpi_physical_address
    402osl_find_rsdp_via_efi_by_keyword(FILE * file, const char *keyword)
    403{
    404	char buffer[80];
    405	unsigned long long address = 0;
    406	char format[32];
    407
    408	snprintf(format, 32, "%s=%s", keyword, "%llx");
    409	fseek(file, 0, SEEK_SET);
    410	while (fgets(buffer, 80, file)) {
    411		if (sscanf(buffer, format, &address) == 1) {
    412			break;
    413		}
    414	}
    415
    416	return ((acpi_physical_address)(address));
    417}
    418
    419/******************************************************************************
    420 *
    421 * 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
    431static acpi_physical_address osl_find_rsdp_via_efi(void)
    432{
    433	FILE *file;
    434	acpi_physical_address address = 0;
    435
    436	file = fopen(EFI_SYSTAB, "r");
    437	if (file) {
    438		address = osl_find_rsdp_via_efi_by_keyword(file, "ACPI20");
    439		if (!address) {
    440			address =
    441			    osl_find_rsdp_via_efi_by_keyword(file, "ACPI");
    442		}
    443		fclose(file);
    444	}
    445
    446	return (address);
    447}
    448
    449/******************************************************************************
    450 *
    451 * FUNCTION:    osl_load_rsdp
    452 *
    453 * PARAMETERS:  None
    454 *
    455 * RETURN:      Status
    456 *
    457 * DESCRIPTION: Scan and load RSDP.
    458 *
    459 *****************************************************************************/
    460
    461static acpi_status osl_load_rsdp(void)
    462{
    463	struct acpi_table_header *mapped_table;
    464	u8 *rsdp_address;
    465	acpi_physical_address rsdp_base;
    466	acpi_size rsdp_size;
    467
    468	/* 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
    519static u8 osl_can_use_xsdt(void)
    520{
    521	if (gbl_revision && !acpi_gbl_do_not_use_xsdt) {
    522		return (TRUE);
    523	} else {
    524		return (FALSE);
    525	}
    526}
    527
    528/******************************************************************************
    529 *
    530 * 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
    542static acpi_status osl_table_initialize(void)
    543{
    544	acpi_status status;
    545	acpi_physical_address address;
    546
    547	if (gbl_table_list_initialized) {
    548		return (AE_OK);
    549	}
    550
    551	if (!gbl_dump_customized_tables) {
    552
    553		/* 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
    686static acpi_status osl_list_bios_tables(void)
    687{
    688	struct acpi_table_header *mapped_table = NULL;
    689	u8 *table_data;
    690	u8 number_of_tables;
    691	u8 item_size;
    692	acpi_physical_address table_address = 0;
    693	acpi_status status = AE_OK;
    694	u32 i;
    695
    696	if (osl_can_use_xsdt()) {
    697		item_size = sizeof(u64);
    698		table_data =
    699		    ACPI_CAST8(gbl_xsdt) + sizeof(struct acpi_table_header);
    700		number_of_tables =
    701		    (u8)((gbl_xsdt->header.length -
    702			  sizeof(struct acpi_table_header))
    703			 / item_size);
    704	} else {		/* 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
    765static acpi_status
    766osl_get_bios_table(char *signature,
    767		   u32 instance,
    768		   struct acpi_table_header **table,
    769		   acpi_physical_address *address)
    770{
    771	struct acpi_table_header *local_table = NULL;
    772	struct acpi_table_header *mapped_table = NULL;
    773	u8 *table_data;
    774	u8 number_of_tables;
    775	u8 item_size;
    776	u32 current_instance = 0;
    777	acpi_physical_address table_address;
    778	acpi_physical_address first_table_address = 0;
    779	u32 table_length = 0;
    780	acpi_status status = AE_OK;
    781	u32 i;
    782
    783	/* 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
    791find_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
    954exit_find_table:
    955
    956	if (!mapped_table) {
    957		return (AE_LIMIT);
    958	}
    959
    960	if (table_length == 0) {
    961		status = AE_BAD_HEADER;
    962		goto exit;
    963	}
    964
    965	/* 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
    977exit:
    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
    994static acpi_status osl_list_customized_tables(char *directory)
    995{
    996	void *table_dir;
    997	u32 instance;
    998	char temp_name[ACPI_NAMESEG_SIZE];
    999	char *filename;
   1000	acpi_status status = AE_OK;
   1001
   1002	/* 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
   1053static acpi_status
   1054osl_map_table(acpi_size address,
   1055	      char *signature, struct acpi_table_header **table)
   1056{
   1057	struct acpi_table_header *mapped_table;
   1058	u32 length;
   1059
   1060	if (!address) {
   1061		return (AE_BAD_ADDRESS);
   1062	}
   1063
   1064	/*
   1065	 * 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
   1131static void osl_unmap_table(struct acpi_table_header *table)
   1132{
   1133	if (table) {
   1134		acpi_os_unmap_memory(table, ap_get_table_length(table));
   1135	}
   1136}
   1137
   1138/******************************************************************************
   1139 *
   1140 * 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
   1155static acpi_status
   1156osl_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
   1195static acpi_status
   1196osl_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
   1280exit:
   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
   1306static acpi_status
   1307osl_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}