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