1 /****************************************************************************** 2 * 3 * Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes) 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2020, 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 MERCHANTIBILITY 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 "acinterp.h" 47 #include "acnamesp.h" 48 #include "actables.h" 49 #include "acdispat.h" 50 #include "acevents.h" 51 #include "amlcode.h" 52 53 54 #define _COMPONENT ACPI_EXECUTER 55 ACPI_MODULE_NAME ("exconfig") 56 57 /* Local prototypes */ 58 59 static ACPI_STATUS 60 AcpiExAddTable ( 61 UINT32 TableIndex, 62 ACPI_OPERAND_OBJECT **DdbHandle); 63 64 static ACPI_STATUS 65 AcpiExRegionRead ( 66 ACPI_OPERAND_OBJECT *ObjDesc, 67 UINT32 Length, 68 UINT8 *Buffer); 69 70 71 /******************************************************************************* 72 * 73 * FUNCTION: AcpiExAddTable 74 * 75 * PARAMETERS: Table - Pointer to raw table 76 * ParentNode - Where to load the table (scope) 77 * DdbHandle - Where to return the table handle. 78 * 79 * RETURN: Status 80 * 81 * DESCRIPTION: Common function to Install and Load an ACPI table with a 82 * returned table handle. 83 * 84 ******************************************************************************/ 85 86 static ACPI_STATUS 87 AcpiExAddTable ( 88 UINT32 TableIndex, 89 ACPI_OPERAND_OBJECT **DdbHandle) 90 { 91 ACPI_OPERAND_OBJECT *ObjDesc; 92 93 94 ACPI_FUNCTION_TRACE (ExAddTable); 95 96 97 /* Create an object to be the table handle */ 98 99 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE); 100 if (!ObjDesc) 101 { 102 return_ACPI_STATUS (AE_NO_MEMORY); 103 } 104 105 /* Init the table handle */ 106 107 ObjDesc->Common.Flags |= AOPOBJ_DATA_VALID; 108 ObjDesc->Reference.Class = ACPI_REFCLASS_TABLE; 109 ObjDesc->Reference.Value = TableIndex; 110 *DdbHandle = ObjDesc; 111 return_ACPI_STATUS (AE_OK); 112 } 113 114 115 /******************************************************************************* 116 * 117 * FUNCTION: AcpiExLoadTableOp 118 * 119 * PARAMETERS: WalkState - Current state with operands 120 * ReturnDesc - Where to store the return object 121 * 122 * RETURN: Status 123 * 124 * DESCRIPTION: Load an ACPI table from the RSDT/XSDT 125 * 126 ******************************************************************************/ 127 128 ACPI_STATUS 129 AcpiExLoadTableOp ( 130 ACPI_WALK_STATE *WalkState, 131 ACPI_OPERAND_OBJECT **ReturnDesc) 132 { 133 ACPI_STATUS Status; 134 ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; 135 ACPI_NAMESPACE_NODE *ParentNode; 136 ACPI_NAMESPACE_NODE *StartNode; 137 ACPI_NAMESPACE_NODE *ParameterNode = NULL; 138 ACPI_OPERAND_OBJECT *DdbHandle; 139 UINT32 TableIndex; 140 141 142 ACPI_FUNCTION_TRACE (ExLoadTableOp); 143 144 145 /* Find the ACPI table in the RSDT/XSDT */ 146 147 AcpiExExitInterpreter (); 148 Status = AcpiTbFindTable ( 149 Operand[0]->String.Pointer, 150 Operand[1]->String.Pointer, 151 Operand[2]->String.Pointer, &TableIndex); 152 AcpiExEnterInterpreter (); 153 if (ACPI_FAILURE (Status)) 154 { 155 if (Status != AE_NOT_FOUND) 156 { 157 return_ACPI_STATUS (Status); 158 } 159 160 /* Table not found, return an Integer=0 and AE_OK */ 161 162 DdbHandle = AcpiUtCreateIntegerObject ((UINT64) 0); 163 if (!DdbHandle) 164 { 165 return_ACPI_STATUS (AE_NO_MEMORY); 166 } 167 168 *ReturnDesc = DdbHandle; 169 return_ACPI_STATUS (AE_OK); 170 } 171 172 /* Default nodes */ 173 174 StartNode = WalkState->ScopeInfo->Scope.Node; 175 ParentNode = AcpiGbl_RootNode; 176 177 /* RootPath (optional parameter) */ 178 179 if (Operand[3]->String.Length > 0) 180 { 181 /* 182 * Find the node referenced by the RootPathString. This is the 183 * location within the namespace where the table will be loaded. 184 */ 185 Status = AcpiNsGetNodeUnlocked (StartNode, 186 Operand[3]->String.Pointer, ACPI_NS_SEARCH_PARENT, 187 &ParentNode); 188 if (ACPI_FAILURE (Status)) 189 { 190 return_ACPI_STATUS (Status); 191 } 192 } 193 194 /* ParameterPath (optional parameter) */ 195 196 if (Operand[4]->String.Length > 0) 197 { 198 if ((Operand[4]->String.Pointer[0] != AML_ROOT_PREFIX) && 199 (Operand[4]->String.Pointer[0] != AML_PARENT_PREFIX)) 200 { 201 /* 202 * Path is not absolute, so it will be relative to the node 203 * referenced by the RootPathString (or the NS root if omitted) 204 */ 205 StartNode = ParentNode; 206 } 207 208 /* Find the node referenced by the ParameterPathString */ 209 210 Status = AcpiNsGetNodeUnlocked (StartNode, 211 Operand[4]->String.Pointer, ACPI_NS_SEARCH_PARENT, 212 &ParameterNode); 213 if (ACPI_FAILURE (Status)) 214 { 215 return_ACPI_STATUS (Status); 216 } 217 } 218 219 /* Load the table into the namespace */ 220 221 ACPI_INFO (("Dynamic OEM Table Load:")); 222 AcpiExExitInterpreter (); 223 Status = AcpiTbLoadTable (TableIndex, ParentNode); 224 AcpiExEnterInterpreter (); 225 if (ACPI_FAILURE (Status)) 226 { 227 return_ACPI_STATUS (Status); 228 } 229 230 Status = AcpiExAddTable (TableIndex, &DdbHandle); 231 if (ACPI_FAILURE (Status)) 232 { 233 return_ACPI_STATUS (Status); 234 } 235 236 /* Complete the initialization/resolution of new objects */ 237 238 AcpiExExitInterpreter(); 239 AcpiNsInitializeObjects(); 240 AcpiExEnterInterpreter(); 241 242 /* Parameter Data (optional) */ 243 244 if (ParameterNode) 245 { 246 /* Store the parameter data into the optional parameter object */ 247 248 Status = AcpiExStore (Operand[5], 249 ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParameterNode), WalkState); 250 if (ACPI_FAILURE (Status)) 251 { 252 (void) AcpiExUnloadTable (DdbHandle); 253 254 AcpiUtRemoveReference (DdbHandle); 255 return_ACPI_STATUS (Status); 256 } 257 } 258 259 *ReturnDesc = DdbHandle; 260 return_ACPI_STATUS (Status); 261 } 262 263 264 /******************************************************************************* 265 * 266 * FUNCTION: AcpiExRegionRead 267 * 268 * PARAMETERS: ObjDesc - Region descriptor 269 * Length - Number of bytes to read 270 * Buffer - Pointer to where to put the data 271 * 272 * RETURN: Status 273 * 274 * DESCRIPTION: Read data from an operation region. The read starts from the 275 * beginning of the region. 276 * 277 ******************************************************************************/ 278 279 static ACPI_STATUS 280 AcpiExRegionRead ( 281 ACPI_OPERAND_OBJECT *ObjDesc, 282 UINT32 Length, 283 UINT8 *Buffer) 284 { 285 ACPI_STATUS Status; 286 UINT64 Value; 287 UINT32 RegionOffset = 0; 288 UINT32 i; 289 290 291 /* Bytewise reads */ 292 293 for (i = 0; i < Length; i++) 294 { 295 Status = AcpiEvAddressSpaceDispatch (ObjDesc, NULL, ACPI_READ, 296 RegionOffset, 8, &Value); 297 if (ACPI_FAILURE (Status)) 298 { 299 return (Status); 300 } 301 302 *Buffer = (UINT8) Value; 303 Buffer++; 304 RegionOffset++; 305 } 306 307 return (AE_OK); 308 } 309 310 311 /******************************************************************************* 312 * 313 * FUNCTION: AcpiExLoadOp 314 * 315 * PARAMETERS: ObjDesc - Region or Buffer/Field where the table will be 316 * obtained 317 * Target - Where a handle to the table will be stored 318 * WalkState - Current state 319 * 320 * RETURN: Status 321 * 322 * DESCRIPTION: Load an ACPI table from a field or operation region 323 * 324 * NOTE: Region Fields (Field, BankField, IndexFields) are resolved to buffer 325 * objects before this code is reached. 326 * 327 * If source is an operation region, it must refer to SystemMemory, as 328 * per the ACPI specification. 329 * 330 ******************************************************************************/ 331 332 ACPI_STATUS 333 AcpiExLoadOp ( 334 ACPI_OPERAND_OBJECT *ObjDesc, 335 ACPI_OPERAND_OBJECT *Target, 336 ACPI_WALK_STATE *WalkState) 337 { 338 ACPI_OPERAND_OBJECT *DdbHandle; 339 ACPI_TABLE_HEADER *TableHeader; 340 ACPI_TABLE_HEADER *Table; 341 UINT32 TableIndex; 342 ACPI_STATUS Status; 343 UINT32 Length; 344 345 346 ACPI_FUNCTION_TRACE (ExLoadOp); 347 348 349 /* Source Object can be either an OpRegion or a Buffer/Field */ 350 351 switch (ObjDesc->Common.Type) 352 { 353 case ACPI_TYPE_REGION: 354 355 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 356 "Load table from Region %p\n", ObjDesc)); 357 358 /* Region must be SystemMemory (from ACPI spec) */ 359 360 if (ObjDesc->Region.SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) 361 { 362 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 363 } 364 365 /* 366 * If the Region Address and Length have not been previously 367 * evaluated, evaluate them now and save the results. 368 */ 369 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 370 { 371 Status = AcpiDsGetRegionArguments (ObjDesc); 372 if (ACPI_FAILURE (Status)) 373 { 374 return_ACPI_STATUS (Status); 375 } 376 } 377 378 /* Get the table header first so we can get the table length */ 379 380 TableHeader = ACPI_ALLOCATE (sizeof (ACPI_TABLE_HEADER)); 381 if (!TableHeader) 382 { 383 return_ACPI_STATUS (AE_NO_MEMORY); 384 } 385 386 Status = AcpiExRegionRead (ObjDesc, sizeof (ACPI_TABLE_HEADER), 387 ACPI_CAST_PTR (UINT8, TableHeader)); 388 Length = TableHeader->Length; 389 ACPI_FREE (TableHeader); 390 391 if (ACPI_FAILURE (Status)) 392 { 393 return_ACPI_STATUS (Status); 394 } 395 396 /* Must have at least an ACPI table header */ 397 398 if (Length < sizeof (ACPI_TABLE_HEADER)) 399 { 400 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); 401 } 402 403 /* 404 * The original implementation simply mapped the table, with no copy. 405 * However, the memory region is not guaranteed to remain stable and 406 * we must copy the table to a local buffer. For example, the memory 407 * region is corrupted after suspend on some machines. Dynamically 408 * loaded tables are usually small, so this overhead is minimal. 409 * 410 * The latest implementation (5/2009) does not use a mapping at all. 411 * We use the low-level operation region interface to read the table 412 * instead of the obvious optimization of using a direct mapping. 413 * This maintains a consistent use of operation regions across the 414 * entire subsystem. This is important if additional processing must 415 * be performed in the (possibly user-installed) operation region 416 * handler. For example, AcpiExec and ASLTS depend on this. 417 */ 418 419 /* Allocate a buffer for the table */ 420 421 Table = ACPI_ALLOCATE (Length); 422 if (!Table) 423 { 424 return_ACPI_STATUS (AE_NO_MEMORY); 425 } 426 427 /* Read the entire table */ 428 429 Status = AcpiExRegionRead (ObjDesc, Length, 430 ACPI_CAST_PTR (UINT8, Table)); 431 if (ACPI_FAILURE (Status)) 432 { 433 ACPI_FREE (Table); 434 return_ACPI_STATUS (Status); 435 } 436 break; 437 438 case ACPI_TYPE_BUFFER: /* Buffer or resolved RegionField */ 439 440 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 441 "Load table from Buffer or Field %p\n", ObjDesc)); 442 443 /* Must have at least an ACPI table header */ 444 445 if (ObjDesc->Buffer.Length < sizeof (ACPI_TABLE_HEADER)) 446 { 447 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); 448 } 449 450 /* Get the actual table length from the table header */ 451 452 TableHeader = ACPI_CAST_PTR ( 453 ACPI_TABLE_HEADER, ObjDesc->Buffer.Pointer); 454 Length = TableHeader->Length; 455 456 /* Table cannot extend beyond the buffer */ 457 458 if (Length > ObjDesc->Buffer.Length) 459 { 460 return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); 461 } 462 if (Length < sizeof (ACPI_TABLE_HEADER)) 463 { 464 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); 465 } 466 467 /* 468 * Copy the table from the buffer because the buffer could be 469 * modified or even deleted in the future 470 */ 471 Table = ACPI_ALLOCATE (Length); 472 if (!Table) 473 { 474 return_ACPI_STATUS (AE_NO_MEMORY); 475 } 476 477 memcpy (Table, TableHeader, Length); 478 break; 479 480 default: 481 482 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 483 } 484 485 /* Install the new table into the local data structures */ 486 487 ACPI_INFO (("Dynamic OEM Table Load:")); 488 AcpiExExitInterpreter (); 489 Status = AcpiTbInstallAndLoadTable (ACPI_PTR_TO_PHYSADDR (Table), 490 ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, TRUE, &TableIndex); 491 AcpiExEnterInterpreter (); 492 if (ACPI_FAILURE (Status)) 493 { 494 /* Delete allocated table buffer */ 495 496 ACPI_FREE (Table); 497 return_ACPI_STATUS (Status); 498 } 499 500 /* 501 * Add the table to the namespace. 502 * 503 * Note: Load the table objects relative to the root of the namespace. 504 * This appears to go against the ACPI specification, but we do it for 505 * compatibility with other ACPI implementations. 506 */ 507 Status = AcpiExAddTable (TableIndex, &DdbHandle); 508 if (ACPI_FAILURE (Status)) 509 { 510 /* On error, TablePtr was deallocated above */ 511 512 return_ACPI_STATUS (Status); 513 } 514 515 /* Complete the initialization/resolution of new objects */ 516 517 AcpiExExitInterpreter (); 518 AcpiNsInitializeObjects (); 519 AcpiExEnterInterpreter (); 520 521 /* Store the DdbHandle into the Target operand */ 522 523 Status = AcpiExStore (DdbHandle, Target, WalkState); 524 if (ACPI_FAILURE (Status)) 525 { 526 (void) AcpiExUnloadTable (DdbHandle); 527 528 /* TablePtr was deallocated above */ 529 530 AcpiUtRemoveReference (DdbHandle); 531 return_ACPI_STATUS (Status); 532 } 533 534 /* Remove the reference by added by AcpiExStore above */ 535 536 AcpiUtRemoveReference (DdbHandle); 537 return_ACPI_STATUS (Status); 538 } 539 540 541 /******************************************************************************* 542 * 543 * FUNCTION: AcpiExUnloadTable 544 * 545 * PARAMETERS: DdbHandle - Handle to a previously loaded table 546 * 547 * RETURN: Status 548 * 549 * DESCRIPTION: Unload an ACPI table 550 * 551 ******************************************************************************/ 552 553 ACPI_STATUS 554 AcpiExUnloadTable ( 555 ACPI_OPERAND_OBJECT *DdbHandle) 556 { 557 ACPI_STATUS Status = AE_OK; 558 ACPI_OPERAND_OBJECT *TableDesc = DdbHandle; 559 UINT32 TableIndex; 560 561 562 ACPI_FUNCTION_TRACE (ExUnloadTable); 563 564 565 /* 566 * Temporarily emit a warning so that the ASL for the machine can be 567 * hopefully obtained. This is to say that the Unload() operator is 568 * extremely rare if not completely unused. 569 */ 570 ACPI_WARNING ((AE_INFO, 571 "Received request to unload an ACPI table")); 572 573 /* 574 * May 2018: Unload is no longer supported for the following reasons: 575 * 1) A correct implementation on some hosts may not be possible. 576 * 2) Other ACPI implementations do not correctly/fully support it. 577 * 3) It requires host device driver support which does not exist. 578 * (To properly support namespace unload out from underneath.) 579 * 4) This AML operator has never been seen in the field. 580 */ 581 ACPI_EXCEPTION ((AE_INFO, AE_NOT_IMPLEMENTED, 582 "AML Unload operator is not supported")); 583 584 /* 585 * Validate the handle 586 * Although the handle is partially validated in AcpiExReconfiguration() 587 * when it calls AcpiExResolveOperands(), the handle is more completely 588 * validated here. 589 * 590 * Handle must be a valid operand object of type reference. Also, the 591 * DdbHandle must still be marked valid (table has not been previously 592 * unloaded) 593 */ 594 if ((!DdbHandle) || 595 (ACPI_GET_DESCRIPTOR_TYPE (DdbHandle) != ACPI_DESC_TYPE_OPERAND) || 596 (DdbHandle->Common.Type != ACPI_TYPE_LOCAL_REFERENCE) || 597 (!(DdbHandle->Common.Flags & AOPOBJ_DATA_VALID))) 598 { 599 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 600 } 601 602 /* Get the table index from the DdbHandle */ 603 604 TableIndex = TableDesc->Reference.Value; 605 606 /* 607 * Release the interpreter lock so that the table lock won't have 608 * strict order requirement against it. 609 */ 610 AcpiExExitInterpreter (); 611 Status = AcpiTbUnloadTable (TableIndex); 612 AcpiExEnterInterpreter (); 613 614 /* 615 * Invalidate the handle. We do this because the handle may be stored 616 * in a named object and may not be actually deleted until much later. 617 */ 618 if (ACPI_SUCCESS (Status)) 619 { 620 DdbHandle->Common.Flags &= ~AOPOBJ_DATA_VALID; 621 } 622 return_ACPI_STATUS (Status); 623 } 624