1/******************************************************************************
2 *
3 * Module Name: asltransform - Parse tree transforms
4 *
5 *****************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2023, 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 "acnamesp.h"
47
48#define _COMPONENT          ACPI_COMPILER
49        ACPI_MODULE_NAME    ("asltransform")
50
51/* Local prototypes */
52
53static void
54TrTransformSubtree (
55    ACPI_PARSE_OBJECT       *Op);
56
57static char *
58TrAmlGetNextTempName (
59    ACPI_PARSE_OBJECT       *Op,
60    UINT8                   *TempCount);
61
62static void
63TrAmlInitLineNumbers (
64    ACPI_PARSE_OBJECT       *Op,
65    ACPI_PARSE_OBJECT       *Neighbor);
66
67static void
68TrAmlInitNode (
69    ACPI_PARSE_OBJECT       *Op,
70    UINT16                  ParseOpcode);
71
72static void
73TrAmlSetSubtreeParent (
74    ACPI_PARSE_OBJECT       *Op,
75    ACPI_PARSE_OBJECT       *Parent);
76
77static void
78TrAmlInsertPeer (
79    ACPI_PARSE_OBJECT       *Op,
80    ACPI_PARSE_OBJECT       *NewPeer);
81
82static void
83TrDoDefinitionBlock (
84    ACPI_PARSE_OBJECT       *Op);
85
86static void
87TrDoSwitch (
88    ACPI_PARSE_OBJECT       *StartNode);
89
90static void
91TrCheckForDuplicateCase (
92    ACPI_PARSE_OBJECT       *CaseOp,
93    ACPI_PARSE_OBJECT       *Predicate1);
94
95static BOOLEAN
96TrCheckForBufferMatch (
97    ACPI_PARSE_OBJECT       *Next1,
98    ACPI_PARSE_OBJECT       *Next2);
99
100static void
101TrDoMethod (
102    ACPI_PARSE_OBJECT       *Op);
103
104
105/*******************************************************************************
106 *
107 * FUNCTION:    TrAmlGetNextTempName
108 *
109 * PARAMETERS:  Op              - Current parse op
110 *              TempCount       - Current temporary counter. Was originally
111 *                                per-module; Currently per method, could be
112 *                                expanded to per-scope.
113 *
114 * RETURN:      A pointer to name (allocated here).
115 *
116 * DESCRIPTION: Generate an ACPI name of the form _T_x. These names are
117 *              reserved for use by the ASL compiler. (_T_0 through _T_Z)
118 *
119 ******************************************************************************/
120
121static char *
122TrAmlGetNextTempName (
123    ACPI_PARSE_OBJECT       *Op,
124    UINT8                   *TempCount)
125{
126    char                    *TempName;
127
128
129    if (*TempCount >= (10 + 26))  /* 0-35 valid: 0-9 and A-Z for TempName[3] */
130    {
131        /* Too many temps */
132
133        AslError (ASL_ERROR, ASL_MSG_TOO_MANY_TEMPS, Op, NULL);
134        return (NULL);
135    }
136
137    TempName = UtLocalCalloc (5);
138
139    if (*TempCount < 10)    /* 0-9 */
140    {
141        TempName[3] = (char) (*TempCount + '0');
142    }
143    else                    /* 10-35: A-Z */
144    {
145        TempName[3] = (char) (*TempCount + ('A' - 10));
146    }
147
148    (*TempCount)++;
149
150    /* First three characters are always "_T_" */
151
152    TempName[0] = '_';
153    TempName[1] = 'T';
154    TempName[2] = '_';
155
156    return (TempName);
157}
158
159
160/*******************************************************************************
161 *
162 * FUNCTION:    TrAmlInitLineNumbers
163 *
164 * PARAMETERS:  Op              - Op to be initialized
165 *              Neighbor        - Op used for initialization values
166 *
167 * RETURN:      None
168 *
169 * DESCRIPTION: Initialized the various line numbers for a parse node.
170 *
171 ******************************************************************************/
172
173static void
174TrAmlInitLineNumbers (
175    ACPI_PARSE_OBJECT       *Op,
176    ACPI_PARSE_OBJECT       *Neighbor)
177{
178
179    Op->Asl.EndLine           = Neighbor->Asl.EndLine;
180    Op->Asl.EndLogicalLine    = Neighbor->Asl.EndLogicalLine;
181    Op->Asl.LineNumber        = Neighbor->Asl.LineNumber;
182    Op->Asl.LogicalByteOffset = Neighbor->Asl.LogicalByteOffset;
183    Op->Asl.LogicalLineNumber = Neighbor->Asl.LogicalLineNumber;
184}
185
186
187/*******************************************************************************
188 *
189 * FUNCTION:    TrAmlInitNode
190 *
191 * PARAMETERS:  Op              - Op to be initialized
192 *              ParseOpcode     - Opcode for this node
193 *
194 * RETURN:      None
195 *
196 * DESCRIPTION: Initialize a node with the parse opcode and opcode name.
197 *
198 ******************************************************************************/
199
200static void
201TrAmlInitNode (
202    ACPI_PARSE_OBJECT       *Op,
203    UINT16                  ParseOpcode)
204{
205
206    Op->Asl.ParseOpcode = ParseOpcode;
207    UtSetParseOpName (Op);
208}
209
210
211/*******************************************************************************
212 *
213 * FUNCTION:    TrAmlSetSubtreeParent
214 *
215 * PARAMETERS:  Op              - First node in a list of peer nodes
216 *              Parent          - Parent of the subtree
217 *
218 * RETURN:      None
219 *
220 * DESCRIPTION: Set the parent for all peer nodes in a subtree
221 *
222 ******************************************************************************/
223
224static void
225TrAmlSetSubtreeParent (
226    ACPI_PARSE_OBJECT       *Op,
227    ACPI_PARSE_OBJECT       *Parent)
228{
229    ACPI_PARSE_OBJECT       *Next;
230
231
232    Next = Op;
233    while (Next)
234    {
235        Next->Asl.Parent = Parent;
236        Next = Next->Asl.Next;
237    }
238}
239
240
241/*******************************************************************************
242 *
243 * FUNCTION:    TrAmlInsertPeer
244 *
245 * PARAMETERS:  Op              - First node in a list of peer nodes
246 *              NewPeer         - Peer node to insert
247 *
248 * RETURN:      None
249 *
250 * DESCRIPTION: Insert a new peer node into a list of peers.
251 *
252 ******************************************************************************/
253
254static void
255TrAmlInsertPeer (
256    ACPI_PARSE_OBJECT       *Op,
257    ACPI_PARSE_OBJECT       *NewPeer)
258{
259
260    NewPeer->Asl.Next = Op->Asl.Next;
261    Op->Asl.Next = NewPeer;
262}
263
264
265/*******************************************************************************
266 *
267 * FUNCTION:    TrAmlTransformWalkBegin
268 *
269 * PARAMETERS:  ASL_WALK_CALLBACK
270 *
271 * RETURN:      None
272 *
273 * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML
274 *              operands.
275 *
276 ******************************************************************************/
277
278ACPI_STATUS
279TrAmlTransformWalkBegin (
280    ACPI_PARSE_OBJECT       *Op,
281    UINT32                  Level,
282    void                    *Context)
283{
284
285    TrTransformSubtree (Op);
286    return (AE_OK);
287}
288
289
290/*******************************************************************************
291 *
292 * FUNCTION:    TrAmlTransformWalkEnd
293 *
294 * PARAMETERS:  ASL_WALK_CALLBACK
295 *
296 * RETURN:      None
297 *
298 * DESCRIPTION: Parse tree walk to generate both the AML opcodes and the AML
299 *              operands.
300 *
301 ******************************************************************************/
302
303ACPI_STATUS
304TrAmlTransformWalkEnd (
305    ACPI_PARSE_OBJECT       *Op,
306    UINT32                  Level,
307    void                    *Context)
308{
309
310    /* Save possible Externals list in the DefintionBlock Op */
311
312    if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
313    {
314        Op->Asl.Value.Arg = AslGbl_ExternalsListHead;
315        AslGbl_ExternalsListHead = NULL;
316    }
317
318    return (AE_OK);
319}
320
321
322/*******************************************************************************
323 *
324 * FUNCTION:    TrTransformSubtree
325 *
326 * PARAMETERS:  Op        - The parent parse node
327 *
328 * RETURN:      None
329 *
330 * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more
331 *              complex AML opcodes require processing of the child nodes
332 *              (arguments/operands).
333 *
334 ******************************************************************************/
335
336static void
337TrTransformSubtree (
338    ACPI_PARSE_OBJECT           *Op)
339{
340    ACPI_PARSE_OBJECT           *MethodOp;
341    ACPI_NAMESTRING_INFO        Info;
342
343
344    if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE)
345    {
346        return;
347    }
348
349    switch (Op->Asl.ParseOpcode)
350    {
351    case PARSEOP_DEFINITION_BLOCK:
352
353        TrDoDefinitionBlock (Op);
354        break;
355
356    case PARSEOP_SWITCH:
357
358        TrDoSwitch (Op);
359        break;
360
361    case PARSEOP_METHOD:
362
363        TrDoMethod (Op);
364        break;
365
366    case PARSEOP_EXTERNAL:
367
368        ExDoExternal (Op);
369        break;
370
371    case PARSEOP___METHOD__:
372
373        /* Transform to a string op containing the parent method name */
374
375        Op->Asl.ParseOpcode = PARSEOP_STRING_LITERAL;
376        UtSetParseOpName (Op);
377
378        /* Find the parent control method op */
379
380        MethodOp = Op;
381        while (MethodOp)
382        {
383            if (MethodOp->Asl.ParseOpcode == PARSEOP_METHOD)
384            {
385                /* First child contains the method name */
386
387                MethodOp = MethodOp->Asl.Child;
388                Op->Asl.Value.String = MethodOp->Asl.Value.String;
389                return;
390            }
391
392            MethodOp = MethodOp->Asl.Parent;
393        }
394
395        /* At the root, invocation not within a control method */
396
397        Op->Asl.Value.String = "\\";
398        break;
399
400    case PARSEOP_NAMESTRING:
401        /*
402         * A NameString can be up to 255 (0xFF) individual NameSegs maximum
403         * (with 254 dot separators) - as per the ACPI specification. Note:
404         * Cannot check for NumSegments == 0 because things like
405         * Scope(\) are legal and OK.
406         */
407        Info.ExternalName = Op->Asl.Value.String;
408        AcpiNsGetInternalNameLength (&Info);
409
410        if (Info.NumSegments > 255)
411        {
412            AslError (ASL_ERROR, ASL_MSG_NAMESTRING_LENGTH, Op, NULL);
413        }
414        break;
415
416    case PARSEOP_UNLOAD:
417
418        AslError (ASL_WARNING, ASL_MSG_UNLOAD, Op, NULL);
419        break;
420
421    case PARSEOP_SLEEP:
422
423        /* Remark for very long sleep values */
424
425        if (Op->Asl.Child->Asl.Value.Integer > 1000)
426        {
427            AslError (ASL_REMARK, ASL_MSG_LONG_SLEEP, Op, NULL);
428        }
429        break;
430
431    case PARSEOP_PROCESSOR:
432
433        AslError (ASL_WARNING, ASL_MSG_LEGACY_PROCESSOR_OP, Op, Op->Asl.ExternalName);
434        break;
435
436    case PARSEOP_OBJECTTYPE_DDB:
437
438        AslError (ASL_WARNING, ASL_MSG_LEGACY_DDB_TYPE, Op, Op->Asl.ExternalName);
439        break;
440
441    default:
442
443        /* Nothing to do here for other opcodes */
444
445        break;
446    }
447}
448
449
450/*******************************************************************************
451 *
452 * FUNCTION:    TrDoDefinitionBlock
453 *
454 * PARAMETERS:  Op        - Parse node
455 *
456 * RETURN:      None
457 *
458 * DESCRIPTION: Find the end of the definition block and set a global to this
459 *              node. It is used by the compiler to insert compiler-generated
460 *              names at the root level of the namespace.
461 *
462 ******************************************************************************/
463
464static void
465TrDoDefinitionBlock (
466    ACPI_PARSE_OBJECT       *Op)
467{
468    ACPI_PARSE_OBJECT       *Next;
469    UINT32                  i;
470
471
472    /* Reset external list when starting a definition block */
473
474    AslGbl_ExternalsListHead = NULL;
475
476    Next = Op->Asl.Child;
477    for (i = 0; i < 5; i++)
478    {
479        Next = Next->Asl.Next;
480        if (i == 0)
481        {
482            /*
483             * This is the table signature. Only the DSDT can be assumed
484             * to be at the root of the namespace;  Therefore, namepath
485             * optimization can only be performed on the DSDT.
486             */
487            if (!ACPI_COMPARE_NAMESEG (Next->Asl.Value.String, ACPI_SIG_DSDT))
488            {
489                AslGbl_ReferenceOptimizationFlag = FALSE;
490            }
491        }
492    }
493
494    AslGbl_FirstLevelInsertionNode = Next;
495}
496
497
498/*******************************************************************************
499 *
500 * FUNCTION:    TrDoSwitch
501 *
502 * PARAMETERS:  StartNode        - Parse node for SWITCH
503 *
504 * RETURN:      None
505 *
506 * DESCRIPTION: Translate ASL SWITCH statement to if/else pairs. There is
507 *              no actual AML opcode for SWITCH -- it must be simulated.
508 *
509 ******************************************************************************/
510
511static void
512TrDoSwitch (
513    ACPI_PARSE_OBJECT       *StartNode)
514{
515    ACPI_PARSE_OBJECT       *Next;
516    ACPI_PARSE_OBJECT       *CaseOp = NULL;
517    ACPI_PARSE_OBJECT       *CaseBlock = NULL;
518    ACPI_PARSE_OBJECT       *DefaultOp = NULL;
519    ACPI_PARSE_OBJECT       *CurrentParentNode;
520    ACPI_PARSE_OBJECT       *Conditional = NULL;
521    ACPI_PARSE_OBJECT       *Predicate;
522    ACPI_PARSE_OBJECT       *Peer;
523    ACPI_PARSE_OBJECT       *NewOp;
524    ACPI_PARSE_OBJECT       *NewOp2;
525    ACPI_PARSE_OBJECT       *MethodOp;
526    ACPI_PARSE_OBJECT       *StoreOp;
527    ACPI_PARSE_OBJECT       *BreakOp;
528    ACPI_PARSE_OBJECT       *BufferOp;
529    char                    *PredicateValueName;
530    UINT16                  Index;
531    UINT32                  Btype;
532
533
534    /* Start node is the Switch() node */
535
536    CurrentParentNode  = StartNode;
537
538    /* Create a new temp name of the form _T_x */
539
540    PredicateValueName = TrAmlGetNextTempName (StartNode, &AslGbl_TempCount);
541    if (!PredicateValueName)
542    {
543        return;
544    }
545
546    /* First child is the Switch() predicate */
547
548    Next = StartNode->Asl.Child;
549
550    /*
551     * Examine the return type of the Switch Value -
552     * must be Integer/Buffer/String
553     */
554    Index = (UINT16) (Next->Asl.ParseOpcode - ASL_PARSE_OPCODE_BASE);
555    Btype = AslKeywordMapping[Index].AcpiBtype;
556    if ((Btype != ACPI_BTYPE_INTEGER) &&
557        (Btype != ACPI_BTYPE_STRING)  &&
558        (Btype != ACPI_BTYPE_BUFFER))
559    {
560        AslError (ASL_WARNING, ASL_MSG_SWITCH_TYPE, Next, NULL);
561        Btype = ACPI_BTYPE_INTEGER;
562    }
563
564    /* CASE statements start at next child */
565
566    Peer = Next->Asl.Next;
567    while (Peer)
568    {
569        Next = Peer;
570        Peer = Next->Asl.Next;
571
572        if (Next->Asl.ParseOpcode == PARSEOP_CASE)
573        {
574            TrCheckForDuplicateCase (Next, Next->Asl.Child);
575
576            if (CaseOp)
577            {
578                /* Add an ELSE to complete the previous CASE */
579
580                NewOp = TrCreateLeafOp (PARSEOP_ELSE);
581                NewOp->Asl.Parent = Conditional->Asl.Parent;
582                TrAmlInitLineNumbers (NewOp, NewOp->Asl.Parent);
583
584                /* Link ELSE node as a peer to the previous IF */
585
586                TrAmlInsertPeer (Conditional, NewOp);
587                CurrentParentNode = NewOp;
588            }
589
590            CaseOp = Next;
591            Conditional = CaseOp;
592            CaseBlock = CaseOp->Asl.Child->Asl.Next;
593            Conditional->Asl.Child->Asl.Next = NULL;
594            Predicate = CaseOp->Asl.Child;
595
596            if ((Predicate->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
597                (Predicate->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
598            {
599                /*
600                 * Convert the package declaration to this form:
601                 *
602                 * If (LNotEqual (Match (Package(<size>){<data>},
603                 *                       MEQ, _T_x, MTR, Zero, Zero), Ones))
604                 */
605                NewOp2              = TrCreateLeafOp (PARSEOP_MATCHTYPE_MEQ);
606                Predicate->Asl.Next = NewOp2;
607                TrAmlInitLineNumbers (NewOp2, Conditional);
608
609                NewOp               = NewOp2;
610                NewOp2              = TrCreateValuedLeafOp (PARSEOP_NAMESTRING,
611                                        (UINT64) ACPI_TO_INTEGER (PredicateValueName));
612                NewOp->Asl.Next     = NewOp2;
613                TrAmlInitLineNumbers (NewOp2, Predicate);
614
615                NewOp               = NewOp2;
616                NewOp2              = TrCreateLeafOp (PARSEOP_MATCHTYPE_MTR);
617                NewOp->Asl.Next     = NewOp2;
618                TrAmlInitLineNumbers (NewOp2, Predicate);
619
620                NewOp               = NewOp2;
621                NewOp2              = TrCreateLeafOp (PARSEOP_ZERO);
622                NewOp->Asl.Next     = NewOp2;
623                TrAmlInitLineNumbers (NewOp2, Predicate);
624
625                NewOp               = NewOp2;
626                NewOp2              = TrCreateLeafOp (PARSEOP_ZERO);
627                NewOp->Asl.Next     = NewOp2;
628                TrAmlInitLineNumbers (NewOp2, Predicate);
629
630                NewOp2              = TrCreateLeafOp (PARSEOP_MATCH);
631                NewOp2->Asl.Child   = Predicate;  /* PARSEOP_PACKAGE */
632                TrAmlInitLineNumbers (NewOp2, Conditional);
633                TrAmlSetSubtreeParent (Predicate, NewOp2);
634
635                NewOp               = NewOp2;
636                NewOp2              = TrCreateLeafOp (PARSEOP_ONES);
637                NewOp->Asl.Next     = NewOp2;
638                TrAmlInitLineNumbers (NewOp2, Conditional);
639
640                NewOp2              = TrCreateLeafOp (PARSEOP_LEQUAL);
641                NewOp2->Asl.Child   = NewOp;
642                NewOp->Asl.Parent   = NewOp2;
643                TrAmlInitLineNumbers (NewOp2, Conditional);
644                TrAmlSetSubtreeParent (NewOp, NewOp2);
645
646                NewOp               = NewOp2;
647                NewOp2              = TrCreateLeafOp (PARSEOP_LNOT);
648                NewOp2->Asl.Child   = NewOp;
649                NewOp2->Asl.Parent  = Conditional;
650                NewOp->Asl.Parent   = NewOp2;
651                TrAmlInitLineNumbers (NewOp2, Conditional);
652
653                Conditional->Asl.Child = NewOp2;
654                NewOp2->Asl.Next = CaseBlock;
655            }
656            else
657            {
658                /*
659                 * Integer and Buffer case.
660                 *
661                 * Change CaseOp() to:  If (LEqual (SwitchValue, CaseValue)) {...}
662                 * Note: SwitchValue is first to allow the CaseValue to be implicitly
663                 * converted to the type of SwitchValue if necessary.
664                 *
665                 * CaseOp->Child is the case value
666                 * CaseOp->Child->Peer is the beginning of the case block
667                 */
668                NewOp = TrCreateValuedLeafOp (PARSEOP_NAMESTRING,
669                    (UINT64) ACPI_TO_INTEGER (PredicateValueName));
670                NewOp->Asl.Next = Predicate;
671                TrAmlInitLineNumbers (NewOp, Predicate);
672
673                NewOp2              = TrCreateLeafOp (PARSEOP_LEQUAL);
674                NewOp2->Asl.Parent  = Conditional;
675                NewOp2->Asl.Child   = NewOp;
676                TrAmlInitLineNumbers (NewOp2, Conditional);
677
678                TrAmlSetSubtreeParent (NewOp, NewOp2);
679
680                Predicate           = NewOp2;
681                Predicate->Asl.Next = CaseBlock;
682
683                TrAmlSetSubtreeParent (Predicate, Conditional);
684                Conditional->Asl.Child = Predicate;
685            }
686
687            /* Reinitialize the CASE node to an IF node */
688
689            TrAmlInitNode (Conditional, PARSEOP_IF);
690
691            /*
692             * The first CASE(IF) is not nested under an ELSE.
693             * All other CASEs are children of a parent ELSE.
694             */
695            if (CurrentParentNode == StartNode)
696            {
697                Conditional->Asl.Next = NULL;
698            }
699            else
700            {
701                /*
702                 * The IF is a child of previous IF/ELSE. It
703                 * is therefore without peer.
704                 */
705                CurrentParentNode->Asl.Child = Conditional;
706                Conditional->Asl.Parent      = CurrentParentNode;
707                Conditional->Asl.Next        = NULL;
708            }
709        }
710        else if (Next->Asl.ParseOpcode == PARSEOP_DEFAULT)
711        {
712            if (DefaultOp)
713            {
714                /*
715                 * More than one Default
716                 * (Parser does not catch this, must check here)
717                 */
718                AslError (ASL_ERROR, ASL_MSG_MULTIPLE_DEFAULT, Next, NULL);
719            }
720            else
721            {
722                /* Save the DEFAULT node for later, after CASEs */
723
724                DefaultOp = Next;
725            }
726        }
727        else
728        {
729            /* Unknown peer opcode */
730
731            AcpiOsPrintf ("Unknown parse opcode for switch statement: %s (%u)\n",
732                Next->Asl.ParseOpName, Next->Asl.ParseOpcode);
733        }
734    }
735
736    /* Add the default case at the end of the if/else construct */
737
738    if (DefaultOp)
739    {
740        /* If no CASE statements, this is an error - see below */
741
742        if (CaseOp)
743        {
744            /* Convert the DEFAULT node to an ELSE */
745
746            TrAmlInitNode (DefaultOp, PARSEOP_ELSE);
747            DefaultOp->Asl.Parent = Conditional->Asl.Parent;
748
749            /* Link ELSE node as a peer to the previous IF */
750
751            TrAmlInsertPeer (Conditional, DefaultOp);
752        }
753    }
754
755    if (!CaseOp)
756    {
757        AslError (ASL_ERROR, ASL_MSG_NO_CASES, StartNode, NULL);
758    }
759
760
761    /*
762     * Create a Name(_T_x, ...) statement. This statement must appear at the
763     * method level, in case a loop surrounds the switch statement and could
764     * cause the name to be created twice (error).
765     */
766
767    /* Create the Name node */
768
769    Predicate = StartNode->Asl.Child;
770    NewOp = TrCreateLeafOp (PARSEOP_NAME);
771    TrAmlInitLineNumbers (NewOp, StartNode);
772
773    /* Find the parent method */
774
775    Next = StartNode;
776    while ((Next->Asl.ParseOpcode != PARSEOP_METHOD) &&
777           (Next->Asl.ParseOpcode != PARSEOP_DEFINITION_BLOCK))
778    {
779        Next = Next->Asl.Parent;
780    }
781    MethodOp = Next;
782
783    NewOp->Asl.CompileFlags |= OP_COMPILER_EMITTED;
784    NewOp->Asl.Parent = Next;
785
786    /* Insert name after the method name and arguments */
787
788    Next = Next->Asl.Child; /* Name */
789    Next = Next->Asl.Next;  /* NumArgs */
790    Next = Next->Asl.Next;  /* SerializeRule */
791
792    /*
793     * If method is not Serialized, we must make is so, because of the way
794     * that Switch() must be implemented -- we cannot allow multiple threads
795     * to execute this method concurrently since we need to create local
796     * temporary name(s).
797     */
798    if (Next->Asl.ParseOpcode != PARSEOP_SERIALIZERULE_SERIAL)
799    {
800        AslError (ASL_REMARK, ASL_MSG_SERIALIZED, MethodOp,
801            "Due to use of Switch operator");
802        Next->Asl.ParseOpcode = PARSEOP_SERIALIZERULE_SERIAL;
803    }
804
805    Next = Next->Asl.Next;  /* SyncLevel */
806    Next = Next->Asl.Next;  /* ReturnType */
807    Next = Next->Asl.Next;  /* ParameterTypes */
808
809    TrAmlInsertPeer (Next, NewOp);
810    TrAmlInitLineNumbers (NewOp, Next);
811
812    /* Create the NameSeg child for the Name node */
813
814    NewOp2 = TrCreateValuedLeafOp (PARSEOP_NAMESEG,
815        (UINT64) ACPI_TO_INTEGER (PredicateValueName));
816    TrAmlInitLineNumbers (NewOp2, NewOp);
817    NewOp2->Asl.CompileFlags |= OP_IS_NAME_DECLARATION;
818    NewOp->Asl.Child  = NewOp2;
819
820    /* Create the initial value for the Name. Btype was already validated above */
821
822    switch (Btype)
823    {
824    case ACPI_BTYPE_INTEGER:
825
826        NewOp2->Asl.Next = TrCreateValuedLeafOp (PARSEOP_ZERO,
827            (UINT64) 0);
828        TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp);
829        break;
830
831    case ACPI_BTYPE_STRING:
832
833        NewOp2->Asl.Next = TrCreateValuedLeafOp (PARSEOP_STRING_LITERAL,
834            (UINT64) ACPI_TO_INTEGER (""));
835        TrAmlInitLineNumbers (NewOp2->Asl.Next, NewOp);
836        break;
837
838    case ACPI_BTYPE_BUFFER:
839
840        (void) TrLinkPeerOp (NewOp2, TrCreateValuedLeafOp (PARSEOP_BUFFER,
841            (UINT64) 0));
842        Next = NewOp2->Asl.Next;
843        TrAmlInitLineNumbers (Next, NewOp2);
844
845        (void) TrLinkOpChildren (Next, 1, TrCreateValuedLeafOp (PARSEOP_ZERO,
846            (UINT64) 1));
847        TrAmlInitLineNumbers (Next->Asl.Child, Next);
848
849        BufferOp = TrCreateValuedLeafOp (PARSEOP_DEFAULT_ARG, (UINT64) 0);
850        TrAmlInitLineNumbers (BufferOp, Next->Asl.Child);
851        (void) TrLinkPeerOp (Next->Asl.Child, BufferOp);
852
853        TrAmlSetSubtreeParent (Next->Asl.Child, Next);
854        break;
855
856    default:
857
858        break;
859    }
860
861    TrAmlSetSubtreeParent (NewOp2, NewOp);
862
863    /*
864     * Transform the Switch() into a While(One)-Break node.
865     * And create a Store() node which will be used to save the
866     * Switch() value. The store is of the form: Store (Value, _T_x)
867     * where _T_x is the temp variable.
868     */
869    TrAmlInitNode (StartNode, PARSEOP_WHILE);
870    NewOp = TrCreateLeafOp (PARSEOP_ONE);
871    TrAmlInitLineNumbers (NewOp, StartNode);
872    NewOp->Asl.Next = Predicate->Asl.Next;
873    NewOp->Asl.Parent = StartNode;
874    StartNode->Asl.Child = NewOp;
875
876    /* Create a Store() node */
877
878    StoreOp = TrCreateLeafOp (PARSEOP_STORE);
879    TrAmlInitLineNumbers (StoreOp, NewOp);
880    StoreOp->Asl.Parent = StartNode;
881    TrAmlInsertPeer (NewOp, StoreOp);
882
883    /* Complete the Store subtree */
884
885    StoreOp->Asl.Child = Predicate;
886    Predicate->Asl.Parent = StoreOp;
887
888    NewOp = TrCreateValuedLeafOp (PARSEOP_NAMESEG,
889        (UINT64) ACPI_TO_INTEGER (PredicateValueName));
890    TrAmlInitLineNumbers (NewOp, StoreOp);
891    NewOp->Asl.Parent    = StoreOp;
892    Predicate->Asl.Next  = NewOp;
893
894    /* Create a Break() node and insert it into the end of While() */
895
896    Conditional = StartNode->Asl.Child;
897    while (Conditional->Asl.Next)
898    {
899        Conditional = Conditional->Asl.Next;
900    }
901
902    BreakOp = TrCreateLeafOp (PARSEOP_BREAK);
903    TrAmlInitLineNumbers (BreakOp, NewOp);
904    BreakOp->Asl.Parent = StartNode;
905    TrAmlInsertPeer (Conditional, BreakOp);
906}
907
908
909/*******************************************************************************
910 *
911 * FUNCTION:    TrCheckForDuplicateCase
912 *
913 * PARAMETERS:  CaseOp          - Parse node for first Case statement in list
914 *              Predicate1      - Case value for the input CaseOp
915 *
916 * RETURN:      None
917 *
918 * DESCRIPTION: Check for duplicate case values. Currently, only handles
919 *              Integers, Strings and Buffers. No support for Package objects.
920 *
921 ******************************************************************************/
922
923static void
924TrCheckForDuplicateCase (
925    ACPI_PARSE_OBJECT       *CaseOp,
926    ACPI_PARSE_OBJECT       *Predicate1)
927{
928    ACPI_PARSE_OBJECT       *Next;
929    ACPI_PARSE_OBJECT       *Predicate2;
930
931
932    /* Walk the list of CASE opcodes */
933
934    Next = CaseOp->Asl.Next;
935    while (Next)
936    {
937        if (Next->Asl.ParseOpcode == PARSEOP_CASE)
938        {
939            /* Emit error only once */
940
941            if (Next->Asl.CompileFlags & OP_IS_DUPLICATE)
942            {
943                goto NextCase;
944            }
945
946            /* Check for a duplicate plain integer */
947
948            Predicate2 = Next->Asl.Child;
949            if ((Predicate1->Asl.ParseOpcode == PARSEOP_INTEGER) &&
950                (Predicate2->Asl.ParseOpcode == PARSEOP_INTEGER))
951            {
952                if (Predicate1->Asl.Value.Integer == Predicate2->Asl.Value.Integer)
953                {
954                    goto FoundDuplicate;
955                }
956            }
957
958            /* Check for pairs of the constants ZERO, ONE, ONES */
959
960            else if (((Predicate1->Asl.ParseOpcode == PARSEOP_ZERO) &&
961                (Predicate2->Asl.ParseOpcode == PARSEOP_ZERO)) ||
962                ((Predicate1->Asl.ParseOpcode == PARSEOP_ONE) &&
963                (Predicate2->Asl.ParseOpcode == PARSEOP_ONE)) ||
964                ((Predicate1->Asl.ParseOpcode == PARSEOP_ONES) &&
965                (Predicate2->Asl.ParseOpcode == PARSEOP_ONES)))
966            {
967                goto FoundDuplicate;
968            }
969
970            /* Check for a duplicate string constant (literal) */
971
972            else if ((Predicate1->Asl.ParseOpcode == PARSEOP_STRING_LITERAL) &&
973                (Predicate2->Asl.ParseOpcode == PARSEOP_STRING_LITERAL))
974            {
975                if (!strcmp (Predicate1->Asl.Value.String,
976                        Predicate2->Asl.Value.String))
977                {
978                    goto FoundDuplicate;
979                }
980            }
981
982            /* Check for a duplicate buffer constant */
983
984            else if ((Predicate1->Asl.ParseOpcode == PARSEOP_BUFFER) &&
985                (Predicate2->Asl.ParseOpcode == PARSEOP_BUFFER))
986            {
987                if (TrCheckForBufferMatch (Predicate1->Asl.Child,
988                        Predicate2->Asl.Child))
989                {
990                    goto FoundDuplicate;
991                }
992            }
993        }
994        goto NextCase;
995
996FoundDuplicate:
997        /* Emit error message only once */
998
999        Next->Asl.CompileFlags |= OP_IS_DUPLICATE;
1000
1001        AslDualParseOpError (ASL_ERROR, ASL_MSG_DUPLICATE_CASE, Next,
1002            Next->Asl.Value.String, ASL_MSG_CASE_FOUND_HERE, CaseOp,
1003            CaseOp->Asl.ExternalName);
1004
1005NextCase:
1006        Next = Next->Asl.Next;
1007    }
1008}
1009
1010/*******************************************************************************
1011 *
1012 * FUNCTION:    TrBufferIsAllZero
1013 *
1014 * PARAMETERS:  Op          - Parse node for first opcode in buffer initializer
1015 *                            list
1016 *
1017 * RETURN:      TRUE if buffer contains all zeros or a DEFAULT_ARG
1018 *
1019 * DESCRIPTION: Check for duplicate Buffer case values.
1020 *
1021 ******************************************************************************/
1022
1023static BOOLEAN
1024TrBufferIsAllZero (
1025    ACPI_PARSE_OBJECT       *Op)
1026{
1027    while (Op)
1028    {
1029        if (Op->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
1030        {
1031            return (TRUE);
1032        }
1033        else if (Op->Asl.Value.Integer != 0)
1034        {
1035            return (FALSE);
1036        }
1037
1038        Op = Op->Asl.Next;
1039    }
1040
1041    return (TRUE);
1042}
1043
1044
1045/*******************************************************************************
1046 *
1047 * FUNCTION:    TrCheckForBufferMatch
1048 *
1049 * PARAMETERS:  Next1       - Parse node for first opcode in first buffer list
1050 *                              (The DEFAULT_ARG or INTEGER node)
1051 *              Next2       - Parse node for first opcode in second buffer list
1052 *                              (The DEFAULT_ARG or INTEGER node)
1053 *
1054 * RETURN:      TRUE if buffers match, FALSE otherwise
1055 *
1056 * DESCRIPTION: Check for duplicate Buffer case values.
1057 *
1058 ******************************************************************************/
1059
1060static BOOLEAN
1061TrCheckForBufferMatch (
1062    ACPI_PARSE_OBJECT       *NextOp1,
1063    ACPI_PARSE_OBJECT       *NextOp2)
1064{
1065    /*
1066     * The buffer length can be a DEFAULT_ARG or INTEGER. If any of the nodes
1067     * are DEFAULT_ARG, it means that the length has yet to be computed.
1068     * However, the initializer list can be compared to determine if these two
1069     * buffers match.
1070     */
1071    if ((NextOp1->Asl.ParseOpcode == PARSEOP_INTEGER &&
1072        NextOp2->Asl.ParseOpcode == PARSEOP_INTEGER) &&
1073        NextOp1->Asl.Value.Integer != NextOp2->Asl.Value.Integer)
1074    {
1075        return (FALSE);
1076    }
1077
1078    /*
1079     * Buffers that have explicit lengths but no initializer lists are
1080     * filled with zeros at runtime. This is equivalent to buffers that have the
1081     * same length that are filled with zeros.
1082     *
1083     * In other words, the following buffers are equivalent:
1084     *
1085     * Buffer(0x4) {}
1086     * Buffer() {0x0, 0x0, 0x0, 0x0}
1087     *
1088     * This statement checks for matches where one buffer does not have an
1089     * initializer list and another buffer contains all zeros.
1090     */
1091    if (NextOp1->Asl.ParseOpcode != NextOp2->Asl.ParseOpcode &&
1092        TrBufferIsAllZero (NextOp1->Asl.Next) &&
1093        TrBufferIsAllZero (NextOp2->Asl.Next))
1094    {
1095        return (TRUE);
1096    }
1097
1098    /* Start at the BYTECONST initializer node list */
1099
1100    NextOp1 = NextOp1->Asl.Next;
1101    NextOp2 = NextOp2->Asl.Next;
1102
1103    /*
1104     * Walk both lists until either a mismatch is found, or one or more
1105     * end-of-lists are found
1106     */
1107    while (NextOp1 && NextOp2)
1108    {
1109        if ((NextOp1->Asl.ParseOpcode == PARSEOP_STRING_LITERAL) &&
1110            (NextOp2->Asl.ParseOpcode == PARSEOP_STRING_LITERAL))
1111        {
1112            if (!strcmp (NextOp1->Asl.Value.String, NextOp2->Asl.Value.String))
1113            {
1114                return (TRUE);
1115            }
1116            else
1117            {
1118                return (FALSE);
1119            }
1120        }
1121        if ((UINT8) NextOp1->Asl.Value.Integer != (UINT8) NextOp2->Asl.Value.Integer)
1122        {
1123            return (FALSE);
1124        }
1125
1126        NextOp1 = NextOp1->Asl.Next;
1127        NextOp2 = NextOp2->Asl.Next;
1128    }
1129
1130    /* Not a match if one of the lists is not at end-of-list */
1131
1132    if (NextOp1 || NextOp2)
1133    {
1134        return (FALSE);
1135    }
1136
1137    /* Otherwise, the buffers match */
1138
1139    return (TRUE);
1140}
1141
1142
1143/*******************************************************************************
1144 *
1145 * FUNCTION:    TrDoMethod
1146 *
1147 * PARAMETERS:  Op               - Parse node for SWITCH
1148 *
1149 * RETURN:      None
1150 *
1151 * DESCRIPTION: Determine that parameter count of an ASL method node by
1152 *              translating the parameter count parse node from
1153 *              PARSEOP_DEFAULT_ARG to PARSEOP_BYTECONST.
1154 *
1155 ******************************************************************************/
1156
1157static void
1158TrDoMethod (
1159    ACPI_PARSE_OBJECT       *Op)
1160{
1161    ACPI_PARSE_OBJECT           *ArgCountOp;
1162    UINT8                       ArgCount;
1163    ACPI_PARSE_OBJECT           *ParameterOp;
1164
1165
1166    /*
1167     * TBD: Zero the tempname (_T_x) count. Probably shouldn't be a global,
1168     * however
1169     */
1170    AslGbl_TempCount = 0;
1171
1172    ArgCountOp = Op->Asl.Child->Asl.Next;
1173    if (ArgCountOp->Asl.ParseOpcode == PARSEOP_BYTECONST)
1174    {
1175        /*
1176         * Parameter count for this method has already been recorded in the
1177         * method declaration.
1178         */
1179        return;
1180    }
1181
1182    /*
1183     * Parameter count has been omitted in the method declaration.
1184     * Count the amount of arguments here.
1185     */
1186    ParameterOp = ArgCountOp->Asl.Next->Asl.Next->Asl.Next->Asl.Next;
1187    if (ParameterOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
1188    {
1189        ArgCount = 0;
1190        ParameterOp = ParameterOp->Asl.Child;
1191
1192        while (ParameterOp)
1193        {
1194            ParameterOp = ParameterOp->Asl.Next;
1195            ArgCount++;
1196        }
1197
1198        ArgCountOp->Asl.Value.Integer = ArgCount;
1199        ArgCountOp->Asl.ParseOpcode = PARSEOP_BYTECONST;
1200    }
1201    else
1202    {
1203        /*
1204         * Method parameters can be counted by analyzing the Parameter type
1205         * list. If the Parameter list contains more than 1 parameter, it
1206         * is nested under PARSEOP_DEFAULT_ARG. When there is only 1
1207         * parameter, the parse tree contains a single node representing
1208         * that type.
1209         */
1210        ArgCountOp->Asl.Value.Integer = 1;
1211        ArgCountOp->Asl.ParseOpcode = PARSEOP_BYTECONST;
1212    }
1213}
1214