xref: /freebsd/sys/contrib/dev/acpica/compiler/aslprintf.c (revision 3fc36ee018bb836bd1796067cf4ef8683f166ebc)
1 /******************************************************************************
2  *
3  * Module Name: aslprintf - ASL Printf/Fprintf macro support
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 <contrib/dev/acpica/compiler/aslcompiler.h>
45 #include "aslcompiler.y.h"
46 #include <contrib/dev/acpica/include/amlcode.h>
47 
48 #define _COMPONENT          ACPI_COMPILER
49         ACPI_MODULE_NAME    ("aslprintf")
50 
51 
52 /* Local prototypes */
53 
54 static void
55 OpcCreateConcatenateNode (
56     ACPI_PARSE_OBJECT       *Op,
57     ACPI_PARSE_OBJECT       *Node);
58 
59 static void
60 OpcParsePrintf (
61     ACPI_PARSE_OBJECT       *Op,
62     ACPI_PARSE_OBJECT       *DestOp);
63 
64 
65 /*******************************************************************************
66  *
67  * FUNCTION:    OpcDoPrintf
68  *
69  * PARAMETERS:  Op                  - printf parse node
70  *
71  * RETURN:      None
72  *
73  * DESCRIPTION: Convert printf macro to a Store(..., Debug) AML operation.
74  *
75  ******************************************************************************/
76 
77 void
78 OpcDoPrintf (
79     ACPI_PARSE_OBJECT       *Op)
80 {
81     ACPI_PARSE_OBJECT       *DestOp;
82 
83 
84     /* Store destination is the Debug op */
85 
86     DestOp = TrAllocateNode (PARSEOP_DEBUG);
87     DestOp->Asl.AmlOpcode = AML_DEBUG_OP;
88     DestOp->Asl.Parent = Op;
89     DestOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
90 
91     OpcParsePrintf (Op, DestOp);
92 }
93 
94 
95 /*******************************************************************************
96  *
97  * FUNCTION:    OpcDoFprintf
98  *
99  * PARAMETERS:  Op                  - fprintf parse node
100  *
101  * RETURN:      None
102  *
103  * DESCRIPTION: Convert fprintf macro to a Store AML operation.
104  *
105  ******************************************************************************/
106 
107 void
108 OpcDoFprintf (
109     ACPI_PARSE_OBJECT       *Op)
110 {
111     ACPI_PARSE_OBJECT       *DestOp;
112 
113 
114     /* Store destination is the first argument of fprintf */
115 
116     DestOp = Op->Asl.Child;
117     Op->Asl.Child = DestOp->Asl.Next;
118     DestOp->Asl.Next = NULL;
119 
120     OpcParsePrintf (Op, DestOp);
121 }
122 
123 
124 /*******************************************************************************
125  *
126  * FUNCTION:    OpcParsePrintf
127  *
128  * PARAMETERS:  Op                  - Printf parse node
129  *              DestOp              - Destination of Store operation
130  *
131  * RETURN:      None
132  *
133  * DESCRIPTION: Convert printf macro to a Store AML operation. The printf
134  *              macro parse tree is layed out as follows:
135  *
136  *              Op        - printf parse op
137  *              Op->Child - Format string
138  *              Op->Next  - Format string arguments
139  *
140  ******************************************************************************/
141 
142 static void
143 OpcParsePrintf (
144     ACPI_PARSE_OBJECT       *Op,
145     ACPI_PARSE_OBJECT       *DestOp)
146 {
147     char                    *Format;
148     char                    *StartPosition = NULL;
149     ACPI_PARSE_OBJECT       *ArgNode;
150     ACPI_PARSE_OBJECT       *NextNode;
151     UINT32                  StringLength = 0;
152     char                    *NewString;
153     BOOLEAN                 StringToProcess = FALSE;
154     ACPI_PARSE_OBJECT       *NewOp;
155 
156 
157     /* Get format string */
158 
159     Format = ACPI_CAST_PTR (char, Op->Asl.Child->Asl.Value.String);
160     ArgNode = Op->Asl.Child->Asl.Next;
161 
162     /*
163      * Detach argument list so that we can use a NULL check to distinguish
164      * the first concatenation operation we need to make
165      */
166     Op->Asl.Child = NULL;
167 
168     for (; *Format; ++Format)
169     {
170         if (*Format != '%')
171         {
172             if (!StringToProcess)
173             {
174                 /* Mark the beginning of a string */
175 
176                 StartPosition = Format;
177                 StringToProcess = TRUE;
178             }
179 
180             ++StringLength;
181             continue;
182         }
183 
184         /* Save string, if any, to new string object and concat it */
185 
186         if (StringToProcess)
187         {
188             NewString = UtStringCacheCalloc (StringLength + 1);
189             strncpy (NewString, StartPosition, StringLength);
190 
191             NewOp = TrAllocateNode (PARSEOP_STRING_LITERAL);
192             NewOp->Asl.Value.String = NewString;
193             NewOp->Asl.AmlOpcode = AML_STRING_OP;
194             NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING;
195             NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
196 
197             OpcCreateConcatenateNode(Op, NewOp);
198 
199             StringLength = 0;
200             StringToProcess = FALSE;
201         }
202 
203         ++Format;
204 
205         /*
206          * We have a format parameter and will need an argument to go
207          * with it
208          */
209         if (!ArgNode ||
210             ArgNode->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
211         {
212             AslError(ASL_ERROR, ASL_MSG_ARG_COUNT_LO, Op, NULL);
213             return;
214         }
215 
216         /*
217          * We do not support sub-specifiers of printf (flags, width,
218          * precision, length). For specifiers we only support %x/%X for
219          * hex or %s for strings. Also, %o for generic "acpi object".
220          */
221         switch (*Format)
222         {
223         case 's':
224 
225             if (ArgNode->Asl.ParseOpcode != PARSEOP_STRING_LITERAL)
226             {
227                 AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgNode,
228                     "String required");
229                 return;
230             }
231 
232             NextNode = ArgNode->Asl.Next;
233             ArgNode->Asl.Next = NULL;
234             OpcCreateConcatenateNode(Op, ArgNode);
235             ArgNode = NextNode;
236             continue;
237 
238         case 'X':
239         case 'x':
240         case 'o':
241 
242             NextNode = ArgNode->Asl.Next;
243             ArgNode->Asl.Next = NULL;
244 
245             /*
246              * Append an empty string if the first argument is
247              * not a string. This will implicitly conver the 2nd
248              * concat source to a string per the ACPI specification.
249              */
250             if (!Op->Asl.Child)
251             {
252                 NewOp = TrAllocateNode (PARSEOP_STRING_LITERAL);
253                 NewOp->Asl.Value.String = "";
254                 NewOp->Asl.AmlOpcode = AML_STRING_OP;
255                 NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING;
256                 NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
257 
258                 OpcCreateConcatenateNode(Op, NewOp);
259             }
260 
261             OpcCreateConcatenateNode(Op, ArgNode);
262             ArgNode = NextNode;
263             break;
264 
265         default:
266 
267             AslError(ASL_ERROR, ASL_MSG_INVALID_OPERAND, Op,
268                 "Unrecognized format specifier");
269             continue;
270         }
271     }
272 
273     /* Process any remaining string */
274 
275     if (StringToProcess)
276     {
277         NewString = UtStringCacheCalloc (StringLength + 1);
278         strncpy (NewString, StartPosition, StringLength);
279 
280         NewOp = TrAllocateNode (PARSEOP_STRING_LITERAL);
281         NewOp->Asl.Value.String = NewString;
282         NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING;
283         NewOp->Asl.AmlOpcode = AML_STRING_OP;
284         NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
285 
286         OpcCreateConcatenateNode(Op, NewOp);
287     }
288 
289     /*
290      * If we get here and there's no child node then Format
291      * was an empty string. Just make a no op.
292      */
293     if (!Op->Asl.Child)
294     {
295         Op->Asl.ParseOpcode = PARSEOP_NOOP;
296         AslError(ASL_WARNING, ASL_MSG_NULL_STRING, Op,
297             "Converted to NOOP");
298         return;
299     }
300 
301      /* Check for erroneous extra arguments */
302 
303     if (ArgNode &&
304         ArgNode->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)
305     {
306         AslError(ASL_WARNING, ASL_MSG_ARG_COUNT_HI, ArgNode,
307             "Extra arguments ignored");
308     }
309 
310     /* Change Op to a Store */
311 
312     Op->Asl.ParseOpcode = PARSEOP_STORE;
313     Op->Common.AmlOpcode = AML_STORE_OP;
314     Op->Asl.CompileFlags  = 0;
315 
316     /* Disable further optimization */
317 
318     Op->Asl.CompileFlags &= ~NODE_COMPILE_TIME_CONST;
319     UtSetParseOpName (Op);
320 
321     /* Set Store destination */
322 
323     Op->Asl.Child->Asl.Next = DestOp;
324 }
325 
326 
327 /*******************************************************************************
328  *
329  * FUNCTION:    OpcCreateConcatenateNode
330  *
331  * PARAMETERS:  Op                  - Parse node
332  *              Node                - Parse node to be concatenated
333  *
334  * RETURN:      None
335  *
336  * DESCRIPTION: Make Node the child of Op. If child node already exists, then
337  *              concat child with Node and makes concat node the child of Op.
338  *
339  ******************************************************************************/
340 
341 static void
342 OpcCreateConcatenateNode (
343     ACPI_PARSE_OBJECT       *Op,
344     ACPI_PARSE_OBJECT       *Node)
345 {
346     ACPI_PARSE_OBJECT       *NewConcatOp;
347 
348 
349     if (!Op->Asl.Child)
350     {
351         Op->Asl.Child = Node;
352         Node->Asl.Parent = Op;
353         return;
354     }
355 
356     NewConcatOp = TrAllocateNode (PARSEOP_CONCATENATE);
357     NewConcatOp->Asl.AmlOpcode = AML_CONCAT_OP;
358     NewConcatOp->Asl.AcpiBtype = 0x7;
359     NewConcatOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
360 
361     /* First arg is child of Op*/
362 
363     NewConcatOp->Asl.Child = Op->Asl.Child;
364     Op->Asl.Child->Asl.Parent = NewConcatOp;
365 
366     /* Second arg is Node */
367 
368     NewConcatOp->Asl.Child->Asl.Next = Node;
369     Node->Asl.Parent = NewConcatOp;
370 
371     /* Third arg is Zero (not used) */
372 
373     NewConcatOp->Asl.Child->Asl.Next->Asl.Next =
374         TrAllocateNode (PARSEOP_ZERO);
375     NewConcatOp->Asl.Child->Asl.Next->Asl.Next->Asl.Parent =
376         NewConcatOp;
377 
378     Op->Asl.Child = NewConcatOp;
379     NewConcatOp->Asl.Parent = Op;
380 }
381