1 /****************************************************************************** 2 * 3 * Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes) 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2011, 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 "acpi.h" 47 #include "accommon.h" 48 #include "acinterp.h" 49 #include "acnamesp.h" 50 #include "actables.h" 51 #include "acdispat.h" 52 #include "acevents.h" 53 54 55 #define _COMPONENT ACPI_EXECUTER 56 ACPI_MODULE_NAME ("exconfig") 57 58 /* Local prototypes */ 59 60 static ACPI_STATUS 61 AcpiExAddTable ( 62 UINT32 TableIndex, 63 ACPI_NAMESPACE_NODE *ParentNode, 64 ACPI_OPERAND_OBJECT **DdbHandle); 65 66 static ACPI_STATUS 67 AcpiExRegionRead ( 68 ACPI_OPERAND_OBJECT *ObjDesc, 69 UINT32 Length, 70 UINT8 *Buffer); 71 72 73 /******************************************************************************* 74 * 75 * FUNCTION: AcpiExAddTable 76 * 77 * PARAMETERS: Table - Pointer to raw table 78 * ParentNode - Where to load the table (scope) 79 * DdbHandle - Where to return the table handle. 80 * 81 * RETURN: Status 82 * 83 * DESCRIPTION: Common function to Install and Load an ACPI table with a 84 * returned table handle. 85 * 86 ******************************************************************************/ 87 88 static ACPI_STATUS 89 AcpiExAddTable ( 90 UINT32 TableIndex, 91 ACPI_NAMESPACE_NODE *ParentNode, 92 ACPI_OPERAND_OBJECT **DdbHandle) 93 { 94 ACPI_OPERAND_OBJECT *ObjDesc; 95 ACPI_STATUS Status; 96 ACPI_OWNER_ID OwnerId; 97 98 99 ACPI_FUNCTION_TRACE (ExAddTable); 100 101 102 /* Create an object to be the table handle */ 103 104 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE); 105 if (!ObjDesc) 106 { 107 return_ACPI_STATUS (AE_NO_MEMORY); 108 } 109 110 /* Init the table handle */ 111 112 ObjDesc->Common.Flags |= AOPOBJ_DATA_VALID; 113 ObjDesc->Reference.Class = ACPI_REFCLASS_TABLE; 114 *DdbHandle = ObjDesc; 115 116 /* Install the new table into the local data structures */ 117 118 ObjDesc->Reference.Value = TableIndex; 119 120 /* Add the table to the namespace */ 121 122 Status = AcpiNsLoadTable (TableIndex, ParentNode); 123 if (ACPI_FAILURE (Status)) 124 { 125 AcpiUtRemoveReference (ObjDesc); 126 *DdbHandle = NULL; 127 return_ACPI_STATUS (Status); 128 } 129 130 /* Execute any module-level code that was found in the table */ 131 132 AcpiExExitInterpreter (); 133 AcpiNsExecModuleCodeList (); 134 AcpiExEnterInterpreter (); 135 136 /* 137 * Update GPEs for any new _Lxx/_Exx methods. Ignore errors. The host is 138 * responsible for discovering any new wake GPEs by running _PRW methods 139 * that may have been loaded by this table. 140 */ 141 Status = AcpiTbGetOwnerId (TableIndex, &OwnerId); 142 if (ACPI_SUCCESS (Status)) 143 { 144 AcpiEvUpdateGpes (OwnerId); 145 } 146 147 return_ACPI_STATUS (AE_OK); 148 } 149 150 151 /******************************************************************************* 152 * 153 * FUNCTION: AcpiExLoadTableOp 154 * 155 * PARAMETERS: WalkState - Current state with operands 156 * ReturnDesc - Where to store the return object 157 * 158 * RETURN: Status 159 * 160 * DESCRIPTION: Load an ACPI table from the RSDT/XSDT 161 * 162 ******************************************************************************/ 163 164 ACPI_STATUS 165 AcpiExLoadTableOp ( 166 ACPI_WALK_STATE *WalkState, 167 ACPI_OPERAND_OBJECT **ReturnDesc) 168 { 169 ACPI_STATUS Status; 170 ACPI_OPERAND_OBJECT **Operand = &WalkState->Operands[0]; 171 ACPI_NAMESPACE_NODE *ParentNode; 172 ACPI_NAMESPACE_NODE *StartNode; 173 ACPI_NAMESPACE_NODE *ParameterNode = NULL; 174 ACPI_OPERAND_OBJECT *DdbHandle; 175 ACPI_TABLE_HEADER *Table; 176 UINT32 TableIndex; 177 178 179 ACPI_FUNCTION_TRACE (ExLoadTableOp); 180 181 182 /* Validate lengths for the SignatureString, OEMIDString, OEMTableID */ 183 184 if ((Operand[0]->String.Length > ACPI_NAME_SIZE) || 185 (Operand[1]->String.Length > ACPI_OEM_ID_SIZE) || 186 (Operand[2]->String.Length > ACPI_OEM_TABLE_ID_SIZE)) 187 { 188 return_ACPI_STATUS (AE_BAD_PARAMETER); 189 } 190 191 /* Find the ACPI table in the RSDT/XSDT */ 192 193 Status = AcpiTbFindTable (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] != '\\') && 241 (Operand[4]->String.Pointer[0] != '^')) 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, 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 *Table; 382 ACPI_TABLE_DESC TableDesc; 383 UINT32 TableIndex; 384 ACPI_STATUS Status; 385 UINT32 Length; 386 387 388 ACPI_FUNCTION_TRACE (ExLoadOp); 389 390 391 ACPI_MEMSET (&TableDesc, 0, sizeof (ACPI_TABLE_DESC)); 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 Table = ACPI_ALLOCATE (sizeof (ACPI_TABLE_HEADER)); 425 if (!Table) 426 { 427 return_ACPI_STATUS (AE_NO_MEMORY); 428 } 429 430 Status = AcpiExRegionRead (ObjDesc, sizeof (ACPI_TABLE_HEADER), 431 ACPI_CAST_PTR (UINT8, Table)); 432 Length = Table->Length; 433 ACPI_FREE (Table); 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 TableDesc.Pointer = ACPI_ALLOCATE (Length); 466 if (!TableDesc.Pointer) 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, TableDesc.Pointer)); 475 if (ACPI_FAILURE (Status)) 476 { 477 ACPI_FREE (TableDesc.Pointer); 478 return_ACPI_STATUS (Status); 479 } 480 481 TableDesc.Address = ObjDesc->Region.Address; 482 break; 483 484 485 case ACPI_TYPE_BUFFER: /* Buffer or resolved RegionField */ 486 487 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 488 "Load table from Buffer or Field %p\n", ObjDesc)); 489 490 /* Must have at least an ACPI table header */ 491 492 if (ObjDesc->Buffer.Length < sizeof (ACPI_TABLE_HEADER)) 493 { 494 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); 495 } 496 497 /* Get the actual table length from the table header */ 498 499 Table = ACPI_CAST_PTR (ACPI_TABLE_HEADER, ObjDesc->Buffer.Pointer); 500 Length = Table->Length; 501 502 /* Table cannot extend beyond the buffer */ 503 504 if (Length > ObjDesc->Buffer.Length) 505 { 506 return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); 507 } 508 if (Length < sizeof (ACPI_TABLE_HEADER)) 509 { 510 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); 511 } 512 513 /* 514 * Copy the table from the buffer because the buffer could be modified 515 * or even deleted in the future 516 */ 517 TableDesc.Pointer = ACPI_ALLOCATE (Length); 518 if (!TableDesc.Pointer) 519 { 520 return_ACPI_STATUS (AE_NO_MEMORY); 521 } 522 523 ACPI_MEMCPY (TableDesc.Pointer, Table, Length); 524 TableDesc.Address = ACPI_TO_INTEGER (TableDesc.Pointer); 525 break; 526 527 528 default: 529 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 530 } 531 532 /* Validate table checksum (will not get validated in TbAddTable) */ 533 534 Status = AcpiTbVerifyChecksum (TableDesc.Pointer, Length); 535 if (ACPI_FAILURE (Status)) 536 { 537 ACPI_FREE (TableDesc.Pointer); 538 return_ACPI_STATUS (Status); 539 } 540 541 /* Complete the table descriptor */ 542 543 TableDesc.Length = Length; 544 TableDesc.Flags = ACPI_TABLE_ORIGIN_ALLOCATED; 545 546 /* Install the new table into the local data structures */ 547 548 Status = AcpiTbAddTable (&TableDesc, &TableIndex); 549 if (ACPI_FAILURE (Status)) 550 { 551 /* Delete allocated table buffer */ 552 553 AcpiTbDeleteTable (&TableDesc); 554 return_ACPI_STATUS (Status); 555 } 556 557 /* 558 * Add the table to the namespace. 559 * 560 * Note: Load the table objects relative to the root of the namespace. 561 * This appears to go against the ACPI specification, but we do it for 562 * compatibility with other ACPI implementations. 563 */ 564 Status = AcpiExAddTable (TableIndex, AcpiGbl_RootNode, &DdbHandle); 565 if (ACPI_FAILURE (Status)) 566 { 567 /* On error, TablePtr was deallocated above */ 568 569 return_ACPI_STATUS (Status); 570 } 571 572 /* Store the DdbHandle into the Target operand */ 573 574 Status = AcpiExStore (DdbHandle, Target, WalkState); 575 if (ACPI_FAILURE (Status)) 576 { 577 (void) AcpiExUnloadTable (DdbHandle); 578 579 /* TablePtr was deallocated above */ 580 581 AcpiUtRemoveReference (DdbHandle); 582 return_ACPI_STATUS (Status); 583 } 584 585 ACPI_INFO ((AE_INFO, "Dynamic OEM Table Load:")); 586 AcpiTbPrintTableHeader (0, TableDesc.Pointer); 587 588 /* Remove the reference by added by AcpiExStore above */ 589 590 AcpiUtRemoveReference (DdbHandle); 591 592 /* Invoke table handler if present */ 593 594 if (AcpiGbl_TableHandler) 595 { 596 (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_LOAD, TableDesc.Pointer, 597 AcpiGbl_TableHandlerContext); 598 } 599 600 return_ACPI_STATUS (Status); 601 } 602 603 604 /******************************************************************************* 605 * 606 * FUNCTION: AcpiExUnloadTable 607 * 608 * PARAMETERS: DdbHandle - Handle to a previously loaded table 609 * 610 * RETURN: Status 611 * 612 * DESCRIPTION: Unload an ACPI table 613 * 614 ******************************************************************************/ 615 616 ACPI_STATUS 617 AcpiExUnloadTable ( 618 ACPI_OPERAND_OBJECT *DdbHandle) 619 { 620 ACPI_STATUS Status = AE_OK; 621 ACPI_OPERAND_OBJECT *TableDesc = DdbHandle; 622 UINT32 TableIndex; 623 ACPI_TABLE_HEADER *Table; 624 625 626 ACPI_FUNCTION_TRACE (ExUnloadTable); 627 628 629 /* 630 * Validate the handle 631 * Although the handle is partially validated in AcpiExReconfiguration() 632 * when it calls AcpiExResolveOperands(), the handle is more completely 633 * validated here. 634 * 635 * Handle must be a valid operand object of type reference. Also, the 636 * DdbHandle must still be marked valid (table has not been previously 637 * unloaded) 638 */ 639 if ((!DdbHandle) || 640 (ACPI_GET_DESCRIPTOR_TYPE (DdbHandle) != ACPI_DESC_TYPE_OPERAND) || 641 (DdbHandle->Common.Type != ACPI_TYPE_LOCAL_REFERENCE) || 642 (!(DdbHandle->Common.Flags & AOPOBJ_DATA_VALID))) 643 { 644 return_ACPI_STATUS (AE_BAD_PARAMETER); 645 } 646 647 /* Get the table index from the DdbHandle */ 648 649 TableIndex = TableDesc->Reference.Value; 650 651 /* Ensure the table is still loaded */ 652 653 if (!AcpiTbIsTableLoaded (TableIndex)) 654 { 655 return_ACPI_STATUS (AE_NOT_EXIST); 656 } 657 658 /* Invoke table handler if present */ 659 660 if (AcpiGbl_TableHandler) 661 { 662 Status = AcpiGetTableByIndex (TableIndex, &Table); 663 if (ACPI_SUCCESS (Status)) 664 { 665 (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_UNLOAD, Table, 666 AcpiGbl_TableHandlerContext); 667 } 668 } 669 670 /* Delete the portion of the namespace owned by this table */ 671 672 Status = AcpiTbDeleteNamespaceByOwner (TableIndex); 673 if (ACPI_FAILURE (Status)) 674 { 675 return_ACPI_STATUS (Status); 676 } 677 678 (void) AcpiTbReleaseOwnerId (TableIndex); 679 AcpiTbSetTableLoadedFlag (TableIndex, FALSE); 680 681 /* 682 * Invalidate the handle. We do this because the handle may be stored 683 * in a named object and may not be actually deleted until much later. 684 */ 685 DdbHandle->Common.Flags &= ~AOPOBJ_DATA_VALID; 686 return_ACPI_STATUS (AE_OK); 687 } 688