1274357Sjkim/******************************************************************************
2274357Sjkim *
3274357Sjkim * Module Name: aslprintf - ASL Printf/Fprintf macro support
4274357Sjkim *
5274357Sjkim *****************************************************************************/
6274357Sjkim
7274357Sjkim/*
8306536Sjkim * Copyright (C) 2000 - 2016, Intel Corp.
9274357Sjkim * All rights reserved.
10274357Sjkim *
11274357Sjkim * Redistribution and use in source and binary forms, with or without
12274357Sjkim * modification, are permitted provided that the following conditions
13274357Sjkim * are met:
14274357Sjkim * 1. Redistributions of source code must retain the above copyright
15274357Sjkim *    notice, this list of conditions, and the following disclaimer,
16274357Sjkim *    without modification.
17274357Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18274357Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19274357Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20274357Sjkim *    including a substantially similar Disclaimer requirement for further
21274357Sjkim *    binary redistribution.
22274357Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23274357Sjkim *    of any contributors may be used to endorse or promote products derived
24274357Sjkim *    from this software without specific prior written permission.
25274357Sjkim *
26274357Sjkim * Alternatively, this software may be distributed under the terms of the
27274357Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28274357Sjkim * Software Foundation.
29274357Sjkim *
30274357Sjkim * NO WARRANTY
31274357Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32274357Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33274357Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34274357Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35274357Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36274357Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37274357Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38274357Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39274357Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40274357Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41274357Sjkim * POSSIBILITY OF SUCH DAMAGES.
42274357Sjkim */
43274357Sjkim
44278970Sjkim#include <contrib/dev/acpica/compiler/aslcompiler.h>
45274357Sjkim#include "aslcompiler.y.h"
46278970Sjkim#include <contrib/dev/acpica/include/amlcode.h>
47274357Sjkim
48274357Sjkim#define _COMPONENT          ACPI_COMPILER
49274357Sjkim        ACPI_MODULE_NAME    ("aslprintf")
50274357Sjkim
51274357Sjkim
52274357Sjkim/* Local prototypes */
53274357Sjkim
54274357Sjkimstatic void
55274357SjkimOpcCreateConcatenateNode (
56274357Sjkim    ACPI_PARSE_OBJECT       *Op,
57274357Sjkim    ACPI_PARSE_OBJECT       *Node);
58274357Sjkim
59274357Sjkimstatic void
60274357SjkimOpcParsePrintf (
61274357Sjkim    ACPI_PARSE_OBJECT       *Op,
62274357Sjkim    ACPI_PARSE_OBJECT       *DestOp);
63274357Sjkim
64274357Sjkim
65274357Sjkim/*******************************************************************************
66274357Sjkim *
67274357Sjkim * FUNCTION:    OpcDoPrintf
68274357Sjkim *
69274357Sjkim * PARAMETERS:  Op                  - printf parse node
70274357Sjkim *
71274357Sjkim * RETURN:      None
72274357Sjkim *
73274357Sjkim * DESCRIPTION: Convert printf macro to a Store(..., Debug) AML operation.
74274357Sjkim *
75274357Sjkim ******************************************************************************/
76274357Sjkim
77274357Sjkimvoid
78274357SjkimOpcDoPrintf (
79274357Sjkim    ACPI_PARSE_OBJECT       *Op)
80274357Sjkim{
81274357Sjkim    ACPI_PARSE_OBJECT       *DestOp;
82274357Sjkim
83274357Sjkim
84274357Sjkim    /* Store destination is the Debug op */
85274357Sjkim
86274357Sjkim    DestOp = TrAllocateNode (PARSEOP_DEBUG);
87274357Sjkim    DestOp->Asl.AmlOpcode = AML_DEBUG_OP;
88274357Sjkim    DestOp->Asl.Parent = Op;
89274357Sjkim    DestOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
90274357Sjkim
91274357Sjkim    OpcParsePrintf (Op, DestOp);
92274357Sjkim}
93274357Sjkim
94274357Sjkim
95274357Sjkim/*******************************************************************************
96274357Sjkim *
97274357Sjkim * FUNCTION:    OpcDoFprintf
98274357Sjkim *
99274357Sjkim * PARAMETERS:  Op                  - fprintf parse node
100274357Sjkim *
101274357Sjkim * RETURN:      None
102274357Sjkim *
103274357Sjkim * DESCRIPTION: Convert fprintf macro to a Store AML operation.
104274357Sjkim *
105274357Sjkim ******************************************************************************/
106274357Sjkim
107274357Sjkimvoid
108274357SjkimOpcDoFprintf (
109274357Sjkim    ACPI_PARSE_OBJECT       *Op)
110274357Sjkim{
111274357Sjkim    ACPI_PARSE_OBJECT       *DestOp;
112274357Sjkim
113274357Sjkim
114274357Sjkim    /* Store destination is the first argument of fprintf */
115274357Sjkim
116274357Sjkim    DestOp = Op->Asl.Child;
117274357Sjkim    Op->Asl.Child = DestOp->Asl.Next;
118274357Sjkim    DestOp->Asl.Next = NULL;
119274357Sjkim
120274357Sjkim    OpcParsePrintf (Op, DestOp);
121274357Sjkim}
122274357Sjkim
123274357Sjkim
124274357Sjkim/*******************************************************************************
125274357Sjkim *
126274357Sjkim * FUNCTION:    OpcParsePrintf
127274357Sjkim *
128274357Sjkim * PARAMETERS:  Op                  - Printf parse node
129274357Sjkim *              DestOp              - Destination of Store operation
130274357Sjkim *
131274357Sjkim * RETURN:      None
132274357Sjkim *
133274357Sjkim * DESCRIPTION: Convert printf macro to a Store AML operation. The printf
134274357Sjkim *              macro parse tree is layed out as follows:
135274357Sjkim *
136274357Sjkim *              Op        - printf parse op
137274357Sjkim *              Op->Child - Format string
138274357Sjkim *              Op->Next  - Format string arguments
139274357Sjkim *
140274357Sjkim ******************************************************************************/
141274357Sjkim
142274357Sjkimstatic void
143274357SjkimOpcParsePrintf (
144274357Sjkim    ACPI_PARSE_OBJECT       *Op,
145274357Sjkim    ACPI_PARSE_OBJECT       *DestOp)
146274357Sjkim{
147274357Sjkim    char                    *Format;
148274357Sjkim    char                    *StartPosition = NULL;
149274357Sjkim    ACPI_PARSE_OBJECT       *ArgNode;
150274357Sjkim    ACPI_PARSE_OBJECT       *NextNode;
151274357Sjkim    UINT32                  StringLength = 0;
152274357Sjkim    char                    *NewString;
153274357Sjkim    BOOLEAN                 StringToProcess = FALSE;
154274357Sjkim    ACPI_PARSE_OBJECT       *NewOp;
155274357Sjkim
156274357Sjkim
157274357Sjkim    /* Get format string */
158274357Sjkim
159274357Sjkim    Format = ACPI_CAST_PTR (char, Op->Asl.Child->Asl.Value.String);
160274357Sjkim    ArgNode = Op->Asl.Child->Asl.Next;
161274357Sjkim
162274357Sjkim    /*
163274357Sjkim     * Detach argument list so that we can use a NULL check to distinguish
164274357Sjkim     * the first concatenation operation we need to make
165274357Sjkim     */
166274357Sjkim    Op->Asl.Child = NULL;
167274357Sjkim
168274357Sjkim    for (; *Format; ++Format)
169274357Sjkim    {
170274357Sjkim        if (*Format != '%')
171274357Sjkim        {
172274357Sjkim            if (!StringToProcess)
173274357Sjkim            {
174274357Sjkim                /* Mark the beginning of a string */
175274357Sjkim
176274357Sjkim                StartPosition = Format;
177274357Sjkim                StringToProcess = TRUE;
178274357Sjkim            }
179274357Sjkim
180274357Sjkim            ++StringLength;
181274357Sjkim            continue;
182274357Sjkim        }
183274357Sjkim
184274357Sjkim        /* Save string, if any, to new string object and concat it */
185274357Sjkim
186274357Sjkim        if (StringToProcess)
187274357Sjkim        {
188274357Sjkim            NewString = UtStringCacheCalloc (StringLength + 1);
189306536Sjkim            strncpy (NewString, StartPosition, StringLength);
190274357Sjkim
191274357Sjkim            NewOp = TrAllocateNode (PARSEOP_STRING_LITERAL);
192274357Sjkim            NewOp->Asl.Value.String = NewString;
193274357Sjkim            NewOp->Asl.AmlOpcode = AML_STRING_OP;
194274357Sjkim            NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING;
195274357Sjkim            NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
196274357Sjkim
197274357Sjkim            OpcCreateConcatenateNode(Op, NewOp);
198274357Sjkim
199274357Sjkim            StringLength = 0;
200274357Sjkim            StringToProcess = FALSE;
201274357Sjkim        }
202274357Sjkim
203274357Sjkim        ++Format;
204274357Sjkim
205274357Sjkim        /*
206274357Sjkim         * We have a format parameter and will need an argument to go
207274357Sjkim         * with it
208274357Sjkim         */
209274357Sjkim        if (!ArgNode ||
210274357Sjkim            ArgNode->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
211274357Sjkim        {
212274357Sjkim            AslError(ASL_ERROR, ASL_MSG_ARG_COUNT_LO, Op, NULL);
213274357Sjkim            return;
214274357Sjkim        }
215274357Sjkim
216274357Sjkim        /*
217274357Sjkim         * We do not support sub-specifiers of printf (flags, width,
218274357Sjkim         * precision, length). For specifiers we only support %x/%X for
219274357Sjkim         * hex or %s for strings. Also, %o for generic "acpi object".
220274357Sjkim         */
221274357Sjkim        switch (*Format)
222274357Sjkim        {
223274357Sjkim        case 's':
224274357Sjkim
225274357Sjkim            if (ArgNode->Asl.ParseOpcode != PARSEOP_STRING_LITERAL)
226274357Sjkim            {
227274357Sjkim                AslError(ASL_ERROR, ASL_MSG_INVALID_TYPE, ArgNode,
228274357Sjkim                    "String required");
229274357Sjkim                return;
230274357Sjkim            }
231274357Sjkim
232274357Sjkim            NextNode = ArgNode->Asl.Next;
233274357Sjkim            ArgNode->Asl.Next = NULL;
234274357Sjkim            OpcCreateConcatenateNode(Op, ArgNode);
235274357Sjkim            ArgNode = NextNode;
236274357Sjkim            continue;
237274357Sjkim
238274357Sjkim        case 'X':
239274357Sjkim        case 'x':
240274357Sjkim        case 'o':
241274357Sjkim
242274357Sjkim            NextNode = ArgNode->Asl.Next;
243274357Sjkim            ArgNode->Asl.Next = NULL;
244274357Sjkim
245274357Sjkim            /*
246274357Sjkim             * Append an empty string if the first argument is
247274357Sjkim             * not a string. This will implicitly conver the 2nd
248274357Sjkim             * concat source to a string per the ACPI specification.
249274357Sjkim             */
250274357Sjkim            if (!Op->Asl.Child)
251274357Sjkim            {
252274357Sjkim                NewOp = TrAllocateNode (PARSEOP_STRING_LITERAL);
253274357Sjkim                NewOp->Asl.Value.String = "";
254274357Sjkim                NewOp->Asl.AmlOpcode = AML_STRING_OP;
255274357Sjkim                NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING;
256274357Sjkim                NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
257274357Sjkim
258274357Sjkim                OpcCreateConcatenateNode(Op, NewOp);
259274357Sjkim            }
260274357Sjkim
261274357Sjkim            OpcCreateConcatenateNode(Op, ArgNode);
262274357Sjkim            ArgNode = NextNode;
263274357Sjkim            break;
264274357Sjkim
265274357Sjkim        default:
266274357Sjkim
267274357Sjkim            AslError(ASL_ERROR, ASL_MSG_INVALID_OPERAND, Op,
268274357Sjkim                "Unrecognized format specifier");
269274357Sjkim            continue;
270274357Sjkim        }
271274357Sjkim    }
272274357Sjkim
273274357Sjkim    /* Process any remaining string */
274274357Sjkim
275274357Sjkim    if (StringToProcess)
276274357Sjkim    {
277274357Sjkim        NewString = UtStringCacheCalloc (StringLength + 1);
278306536Sjkim        strncpy (NewString, StartPosition, StringLength);
279274357Sjkim
280274357Sjkim        NewOp = TrAllocateNode (PARSEOP_STRING_LITERAL);
281274357Sjkim        NewOp->Asl.Value.String = NewString;
282274357Sjkim        NewOp->Asl.AcpiBtype = ACPI_BTYPE_STRING;
283274357Sjkim        NewOp->Asl.AmlOpcode = AML_STRING_OP;
284274357Sjkim        NewOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
285274357Sjkim
286274357Sjkim        OpcCreateConcatenateNode(Op, NewOp);
287274357Sjkim    }
288274357Sjkim
289274357Sjkim    /*
290274357Sjkim     * If we get here and there's no child node then Format
291274357Sjkim     * was an empty string. Just make a no op.
292274357Sjkim     */
293274357Sjkim    if (!Op->Asl.Child)
294274357Sjkim    {
295274357Sjkim        Op->Asl.ParseOpcode = PARSEOP_NOOP;
296274357Sjkim        AslError(ASL_WARNING, ASL_MSG_NULL_STRING, Op,
297274357Sjkim            "Converted to NOOP");
298274357Sjkim        return;
299274357Sjkim    }
300274357Sjkim
301274357Sjkim     /* Check for erroneous extra arguments */
302274357Sjkim
303274357Sjkim    if (ArgNode &&
304274357Sjkim        ArgNode->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)
305274357Sjkim    {
306274357Sjkim        AslError(ASL_WARNING, ASL_MSG_ARG_COUNT_HI, ArgNode,
307274357Sjkim            "Extra arguments ignored");
308274357Sjkim    }
309274357Sjkim
310274357Sjkim    /* Change Op to a Store */
311274357Sjkim
312274357Sjkim    Op->Asl.ParseOpcode = PARSEOP_STORE;
313274357Sjkim    Op->Common.AmlOpcode = AML_STORE_OP;
314274357Sjkim    Op->Asl.CompileFlags  = 0;
315274357Sjkim
316274357Sjkim    /* Disable further optimization */
317274357Sjkim
318274357Sjkim    Op->Asl.CompileFlags &= ~NODE_COMPILE_TIME_CONST;
319274357Sjkim    UtSetParseOpName (Op);
320274357Sjkim
321274357Sjkim    /* Set Store destination */
322274357Sjkim
323274357Sjkim    Op->Asl.Child->Asl.Next = DestOp;
324274357Sjkim}
325274357Sjkim
326274357Sjkim
327274357Sjkim/*******************************************************************************
328274357Sjkim *
329274357Sjkim * FUNCTION:    OpcCreateConcatenateNode
330274357Sjkim *
331274357Sjkim * PARAMETERS:  Op                  - Parse node
332274357Sjkim *              Node                - Parse node to be concatenated
333274357Sjkim *
334274357Sjkim * RETURN:      None
335274357Sjkim *
336274357Sjkim * DESCRIPTION: Make Node the child of Op. If child node already exists, then
337274357Sjkim *              concat child with Node and makes concat node the child of Op.
338274357Sjkim *
339274357Sjkim ******************************************************************************/
340274357Sjkim
341274357Sjkimstatic void
342274357SjkimOpcCreateConcatenateNode (
343274357Sjkim    ACPI_PARSE_OBJECT       *Op,
344274357Sjkim    ACPI_PARSE_OBJECT       *Node)
345274357Sjkim{
346274357Sjkim    ACPI_PARSE_OBJECT       *NewConcatOp;
347274357Sjkim
348274357Sjkim
349274357Sjkim    if (!Op->Asl.Child)
350274357Sjkim    {
351274357Sjkim        Op->Asl.Child = Node;
352274357Sjkim        Node->Asl.Parent = Op;
353274357Sjkim        return;
354274357Sjkim    }
355274357Sjkim
356274357Sjkim    NewConcatOp = TrAllocateNode (PARSEOP_CONCATENATE);
357274357Sjkim    NewConcatOp->Asl.AmlOpcode = AML_CONCAT_OP;
358274357Sjkim    NewConcatOp->Asl.AcpiBtype = 0x7;
359274357Sjkim    NewConcatOp->Asl.LogicalLineNumber = Op->Asl.LogicalLineNumber;
360274357Sjkim
361274357Sjkim    /* First arg is child of Op*/
362274357Sjkim
363274357Sjkim    NewConcatOp->Asl.Child = Op->Asl.Child;
364274357Sjkim    Op->Asl.Child->Asl.Parent = NewConcatOp;
365274357Sjkim
366274357Sjkim    /* Second arg is Node */
367274357Sjkim
368274357Sjkim    NewConcatOp->Asl.Child->Asl.Next = Node;
369274357Sjkim    Node->Asl.Parent = NewConcatOp;
370274357Sjkim
371274357Sjkim    /* Third arg is Zero (not used) */
372274357Sjkim
373274357Sjkim    NewConcatOp->Asl.Child->Asl.Next->Asl.Next =
374274357Sjkim        TrAllocateNode (PARSEOP_ZERO);
375274357Sjkim    NewConcatOp->Asl.Child->Asl.Next->Asl.Next->Asl.Parent =
376274357Sjkim        NewConcatOp;
377274357Sjkim
378274357Sjkim    Op->Asl.Child = NewConcatOp;
379274357Sjkim    NewConcatOp->Asl.Parent = Op;
380274357Sjkim}
381