1/****************************************************************************** 2 * 3 * Module Name: tbutils - ACPI Table utilities 4 * 5 *****************************************************************************/ 6 7/* 8 * Copyright (C) 2000 - 2023, Intel Corp. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions, and the following disclaimer, 16 * without modification. 17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 18 * substantially similar to the "NO WARRANTY" disclaimer below 19 * ("Disclaimer") and any redistribution must be conditioned upon 20 * including a substantially similar Disclaimer requirement for further 21 * binary redistribution. 22 * 3. Neither the names of the above-listed copyright holders nor the names 23 * of any contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * Alternatively, this software may be distributed under the terms of the 27 * GNU General Public License ("GPL") version 2 as published by the Free 28 * Software Foundation. 29 * 30 * NO WARRANTY 31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 41 * POSSIBILITY OF SUCH DAMAGES. 42 */ 43 44#include "acpi.h" 45#include "accommon.h" 46#include "actables.h" 47 48#define _COMPONENT ACPI_TABLES 49 ACPI_MODULE_NAME ("tbutils") 50 51 52/* Local prototypes */ 53 54static ACPI_PHYSICAL_ADDRESS 55AcpiTbGetRootTableEntry ( 56 UINT8 *TableEntry, 57 UINT32 TableEntrySize); 58 59 60#if (!ACPI_REDUCED_HARDWARE) 61/******************************************************************************* 62 * 63 * FUNCTION: AcpiTbInitializeFacs 64 * 65 * PARAMETERS: None 66 * 67 * RETURN: Status 68 * 69 * DESCRIPTION: Create a permanent mapping for the FADT and save it in a global 70 * for accessing the Global Lock and Firmware Waking Vector 71 * 72 ******************************************************************************/ 73 74ACPI_STATUS 75AcpiTbInitializeFacs ( 76 void) 77{ 78 ACPI_TABLE_FACS *Facs; 79 80 81 /* If Hardware Reduced flag is set, there is no FACS */ 82 83 if (AcpiGbl_ReducedHardware) 84 { 85 AcpiGbl_FACS = NULL; 86 return (AE_OK); 87 } 88 else if (AcpiGbl_FADT.XFacs && 89 (!AcpiGbl_FADT.Facs || !AcpiGbl_Use32BitFacsAddresses)) 90 { 91 (void) AcpiGetTableByIndex (AcpiGbl_XFacsIndex, 92 ACPI_CAST_INDIRECT_PTR (ACPI_TABLE_HEADER, &Facs)); 93 AcpiGbl_FACS = Facs; 94 } 95 else if (AcpiGbl_FADT.Facs) 96 { 97 (void) AcpiGetTableByIndex (AcpiGbl_FacsIndex, 98 ACPI_CAST_INDIRECT_PTR (ACPI_TABLE_HEADER, &Facs)); 99 AcpiGbl_FACS = Facs; 100 } 101 102 /* If there is no FACS, just continue. There was already an error msg */ 103 104 return (AE_OK); 105} 106#endif /* !ACPI_REDUCED_HARDWARE */ 107 108 109/******************************************************************************* 110 * 111 * FUNCTION: AcpiTbCheckDsdtHeader 112 * 113 * PARAMETERS: None 114 * 115 * RETURN: None 116 * 117 * DESCRIPTION: Quick compare to check validity of the DSDT. This will detect 118 * if the DSDT has been replaced from outside the OS and/or if 119 * the DSDT header has been corrupted. 120 * 121 ******************************************************************************/ 122 123void 124AcpiTbCheckDsdtHeader ( 125 void) 126{ 127 128 /* Compare original length and checksum to current values */ 129 130 if (AcpiGbl_OriginalDsdtHeader.Length != AcpiGbl_DSDT->Length || 131 AcpiGbl_OriginalDsdtHeader.Checksum != AcpiGbl_DSDT->Checksum) 132 { 133 ACPI_BIOS_ERROR ((AE_INFO, 134 "The DSDT has been corrupted or replaced - " 135 "old, new headers below")); 136 137 AcpiTbPrintTableHeader (0, &AcpiGbl_OriginalDsdtHeader); 138 AcpiTbPrintTableHeader (0, AcpiGbl_DSDT); 139 140 /* Disable further error messages */ 141 142 AcpiGbl_OriginalDsdtHeader.Length = AcpiGbl_DSDT->Length; 143 AcpiGbl_OriginalDsdtHeader.Checksum = AcpiGbl_DSDT->Checksum; 144 } 145} 146 147 148/******************************************************************************* 149 * 150 * FUNCTION: AcpiTbCopyDsdt 151 * 152 * PARAMETERS: TableIndex - Index of installed table to copy 153 * 154 * RETURN: The copied DSDT 155 * 156 * DESCRIPTION: Implements a subsystem option to copy the DSDT to local memory. 157 * Some very bad BIOSs are known to either corrupt the DSDT or 158 * install a new, bad DSDT. This copy works around the problem. 159 * 160 ******************************************************************************/ 161 162ACPI_TABLE_HEADER * 163AcpiTbCopyDsdt ( 164 UINT32 TableIndex) 165{ 166 ACPI_TABLE_HEADER *NewTable; 167 ACPI_TABLE_DESC *TableDesc; 168 169 170 TableDesc = &AcpiGbl_RootTableList.Tables[TableIndex]; 171 172 NewTable = ACPI_ALLOCATE (TableDesc->Length); 173 if (!NewTable) 174 { 175 ACPI_ERROR ((AE_INFO, "Could not copy DSDT of length 0x%X", 176 TableDesc->Length)); 177 return (NULL); 178 } 179 180 memcpy (NewTable, TableDesc->Pointer, TableDesc->Length); 181 AcpiTbUninstallTable (TableDesc); 182 183 AcpiTbInitTableDescriptor ( 184 &AcpiGbl_RootTableList.Tables[AcpiGbl_DsdtIndex], 185 ACPI_PTR_TO_PHYSADDR (NewTable), 186 ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, NewTable); 187 188 ACPI_INFO (( 189 "Forced DSDT copy: length 0x%05X copied locally, original unmapped", 190 NewTable->Length)); 191 192 return (NewTable); 193} 194 195 196/******************************************************************************* 197 * 198 * FUNCTION: AcpiTbGetRootTableEntry 199 * 200 * PARAMETERS: TableEntry - Pointer to the RSDT/XSDT table entry 201 * TableEntrySize - sizeof 32 or 64 (RSDT or XSDT) 202 * 203 * RETURN: Physical address extracted from the root table 204 * 205 * DESCRIPTION: Get one root table entry. Handles 32-bit and 64-bit cases on 206 * both 32-bit and 64-bit platforms 207 * 208 * NOTE: ACPI_PHYSICAL_ADDRESS is 32-bit on 32-bit platforms, 64-bit on 209 * 64-bit platforms. 210 * 211 ******************************************************************************/ 212 213static ACPI_PHYSICAL_ADDRESS 214AcpiTbGetRootTableEntry ( 215 UINT8 *TableEntry, 216 UINT32 TableEntrySize) 217{ 218 UINT32 Address32; 219 UINT64 Address64; 220 221 222 /* 223 * Get the table physical address (32-bit for RSDT, 64-bit for XSDT): 224 * Note: Addresses are 32-bit aligned (not 64) in both RSDT and XSDT 225 */ 226 if (TableEntrySize == ACPI_RSDT_ENTRY_SIZE) 227 { 228 /* 229 * 32-bit platform, RSDT: Return 32-bit table entry 230 * 64-bit platform, RSDT: Expand 32-bit to 64-bit and return 231 */ 232 ACPI_MOVE_32_TO_32(&Address32, TableEntry); 233 return Address32; 234 } 235 else 236 { 237 /* 238 * 32-bit platform, XSDT: Truncate 64-bit to 32-bit and return 239 * 64-bit platform, XSDT: Move (unaligned) 64-bit to local, 240 * return 64-bit 241 */ 242 ACPI_MOVE_64_TO_64 (&Address64, TableEntry); 243 244#if ACPI_MACHINE_WIDTH == 32 245 if (Address64 > ACPI_UINT32_MAX) 246 { 247 /* Will truncate 64-bit address to 32 bits, issue warning */ 248 249 ACPI_BIOS_WARNING ((AE_INFO, 250 "64-bit Physical Address in XSDT is too large (0x%8.8X%8.8X)," 251 " truncating", 252 ACPI_FORMAT_UINT64 (Address64))); 253 } 254#endif 255 return ((ACPI_PHYSICAL_ADDRESS) (Address64)); 256 } 257} 258 259 260/******************************************************************************* 261 * 262 * FUNCTION: AcpiTbParseRootTable 263 * 264 * PARAMETERS: RsdpAddress - Pointer to the RSDP 265 * 266 * RETURN: Status 267 * 268 * DESCRIPTION: This function is called to parse the Root System Description 269 * Table (RSDT or XSDT) 270 * 271 * NOTE: Tables are mapped (not copied) for efficiency. The FACS must 272 * be mapped and cannot be copied because it contains the actual 273 * memory location of the ACPI Global Lock. 274 * 275 ******************************************************************************/ 276 277ACPI_STATUS ACPI_INIT_FUNCTION 278AcpiTbParseRootTable ( 279 ACPI_PHYSICAL_ADDRESS RsdpAddress) 280{ 281 ACPI_TABLE_RSDP *Rsdp; 282 UINT32 TableEntrySize; 283 UINT32 i; 284 UINT32 TableCount; 285 ACPI_TABLE_HEADER *Table; 286 ACPI_PHYSICAL_ADDRESS Address; 287 UINT32 Length; 288 UINT8 *TableEntry; 289 ACPI_STATUS Status; 290 UINT32 TableIndex; 291 292 293 ACPI_FUNCTION_TRACE (TbParseRootTable); 294 295 296 /* Map the entire RSDP and extract the address of the RSDT or XSDT */ 297 298 Rsdp = AcpiOsMapMemory (RsdpAddress, sizeof (ACPI_TABLE_RSDP)); 299 if (!Rsdp) 300 { 301 return_ACPI_STATUS (AE_NO_MEMORY); 302 } 303 304 AcpiTbPrintTableHeader (RsdpAddress, 305 ACPI_CAST_PTR (ACPI_TABLE_HEADER, Rsdp)); 306 307 /* Use XSDT if present and not overridden. Otherwise, use RSDT */ 308 309 if ((Rsdp->Revision > 1) && 310 Rsdp->XsdtPhysicalAddress && 311 !AcpiGbl_DoNotUseXsdt) 312 { 313 /* 314 * RSDP contains an XSDT (64-bit physical addresses). We must use 315 * the XSDT if the revision is > 1 and the XSDT pointer is present, 316 * as per the ACPI specification. 317 */ 318 Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->XsdtPhysicalAddress; 319 TableEntrySize = ACPI_XSDT_ENTRY_SIZE; 320 } 321 else 322 { 323 /* Root table is an RSDT (32-bit physical addresses) */ 324 325 Address = (ACPI_PHYSICAL_ADDRESS) Rsdp->RsdtPhysicalAddress; 326 TableEntrySize = ACPI_RSDT_ENTRY_SIZE; 327 } 328 329 /* 330 * It is not possible to map more than one entry in some environments, 331 * so unmap the RSDP here before mapping other tables 332 */ 333 AcpiOsUnmapMemory (Rsdp, sizeof (ACPI_TABLE_RSDP)); 334 335 /* Map the RSDT/XSDT table header to get the full table length */ 336 337 Table = AcpiOsMapMemory (Address, sizeof (ACPI_TABLE_HEADER)); 338 if (!Table) 339 { 340 return_ACPI_STATUS (AE_NO_MEMORY); 341 } 342 343 AcpiTbPrintTableHeader (Address, Table); 344 345 /* 346 * Validate length of the table, and map entire table. 347 * Minimum length table must contain at least one entry. 348 */ 349 Length = Table->Length; 350 AcpiOsUnmapMemory (Table, sizeof (ACPI_TABLE_HEADER)); 351 352 if (Length < (sizeof (ACPI_TABLE_HEADER) + TableEntrySize)) 353 { 354 ACPI_BIOS_ERROR ((AE_INFO, 355 "Invalid table length 0x%X in RSDT/XSDT", Length)); 356 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); 357 } 358 359 Table = AcpiOsMapMemory (Address, Length); 360 if (!Table) 361 { 362 return_ACPI_STATUS (AE_NO_MEMORY); 363 } 364 365 /* Validate the root table checksum */ 366 367 Status = AcpiUtVerifyChecksum (Table, Length); 368 if (ACPI_FAILURE (Status)) 369 { 370 AcpiOsUnmapMemory (Table, Length); 371 return_ACPI_STATUS (Status); 372 } 373 374 /* Get the number of entries and pointer to first entry */ 375 376 TableCount = (UINT32) ((Table->Length - sizeof (ACPI_TABLE_HEADER)) / 377 TableEntrySize); 378 TableEntry = ACPI_ADD_PTR (UINT8, Table, sizeof (ACPI_TABLE_HEADER)); 379 380 /* Initialize the root table array from the RSDT/XSDT */ 381 382 for (i = 0; i < TableCount; i++) 383 { 384 /* Get the table physical address (32-bit for RSDT, 64-bit for XSDT) */ 385 386 Address = AcpiTbGetRootTableEntry (TableEntry, TableEntrySize); 387 388 /* Skip NULL entries in RSDT/XSDT */ 389 390 if (!Address) 391 { 392 goto NextTable; 393 } 394 395 Status = AcpiTbInstallStandardTable (Address, 396 ACPI_TABLE_ORIGIN_INTERNAL_PHYSICAL, NULL, FALSE, TRUE, 397 &TableIndex); 398 399 if (ACPI_SUCCESS (Status) && 400 ACPI_COMPARE_NAMESEG ( 401 &AcpiGbl_RootTableList.Tables[TableIndex].Signature, 402 ACPI_SIG_FADT)) 403 { 404 AcpiGbl_FadtIndex = TableIndex; 405 AcpiTbParseFadt (); 406 } 407 408NextTable: 409 410 TableEntry += TableEntrySize; 411 } 412 413 AcpiOsUnmapMemory (Table, Length); 414 return_ACPI_STATUS (AE_OK); 415} 416 417 418/******************************************************************************* 419 * 420 * FUNCTION: AcpiTbGetTable 421 * 422 * PARAMETERS: TableDesc - Table descriptor 423 * OutTable - Where the pointer to the table is returned 424 * 425 * RETURN: Status and pointer to the requested table 426 * 427 * DESCRIPTION: Increase a reference to a table descriptor and return the 428 * validated table pointer. 429 * If the table descriptor is an entry of the root table list, 430 * this API must be invoked with ACPI_MTX_TABLES acquired. 431 * 432 ******************************************************************************/ 433 434ACPI_STATUS 435AcpiTbGetTable ( 436 ACPI_TABLE_DESC *TableDesc, 437 ACPI_TABLE_HEADER **OutTable) 438{ 439 ACPI_STATUS Status; 440 441 442 ACPI_FUNCTION_TRACE (AcpiTbGetTable); 443 444 445 if (TableDesc->ValidationCount == 0) 446 { 447 /* Table need to be "VALIDATED" */ 448 449 Status = AcpiTbValidateTable (TableDesc); 450 if (ACPI_FAILURE (Status)) 451 { 452 return_ACPI_STATUS (Status); 453 } 454 } 455 456 if (TableDesc->ValidationCount < ACPI_MAX_TABLE_VALIDATIONS) 457 { 458 TableDesc->ValidationCount++; 459 460 /* 461 * Detect ValidationCount overflows to ensure that the warning 462 * message will only be printed once. 463 */ 464 if (TableDesc->ValidationCount >= ACPI_MAX_TABLE_VALIDATIONS) 465 { 466 ACPI_WARNING((AE_INFO, 467 "Table %p, Validation count overflows\n", TableDesc)); 468 } 469 } 470 471 *OutTable = TableDesc->Pointer; 472 return_ACPI_STATUS (AE_OK); 473} 474 475 476/******************************************************************************* 477 * 478 * FUNCTION: AcpiTbPutTable 479 * 480 * PARAMETERS: TableDesc - Table descriptor 481 * 482 * RETURN: None 483 * 484 * DESCRIPTION: Decrease a reference to a table descriptor and release the 485 * validated table pointer if no references. 486 * If the table descriptor is an entry of the root table list, 487 * this API must be invoked with ACPI_MTX_TABLES acquired. 488 * 489 ******************************************************************************/ 490 491void 492AcpiTbPutTable ( 493 ACPI_TABLE_DESC *TableDesc) 494{ 495 496 ACPI_FUNCTION_TRACE (AcpiTbPutTable); 497 498 499 if (TableDesc->ValidationCount < ACPI_MAX_TABLE_VALIDATIONS) 500 { 501 TableDesc->ValidationCount--; 502 503 /* 504 * Detect ValidationCount underflows to ensure that the warning 505 * message will only be printed once. 506 */ 507 if (TableDesc->ValidationCount >= ACPI_MAX_TABLE_VALIDATIONS) 508 { 509 ACPI_WARNING ((AE_INFO, 510 "Table %p, Validation count underflows\n", TableDesc)); 511 return_VOID; 512 } 513 } 514 515 if (TableDesc->ValidationCount == 0) 516 { 517 /* Table need to be "INVALIDATED" */ 518 519 AcpiTbInvalidateTable (TableDesc); 520 } 521 522 return_VOID; 523} 524