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