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