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