aslxref.c revision 1.17 1 /******************************************************************************
2 *
3 * Module Name: aslxref - Namespace cross-reference
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 "acparser.h"
47 #include "amlcode.h"
48 #include "acnamesp.h"
49 #include "acdispat.h"
50
51
52 #define _COMPONENT ACPI_COMPILER
53 ACPI_MODULE_NAME ("aslxref")
54
55 /* Local prototypes */
56
57 static ACPI_STATUS
58 XfNamespaceLocateBegin (
59 ACPI_PARSE_OBJECT *Op,
60 UINT32 Level,
61 void *Context);
62
63 static ACPI_STATUS
64 XfNamespaceLocateEnd (
65 ACPI_PARSE_OBJECT *Op,
66 UINT32 Level,
67 void *Context);
68
69 static BOOLEAN
70 XfValidateCrossReference (
71 ACPI_PARSE_OBJECT *Op,
72 const ACPI_OPCODE_INFO *OpInfo,
73 ACPI_NAMESPACE_NODE *Node);
74
75 static BOOLEAN
76 XfObjectExists (
77 char *Name);
78
79 static ACPI_STATUS
80 XfCompareOneNamespaceObject (
81 ACPI_HANDLE ObjHandle,
82 UINT32 Level,
83 void *Context,
84 void **ReturnValue);
85
86 static void
87 XfCheckFieldRange (
88 ACPI_PARSE_OBJECT *Op,
89 UINT32 RegionBitLength,
90 UINT32 FieldBitOffset,
91 UINT32 FieldBitLength,
92 UINT32 AccessBitWidth);
93
94
95 /*******************************************************************************
96 *
97 * FUNCTION: XfCrossReferenceNamespace
98 *
99 * PARAMETERS: None
100 *
101 * RETURN: Status
102 *
103 * DESCRIPTION: Perform a cross reference check of the parse tree against the
104 * namespace. Every named referenced within the parse tree
105 * should be get resolved with a namespace lookup. If not, the
106 * original reference in the ASL code is invalid -- i.e., refers
107 * to a non-existent object.
108 *
109 * NOTE: The ASL "External" operator causes the name to be inserted into the
110 * namespace so that references to the external name will be resolved
111 * correctly here.
112 *
113 ******************************************************************************/
114
115 ACPI_STATUS
116 XfCrossReferenceNamespace (
117 void)
118 {
119 ACPI_WALK_STATE *WalkState;
120
121
122 /*
123 * Create a new walk state for use when looking up names
124 * within the namespace (Passed as context to the callbacks)
125 */
126 WalkState = AcpiDsCreateWalkState (0, NULL, NULL, NULL);
127 if (!WalkState)
128 {
129 return (AE_NO_MEMORY);
130 }
131
132 /* Walk the entire parse tree */
133
134 TrWalkParseTree (AslGbl_ParseTreeRoot, ASL_WALK_VISIT_TWICE,
135 XfNamespaceLocateBegin, XfNamespaceLocateEnd, WalkState);
136
137 ACPI_FREE (WalkState);
138 return (AE_OK);
139 }
140
141
142 /*******************************************************************************
143 *
144 * FUNCTION: XfObjectExists
145 *
146 * PARAMETERS: Name - 4 char ACPI name
147 *
148 * RETURN: TRUE if name exists in namespace
149 *
150 * DESCRIPTION: Walk the namespace to find an object
151 *
152 ******************************************************************************/
153
154 static BOOLEAN
155 XfObjectExists (
156 char *Name)
157 {
158 ACPI_STATUS Status;
159
160
161 /* Walk entire namespace from the supplied root */
162
163 Status = AcpiNsWalkNamespace (ACPI_TYPE_ANY, ACPI_ROOT_OBJECT,
164 ACPI_UINT32_MAX, FALSE, XfCompareOneNamespaceObject, NULL,
165 Name, NULL);
166 if (Status == AE_CTRL_TRUE)
167 {
168 /* At least one instance of the name was found */
169
170 return (TRUE);
171 }
172
173 return (FALSE);
174 }
175
176
177 /*******************************************************************************
178 *
179 * FUNCTION: XfCompareOneNamespaceObject
180 *
181 * PARAMETERS: ACPI_WALK_CALLBACK
182 *
183 * RETURN: Status
184 *
185 * DESCRIPTION: Compare name of one object.
186 *
187 ******************************************************************************/
188
189 static ACPI_STATUS
190 XfCompareOneNamespaceObject (
191 ACPI_HANDLE ObjHandle,
192 UINT32 Level,
193 void *Context,
194 void **ReturnValue)
195 {
196 ACPI_NAMESPACE_NODE *Node = (ACPI_NAMESPACE_NODE *) ObjHandle;
197
198
199 /* Simply check the name */
200
201 if (*((UINT32 *) (Context)) == Node->Name.Integer)
202 {
203 /* Abort walk if we found one instance */
204
205 return (AE_CTRL_TRUE);
206 }
207
208 return (AE_OK);
209 }
210
211
212 /*******************************************************************************
213 *
214 * FUNCTION: XfCheckFieldRange
215 *
216 * PARAMETERS: RegionBitLength - Length of entire parent region
217 * FieldBitOffset - Start of the field unit (within region)
218 * FieldBitLength - Entire length of field unit
219 * AccessBitWidth - Access width of the field unit
220 *
221 * RETURN: None
222 *
223 * DESCRIPTION: Check one field unit to make sure it fits in the parent
224 * op region.
225 *
226 * Note: AccessBitWidth must be either 8,16,32, or 64
227 *
228 ******************************************************************************/
229
230 static void
231 XfCheckFieldRange (
232 ACPI_PARSE_OBJECT *Op,
233 UINT32 RegionBitLength,
234 UINT32 FieldBitOffset,
235 UINT32 FieldBitLength,
236 UINT32 AccessBitWidth)
237 {
238 UINT32 FieldEndBitOffset;
239
240
241 /*
242 * Check each field unit against the region size. The entire
243 * field unit (start offset plus length) must fit within the
244 * region.
245 */
246 FieldEndBitOffset = FieldBitOffset + FieldBitLength;
247
248 if (FieldEndBitOffset > RegionBitLength)
249 {
250 /* Field definition itself is beyond the end-of-region */
251
252 AslError (ASL_ERROR, ASL_MSG_FIELD_UNIT_OFFSET, Op, NULL);
253 return;
254 }
255
256 /*
257 * Now check that the field plus AccessWidth doesn't go beyond
258 * the end-of-region. Assumes AccessBitWidth is a power of 2
259 */
260 FieldEndBitOffset = ACPI_ROUND_UP (FieldEndBitOffset, AccessBitWidth);
261
262 if (FieldEndBitOffset > RegionBitLength)
263 {
264 /* Field definition combined with the access is beyond EOR */
265
266 AslError (ASL_ERROR, ASL_MSG_FIELD_UNIT_ACCESS_WIDTH, Op, NULL);
267 }
268 }
269
270
271 /*******************************************************************************
272 *
273 * FUNCTION: XfNamespaceLocateBegin
274 *
275 * PARAMETERS: ASL_WALK_CALLBACK
276 *
277 * RETURN: Status
278 *
279 * DESCRIPTION: Descending callback used during cross-reference. For named
280 * object references, attempt to locate the name in the
281 * namespace.
282 *
283 * NOTE: ASL references to named fields within resource descriptors are
284 * resolved to integer values here. Therefore, this step is an
285 * important part of the code generation. We don't know that the
286 * name refers to a resource descriptor until now.
287 *
288 ******************************************************************************/
289
290 static ACPI_STATUS
291 XfNamespaceLocateBegin (
292 ACPI_PARSE_OBJECT *Op,
293 UINT32 Level,
294 void *Context)
295 {
296 ACPI_WALK_STATE *WalkState = (ACPI_WALK_STATE *) Context;
297 ACPI_NAMESPACE_NODE *Node;
298 ACPI_STATUS Status;
299 ACPI_OBJECT_TYPE ObjectType;
300 char *Path;
301 UINT8 PassedArgs;
302 ACPI_PARSE_OBJECT *NextOp;
303 ACPI_PARSE_OBJECT *OwningOp;
304 ACPI_PARSE_OBJECT *SpaceIdOp;
305 UINT32 MinimumLength;
306 UINT32 Offset;
307 UINT32 FieldBitLength;
308 UINT32 TagBitLength;
309 UINT8 Message = 0;
310 const ACPI_OPCODE_INFO *OpInfo;
311 UINT32 Flags;
312 ASL_METHOD_LOCAL *MethodLocals = NULL;
313 ASL_METHOD_LOCAL *MethodArgs = NULL;
314 int RegisterNumber;
315 UINT32 i;
316 ACPI_NAMESPACE_NODE *DeclarationParentMethod;
317 ACPI_PARSE_OBJECT *ReferenceParentMethod;
318
319
320 ACPI_FUNCTION_TRACE_PTR (XfNamespaceLocateBegin, Op);
321
322
323 if ((Op->Asl.AmlOpcode == AML_METHOD_OP) && Op->Asl.Node)
324 {
325 Node = Op->Asl.Node;
326
327 /* Support for method LocalX/ArgX analysis */
328
329 if (!Node->MethodLocals)
330 {
331 /* Create local/arg info blocks */
332
333 MethodLocals = UtLocalCalloc (
334 sizeof (ASL_METHOD_LOCAL) * ACPI_METHOD_NUM_LOCALS);
335 Node->MethodLocals = MethodLocals;
336
337 MethodArgs = UtLocalCalloc (
338 sizeof (ASL_METHOD_LOCAL) * ACPI_METHOD_NUM_ARGS);
339 Node->MethodArgs = MethodArgs;
340
341 /*
342 * Get the method argument count
343 * First, get the name node
344 */
345 NextOp = Op->Asl.Child;
346
347 /* Get the NumArguments node */
348
349 NextOp = NextOp->Asl.Next;
350 Node->ArgCount = (UINT8)
351 (((UINT8) NextOp->Asl.Value.Integer) & 0x07);
352
353 /* We will track all possible ArgXs */
354
355 for (i = 0; i < ACPI_METHOD_NUM_ARGS; i++)
356 {
357 if (i < Node->ArgCount)
358 {
359 /* Real Args are always "initialized" */
360
361 MethodArgs[i].Flags = ASL_ARG_INITIALIZED;
362 }
363 else
364 {
365 /* Other ArgXs can be used as locals */
366
367 MethodArgs[i].Flags = ASL_ARG_IS_LOCAL;
368 }
369
370 MethodArgs[i].Op = Op;
371 }
372 }
373 }
374
375 /*
376 * If this node is the actual declaration of a name
377 * [such as the XXXX name in "Method (XXXX)"],
378 * we are not interested in it here. We only care about names that are
379 * references to other objects within the namespace and the parent objects
380 * of name declarations
381 */
382 if (Op->Asl.CompileFlags & OP_IS_NAME_DECLARATION)
383 {
384 return_ACPI_STATUS (AE_OK);
385 }
386
387 OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
388
389 /* Check method LocalX variables */
390
391 if (OpInfo->Type == AML_TYPE_LOCAL_VARIABLE)
392 {
393 /* Find parent method Op */
394
395 NextOp = UtGetParentMethodOp (Op);
396 if (!NextOp)
397 {
398 return_ACPI_STATUS (AE_OK);
399 }
400
401 /* Get method node */
402
403 Node = NextOp->Asl.Node;
404
405 RegisterNumber = Op->Asl.AmlOpcode & 0x0007; /* 0x60 through 0x67 */
406 MethodLocals = Node->MethodLocals;
407
408 if (Op->Asl.CompileFlags & OP_IS_TARGET)
409 {
410 /* Local is being initialized */
411
412 MethodLocals[RegisterNumber].Flags |= ASL_LOCAL_INITIALIZED;
413 MethodLocals[RegisterNumber].Op = Op;
414
415 return_ACPI_STATUS (AE_OK);
416 }
417
418 /* Mark this Local as referenced */
419
420 MethodLocals[RegisterNumber].Flags |= ASL_LOCAL_REFERENCED;
421 MethodLocals[RegisterNumber].Op = Op;
422
423 return_ACPI_STATUS (AE_OK);
424 }
425
426 /* Check method ArgX variables */
427
428 if (OpInfo->Type == AML_TYPE_METHOD_ARGUMENT)
429 {
430 /* Find parent method Op */
431
432 NextOp = UtGetParentMethodOp (Op);
433 if (!NextOp)
434 {
435 return_ACPI_STATUS (AE_OK);
436 }
437
438 /* Get method node */
439
440 Node = NextOp->Asl.Node;
441
442 /* Get Arg # */
443
444 RegisterNumber = Op->Asl.AmlOpcode - AML_ARG0; /* 0x68 through 0x6F */
445 MethodArgs = Node->MethodArgs;
446
447 /* Mark this Arg as referenced */
448
449 MethodArgs[RegisterNumber].Flags |= ASL_ARG_REFERENCED;
450 MethodArgs[RegisterNumber].Op = Op;
451
452 if (Op->Asl.CompileFlags & OP_IS_TARGET)
453 {
454 /* Arg is being initialized */
455
456 MethodArgs[RegisterNumber].Flags |= ASL_ARG_INITIALIZED;
457 }
458
459 return_ACPI_STATUS (AE_OK);
460 }
461
462 /*
463 * After method ArgX and LocalX, we are only interested in opcodes
464 * that have an associated name
465 */
466 if ((!(OpInfo->Flags & AML_NAMED)) &&
467 (!(OpInfo->Flags & AML_CREATE)) &&
468 (Op->Asl.ParseOpcode != PARSEOP_NAMESTRING) &&
469 (Op->Asl.ParseOpcode != PARSEOP_NAMESEG) &&
470 (Op->Asl.ParseOpcode != PARSEOP_METHODCALL) &&
471 (Op->Asl.ParseOpcode != PARSEOP_EXTERNAL))
472 {
473 return_ACPI_STATUS (AE_OK);
474 }
475
476 /*
477 * One special case: CondRefOf operator - we don't care if the name exists
478 * or not at this point, just ignore it, the point of the operator is to
479 * determine if the name exists at runtime.
480 */
481 if ((Op->Asl.Parent) &&
482 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONDREFOF))
483 {
484 return_ACPI_STATUS (AE_OK);
485 }
486
487 /*
488 * We must enable the "search-to-root" for single NameSegs, but
489 * we have to be very careful about opening up scopes
490 */
491 Flags = ACPI_NS_SEARCH_PARENT;
492 if ((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) ||
493 (Op->Asl.ParseOpcode == PARSEOP_NAMESEG) ||
494 (Op->Asl.ParseOpcode == PARSEOP_METHODCALL) ||
495 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL))
496 {
497 /*
498 * These are name references, do not push the scope stack
499 * for them.
500 */
501 Flags |= ACPI_NS_DONT_OPEN_SCOPE;
502 }
503
504 /* Get the NamePath from the appropriate place */
505
506 if (OpInfo->Flags & AML_NAMED)
507 {
508 /* For nearly all NAMED operators, the name reference is the first child */
509
510 Path = Op->Asl.Child->Asl.Value.String;
511 if (Op->Asl.AmlOpcode == AML_ALIAS_OP)
512 {
513 /*
514 * ALIAS is the only oddball opcode, the name declaration
515 * (alias name) is the second operand
516 */
517 Path = Op->Asl.Child->Asl.Next->Asl.Value.String;
518 }
519 }
520 else if (OpInfo->Flags & AML_CREATE)
521 {
522 /* Name must appear as the last parameter */
523
524 NextOp = Op->Asl.Child;
525 while (!(NextOp->Asl.CompileFlags & OP_IS_NAME_DECLARATION))
526 {
527 NextOp = NextOp->Asl.Next;
528 }
529
530 Path = NextOp->Asl.Value.String;
531 }
532 else
533 {
534 Path = Op->Asl.Value.String;
535 }
536
537 ObjectType = AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode);
538 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
539 "Type=%s\n", AcpiUtGetTypeName (ObjectType)));
540
541 /*
542 * Lookup the name in the namespace. Name must exist at this point, or it
543 * is an invalid reference.
544 *
545 * The namespace is also used as a lookup table for references to resource
546 * descriptors and the fields within them.
547 */
548 AslGbl_NsLookupCount++;
549
550 Status = AcpiNsLookup (WalkState->ScopeInfo, Path, ObjectType,
551 ACPI_IMODE_EXECUTE, Flags, WalkState, &Node);
552 if (ACPI_FAILURE (Status))
553 {
554 if (Status == AE_NOT_FOUND)
555 {
556 /*
557 * We didn't find the name reference by path -- we can qualify this
558 * a little better before we print an error message
559 */
560 if (strlen (Path) == ACPI_NAMESEG_SIZE)
561 {
562 /* A simple, one-segment ACPI name */
563
564 if (XfObjectExists (Path))
565 {
566 /*
567 * There exists such a name, but we couldn't get to it
568 * from this scope
569 */
570 AslError (ASL_ERROR, ASL_MSG_NOT_REACHABLE, Op,
571 Op->Asl.ExternalName);
572 }
573 else
574 {
575 /* The name doesn't exist, period */
576
577 AslError (ASL_ERROR, ASL_MSG_NOT_EXIST,
578 Op, Op->Asl.ExternalName);
579 }
580 }
581 else
582 {
583 /* The NamePath contains multiple NameSegs */
584
585 if ((OpInfo->Flags & AML_CREATE) ||
586 (OpInfo->ObjectType == ACPI_TYPE_LOCAL_ALIAS))
587 {
588 /*
589 * The new name is the last parameter. For the
590 * CreateXXXXField and Alias operators
591 */
592 NextOp = Op->Asl.Child;
593 while (!(NextOp->Asl.CompileFlags & OP_IS_NAME_DECLARATION))
594 {
595 NextOp = NextOp->Asl.Next;
596 }
597
598 AslError (ASL_ERROR, ASL_MSG_PREFIX_NOT_EXIST, NextOp,
599 NextOp->Asl.ExternalName);
600 }
601 else if (OpInfo->Flags & AML_NAMED)
602 {
603 /* The new name is the first parameter */
604
605 AslError (ASL_ERROR, ASL_MSG_PREFIX_NOT_EXIST, Op,
606 Op->Asl.ExternalName);
607 }
608 else if (Path[0] == AML_ROOT_PREFIX)
609 {
610 /* Full namepath from root, the object does not exist */
611
612 AslError (ASL_ERROR, ASL_MSG_NOT_EXIST, Op,
613 Op->Asl.ExternalName);
614 }
615 else
616 {
617 /*
618 * Generic "not found" error. Cannot determine whether it
619 * doesn't exist or just can't be reached. However, we
620 * can differentiate between a NameSeg vs. NamePath.
621 */
622 if (strlen (Op->Asl.ExternalName) == ACPI_NAMESEG_SIZE)
623 {
624 AslError (ASL_ERROR, ASL_MSG_NOT_FOUND, Op,
625 Op->Asl.ExternalName);
626 }
627 else
628 {
629 AslError (ASL_ERROR, ASL_MSG_NAMEPATH_NOT_EXIST, Op,
630 Op->Asl.ExternalName);
631 }
632 }
633 }
634
635 Status = AE_OK;
636 }
637
638 return_ACPI_STATUS (Status);
639 }
640
641 /* Check for an attempt to access an object in another method */
642
643 if (!XfValidateCrossReference (Op, OpInfo, Node))
644 {
645 AslError (ASL_ERROR, ASL_MSG_TEMPORARY_OBJECT, Op,
646 Op->Asl.ExternalName);
647 return_ACPI_STATUS (Status);
648 }
649
650 /* Object was found above, check for an illegal forward reference */
651
652 if (Op->Asl.CompileFlags & OP_NOT_FOUND_DURING_LOAD)
653 {
654 /*
655 * During the load phase, this Op was flagged as a possible
656 * illegal forward reference. In other words, Op is a name path or
657 * name segment that refers to a named object declared after the
658 * reference. In this scinario, Node refers to the actual declaration
659 * and Op is a parse node that references the named object.
660 *
661 * Note:
662 *
663 * Object references inside of control methods are allowed to
664 * refer to objects declared outside of control methods.
665 *
666 * If the declaration and reference are both contained inside of the
667 * same method or outside of any method, this is a forward reference
668 * and should be reported as a compiler error.
669 */
670 DeclarationParentMethod = UtGetParentMethodNode (Node);
671 ReferenceParentMethod = UtGetParentMethodOp (Op);
672
673 /* case 1: declaration and reference are both outside of method */
674
675 if (!ReferenceParentMethod && !DeclarationParentMethod)
676 {
677 AslError (ASL_ERROR, ASL_MSG_ILLEGAL_FORWARD_REF, Op,
678 Op->Asl.ExternalName);
679 }
680
681 /* case 2: declaration and reference are both inside of the same method */
682
683 else if (ReferenceParentMethod && DeclarationParentMethod &&
684 ReferenceParentMethod == DeclarationParentMethod->Op)
685 {
686 AslError (ASL_ERROR, ASL_MSG_ILLEGAL_FORWARD_REF, Op,
687 Op->Asl.ExternalName);
688 }
689 }
690
691 /* Check for a reference vs. name declaration */
692
693 if (!(OpInfo->Flags & AML_NAMED) &&
694 !(OpInfo->Flags & AML_CREATE))
695 {
696 /* This node has been referenced, mark it for reference check */
697
698 Node->Flags |= ANOBJ_IS_REFERENCED;
699 }
700
701 /* Attempt to optimize the NamePath */
702
703 OptOptimizeNamePath (Op, OpInfo->Flags, WalkState, Path, Node);
704
705 /*
706 * 1) Dereference an alias (A name reference that is an alias)
707 * Aliases are not nested, the alias always points to the final object
708 */
709 if ((Op->Asl.ParseOpcode != PARSEOP_ALIAS) &&
710 (Node->Type == ACPI_TYPE_LOCAL_ALIAS))
711 {
712 /* This node points back to the original PARSEOP_ALIAS */
713
714 NextOp = Node->Op;
715
716 /* The first child is the alias target op */
717
718 NextOp = NextOp->Asl.Child;
719
720 /* That in turn points back to original target alias node */
721
722 if (NextOp->Asl.Node)
723 {
724 Node = NextOp->Asl.Node;
725 }
726
727 /* Else - forward reference to alias, will be resolved later */
728 }
729
730 /* 2) Check for a reference to a resource descriptor */
731
732 if ((Node->Type == ACPI_TYPE_LOCAL_RESOURCE_FIELD) ||
733 (Node->Type == ACPI_TYPE_LOCAL_RESOURCE))
734 {
735 /*
736 * This was a reference to a field within a resource descriptor.
737 * Extract the associated field offset (either a bit or byte
738 * offset depending on the field type) and change the named
739 * reference into an integer for AML code generation
740 */
741 Offset = Node->Value;
742 TagBitLength = Node->Length;
743
744 /*
745 * If a field is being created, generate the length (in bits) of
746 * the field. Note: Opcodes other than CreateXxxField and Index
747 * can come through here. For other opcodes, we just need to
748 * convert the resource tag reference to an integer offset.
749 */
750 switch (Op->Asl.Parent->Asl.AmlOpcode)
751 {
752 case AML_CREATE_FIELD_OP: /* Variable "Length" field, in bits */
753 /*
754 * We know the length operand is an integer constant because
755 * we know that it contains a reference to a resource
756 * descriptor tag.
757 */
758 FieldBitLength = (UINT32) Op->Asl.Next->Asl.Value.Integer;
759 break;
760
761 case AML_CREATE_BIT_FIELD_OP:
762
763 FieldBitLength = 1;
764 break;
765
766 case AML_CREATE_BYTE_FIELD_OP:
767 case AML_INDEX_OP:
768
769 FieldBitLength = 8;
770 break;
771
772 case AML_CREATE_WORD_FIELD_OP:
773
774 FieldBitLength = 16;
775 break;
776
777 case AML_CREATE_DWORD_FIELD_OP:
778
779 FieldBitLength = 32;
780 break;
781
782 case AML_CREATE_QWORD_FIELD_OP:
783
784 FieldBitLength = 64;
785 break;
786
787 default:
788
789 FieldBitLength = 0;
790 break;
791 }
792
793 /* Check the field length against the length of the resource tag */
794
795 if (FieldBitLength)
796 {
797 if (TagBitLength < FieldBitLength)
798 {
799 Message = ASL_MSG_TAG_SMALLER;
800 }
801 else if (TagBitLength > FieldBitLength)
802 {
803 Message = ASL_MSG_TAG_LARGER;
804 }
805
806 if (Message)
807 {
808 snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer),
809 "Size mismatch, Tag: %u bit%s, Field: %u bit%s",
810 TagBitLength, (TagBitLength > 1) ? "s" : "",
811 FieldBitLength, (FieldBitLength > 1) ? "s" : "");
812
813 AslError (ASL_WARNING, Message, Op, AslGbl_MsgBuffer);
814 }
815 }
816
817 /* Convert the BitOffset to a ByteOffset for certain opcodes */
818
819 switch (Op->Asl.Parent->Asl.AmlOpcode)
820 {
821 case AML_CREATE_BYTE_FIELD_OP:
822 case AML_CREATE_WORD_FIELD_OP:
823 case AML_CREATE_DWORD_FIELD_OP:
824 case AML_CREATE_QWORD_FIELD_OP:
825 case AML_INDEX_OP:
826
827 Offset = ACPI_DIV_8 (Offset);
828 break;
829
830 default:
831
832 break;
833 }
834
835 /* Now convert this node to an integer whose value is the field offset */
836
837 Op->Asl.AmlLength = 0;
838 Op->Asl.ParseOpcode = PARSEOP_INTEGER;
839 Op->Asl.Value.Integer = (UINT64) Offset;
840 Op->Asl.CompileFlags |= OP_IS_RESOURCE_FIELD;
841
842 OpcGenerateAmlOpcode (Op);
843 }
844
845 /* 3) Check for a method invocation */
846
847 else if ((((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) || (Op->Asl.ParseOpcode == PARSEOP_NAMESEG)) &&
848 (Node->Type == ACPI_TYPE_METHOD) &&
849 (Op->Asl.Parent) &&
850 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_METHOD)) ||
851
852 (Op->Asl.ParseOpcode == PARSEOP_METHODCALL))
853 {
854 /*
855 * A reference to a method within one of these opcodes is not an
856 * invocation of the method, it is simply a reference to the method.
857 *
858 * September 2016: Removed DeRefOf from this list
859 */
860 if ((Op->Asl.Parent) &&
861 ((Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_REFOF) ||
862 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
863 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE)||
864 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_OBJECTTYPE)))
865 {
866 return_ACPI_STATUS (AE_OK);
867 }
868
869 /*
870 * There are two types of method invocation:
871 * 1) Invocation with arguments -- the parser recognizes this
872 * as a METHODCALL.
873 * 2) Invocation with no arguments --the parser cannot determine that
874 * this is a method invocation, therefore we have to figure it out
875 * here.
876 */
877 if (Node->Type != ACPI_TYPE_METHOD)
878 {
879 snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer), "%s is a %s",
880 Op->Asl.ExternalName, AcpiUtGetTypeName (Node->Type));
881
882 AslError (ASL_ERROR, ASL_MSG_NOT_METHOD, Op, AslGbl_MsgBuffer);
883 return_ACPI_STATUS (AE_OK);
884 }
885
886 /* Save the method node in the caller's op */
887
888 Op->Asl.Node = Node;
889 if (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONDREFOF)
890 {
891 return_ACPI_STATUS (AE_OK);
892 }
893
894 /*
895 * This is a method invocation, with or without arguments.
896 * Count the number of arguments, each appears as a child
897 * under the parent node
898 */
899 Op->Asl.ParseOpcode = PARSEOP_METHODCALL;
900 UtSetParseOpName (Op);
901
902 PassedArgs = 0;
903 NextOp = Op->Asl.Child;
904
905 while (NextOp)
906 {
907 PassedArgs++;
908 NextOp = NextOp->Asl.Next;
909 }
910
911 if (Node->Value != ASL_EXTERNAL_METHOD_UNKNOWN_PARAMS &&
912 Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_EXTERNAL)
913 {
914 /*
915 * Check the parsed arguments with the number expected by the
916 * method declaration itself
917 */
918 if (PassedArgs != Node->Value)
919 {
920 if (Node->Flags & ANOBJ_IS_EXTERNAL)
921 {
922 snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer),
923 "according to previous use, %s requires %u",
924 Op->Asl.ExternalName, Node->Value);
925 }
926 else
927 {
928 snprintf (AslGbl_MsgBuffer, sizeof(AslGbl_MsgBuffer),
929 "%s requires %u", Op->Asl.ExternalName,
930 Node->Value);
931 }
932
933 if (PassedArgs < Node->Value)
934 {
935 AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_LO, Op, AslGbl_MsgBuffer);
936 }
937 else
938 {
939 AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_HI, Op, AslGbl_MsgBuffer);
940 }
941 }
942 }
943
944 /*
945 * At this point, a method call to an external method has been
946 * detected. As of 11/19/2019, iASL does not support parameter counts
947 * for methods declared as external. Therefore, save the parameter
948 * count of the first method call and use this count check other
949 * method calls to ensure that the methods are being called with the
950 * same amount of parameters.
951 */
952 else if (Node->Type == ACPI_TYPE_METHOD &&
953 (Node->Flags & ANOBJ_IS_EXTERNAL) &&
954 Node->Value == ASL_EXTERNAL_METHOD_UNKNOWN_PARAMS &&
955 Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_EXTERNAL)
956 {
957 Node->Value = PassedArgs;
958 }
959 }
960
961 /* 4) Check for an ASL Field definition */
962
963 else if ((Op->Asl.Parent) &&
964 ((Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_FIELD) ||
965 (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_BANKFIELD)))
966 {
967 /*
968 * Offset checking for fields. If the parent operation region has a
969 * constant length (known at compile time), we can check fields
970 * defined in that region against the region length. This will catch
971 * fields and field units that cannot possibly fit within the region.
972 *
973 * Note: Index fields do not directly reference an operation region,
974 * thus they are not included in this check.
975 */
976 if (Op == Op->Asl.Parent->Asl.Child)
977 {
978 /*
979 * This is the first child of the field node, which is
980 * the name of the region. Get the parse node for the
981 * region -- which contains the length of the region.
982 */
983 OwningOp = Node->Op;
984 Op->Asl.Parent->Asl.ExtraValue =
985 ACPI_MUL_8 ((UINT32) OwningOp->Asl.Value.Integer);
986
987 /* Examine the field access width */
988
989 switch ((UINT8) Op->Asl.Parent->Asl.Value.Integer)
990 {
991 case AML_FIELD_ACCESS_ANY:
992 case AML_FIELD_ACCESS_BYTE:
993 case AML_FIELD_ACCESS_BUFFER:
994 default:
995
996 MinimumLength = 1;
997 break;
998
999 case AML_FIELD_ACCESS_WORD:
1000
1001 MinimumLength = 2;
1002 break;
1003
1004 case AML_FIELD_ACCESS_DWORD:
1005
1006 MinimumLength = 4;
1007 break;
1008
1009 case AML_FIELD_ACCESS_QWORD:
1010
1011 MinimumLength = 8;
1012 break;
1013 }
1014
1015 /*
1016 * Is the region at least as big as the access width?
1017 * Note: DataTableRegions have 0 length
1018 */
1019 if (((UINT32) OwningOp->Asl.Value.Integer) &&
1020 ((UINT32) OwningOp->Asl.Value.Integer < MinimumLength))
1021 {
1022 AslError (ASL_ERROR, ASL_MSG_FIELD_ACCESS_WIDTH, Op, NULL);
1023 }
1024
1025 /*
1026 * Check EC/CMOS/SMBUS fields to make sure that the correct
1027 * access type is used (BYTE for EC/CMOS, BUFFER for SMBUS)
1028 */
1029 SpaceIdOp = OwningOp->Asl.Child->Asl.Next;
1030 switch ((UINT32) SpaceIdOp->Asl.Value.Integer)
1031 {
1032 case ACPI_ADR_SPACE_EC:
1033 case ACPI_ADR_SPACE_CMOS:
1034 case ACPI_ADR_SPACE_GPIO:
1035
1036 if ((UINT8) Op->Asl.Parent->Asl.Value.Integer !=
1037 AML_FIELD_ACCESS_BYTE)
1038 {
1039 AslError (ASL_ERROR, ASL_MSG_REGION_BYTE_ACCESS, Op, NULL);
1040 }
1041 break;
1042
1043 case ACPI_ADR_SPACE_SMBUS:
1044 case ACPI_ADR_SPACE_IPMI:
1045 case ACPI_ADR_SPACE_GSBUS:
1046
1047 if ((UINT8) Op->Asl.Parent->Asl.Value.Integer !=
1048 AML_FIELD_ACCESS_BUFFER)
1049 {
1050 AslError (ASL_ERROR, ASL_MSG_REGION_BUFFER_ACCESS, Op, NULL);
1051 }
1052 break;
1053
1054 default:
1055
1056 /* Nothing to do for other address spaces */
1057
1058 break;
1059 }
1060 }
1061 else
1062 {
1063 /*
1064 * This is one element of the field list. Check to make sure
1065 * that it does not go beyond the end of the parent operation region.
1066 *
1067 * In the code below:
1068 * Op->Asl.Parent->Asl.ExtraValue - Region Length (bits)
1069 * Op->Asl.ExtraValue - Field start offset (bits)
1070 * Op->Asl.Child->Asl.Value.Integer32 - Field length (bits)
1071 * Op->Asl.Child->Asl.ExtraValue - Field access width (bits)
1072 */
1073 if (Op->Asl.Parent->Asl.ExtraValue && Op->Asl.Child)
1074 {
1075 XfCheckFieldRange (Op,
1076 Op->Asl.Parent->Asl.ExtraValue,
1077 Op->Asl.ExtraValue,
1078 (UINT32) Op->Asl.Child->Asl.Value.Integer,
1079 Op->Asl.Child->Asl.ExtraValue);
1080 }
1081 }
1082 }
1083
1084 /*
1085 * 5) Check for external resolution
1086 * By this point, everything should be loaded in the namespace. If a
1087 * namespace lookup results in a namespace node that is an external, it
1088 * means that this named object was not defined in the input ASL. This
1089 * causes issues because there are plenty of incidents where developers
1090 * use the external keyword to suppress compiler errors about undefined
1091 * objects. Note: this only applies when compiling multiple definition
1092 * blocks.
1093 */
1094 if (AslGbl_ParseTreeRoot->Asl.Child && AslGbl_ParseTreeRoot->Asl.Child->Asl.Next &&
1095 (Op->Asl.ParseOpcode != PARSEOP_EXTERNAL &&
1096 Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_EXTERNAL) &&
1097 (Node->Flags & ANOBJ_IS_EXTERNAL))
1098 {
1099 AslError (ASL_ERROR, ASL_MSG_UNDEFINED_EXTERNAL, Op, NULL);
1100 }
1101
1102 /* 5) Check for a connection object */
1103 #if 0
1104 else if (Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_CONNECTION)
1105 {
1106 return_ACPI_STATUS (Status);
1107 }
1108 #endif
1109
1110 Op->Asl.Node = Node;
1111 return_ACPI_STATUS (Status);
1112 }
1113
1114
1115 /*******************************************************************************
1116 *
1117 * FUNCTION: XfNamespaceLocateEnd
1118 *
1119 * PARAMETERS: ASL_WALK_CALLBACK
1120 *
1121 * RETURN: Status
1122 *
1123 * DESCRIPTION: Ascending callback used during cross reference. We only
1124 * need to worry about scope management here.
1125 *
1126 ******************************************************************************/
1127
1128 static ACPI_STATUS
1129 XfNamespaceLocateEnd (
1130 ACPI_PARSE_OBJECT *Op,
1131 UINT32 Level,
1132 void *Context)
1133 {
1134 ACPI_WALK_STATE *WalkState = (ACPI_WALK_STATE *) Context;
1135 const ACPI_OPCODE_INFO *OpInfo;
1136
1137
1138 ACPI_FUNCTION_TRACE (XfNamespaceLocateEnd);
1139
1140
1141 /* We are only interested in opcodes that have an associated name */
1142
1143 OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
1144 if (!(OpInfo->Flags & AML_NAMED))
1145 {
1146 return_ACPI_STATUS (AE_OK);
1147 }
1148
1149 /* Not interested in name references, we did not open a scope for them */
1150
1151 if ((Op->Asl.ParseOpcode == PARSEOP_NAMESTRING) ||
1152 (Op->Asl.ParseOpcode == PARSEOP_NAMESEG) ||
1153 (Op->Asl.ParseOpcode == PARSEOP_METHODCALL) ||
1154 (Op->Asl.ParseOpcode == PARSEOP_EXTERNAL))
1155 {
1156 return_ACPI_STATUS (AE_OK);
1157 }
1158
1159 /* Pop the scope stack if necessary */
1160
1161 if (AcpiNsOpensScope (AslMapNamedOpcodeToDataType (Op->Asl.AmlOpcode)))
1162 {
1163
1164 ACPI_DEBUG_PRINT ((ACPI_DB_DISPATCH,
1165 "%s: Popping scope for Op %p\n",
1166 AcpiUtGetTypeName (OpInfo->ObjectType), Op));
1167
1168 (void) AcpiDsScopeStackPop (WalkState);
1169 }
1170
1171 return_ACPI_STATUS (AE_OK);
1172 }
1173
1174
1175 /*******************************************************************************
1176 *
1177 * FUNCTION: XfValidateCrossReference
1178 *
1179 * PARAMETERS: Op - Parse Op that references the object
1180 * OpInfo - Parse Op info struct
1181 * Node - Node for the referenced object
1182 *
1183 * RETURN: TRUE if the reference is legal, FALSE otherwise
1184 *
1185 * DESCRIPTION: Determine if a reference to another object is allowed.
1186 *
1187 * EXAMPLE:
1188 * Method (A) {Name (INT1, 1)} Declaration of object INT1
1189 * Method (B) (Store (2, \A.INT1)} Illegal reference to object INT1
1190 * (INT1 is temporary, valid only during
1191 * execution of A)
1192 *
1193 * NOTES:
1194 * A null pointer returned by either UtGetParentMethodOp or
1195 * UtGetParentMethodNode indicates that the parameter object is not
1196 * within a control method.
1197 *
1198 * Five cases are handled: Case(Op, Node)
1199 * 1) Case(0,0): Op is not within a method, Node is not --> OK
1200 * 2) Case(0,1): Op is not within a method, but Node is --> Illegal
1201 * 3) Case(1,0): Op is within a method, Node is not --> OK
1202 * 4) Case(1,1): Both are within the same method --> OK
1203 * 5) Case(1,1): Both are in methods, but not same method --> Illegal
1204 *
1205 ******************************************************************************/
1206
1207 static BOOLEAN
1208 XfValidateCrossReference (
1209 ACPI_PARSE_OBJECT *Op,
1210 const ACPI_OPCODE_INFO *OpInfo,
1211 ACPI_NAMESPACE_NODE *Node)
1212 {
1213 ACPI_PARSE_OBJECT *ReferencingMethodOp;
1214 ACPI_NAMESPACE_NODE *ReferencedMethodNode;
1215
1216
1217 /* Ignore actual named (and related) object declarations */
1218
1219 if (OpInfo->Flags & (AML_NAMED | AML_CREATE | AML_DEFER | AML_HAS_ARGS))
1220 {
1221 return (TRUE);
1222 }
1223
1224 /*
1225 * 1) Search upwards in parse tree for owner of the referencing object
1226 * 2) Search upwards in namespace to find the owner of the referenced object
1227 */
1228 ReferencingMethodOp = UtGetParentMethodOp (Op);
1229 ReferencedMethodNode = UtGetParentMethodNode (Node);
1230
1231 if (!ReferencingMethodOp && !ReferencedMethodNode)
1232 {
1233 /*
1234 * 1) Case (0,0): Both Op and Node are not within methods
1235 * --> OK
1236 */
1237 return (TRUE);
1238 }
1239
1240 if (!ReferencingMethodOp && ReferencedMethodNode)
1241 {
1242 /*
1243 * 2) Case (0,1): Op is not in a method, but Node is within a
1244 * method --> illegal
1245 */
1246 return (FALSE);
1247 }
1248 else if (ReferencingMethodOp && !ReferencedMethodNode)
1249 {
1250 /*
1251 * 3) Case (1,0): Op is within a method, but Node is not
1252 * --> OK
1253 */
1254 return (TRUE);
1255 }
1256 else if (ReferencingMethodOp->Asl.Node == ReferencedMethodNode)
1257 {
1258 /*
1259 * 4) Case (1,1): Both Op and Node are within the same method
1260 * --> OK
1261 */
1262 return (TRUE);
1263 }
1264 else
1265 {
1266 /*
1267 * 5) Case (1,1), Op and Node are in different methods
1268 * --> Illegal
1269 */
1270 return (FALSE);
1271 }
1272 }
1273