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