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