280 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/******************************************************************************3 *4 * Module Name: tbxfroot - Find the root ACPI table (RSDT)5 *6 * Copyright (C) 2000 - 2023, Intel Corp.7 *8 *****************************************************************************/9 10#include <acpi/acpi.h>11#include "accommon.h"12#include "actables.h"13 14#define _COMPONENT ACPI_TABLES15ACPI_MODULE_NAME("tbxfroot")16 17/*******************************************************************************18 *19 * FUNCTION: acpi_tb_get_rsdp_length20 *21 * PARAMETERS: rsdp - Pointer to RSDP22 *23 * RETURN: Table length24 *25 * DESCRIPTION: Get the length of the RSDP26 *27 ******************************************************************************/28u32 acpi_tb_get_rsdp_length(struct acpi_table_rsdp *rsdp)29{30 31 if (!ACPI_VALIDATE_RSDP_SIG(rsdp->signature)) {32 33 /* BAD Signature */34 35 return (0);36 }37 38 /* "Length" field is available if table version >= 2 */39 40 if (rsdp->revision >= 2) {41 return (rsdp->length);42 } else {43 return (ACPI_RSDP_CHECKSUM_LENGTH);44 }45}46 47/*******************************************************************************48 *49 * FUNCTION: acpi_tb_validate_rsdp50 *51 * PARAMETERS: rsdp - Pointer to unvalidated RSDP52 *53 * RETURN: Status54 *55 * DESCRIPTION: Validate the RSDP (ptr)56 *57 ******************************************************************************/58 59acpi_status acpi_tb_validate_rsdp(struct acpi_table_rsdp *rsdp)60{61 62 /*63 * The signature and checksum must both be correct64 *65 * Note: Sometimes there exists more than one RSDP in memory; the valid66 * RSDP has a valid checksum, all others have an invalid checksum.67 */68 if (!ACPI_VALIDATE_RSDP_SIG(rsdp->signature)) {69 70 /* Nope, BAD Signature */71 72 return (AE_BAD_SIGNATURE);73 }74 75 /* Check the standard checksum */76 77 if (acpi_ut_checksum((u8 *)rsdp, ACPI_RSDP_CHECKSUM_LENGTH) != 0) {78 return (AE_BAD_CHECKSUM);79 }80 81 /* Check extended checksum if table version >= 2 */82 83 if ((rsdp->revision >= 2) &&84 (acpi_ut_checksum((u8 *)rsdp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)) {85 return (AE_BAD_CHECKSUM);86 }87 88 return (AE_OK);89}90 91/*******************************************************************************92 *93 * FUNCTION: acpi_find_root_pointer94 *95 * PARAMETERS: table_address - Where the table pointer is returned96 *97 * RETURN: Status, RSDP physical address98 *99 * DESCRIPTION: Search lower 1Mbyte of memory for the root system descriptor100 * pointer structure. If it is found, set *RSDP to point to it.101 *102 * NOTE1: The RSDP must be either in the first 1K of the Extended103 * BIOS Data Area or between E0000 and FFFFF (From ACPI Spec.)104 * Only a 32-bit physical address is necessary.105 *106 * NOTE2: This function is always available, regardless of the107 * initialization state of the rest of ACPI.108 *109 ******************************************************************************/110 111acpi_status ACPI_INIT_FUNCTION112acpi_find_root_pointer(acpi_physical_address *table_address)113{114 u8 *table_ptr;115 u8 *mem_rover;116 u32 physical_address;117 u32 ebda_window_size;118 119 ACPI_FUNCTION_TRACE(acpi_find_root_pointer);120 121 /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */122 123 table_ptr = acpi_os_map_memory((acpi_physical_address)124 ACPI_EBDA_PTR_LOCATION,125 ACPI_EBDA_PTR_LENGTH);126 if (!table_ptr) {127 ACPI_ERROR((AE_INFO,128 "Could not map memory at 0x%8.8X for length %u",129 ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH));130 131 return_ACPI_STATUS(AE_NO_MEMORY);132 }133 134 ACPI_MOVE_16_TO_32(&physical_address, table_ptr);135 136 /* Convert segment part to physical address */137 138 physical_address <<= 4;139 acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);140 141 /* EBDA present? */142 143 /*144 * Check that the EBDA pointer from memory is sane and does not point145 * above valid low memory146 */147 if (physical_address > 0x400 && physical_address < 0xA0000) {148 /*149 * Calculate the scan window size150 * The EBDA is not guaranteed to be larger than a ki_b and in case151 * that it is smaller, the scanning function would leave the low152 * memory and continue to the VGA range.153 */154 ebda_window_size = ACPI_MIN(ACPI_EBDA_WINDOW_SIZE,155 0xA0000 - physical_address);156 157 /*158 * 1b) Search EBDA paragraphs159 */160 table_ptr = acpi_os_map_memory((acpi_physical_address)161 physical_address,162 ebda_window_size);163 if (!table_ptr) {164 ACPI_ERROR((AE_INFO,165 "Could not map memory at 0x%8.8X for length %u",166 physical_address, ebda_window_size));167 168 return_ACPI_STATUS(AE_NO_MEMORY);169 }170 171 mem_rover =172 acpi_tb_scan_memory_for_rsdp(table_ptr, ebda_window_size);173 acpi_os_unmap_memory(table_ptr, ebda_window_size);174 175 if (mem_rover) {176 177 /* Return the physical address */178 179 physical_address +=180 (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);181 182 *table_address =183 (acpi_physical_address)physical_address;184 return_ACPI_STATUS(AE_OK);185 }186 }187 188 /*189 * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh190 */191 table_ptr = acpi_os_map_memory((acpi_physical_address)192 ACPI_HI_RSDP_WINDOW_BASE,193 ACPI_HI_RSDP_WINDOW_SIZE);194 195 if (!table_ptr) {196 ACPI_ERROR((AE_INFO,197 "Could not map memory at 0x%8.8X for length %u",198 ACPI_HI_RSDP_WINDOW_BASE,199 ACPI_HI_RSDP_WINDOW_SIZE));200 201 return_ACPI_STATUS(AE_NO_MEMORY);202 }203 204 mem_rover =205 acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);206 acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);207 208 if (mem_rover) {209 210 /* Return the physical address */211 212 physical_address = (u32)213 (ACPI_HI_RSDP_WINDOW_BASE +214 ACPI_PTR_DIFF(mem_rover, table_ptr));215 216 *table_address = (acpi_physical_address)physical_address;217 return_ACPI_STATUS(AE_OK);218 }219 220 /* A valid RSDP was not found */221 222 ACPI_BIOS_ERROR((AE_INFO, "A valid RSDP was not found"));223 return_ACPI_STATUS(AE_NOT_FOUND);224}225 226ACPI_EXPORT_SYMBOL_INIT(acpi_find_root_pointer)227 228/*******************************************************************************229 *230 * FUNCTION: acpi_tb_scan_memory_for_rsdp231 *232 * PARAMETERS: start_address - Starting pointer for search233 * length - Maximum length to search234 *235 * RETURN: Pointer to the RSDP if found, otherwise NULL.236 *237 * DESCRIPTION: Search a block of memory for the RSDP signature238 *239 ******************************************************************************/240u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length)241{242 acpi_status status;243 u8 *mem_rover;244 u8 *end_address;245 246 ACPI_FUNCTION_TRACE(tb_scan_memory_for_rsdp);247 248 end_address = start_address + length;249 250 /* Search from given start address for the requested length */251 252 for (mem_rover = start_address; mem_rover < end_address;253 mem_rover += ACPI_RSDP_SCAN_STEP) {254 255 /* The RSDP signature and checksum must both be correct */256 257 status =258 acpi_tb_validate_rsdp(ACPI_CAST_PTR259 (struct acpi_table_rsdp, mem_rover));260 if (ACPI_SUCCESS(status)) {261 262 /* Sig and checksum valid, we have found a real RSDP */263 264 ACPI_DEBUG_PRINT((ACPI_DB_INFO,265 "RSDP located at physical address %p\n",266 mem_rover));267 return_PTR(mem_rover);268 }269 270 /* No sig match or bad checksum, keep searching */271 }272 273 /* Searched entire block, no RSDP was found */274 275 ACPI_DEBUG_PRINT((ACPI_DB_INFO,276 "Searched entire block from %p, valid RSDP was not found\n",277 start_address));278 return_PTR(NULL);279}280