1 /****************************************************************************** 2 * 3 * Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes) 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2017, 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 <contrib/dev/acpica/include/acpi.h> 45 #include <contrib/dev/acpica/include/accommon.h> 46 #include <contrib/dev/acpica/include/acinterp.h> 47 #include <contrib/dev/acpica/include/acnamesp.h> 48 #include <contrib/dev/acpica/include/actables.h> 49 #include <contrib/dev/acpica/include/acdispat.h> 50 #include <contrib/dev/acpica/include/acevents.h> 51 #include <contrib/dev/acpica/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 /* Parameter Data (optional) */ 237 238 if (ParameterNode) 239 { 240 /* Store the parameter data into the optional parameter object */ 241 242 Status = AcpiExStore (Operand[5], 243 ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParameterNode), WalkState); 244 if (ACPI_FAILURE (Status)) 245 { 246 (void) AcpiExUnloadTable (DdbHandle); 247 248 AcpiUtRemoveReference (DdbHandle); 249 return_ACPI_STATUS (Status); 250 } 251 } 252 253 *ReturnDesc = DdbHandle; 254 return_ACPI_STATUS (Status); 255 } 256 257 258 /******************************************************************************* 259 * 260 * FUNCTION: AcpiExRegionRead 261 * 262 * PARAMETERS: ObjDesc - Region descriptor 263 * Length - Number of bytes to read 264 * Buffer - Pointer to where to put the data 265 * 266 * RETURN: Status 267 * 268 * DESCRIPTION: Read data from an operation region. The read starts from the 269 * beginning of the region. 270 * 271 ******************************************************************************/ 272 273 static ACPI_STATUS 274 AcpiExRegionRead ( 275 ACPI_OPERAND_OBJECT *ObjDesc, 276 UINT32 Length, 277 UINT8 *Buffer) 278 { 279 ACPI_STATUS Status; 280 UINT64 Value; 281 UINT32 RegionOffset = 0; 282 UINT32 i; 283 284 285 /* Bytewise reads */ 286 287 for (i = 0; i < Length; i++) 288 { 289 Status = AcpiEvAddressSpaceDispatch (ObjDesc, NULL, ACPI_READ, 290 RegionOffset, 8, &Value); 291 if (ACPI_FAILURE (Status)) 292 { 293 return (Status); 294 } 295 296 *Buffer = (UINT8) Value; 297 Buffer++; 298 RegionOffset++; 299 } 300 301 return (AE_OK); 302 } 303 304 305 /******************************************************************************* 306 * 307 * FUNCTION: AcpiExLoadOp 308 * 309 * PARAMETERS: ObjDesc - Region or Buffer/Field where the table will be 310 * obtained 311 * Target - Where a handle to the table will be stored 312 * WalkState - Current state 313 * 314 * RETURN: Status 315 * 316 * DESCRIPTION: Load an ACPI table from a field or operation region 317 * 318 * NOTE: Region Fields (Field, BankField, IndexFields) are resolved to buffer 319 * objects before this code is reached. 320 * 321 * If source is an operation region, it must refer to SystemMemory, as 322 * per the ACPI specification. 323 * 324 ******************************************************************************/ 325 326 ACPI_STATUS 327 AcpiExLoadOp ( 328 ACPI_OPERAND_OBJECT *ObjDesc, 329 ACPI_OPERAND_OBJECT *Target, 330 ACPI_WALK_STATE *WalkState) 331 { 332 ACPI_OPERAND_OBJECT *DdbHandle; 333 ACPI_TABLE_HEADER *TableHeader; 334 ACPI_TABLE_HEADER *Table; 335 UINT32 TableIndex; 336 ACPI_STATUS Status; 337 UINT32 Length; 338 339 340 ACPI_FUNCTION_TRACE (ExLoadOp); 341 342 343 /* Source Object can be either an OpRegion or a Buffer/Field */ 344 345 switch (ObjDesc->Common.Type) 346 { 347 case ACPI_TYPE_REGION: 348 349 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 350 "Load table from Region %p\n", ObjDesc)); 351 352 /* Region must be SystemMemory (from ACPI spec) */ 353 354 if (ObjDesc->Region.SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY) 355 { 356 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 357 } 358 359 /* 360 * If the Region Address and Length have not been previously 361 * evaluated, evaluate them now and save the results. 362 */ 363 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 364 { 365 Status = AcpiDsGetRegionArguments (ObjDesc); 366 if (ACPI_FAILURE (Status)) 367 { 368 return_ACPI_STATUS (Status); 369 } 370 } 371 372 /* Get the table header first so we can get the table length */ 373 374 TableHeader = ACPI_ALLOCATE (sizeof (ACPI_TABLE_HEADER)); 375 if (!TableHeader) 376 { 377 return_ACPI_STATUS (AE_NO_MEMORY); 378 } 379 380 Status = AcpiExRegionRead (ObjDesc, sizeof (ACPI_TABLE_HEADER), 381 ACPI_CAST_PTR (UINT8, TableHeader)); 382 Length = TableHeader->Length; 383 ACPI_FREE (TableHeader); 384 385 if (ACPI_FAILURE (Status)) 386 { 387 return_ACPI_STATUS (Status); 388 } 389 390 /* Must have at least an ACPI table header */ 391 392 if (Length < sizeof (ACPI_TABLE_HEADER)) 393 { 394 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); 395 } 396 397 /* 398 * The original implementation simply mapped the table, with no copy. 399 * However, the memory region is not guaranteed to remain stable and 400 * we must copy the table to a local buffer. For example, the memory 401 * region is corrupted after suspend on some machines. Dynamically 402 * loaded tables are usually small, so this overhead is minimal. 403 * 404 * The latest implementation (5/2009) does not use a mapping at all. 405 * We use the low-level operation region interface to read the table 406 * instead of the obvious optimization of using a direct mapping. 407 * This maintains a consistent use of operation regions across the 408 * entire subsystem. This is important if additional processing must 409 * be performed in the (possibly user-installed) operation region 410 * handler. For example, AcpiExec and ASLTS depend on this. 411 */ 412 413 /* Allocate a buffer for the table */ 414 415 Table = ACPI_ALLOCATE (Length); 416 if (!Table) 417 { 418 return_ACPI_STATUS (AE_NO_MEMORY); 419 } 420 421 /* Read the entire table */ 422 423 Status = AcpiExRegionRead (ObjDesc, Length, 424 ACPI_CAST_PTR (UINT8, Table)); 425 if (ACPI_FAILURE (Status)) 426 { 427 ACPI_FREE (Table); 428 return_ACPI_STATUS (Status); 429 } 430 break; 431 432 case ACPI_TYPE_BUFFER: /* Buffer or resolved RegionField */ 433 434 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, 435 "Load table from Buffer or Field %p\n", ObjDesc)); 436 437 /* Must have at least an ACPI table header */ 438 439 if (ObjDesc->Buffer.Length < sizeof (ACPI_TABLE_HEADER)) 440 { 441 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); 442 } 443 444 /* Get the actual table length from the table header */ 445 446 TableHeader = ACPI_CAST_PTR ( 447 ACPI_TABLE_HEADER, ObjDesc->Buffer.Pointer); 448 Length = TableHeader->Length; 449 450 /* Table cannot extend beyond the buffer */ 451 452 if (Length > ObjDesc->Buffer.Length) 453 { 454 return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); 455 } 456 if (Length < sizeof (ACPI_TABLE_HEADER)) 457 { 458 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH); 459 } 460 461 /* 462 * Copy the table from the buffer because the buffer could be 463 * modified or even deleted in the future 464 */ 465 Table = ACPI_ALLOCATE (Length); 466 if (!Table) 467 { 468 return_ACPI_STATUS (AE_NO_MEMORY); 469 } 470 471 memcpy (Table, TableHeader, Length); 472 break; 473 474 default: 475 476 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 477 } 478 479 /* Install the new table into the local data structures */ 480 481 ACPI_INFO (("Dynamic OEM Table Load:")); 482 AcpiExExitInterpreter (); 483 Status = AcpiTbInstallAndLoadTable (ACPI_PTR_TO_PHYSADDR (Table), 484 ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, TRUE, &TableIndex); 485 AcpiExEnterInterpreter (); 486 if (ACPI_FAILURE (Status)) 487 { 488 /* Delete allocated table buffer */ 489 490 ACPI_FREE (Table); 491 return_ACPI_STATUS (Status); 492 } 493 494 /* 495 * Add the table to the namespace. 496 * 497 * Note: Load the table objects relative to the root of the namespace. 498 * This appears to go against the ACPI specification, but we do it for 499 * compatibility with other ACPI implementations. 500 */ 501 Status = AcpiExAddTable (TableIndex, &DdbHandle); 502 if (ACPI_FAILURE (Status)) 503 { 504 /* On error, TablePtr was deallocated above */ 505 506 return_ACPI_STATUS (Status); 507 } 508 509 /* Store the DdbHandle into the Target operand */ 510 511 Status = AcpiExStore (DdbHandle, Target, WalkState); 512 if (ACPI_FAILURE (Status)) 513 { 514 (void) AcpiExUnloadTable (DdbHandle); 515 516 /* TablePtr was deallocated above */ 517 518 AcpiUtRemoveReference (DdbHandle); 519 return_ACPI_STATUS (Status); 520 } 521 522 /* Remove the reference by added by AcpiExStore above */ 523 524 AcpiUtRemoveReference (DdbHandle); 525 return_ACPI_STATUS (Status); 526 } 527 528 529 /******************************************************************************* 530 * 531 * FUNCTION: AcpiExUnloadTable 532 * 533 * PARAMETERS: DdbHandle - Handle to a previously loaded table 534 * 535 * RETURN: Status 536 * 537 * DESCRIPTION: Unload an ACPI table 538 * 539 ******************************************************************************/ 540 541 ACPI_STATUS 542 AcpiExUnloadTable ( 543 ACPI_OPERAND_OBJECT *DdbHandle) 544 { 545 ACPI_STATUS Status = AE_OK; 546 ACPI_OPERAND_OBJECT *TableDesc = DdbHandle; 547 UINT32 TableIndex; 548 549 550 ACPI_FUNCTION_TRACE (ExUnloadTable); 551 552 553 /* 554 * Temporarily emit a warning so that the ASL for the machine can be 555 * hopefully obtained. This is to say that the Unload() operator is 556 * extremely rare if not completely unused. 557 */ 558 ACPI_WARNING ((AE_INFO, 559 "Received request to unload an ACPI table")); 560 561 /* 562 * Validate the handle 563 * Although the handle is partially validated in AcpiExReconfiguration() 564 * when it calls AcpiExResolveOperands(), the handle is more completely 565 * validated here. 566 * 567 * Handle must be a valid operand object of type reference. Also, the 568 * DdbHandle must still be marked valid (table has not been previously 569 * unloaded) 570 */ 571 if ((!DdbHandle) || 572 (ACPI_GET_DESCRIPTOR_TYPE (DdbHandle) != ACPI_DESC_TYPE_OPERAND) || 573 (DdbHandle->Common.Type != ACPI_TYPE_LOCAL_REFERENCE) || 574 (!(DdbHandle->Common.Flags & AOPOBJ_DATA_VALID))) 575 { 576 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 577 } 578 579 /* Get the table index from the DdbHandle */ 580 581 TableIndex = TableDesc->Reference.Value; 582 583 /* 584 * Release the interpreter lock so that the table lock won't have 585 * strict order requirement against it. 586 */ 587 AcpiExExitInterpreter (); 588 Status = AcpiTbUnloadTable (TableIndex); 589 AcpiExEnterInterpreter (); 590 591 /* 592 * Invalidate the handle. We do this because the handle may be stored 593 * in a named object and may not be actually deleted until much later. 594 */ 595 if (ACPI_SUCCESS (Status)) 596 { 597 DdbHandle->Common.Flags &= ~AOPOBJ_DATA_VALID; 598 } 599 return_ACPI_STATUS (Status); 600 } 601