1 /******************************************************************************
2  *
3  * Module Name: asloperands - AML operand processing
4  *
5  *****************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2022, 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 "amlcode.h"
47 
48 #define _COMPONENT          ACPI_COMPILER
49         ACPI_MODULE_NAME    ("asloperands")
50 
51 /* Local prototypes */
52 
53 static void
54 OpnDoField (
55     ACPI_PARSE_OBJECT       *Op);
56 
57 static void
58 OpnDoBankField (
59     ACPI_PARSE_OBJECT       *Op);
60 
61 static void
62 OpnDoBuffer (
63     ACPI_PARSE_OBJECT       *Op);
64 
65 static void
66 OpnDoDefinitionBlock (
67     ACPI_PARSE_OBJECT       *Op);
68 
69 static void
70 OpnDoFieldCommon (
71     ACPI_PARSE_OBJECT       *FieldOp,
72     ACPI_PARSE_OBJECT       *Op);
73 
74 static void
75 OpnDoIndexField (
76     ACPI_PARSE_OBJECT       *Op);
77 
78 static void
79 OpnDoLoadTable (
80     ACPI_PARSE_OBJECT       *Op);
81 
82 static void
83 OpnDoMethod (
84     ACPI_PARSE_OBJECT       *Op);
85 
86 static void
87 OpnDoMutex (
88     ACPI_PARSE_OBJECT       *Op);
89 
90 static void
91 OpnDoRegion (
92     ACPI_PARSE_OBJECT       *Op);
93 
94 static void
95 OpnAttachNameToNode (
96     ACPI_PARSE_OBJECT       *Op);
97 
98 
99 /*******************************************************************************
100  *
101  * FUNCTION:    OpnDoMutex
102  *
103  * PARAMETERS:  Op        - The parent parse node
104  *
105  * RETURN:      None
106  *
107  * DESCRIPTION: Construct the operands for the MUTEX ASL keyword.
108  *
109  ******************************************************************************/
110 
111 static void
OpnDoMutex(ACPI_PARSE_OBJECT * Op)112 OpnDoMutex (
113     ACPI_PARSE_OBJECT       *Op)
114 {
115     ACPI_PARSE_OBJECT       *Next;
116 
117 
118     Next = Op->Asl.Child;
119     Next = Next->Asl.Next;
120 
121     if (Next->Asl.Value.Integer > 15)
122     {
123         AslError (ASL_ERROR, ASL_MSG_SYNC_LEVEL, Next, NULL);
124     }
125     return;
126 }
127 
128 
129 /*******************************************************************************
130  *
131  * FUNCTION:    OpnDoMethod
132  *
133  * PARAMETERS:  Op        - The parent parse node
134  *
135  * RETURN:      None
136  *
137  * DESCRIPTION: Construct the operands for the METHOD ASL keyword.
138  *
139  ******************************************************************************/
140 
141 static void
OpnDoMethod(ACPI_PARSE_OBJECT * Op)142 OpnDoMethod (
143     ACPI_PARSE_OBJECT       *Op)
144 {
145     ACPI_PARSE_OBJECT       *Next;
146 
147     /* Optional arguments for this opcode with defaults */
148 
149     UINT8                   NumArgs = 0;
150     UINT8                   Serialized = 0;
151     UINT8                   Concurrency = 0;
152     UINT8                   MethodFlags;
153 
154 
155     /* Opcode and package length first */
156     /* Method name */
157 
158     Next = Op->Asl.Child;
159 
160     /* Num args */
161 
162     Next = Next->Asl.Next;
163     if (Next->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)
164     {
165         NumArgs = (UINT8) Next->Asl.Value.Integer;
166         Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
167     }
168 
169     /* Serialized Flag */
170 
171     Next = Next->Asl.Next;
172     if (Next->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)
173     {
174         Serialized = (UINT8) Next->Asl.Value.Integer;
175         Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
176     }
177 
178     /* Concurrency value (valid values are 0-15) */
179 
180     Next = Next->Asl.Next;
181     if (Next->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)
182     {
183         /* This is a ByteConstExpr, so eval the constant now */
184 
185         OpcAmlConstantWalk (Next, 0, NULL);
186 
187         if (Next->Asl.Value.Integer > 15)
188         {
189             AslError (ASL_ERROR, ASL_MSG_SYNC_LEVEL, Next, NULL);
190         }
191 
192         Concurrency = (UINT8) Next->Asl.Value.Integer;
193     }
194 
195     /* Put the bits in their proper places */
196 
197     MethodFlags = (UINT8)
198         ((NumArgs & 0x7) |
199         ((Serialized & 0x1) << 3) |
200         ((Concurrency & 0xF) << 4));
201 
202     /* Use the last node for the combined flags byte */
203 
204     Next->Asl.Value.Integer = MethodFlags;
205     Next->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
206     Next->Asl.AmlLength = 1;
207     Next->Asl.ParseOpcode = PARSEOP_RAW_DATA;
208 
209     /* Save the arg count in the first node */
210 
211     Op->Asl.Extra = NumArgs;
212 }
213 
214 
215 /*******************************************************************************
216  *
217  * FUNCTION:    OpnDoFieldCommon
218  *
219  * PARAMETERS:  FieldOp       - Node for an ASL field
220  *              Op            - The parent parse node
221  *
222  * RETURN:      None
223  *
224  * DESCRIPTION: Construct the AML operands for the various field keywords,
225  *              FIELD, BANKFIELD, INDEXFIELD
226  *
227  ******************************************************************************/
228 
229 static void
OpnDoFieldCommon(ACPI_PARSE_OBJECT * FieldOp,ACPI_PARSE_OBJECT * Op)230 OpnDoFieldCommon (
231     ACPI_PARSE_OBJECT       *FieldOp,
232     ACPI_PARSE_OBJECT       *Op)
233 {
234     ACPI_PARSE_OBJECT       *Next;
235     ACPI_PARSE_OBJECT       *PkgLengthNode;
236     UINT32                  CurrentBitOffset;
237     UINT32                  NewBitOffset;
238     UINT8                   AccessType;
239     UINT8                   LockRule;
240     UINT8                   UpdateRule;
241     UINT8                   FieldFlags;
242     UINT32                  MinimumLength;
243 
244 
245     /* AccessType -- not optional, so no need to check for DEFAULT_ARG */
246 
247     AccessType = (UINT8) Op->Asl.Value.Integer;
248     Op->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
249 
250     /* Set the access type in the parent (field) node for use later */
251 
252     FieldOp->Asl.Value.Integer = AccessType;
253 
254     /* LockRule -- not optional, so no need to check for DEFAULT_ARG */
255 
256     Next = Op->Asl.Next;
257     LockRule = (UINT8) Next->Asl.Value.Integer;
258     Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
259 
260     /* UpdateRule -- not optional, so no need to check for DEFAULT_ARG */
261 
262     Next = Next->Asl.Next;
263     UpdateRule = (UINT8) Next->Asl.Value.Integer;
264 
265     /*
266      * Generate the flags byte. The various fields are already
267      * in the right bit position via translation from the
268      * keywords by the parser.
269      */
270     FieldFlags = (UINT8) (AccessType | LockRule | UpdateRule);
271 
272     /* Use the previous node to be the FieldFlags node */
273 
274     /* Set the node to RAW_DATA */
275 
276     Next->Asl.Value.Integer = FieldFlags;
277     Next->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
278     Next->Asl.AmlLength = 1;
279     Next->Asl.ParseOpcode = PARSEOP_RAW_DATA;
280 
281     /* Process the FieldUnitList */
282 
283     Next = Next->Asl.Next;
284     CurrentBitOffset = 0;
285 
286     while (Next)
287     {
288         /* Save the offset of this field unit */
289 
290         Next->Asl.ExtraValue = CurrentBitOffset;
291 
292         switch (Next->Asl.ParseOpcode)
293         {
294         case PARSEOP_ACCESSAS:
295 
296             PkgLengthNode = Next->Asl.Child;
297             AccessType = (UINT8) PkgLengthNode->Asl.Value.Integer;
298 
299             /* Nothing additional to do */
300             break;
301 
302         case PARSEOP_OFFSET:
303 
304             /* New offset into the field */
305 
306             PkgLengthNode = Next->Asl.Child;
307             NewBitOffset = ((UINT32) PkgLengthNode->Asl.Value.Integer) * 8;
308 
309             /*
310              * Examine the specified offset in relation to the
311              * current offset counter.
312              */
313             if (NewBitOffset < CurrentBitOffset)
314             {
315                 /*
316                  * Not allowed to specify a backwards offset!
317                  * Issue error and ignore this node.
318                  */
319                 AslError (ASL_ERROR, ASL_MSG_BACKWARDS_OFFSET, PkgLengthNode,
320                     NULL);
321                 Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
322                 PkgLengthNode->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
323             }
324 #ifdef _OBSOLETE_CODE
325             /*
326              * January 2022: removed this check due to complaints by users
327              * for too many (invalid) remarks.
328              */
329             else if (NewBitOffset == CurrentBitOffset)
330             {
331                 /*
332                  * This Offset() operator is redundant and not needed,
333                  * because the offset value is the same as the current
334                  * offset.
335                  */
336                 AslError (ASL_REMARK, ASL_MSG_OFFSET, PkgLengthNode, NULL);
337 
338                 if (AslGbl_OptimizeTrivialParseNodes)
339                 {
340                     /*
341                      * Optimize this Offset() operator by removing/ignoring
342                      * it. Set the related nodes to default.
343                      */
344                     Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
345                     PkgLengthNode->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
346 
347                     AslError (ASL_OPTIMIZATION, ASL_MSG_OFFSET, PkgLengthNode,
348                         "Optimizer has removed statement");
349                 }
350                 else
351                 {
352                     /* Optimization is disabled, treat as a valid Offset */
353 
354                     PkgLengthNode->Asl.Value.Integer =
355                         NewBitOffset - CurrentBitOffset;
356                     CurrentBitOffset = NewBitOffset;
357                 }
358             }
359 #endif
360             else
361             {
362                 /*
363                  * Valid new offset - set the value to be inserted into the AML
364                  * and update the offset counter.
365                  */
366                 PkgLengthNode->Asl.Value.Integer =
367                     NewBitOffset - CurrentBitOffset;
368                 CurrentBitOffset = NewBitOffset;
369             }
370             break;
371 
372         case PARSEOP_NAMESEG:
373         case PARSEOP_RESERVED_BYTES:
374 
375             /* Named or reserved field entry */
376 
377             PkgLengthNode = Next->Asl.Child;
378             NewBitOffset = (UINT32) PkgLengthNode->Asl.Value.Integer;
379             CurrentBitOffset += NewBitOffset;
380 
381             if ((NewBitOffset == 0) &&
382                 (Next->Asl.ParseOpcode == PARSEOP_RESERVED_BYTES) &&
383                 AslGbl_OptimizeTrivialParseNodes)
384             {
385                 /*
386                  * Unnamed field with a bit length of zero. We can
387                  * safely just ignore this. However, we will not ignore
388                  * a named field of zero length, we don't want to just
389                  * toss out a name.
390                  */
391                 Next->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
392                 PkgLengthNode->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
393                 break;
394             }
395 
396             /* Save the current AccessAs value for error checking later */
397 
398             switch (AccessType)
399             {
400                 case AML_FIELD_ACCESS_ANY:
401                 case AML_FIELD_ACCESS_BYTE:
402                 case AML_FIELD_ACCESS_BUFFER:
403                 default:
404 
405                     MinimumLength = 8;
406                     break;
407 
408                 case AML_FIELD_ACCESS_WORD:
409                     MinimumLength = 16;
410                     break;
411 
412                 case AML_FIELD_ACCESS_DWORD:
413                     MinimumLength = 32;
414                     break;
415 
416                 case AML_FIELD_ACCESS_QWORD:
417                     MinimumLength = 64;
418                     break;
419             }
420 
421             PkgLengthNode->Asl.ExtraValue = MinimumLength;
422             break;
423 
424         default:
425 
426             /* All supported field opcodes must appear above */
427 
428             break;
429         }
430 
431         /* Move on to next entry in the field list */
432 
433         Next = Next->Asl.Next;
434     }
435 }
436 
437 
438 /*******************************************************************************
439  *
440  * FUNCTION:    OpnDoField
441  *
442  * PARAMETERS:  Op        - The parent parse node
443  *
444  * RETURN:      None
445  *
446  * DESCRIPTION: Construct the AML operands for the FIELD ASL keyword
447  *
448  ******************************************************************************/
449 
450 static void
OpnDoField(ACPI_PARSE_OBJECT * Op)451 OpnDoField (
452     ACPI_PARSE_OBJECT       *Op)
453 {
454     ACPI_PARSE_OBJECT       *Next;
455 
456 
457     /* Opcode is parent node */
458     /* First child is field name */
459 
460     Next = Op->Asl.Child;
461 
462     /* Second child is the AccessType */
463 
464     OpnDoFieldCommon (Op, Next->Asl.Next);
465 }
466 
467 
468 /*******************************************************************************
469  *
470  * FUNCTION:    OpnDoIndexField
471  *
472  * PARAMETERS:  Op        - The parent parse node
473  *
474  * RETURN:      None
475  *
476  * DESCRIPTION: Construct the AML operands for the INDEXFIELD ASL keyword
477  *
478  ******************************************************************************/
479 
480 static void
OpnDoIndexField(ACPI_PARSE_OBJECT * Op)481 OpnDoIndexField (
482     ACPI_PARSE_OBJECT       *Op)
483 {
484     ACPI_PARSE_OBJECT       *Next;
485 
486 
487     /* Opcode is parent node */
488     /* First child is the index name */
489 
490     Next = Op->Asl.Child;
491 
492     /* Second child is the data name */
493 
494     Next = Next->Asl.Next;
495 
496     /* Third child is the AccessType */
497 
498     OpnDoFieldCommon (Op, Next->Asl.Next);
499 }
500 
501 
502 /*******************************************************************************
503  *
504  * FUNCTION:    OpnDoBankField
505  *
506  * PARAMETERS:  Op        - The parent parse node
507  *
508  * RETURN:      None
509  *
510  * DESCRIPTION: Construct the AML operands for the BANKFIELD ASL keyword
511  *
512  ******************************************************************************/
513 
514 static void
OpnDoBankField(ACPI_PARSE_OBJECT * Op)515 OpnDoBankField (
516     ACPI_PARSE_OBJECT       *Op)
517 {
518     ACPI_PARSE_OBJECT       *Next;
519 
520 
521     /* Opcode is parent node */
522     /* First child is the region name */
523 
524     Next = Op->Asl.Child;
525 
526     /* Second child is the bank name */
527 
528     Next = Next->Asl.Next;
529 
530     /* Third child is the bank value */
531 
532     Next = Next->Asl.Next;
533 
534     /* Fourth child is the AccessType */
535 
536     OpnDoFieldCommon (Op, Next->Asl.Next);
537 }
538 
539 
540 /*******************************************************************************
541  *
542  * FUNCTION:    OpnDoRegion
543  *
544  * PARAMETERS:  Op        - The parent parse node
545  *
546  * RETURN:      None
547  *
548  * DESCRIPTION: Tries to get the length of the region. Can only do this at
549  *              compile time if the length is a constant.
550  *
551  ******************************************************************************/
552 
553 static void
OpnDoRegion(ACPI_PARSE_OBJECT * Op)554 OpnDoRegion (
555     ACPI_PARSE_OBJECT       *Op)
556 {
557     ACPI_PARSE_OBJECT       *Next;
558     ACPI_ADR_SPACE_TYPE     SpaceId;
559 
560 
561     /* Opcode is parent node */
562     /* First child is the region name */
563 
564     Next = Op->Asl.Child;
565 
566     /* Second child is the space ID */
567 
568     Next = Next->Asl.Next;
569     SpaceId = (ACPI_ADR_SPACE_TYPE) Next->Common.Value.Integer;
570 
571     /* Third child is the region offset */
572 
573     Next = Next->Asl.Next;
574 
575     /* Fourth child is the region length */
576 
577     Next = Next->Asl.Next;
578     if (Next->Asl.ParseOpcode == PARSEOP_INTEGER)
579     {
580         /* Check for zero length */
581 
582         Op->Asl.Value.Integer = Next->Asl.Value.Integer;
583         if (!Op->Asl.Value.Integer && (SpaceId < ACPI_NUM_PREDEFINED_REGIONS))
584         {
585             AslError (ASL_ERROR, ASL_MSG_REGION_LENGTH, Op, NULL);
586         }
587     }
588     else
589     {
590         Op->Asl.Value.Integer = ACPI_UINT64_MAX;
591     }
592 }
593 
594 
595 /*******************************************************************************
596  *
597  * FUNCTION:    OpnDoBuffer
598  *
599  * PARAMETERS:  Op        - The parent parse node
600  *
601  * RETURN:      None
602  *
603  * DESCRIPTION: Construct the AML operands for the BUFFER ASL keyword. We
604  *              build a single raw byte buffer from the initialization nodes,
605  *              each parse node contains a buffer byte.
606  *
607  ******************************************************************************/
608 
609 static void
OpnDoBuffer(ACPI_PARSE_OBJECT * Op)610 OpnDoBuffer (
611     ACPI_PARSE_OBJECT       *Op)
612 {
613     ACPI_PARSE_OBJECT       *InitializerOp;
614     ACPI_PARSE_OBJECT       *BufferLengthOp;
615 
616     /* Optional arguments for this opcode with defaults */
617 
618     UINT32                  BufferLength = 0;
619 
620 
621     /* Opcode and package length first */
622     /* Buffer Length is next, followed by the initializer list */
623 
624     BufferLengthOp = Op->Asl.Child;
625     InitializerOp = BufferLengthOp->Asl.Next;
626 
627     /*
628      * If the BufferLength is not an INTEGER or was not specified in the ASL
629      * (DEFAULT_ARG), it is a TermArg that is
630      * evaluated at run-time, and we are therefore finished.
631      */
632     if ((BufferLengthOp->Asl.ParseOpcode != PARSEOP_INTEGER) &&
633         (BufferLengthOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG))
634     {
635         return;
636     }
637 
638     /*
639      * We want to count the number of items in the initializer list, because if
640      * it is larger than the buffer length, we will define the buffer size
641      * to be the size of the initializer list (as per the ACPI Specification)
642      */
643     switch (InitializerOp->Asl.ParseOpcode)
644     {
645     case PARSEOP_INTEGER:
646     case PARSEOP_BYTECONST:
647     case PARSEOP_WORDCONST:
648     case PARSEOP_DWORDCONST:
649 
650         /* The peer list contains the byte list (if any...) */
651 
652         while (InitializerOp)
653         {
654             /* For buffers, this is a list of raw bytes */
655 
656             InitializerOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
657             InitializerOp->Asl.AmlLength = 1;
658             InitializerOp->Asl.ParseOpcode = PARSEOP_RAW_DATA;
659 
660             BufferLength++;
661             InitializerOp = ASL_GET_PEER_NODE (InitializerOp);
662         }
663         break;
664 
665     case PARSEOP_STRING_LITERAL:
666 
667         /*
668          * Only one initializer, the string. Buffer must be big enough to hold
669          * the string plus the null termination byte
670          */
671         BufferLength = strlen (InitializerOp->Asl.Value.String) + 1;
672 
673         InitializerOp->Asl.AmlOpcode = AML_RAW_DATA_BUFFER;
674         InitializerOp->Asl.AmlLength = BufferLength;
675         InitializerOp->Asl.ParseOpcode = PARSEOP_RAW_DATA;
676         break;
677 
678     case PARSEOP_RAW_DATA:
679 
680         /* Buffer nodes are already initialized (e.g. Unicode operator) */
681         return;
682 
683     case PARSEOP_DEFAULT_ARG:
684         break;
685 
686     default:
687 
688         AslError (ASL_ERROR, ASL_MSG_INVALID_OPERAND, InitializerOp,
689             "Unknown buffer initializer opcode");
690         printf ("Unknown buffer initializer opcode [%s]\n",
691             UtGetOpName (InitializerOp->Asl.ParseOpcode));
692         return;
693     }
694 
695     /* Check if initializer list is longer than the buffer length */
696 
697     if (BufferLengthOp->Asl.Value.Integer > BufferLength)
698     {
699         BufferLength = (UINT32) BufferLengthOp->Asl.Value.Integer;
700     }
701 
702     if (!BufferLength)
703     {
704         /* No length AND no items -- issue notice */
705 
706         AslError (ASL_REMARK, ASL_MSG_BUFFER_LENGTH, BufferLengthOp, NULL);
707 
708         /* But go ahead and put the buffer length of zero into the AML */
709     }
710 
711     /*
712      * Just set the buffer size node to be the buffer length, regardless
713      * of whether it was previously an integer or a default_arg placeholder
714      */
715     BufferLengthOp->Asl.ParseOpcode = PARSEOP_INTEGER;
716     BufferLengthOp->Asl.AmlOpcode = AML_DWORD_OP;
717     BufferLengthOp->Asl.Value.Integer = BufferLength;
718 
719     (void) OpcSetOptimalIntegerSize (BufferLengthOp);
720     UtSetParseOpName (BufferLengthOp);
721 
722     /* Remaining nodes are handled via the tree walk */
723 }
724 
725 
726 /*******************************************************************************
727  *
728  * FUNCTION:    OpnDoPackage
729  *
730  * PARAMETERS:  Op        - The parent parse node
731  *
732  * RETURN:      None
733  *
734  * DESCRIPTION: Construct the AML operands for the PACKAGE ASL keyword. NOTE:
735  *              can only be called after constants have been folded, to ensure
736  *              that the PackageLength operand has been fully reduced.
737  *
738  ******************************************************************************/
739 
740 void
OpnDoPackage(ACPI_PARSE_OBJECT * Op)741 OpnDoPackage (
742     ACPI_PARSE_OBJECT       *Op)
743 {
744     ACPI_PARSE_OBJECT       *InitializerOp;
745     ACPI_PARSE_OBJECT       *PackageLengthOp;
746     UINT32                  PackageLength = 0;
747 
748 
749     /* Opcode and package length first, followed by the initializer list */
750 
751     PackageLengthOp = Op->Asl.Child;
752     InitializerOp = PackageLengthOp->Asl.Next;
753 
754     /* Count the number of items in the initializer list */
755 
756     if (InitializerOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)
757     {
758         /* The peer list contains the byte list (if any...) */
759 
760         while (InitializerOp)
761         {
762             PackageLength++;
763             InitializerOp = InitializerOp->Asl.Next;
764         }
765     }
766 
767     /* If package length is a constant, compare to the initializer list */
768 
769     if ((PackageLengthOp->Asl.ParseOpcode == PARSEOP_INTEGER)      ||
770         (PackageLengthOp->Asl.ParseOpcode == PARSEOP_QWORDCONST))
771     {
772         if (PackageLengthOp->Asl.Value.Integer > PackageLength)
773         {
774             /*
775              * Allow package length to be longer than the initializer
776              * list -- but if the length of initializer list is nonzero,
777              * issue a message since this is probably a coding error,
778              * even though technically legal.
779              */
780             if (PackageLength > 0)
781             {
782                 AslError (ASL_REMARK, ASL_MSG_LIST_LENGTH_SHORT,
783                     PackageLengthOp, NULL);
784             }
785 
786             PackageLength = (UINT32) PackageLengthOp->Asl.Value.Integer;
787         }
788         else if (PackageLengthOp->Asl.Value.Integer < PackageLength)
789         {
790             /*
791              * The package length is smaller than the length of the
792              * initializer list. This is an error as per the ACPI spec.
793              */
794             AslError (ASL_ERROR, ASL_MSG_LIST_LENGTH_LONG,
795                 PackageLengthOp, NULL);
796         }
797     }
798 
799     if (PackageLengthOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG)
800     {
801         /*
802          * This is the case if the PackageLength was left empty - Package()
803          * The package length becomes the length of the initializer list
804          */
805         Op->Asl.Child->Asl.ParseOpcode = PARSEOP_INTEGER;
806         Op->Asl.Child->Asl.Value.Integer = PackageLength;
807         UtSetParseOpName (Op);
808 
809         /* Set the AML opcode */
810 
811         (void) OpcSetOptimalIntegerSize (Op->Asl.Child);
812     }
813 
814     /* If not a variable-length package, check for a zero package length */
815 
816     if ((PackageLengthOp->Asl.ParseOpcode == PARSEOP_INTEGER)      ||
817         (PackageLengthOp->Asl.ParseOpcode == PARSEOP_QWORDCONST)   ||
818         (PackageLengthOp->Asl.ParseOpcode == PARSEOP_ZERO)         ||
819         (PackageLengthOp->Asl.ParseOpcode == PARSEOP_DEFAULT_ARG))
820     {
821         if (!PackageLength)
822         {
823             /* No length AND no initializer list -- issue a remark */
824 
825             AslError (ASL_REMARK, ASL_MSG_PACKAGE_LENGTH,
826                 PackageLengthOp, NULL);
827 
828             /* But go ahead and put the buffer length of zero into the AML */
829         }
830     }
831 
832     /*
833      * If the PackageLength is a constant <= 255, we can change the
834      * AML opcode from VarPackage to a simple (ACPI 1.0) Package opcode.
835      */
836     if (((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) &&
837             (Op->Asl.Child->Asl.Value.Integer <= 255))  ||
838         (Op->Asl.Child->Asl.ParseOpcode == PARSEOP_ONE) ||
839         (Op->Asl.Child->Asl.ParseOpcode == PARSEOP_ONES)||
840         (Op->Asl.Child->Asl.ParseOpcode == PARSEOP_ZERO))
841     {
842         Op->Asl.AmlOpcode = AML_PACKAGE_OP;
843         Op->Asl.ParseOpcode = PARSEOP_PACKAGE;
844 
845         /*
846          * Just set the package size node to be the package length, regardless
847          * of whether it was previously an integer or a default_arg placeholder
848          */
849         PackageLengthOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
850         PackageLengthOp->Asl.AmlLength = 1;
851         PackageLengthOp->Asl.ParseOpcode = PARSEOP_RAW_DATA;
852         PackageLengthOp->Asl.Value.Integer = PackageLength;
853     }
854 
855     /* Remaining nodes are handled via the tree walk */
856 }
857 
858 
859 /*******************************************************************************
860  *
861  * FUNCTION:    OpnDoLoadTable
862  *
863  * PARAMETERS:  Op        - The parent parse node
864  *
865  * RETURN:      None
866  *
867  * DESCRIPTION: Construct the AML operands for the LOADTABLE ASL keyword.
868  *
869  ******************************************************************************/
870 
871 static void
OpnDoLoadTable(ACPI_PARSE_OBJECT * Op)872 OpnDoLoadTable (
873     ACPI_PARSE_OBJECT       *Op)
874 {
875     ACPI_PARSE_OBJECT       *Next;
876 
877 
878     /* Opcode is parent node */
879     /* First child is the table signature */
880 
881     Next = Op->Asl.Child;
882 
883     /* Second child is the OEM ID*/
884 
885     Next = Next->Asl.Next;
886 
887     /* Third child is the OEM table ID */
888 
889     Next = Next->Asl.Next;
890 
891     /* Fourth child is the RootPath string */
892 
893     Next = Next->Asl.Next;
894     if (Next->Asl.ParseOpcode == PARSEOP_ZERO)
895     {
896         Next->Asl.ParseOpcode = PARSEOP_STRING_LITERAL;
897         Next->Asl.Value.String = "\\";
898         Next->Asl.AmlLength = 2;
899         OpcGenerateAmlOpcode (Next);
900     }
901 
902 #ifdef ASL_FUTURE_IMPLEMENTATION
903 
904     /* TBD: NOT IMPLEMENTED */
905     /* Fifth child is the [optional] ParameterPathString */
906     /* Sixth child is the [optional] ParameterData */
907 
908     Next = Next->Asl.Next;
909     if (Next->Asl.ParseOpcode == DEFAULT_ARG)
910     {
911         Next->Asl.AmlLength = 1;
912         Next->Asl.ParseOpcode = ZERO;
913         OpcGenerateAmlOpcode (Next);
914     }
915 
916 
917     Next = Next->Asl.Next;
918     if (Next->Asl.ParseOpcode == DEFAULT_ARG)
919     {
920         Next->Asl.AmlLength = 1;
921         Next->Asl.ParseOpcode = ZERO;
922         OpcGenerateAmlOpcode (Next);
923     }
924 #endif
925 }
926 
927 
928 /*******************************************************************************
929  *
930  * FUNCTION:    OpnDoDefinitionBlock
931  *
932  * PARAMETERS:  Op        - The parent parse node
933  *
934  * RETURN:      None
935  *
936  * DESCRIPTION: Construct the AML operands for the DEFINITIONBLOCK ASL keyword
937  *
938  ******************************************************************************/
939 
940 static void
OpnDoDefinitionBlock(ACPI_PARSE_OBJECT * Op)941 OpnDoDefinitionBlock (
942     ACPI_PARSE_OBJECT       *Op)
943 {
944     ACPI_PARSE_OBJECT       *Child;
945     ACPI_SIZE               Length;
946     UINT32                  i;
947     char                    *Filename;
948     ACPI_STATUS             Status;
949 
950 
951     /*
952      * These nodes get stuffed into the table header. They are special
953      * cased when the table is written to the output file.
954      *
955      * Mark all of these nodes as non-usable so they won't get output
956      * as AML opcodes!
957      */
958 
959     /* Get AML filename. Use it if non-null */
960 
961     Child = Op->Asl.Child;
962     if (Child->Asl.Value.Buffer  &&
963         *Child->Asl.Value.Buffer &&
964         (AslGbl_UseDefaultAmlFilename))
965     {
966         /*
967          * The walk may traverse multiple definition blocks. Switch files
968          * to ensure that the correct files are manipulated.
969          */
970         FlSwitchFileSet (Op->Asl.Filename);
971 
972         /*
973          * We will use the AML filename that is embedded in the source file
974          * for the output filename.
975          */
976         Filename = UtLocalCacheCalloc (strlen (AslGbl_DirectoryPath) +
977             strlen ((char *) Child->Asl.Value.Buffer) + 1);
978 
979         /* Prepend the current directory path */
980 
981         strcpy (Filename, AslGbl_DirectoryPath);
982         strcat (Filename, (char *) Child->Asl.Value.Buffer);
983 
984         AslGbl_OutputFilenamePrefix = Filename;
985         UtConvertBackslashes (AslGbl_OutputFilenamePrefix);
986 
987         /*
988          * Use the definition block file parameter instead of the input
989          * filename. Since all files were opened previously, remove the
990          * existing file and open a new file with the name of this
991          * definition block parameter. Since AML code generation has yet
992          * to happen, the previous file can be removed without any impacts.
993          */
994         FlCloseFile (ASL_FILE_AML_OUTPUT);
995         FlDeleteFile (ASL_FILE_AML_OUTPUT);
996         Status = FlOpenAmlOutputFile (AslGbl_OutputFilenamePrefix);
997         if (ACPI_FAILURE (Status))
998         {
999             AslError (ASL_ERROR, ASL_MSG_OUTPUT_FILE_OPEN, NULL, NULL);
1000             return;
1001         }
1002     }
1003 
1004     Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
1005 
1006     /* Signature */
1007 
1008     Child = Child->Asl.Next;
1009     Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
1010     if (Child->Asl.Value.String)
1011     {
1012         AslGbl_FilesList->TableSignature = Child->Asl.Value.String;
1013         AslGbl_TableSignature = Child->Asl.Value.String;
1014         if (strlen (AslGbl_TableSignature) != ACPI_NAMESEG_SIZE)
1015         {
1016             AslError (ASL_ERROR, ASL_MSG_TABLE_SIGNATURE, Child,
1017                 "Length must be exactly 4 characters");
1018         }
1019 
1020         for (i = 0; i < ACPI_NAMESEG_SIZE; i++)
1021         {
1022             if (!isalnum ((int) AslGbl_TableSignature[i]))
1023             {
1024                 AslError (ASL_ERROR, ASL_MSG_TABLE_SIGNATURE, Child,
1025                     "Contains non-alphanumeric characters");
1026             }
1027         }
1028     }
1029 
1030     /* Revision */
1031 
1032     Child = Child->Asl.Next;
1033     Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
1034 
1035     /*
1036      * We used the revision to set the integer width earlier
1037      */
1038 
1039     /* OEMID */
1040 
1041     Child = Child->Asl.Next;
1042     Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
1043     if (Child->Asl.Value.String &&
1044         strlen (Child->Asl.Value.String) > ACPI_OEM_ID_SIZE)
1045     {
1046         AslError (ASL_ERROR, ASL_MSG_OEM_ID, Child,
1047             "Length cannot exceed 6 characters");
1048     }
1049 
1050     /* OEM TableID */
1051 
1052     Child = Child->Asl.Next;
1053     Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
1054     if (Child->Asl.Value.String)
1055     {
1056         Length = strlen (Child->Asl.Value.String);
1057         if (Length > ACPI_OEM_TABLE_ID_SIZE)
1058         {
1059             AslError (ASL_ERROR, ASL_MSG_OEM_TABLE_ID, Child,
1060                 "Length cannot exceed 8 characters");
1061         }
1062 
1063         AslGbl_TableId = UtLocalCacheCalloc (Length + 1);
1064         strcpy (AslGbl_TableId, Child->Asl.Value.String);
1065         AslGbl_FilesList->TableId = AslGbl_TableId;
1066 
1067         /*
1068          * Convert anything non-alphanumeric to an underscore. This
1069          * allows us to use the TableID to generate unique C symbols.
1070          */
1071         for (i = 0; i < Length; i++)
1072         {
1073             if (!isalnum ((int) AslGbl_TableId[i]))
1074             {
1075                 AslGbl_TableId[i] = '_';
1076             }
1077         }
1078     }
1079 
1080     /* OEM Revision */
1081 
1082     Child = Child->Asl.Next;
1083     Child->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
1084 }
1085 
1086 
1087 /*******************************************************************************
1088  *
1089  * FUNCTION:    UtGetArg
1090  *
1091  * PARAMETERS:  Op              - Get an argument for this op
1092  *              Argn            - Nth argument to get
1093  *
1094  * RETURN:      The argument (as an Op object). NULL if argument does not exist
1095  *
1096  * DESCRIPTION: Get the specified op's argument (peer)
1097  *
1098  ******************************************************************************/
1099 
1100 ACPI_PARSE_OBJECT *
UtGetArg(ACPI_PARSE_OBJECT * Op,UINT32 Argn)1101 UtGetArg (
1102     ACPI_PARSE_OBJECT       *Op,
1103     UINT32                  Argn)
1104 {
1105     ACPI_PARSE_OBJECT       *Arg = NULL;
1106 
1107 
1108     /* Get the requested argument object */
1109 
1110     Arg = Op->Asl.Child;
1111     while (Arg && Argn)
1112     {
1113         Argn--;
1114         Arg = Arg->Asl.Next;
1115     }
1116 
1117     return (Arg);
1118 }
1119 
1120 
1121 /*******************************************************************************
1122  *
1123  * FUNCTION:    OpnAttachNameToNode
1124  *
1125  * PARAMETERS:  Op        - The parent parse node
1126  *
1127  * RETURN:      None
1128  *
1129  * DESCRIPTION: For the named ASL/AML operators, get the actual name from the
1130  *              argument list and attach it to the parent node so that we
1131  *              can get to it quickly later.
1132  *
1133  ******************************************************************************/
1134 
1135 static void
OpnAttachNameToNode(ACPI_PARSE_OBJECT * Op)1136 OpnAttachNameToNode (
1137     ACPI_PARSE_OBJECT       *Op)
1138 {
1139     ACPI_PARSE_OBJECT       *Child = NULL;
1140 
1141 
1142     switch (Op->Asl.AmlOpcode)
1143     {
1144     case AML_DATA_REGION_OP:
1145     case AML_DEVICE_OP:
1146     case AML_EVENT_OP:
1147     case AML_EXTERNAL_OP:
1148     case AML_METHOD_OP:
1149     case AML_MUTEX_OP:
1150     case AML_REGION_OP:
1151     case AML_POWER_RESOURCE_OP:
1152     case AML_PROCESSOR_OP:
1153     case AML_THERMAL_ZONE_OP:
1154     case AML_NAME_OP:
1155     case AML_SCOPE_OP:
1156 
1157         Child = UtGetArg (Op, 0);
1158         break;
1159 
1160     case AML_ALIAS_OP:
1161 
1162         Child = UtGetArg (Op, 1);
1163         break;
1164 
1165     case AML_CREATE_BIT_FIELD_OP:
1166     case AML_CREATE_BYTE_FIELD_OP:
1167     case AML_CREATE_WORD_FIELD_OP:
1168     case AML_CREATE_DWORD_FIELD_OP:
1169     case AML_CREATE_QWORD_FIELD_OP:
1170 
1171         Child = UtGetArg (Op, 2);
1172         break;
1173 
1174     case AML_CREATE_FIELD_OP:
1175 
1176         Child = UtGetArg (Op, 3);
1177         break;
1178 
1179     case AML_BANK_FIELD_OP:
1180     case AML_INDEX_FIELD_OP:
1181     case AML_FIELD_OP:
1182 
1183         return;
1184 
1185     default:
1186 
1187         return;
1188     }
1189 
1190     if (Child)
1191     {
1192         UtAttachNamepathToOwner (Op, Child);
1193     }
1194 }
1195 
1196 
1197 /*******************************************************************************
1198  *
1199  * FUNCTION:    OpnGenerateAmlOperands
1200  *
1201  * PARAMETERS:  Op        - The parent parse node
1202  *
1203  * RETURN:      None
1204  *
1205  * DESCRIPTION: Prepare nodes to be output as AML data and operands. The more
1206  *              complex AML opcodes require processing of the child nodes
1207  *              (arguments/operands).
1208  *
1209  ******************************************************************************/
1210 
1211 void
OpnGenerateAmlOperands(ACPI_PARSE_OBJECT * Op)1212 OpnGenerateAmlOperands (
1213     ACPI_PARSE_OBJECT       *Op)
1214 {
1215 
1216 
1217     if (Op->Asl.AmlOpcode == AML_RAW_DATA_BYTE)
1218     {
1219         return;
1220     }
1221 
1222     switch (Op->Asl.ParseOpcode)
1223     {
1224     case PARSEOP_DEFINITION_BLOCK:
1225 
1226         OpnDoDefinitionBlock (Op);
1227         break;
1228 
1229     case PARSEOP_METHOD:
1230 
1231         OpnDoMethod (Op);
1232         break;
1233 
1234     case PARSEOP_MUTEX:
1235 
1236         OpnDoMutex (Op);
1237         break;
1238 
1239     case PARSEOP_FIELD:
1240 
1241         OpnDoField (Op);
1242         break;
1243 
1244     case PARSEOP_INDEXFIELD:
1245 
1246         OpnDoIndexField (Op);
1247         break;
1248 
1249     case PARSEOP_BANKFIELD:
1250 
1251         OpnDoBankField (Op);
1252         break;
1253 
1254     case PARSEOP_BUFFER:
1255 
1256         OpnDoBuffer (Op);
1257         break;
1258 
1259     case PARSEOP_LOADTABLE:
1260 
1261         OpnDoLoadTable (Op);
1262         break;
1263 
1264     case PARSEOP_OPERATIONREGION:
1265 
1266         OpnDoRegion (Op);
1267         break;
1268 
1269     case PARSEOP_RESOURCETEMPLATE:
1270 
1271         RsDoResourceTemplate (Op);
1272         break;
1273 
1274     case PARSEOP_NAMESEG:
1275     case PARSEOP_NAMESTRING:
1276     case PARSEOP_METHODCALL:
1277     case PARSEOP_STRING_LITERAL:
1278     default:
1279 
1280         break;
1281     }
1282 
1283     /* TBD: move */
1284 
1285     OpnAttachNameToNode (Op);
1286 }
1287