File Index
Files and directories
Sign in
FILE

oslinuxtbl.c

File preview with syntax highlighting.

linux-6.19.14/tools/power/acpi/os_specific/service_layers/oslinuxtbl.c C
   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 - 2025, 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] ACPI_NONSTRING;
  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] ACPI_NONSTRING;
 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] ACPI_NONSTRING;
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}
~/ Read-only file preview.