1218585Sjkim/******************************************************************************
2218585Sjkim *
3218585Sjkim * Module Name: dtexpress.c - Support for integer expressions and labels
4218585Sjkim *
5218585Sjkim *****************************************************************************/
6218585Sjkim
7218585Sjkim/*
8306536Sjkim * Copyright (C) 2000 - 2016, Intel Corp.
9218585Sjkim * All rights reserved.
10218585Sjkim *
11218585Sjkim * Redistribution and use in source and binary forms, with or without
12218585Sjkim * modification, are permitted provided that the following conditions
13218585Sjkim * are met:
14218585Sjkim * 1. Redistributions of source code must retain the above copyright
15218585Sjkim *    notice, this list of conditions, and the following disclaimer,
16218585Sjkim *    without modification.
17218585Sjkim * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18218585Sjkim *    substantially similar to the "NO WARRANTY" disclaimer below
19218585Sjkim *    ("Disclaimer") and any redistribution must be conditioned upon
20218585Sjkim *    including a substantially similar Disclaimer requirement for further
21218585Sjkim *    binary redistribution.
22218585Sjkim * 3. Neither the names of the above-listed copyright holders nor the names
23218585Sjkim *    of any contributors may be used to endorse or promote products derived
24218585Sjkim *    from this software without specific prior written permission.
25218585Sjkim *
26218585Sjkim * Alternatively, this software may be distributed under the terms of the
27218585Sjkim * GNU General Public License ("GPL") version 2 as published by the Free
28218585Sjkim * Software Foundation.
29218585Sjkim *
30218585Sjkim * NO WARRANTY
31218585Sjkim * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32218585Sjkim * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33218585Sjkim * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
34218585Sjkim * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35218585Sjkim * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36218585Sjkim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37218585Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38218585Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39218585Sjkim * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40218585Sjkim * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41218585Sjkim * POSSIBILITY OF SUCH DAMAGES.
42218585Sjkim */
43218585Sjkim
44218590Sjkim#include <contrib/dev/acpica/compiler/aslcompiler.h>
45218590Sjkim#include <contrib/dev/acpica/compiler/dtcompiler.h>
46220663Sjkim#include "dtparser.y.h"
47218585Sjkim
48218585Sjkim#define _COMPONENT          DT_COMPILER
49218585Sjkim        ACPI_MODULE_NAME    ("dtexpress")
50218585Sjkim
51218585Sjkim
52218585Sjkim/* Local prototypes */
53218585Sjkim
54218585Sjkimstatic void
55218585SjkimDtInsertLabelField (
56218585Sjkim    DT_FIELD                *Field);
57218585Sjkim
58218585Sjkimstatic DT_FIELD *
59218585SjkimDtLookupLabel (
60218585Sjkim    char                    *Name);
61218585Sjkim
62220663Sjkim/* Global used for errors during parse and related functions */
63218585Sjkim
64220663SjkimDT_FIELD                *Gbl_CurrentField;
65220663Sjkim
66220663Sjkim
67218585Sjkim/******************************************************************************
68218585Sjkim *
69218585Sjkim * FUNCTION:    DtResolveIntegerExpression
70218585Sjkim *
71218585Sjkim * PARAMETERS:  Field               - Field object with Integer expression
72220663Sjkim *              ReturnValue         - Where the integer is returned
73218585Sjkim *
74220663Sjkim * RETURN:      Status, and the resolved 64-bit integer value
75218585Sjkim *
76218585Sjkim * DESCRIPTION: Resolve an integer expression to a single value. Supports
77220663Sjkim *              both integer constants and labels.
78218585Sjkim *
79218585Sjkim *****************************************************************************/
80218585Sjkim
81220663SjkimACPI_STATUS
82218585SjkimDtResolveIntegerExpression (
83220663Sjkim    DT_FIELD                *Field,
84220663Sjkim    UINT64                  *ReturnValue)
85218585Sjkim{
86220663Sjkim    UINT64                  Result;
87218585Sjkim
88218585Sjkim
89218585Sjkim    DbgPrint (ASL_DEBUG_OUTPUT, "Full Integer expression: %s\n",
90218585Sjkim        Field->Value);
91218585Sjkim
92220663Sjkim    Gbl_CurrentField = Field;
93218585Sjkim
94220663Sjkim    Result = DtEvaluateExpression (Field->Value);
95220663Sjkim    *ReturnValue = Result;
96220663Sjkim    return (AE_OK);
97220663Sjkim}
98218585Sjkim
99218585Sjkim
100220663Sjkim/******************************************************************************
101220663Sjkim *
102220663Sjkim * FUNCTION:    DtDoOperator
103220663Sjkim *
104220663Sjkim * PARAMETERS:  LeftValue           - First 64-bit operand
105220663Sjkim *              Operator            - Parse token for the operator (EXPOP_*)
106220663Sjkim *              RightValue          - Second 64-bit operand
107220663Sjkim *
108220663Sjkim * RETURN:      64-bit result of the requested operation
109220663Sjkim *
110220663Sjkim * DESCRIPTION: Perform the various 64-bit integer math functions
111220663Sjkim *
112220663Sjkim *****************************************************************************/
113218585Sjkim
114220663SjkimUINT64
115220663SjkimDtDoOperator (
116220663Sjkim    UINT64                  LeftValue,
117220663Sjkim    UINT32                  Operator,
118220663Sjkim    UINT64                  RightValue)
119220663Sjkim{
120220663Sjkim    UINT64                  Result;
121220663Sjkim
122220663Sjkim
123220663Sjkim    /* Perform the requested operation */
124220663Sjkim
125220663Sjkim    switch (Operator)
126218585Sjkim    {
127220663Sjkim    case EXPOP_ONES_COMPLIMENT:
128250838Sjkim
129220663Sjkim        Result = ~RightValue;
130220663Sjkim        break;
131218585Sjkim
132220663Sjkim    case EXPOP_LOGICAL_NOT:
133250838Sjkim
134220663Sjkim        Result = !RightValue;
135220663Sjkim        break;
136218585Sjkim
137220663Sjkim    case EXPOP_MULTIPLY:
138250838Sjkim
139220663Sjkim        Result = LeftValue * RightValue;
140220663Sjkim        break;
141220663Sjkim
142220663Sjkim    case EXPOP_DIVIDE:
143250838Sjkim
144220663Sjkim        if (!RightValue)
145220663Sjkim        {
146220663Sjkim            DtError (ASL_ERROR, ASL_MSG_DIVIDE_BY_ZERO,
147233250Sjkim                Gbl_CurrentField, NULL);
148220663Sjkim            return (0);
149218585Sjkim        }
150306536Sjkim
151220663Sjkim        Result = LeftValue / RightValue;
152220663Sjkim        break;
153218585Sjkim
154220663Sjkim    case EXPOP_MODULO:
155250838Sjkim
156220663Sjkim        if (!RightValue)
157218585Sjkim        {
158220663Sjkim            DtError (ASL_ERROR, ASL_MSG_DIVIDE_BY_ZERO,
159233250Sjkim                Gbl_CurrentField, NULL);
160218585Sjkim            return (0);
161218585Sjkim        }
162306536Sjkim
163220663Sjkim        Result = LeftValue % RightValue;
164220663Sjkim        break;
165218585Sjkim
166220663Sjkim    case EXPOP_ADD:
167220663Sjkim        Result = LeftValue + RightValue;
168220663Sjkim        break;
169218585Sjkim
170220663Sjkim    case EXPOP_SUBTRACT:
171250838Sjkim
172220663Sjkim        Result = LeftValue - RightValue;
173220663Sjkim        break;
174218585Sjkim
175220663Sjkim    case EXPOP_SHIFT_RIGHT:
176250838Sjkim
177220663Sjkim        Result = LeftValue >> RightValue;
178220663Sjkim        break;
179218585Sjkim
180220663Sjkim    case EXPOP_SHIFT_LEFT:
181250838Sjkim
182220663Sjkim        Result = LeftValue << RightValue;
183220663Sjkim        break;
184218585Sjkim
185220663Sjkim    case EXPOP_LESS:
186250838Sjkim
187220663Sjkim        Result = LeftValue < RightValue;
188220663Sjkim        break;
189218585Sjkim
190220663Sjkim    case EXPOP_GREATER:
191250838Sjkim
192220663Sjkim        Result = LeftValue > RightValue;
193220663Sjkim        break;
194218585Sjkim
195220663Sjkim    case EXPOP_LESS_EQUAL:
196250838Sjkim
197220663Sjkim        Result = LeftValue <= RightValue;
198220663Sjkim        break;
199218585Sjkim
200220663Sjkim    case EXPOP_GREATER_EQUAL:
201250838Sjkim
202220663Sjkim        Result = LeftValue >= RightValue;
203220663Sjkim        break;
204218585Sjkim
205220663Sjkim    case EXPOP_EQUAL:
206250838Sjkim
207233250Sjkim        Result = LeftValue == RightValue;
208220663Sjkim        break;
209218585Sjkim
210220663Sjkim    case EXPOP_NOT_EQUAL:
211250838Sjkim
212220663Sjkim        Result = LeftValue != RightValue;
213220663Sjkim        break;
214218585Sjkim
215220663Sjkim    case EXPOP_AND:
216250838Sjkim
217220663Sjkim        Result = LeftValue & RightValue;
218220663Sjkim        break;
219218585Sjkim
220220663Sjkim    case EXPOP_XOR:
221250838Sjkim
222220663Sjkim        Result = LeftValue ^ RightValue;
223220663Sjkim        break;
224218585Sjkim
225220663Sjkim    case EXPOP_OR:
226250838Sjkim
227220663Sjkim        Result = LeftValue | RightValue;
228220663Sjkim        break;
229220663Sjkim
230220663Sjkim    case EXPOP_LOGICAL_AND:
231250838Sjkim
232220663Sjkim        Result = LeftValue && RightValue;
233220663Sjkim        break;
234220663Sjkim
235220663Sjkim    case EXPOP_LOGICAL_OR:
236250838Sjkim
237220663Sjkim        Result = LeftValue || RightValue;
238220663Sjkim        break;
239220663Sjkim
240220663Sjkim   default:
241220663Sjkim
242220663Sjkim        /* Unknown operator */
243220663Sjkim
244220663Sjkim        DtFatal (ASL_MSG_INVALID_EXPRESSION,
245233250Sjkim            Gbl_CurrentField, NULL);
246220663Sjkim        return (0);
247218585Sjkim    }
248218585Sjkim
249220663Sjkim    DbgPrint (ASL_DEBUG_OUTPUT,
250233250Sjkim        "IntegerEval: (%8.8X%8.8X %s %8.8X%8.8X) = %8.8X%8.8X\n",
251220663Sjkim        ACPI_FORMAT_UINT64 (LeftValue),
252220663Sjkim        DtGetOpName (Operator),
253220663Sjkim        ACPI_FORMAT_UINT64 (RightValue),
254220663Sjkim        ACPI_FORMAT_UINT64 (Result));
255220663Sjkim
256220663Sjkim    return (Result);
257218585Sjkim}
258218585Sjkim
259218585Sjkim
260218585Sjkim/******************************************************************************
261218585Sjkim *
262220663Sjkim * FUNCTION:    DtResolveLabel
263218585Sjkim *
264220663Sjkim * PARAMETERS:  LabelString         - Contains the label
265218585Sjkim *
266220663Sjkim * RETURN:      Table offset associated with the label
267218585Sjkim *
268220663Sjkim * DESCRIPTION: Lookup a lable and return its value.
269218585Sjkim *
270218585Sjkim *****************************************************************************/
271218585Sjkim
272220663SjkimUINT64
273220663SjkimDtResolveLabel (
274220663Sjkim    char                    *LabelString)
275218585Sjkim{
276218585Sjkim    DT_FIELD                *LabelField;
277218585Sjkim
278218585Sjkim
279220663Sjkim    DbgPrint (ASL_DEBUG_OUTPUT, "Resolve Label: %s\n", LabelString);
280218585Sjkim
281218585Sjkim    /* Resolve a label reference to an integer (table offset) */
282218585Sjkim
283220663Sjkim    if (*LabelString != '$')
284218585Sjkim    {
285220663Sjkim        return (0);
286220663Sjkim    }
287218585Sjkim
288220663Sjkim    LabelField = DtLookupLabel (LabelString);
289220663Sjkim    if (!LabelField)
290220663Sjkim    {
291220663Sjkim        DtError (ASL_ERROR, ASL_MSG_UNKNOWN_LABEL,
292220663Sjkim            Gbl_CurrentField, LabelString);
293220663Sjkim        return (0);
294218585Sjkim    }
295218585Sjkim
296220663Sjkim    /* All we need from the label is the offset in the table */
297218585Sjkim
298220663Sjkim    DbgPrint (ASL_DEBUG_OUTPUT, "Resolved Label: 0x%8.8X\n",
299220663Sjkim        LabelField->TableOffset);
300218585Sjkim
301220663Sjkim    return (LabelField->TableOffset);
302218585Sjkim}
303218585Sjkim
304218585Sjkim
305218585Sjkim/******************************************************************************
306218585Sjkim *
307218585Sjkim * FUNCTION:    DtDetectAllLabels
308218585Sjkim *
309218585Sjkim * PARAMETERS:  FieldList           - Field object at start of generic list
310218585Sjkim *
311218585Sjkim * RETURN:      None
312218585Sjkim *
313218585Sjkim * DESCRIPTION: Detect all labels in a list of "generic" opcodes (such as
314218585Sjkim *              a UEFI table.) and insert them into the global label list.
315218585Sjkim *
316218585Sjkim *****************************************************************************/
317218585Sjkim
318218585Sjkimvoid
319218585SjkimDtDetectAllLabels (
320218585Sjkim    DT_FIELD                *FieldList)
321218585Sjkim{
322218585Sjkim    ACPI_DMTABLE_INFO       *Info;
323218585Sjkim    DT_FIELD                *GenericField;
324218585Sjkim    UINT32                  TableOffset;
325218585Sjkim
326218585Sjkim
327218585Sjkim    TableOffset = Gbl_CurrentTableOffset;
328218585Sjkim    GenericField = FieldList;
329218585Sjkim
330218585Sjkim    /*
331218585Sjkim     * Process all "Label:" fields within the parse tree. We need
332218585Sjkim     * to know the offsets for all labels before we can compile
333218585Sjkim     * the parse tree in order to handle forward references. Traverse
334218585Sjkim     * tree and get/set all field lengths of all operators in order to
335218585Sjkim     * determine the label offsets.
336218585Sjkim     */
337218585Sjkim    while (GenericField)
338218585Sjkim    {
339218585Sjkim        Info = DtGetGenericTableInfo (GenericField->Name);
340218585Sjkim        if (Info)
341218585Sjkim        {
342218585Sjkim            /* Maintain table offsets */
343218585Sjkim
344218585Sjkim            GenericField->TableOffset = TableOffset;
345218585Sjkim            TableOffset += DtGetFieldLength (GenericField, Info);
346218585Sjkim
347218585Sjkim            /* Insert all labels in the global label list */
348218585Sjkim
349218585Sjkim            if (Info->Opcode == ACPI_DMT_LABEL)
350218585Sjkim            {
351218585Sjkim                DtInsertLabelField (GenericField);
352218585Sjkim            }
353218585Sjkim        }
354218585Sjkim
355218585Sjkim        GenericField = GenericField->Next;
356218585Sjkim    }
357218585Sjkim}
358218585Sjkim
359218585Sjkim
360218585Sjkim/******************************************************************************
361218585Sjkim *
362218585Sjkim * FUNCTION:    DtInsertLabelField
363218585Sjkim *
364218585Sjkim * PARAMETERS:  Field               - Field object with Label to be inserted
365218585Sjkim *
366218585Sjkim * RETURN:      None
367218585Sjkim *
368218585Sjkim * DESCRIPTION: Insert a label field into the global label list
369218585Sjkim *
370218585Sjkim *****************************************************************************/
371218585Sjkim
372218585Sjkimstatic void
373218585SjkimDtInsertLabelField (
374218585Sjkim    DT_FIELD                *Field)
375218585Sjkim{
376218585Sjkim
377218585Sjkim    DbgPrint (ASL_DEBUG_OUTPUT,
378218585Sjkim        "DtInsertLabelField: Found Label : %s at output table offset %X\n",
379218585Sjkim        Field->Value, Field->TableOffset);
380218585Sjkim
381218585Sjkim    Field->NextLabel = Gbl_LabelList;
382218585Sjkim    Gbl_LabelList = Field;
383218585Sjkim}
384218585Sjkim
385218585Sjkim
386218585Sjkim/******************************************************************************
387218585Sjkim *
388218585Sjkim * FUNCTION:    DtLookupLabel
389218585Sjkim *
390218585Sjkim * PARAMETERS:  Name                - Label to be resolved
391218585Sjkim *
392218585Sjkim * RETURN:      Field object associated with the label
393218585Sjkim *
394218585Sjkim * DESCRIPTION: Lookup a label in the global label list. Used during the
395218585Sjkim *              resolution of integer expressions.
396218585Sjkim *
397218585Sjkim *****************************************************************************/
398218585Sjkim
399218585Sjkimstatic DT_FIELD *
400218585SjkimDtLookupLabel (
401218585Sjkim    char                    *Name)
402218585Sjkim{
403218585Sjkim    DT_FIELD                *LabelField;
404218585Sjkim
405218585Sjkim
406218585Sjkim    /* Skip a leading $ */
407218585Sjkim
408218585Sjkim    if (*Name == '$')
409218585Sjkim    {
410218585Sjkim        Name++;
411218585Sjkim    }
412218585Sjkim
413218585Sjkim    /* Search global list */
414218585Sjkim
415218585Sjkim    LabelField = Gbl_LabelList;
416218585Sjkim    while (LabelField)
417218585Sjkim    {
418306536Sjkim        if (!strcmp (Name, LabelField->Value))
419218585Sjkim        {
420218585Sjkim            return (LabelField);
421218585Sjkim        }
422306536Sjkim
423218585Sjkim        LabelField = LabelField->NextLabel;
424218585Sjkim    }
425218585Sjkim
426218585Sjkim    return (NULL);
427218585Sjkim}
428