xref: /netbsd-src/sys/external/bsd/acpica/dist/compiler/asloffset.c (revision 046a29855e04359424fd074e8313af6b6be8cfb6)
1 /******************************************************************************
2  *
3  * Module Name: asloffset - Generate a C "offset table" for BIOS use.
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2023, 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 MERCHANTABILITY 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 "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #include "amlcode.h"
47 #include "acnamesp.h"
48 
49 
50 #define _COMPONENT          ACPI_COMPILER
51         ACPI_MODULE_NAME    ("asloffset")
52 
53 
54 /* Local prototypes */
55 
56 static void
57 LsEmitOffsetTableEntry (
58     UINT32                  FileId,
59     ACPI_NAMESPACE_NODE     *Node,
60     UINT32                  NamepathOffset,
61     UINT32                  Offset,
62     char                    *OpName,
63     UINT64                  Value,
64     UINT8                   AmlOpcode,
65     UINT16                  ParentOpcode);
66 
67 
68 /*******************************************************************************
69  *
70  * FUNCTION:    LsAmlOffsetWalk
71  *
72  * PARAMETERS:  ASL_WALK_CALLBACK
73  *
74  * RETURN:      Status
75  *
76  * DESCRIPTION: Process one node during a offset table file generation.
77  *
78  * Three types of objects are currently emitted to the offset table:
79  *   1) Tagged (named) resource descriptors
80  *   2) Named integer objects with constant integer values
81  *   3) Named package objects
82  *   4) Operation Regions that have constant Offset (address) parameters
83  *   5) Control methods
84  *
85  * The offset table allows the BIOS to dynamically update the values of these
86  * objects at boot time.
87  *
88  ******************************************************************************/
89 
90 ACPI_STATUS
LsAmlOffsetWalk(ACPI_PARSE_OBJECT * Op,UINT32 Level,void * Context)91 LsAmlOffsetWalk (
92     ACPI_PARSE_OBJECT       *Op,
93     UINT32                  Level,
94     void                    *Context)
95 {
96     UINT32                  FileId = (UINT32) ACPI_TO_INTEGER (Context);
97     ACPI_NAMESPACE_NODE     *Node;
98     UINT32                  Length;
99     UINT32                  NamepathOffset;
100     UINT32                  DataOffset;
101     ACPI_PARSE_OBJECT       *NextOp;
102 
103 
104     /* Ignore actual data blocks for resource descriptors */
105 
106     if (Op->Asl.CompileFlags & OP_IS_RESOURCE_DATA)
107     {
108         return (AE_OK); /* Do NOT update the global AML offset */
109     }
110 
111     /* We are only interested in named objects (have a namespace node) */
112 
113     Node = Op->Asl.Node;
114     if (!Node)
115     {
116         AslGbl_CurrentAmlOffset += Op->Asl.FinalAmlLength;
117         return (AE_OK);
118     }
119 
120     /* Named resource descriptor (has a descriptor tag) */
121 
122     if ((Node->Type == ACPI_TYPE_LOCAL_RESOURCE) &&
123         (Op->Asl.CompileFlags & OP_IS_RESOURCE_DESC))
124     {
125         LsEmitOffsetTableEntry (FileId, Node, 0, AslGbl_CurrentAmlOffset,
126             Op->Asl.ParseOpName, 0, Op->Asl.Extra, AML_BUFFER_OP);
127 
128         AslGbl_CurrentAmlOffset += Op->Asl.FinalAmlLength;
129         return (AE_OK);
130     }
131 
132     switch (Op->Asl.AmlOpcode)
133     {
134     case AML_NAME_OP:
135 
136         /* Named object -- Name (NameString, DataRefObject) */
137 
138         if (!Op->Asl.Child)
139         {
140             FlPrintFile (FileId, "%s NO CHILD!\n", AslGbl_MsgBuffer);
141             return (AE_OK);
142         }
143 
144         Length = Op->Asl.FinalAmlLength;
145 
146         /* Get to the NameSeg/NamePath Op (and length of the name) */
147 
148         Op = Op->Asl.Child;
149 
150         /* Get offset of last nameseg and the actual data */
151 
152         NamepathOffset = AslGbl_CurrentAmlOffset + Length +
153             (Op->Asl.FinalAmlLength - ACPI_NAMESEG_SIZE);
154 
155         DataOffset = AslGbl_CurrentAmlOffset + Length +
156             Op->Asl.FinalAmlLength;
157 
158         /* Get actual value associated with the name */
159 
160         Op = Op->Asl.Next;
161         switch (Op->Asl.AmlOpcode)
162         {
163         case AML_BYTE_OP:
164         case AML_WORD_OP:
165         case AML_DWORD_OP:
166         case AML_QWORD_OP:
167 
168             /* The +1 is to handle the integer size prefix (opcode) */
169 
170             LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, (DataOffset + 1),
171                 Op->Asl.ParseOpName, Op->Asl.Value.Integer,
172                 (UINT8) Op->Asl.AmlOpcode, AML_NAME_OP);
173             break;
174 
175         case AML_ONE_OP:
176         case AML_ONES_OP:
177         case AML_ZERO_OP:
178 
179             /* For these, offset will point to the opcode */
180 
181             LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset,
182                 Op->Asl.ParseOpName, Op->Asl.Value.Integer,
183                 (UINT8) Op->Asl.AmlOpcode, AML_NAME_OP);
184             break;
185 
186         case AML_PACKAGE_OP:
187         case AML_VARIABLE_PACKAGE_OP:
188 
189             /* Get the package element count */
190 
191             NextOp = Op->Asl.Child;
192 
193             LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset,
194                 Op->Asl.ParseOpName, NextOp->Asl.Value.Integer,
195                 (UINT8) Op->Asl.AmlOpcode, AML_NAME_OP);
196             break;
197 
198          default:
199              break;
200         }
201 
202         AslGbl_CurrentAmlOffset += Length;
203         return (AE_OK);
204 
205     case AML_REGION_OP:
206 
207         /* OperationRegion (NameString, RegionSpace, RegionOffset, RegionLength) */
208 
209         Length = Op->Asl.FinalAmlLength;
210 
211         /* Get the name/namepath node */
212 
213         NextOp = Op->Asl.Child;
214 
215         /* Get offset of last nameseg and the actual data */
216 
217         NamepathOffset = AslGbl_CurrentAmlOffset + Length +
218             (NextOp->Asl.FinalAmlLength - ACPI_NAMESEG_SIZE);
219 
220         DataOffset = AslGbl_CurrentAmlOffset + Length +
221             (NextOp->Asl.FinalAmlLength + 1);
222 
223         /* Get the SpaceId node, then the Offset (address) node */
224 
225         NextOp = NextOp->Asl.Next;
226         NextOp = NextOp->Asl.Next;
227 
228         switch (NextOp->Asl.AmlOpcode)
229         {
230         /*
231          * We are only interested in integer constants that can be changed
232          * at boot time. Note, the One/Ones/Zero opcodes are considered
233          * non-changeable, so we ignore them here.
234          */
235         case AML_BYTE_OP:
236         case AML_WORD_OP:
237         case AML_DWORD_OP:
238         case AML_QWORD_OP:
239 
240             LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, (DataOffset + 1),
241                 Op->Asl.ParseOpName, NextOp->Asl.Value.Integer,
242                 (UINT8) NextOp->Asl.AmlOpcode, AML_REGION_OP);
243 
244             AslGbl_CurrentAmlOffset += Length;
245             return (AE_OK);
246 
247         default:
248             break;
249         }
250         break;
251 
252     case AML_METHOD_OP:
253 
254         /* Method (Namepath, ...) */
255 
256         Length = Op->Asl.FinalAmlLength;
257 
258         /* Get the NameSeg/NamePath Op */
259 
260         NextOp = Op->Asl.Child;
261 
262         /* Get offset of last nameseg and the actual data (flags byte) */
263 
264         NamepathOffset = AslGbl_CurrentAmlOffset + Length +
265             (NextOp->Asl.FinalAmlLength - ACPI_NAMESEG_SIZE);
266 
267         DataOffset = AslGbl_CurrentAmlOffset + Length +
268             NextOp->Asl.FinalAmlLength;
269 
270         /* Get the flags byte Op */
271 
272         NextOp = NextOp->Asl.Next;
273 
274         LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset,
275             Op->Asl.ParseOpName, NextOp->Asl.Value.Integer,
276             (UINT8) Op->Asl.AmlOpcode, AML_METHOD_OP);
277         break;
278 
279     case AML_PROCESSOR_OP:
280 
281         /* Processor (Namepath, ProcessorId, Address, Length) */
282 
283         Length = Op->Asl.FinalAmlLength;
284         NextOp = Op->Asl.Child;     /* Get Namepath */
285 
286         /* Get offset of last nameseg and the actual data (PBlock address) */
287 
288         NamepathOffset = AslGbl_CurrentAmlOffset + Length +
289             (NextOp->Asl.FinalAmlLength - ACPI_NAMESEG_SIZE);
290 
291         DataOffset = AslGbl_CurrentAmlOffset + Length +
292             (NextOp->Asl.FinalAmlLength + 1);
293 
294         NextOp = NextOp->Asl.Next;  /* Get ProcessorID (BYTE) */
295         NextOp = NextOp->Asl.Next;  /* Get Address (DWORD) */
296 
297         LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, DataOffset,
298             Op->Asl.ParseOpName, NextOp->Asl.Value.Integer,
299             (UINT8) AML_DWORD_OP, AML_PROCESSOR_OP);
300         break;
301 
302     case AML_DEVICE_OP:
303     case AML_SCOPE_OP:
304     case AML_THERMAL_ZONE_OP:
305 
306         /* Device/Scope/ThermalZone (Namepath) */
307 
308         Length = Op->Asl.FinalAmlLength;
309         NextOp = Op->Asl.Child;     /* Get Namepath */
310 
311         /* Get offset of last nameseg */
312 
313         NamepathOffset = AslGbl_CurrentAmlOffset + Length +
314             (NextOp->Asl.FinalAmlLength - ACPI_NAMESEG_SIZE);
315 
316         LsEmitOffsetTableEntry (FileId, Node, NamepathOffset, 0,
317             Op->Asl.ParseOpName, 0, (UINT8) 0, Op->Asl.AmlOpcode);
318         break;
319 
320     default:
321         break;
322     }
323 
324     AslGbl_CurrentAmlOffset += Op->Asl.FinalAmlLength;
325     return (AE_OK);
326 }
327 
328 
329 /*******************************************************************************
330  *
331  * FUNCTION:    LsEmitOffsetTableEntry
332  *
333  * PARAMETERS:  FileId          - ID of current listing file
334  *              Node            - Namespace node associated with the name
335  *              Offset          - Offset of the value within the AML table
336  *              OpName          - Name of the AML opcode
337  *              Value           - Current value of the AML field
338  *              AmlOpcode       - Opcode associated with the field
339  *              ObjectType      - ACPI object type
340  *
341  * RETURN:      None
342  *
343  * DESCRIPTION: Emit a line of the offset table (-so option)
344  *
345  ******************************************************************************/
346 
347 static void
LsEmitOffsetTableEntry(UINT32 FileId,ACPI_NAMESPACE_NODE * Node,UINT32 NamepathOffset,UINT32 Offset,char * OpName,UINT64 Value,UINT8 AmlOpcode,UINT16 ParentOpcode)348 LsEmitOffsetTableEntry (
349     UINT32                  FileId,
350     ACPI_NAMESPACE_NODE     *Node,
351     UINT32                  NamepathOffset,
352     UINT32                  Offset,
353     char                    *OpName,
354     UINT64                  Value,
355     UINT8                   AmlOpcode,
356     UINT16                  ParentOpcode)
357 {
358     ACPI_BUFFER             TargetPath;
359     ACPI_STATUS             Status;
360 
361 
362     /* Get the full pathname to the namespace node */
363 
364     TargetPath.Length = ACPI_ALLOCATE_LOCAL_BUFFER;
365     Status = AcpiNsHandleToPathname (Node, &TargetPath, FALSE);
366     if (ACPI_FAILURE (Status))
367     {
368         return;
369     }
370 
371     /* [1] - Skip the opening backslash for the path */
372 
373     strcpy (AslGbl_MsgBuffer, "\"");
374     strcat (AslGbl_MsgBuffer, &((char *) TargetPath.Pointer)[1]);
375     strcat (AslGbl_MsgBuffer, "\",");
376     ACPI_FREE (TargetPath.Pointer);
377 
378     /*
379      * Max offset is 4G, constrained by 32-bit ACPI table length.
380      * Max Length for Integers is 8 bytes.
381      */
382     FlPrintFile (FileId,
383         "    {%-29s 0x%4.4X, 0x%8.8X, 0x%2.2X, 0x%8.8X, 0x%8.8X%8.8X}, /* %s */\n",
384         AslGbl_MsgBuffer, ParentOpcode, NamepathOffset, AmlOpcode,
385         Offset, ACPI_FORMAT_UINT64 (Value), OpName);
386 }
387 
388 
389 /*******************************************************************************
390  *
391  * FUNCTION:    LsDoOffsetTableHeader, LsDoOffsetTableFooter
392  *
393  * PARAMETERS:  FileId          - ID of current listing file
394  *
395  * RETURN:      None
396  *
397  * DESCRIPTION: Header and footer for the offset table file.
398  *
399  ******************************************************************************/
400 
401 void
LsDoOffsetTableHeader(UINT32 FileId)402 LsDoOffsetTableHeader (
403     UINT32                  FileId)
404 {
405 
406     FlPrintFile (FileId,
407         "#ifndef __AML_OFFSET_TABLE_H\n"
408         "#define __AML_OFFSET_TABLE_H\n\n");
409 
410     FlPrintFile (FileId, "typedef struct {\n"
411         "    char                   *Pathname;      /* Full pathname (from root) to the object */\n"
412         "    unsigned short         ParentOpcode;   /* AML opcode for the parent object */\n"
413         "    unsigned long          NamesegOffset;  /* Offset of last nameseg in the parent namepath */\n"
414         "    unsigned char          Opcode;         /* AML opcode for the data */\n"
415         "    unsigned long          Offset;         /* Offset for the data */\n"
416         "    unsigned long long     Value;          /* Original value of the data (as applicable) */\n"
417         "} AML_OFFSET_TABLE_ENTRY;\n\n");
418 
419     FlPrintFile (FileId,
420         "#endif /* __AML_OFFSET_TABLE_H */\n\n");
421 
422     FlPrintFile (FileId,
423         "/*\n"
424         " * Information specific to the supported object types:\n"
425         " *\n"
426         " * Integers:\n"
427         " *    Opcode is the integer prefix, indicates length of the data\n"
428         " *        (One of: BYTE, WORD, DWORD, QWORD, ZERO, ONE, ONES)\n"
429         " *    Offset points to the actual integer data\n"
430         " *    Value is the existing value in the AML\n"
431         " *\n"
432         " * Packages:\n"
433         " *    Opcode is the package or var_package opcode\n"
434         " *    Offset points to the package opcode\n"
435         " *    Value is the package element count\n"
436         " *\n"
437         " * Operation Regions:\n"
438         " *    Opcode is the address integer prefix, indicates length of the data\n"
439         " *    Offset points to the region address\n"
440         " *    Value is the existing address value in the AML\n"
441         " *\n"
442         " * Control Methods:\n"
443         " *    Offset points to the method flags byte\n"
444         " *    Value is the existing flags value in the AML\n"
445         " *\n"
446         " * Processors:\n"
447         " *    Offset points to the first byte of the PBlock Address\n"
448         " *\n"
449         " * Resource Descriptors:\n"
450         " *    Opcode is the descriptor type\n"
451         " *    Offset points to the start of the descriptor\n"
452         " *\n"
453         " * Scopes/Devices/ThermalZones:\n"
454         " *    Nameseg offset only\n"
455         " */\n");
456 
457     FlPrintFile (FileId,
458         "AML_OFFSET_TABLE_ENTRY   %s_%s_OffsetTable[] =\n{\n",
459         AslGbl_TableSignature, AslGbl_TableId);
460 }
461 
462 
463 void
LsDoOffsetTableFooter(UINT32 FileId)464 LsDoOffsetTableFooter (
465     UINT32                  FileId)
466 {
467 
468     FlPrintFile (FileId,
469         "    {NULL,0,0,0,0,0} /* Table terminator */\n};\n\n");
470     AslGbl_CurrentAmlOffset = 0;
471 }
472