1 /******************************************************************************
2 *
3 * Module Name: aslprintf - ASL Printf/Fprintf macro support
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2022, 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
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
OpcDoPrintf(ACPI_PARSE_OBJECT * Op)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 = TrAllocateOp (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
OpcDoFprintf(ACPI_PARSE_OBJECT * Op)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 laid 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
OpcParsePrintf(ACPI_PARSE_OBJECT * Op,ACPI_PARSE_OBJECT * DestOp)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 = UtLocalCacheCalloc (StringLength + 1);
189 strncpy (NewString, StartPosition, StringLength);
190
191 NewOp = TrAllocateOp (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 convert the 2nd
248 * concat source to a string per the ACPI specification.
249 */
250 if (!Op->Asl.Child)
251 {
252 NewOp = TrAllocateOp (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 = UtLocalCacheCalloc (StringLength + 1);
278 strncpy (NewString, StartPosition, StringLength);
279
280 NewOp = TrAllocateOp (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 &= ~OP_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
OpcCreateConcatenateNode(ACPI_PARSE_OBJECT * Op,ACPI_PARSE_OBJECT * Node)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 = TrAllocateOp (PARSEOP_CONCATENATE);
357 NewConcatOp->Asl.AmlOpcode = AML_CONCATENATE_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 TrAllocateOp (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