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