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