aslprintf.c revision 306536
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
54static void
55OpcCreateConcatenateNode (
56    ACPI_PARSE_OBJECT       *Op,
57    ACPI_PARSE_OBJECT       *Node);
58
59static void
60OpcParsePrintf (
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
77void
78OpcDoPrintf (
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
107void
108OpcDoFprintf (
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
142static void
143OpcParsePrintf (
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
341static void
342OpcCreateConcatenateNode (
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