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