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 /* 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), 267 WalkState); 268 if (ACPI_FAILURE (Status)) 269 { 270 (void) AcpiExUnloadTable (DdbHandle); 271 272 AcpiUtRemoveReference (DdbHandle); 273 return_ACPI_STATUS (Status); 274 } 275 } 276 277 Status = AcpiGetTableByIndex (TableIndex, &Table); 278 if (ACPI_SUCCESS (Status)) 279 { 280 ACPI_INFO ((AE_INFO, "Dynamic OEM Table Load:")); 281 AcpiTbPrintTableHeader (0, Table); 282 } 283 284 /* Invoke table handler if present */ 285 286 if (AcpiGbl_TableHandler) 287 { 288 (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_LOAD, Table, 289 AcpiGbl_TableHandlerContext); 290 } 291 292 *ReturnDesc = DdbHandle; 293 return_ACPI_STATUS (Status); 294 } 295 296 297 /******************************************************************************* 298 * 299 * FUNCTION: AcpiExRegionRead 300 * 301 * PARAMETERS: ObjDesc - Region descriptor 302 * Length - Number of bytes to read 303 * Buffer - Pointer to where to put the data 304 * 305 * RETURN: Status 306 * 307 * DESCRIPTION: Read data from an operation region. The read starts from the 308 * beginning of the region. 309 * 310 ******************************************************************************/ 311 312 static ACPI_STATUS 313 AcpiExRegionRead ( 314 ACPI_OPERAND_OBJECT *ObjDesc, 315 UINT32 Length, 316 UINT8 *Buffer) 317 { 318 ACPI_STATUS Status; 319 UINT64 Value; 320 UINT32 RegionOffset = 0; 321 UINT32 i; 322 323 324 /* Bytewise reads */ 325 326 for (i = 0; i < Length; i++) 327 { 328 Status = AcpiEvAddressSpaceDispatch (ObjDesc, NULL, ACPI_READ, 329 RegionOffset, 8, &Value); 330 if (ACPI_FAILURE (Status)) 331 { 332 return (Status); 333 } 334 335 *Buffer = (UINT8) Value; 336 Buffer++; 337 RegionOffset++; 338 } 339 340 return (AE_OK); 341 } 342 343 344 /******************************************************************************* 345 * 346 * FUNCTION: AcpiExLoadOp 347 * 348 * PARAMETERS: ObjDesc - Region or Buffer/Field where the table will be 349 * obtained 350 * Target - Where a handle to the table will be stored 351 * WalkState - Current state 352 * 353 * RETURN: Status 354 * 355 * DESCRIPTION: Load an ACPI table from a field or operation region 356 * 357 * NOTE: Region Fields (Field, BankField, IndexFields) are resolved to buffer 358 * objects before this code is reached. 359 * 360 * If source is an operation region, it must refer to SystemMemory, as 361 * per the ACPI specification. 362 * 363 ******************************************************************************/ 364 365 ACPI_STATUS 366 AcpiExLoadOp ( 367 ACPI_OPERAND_OBJECT *ObjDesc, 368 ACPI_OPERAND_OBJECT *Target, 369 ACPI_WALK_STATE *WalkState) 370 { 371 ACPI_OPERAND_OBJECT *DdbHandle; 372 ACPI_TABLE_HEADER *TableHeader; 373 ACPI_TABLE_HEADER *Table; 374 UINT32 TableIndex; 375 ACPI_STATUS Status; 376 UINT32 Length; 377 378 379 ACPI_FUNCTION_TRACE (ExLoadOp); 380 381 382 /* Source Object can be either an OpRegion or a Buffer/Field */ 383 384 switch (ObjDesc->Common.Type) 385 { 386 case ACPI_TYPE_REGION: 387 388 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 389 "Load table from Region %p\n", ObjDesc)); 390 391 /* Region must be SystemMemory (from ACPI spec) */ 392 393 if (ObjDesc->Region.SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) 394 { 395 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 396 } 397 398 /* 399 * If the Region Address and Length have not been previously evaluated, 400 * evaluate them now and save the results. 401 */ 402 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 403 { 404 Status = AcpiDsGetRegionArguments (ObjDesc); 405 if (ACPI_FAILURE (Status)) 406 { 407 return_ACPI_STATUS (Status); 408 } 409 } 410 411 /* Get the table header first so we can get the table length */ 412 413 TableHeader = ACPI_ALLOCATE (sizeof (ACPI_TABLE_HEADER)); 414 if (!TableHeader) 415 { 416 return_ACPI_STATUS (AE_NO_MEMORY); 417 } 418 419 Status = AcpiExRegionRead (ObjDesc, sizeof (ACPI_TABLE_HEADER), 420 ACPI_CAST_PTR (UINT8, TableHeader)); 421 Length = TableHeader->Length; 422 ACPI_FREE (TableHeader); 423 424 if (ACPI_FAILURE (Status)) 425 { 426 return_ACPI_STATUS (Status); 427 } 428 429 /* Must have at least an ACPI table header */ 430 431 if (Length < sizeof (ACPI_TABLE_HEADER)) 432 { 433 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); 434 } 435 436 /* 437 * The original implementation simply mapped the table, with no copy. 438 * However, the memory region is not guaranteed to remain stable and 439 * we must copy the table to a local buffer. For example, the memory 440 * region is corrupted after suspend on some machines. Dynamically 441 * loaded tables are usually small, so this overhead is minimal. 442 * 443 * The latest implementation (5/2009) does not use a mapping at all. 444 * We use the low-level operation region interface to read the table 445 * instead of the obvious optimization of using a direct mapping. 446 * This maintains a consistent use of operation regions across the 447 * entire subsystem. This is important if additional processing must 448 * be performed in the (possibly user-installed) operation region 449 * handler. For example, AcpiExec and ASLTS depend on this. 450 */ 451 452 /* Allocate a buffer for the table */ 453 454 Table = ACPI_ALLOCATE (Length); 455 if (!Table) 456 { 457 return_ACPI_STATUS (AE_NO_MEMORY); 458 } 459 460 /* Read the entire table */ 461 462 Status = AcpiExRegionRead (ObjDesc, Length, 463 ACPI_CAST_PTR (UINT8, Table)); 464 if (ACPI_FAILURE (Status)) 465 { 466 ACPI_FREE (Table); 467 return_ACPI_STATUS (Status); 468 } 469 break; 470 471 case ACPI_TYPE_BUFFER: /* Buffer or resolved RegionField */ 472 473 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 474 "Load table from Buffer or Field %p\n", ObjDesc)); 475 476 /* Must have at least an ACPI table header */ 477 478 if (ObjDesc->Buffer.Length < sizeof (ACPI_TABLE_HEADER)) 479 { 480 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); 481 } 482 483 /* Get the actual table length from the table header */ 484 485 TableHeader = ACPI_CAST_PTR (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 modified 501 * 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 (&AcpiGbl_RootTableList.Tables[TableIndex]); 540 if (ACPI_FAILURE (Status)) 541 { 542 return_ACPI_STATUS (Status); 543 } 544 545 /* 546 * Add the table to the namespace. 547 * 548 * Note: Load the table objects relative to the root of the namespace. 549 * This appears to go against the ACPI specification, but we do it for 550 * compatibility with other ACPI implementations. 551 */ 552 Status = AcpiExAddTable (TableIndex, AcpiGbl_RootNode, &DdbHandle); 553 if (ACPI_FAILURE (Status)) 554 { 555 /* On error, TablePtr was deallocated above */ 556 557 return_ACPI_STATUS (Status); 558 } 559 560 /* Store the DdbHandle into the Target operand */ 561 562 Status = AcpiExStore (DdbHandle, Target, WalkState); 563 if (ACPI_FAILURE (Status)) 564 { 565 (void) AcpiExUnloadTable (DdbHandle); 566 567 /* TablePtr was deallocated above */ 568 569 AcpiUtRemoveReference (DdbHandle); 570 return_ACPI_STATUS (Status); 571 } 572 573 /* Remove the reference by added by AcpiExStore above */ 574 575 AcpiUtRemoveReference (DdbHandle); 576 577 /* Invoke table handler if present */ 578 579 if (AcpiGbl_TableHandler) 580 { 581 (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_LOAD, Table, 582 AcpiGbl_TableHandlerContext); 583 } 584 585 return_ACPI_STATUS (Status); 586 } 587 588 589 /******************************************************************************* 590 * 591 * FUNCTION: AcpiExUnloadTable 592 * 593 * PARAMETERS: DdbHandle - Handle to a previously loaded table 594 * 595 * RETURN: Status 596 * 597 * DESCRIPTION: Unload an ACPI table 598 * 599 ******************************************************************************/ 600 601 ACPI_STATUS 602 AcpiExUnloadTable ( 603 ACPI_OPERAND_OBJECT *DdbHandle) 604 { 605 ACPI_STATUS Status = AE_OK; 606 ACPI_OPERAND_OBJECT *TableDesc = DdbHandle; 607 UINT32 TableIndex; 608 ACPI_TABLE_HEADER *Table; 609 610 611 ACPI_FUNCTION_TRACE (ExUnloadTable); 612 613 614 /* 615 * Temporarily emit a warning so that the ASL for the machine can be 616 * hopefully obtained. This is to say that the Unload() operator is 617 * extremely rare if not completely unused. 618 */ 619 ACPI_WARNING ((AE_INFO, 620 "Received request to unload an ACPI table")); 621 622 /* 623 * Validate the handle 624 * Although the handle is partially validated in AcpiExReconfiguration() 625 * when it calls AcpiExResolveOperands(), the handle is more completely 626 * validated here. 627 * 628 * Handle must be a valid operand object of type reference. Also, the 629 * DdbHandle must still be marked valid (table has not been previously 630 * unloaded) 631 */ 632 if ((!DdbHandle) || 633 (ACPI_GET_DESCRIPTOR_TYPE (DdbHandle) != ACPI_DESC_TYPE_OPERAND) || 634 (DdbHandle->Common.Type != ACPI_TYPE_LOCAL_REFERENCE) || 635 (!(DdbHandle->Common.Flags & AOPOBJ_DATA_VALID))) 636 { 637 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 638 } 639 640 /* Get the table index from the DdbHandle */ 641 642 TableIndex = TableDesc->Reference.Value; 643 644 /* Ensure the table is still loaded */ 645 646 if (!AcpiTbIsTableLoaded (TableIndex)) 647 { 648 return_ACPI_STATUS (AE_NOT_EXIST); 649 } 650 651 /* Invoke table handler if present */ 652 653 if (AcpiGbl_TableHandler) 654 { 655 Status = AcpiGetTableByIndex (TableIndex, &Table); 656 if (ACPI_SUCCESS (Status)) 657 { 658 (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_UNLOAD, Table, 659 AcpiGbl_TableHandlerContext); 660 } 661 } 662 663 /* Delete the portion of the namespace owned by this table */ 664 665 Status = AcpiTbDeleteNamespaceByOwner (TableIndex); 666 if (ACPI_FAILURE (Status)) 667 { 668 return_ACPI_STATUS (Status); 669 } 670 671 (void) AcpiTbReleaseOwnerId (TableIndex); 672 AcpiTbSetTableLoadedFlag (TableIndex, FALSE); 673 674 /* 675 * Invalidate the handle. We do this because the handle may be stored 676 * in a named object and may not be actually deleted until much later. 677 */ 678 DdbHandle->Common.Flags &= ~AOPOBJ_DATA_VALID; 679 return_ACPI_STATUS (AE_OK); 680 } 681