1 /******************************************************************************
3 * Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes)
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2011, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
44 #define __EXCONFIG_C__
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>
55 #define _COMPONENT ACPI_EXECUTER
56 ACPI_MODULE_NAME ("exconfig")
58 /* Local prototypes */
63 ACPI_NAMESPACE_NODE *ParentNode,
64 ACPI_OPERAND_OBJECT **DdbHandle);
68 ACPI_OPERAND_OBJECT *ObjDesc,
73 /*******************************************************************************
75 * FUNCTION: AcpiExAddTable
77 * PARAMETERS: Table - Pointer to raw table
78 * ParentNode - Where to load the table (scope)
79 * DdbHandle - Where to return the table handle.
83 * DESCRIPTION: Common function to Install and Load an ACPI table with a
84 * returned table handle.
86 ******************************************************************************/
91 ACPI_NAMESPACE_NODE *ParentNode,
92 ACPI_OPERAND_OBJECT **DdbHandle)
94 ACPI_OPERAND_OBJECT *ObjDesc;
96 ACPI_OWNER_ID OwnerId;
99 ACPI_FUNCTION_TRACE (ExAddTable);
102 /* Create an object to be the table handle */
104 ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE);
107 return_ACPI_STATUS (AE_NO_MEMORY);
110 /* Init the table handle */
112 ObjDesc->Common.Flags |= AOPOBJ_DATA_VALID;
113 ObjDesc->Reference.Class = ACPI_REFCLASS_TABLE;
114 *DdbHandle = ObjDesc;
116 /* Install the new table into the local data structures */
118 ObjDesc->Reference.Value = TableIndex;
120 /* Add the table to the namespace */
122 Status = AcpiNsLoadTable (TableIndex, ParentNode);
123 if (ACPI_FAILURE (Status))
125 AcpiUtRemoveReference (ObjDesc);
127 return_ACPI_STATUS (Status);
130 /* Execute any module-level code that was found in the table */
132 AcpiExExitInterpreter ();
133 AcpiNsExecModuleCodeList ();
134 AcpiExEnterInterpreter ();
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.
141 Status = AcpiTbGetOwnerId (TableIndex, &OwnerId);
142 if (ACPI_SUCCESS (Status))
144 AcpiEvUpdateGpes (OwnerId);
147 return_ACPI_STATUS (AE_OK);
151 /*******************************************************************************
153 * FUNCTION: AcpiExLoadTableOp
155 * PARAMETERS: WalkState - Current state with operands
156 * ReturnDesc - Where to store the return object
160 * DESCRIPTION: Load an ACPI table from the RSDT/XSDT
162 ******************************************************************************/
166 ACPI_WALK_STATE *WalkState,
167 ACPI_OPERAND_OBJECT **ReturnDesc)
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;
179 ACPI_FUNCTION_TRACE (ExLoadTableOp);
182 /* Validate lengths for the SignatureString, OEMIDString, OEMTableID */
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))
188 return_ACPI_STATUS (AE_BAD_PARAMETER);
191 /* Find the ACPI table in the RSDT/XSDT */
193 Status = AcpiTbFindTable (Operand[0]->String.Pointer,
194 Operand[1]->String.Pointer,
195 Operand[2]->String.Pointer, &TableIndex);
196 if (ACPI_FAILURE (Status))
198 if (Status != AE_NOT_FOUND)
200 return_ACPI_STATUS (Status);
203 /* Table not found, return an Integer=0 and AE_OK */
205 DdbHandle = AcpiUtCreateIntegerObject ((UINT64) 0);
208 return_ACPI_STATUS (AE_NO_MEMORY);
211 *ReturnDesc = DdbHandle;
212 return_ACPI_STATUS (AE_OK);
217 StartNode = WalkState->ScopeInfo->Scope.Node;
218 ParentNode = AcpiGbl_RootNode;
220 /* RootPath (optional parameter) */
222 if (Operand[3]->String.Length > 0)
225 * Find the node referenced by the RootPathString. This is the
226 * location within the namespace where the table will be loaded.
228 Status = AcpiNsGetNode (StartNode, Operand[3]->String.Pointer,
229 ACPI_NS_SEARCH_PARENT, &ParentNode);
230 if (ACPI_FAILURE (Status))
232 return_ACPI_STATUS (Status);
236 /* ParameterPath (optional parameter) */
238 if (Operand[4]->String.Length > 0)
240 if ((Operand[4]->String.Pointer[0] != '\\') &&
241 (Operand[4]->String.Pointer[0] != '^'))
244 * Path is not absolute, so it will be relative to the node
245 * referenced by the RootPathString (or the NS root if omitted)
247 StartNode = ParentNode;
250 /* Find the node referenced by the ParameterPathString */
252 Status = AcpiNsGetNode (StartNode, Operand[4]->String.Pointer,
253 ACPI_NS_SEARCH_PARENT, &ParameterNode);
254 if (ACPI_FAILURE (Status))
256 return_ACPI_STATUS (Status);
260 /* Load the table into the namespace */
262 Status = AcpiExAddTable (TableIndex, ParentNode, &DdbHandle);
263 if (ACPI_FAILURE (Status))
265 return_ACPI_STATUS (Status);
268 /* Parameter Data (optional) */
272 /* Store the parameter data into the optional parameter object */
274 Status = AcpiExStore (Operand[5],
275 ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParameterNode),
277 if (ACPI_FAILURE (Status))
279 (void) AcpiExUnloadTable (DdbHandle);
281 AcpiUtRemoveReference (DdbHandle);
282 return_ACPI_STATUS (Status);
286 Status = AcpiGetTableByIndex (TableIndex, &Table);
287 if (ACPI_SUCCESS (Status))
289 ACPI_INFO ((AE_INFO, "Dynamic OEM Table Load:"));
290 AcpiTbPrintTableHeader (0, Table);
293 /* Invoke table handler if present */
295 if (AcpiGbl_TableHandler)
297 (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_LOAD, Table,
298 AcpiGbl_TableHandlerContext);
301 *ReturnDesc = DdbHandle;
302 return_ACPI_STATUS (Status);
306 /*******************************************************************************
308 * FUNCTION: AcpiExRegionRead
310 * PARAMETERS: ObjDesc - Region descriptor
311 * Length - Number of bytes to read
312 * Buffer - Pointer to where to put the data
316 * DESCRIPTION: Read data from an operation region. The read starts from the
317 * beginning of the region.
319 ******************************************************************************/
323 ACPI_OPERAND_OBJECT *ObjDesc,
329 UINT32 RegionOffset = 0;
335 for (i = 0; i < Length; i++)
337 Status = AcpiEvAddressSpaceDispatch (ObjDesc, ACPI_READ,
338 RegionOffset, 8, &Value);
339 if (ACPI_FAILURE (Status))
344 *Buffer = (UINT8) Value;
353 /*******************************************************************************
355 * FUNCTION: AcpiExLoadOp
357 * PARAMETERS: ObjDesc - Region or Buffer/Field where the table will be
359 * Target - Where a handle to the table will be stored
360 * WalkState - Current state
364 * DESCRIPTION: Load an ACPI table from a field or operation region
366 * NOTE: Region Fields (Field, BankField, IndexFields) are resolved to buffer
367 * objects before this code is reached.
369 * If source is an operation region, it must refer to SystemMemory, as
370 * per the ACPI specification.
372 ******************************************************************************/
376 ACPI_OPERAND_OBJECT *ObjDesc,
377 ACPI_OPERAND_OBJECT *Target,
378 ACPI_WALK_STATE *WalkState)
380 ACPI_OPERAND_OBJECT *DdbHandle;
381 ACPI_TABLE_HEADER *Table;
382 ACPI_TABLE_DESC TableDesc;
388 ACPI_FUNCTION_TRACE (ExLoadOp);
391 ACPI_MEMSET (&TableDesc, 0, sizeof (ACPI_TABLE_DESC));
393 /* Source Object can be either an OpRegion or a Buffer/Field */
395 switch (ObjDesc->Common.Type)
397 case ACPI_TYPE_REGION:
399 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
400 "Load table from Region %p\n", ObjDesc));
402 /* Region must be SystemMemory (from ACPI spec) */
404 if (ObjDesc->Region.SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY)
406 return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
410 * If the Region Address and Length have not been previously evaluated,
411 * evaluate them now and save the results.
413 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
415 Status = AcpiDsGetRegionArguments (ObjDesc);
416 if (ACPI_FAILURE (Status))
418 return_ACPI_STATUS (Status);
422 /* Get the table header first so we can get the table length */
424 Table = ACPI_ALLOCATE (sizeof (ACPI_TABLE_HEADER));
427 return_ACPI_STATUS (AE_NO_MEMORY);
430 Status = AcpiExRegionRead (ObjDesc, sizeof (ACPI_TABLE_HEADER),
431 ACPI_CAST_PTR (UINT8, Table));
432 Length = Table->Length;
435 if (ACPI_FAILURE (Status))
437 return_ACPI_STATUS (Status);
440 /* Must have at least an ACPI table header */
442 if (Length < sizeof (ACPI_TABLE_HEADER))
444 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
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.
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.
463 /* Allocate a buffer for the table */
465 TableDesc.Pointer = ACPI_ALLOCATE (Length);
466 if (!TableDesc.Pointer)
468 return_ACPI_STATUS (AE_NO_MEMORY);
471 /* Read the entire table */
473 Status = AcpiExRegionRead (ObjDesc, Length,
474 ACPI_CAST_PTR (UINT8, TableDesc.Pointer));
475 if (ACPI_FAILURE (Status))
477 ACPI_FREE (TableDesc.Pointer);
478 return_ACPI_STATUS (Status);
481 TableDesc.Address = ObjDesc->Region.Address;
485 case ACPI_TYPE_BUFFER: /* Buffer or resolved RegionField */
487 ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
488 "Load table from Buffer or Field %p\n", ObjDesc));
490 /* Must have at least an ACPI table header */
492 if (ObjDesc->Buffer.Length < sizeof (ACPI_TABLE_HEADER))
494 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
497 /* Get the actual table length from the table header */
499 Table = ACPI_CAST_PTR (ACPI_TABLE_HEADER, ObjDesc->Buffer.Pointer);
500 Length = Table->Length;
502 /* Table cannot extend beyond the buffer */
504 if (Length > ObjDesc->Buffer.Length)
506 return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
508 if (Length < sizeof (ACPI_TABLE_HEADER))
510 return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
514 * Copy the table from the buffer because the buffer could be modified
515 * or even deleted in the future
517 TableDesc.Pointer = ACPI_ALLOCATE (Length);
518 if (!TableDesc.Pointer)
520 return_ACPI_STATUS (AE_NO_MEMORY);
523 ACPI_MEMCPY (TableDesc.Pointer, Table, Length);
524 TableDesc.Address = ACPI_TO_INTEGER (TableDesc.Pointer);
529 return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
532 /* Validate table checksum (will not get validated in TbAddTable) */
534 Status = AcpiTbVerifyChecksum (TableDesc.Pointer, Length);
535 if (ACPI_FAILURE (Status))
537 ACPI_FREE (TableDesc.Pointer);
538 return_ACPI_STATUS (Status);
541 /* Complete the table descriptor */
543 TableDesc.Length = Length;
544 TableDesc.Flags = ACPI_TABLE_ORIGIN_ALLOCATED;
546 /* Install the new table into the local data structures */
548 Status = AcpiTbAddTable (&TableDesc, &TableIndex);
549 if (ACPI_FAILURE (Status))
551 /* Delete allocated table buffer */
553 AcpiTbDeleteTable (&TableDesc);
554 return_ACPI_STATUS (Status);
558 * Add the table to the namespace.
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.
564 Status = AcpiExAddTable (TableIndex, AcpiGbl_RootNode, &DdbHandle);
565 if (ACPI_FAILURE (Status))
567 /* On error, TablePtr was deallocated above */
569 return_ACPI_STATUS (Status);
572 /* Store the DdbHandle into the Target operand */
574 Status = AcpiExStore (DdbHandle, Target, WalkState);
575 if (ACPI_FAILURE (Status))
577 (void) AcpiExUnloadTable (DdbHandle);
579 /* TablePtr was deallocated above */
581 AcpiUtRemoveReference (DdbHandle);
582 return_ACPI_STATUS (Status);
585 ACPI_INFO ((AE_INFO, "Dynamic OEM Table Load:"));
586 AcpiTbPrintTableHeader (0, TableDesc.Pointer);
588 /* Remove the reference by added by AcpiExStore above */
590 AcpiUtRemoveReference (DdbHandle);
592 /* Invoke table handler if present */
594 if (AcpiGbl_TableHandler)
596 (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_LOAD, TableDesc.Pointer,
597 AcpiGbl_TableHandlerContext);
600 return_ACPI_STATUS (Status);
604 /*******************************************************************************
606 * FUNCTION: AcpiExUnloadTable
608 * PARAMETERS: DdbHandle - Handle to a previously loaded table
612 * DESCRIPTION: Unload an ACPI table
614 ******************************************************************************/
618 ACPI_OPERAND_OBJECT *DdbHandle)
620 ACPI_STATUS Status = AE_OK;
621 ACPI_OPERAND_OBJECT *TableDesc = DdbHandle;
623 ACPI_TABLE_HEADER *Table;
626 ACPI_FUNCTION_TRACE (ExUnloadTable);
630 * Validate the handle
631 * Although the handle is partially validated in AcpiExReconfiguration()
632 * when it calls AcpiExResolveOperands(), the handle is more completely
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
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)))
644 return_ACPI_STATUS (AE_BAD_PARAMETER);
647 /* Get the table index from the DdbHandle */
649 TableIndex = TableDesc->Reference.Value;
651 /* Ensure the table is still loaded */
653 if (!AcpiTbIsTableLoaded (TableIndex))
655 return_ACPI_STATUS (AE_NOT_EXIST);
658 /* Invoke table handler if present */
660 if (AcpiGbl_TableHandler)
662 Status = AcpiGetTableByIndex (TableIndex, &Table);
663 if (ACPI_SUCCESS (Status))
665 (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_UNLOAD, Table,
666 AcpiGbl_TableHandlerContext);
670 /* Delete the portion of the namespace owned by this table */
672 Status = AcpiTbDeleteNamespaceByOwner (TableIndex);
673 if (ACPI_FAILURE (Status))
675 return_ACPI_STATUS (Status);
678 (void) AcpiTbReleaseOwnerId (TableIndex);
679 AcpiTbSetTableLoadedFlag (TableIndex, FALSE);
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.
685 DdbHandle->Common.Flags &= ~AOPOBJ_DATA_VALID;
686 return_ACPI_STATUS (AE_OK);