brintos

brintos / linux-shallow public Read only

0
0
Text · 34.5 KiB · 9d70d8c Raw
1374 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: oslinuxtbl - Linux OSL for obtaining ACPI tables5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include "acpidump.h"11 12#define _COMPONENT          ACPI_OS_SERVICES13ACPI_MODULE_NAME("oslinuxtbl")14 15#ifndef PATH_MAX16#define PATH_MAX 25617#endif18/* 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_status31osl_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_status36osl_read_table_from_file(char *filename,37			 acpi_size file_offset,38			 struct acpi_table_header **table);39 40static acpi_status41osl_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_address47osl_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_status56osl_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_status65osl_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_status108 *109 * PARAMETERS:  default_status  - Default error status to return110 *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_address143 *144 * PARAMETERS:  address         - Physical address of the ACPI table145 *              table           - Where a pointer to the table is returned146 *147 * RETURN:      Status; Table buffer is returned if AE_OK.148 *              AE_NOT_FOUND: A valid table was not found at the address149 *150 * DESCRIPTION: Get an ACPI table via a physical memory address.151 *152 *****************************************************************************/153 154acpi_status155acpi_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_name202 *203 * PARAMETERS:  signature       - ACPI Signature for desired table. Must be204 *                                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 returned208 *              address         - Where the table physical address is returned209 *210 * RETURN:      Status; Table buffer and physical address returned if AE_OK.211 *              AE_LIMIT: Instance is beyond valid limit212 *              AE_NOT_FOUND: A table with the signature was not found213 *214 * NOTE:        Assumes the input signature is uppercase.215 *216 *****************************************************************************/217 218acpi_status219acpi_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_list266 *267 * PARAMETERS:  signature       - Table signature268 *              instance        - Table instance269 *270 * RETURN:      Status; Successfully added if AE_OK.271 *              AE_NO_MEMORY: Memory allocation error272 *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_index331 *332 * PARAMETERS:  index           - Which table to get333 *              table           - Where a pointer to the table is returned334 *              instance        - Where a pointer to the table instance no. is335 *                                returned336 *              address         - Where the table physical address is returned337 *338 * RETURN:      Status; Table buffer and physical address returned if AE_OK.339 *              AE_LIMIT: Index is beyond valid limit340 *341 * DESCRIPTION: Get an ACPI table via an index value (0 through n). Returns342 *              AE_LIMIT when an invalid index is reached. Index is not343 *              necessarily an index into the RSDT/XSDT.344 *345 *****************************************************************************/346 347acpi_status348acpi_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_keyword390 *391 * PARAMETERS:  keyword         - Character string indicating ACPI GUID version392 *                                in the EFI table393 *394 * RETURN:      RSDP address if found395 *396 * DESCRIPTION: Find RSDP address via EFI using keyword indicating the ACPI397 *              GUID version.398 *399 *****************************************************************************/400 401static acpi_physical_address402osl_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_efi422 *423 * PARAMETERS:  None424 *425 * RETURN:      RSDP address if found426 *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_rsdp452 *453 * PARAMETERS:  None454 *455 * RETURN:      Status456 *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_xsdt509 *510 * PARAMETERS:  None511 *512 * RETURN:      TRUE if XSDT is allowed to be used.513 *514 * DESCRIPTION: This function collects logic that can be used to determine if515 *              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_initialize531 *532 * PARAMETERS:  None533 *534 * RETURN:      Status535 *536 * DESCRIPTION: Initialize ACPI table data. Get and store main ACPI tables to537 *              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(struct571								  acpi_table_header572								  *, &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(struct589								  acpi_table_header590								  *, &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(struct606							  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_tables674 *675 * PARAMETERS:  None676 *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 the682 *              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_table747 *748 * PARAMETERS:  signature       - ACPI Signature for common table. Must be749 *                                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 returned753 *              address         - Where the table physical address is returned754 *755 * RETURN:      Status; Table buffer and physical address returned if AE_OK.756 *              AE_LIMIT: Instance is beyond valid limit757 *              AE_NOT_FOUND: A table with the signature was not found758 *759 * DESCRIPTION: Get a BIOS provided ACPI table760 *761 * NOTE:        Assumes the input signature is uppercase.762 *763 *****************************************************************************/764 765static acpi_status766osl_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 very797		 * 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->Xdsdt804				    && current_instance == 0) {805					table_address =806					    (acpi_physical_address)gbl_fadt->807					    Xdsdt;808				} else809				    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->Xfacs822				    && current_instance == 0) {823					table_address =824					    (acpi_physical_address)gbl_fadt->825					    Xfacs;826				} else827				    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_CAST64912							    (table_data));913			} else {914				table_address =915				    (acpi_physical_address)(*ACPI_CAST32916							    (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_NAMESEG935			    (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_tables985 *986 * PARAMETERS:  directory           - Directory that contains the tables987 *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_table1039 *1040 * PARAMETERS:  address             - Address of the table in memory1041 *              signature           - Optional ACPI Signature for desired table.1042 *                                    Null terminated 4-character string.1043 *              table               - Where a pointer to the mapped table is1044 *                                    returned1045 *1046 * RETURN:      Status; Mapped table is returned if AE_OK.1047 *              AE_NOT_FOUND: A valid table was not found at the address1048 *1049 * DESCRIPTION: Map entire ACPI table into caller's address space.1050 *1051 *****************************************************************************/1052 1053static acpi_status1054osl_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->Length1068	 * 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(struct1085							    acpi_table_header));1086				return (AE_BAD_SIGNATURE);1087			}1088		} else1089		    if (!ACPI_COMPARE_NAMESEG1090			(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_table1122 *1123 * PARAMETERS:  table               - A pointer to the mapped table1124 *1125 * RETURN:      None1126 *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_file1141 *1142 * PARAMETERS:  filename            - File that contains the desired table1143 *              signature           - Pointer to 4-character buffer to store1144 *                                    extracted table signature.1145 *              instance            - Pointer to integer to store extracted1146 *                                    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 file1151 *              name.1152 *1153 *****************************************************************************/1154 1155static acpi_status1156osl_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_file1184 *1185 * PARAMETERS:  filename            - File that contains the desired table1186 *              file_offset         - Offset of the table in file1187 *              table               - Where a pointer to the table is returned1188 *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_status1196osl_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_FUNCTIONS1227 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#endif1248 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_table1289 *1290 * PARAMETERS:  pathname        - Directory to find Linux customized table1291 *              signature       - ACPI Signature for desired table. Must be1292 *                                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 returned1296 *              address         - Where the table physical address is returned1297 *1298 * RETURN:      Status; Table buffer is returned if AE_OK.1299 *              AE_LIMIT: Instance is beyond valid limit1300 *              AE_NOT_FOUND: A table with the signature was not found1301 *1302 * DESCRIPTION: Get an OS customized table.1303 *1304 *****************************************************************************/1305 1306static acpi_status1307osl_get_customized_table(char *pathname,1308			 char *signature,1309			 u32 instance,1310			 struct acpi_table_header **table,1311			 acpi_physical_address *address)1312{1313	void *table_dir;1314	u32 current_instance = 0;1315	char temp_name[ACPI_NAMESEG_SIZE];1316	char table_filename[PATH_MAX];1317	char *filename;1318	acpi_status status;1319 1320	/* Open the directory for customized tables */1321 1322	table_dir = acpi_os_open_directory(pathname, "*", REQUEST_FILE_ONLY);1323	if (!table_dir) {1324		return (osl_get_last_status(AE_NOT_FOUND));1325	}1326 1327	/* Attempt to find the table in the directory */1328 1329	while ((filename = acpi_os_get_next_filename(table_dir))) {1330 1331		/* Ignore meaningless files */1332 1333		if (!ACPI_COMPARE_NAMESEG(filename, signature)) {1334			continue;1335		}1336 1337		/* Extract table name and instance number */1338 1339		status =1340		    osl_table_name_from_file(filename, temp_name,1341					     &current_instance);1342 1343		/* Ignore meaningless files */1344 1345		if (ACPI_FAILURE(status) || current_instance != instance) {1346			continue;1347		}1348 1349		/* Create the table pathname */1350 1351		if (instance != 0) {1352			sprintf(table_filename, "%s/%4.4s%d", pathname,1353				temp_name, instance);1354		} else {1355			sprintf(table_filename, "%s/%4.4s", pathname,1356				temp_name);1357		}1358		break;1359	}1360 1361	acpi_os_close_directory(table_dir);1362 1363	if (!filename) {1364		return (AE_LIMIT);1365	}1366 1367	/* There is no physical address saved for customized tables, use zero */1368 1369	*address = 0;1370	status = osl_read_table_from_file(table_filename, 0, table);1371 1372	return (status);1373}1374