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