xref: /netbsd-src/sys/external/bsd/acpica/dist/dispatcher/dsobject.c (revision bdc22b2e01993381dcefeff2bc9b56ca75a4235c)
1 /******************************************************************************
2  *
3  * Module Name: dsobject - Dispatcher object management routines
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2018, 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 "acparser.h"
47 #include "amlcode.h"
48 #include "acdispat.h"
49 #include "acnamesp.h"
50 #include "acinterp.h"
51 
52 #define _COMPONENT          ACPI_DISPATCHER
53         ACPI_MODULE_NAME    ("dsobject")
54 
55 
56 #ifndef ACPI_NO_METHOD_EXECUTION
57 /*******************************************************************************
58  *
59  * FUNCTION:    AcpiDsBuildInternalObject
60  *
61  * PARAMETERS:  WalkState       - Current walk state
62  *              Op              - Parser object to be translated
63  *              ObjDescPtr      - Where the ACPI internal object is returned
64  *
65  * RETURN:      Status
66  *
67  * DESCRIPTION: Translate a parser Op object to the equivalent namespace object
68  *              Simple objects are any objects other than a package object!
69  *
70  ******************************************************************************/
71 
72 ACPI_STATUS
73 AcpiDsBuildInternalObject (
74     ACPI_WALK_STATE         *WalkState,
75     ACPI_PARSE_OBJECT       *Op,
76     ACPI_OPERAND_OBJECT     **ObjDescPtr)
77 {
78     ACPI_OPERAND_OBJECT     *ObjDesc;
79     ACPI_STATUS             Status;
80 
81 
82     ACPI_FUNCTION_TRACE (DsBuildInternalObject);
83 
84 
85     *ObjDescPtr = NULL;
86     if (Op->Common.AmlOpcode == AML_INT_NAMEPATH_OP)
87     {
88         /*
89          * This is a named object reference. If this name was
90          * previously looked up in the namespace, it was stored in
91          * this op. Otherwise, go ahead and look it up now
92          */
93         if (!Op->Common.Node)
94         {
95             /* Check if we are resolving a named reference within a package */
96 
97             if ((Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) ||
98                 (Op->Common.Parent->Common.AmlOpcode == AML_VARIABLE_PACKAGE_OP))
99             {
100                 /*
101                  * We won't resolve package elements here, we will do this
102                  * after all ACPI tables are loaded into the namespace. This
103                  * behavior supports both forward references to named objects
104                  * and external references to objects in other tables.
105                  */
106                 goto CreateNewObject;
107             }
108             else
109             {
110                 Status = AcpiNsLookup (WalkState->ScopeInfo,
111                     Op->Common.Value.String,
112                     ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
113                     ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL,
114                     ACPI_CAST_INDIRECT_PTR (
115                         ACPI_NAMESPACE_NODE, &(Op->Common.Node)));
116                 if (ACPI_FAILURE (Status))
117                 {
118                     ACPI_ERROR_NAMESPACE (WalkState->ScopeInfo,
119                         Op->Common.Value.String, Status);
120                     return_ACPI_STATUS (Status);
121                 }
122             }
123         }
124     }
125 
126 CreateNewObject:
127 
128     /* Create and init a new internal ACPI object */
129 
130     ObjDesc = AcpiUtCreateInternalObject (
131         (AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode))->ObjectType);
132     if (!ObjDesc)
133     {
134         return_ACPI_STATUS (AE_NO_MEMORY);
135     }
136 
137     Status = AcpiDsInitObjectFromOp (
138         WalkState, Op, Op->Common.AmlOpcode, &ObjDesc);
139     if (ACPI_FAILURE (Status))
140     {
141         AcpiUtRemoveReference (ObjDesc);
142         return_ACPI_STATUS (Status);
143     }
144 
145     /*
146      * Handling for unresolved package reference elements.
147      * These are elements that are namepaths.
148      */
149     if ((Op->Common.Parent->Common.AmlOpcode == AML_PACKAGE_OP) ||
150         (Op->Common.Parent->Common.AmlOpcode == AML_VARIABLE_PACKAGE_OP))
151     {
152         ObjDesc->Reference.Resolved = TRUE;
153 
154         if ((Op->Common.AmlOpcode == AML_INT_NAMEPATH_OP) &&
155             !ObjDesc->Reference.Node)
156         {
157             /*
158              * Name was unresolved above.
159              * Get the prefix node for later lookup
160              */
161             ObjDesc->Reference.Node = WalkState->ScopeInfo->Scope.Node;
162             ObjDesc->Reference.Aml = Op->Common.Aml;
163             ObjDesc->Reference.Resolved = FALSE;
164         }
165     }
166 
167     *ObjDescPtr = ObjDesc;
168     return_ACPI_STATUS (Status);
169 }
170 
171 
172 /*******************************************************************************
173  *
174  * FUNCTION:    AcpiDsBuildInternalBufferObj
175  *
176  * PARAMETERS:  WalkState       - Current walk state
177  *              Op              - Parser object to be translated
178  *              BufferLength    - Length of the buffer
179  *              ObjDescPtr      - Where the ACPI internal object is returned
180  *
181  * RETURN:      Status
182  *
183  * DESCRIPTION: Translate a parser Op package object to the equivalent
184  *              namespace object
185  *
186  ******************************************************************************/
187 
188 ACPI_STATUS
189 AcpiDsBuildInternalBufferObj (
190     ACPI_WALK_STATE         *WalkState,
191     ACPI_PARSE_OBJECT       *Op,
192     UINT32                  BufferLength,
193     ACPI_OPERAND_OBJECT     **ObjDescPtr)
194 {
195     ACPI_PARSE_OBJECT       *Arg;
196     ACPI_OPERAND_OBJECT     *ObjDesc;
197     ACPI_PARSE_OBJECT       *ByteList;
198     UINT32                  ByteListLength = 0;
199 
200 
201     ACPI_FUNCTION_TRACE (DsBuildInternalBufferObj);
202 
203 
204     /*
205      * If we are evaluating a Named buffer object "Name (xxxx, Buffer)".
206      * The buffer object already exists (from the NS node), otherwise it must
207      * be created.
208      */
209     ObjDesc = *ObjDescPtr;
210     if (!ObjDesc)
211     {
212         /* Create a new buffer object */
213 
214         ObjDesc = AcpiUtCreateInternalObject (ACPI_TYPE_BUFFER);
215         *ObjDescPtr = ObjDesc;
216         if (!ObjDesc)
217         {
218             return_ACPI_STATUS (AE_NO_MEMORY);
219         }
220     }
221 
222     /*
223      * Second arg is the buffer data (optional) ByteList can be either
224      * individual bytes or a string initializer. In either case, a
225      * ByteList appears in the AML.
226      */
227     Arg = Op->Common.Value.Arg;         /* skip first arg */
228 
229     ByteList = Arg->Named.Next;
230     if (ByteList)
231     {
232         if (ByteList->Common.AmlOpcode != AML_INT_BYTELIST_OP)
233         {
234             ACPI_ERROR ((AE_INFO,
235                 "Expecting bytelist, found AML opcode 0x%X in op %p",
236                 ByteList->Common.AmlOpcode, ByteList));
237 
238             AcpiUtRemoveReference (ObjDesc);
239             return (AE_TYPE);
240         }
241 
242         ByteListLength = (UINT32) ByteList->Common.Value.Integer;
243     }
244 
245     /*
246      * The buffer length (number of bytes) will be the larger of:
247      * 1) The specified buffer length and
248      * 2) The length of the initializer byte list
249      */
250     ObjDesc->Buffer.Length = BufferLength;
251     if (ByteListLength > BufferLength)
252     {
253         ObjDesc->Buffer.Length = ByteListLength;
254     }
255 
256     /* Allocate the buffer */
257 
258     if (ObjDesc->Buffer.Length == 0)
259     {
260         ObjDesc->Buffer.Pointer = NULL;
261         ACPI_DEBUG_PRINT ((ACPI_DB_EXEC,
262             "Buffer defined with zero length in AML, creating\n"));
263     }
264     else
265     {
266         ObjDesc->Buffer.Pointer =
267             ACPI_ALLOCATE_ZEROED (ObjDesc->Buffer.Length);
268         if (!ObjDesc->Buffer.Pointer)
269         {
270             AcpiUtDeleteObjectDesc (ObjDesc);
271             return_ACPI_STATUS (AE_NO_MEMORY);
272         }
273 
274         /* Initialize buffer from the ByteList (if present) */
275 
276         if (ByteList)
277         {
278             memcpy (ObjDesc->Buffer.Pointer, ByteList->Named.Data,
279                 ByteListLength);
280         }
281     }
282 
283     ObjDesc->Buffer.Flags |= AOPOBJ_DATA_VALID;
284     Op->Common.Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, ObjDesc);
285     return_ACPI_STATUS (AE_OK);
286 }
287 
288 /*******************************************************************************
289  *
290  * FUNCTION:    AcpiDsCreateNode
291  *
292  * PARAMETERS:  WalkState       - Current walk state
293  *              Node            - NS Node to be initialized
294  *              Op              - Parser object to be translated
295  *
296  * RETURN:      Status
297  *
298  * DESCRIPTION: Create the object to be associated with a namespace node
299  *
300  ******************************************************************************/
301 
302 ACPI_STATUS
303 AcpiDsCreateNode (
304     ACPI_WALK_STATE         *WalkState,
305     ACPI_NAMESPACE_NODE     *Node,
306     ACPI_PARSE_OBJECT       *Op)
307 {
308     ACPI_STATUS             Status;
309     ACPI_OPERAND_OBJECT     *ObjDesc;
310 
311 
312     ACPI_FUNCTION_TRACE_PTR (DsCreateNode, Op);
313 
314 
315     /*
316      * Because of the execution pass through the non-control-method
317      * parts of the table, we can arrive here twice. Only init
318      * the named object node the first time through
319      */
320     if (AcpiNsGetAttachedObject (Node))
321     {
322         return_ACPI_STATUS (AE_OK);
323     }
324 
325     if (!Op->Common.Value.Arg)
326     {
327         /* No arguments, there is nothing to do */
328 
329         return_ACPI_STATUS (AE_OK);
330     }
331 
332     /* Build an internal object for the argument(s) */
333 
334     Status = AcpiDsBuildInternalObject (
335         WalkState, Op->Common.Value.Arg, &ObjDesc);
336     if (ACPI_FAILURE (Status))
337     {
338         return_ACPI_STATUS (Status);
339     }
340 
341     /* Re-type the object according to its argument */
342 
343     Node->Type = ObjDesc->Common.Type;
344 
345     /* Attach obj to node */
346 
347     Status = AcpiNsAttachObject (Node, ObjDesc, Node->Type);
348 
349     /* Remove local reference to the object */
350 
351     AcpiUtRemoveReference (ObjDesc);
352     return_ACPI_STATUS (Status);
353 }
354 
355 #endif /* ACPI_NO_METHOD_EXECUTION */
356 
357 
358 /*******************************************************************************
359  *
360  * FUNCTION:    AcpiDsInitObjectFromOp
361  *
362  * PARAMETERS:  WalkState       - Current walk state
363  *              Op              - Parser op used to init the internal object
364  *              Opcode          - AML opcode associated with the object
365  *              RetObjDesc      - Namespace object to be initialized
366  *
367  * RETURN:      Status
368  *
369  * DESCRIPTION: Initialize a namespace object from a parser Op and its
370  *              associated arguments. The namespace object is a more compact
371  *              representation of the Op and its arguments.
372  *
373  ******************************************************************************/
374 
375 ACPI_STATUS
376 AcpiDsInitObjectFromOp (
377     ACPI_WALK_STATE         *WalkState,
378     ACPI_PARSE_OBJECT       *Op,
379     UINT16                  Opcode,
380     ACPI_OPERAND_OBJECT     **RetObjDesc)
381 {
382     const ACPI_OPCODE_INFO  *OpInfo;
383     ACPI_OPERAND_OBJECT     *ObjDesc;
384     ACPI_STATUS             Status = AE_OK;
385 
386 
387     ACPI_FUNCTION_TRACE (DsInitObjectFromOp);
388 
389 
390     ObjDesc = *RetObjDesc;
391     OpInfo = AcpiPsGetOpcodeInfo (Opcode);
392     if (OpInfo->Class == AML_CLASS_UNKNOWN)
393     {
394         /* Unknown opcode */
395 
396         return_ACPI_STATUS (AE_TYPE);
397     }
398 
399     /* Perform per-object initialization */
400 
401     switch (ObjDesc->Common.Type)
402     {
403     case ACPI_TYPE_BUFFER:
404         /*
405          * Defer evaluation of Buffer TermArg operand
406          */
407         ObjDesc->Buffer.Node = ACPI_CAST_PTR (
408             ACPI_NAMESPACE_NODE, WalkState->Operands[0]);
409         ObjDesc->Buffer.AmlStart = Op->Named.Data;
410         ObjDesc->Buffer.AmlLength = Op->Named.Length;
411         break;
412 
413     case ACPI_TYPE_PACKAGE:
414         /*
415          * Defer evaluation of Package TermArg operand and all
416          * package elements. (01/2017): We defer the element
417          * resolution to allow forward references from the package
418          * in order to provide compatibility with other ACPI
419          * implementations.
420          */
421         ObjDesc->Package.Node = ACPI_CAST_PTR (
422             ACPI_NAMESPACE_NODE, WalkState->Operands[0]);
423 
424         if (!Op->Named.Data)
425         {
426             return_ACPI_STATUS (AE_OK);
427         }
428 
429         ObjDesc->Package.AmlStart = Op->Named.Data;
430         ObjDesc->Package.AmlLength = Op->Named.Length;
431         break;
432 
433     case ACPI_TYPE_INTEGER:
434 
435         switch (OpInfo->Type)
436         {
437         case AML_TYPE_CONSTANT:
438             /*
439              * Resolve AML Constants here - AND ONLY HERE!
440              * All constants are integers.
441              * We mark the integer with a flag that indicates that it started
442              * life as a constant -- so that stores to constants will perform
443              * as expected (noop). ZeroOp is used as a placeholder for optional
444              * target operands.
445              */
446             ObjDesc->Common.Flags = AOPOBJ_AML_CONSTANT;
447 
448             switch (Opcode)
449             {
450             case AML_ZERO_OP:
451 
452                 ObjDesc->Integer.Value = 0;
453                 break;
454 
455             case AML_ONE_OP:
456 
457                 ObjDesc->Integer.Value = 1;
458                 break;
459 
460             case AML_ONES_OP:
461 
462                 ObjDesc->Integer.Value = ACPI_UINT64_MAX;
463 
464                 /* Truncate value if we are executing from a 32-bit ACPI table */
465 
466 #ifndef ACPI_NO_METHOD_EXECUTION
467                 (void) AcpiExTruncateFor32bitTable (ObjDesc);
468 #endif
469                 break;
470 
471             case AML_REVISION_OP:
472 
473                 ObjDesc->Integer.Value = ACPI_CA_VERSION;
474                 break;
475 
476             default:
477 
478                 ACPI_ERROR ((AE_INFO,
479                     "Unknown constant opcode 0x%X", Opcode));
480                 Status = AE_AML_OPERAND_TYPE;
481                 break;
482             }
483             break;
484 
485         case AML_TYPE_LITERAL:
486 
487             ObjDesc->Integer.Value = Op->Common.Value.Integer;
488 
489 #ifndef ACPI_NO_METHOD_EXECUTION
490             if (AcpiExTruncateFor32bitTable (ObjDesc))
491             {
492                 /* Warn if we found a 64-bit constant in a 32-bit table */
493 
494                 ACPI_WARNING ((AE_INFO,
495                     "Truncated 64-bit constant found in 32-bit table: %8.8X%8.8X => %8.8X",
496                     ACPI_FORMAT_UINT64 (Op->Common.Value.Integer),
497                     (UINT32) ObjDesc->Integer.Value));
498             }
499 #endif
500             break;
501 
502         default:
503 
504             ACPI_ERROR ((AE_INFO, "Unknown Integer type 0x%X",
505                 OpInfo->Type));
506             Status = AE_AML_OPERAND_TYPE;
507             break;
508         }
509         break;
510 
511     case ACPI_TYPE_STRING:
512 
513         ObjDesc->String.Pointer = Op->Common.Value.String;
514         ObjDesc->String.Length = (UINT32) strlen (Op->Common.Value.String);
515 
516         /*
517          * The string is contained in the ACPI table, don't ever try
518          * to delete it
519          */
520         ObjDesc->Common.Flags |= AOPOBJ_STATIC_POINTER;
521         break;
522 
523     case ACPI_TYPE_METHOD:
524         break;
525 
526     case ACPI_TYPE_LOCAL_REFERENCE:
527 
528         switch (OpInfo->Type)
529         {
530         case AML_TYPE_LOCAL_VARIABLE:
531 
532             /* Local ID (0-7) is (AML opcode - base AML_FIRST_LOCAL_OP) */
533 
534             ObjDesc->Reference.Value = ((UINT32) Opcode) - AML_FIRST_LOCAL_OP;
535             ObjDesc->Reference.Class = ACPI_REFCLASS_LOCAL;
536 
537 #ifndef ACPI_NO_METHOD_EXECUTION
538             Status = AcpiDsMethodDataGetNode (ACPI_REFCLASS_LOCAL,
539                 ObjDesc->Reference.Value, WalkState,
540                 ACPI_CAST_INDIRECT_PTR (ACPI_NAMESPACE_NODE,
541                     &ObjDesc->Reference.Object));
542 #endif
543             break;
544 
545         case AML_TYPE_METHOD_ARGUMENT:
546 
547             /* Arg ID (0-6) is (AML opcode - base AML_FIRST_ARG_OP) */
548 
549             ObjDesc->Reference.Value = ((UINT32) Opcode) - AML_FIRST_ARG_OP;
550             ObjDesc->Reference.Class = ACPI_REFCLASS_ARG;
551 
552 #ifndef ACPI_NO_METHOD_EXECUTION
553             Status = AcpiDsMethodDataGetNode (ACPI_REFCLASS_ARG,
554                 ObjDesc->Reference.Value, WalkState,
555                 ACPI_CAST_INDIRECT_PTR (ACPI_NAMESPACE_NODE,
556                     &ObjDesc->Reference.Object));
557 #endif
558             break;
559 
560         default: /* Object name or Debug object */
561 
562             switch (Op->Common.AmlOpcode)
563             {
564             case AML_INT_NAMEPATH_OP:
565 
566                 /* Node was saved in Op */
567 
568                 ObjDesc->Reference.Node = Op->Common.Node;
569                 ObjDesc->Reference.Class = ACPI_REFCLASS_NAME;
570                 if (Op->Common.Node)
571                 {
572                     ObjDesc->Reference.Object = Op->Common.Node->Object;
573                 }
574                 break;
575 
576             case AML_DEBUG_OP:
577 
578                 ObjDesc->Reference.Class = ACPI_REFCLASS_DEBUG;
579                 break;
580 
581             default:
582 
583                 ACPI_ERROR ((AE_INFO,
584                     "Unimplemented reference type for AML opcode: 0x%4.4X", Opcode));
585                 return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
586             }
587             break;
588         }
589         break;
590 
591     default:
592 
593         ACPI_ERROR ((AE_INFO, "Unimplemented data type: 0x%X",
594             ObjDesc->Common.Type));
595 
596         Status = AE_AML_OPERAND_TYPE;
597         break;
598     }
599 
600     return_ACPI_STATUS (Status);
601 }
602