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