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