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