167754Smsmith/******************************************************************************
267754Smsmith *
377424Smsmith * Module Name: exconfig - Namespace reconfiguration (Load/Unload opcodes)
467754Smsmith *
567754Smsmith *****************************************************************************/
667754Smsmith
7217365Sjkim/*
8306536Sjkim * Copyright (C) 2000 - 2016, Intel Corp.
970243Smsmith * All rights reserved.
1067754Smsmith *
11217365Sjkim * Redistribution and use in source and binary forms, with or without
12217365Sjkim * modification, are permitted provided that the following conditions
13217365Sjkim * are met:
14217365Sjkim * 1. Redistributions of source code must retain the above copyright
15217365Sjkim *    notice, this list of conditions, and the following disclaimer,
16217365Sjkim *    without modification.
17217365Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18217365Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19217365Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20217365Sjkim *    including a substantially similar Disclaimer requirement for further
21217365Sjkim *    binary redistribution.
22217365Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23217365Sjkim *    of any contributors may be used to endorse or promote products derived
24217365Sjkim *    from this software without specific prior written permission.
2567754Smsmith *
26217365Sjkim * Alternatively, this software may be distributed under the terms of the
27217365Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28217365Sjkim * Software Foundation.
2967754Smsmith *
30217365Sjkim * NO WARRANTY
31217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32217365Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33217365Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34217365Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35217365Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36217365Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39217365Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40217365Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41217365Sjkim * POSSIBILITY OF SUCH DAMAGES.
42217365Sjkim */
4367754Smsmith
44193341Sjkim#include <contrib/dev/acpica/include/acpi.h>
45193341Sjkim#include <contrib/dev/acpica/include/accommon.h>
46193341Sjkim#include <contrib/dev/acpica/include/acinterp.h>
47193341Sjkim#include <contrib/dev/acpica/include/acnamesp.h>
48193341Sjkim#include <contrib/dev/acpica/include/actables.h>
49193341Sjkim#include <contrib/dev/acpica/include/acdispat.h>
50193341Sjkim#include <contrib/dev/acpica/include/acevents.h>
51245582Sjkim#include <contrib/dev/acpica/include/amlcode.h>
5267754Smsmith
5367754Smsmith
5477424Smsmith#define _COMPONENT          ACPI_EXECUTER
5591116Smsmith        ACPI_MODULE_NAME    ("exconfig")
5667754Smsmith
57151937Sjkim/* Local prototypes */
5867754Smsmith
59151937Sjkimstatic ACPI_STATUS
60151937SjkimAcpiExAddTable (
61193267Sjkim    UINT32                  TableIndex,
62151937Sjkim    ACPI_NAMESPACE_NODE     *ParentNode,
63151937Sjkim    ACPI_OPERAND_OBJECT     **DdbHandle);
64151937Sjkim
65193267Sjkimstatic ACPI_STATUS
66193267SjkimAcpiExRegionRead (
67193267Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
68193267Sjkim    UINT32                  Length,
69193267Sjkim    UINT8                   *Buffer);
70151937Sjkim
71193267Sjkim
7291116Smsmith/*******************************************************************************
7367754Smsmith *
7491116Smsmith * FUNCTION:    AcpiExAddTable
7591116Smsmith *
7691116Smsmith * PARAMETERS:  Table               - Pointer to raw table
7791116Smsmith *              ParentNode          - Where to load the table (scope)
7891116Smsmith *              DdbHandle           - Where to return the table handle.
7991116Smsmith *
8091116Smsmith * RETURN:      Status
8191116Smsmith *
8291116Smsmith * DESCRIPTION: Common function to Install and Load an ACPI table with a
8391116Smsmith *              returned table handle.
8491116Smsmith *
8591116Smsmith ******************************************************************************/
8691116Smsmith
87151937Sjkimstatic ACPI_STATUS
8891116SmsmithAcpiExAddTable (
89193267Sjkim    UINT32                  TableIndex,
9091116Smsmith    ACPI_NAMESPACE_NODE     *ParentNode,
9191116Smsmith    ACPI_OPERAND_OBJECT     **DdbHandle)
9291116Smsmith{
93207344Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc;
9491116Smsmith    ACPI_STATUS             Status;
95207344Sjkim    ACPI_OWNER_ID           OwnerId;
9691116Smsmith
9791116Smsmith
98167802Sjkim    ACPI_FUNCTION_TRACE (ExAddTable);
9991116Smsmith
10091116Smsmith
10191116Smsmith    /* Create an object to be the table handle */
10291116Smsmith
103107325Siwasaki    ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE);
10491116Smsmith    if (!ObjDesc)
10591116Smsmith    {
10691116Smsmith        return_ACPI_STATUS (AE_NO_MEMORY);
10791116Smsmith    }
10891116Smsmith
109151937Sjkim    /* Init the table handle */
110151937Sjkim
111193267Sjkim    ObjDesc->Common.Flags |= AOPOBJ_DATA_VALID;
112193267Sjkim    ObjDesc->Reference.Class = ACPI_REFCLASS_TABLE;
113151937Sjkim    *DdbHandle = ObjDesc;
114151937Sjkim
11591116Smsmith    /* Install the new table into the local data structures */
11691116Smsmith
117193267Sjkim    ObjDesc->Reference.Value = TableIndex;
118123315Snjl
11991116Smsmith    /* Add the table to the namespace */
12091116Smsmith
121167802Sjkim    Status = AcpiNsLoadTable (TableIndex, ParentNode);
12291116Smsmith    if (ACPI_FAILURE (Status))
12391116Smsmith    {
124167802Sjkim        AcpiUtRemoveReference (ObjDesc);
125167802Sjkim        *DdbHandle = NULL;
126197104Sjkim        return_ACPI_STATUS (Status);
12791116Smsmith    }
12891116Smsmith
129197104Sjkim    /* Execute any module-level code that was found in the table */
130197104Sjkim
131197104Sjkim    AcpiExExitInterpreter ();
132306536Sjkim    if (AcpiGbl_GroupModuleLevelCode)
133306536Sjkim    {
134306536Sjkim        AcpiNsExecModuleCodeList ();
135306536Sjkim    }
136197104Sjkim    AcpiExEnterInterpreter ();
137197104Sjkim
138216471Sjkim    /*
139216471Sjkim     * Update GPEs for any new _Lxx/_Exx methods. Ignore errors. The host is
140216471Sjkim     * responsible for discovering any new wake GPEs by running _PRW methods
141216471Sjkim     * that may have been loaded by this table.
142216471Sjkim     */
143207344Sjkim    Status = AcpiTbGetOwnerId (TableIndex, &OwnerId);
144207344Sjkim    if (ACPI_SUCCESS (Status))
145207344Sjkim    {
146207344Sjkim        AcpiEvUpdateGpes (OwnerId);
147207344Sjkim    }
148207344Sjkim
149207344Sjkim    return_ACPI_STATUS (AE_OK);
15091116Smsmith}
15191116Smsmith
15291116Smsmith
15391116Smsmith/*******************************************************************************
15491116Smsmith *
15577424Smsmith * FUNCTION:    AcpiExLoadTableOp
15667754Smsmith *
15791116Smsmith * PARAMETERS:  WalkState           - Current state with operands
15891116Smsmith *              ReturnDesc          - Where to store the return object
15967754Smsmith *
16067754Smsmith * RETURN:      Status
16167754Smsmith *
162167802Sjkim * DESCRIPTION: Load an ACPI table from the RSDT/XSDT
16367754Smsmith *
16491116Smsmith ******************************************************************************/
16567754Smsmith
16685756SmsmithACPI_STATUS
16791116SmsmithAcpiExLoadTableOp (
16891116Smsmith    ACPI_WALK_STATE         *WalkState,
16991116Smsmith    ACPI_OPERAND_OBJECT     **ReturnDesc)
17067754Smsmith{
17167754Smsmith    ACPI_STATUS             Status;
17291116Smsmith    ACPI_OPERAND_OBJECT     **Operand = &WalkState->Operands[0];
17391116Smsmith    ACPI_NAMESPACE_NODE     *ParentNode;
17491116Smsmith    ACPI_NAMESPACE_NODE     *StartNode;
17591116Smsmith    ACPI_NAMESPACE_NODE     *ParameterNode = NULL;
17691116Smsmith    ACPI_OPERAND_OBJECT     *DdbHandle;
177167802Sjkim    ACPI_TABLE_HEADER       *Table;
178193267Sjkim    UINT32                  TableIndex;
17967754Smsmith
18067754Smsmith
181167802Sjkim    ACPI_FUNCTION_TRACE (ExLoadTableOp);
18267754Smsmith
18367754Smsmith
184167802Sjkim    /* Find the ACPI table in the RSDT/XSDT */
18567754Smsmith
186245582Sjkim    Status = AcpiTbFindTable (
187306536Sjkim        Operand[0]->String.Pointer,
188306536Sjkim        Operand[1]->String.Pointer,
189306536Sjkim        Operand[2]->String.Pointer, &TableIndex);
19091116Smsmith    if (ACPI_FAILURE (Status))
19167754Smsmith    {
19291116Smsmith        if (Status != AE_NOT_FOUND)
19391116Smsmith        {
19491116Smsmith            return_ACPI_STATUS (Status);
19591116Smsmith        }
19691116Smsmith
197123315Snjl        /* Table not found, return an Integer=0 and AE_OK */
19891116Smsmith
199199337Sjkim        DdbHandle = AcpiUtCreateIntegerObject ((UINT64) 0);
20091116Smsmith        if (!DdbHandle)
20191116Smsmith        {
20291116Smsmith            return_ACPI_STATUS (AE_NO_MEMORY);
20391116Smsmith        }
20491116Smsmith
20591116Smsmith        *ReturnDesc = DdbHandle;
20691116Smsmith        return_ACPI_STATUS (AE_OK);
20791116Smsmith    }
20891116Smsmith
20991116Smsmith    /* Default nodes */
21091116Smsmith
21191116Smsmith    StartNode = WalkState->ScopeInfo->Scope.Node;
21291116Smsmith    ParentNode = AcpiGbl_RootNode;
21391116Smsmith
21491116Smsmith    /* RootPath (optional parameter) */
21591116Smsmith
21691116Smsmith    if (Operand[3]->String.Length > 0)
21791116Smsmith    {
21891116Smsmith        /*
219241973Sjkim         * Find the node referenced by the RootPathString. This is the
22091116Smsmith         * location within the namespace where the table will be loaded.
22191116Smsmith         */
222167802Sjkim        Status = AcpiNsGetNode (StartNode, Operand[3]->String.Pointer,
223306536Sjkim            ACPI_NS_SEARCH_PARENT, &ParentNode);
22467754Smsmith        if (ACPI_FAILURE (Status))
22567754Smsmith        {
22667754Smsmith            return_ACPI_STATUS (Status);
22767754Smsmith        }
22867754Smsmith    }
22967754Smsmith
23091116Smsmith    /* ParameterPath (optional parameter) */
23167754Smsmith
23291116Smsmith    if (Operand[4]->String.Length > 0)
23367754Smsmith    {
234245582Sjkim        if ((Operand[4]->String.Pointer[0] != AML_ROOT_PREFIX) &&
235245582Sjkim            (Operand[4]->String.Pointer[0] != AML_PARENT_PREFIX))
23691116Smsmith        {
23791116Smsmith            /*
23891116Smsmith             * Path is not absolute, so it will be relative to the node
23991116Smsmith             * referenced by the RootPathString (or the NS root if omitted)
24091116Smsmith             */
24191116Smsmith            StartNode = ParentNode;
24291116Smsmith        }
24391116Smsmith
244151937Sjkim        /* Find the node referenced by the ParameterPathString */
245151937Sjkim
246167802Sjkim        Status = AcpiNsGetNode (StartNode, Operand[4]->String.Pointer,
247306536Sjkim            ACPI_NS_SEARCH_PARENT, &ParameterNode);
24891116Smsmith        if (ACPI_FAILURE (Status))
24991116Smsmith        {
25091116Smsmith            return_ACPI_STATUS (Status);
25191116Smsmith        }
25267754Smsmith    }
25367754Smsmith
25491116Smsmith    /* Load the table into the namespace */
25567754Smsmith
256167802Sjkim    Status = AcpiExAddTable (TableIndex, ParentNode, &DdbHandle);
25791116Smsmith    if (ACPI_FAILURE (Status))
25891116Smsmith    {
25991116Smsmith        return_ACPI_STATUS (Status);
26091116Smsmith    }
26167754Smsmith
26291116Smsmith    /* Parameter Data (optional) */
26367754Smsmith
26491116Smsmith    if (ParameterNode)
26591116Smsmith    {
26691116Smsmith        /* Store the parameter data into the optional parameter object */
26767754Smsmith
268151937Sjkim        Status = AcpiExStore (Operand[5],
269306536Sjkim            ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParameterNode), WalkState);
27091116Smsmith        if (ACPI_FAILURE (Status))
27191116Smsmith        {
27299679Siwasaki            (void) AcpiExUnloadTable (DdbHandle);
273193267Sjkim
274193267Sjkim            AcpiUtRemoveReference (DdbHandle);
275123315Snjl            return_ACPI_STATUS (Status);
27691116Smsmith        }
27791116Smsmith    }
27891116Smsmith
279167802Sjkim    Status = AcpiGetTableByIndex (TableIndex, &Table);
280167802Sjkim    if (ACPI_SUCCESS (Status))
281167802Sjkim    {
282306536Sjkim        ACPI_INFO (("Dynamic OEM Table Load:"));
283207344Sjkim        AcpiTbPrintTableHeader (0, Table);
284167802Sjkim    }
285167802Sjkim
286193267Sjkim    /* Invoke table handler if present */
287193267Sjkim
288193267Sjkim    if (AcpiGbl_TableHandler)
289193267Sjkim    {
290193267Sjkim        (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_LOAD, Table,
291306536Sjkim            AcpiGbl_TableHandlerContext);
292193267Sjkim    }
293193267Sjkim
294123315Snjl    *ReturnDesc = DdbHandle;
295245582Sjkim    return_ACPI_STATUS (Status);
29691116Smsmith}
29791116Smsmith
29891116Smsmith
29991116Smsmith/*******************************************************************************
30091116Smsmith *
301193267Sjkim * FUNCTION:    AcpiExRegionRead
302193267Sjkim *
303193267Sjkim * PARAMETERS:  ObjDesc         - Region descriptor
304193267Sjkim *              Length          - Number of bytes to read
305193267Sjkim *              Buffer          - Pointer to where to put the data
306193267Sjkim *
307193267Sjkim * RETURN:      Status
308193267Sjkim *
309193267Sjkim * DESCRIPTION: Read data from an operation region. The read starts from the
310193267Sjkim *              beginning of the region.
311193267Sjkim *
312193267Sjkim ******************************************************************************/
313193267Sjkim
314193267Sjkimstatic ACPI_STATUS
315193267SjkimAcpiExRegionRead (
316193267Sjkim    ACPI_OPERAND_OBJECT     *ObjDesc,
317193267Sjkim    UINT32                  Length,
318193267Sjkim    UINT8                   *Buffer)
319193267Sjkim{
320193267Sjkim    ACPI_STATUS             Status;
321202771Sjkim    UINT64                  Value;
322193267Sjkim    UINT32                  RegionOffset = 0;
323193267Sjkim    UINT32                  i;
324193267Sjkim
325193267Sjkim
326193267Sjkim    /* Bytewise reads */
327193267Sjkim
328193267Sjkim    for (i = 0; i < Length; i++)
329193267Sjkim    {
330228110Sjkim        Status = AcpiEvAddressSpaceDispatch (ObjDesc, NULL, ACPI_READ,
331306536Sjkim            RegionOffset, 8, &Value);
332193267Sjkim        if (ACPI_FAILURE (Status))
333193267Sjkim        {
334193267Sjkim            return (Status);
335193267Sjkim        }
336193267Sjkim
337193267Sjkim        *Buffer = (UINT8) Value;
338193267Sjkim        Buffer++;
339193267Sjkim        RegionOffset++;
340193267Sjkim    }
341193267Sjkim
342193267Sjkim    return (AE_OK);
343193267Sjkim}
344193267Sjkim
345193267Sjkim
346193267Sjkim/*******************************************************************************
347193267Sjkim *
34891116Smsmith * FUNCTION:    AcpiExLoadOp
34991116Smsmith *
350167802Sjkim * PARAMETERS:  ObjDesc         - Region or Buffer/Field where the table will be
35191116Smsmith *                                obtained
35291116Smsmith *              Target          - Where a handle to the table will be stored
35391116Smsmith *              WalkState       - Current state
35491116Smsmith *
35591116Smsmith * RETURN:      Status
35691116Smsmith *
35791116Smsmith * DESCRIPTION: Load an ACPI table from a field or operation region
35891116Smsmith *
359167802Sjkim * NOTE: Region Fields (Field, BankField, IndexFields) are resolved to buffer
360167802Sjkim *       objects before this code is reached.
361167802Sjkim *
362167802Sjkim *       If source is an operation region, it must refer to SystemMemory, as
363167802Sjkim *       per the ACPI specification.
364167802Sjkim *
36591116Smsmith ******************************************************************************/
36691116Smsmith
36791116SmsmithACPI_STATUS
36891116SmsmithAcpiExLoadOp (
36991116Smsmith    ACPI_OPERAND_OBJECT     *ObjDesc,
37091116Smsmith    ACPI_OPERAND_OBJECT     *Target,
37191116Smsmith    ACPI_WALK_STATE         *WalkState)
37291116Smsmith{
373167802Sjkim    ACPI_OPERAND_OBJECT     *DdbHandle;
374281075Sdim    ACPI_TABLE_HEADER       *TableHeader;
375193267Sjkim    ACPI_TABLE_HEADER       *Table;
376193267Sjkim    UINT32                  TableIndex;
37791116Smsmith    ACPI_STATUS             Status;
378193267Sjkim    UINT32                  Length;
37991116Smsmith
38091116Smsmith
381167802Sjkim    ACPI_FUNCTION_TRACE (ExLoadOp);
38291116Smsmith
38391116Smsmith
384167802Sjkim    /* Source Object can be either an OpRegion or a Buffer/Field */
385167802Sjkim
386193267Sjkim    switch (ObjDesc->Common.Type)
38767754Smsmith    {
38891116Smsmith    case ACPI_TYPE_REGION:
38991116Smsmith
390193267Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
391193267Sjkim            "Load table from Region %p\n", ObjDesc));
392193267Sjkim
393167802Sjkim        /* Region must be SystemMemory (from ACPI spec) */
394167802Sjkim
395167802Sjkim        if (ObjDesc->Region.SpaceId != ACPI_ADR_SPACE_SYSTEM_MEMORY)
396167802Sjkim        {
397167802Sjkim            return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
398167802Sjkim        }
399167802Sjkim
400129684Snjl        /*
401306536Sjkim         * If the Region Address and Length have not been previously
402306536Sjkim         * evaluated, evaluate them now and save the results.
403129684Snjl         */
404129684Snjl        if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
405129684Snjl        {
406129684Snjl            Status = AcpiDsGetRegionArguments (ObjDesc);
407129684Snjl            if (ACPI_FAILURE (Status))
408129684Snjl            {
409129684Snjl                return_ACPI_STATUS (Status);
410129684Snjl            }
411129684Snjl        }
41291116Smsmith
413193267Sjkim        /* Get the table header first so we can get the table length */
414193267Sjkim
415281075Sdim        TableHeader = ACPI_ALLOCATE (sizeof (ACPI_TABLE_HEADER));
416281075Sdim        if (!TableHeader)
417193267Sjkim        {
418193267Sjkim            return_ACPI_STATUS (AE_NO_MEMORY);
419193267Sjkim        }
420193267Sjkim
421193267Sjkim        Status = AcpiExRegionRead (ObjDesc, sizeof (ACPI_TABLE_HEADER),
422306536Sjkim            ACPI_CAST_PTR (UINT8, TableHeader));
423281075Sdim        Length = TableHeader->Length;
424281075Sdim        ACPI_FREE (TableHeader);
425193267Sjkim
426193267Sjkim        if (ACPI_FAILURE (Status))
427193267Sjkim        {
428193267Sjkim            return_ACPI_STATUS (Status);
429193267Sjkim        }
430193267Sjkim
431193267Sjkim        /* Must have at least an ACPI table header */
432193267Sjkim
433193267Sjkim        if (Length < sizeof (ACPI_TABLE_HEADER))
434193267Sjkim        {
435193267Sjkim            return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
436193267Sjkim        }
437193267Sjkim
438193267Sjkim        /*
439193267Sjkim         * The original implementation simply mapped the table, with no copy.
440193267Sjkim         * However, the memory region is not guaranteed to remain stable and
441193267Sjkim         * we must copy the table to a local buffer. For example, the memory
442193267Sjkim         * region is corrupted after suspend on some machines. Dynamically
443193267Sjkim         * loaded tables are usually small, so this overhead is minimal.
444193267Sjkim         *
445193267Sjkim         * The latest implementation (5/2009) does not use a mapping at all.
446193267Sjkim         * We use the low-level operation region interface to read the table
447193267Sjkim         * instead of the obvious optimization of using a direct mapping.
448193267Sjkim         * This maintains a consistent use of operation regions across the
449193267Sjkim         * entire subsystem. This is important if additional processing must
450193267Sjkim         * be performed in the (possibly user-installed) operation region
451193267Sjkim         * handler. For example, AcpiExec and ASLTS depend on this.
452193267Sjkim         */
453193267Sjkim
454193267Sjkim        /* Allocate a buffer for the table */
455193267Sjkim
456281075Sdim        Table = ACPI_ALLOCATE (Length);
457281075Sdim        if (!Table)
458193267Sjkim        {
459193267Sjkim            return_ACPI_STATUS (AE_NO_MEMORY);
460193267Sjkim        }
461193267Sjkim
462193267Sjkim        /* Read the entire table */
463193267Sjkim
464193267Sjkim        Status = AcpiExRegionRead (ObjDesc, Length,
465306536Sjkim            ACPI_CAST_PTR (UINT8, Table));
466193267Sjkim        if (ACPI_FAILURE (Status))
467193267Sjkim        {
468281075Sdim            ACPI_FREE (Table);
469193267Sjkim            return_ACPI_STATUS (Status);
470193267Sjkim        }
47191116Smsmith        break;
47291116Smsmith
473167802Sjkim    case ACPI_TYPE_BUFFER: /* Buffer or resolved RegionField */
47491116Smsmith
475193267Sjkim        ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
476193267Sjkim            "Load table from Buffer or Field %p\n", ObjDesc));
47791116Smsmith
478193267Sjkim        /* Must have at least an ACPI table header */
47991116Smsmith
480193267Sjkim        if (ObjDesc->Buffer.Length < sizeof (ACPI_TABLE_HEADER))
481193267Sjkim        {
482193267Sjkim            return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
483193267Sjkim        }
48491116Smsmith
485193267Sjkim        /* Get the actual table length from the table header */
486193267Sjkim
487306536Sjkim        TableHeader = ACPI_CAST_PTR (
488306536Sjkim            ACPI_TABLE_HEADER, ObjDesc->Buffer.Pointer);
489281075Sdim        Length = TableHeader->Length;
490193267Sjkim
491193267Sjkim        /* Table cannot extend beyond the buffer */
492193267Sjkim
493193267Sjkim        if (Length > ObjDesc->Buffer.Length)
494193267Sjkim        {
495193267Sjkim            return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
496193267Sjkim        }
497193267Sjkim        if (Length < sizeof (ACPI_TABLE_HEADER))
498193267Sjkim        {
499193267Sjkim            return_ACPI_STATUS (AE_INVALID_TABLE_LENGTH);
500193267Sjkim        }
501193267Sjkim
502193267Sjkim        /*
503306536Sjkim         * Copy the table from the buffer because the buffer could be
504306536Sjkim         * modified or even deleted in the future
505193267Sjkim         */
506281075Sdim        Table = ACPI_ALLOCATE (Length);
507281075Sdim        if (!Table)
508193267Sjkim        {
509193267Sjkim            return_ACPI_STATUS (AE_NO_MEMORY);
510193267Sjkim        }
511193267Sjkim
512306536Sjkim        memcpy (Table, TableHeader, Length);
51391116Smsmith        break;
51491116Smsmith
515250838Sjkim    default:
516193267Sjkim
51791116Smsmith        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
51867754Smsmith    }
51967754Smsmith
520281075Sdim    /* Install the new table into the local data structures */
521193267Sjkim
522306536Sjkim    ACPI_INFO (("Dynamic OEM Table Load:"));
523281075Sdim    (void) AcpiUtAcquireMutex (ACPI_MTX_TABLES);
524281075Sdim
525281075Sdim    Status = AcpiTbInstallStandardTable (ACPI_PTR_TO_PHYSADDR (Table),
526306536Sjkim        ACPI_TABLE_ORIGIN_INTERNAL_VIRTUAL, TRUE, TRUE,
527306536Sjkim        &TableIndex);
528281075Sdim
529281075Sdim    (void) AcpiUtReleaseMutex (ACPI_MTX_TABLES);
530193267Sjkim    if (ACPI_FAILURE (Status))
531193267Sjkim    {
532281075Sdim        /* Delete allocated table buffer */
533281075Sdim
534281075Sdim        ACPI_FREE (Table);
535193267Sjkim        return_ACPI_STATUS (Status);
536193267Sjkim    }
537193267Sjkim
538281075Sdim    /*
539281075Sdim     * Note: Now table is "INSTALLED", it must be validated before
540281075Sdim     * loading.
541281075Sdim     */
542306536Sjkim    Status = AcpiTbValidateTable (
543306536Sjkim        &AcpiGbl_RootTableList.Tables[TableIndex]);
544167802Sjkim    if (ACPI_FAILURE (Status))
54567754Smsmith    {
546202771Sjkim        return_ACPI_STATUS (Status);
54767754Smsmith    }
54867754Smsmith
549193267Sjkim    /*
550193267Sjkim     * Add the table to the namespace.
551193267Sjkim     *
552193267Sjkim     * Note: Load the table objects relative to the root of the namespace.
553193267Sjkim     * This appears to go against the ACPI specification, but we do it for
554193267Sjkim     * compatibility with other ACPI implementations.
555193267Sjkim     */
556167802Sjkim    Status = AcpiExAddTable (TableIndex, AcpiGbl_RootNode, &DdbHandle);
55767754Smsmith    if (ACPI_FAILURE (Status))
55867754Smsmith    {
559151937Sjkim        /* On error, TablePtr was deallocated above */
560151937Sjkim
561151937Sjkim        return_ACPI_STATUS (Status);
56267754Smsmith    }
56367754Smsmith
56491116Smsmith    /* Store the DdbHandle into the Target operand */
56567754Smsmith
56691116Smsmith    Status = AcpiExStore (DdbHandle, Target, WalkState);
56767754Smsmith    if (ACPI_FAILURE (Status))
56867754Smsmith    {
56999679Siwasaki        (void) AcpiExUnloadTable (DdbHandle);
57067754Smsmith
571151937Sjkim        /* TablePtr was deallocated above */
57267754Smsmith
573193267Sjkim        AcpiUtRemoveReference (DdbHandle);
574151937Sjkim        return_ACPI_STATUS (Status);
575151937Sjkim    }
57667754Smsmith
577193267Sjkim    /* Remove the reference by added by AcpiExStore above */
578193267Sjkim
579193267Sjkim    AcpiUtRemoveReference (DdbHandle);
580193267Sjkim
581193267Sjkim    /* Invoke table handler if present */
582193267Sjkim
583193267Sjkim    if (AcpiGbl_TableHandler)
584193267Sjkim    {
585281075Sdim        (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_LOAD, Table,
586306536Sjkim            AcpiGbl_TableHandlerContext);
587193267Sjkim    }
588193267Sjkim
58967754Smsmith    return_ACPI_STATUS (Status);
59067754Smsmith}
59167754Smsmith
59267754Smsmith
59391116Smsmith/*******************************************************************************
59467754Smsmith *
59577424Smsmith * FUNCTION:    AcpiExUnloadTable
59667754Smsmith *
59767754Smsmith * PARAMETERS:  DdbHandle           - Handle to a previously loaded table
59867754Smsmith *
59967754Smsmith * RETURN:      Status
60067754Smsmith *
60167754Smsmith * DESCRIPTION: Unload an ACPI table
60267754Smsmith *
60391116Smsmith ******************************************************************************/
60467754Smsmith
60585756SmsmithACPI_STATUS
60677424SmsmithAcpiExUnloadTable (
60783174Smsmith    ACPI_OPERAND_OBJECT     *DdbHandle)
60867754Smsmith{
609123315Snjl    ACPI_STATUS             Status = AE_OK;
61083174Smsmith    ACPI_OPERAND_OBJECT     *TableDesc = DdbHandle;
611193267Sjkim    UINT32                  TableIndex;
612193267Sjkim    ACPI_TABLE_HEADER       *Table;
61367754Smsmith
61467754Smsmith
615167802Sjkim    ACPI_FUNCTION_TRACE (ExUnloadTable);
61667754Smsmith
61767754Smsmith
61883174Smsmith    /*
619281075Sdim     * Temporarily emit a warning so that the ASL for the machine can be
620281075Sdim     * hopefully obtained. This is to say that the Unload() operator is
621281075Sdim     * extremely rare if not completely unused.
622281075Sdim     */
623281075Sdim    ACPI_WARNING ((AE_INFO,
624281075Sdim        "Received request to unload an ACPI table"));
625281075Sdim
626281075Sdim    /*
62783174Smsmith     * Validate the handle
628193267Sjkim     * Although the handle is partially validated in AcpiExReconfiguration()
62983174Smsmith     * when it calls AcpiExResolveOperands(), the handle is more completely
63083174Smsmith     * validated here.
631193267Sjkim     *
632193267Sjkim     * Handle must be a valid operand object of type reference. Also, the
633193267Sjkim     * DdbHandle must still be marked valid (table has not been previously
634193267Sjkim     * unloaded)
63567754Smsmith     */
63667754Smsmith    if ((!DdbHandle) ||
63799679Siwasaki        (ACPI_GET_DESCRIPTOR_TYPE (DdbHandle) != ACPI_DESC_TYPE_OPERAND) ||
638193267Sjkim        (DdbHandle->Common.Type != ACPI_TYPE_LOCAL_REFERENCE) ||
639193267Sjkim        (!(DdbHandle->Common.Flags & AOPOBJ_DATA_VALID)))
64067754Smsmith    {
641249663Sjkim        return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
64267754Smsmith    }
64367754Smsmith
644167802Sjkim    /* Get the table index from the DdbHandle */
64567754Smsmith
646193267Sjkim    TableIndex = TableDesc->Reference.Value;
64767754Smsmith
648193267Sjkim    /* Ensure the table is still loaded */
64967754Smsmith
650193267Sjkim    if (!AcpiTbIsTableLoaded (TableIndex))
651193267Sjkim    {
652193267Sjkim        return_ACPI_STATUS (AE_NOT_EXIST);
653193267Sjkim    }
654193267Sjkim
655193267Sjkim    /* Invoke table handler if present */
656193267Sjkim
657193267Sjkim    if (AcpiGbl_TableHandler)
658193267Sjkim    {
659193267Sjkim        Status = AcpiGetTableByIndex (TableIndex, &Table);
660193267Sjkim        if (ACPI_SUCCESS (Status))
661193267Sjkim        {
662193267Sjkim            (void) AcpiGbl_TableHandler (ACPI_TABLE_EVENT_UNLOAD, Table,
663306536Sjkim                AcpiGbl_TableHandlerContext);
664193267Sjkim        }
665193267Sjkim    }
666193267Sjkim
667193267Sjkim    /* Delete the portion of the namespace owned by this table */
668193267Sjkim
669193267Sjkim    Status = AcpiTbDeleteNamespaceByOwner (TableIndex);
670193267Sjkim    if (ACPI_FAILURE (Status))
671193267Sjkim    {
672193267Sjkim        return_ACPI_STATUS (Status);
673193267Sjkim    }
674193267Sjkim
675193267Sjkim    (void) AcpiTbReleaseOwnerId (TableIndex);
676167802Sjkim    AcpiTbSetTableLoadedFlag (TableIndex, FALSE);
67767754Smsmith
678193267Sjkim    /*
679193267Sjkim     * Invalidate the handle. We do this because the handle may be stored
680193267Sjkim     * in a named object and may not be actually deleted until much later.
681193267Sjkim     */
682193267Sjkim    DdbHandle->Common.Flags &= ~AOPOBJ_DATA_VALID;
683193267Sjkim    return_ACPI_STATUS (AE_OK);
68467754Smsmith}
685