xref: /titanic_50/usr/src/uts/intel/io/acpica/executer/exconfig.c (revision 356f72340a69936724c69f2f87fffa6f5887f885)
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 "acpi.h"
45 #include "accommon.h"
46 #include "acinterp.h"
47 #include "acnamesp.h"
48 #include "actables.h"
49 #include "acdispat.h"
50 #include "acevents.h"
51 #include "amlcode.h"
52 
53 
54 #define _COMPONENT          ACPI_EXECUTER
55         ACPI_MODULE_NAME    ("exconfig")
56 
57 /* Local prototypes */
58 
59 static ACPI_STATUS
60 AcpiExAddTable (
61     UINT32                  TableIndex,
62     ACPI_NAMESPACE_NODE     *ParentNode,
63     ACPI_OPERAND_OBJECT     **DdbHandle);
64 
65 static ACPI_STATUS
66 AcpiExRegionRead (
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 
87 static ACPI_STATUS
88 AcpiExAddTable (
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 
166 ACPI_STATUS
167 AcpiExLoadTableOp (
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 
314 static ACPI_STATUS
315 AcpiExRegionRead (
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 
367 ACPI_STATUS
368 AcpiExLoadOp (
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 
605 ACPI_STATUS
606 AcpiExUnloadTable (
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