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

tbutils.c (13134B)


      1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
      2/******************************************************************************
      3 *
      4 * Module Name: tbutils - ACPI Table utilities
      5 *
      6 * Copyright (C) 2000 - 2022, Intel Corp.
      7 *
      8 *****************************************************************************/
      9
     10#include <acpi/acpi.h>
     11#include "accommon.h"
     12#include "actables.h"
     13
     14#define _COMPONENT          ACPI_TABLES
     15ACPI_MODULE_NAME("tbutils")
     16
     17/* Local prototypes */
     18static acpi_physical_address
     19acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size);
     20
     21#if (!ACPI_REDUCED_HARDWARE)
     22/*******************************************************************************
     23 *
     24 * FUNCTION:    acpi_tb_initialize_facs
     25 *
     26 * PARAMETERS:  None
     27 *
     28 * RETURN:      Status
     29 *
     30 * DESCRIPTION: Create a permanent mapping for the FADT and save it in a global
     31 *              for accessing the Global Lock and Firmware Waking Vector
     32 *
     33 ******************************************************************************/
     34
     35acpi_status acpi_tb_initialize_facs(void)
     36{
     37	struct acpi_table_facs *facs;
     38
     39	/* If Hardware Reduced flag is set, there is no FACS */
     40
     41	if (acpi_gbl_reduced_hardware) {
     42		acpi_gbl_FACS = NULL;
     43		return (AE_OK);
     44	} else if (acpi_gbl_FADT.Xfacs &&
     45		   (!acpi_gbl_FADT.facs
     46		    || !acpi_gbl_use32_bit_facs_addresses)) {
     47		(void)acpi_get_table_by_index(acpi_gbl_xfacs_index,
     48					      ACPI_CAST_INDIRECT_PTR(struct
     49								     acpi_table_header,
     50								     &facs));
     51		acpi_gbl_FACS = facs;
     52	} else if (acpi_gbl_FADT.facs) {
     53		(void)acpi_get_table_by_index(acpi_gbl_facs_index,
     54					      ACPI_CAST_INDIRECT_PTR(struct
     55								     acpi_table_header,
     56								     &facs));
     57		acpi_gbl_FACS = facs;
     58	}
     59
     60	/* If there is no FACS, just continue. There was already an error msg */
     61
     62	return (AE_OK);
     63}
     64#endif				/* !ACPI_REDUCED_HARDWARE */
     65
     66/*******************************************************************************
     67 *
     68 * FUNCTION:    acpi_tb_check_dsdt_header
     69 *
     70 * PARAMETERS:  None
     71 *
     72 * RETURN:      None
     73 *
     74 * DESCRIPTION: Quick compare to check validity of the DSDT. This will detect
     75 *              if the DSDT has been replaced from outside the OS and/or if
     76 *              the DSDT header has been corrupted.
     77 *
     78 ******************************************************************************/
     79
     80void acpi_tb_check_dsdt_header(void)
     81{
     82
     83	/* Compare original length and checksum to current values */
     84
     85	if (acpi_gbl_original_dsdt_header.length != acpi_gbl_DSDT->length ||
     86	    acpi_gbl_original_dsdt_header.checksum != acpi_gbl_DSDT->checksum) {
     87		ACPI_BIOS_ERROR((AE_INFO,
     88				 "The DSDT has been corrupted or replaced - "
     89				 "old, new headers below"));
     90
     91		acpi_tb_print_table_header(0, &acpi_gbl_original_dsdt_header);
     92		acpi_tb_print_table_header(0, acpi_gbl_DSDT);
     93
     94		ACPI_ERROR((AE_INFO,
     95			    "Please send DMI info to linux-acpi@vger.kernel.org\n"
     96			    "If system does not work as expected, please boot with acpi=copy_dsdt"));
     97
     98		/* Disable further error messages */
     99
    100		acpi_gbl_original_dsdt_header.length = acpi_gbl_DSDT->length;
    101		acpi_gbl_original_dsdt_header.checksum =
    102		    acpi_gbl_DSDT->checksum;
    103	}
    104}
    105
    106/*******************************************************************************
    107 *
    108 * FUNCTION:    acpi_tb_copy_dsdt
    109 *
    110 * PARAMETERS:  table_index         - Index of installed table to copy
    111 *
    112 * RETURN:      The copied DSDT
    113 *
    114 * DESCRIPTION: Implements a subsystem option to copy the DSDT to local memory.
    115 *              Some very bad BIOSs are known to either corrupt the DSDT or
    116 *              install a new, bad DSDT. This copy works around the problem.
    117 *
    118 ******************************************************************************/
    119
    120struct acpi_table_header *acpi_tb_copy_dsdt(u32 table_index)
    121{
    122	struct acpi_table_header *new_table;
    123	struct acpi_table_desc *table_desc;
    124
    125	table_desc = &acpi_gbl_root_table_list.tables[table_index];
    126
    127	new_table = ACPI_ALLOCATE(table_desc->length);
    128	if (!new_table) {
    129		ACPI_ERROR((AE_INFO, "Could not copy DSDT of length 0x%X",
    130			    table_desc->length));
    131		return (NULL);
    132	}
    133
    134	memcpy(new_table, table_desc->pointer, table_desc->length);
    135	acpi_tb_uninstall_table(table_desc);
    136
    137	acpi_tb_init_table_descriptor(&acpi_gbl_root_table_list.
    138				      tables[acpi_gbl_dsdt_index],
    139				      ACPI_PTR_TO_PHYSADDR(new_table),
    140				      ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL,
    141				      new_table);
    142
    143	ACPI_INFO(("Forced DSDT copy: length 0x%05X copied locally, original unmapped", new_table->length));
    144
    145	return (new_table);
    146}
    147
    148/*******************************************************************************
    149 *
    150 * FUNCTION:    acpi_tb_get_root_table_entry
    151 *
    152 * PARAMETERS:  table_entry         - Pointer to the RSDT/XSDT table entry
    153 *              table_entry_size    - sizeof 32 or 64 (RSDT or XSDT)
    154 *
    155 * RETURN:      Physical address extracted from the root table
    156 *
    157 * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on
    158 *              both 32-bit and 64-bit platforms
    159 *
    160 * NOTE:        acpi_physical_address is 32-bit on 32-bit platforms, 64-bit on
    161 *              64-bit platforms.
    162 *
    163 ******************************************************************************/
    164
    165static acpi_physical_address
    166acpi_tb_get_root_table_entry(u8 *table_entry, u32 table_entry_size)
    167{
    168	u64 address64;
    169
    170	/*
    171	 * Get the table physical address (32-bit for RSDT, 64-bit for XSDT):
    172	 * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT
    173	 */
    174	if (table_entry_size == ACPI_RSDT_ENTRY_SIZE) {
    175		/*
    176		 * 32-bit platform, RSDT: Return 32-bit table entry
    177		 * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return
    178		 */
    179		return ((acpi_physical_address)
    180			(*ACPI_CAST_PTR(u32, table_entry)));
    181	} else {
    182		/*
    183		 * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return
    184		 * 64-bit platform, XSDT: Move (unaligned) 64-bit to local,
    185		 *  return 64-bit
    186		 */
    187		ACPI_MOVE_64_TO_64(&address64, table_entry);
    188
    189#if ACPI_MACHINE_WIDTH == 32
    190		if (address64 > ACPI_UINT32_MAX) {
    191
    192			/* Will truncate 64-bit address to 32 bits, issue warning */
    193
    194			ACPI_BIOS_WARNING((AE_INFO,
    195					   "64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X),"
    196					   " truncating",
    197					   ACPI_FORMAT_UINT64(address64)));
    198		}
    199#endif
    200		return ((acpi_physical_address)(address64));
    201	}
    202}
    203
    204/*******************************************************************************
    205 *
    206 * FUNCTION:    acpi_tb_parse_root_table
    207 *
    208 * PARAMETERS:  rsdp_address        - Pointer to the RSDP
    209 *
    210 * RETURN:      Status
    211 *
    212 * DESCRIPTION: This function is called to parse the Root System Description
    213 *              Table (RSDT or XSDT)
    214 *
    215 * NOTE:        Tables are mapped (not copied) for efficiency. The FACS must
    216 *              be mapped and cannot be copied because it contains the actual
    217 *              memory location of the ACPI Global Lock.
    218 *
    219 ******************************************************************************/
    220
    221acpi_status ACPI_INIT_FUNCTION
    222acpi_tb_parse_root_table(acpi_physical_address rsdp_address)
    223{
    224	struct acpi_table_rsdp *rsdp;
    225	u32 table_entry_size;
    226	u32 i;
    227	u32 table_count;
    228	struct acpi_table_header *table;
    229	acpi_physical_address address;
    230	u32 length;
    231	u8 *table_entry;
    232	acpi_status status;
    233	u32 table_index;
    234
    235	ACPI_FUNCTION_TRACE(tb_parse_root_table);
    236
    237	/* Map the entire RSDP and extract the address of the RSDT or XSDT */
    238
    239	rsdp = acpi_os_map_memory(rsdp_address, sizeof(struct acpi_table_rsdp));
    240	if (!rsdp) {
    241		return_ACPI_STATUS(AE_NO_MEMORY);
    242	}
    243
    244	acpi_tb_print_table_header(rsdp_address,
    245				   ACPI_CAST_PTR(struct acpi_table_header,
    246						 rsdp));
    247
    248	/* Use XSDT if present and not overridden. Otherwise, use RSDT */
    249
    250	if ((rsdp->revision > 1) &&
    251	    rsdp->xsdt_physical_address && !acpi_gbl_do_not_use_xsdt) {
    252		/*
    253		 * RSDP contains an XSDT (64-bit physical addresses). We must use
    254		 * the XSDT if the revision is > 1 and the XSDT pointer is present,
    255		 * as per the ACPI specification.
    256		 */
    257		address = (acpi_physical_address)rsdp->xsdt_physical_address;
    258		table_entry_size = ACPI_XSDT_ENTRY_SIZE;
    259	} else {
    260		/* Root table is an RSDT (32-bit physical addresses) */
    261
    262		address = (acpi_physical_address)rsdp->rsdt_physical_address;
    263		table_entry_size = ACPI_RSDT_ENTRY_SIZE;
    264	}
    265
    266	/*
    267	 * It is not possible to map more than one entry in some environments,
    268	 * so unmap the RSDP here before mapping other tables
    269	 */
    270	acpi_os_unmap_memory(rsdp, sizeof(struct acpi_table_rsdp));
    271
    272	/* Map the RSDT/XSDT table header to get the full table length */
    273
    274	table = acpi_os_map_memory(address, sizeof(struct acpi_table_header));
    275	if (!table) {
    276		return_ACPI_STATUS(AE_NO_MEMORY);
    277	}
    278
    279	acpi_tb_print_table_header(address, table);
    280
    281	/*
    282	 * Validate length of the table, and map entire table.
    283	 * Minimum length table must contain at least one entry.
    284	 */
    285	length = table->length;
    286	acpi_os_unmap_memory(table, sizeof(struct acpi_table_header));
    287
    288	if (length < (sizeof(struct acpi_table_header) + table_entry_size)) {
    289		ACPI_BIOS_ERROR((AE_INFO,
    290				 "Invalid table length 0x%X in RSDT/XSDT",
    291				 length));
    292		return_ACPI_STATUS(AE_INVALID_TABLE_LENGTH);
    293	}
    294
    295	table = acpi_os_map_memory(address, length);
    296	if (!table) {
    297		return_ACPI_STATUS(AE_NO_MEMORY);
    298	}
    299
    300	/* Validate the root table checksum */
    301
    302	status = acpi_tb_verify_checksum(table, length);
    303	if (ACPI_FAILURE(status)) {
    304		acpi_os_unmap_memory(table, length);
    305		return_ACPI_STATUS(status);
    306	}
    307
    308	/* Get the number of entries and pointer to first entry */
    309
    310	table_count = (u32)((table->length - sizeof(struct acpi_table_header)) /
    311			    table_entry_size);
    312	table_entry = ACPI_ADD_PTR(u8, table, sizeof(struct acpi_table_header));
    313
    314	/* Initialize the root table array from the RSDT/XSDT */
    315
    316	for (i = 0; i < table_count; i++) {
    317
    318		/* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */
    319
    320		address =
    321		    acpi_tb_get_root_table_entry(table_entry, table_entry_size);
    322
    323		/* Skip NULL entries in RSDT/XSDT */
    324
    325		if (!address) {
    326			goto next_table;
    327		}
    328
    329		status = acpi_tb_install_standard_table(address,
    330							ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL,
    331							NULL, FALSE, TRUE,
    332							&table_index);
    333
    334		if (ACPI_SUCCESS(status) &&
    335		    ACPI_COMPARE_NAMESEG(&acpi_gbl_root_table_list.
    336					 tables[table_index].signature,
    337					 ACPI_SIG_FADT)) {
    338			acpi_gbl_fadt_index = table_index;
    339			acpi_tb_parse_fadt();
    340		}
    341
    342next_table:
    343
    344		table_entry += table_entry_size;
    345	}
    346
    347	acpi_os_unmap_memory(table, length);
    348	return_ACPI_STATUS(AE_OK);
    349}
    350
    351/*******************************************************************************
    352 *
    353 * FUNCTION:    acpi_tb_get_table
    354 *
    355 * PARAMETERS:  table_desc          - Table descriptor
    356 *              out_table           - Where the pointer to the table is returned
    357 *
    358 * RETURN:      Status and pointer to the requested table
    359 *
    360 * DESCRIPTION: Increase a reference to a table descriptor and return the
    361 *              validated table pointer.
    362 *              If the table descriptor is an entry of the root table list,
    363 *              this API must be invoked with ACPI_MTX_TABLES acquired.
    364 *
    365 ******************************************************************************/
    366
    367acpi_status
    368acpi_tb_get_table(struct acpi_table_desc *table_desc,
    369		  struct acpi_table_header **out_table)
    370{
    371	acpi_status status;
    372
    373	ACPI_FUNCTION_TRACE(acpi_tb_get_table);
    374
    375	if (table_desc->validation_count == 0) {
    376
    377		/* Table need to be "VALIDATED" */
    378
    379		status = acpi_tb_validate_table(table_desc);
    380		if (ACPI_FAILURE(status)) {
    381			return_ACPI_STATUS(status);
    382		}
    383	}
    384
    385	if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
    386		table_desc->validation_count++;
    387
    388		/*
    389		 * Detect validation_count overflows to ensure that the warning
    390		 * message will only be printed once.
    391		 */
    392		if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) {
    393			ACPI_WARNING((AE_INFO,
    394				      "Table %p, Validation count overflows\n",
    395				      table_desc));
    396		}
    397	}
    398
    399	*out_table = table_desc->pointer;
    400	return_ACPI_STATUS(AE_OK);
    401}
    402
    403/*******************************************************************************
    404 *
    405 * FUNCTION:    acpi_tb_put_table
    406 *
    407 * PARAMETERS:  table_desc          - Table descriptor
    408 *
    409 * RETURN:      None
    410 *
    411 * DESCRIPTION: Decrease a reference to a table descriptor and release the
    412 *              validated table pointer if no references.
    413 *              If the table descriptor is an entry of the root table list,
    414 *              this API must be invoked with ACPI_MTX_TABLES acquired.
    415 *
    416 ******************************************************************************/
    417
    418void acpi_tb_put_table(struct acpi_table_desc *table_desc)
    419{
    420
    421	ACPI_FUNCTION_TRACE(acpi_tb_put_table);
    422
    423	if (table_desc->validation_count < ACPI_MAX_TABLE_VALIDATIONS) {
    424		table_desc->validation_count--;
    425
    426		/*
    427		 * Detect validation_count underflows to ensure that the warning
    428		 * message will only be printed once.
    429		 */
    430		if (table_desc->validation_count >= ACPI_MAX_TABLE_VALIDATIONS) {
    431			ACPI_WARNING((AE_INFO,
    432				      "Table %p, Validation count underflows\n",
    433				      table_desc));
    434			return_VOID;
    435		}
    436	}
    437
    438	if (table_desc->validation_count == 0) {
    439
    440		/* Table need to be "INVALIDATED" */
    441
    442		acpi_tb_invalidate_table(table_desc);
    443	}
    444
    445	return_VOID;
    446}