linux/drivers/acpi/acpica/tbxfroot.c
<<
>>
Prefs
   1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
   2/******************************************************************************
   3 *
   4 * Module Name: tbxfroot - Find the root ACPI table (RSDT)
   5 *
   6 * Copyright (C) 2000 - 2019, 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("tbxfroot")
  16
  17/*******************************************************************************
  18 *
  19 * FUNCTION:    acpi_tb_get_rsdp_length
  20 *
  21 * PARAMETERS:  rsdp                - Pointer to RSDP
  22 *
  23 * RETURN:      Table length
  24 *
  25 * DESCRIPTION: Get the length of the RSDP
  26 *
  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_rsdp
  50 *
  51 * PARAMETERS:  rsdp                - Pointer to unvalidated RSDP
  52 *
  53 * RETURN:      Status
  54 *
  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 correct
  64         *
  65         * Note: Sometimes there exists more than one RSDP in memory; the valid
  66         * 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_tb_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_tb_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_pointer
  94 *
  95 * PARAMETERS:  table_address           - Where the table pointer is returned
  96 *
  97 * RETURN:      Status, RSDP physical address
  98 *
  99 * DESCRIPTION: Search lower 1Mbyte of memory for the root system descriptor
 100 *              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 Extended
 103 *              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 the
 107 *              initialization state of the rest of ACPI.
 108 *
 109 ******************************************************************************/
 110
 111acpi_status ACPI_INIT_FUNCTION
 112acpi_find_root_pointer(acpi_physical_address *table_address)
 113{
 114        u8 *table_ptr;
 115        u8 *mem_rover;
 116        u32 physical_address;
 117
 118        ACPI_FUNCTION_TRACE(acpi_find_root_pointer);
 119
 120        /* 1a) Get the location of the Extended BIOS Data Area (EBDA) */
 121
 122        table_ptr = acpi_os_map_memory((acpi_physical_address)
 123                                       ACPI_EBDA_PTR_LOCATION,
 124                                       ACPI_EBDA_PTR_LENGTH);
 125        if (!table_ptr) {
 126                ACPI_ERROR((AE_INFO,
 127                            "Could not map memory at 0x%8.8X for length %u",
 128                            ACPI_EBDA_PTR_LOCATION, ACPI_EBDA_PTR_LENGTH));
 129
 130                return_ACPI_STATUS(AE_NO_MEMORY);
 131        }
 132
 133        ACPI_MOVE_16_TO_32(&physical_address, table_ptr);
 134
 135        /* Convert segment part to physical address */
 136
 137        physical_address <<= 4;
 138        acpi_os_unmap_memory(table_ptr, ACPI_EBDA_PTR_LENGTH);
 139
 140        /* EBDA present? */
 141
 142        if (physical_address > 0x400) {
 143                /*
 144                 * 1b) Search EBDA paragraphs (EBDA is required to be a
 145                 *     minimum of 1K length)
 146                 */
 147                table_ptr = acpi_os_map_memory((acpi_physical_address)
 148                                               physical_address,
 149                                               ACPI_EBDA_WINDOW_SIZE);
 150                if (!table_ptr) {
 151                        ACPI_ERROR((AE_INFO,
 152                                    "Could not map memory at 0x%8.8X for length %u",
 153                                    physical_address, ACPI_EBDA_WINDOW_SIZE));
 154
 155                        return_ACPI_STATUS(AE_NO_MEMORY);
 156                }
 157
 158                mem_rover =
 159                    acpi_tb_scan_memory_for_rsdp(table_ptr,
 160                                                 ACPI_EBDA_WINDOW_SIZE);
 161                acpi_os_unmap_memory(table_ptr, ACPI_EBDA_WINDOW_SIZE);
 162
 163                if (mem_rover) {
 164
 165                        /* Return the physical address */
 166
 167                        physical_address +=
 168                            (u32) ACPI_PTR_DIFF(mem_rover, table_ptr);
 169
 170                        *table_address =
 171                            (acpi_physical_address)physical_address;
 172                        return_ACPI_STATUS(AE_OK);
 173                }
 174        }
 175
 176        /*
 177         * 2) Search upper memory: 16-byte boundaries in E0000h-FFFFFh
 178         */
 179        table_ptr = acpi_os_map_memory((acpi_physical_address)
 180                                       ACPI_HI_RSDP_WINDOW_BASE,
 181                                       ACPI_HI_RSDP_WINDOW_SIZE);
 182
 183        if (!table_ptr) {
 184                ACPI_ERROR((AE_INFO,
 185                            "Could not map memory at 0x%8.8X for length %u",
 186                            ACPI_HI_RSDP_WINDOW_BASE,
 187                            ACPI_HI_RSDP_WINDOW_SIZE));
 188
 189                return_ACPI_STATUS(AE_NO_MEMORY);
 190        }
 191
 192        mem_rover =
 193            acpi_tb_scan_memory_for_rsdp(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
 194        acpi_os_unmap_memory(table_ptr, ACPI_HI_RSDP_WINDOW_SIZE);
 195
 196        if (mem_rover) {
 197
 198                /* Return the physical address */
 199
 200                physical_address = (u32)
 201                    (ACPI_HI_RSDP_WINDOW_BASE +
 202                     ACPI_PTR_DIFF(mem_rover, table_ptr));
 203
 204                *table_address = (acpi_physical_address)physical_address;
 205                return_ACPI_STATUS(AE_OK);
 206        }
 207
 208        /* A valid RSDP was not found */
 209
 210        ACPI_BIOS_ERROR((AE_INFO, "A valid RSDP was not found"));
 211        return_ACPI_STATUS(AE_NOT_FOUND);
 212}
 213
 214ACPI_EXPORT_SYMBOL_INIT(acpi_find_root_pointer)
 215
 216/*******************************************************************************
 217 *
 218 * FUNCTION:    acpi_tb_scan_memory_for_rsdp
 219 *
 220 * PARAMETERS:  start_address       - Starting pointer for search
 221 *              length              - Maximum length to search
 222 *
 223 * RETURN:      Pointer to the RSDP if found, otherwise NULL.
 224 *
 225 * DESCRIPTION: Search a block of memory for the RSDP signature
 226 *
 227 ******************************************************************************/
 228u8 *acpi_tb_scan_memory_for_rsdp(u8 *start_address, u32 length)
 229{
 230        acpi_status status;
 231        u8 *mem_rover;
 232        u8 *end_address;
 233
 234        ACPI_FUNCTION_TRACE(tb_scan_memory_for_rsdp);
 235
 236        end_address = start_address + length;
 237
 238        /* Search from given start address for the requested length */
 239
 240        for (mem_rover = start_address; mem_rover < end_address;
 241             mem_rover += ACPI_RSDP_SCAN_STEP) {
 242
 243                /* The RSDP signature and checksum must both be correct */
 244
 245                status =
 246                    acpi_tb_validate_rsdp(ACPI_CAST_PTR
 247                                          (struct acpi_table_rsdp, mem_rover));
 248                if (ACPI_SUCCESS(status)) {
 249
 250                        /* Sig and checksum valid, we have found a real RSDP */
 251
 252                        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 253                                          "RSDP located at physical address %p\n",
 254                                          mem_rover));
 255                        return_PTR(mem_rover);
 256                }
 257
 258                /* No sig match or bad checksum, keep searching */
 259        }
 260
 261        /* Searched entire block, no RSDP was found */
 262
 263        ACPI_DEBUG_PRINT((ACPI_DB_INFO,
 264                          "Searched entire block from %p, valid RSDP was not found\n",
 265                          start_address));
 266        return_PTR(NULL);
 267}
 268