1 /****************************************************************************** 2 * 3 * Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes) 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2013, 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 61 static ACPI_STATUS 62 AcpiExAddTable ( 63 UINT32 TableIndex, 64 ACPI_NAMESPACE_NODE *ParentNode, 65 ACPI_OPERAND_OBJECT **DdbHandle); 66 67 static ACPI_STATUS 68 AcpiExRegionRead ( 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 89 static ACPI_STATUS 90 AcpiExAddTable ( 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 165 ACPI_STATUS 166 AcpiExLoadTableOp ( 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 323 static ACPI_STATUS 324 AcpiExRegionRead ( 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 376 ACPI_STATUS 377 AcpiExLoadOp ( 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 *Table; 384 ACPI_TABLE_DESC TableDesc; 385 UINT32 TableIndex; 386 ACPI_STATUS Status; 387 UINT32 Length; 388 389 390 ACPI_FUNCTION_TRACE (ExLoadOp); 391 392 393 ACPI_MEMSET (&TableDesc, 0, sizeof (ACPI_TABLE_DESC)); 394 395 /* Source Object can be either an OpRegion or a Buffer/Field */ 396 397 switch (ObjDesc->Common.Type) 398 { 399 case ACPI_TYPE_REGION: 400 401 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 402 "Load table from Region %p\n", ObjDesc)); 403 404 /* Region must be SystemMemory (from ACPI spec) */ 405 406 if (ObjDesc->Region.SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) 407 { 408 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 409 } 410 411 /* 412 * If the Region Address and Length have not been previously evaluated, 413 * evaluate them now and save the results. 414 */ 415 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 416 { 417 Status = AcpiDsGetRegionArguments (ObjDesc); 418 if (ACPI_FAILURE (Status)) 419 { 420 return_ACPI_STATUS (Status); 421 } 422 } 423 424 /* Get the table header first so we can get the table length */ 425 426 Table = ACPI_ALLOCATE (sizeof (ACPI_TABLE_HEADER)); 427 if (!Table) 428 { 429 return_ACPI_STATUS (AE_NO_MEMORY); 430 } 431 432 Status = AcpiExRegionRead (ObjDesc, sizeof (ACPI_TABLE_HEADER), 433 ACPI_CAST_PTR (UINT8, Table)); 434 Length = Table->Length; 435 ACPI_FREE (Table); 436 437 if (ACPI_FAILURE (Status)) 438 { 439 return_ACPI_STATUS (Status); 440 } 441 442 /* Must have at least an ACPI table header */ 443 444 if (Length < sizeof (ACPI_TABLE_HEADER)) 445 { 446 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); 447 } 448 449 /* 450 * The original implementation simply mapped the table, with no copy. 451 * However, the memory region is not guaranteed to remain stable and 452 * we must copy the table to a local buffer. For example, the memory 453 * region is corrupted after suspend on some machines. Dynamically 454 * loaded tables are usually small, so this overhead is minimal. 455 * 456 * The latest implementation (5/2009) does not use a mapping at all. 457 * We use the low-level operation region interface to read the table 458 * instead of the obvious optimization of using a direct mapping. 459 * This maintains a consistent use of operation regions across the 460 * entire subsystem. This is important if additional processing must 461 * be performed in the (possibly user-installed) operation region 462 * handler. For example, AcpiExec and ASLTS depend on this. 463 */ 464 465 /* Allocate a buffer for the table */ 466 467 TableDesc.Pointer = ACPI_ALLOCATE (Length); 468 if (!TableDesc.Pointer) 469 { 470 return_ACPI_STATUS (AE_NO_MEMORY); 471 } 472 473 /* Read the entire table */ 474 475 Status = AcpiExRegionRead (ObjDesc, Length, 476 ACPI_CAST_PTR (UINT8, TableDesc.Pointer)); 477 if (ACPI_FAILURE (Status)) 478 { 479 ACPI_FREE (TableDesc.Pointer); 480 return_ACPI_STATUS (Status); 481 } 482 483 TableDesc.Address = ObjDesc->Region.Address; 484 break; 485 486 case ACPI_TYPE_BUFFER: /* Buffer or resolved RegionField */ 487 488 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 489 "Load table from Buffer or Field %p\n", ObjDesc)); 490 491 /* Must have at least an ACPI table header */ 492 493 if (ObjDesc->Buffer.Length < sizeof (ACPI_TABLE_HEADER)) 494 { 495 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); 496 } 497 498 /* Get the actual table length from the table header */ 499 500 Table = ACPI_CAST_PTR (ACPI_TABLE_HEADER, ObjDesc->Buffer.Pointer); 501 Length = Table->Length; 502 503 /* Table cannot extend beyond the buffer */ 504 505 if (Length > ObjDesc->Buffer.Length) 506 { 507 return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); 508 } 509 if (Length < sizeof (ACPI_TABLE_HEADER)) 510 { 511 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); 512 } 513 514 /* 515 * Copy the table from the buffer because the buffer could be modified 516 * or even deleted in the future 517 */ 518 TableDesc.Pointer = ACPI_ALLOCATE (Length); 519 if (!TableDesc.Pointer) 520 { 521 return_ACPI_STATUS (AE_NO_MEMORY); 522 } 523 524 ACPI_MEMCPY (TableDesc.Pointer, Table, Length); 525 TableDesc.Address = ACPI_TO_INTEGER (TableDesc.Pointer); 526 break; 527 528 default: 529 530 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 531 } 532 533 /* Validate table checksum (will not get validated in TbAddTable) */ 534 535 Status = AcpiTbVerifyChecksum (TableDesc.Pointer, Length); 536 if (ACPI_FAILURE (Status)) 537 { 538 ACPI_FREE (TableDesc.Pointer); 539 return_ACPI_STATUS (Status); 540 } 541 542 /* Complete the table descriptor */ 543 544 TableDesc.Length = Length; 545 TableDesc.Flags = ACPI_TABLE_ORIGIN_ALLOCATED; 546 547 /* Install the new table into the local data structures */ 548 549 Status = AcpiTbAddTable (&TableDesc, &TableIndex); 550 if (ACPI_FAILURE (Status)) 551 { 552 /* Delete allocated table buffer */ 553 554 AcpiTbDeleteTable (&TableDesc); 555 return_ACPI_STATUS (Status); 556 } 557 558 /* 559 * Add the table to the namespace. 560 * 561 * Note: Load the table objects relative to the root of the namespace. 562 * This appears to go against the ACPI specification, but we do it for 563 * compatibility with other ACPI implementations. 564 */ 565 Status = AcpiExAddTable (TableIndex, AcpiGbl_RootNode, &DdbHandle); 566 if (ACPI_FAILURE (Status)) 567 { 568 /* On error, TablePtr was deallocated above */ 569 570 return_ACPI_STATUS (Status); 571 } 572 573 /* Store the DdbHandle into the Target operand */ 574 575 Status = AcpiExStore (DdbHandle, Target, WalkState); 576 if (ACPI_FAILURE (Status)) 577 { 578 (void) AcpiExUnloadTable (DdbHandle); 579 580 /* TablePtr was deallocated above */ 581 582 AcpiUtRemoveReference (DdbHandle); 583 return_ACPI_STATUS (Status); 584 } 585 586 ACPI_INFO ((AE_INFO, "Dynamic OEM Table Load:")); 587 AcpiTbPrintTableHeader (0, TableDesc.Pointer); 588 589 /* Remove the reference by added by AcpiExStore above */ 590 591 AcpiUtRemoveReference (DdbHandle); 592 593 /* Invoke table handler if present */ 594 595 if (AcpiGbl_TableHandler) 596 { 597 (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_LOAD, TableDesc.Pointer, 598 AcpiGbl_TableHandlerContext); 599 } 600 601 return_ACPI_STATUS (Status); 602 } 603 604 605 /******************************************************************************* 606 * 607 * FUNCTION: AcpiExUnloadTable 608 * 609 * PARAMETERS: DdbHandle - Handle to a previously loaded table 610 * 611 * RETURN: Status 612 * 613 * DESCRIPTION: Unload an ACPI table 614 * 615 ******************************************************************************/ 616 617 ACPI_STATUS 618 AcpiExUnloadTable ( 619 ACPI_OPERAND_OBJECT *DdbHandle) 620 { 621 ACPI_STATUS Status = AE_OK; 622 ACPI_OPERAND_OBJECT *TableDesc = DdbHandle; 623 UINT32 TableIndex; 624 ACPI_TABLE_HEADER *Table; 625 626 627 ACPI_FUNCTION_TRACE (ExUnloadTable); 628 629 630 /* 631 * Validate the handle 632 * Although the handle is partially validated in AcpiExReconfiguration() 633 * when it calls AcpiExResolveOperands(), the handle is more completely 634 * validated here. 635 * 636 * Handle must be a valid operand object of type reference. Also, the 637 * DdbHandle must still be marked valid (table has not been previously 638 * unloaded) 639 */ 640 if ((!DdbHandle) || 641 (ACPI_GET_DESCRIPTOR_TYPE (DdbHandle) != ACPI_DESC_TYPE_OPERAND) || 642 (DdbHandle->Common.Type != ACPI_TYPE_LOCAL_REFERENCE) || 643 (!(DdbHandle->Common.Flags & AOPOBJ_DATA_VALID))) 644 { 645 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 646 } 647 648 /* Get the table index from the DdbHandle */ 649 650 TableIndex = TableDesc->Reference.Value; 651 652 /* Ensure the table is still loaded */ 653 654 if (!AcpiTbIsTableLoaded (TableIndex)) 655 { 656 return_ACPI_STATUS (AE_NOT_EXIST); 657 } 658 659 /* Invoke table handler if present */ 660 661 if (AcpiGbl_TableHandler) 662 { 663 Status = AcpiGetTableByIndex (TableIndex, &Table); 664 if (ACPI_SUCCESS (Status)) 665 { 666 (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_UNLOAD, Table, 667 AcpiGbl_TableHandlerContext); 668 } 669 } 670 671 /* Delete the portion of the namespace owned by this table */ 672 673 Status = AcpiTbDeleteNamespaceByOwner (TableIndex); 674 if (ACPI_FAILURE (Status)) 675 { 676 return_ACPI_STATUS (Status); 677 } 678 679 (void) AcpiTbReleaseOwnerId (TableIndex); 680 AcpiTbSetTableLoadedFlag (TableIndex, FALSE); 681 682 /* 683 * Invalidate the handle. We do this because the handle may be stored 684 * in a named object and may not be actually deleted until much later. 685 */ 686 DdbHandle->Common.Flags &= ~AOPOBJ_DATA_VALID; 687 return_ACPI_STATUS (AE_OK); 688 } 689