aslmethod.c revision 1.1.1.16 1 /******************************************************************************
2 *
3 * Module Name: aslmethod.c - Control method analysis walk
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2021, Intel Corp.
9 * All rights reserved.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions, and the following disclaimer,
16 * without modification.
17 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
18 * substantially similar to the "NO WARRANTY" disclaimer below
19 * ("Disclaimer") and any redistribution must be conditioned upon
20 * including a substantially similar Disclaimer requirement for further
21 * binary redistribution.
22 * 3. Neither the names of the above-listed copyright holders nor the names
23 * of any contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * Alternatively, this software may be distributed under the terms of the
27 * GNU General Public License ("GPL") version 2 as published by the Free
28 * Software Foundation.
29 *
30 * NO WARRANTY
31 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
32 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
33 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
34 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
35 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
36 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
37 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
38 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
39 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
40 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
41 * POSSIBILITY OF SUCH DAMAGES.
42 */
43
44 #include "aslcompiler.h"
45 #include "aslcompiler.y.h"
46 #include "acnamesp.h"
47 #include "acparser.h"
48 #include "amlcode.h"
49
50
51 #define _COMPONENT ACPI_COMPILER
52 ACPI_MODULE_NAME ("aslmethod")
53
54
55 /* Local prototypes */
56
57 static void
58 MtCheckNamedObjectInMethod (
59 ACPI_PARSE_OBJECT *Op,
60 ASL_METHOD_INFO *MethodInfo);
61
62 static void
63 MtCheckStaticOperationRegionInMethod (
64 ACPI_PARSE_OBJECT *Op);
65
66
67 /*******************************************************************************
68 *
69 * FUNCTION: MtMethodAnalysisWalkBegin
70 *
71 * PARAMETERS: ASL_WALK_CALLBACK
72 *
73 * RETURN: Status
74 *
75 * DESCRIPTION: Descending callback for the analysis walk. Check methods for:
76 * 1) Initialized local variables
77 * 2) Valid arguments
78 * 3) Return types
79 *
80 ******************************************************************************/
81
82 ACPI_STATUS
83 MtMethodAnalysisWalkBegin (
84 ACPI_PARSE_OBJECT *Op,
85 UINT32 Level,
86 void *Context)
87 {
88 ASL_ANALYSIS_WALK_INFO *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
89 ASL_METHOD_INFO *MethodInfo = WalkInfo->MethodStack;
90 ACPI_PARSE_OBJECT *Next;
91 UINT32 RegisterNumber;
92 UINT32 i;
93 char LocalName[] = "Local0";
94 char ArgName[] = "Arg0";
95 ACPI_PARSE_OBJECT *ArgNode;
96 ACPI_PARSE_OBJECT *NextType;
97 UINT8 ActualArgs = 0;
98 BOOLEAN HidExists;
99 BOOLEAN AdrExists;
100
101
102 /* Build cross-reference output file if requested */
103
104 if (AslGbl_CrossReferenceOutput)
105 {
106 OtXrefWalkPart1 (Op, Level, MethodInfo);
107 }
108
109 switch (Op->Asl.ParseOpcode)
110 {
111 case PARSEOP_METHOD:
112
113 AslGbl_TotalMethods++;
114
115 /* Create and init method info */
116
117 MethodInfo = UtLocalCalloc (sizeof (ASL_METHOD_INFO));
118 MethodInfo->Next = WalkInfo->MethodStack;
119 MethodInfo->Op = Op;
120
121 WalkInfo->MethodStack = MethodInfo;
122
123 /*
124 * Special handling for _PSx methods. Dependency rules (same scope):
125 *
126 * 1) _PS0 - One of these must exist: _PS1, _PS2, _PS3
127 * 2) _PS1/_PS2/_PS3: A _PS0 must exist
128 */
129 if (ACPI_COMPARE_NAMESEG (METHOD_NAME__PS0, Op->Asl.NameSeg))
130 {
131 /* For _PS0, one of _PS1/_PS2/_PS3 must exist */
132
133 if ((!ApFindNameInScope (METHOD_NAME__PS1, Op)) &&
134 (!ApFindNameInScope (METHOD_NAME__PS2, Op)) &&
135 (!ApFindNameInScope (METHOD_NAME__PS3, Op)))
136 {
137 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
138 "_PS0 requires one of _PS1/_PS2/_PS3 in same scope");
139 }
140 }
141 else if (
142 ACPI_COMPARE_NAMESEG (METHOD_NAME__PS1, Op->Asl.NameSeg) ||
143 ACPI_COMPARE_NAMESEG (METHOD_NAME__PS2, Op->Asl.NameSeg) ||
144 ACPI_COMPARE_NAMESEG (METHOD_NAME__PS3, Op->Asl.NameSeg))
145 {
146 /* For _PS1/_PS2/_PS3, a _PS0 must exist */
147
148 if (!ApFindNameInScope (METHOD_NAME__PS0, Op))
149 {
150 sprintf (AslGbl_MsgBuffer,
151 "%4.4s requires _PS0 in same scope", Op->Asl.NameSeg);
152
153 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
154 AslGbl_MsgBuffer);
155 }
156 }
157
158 /* Get the name node */
159
160 Next = Op->Asl.Child;
161
162 /* Get the NumArguments node */
163
164 Next = Next->Asl.Next;
165 MethodInfo->NumArguments = (UINT8)
166 (((UINT8) Next->Asl.Value.Integer) & 0x07);
167
168 /* Get the SerializeRule and SyncLevel nodes, ignored here */
169
170 Next = Next->Asl.Next;
171 MethodInfo->ShouldBeSerialized = (UINT8) Next->Asl.Value.Integer;
172
173 Next = Next->Asl.Next;
174 ArgNode = Next;
175
176 /* Get the ReturnType node */
177
178 Next = Next->Asl.Next;
179
180 NextType = Next->Asl.Child;
181
182 MethodInfo->ValidReturnTypes = MtProcessTypeOp (NextType);
183 Op->Asl.AcpiBtype |= MethodInfo->ValidReturnTypes;
184
185 /* Get the ParameterType node */
186
187 Next = Next->Asl.Next;
188
189 NextType = Next->Asl.Child;
190 if (!NextType)
191 {
192 /*
193 * The optional parameter types list was omitted at the source
194 * level. Use the Argument count parameter instead.
195 */
196 ActualArgs = MethodInfo->NumArguments;
197 }
198 else
199 {
200 ActualArgs = MtProcessParameterTypeList (NextType,
201 MethodInfo->ValidArgTypes);
202 MethodInfo->NumArguments = ActualArgs;
203 ArgNode->Asl.Value.Integer |= ActualArgs;
204 }
205
206 if ((MethodInfo->NumArguments) &&
207 (MethodInfo->NumArguments != ActualArgs))
208 {
209 sprintf (AslGbl_MsgBuffer,
210 "Length = %u", ActualArgs);
211 AslError (ASL_ERROR, ASL_MSG_ARG_COUNT_MISMATCH,
212 Op->Asl.Child->Asl.Next, AslGbl_MsgBuffer);
213 }
214
215 /* Allow numarguments == 0 for Function() */
216
217 if ((!MethodInfo->NumArguments) && (ActualArgs))
218 {
219 MethodInfo->NumArguments = ActualArgs;
220 ArgNode->Asl.Value.Integer |= ActualArgs;
221 }
222
223 /*
224 * Actual arguments are initialized at method entry.
225 * All other ArgX "registers" can be used as locals, so we
226 * track their initialization.
227 */
228 for (i = 0; i < MethodInfo->NumArguments; i++)
229 {
230 MethodInfo->ArgInitialized[i] = TRUE;
231 }
232 break;
233
234 case PARSEOP_METHODCALL:
235
236 /* Check for a recursive method call */
237
238 if (MethodInfo &&
239 (Op->Asl.Node == MethodInfo->Op->Asl.Node))
240 {
241 if (MethodInfo->CreatesNamedObjects)
242 {
243 /*
244 * This is an error, as it will fail at runtime on all ACPI
245 * implementations. Any named object declarations will be
246 * executed twice, causing failure the second time. Note,
247 * this is independent of whether the method is declared
248 * Serialized, because the same thread is attempting to
249 * reenter the method, and this will always succeed.
250 */
251 AslDualParseOpError (ASL_ERROR, ASL_MSG_ILLEGAL_RECURSION, Op,
252 Op->Asl.Value.String, ASL_MSG_FOUND_HERE, MethodInfo->Op,
253 MethodInfo->Op->Asl.ExternalName);
254 }
255 else
256 {
257 /* Method does not create objects, issue a remark */
258
259 AslError (ASL_REMARK, ASL_MSG_RECURSION, Op, Op->Asl.ExternalName);
260 }
261 }
262 break;
263
264 case PARSEOP_LOCAL0:
265 case PARSEOP_LOCAL1:
266 case PARSEOP_LOCAL2:
267 case PARSEOP_LOCAL3:
268 case PARSEOP_LOCAL4:
269 case PARSEOP_LOCAL5:
270 case PARSEOP_LOCAL6:
271 case PARSEOP_LOCAL7:
272
273 if (!MethodInfo)
274 {
275 /*
276 * Local was used outside a control method, or there was an error
277 * in the method declaration.
278 */
279 AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD,
280 Op, Op->Asl.ExternalName);
281 return (AE_ERROR);
282 }
283
284 RegisterNumber = (Op->Asl.AmlOpcode & 0x0007);
285
286 /*
287 * If the local is being used as a target, mark the local
288 * initialized
289 */
290 if (Op->Asl.CompileFlags & OP_IS_TARGET)
291 {
292 MethodInfo->LocalInitialized[RegisterNumber] = TRUE;
293 }
294
295 /*
296 * Otherwise, this is a reference, check if the local
297 * has been previously initialized.
298 *
299 * The only operator that accepts an uninitialized value is ObjectType()
300 */
301 else if ((!MethodInfo->LocalInitialized[RegisterNumber]) &&
302 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
303 {
304 LocalName[strlen (LocalName) -1] = (char) (RegisterNumber + 0x30);
305 AslError (ASL_ERROR, ASL_MSG_LOCAL_INIT, Op, LocalName);
306 }
307 break;
308
309 case PARSEOP_ARG0:
310 case PARSEOP_ARG1:
311 case PARSEOP_ARG2:
312 case PARSEOP_ARG3:
313 case PARSEOP_ARG4:
314 case PARSEOP_ARG5:
315 case PARSEOP_ARG6:
316
317 if (!MethodInfo)
318 {
319 /*
320 * Arg was used outside a control method, or there was an error
321 * in the method declaration.
322 */
323 AslError (ASL_REMARK, ASL_MSG_LOCAL_OUTSIDE_METHOD,
324 Op, Op->Asl.ExternalName);
325 return (AE_ERROR);
326 }
327
328 RegisterNumber = (Op->Asl.AmlOpcode & 0x000F) - 8;
329 ArgName[strlen (ArgName) -1] = (char) (RegisterNumber + 0x30);
330
331 /*
332 * If the Arg is being used as a target, mark the local
333 * initialized
334 */
335 if (Op->Asl.CompileFlags & OP_IS_TARGET)
336 {
337 MethodInfo->ArgInitialized[RegisterNumber] = TRUE;
338 }
339
340 /*
341 * Otherwise, this is a reference, check if the Arg
342 * has been previously initialized.
343 *
344 * The only operator that accepts an uninitialized value is ObjectType()
345 */
346 else if ((!MethodInfo->ArgInitialized[RegisterNumber]) &&
347 (Op->Asl.Parent->Asl.ParseOpcode != PARSEOP_OBJECTTYPE))
348 {
349 AslError (ASL_ERROR, ASL_MSG_ARG_INIT, Op, ArgName);
350 }
351
352 /* Flag this arg if it is not a "real" argument to the method */
353
354 if (RegisterNumber >= MethodInfo->NumArguments)
355 {
356 AslError (ASL_REMARK, ASL_MSG_NOT_PARAMETER, Op, ArgName);
357 }
358 break;
359
360 case PARSEOP_RETURN:
361
362 if (!MethodInfo)
363 {
364 /*
365 * Probably was an error in the method declaration,
366 * no additional error here
367 */
368 ACPI_WARNING ((AE_INFO, "%p, No parent method", Op));
369 return (AE_ERROR);
370 }
371
372 /*
373 * A child indicates a possible return value. A simple Return or
374 * Return() is marked with OP_IS_NULL_RETURN by the parser so
375 * that it is not counted as a "real" return-with-value, although
376 * the AML code that is actually emitted is Return(0). The AML
377 * definition of Return has a required parameter, so we are
378 * forced to convert a null return to Return(0).
379 */
380 if ((Op->Asl.Child) &&
381 (Op->Asl.Child->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG) &&
382 (!(Op->Asl.Child->Asl.CompileFlags & OP_IS_NULL_RETURN)))
383 {
384 MethodInfo->NumReturnWithValue++;
385 }
386 else
387 {
388 MethodInfo->NumReturnNoValue++;
389 }
390 break;
391
392 case PARSEOP_BREAK:
393 case PARSEOP_CONTINUE:
394
395 Next = Op->Asl.Parent;
396 while (Next)
397 {
398 if (Next->Asl.ParseOpcode == PARSEOP_WHILE)
399 {
400 break;
401 }
402 Next = Next->Asl.Parent;
403 }
404
405 if (!Next)
406 {
407 AslError (ASL_ERROR, ASL_MSG_NO_WHILE, Op, NULL);
408 }
409 break;
410
411 case PARSEOP_STALL:
412
413 /* We can range check if the argument is an integer */
414
415 if ((Op->Asl.Child->Asl.ParseOpcode == PARSEOP_INTEGER) &&
416 (Op->Asl.Child->Asl.Value.Integer > ACPI_UINT8_MAX))
417 {
418 AslError (ASL_ERROR, ASL_MSG_INVALID_TIME, Op, NULL);
419 }
420 break;
421
422 case PARSEOP_DEVICE:
423
424 /* Check usage of _HID and _ADR objects */
425
426 HidExists = ApFindNameInDeviceTree (METHOD_NAME__HID, Op);
427 AdrExists = ApFindNameInDeviceTree (METHOD_NAME__ADR, Op);
428
429 if (!HidExists && !AdrExists)
430 {
431 AslError (ASL_WARNING, ASL_MSG_MISSING_DEPENDENCY, Op,
432 "Device object requires a _HID or _ADR in same scope");
433 }
434 else if (HidExists && AdrExists)
435 {
436 /*
437 * According to the ACPI spec, "A device object must contain
438 * either an _HID object or an _ADR object, but should not contain
439 * both".
440 */
441 AslError (ASL_WARNING, ASL_MSG_MULTIPLE_TYPES, Op,
442 "Device object requires either a _HID or _ADR, but not both");
443 }
444 break;
445
446 case PARSEOP_EVENT:
447 case PARSEOP_MUTEX:
448 case PARSEOP_OPERATIONREGION:
449 case PARSEOP_POWERRESOURCE:
450 case PARSEOP_PROCESSOR:
451 case PARSEOP_THERMALZONE:
452
453 /*
454 * The first operand is a name to be created in the namespace.
455 * Check against the reserved list.
456 */
457 i = ApCheckForPredefinedName (Op, Op->Asl.NameSeg);
458 if (i < ACPI_VALID_RESERVED_NAME_MAX)
459 {
460 AslError (ASL_ERROR, ASL_MSG_RESERVED_USE,
461 Op, Op->Asl.ExternalName);
462 }
463
464 MtCheckStaticOperationRegionInMethod (Op);
465 break;
466
467 case PARSEOP_NAME:
468
469 /* Typecheck any predefined names statically defined with Name() */
470
471 ApCheckForPredefinedObject (Op, Op->Asl.NameSeg);
472
473 /* Special typechecking for _HID */
474
475 if (ACPI_COMPARE_NAMESEG (METHOD_NAME__HID, Op->Asl.NameSeg))
476 {
477 Next = Op->Asl.Child->Asl.Next;
478 AnCheckId (Next, ASL_TYPE_HID);
479 }
480
481 /* Special typechecking for _CID */
482
483 else if (ACPI_COMPARE_NAMESEG (METHOD_NAME__CID, Op->Asl.NameSeg))
484 {
485 Next = Op->Asl.Child->Asl.Next;
486
487 if ((Next->Asl.ParseOpcode == PARSEOP_PACKAGE) ||
488 (Next->Asl.ParseOpcode == PARSEOP_VAR_PACKAGE))
489 {
490 Next = Next->Asl.Child;
491 while (Next)
492 {
493 AnCheckId (Next, ASL_TYPE_CID);
494 Next = Next->Asl.Next;
495 }
496 }
497 else
498 {
499 AnCheckId (Next, ASL_TYPE_CID);
500 }
501 }
502
503 break;
504
505 default:
506
507 break;
508 }
509
510 /* Check for named object creation within a non-serialized method */
511
512 MtCheckNamedObjectInMethod (Op, MethodInfo);
513 return (AE_OK);
514 }
515
516
517 /*******************************************************************************
518 *
519 * FUNCTION: MtProcessTypeOp
520 *
521 * PARAMETERS: Op - Op representing a btype
522 *
523 * RETURN: Btype represented by Op
524 *
525 * DESCRIPTION: Process a parse object that represents single parameter type or
526 * a return type in method, function, and external declarations.
527 *
528 ******************************************************************************/
529
530 UINT32
531 MtProcessTypeOp (
532 ACPI_PARSE_OBJECT *TypeOp)
533 {
534 UINT32 Btype = ACPI_BTYPE_ANY;
535
536
537 while (TypeOp)
538 {
539 Btype |= AnMapObjTypeToBtype (TypeOp);
540 TypeOp->Asl.ParseOpcode = PARSEOP_DEFAULT_ARG;
541 TypeOp = TypeOp->Asl.Next;
542 }
543
544 return (Btype);
545 }
546
547
548 /*******************************************************************************
549 *
550 * FUNCTION: MtProcessParameterTypeList
551 *
552 * PARAMETERS: Op - Op representing a btype
553 *
554 * RETURN: Btype represented by Op
555 *
556 * DESCRIPTION: Process a parse object that represents a parameter type list in
557 * method, function, and external declarations.
558 *
559 ******************************************************************************/
560
561 UINT8
562 MtProcessParameterTypeList (
563 ACPI_PARSE_OBJECT *ParamTypeOp,
564 UINT32 *TypeList)
565 {
566 UINT8 ParameterCount = 0;
567
568
569 if (ParamTypeOp && ParamTypeOp->Asl.ParseOpcode != PARSEOP_DEFAULT_ARG)
570 {
571 /* Special case for a single parameter without braces */
572
573 TypeList[ParameterCount] =
574 MtProcessTypeOp (ParamTypeOp);
575
576 return (1);
577 }
578
579 while (ParamTypeOp)
580 {
581 TypeList[ParameterCount] =
582 MtProcessTypeOp (ParamTypeOp->Asl.Child);
583
584 ParameterCount++;
585 ParamTypeOp = ParamTypeOp->Asl.Next;
586 }
587
588 return (ParameterCount);
589 }
590
591
592 /*******************************************************************************
593 *
594 * FUNCTION: MtCheckNamedObjectInMethod
595 *
596 * PARAMETERS: Op - Current parser op
597 * MethodInfo - Info for method being parsed
598 *
599 * RETURN: None
600 *
601 * DESCRIPTION: Detect if a non-serialized method is creating a named object,
602 * which could possibly cause problems if two threads execute
603 * the method concurrently. Emit a remark in this case.
604 *
605 ******************************************************************************/
606
607 static void
608 MtCheckNamedObjectInMethod (
609 ACPI_PARSE_OBJECT *Op,
610 ASL_METHOD_INFO *MethodInfo)
611 {
612 const ACPI_OPCODE_INFO *OpInfo;
613 char *ExternalPath;
614
615
616 /* We don't care about actual method declarations or scopes */
617
618 if ((Op->Asl.AmlOpcode == AML_METHOD_OP) ||
619 (Op->Asl.AmlOpcode == AML_SCOPE_OP))
620 {
621 return;
622 }
623
624 /* Determine if we are creating a named object within a method */
625
626 if (!MethodInfo)
627 {
628 return;
629 }
630
631 OpInfo = AcpiPsGetOpcodeInfo (Op->Asl.AmlOpcode);
632 if ((OpInfo->Class == AML_CLASS_NAMED_OBJECT) && (Op->Asl.AmlOpcode != AML_FIELD_OP))
633 {
634 /*
635 * 1) Mark the method as a method that creates named objects.
636 *
637 * 2) Issue a remark indicating the inefficiency of creating named
638 * objects within a method (Except for compiler-emitted temporary
639 * variables).
640 *
641 * 3) If the method is non-serialized, emit a remark that the method
642 * should be serialized.
643 *
644 * Reason: If a thread blocks within the method for any reason, and
645 * another thread enters the method, the method will fail because
646 * an attempt will be made to create the same object twice.
647 *
648 * Note: The Field opcode is disallowed here because Field() does not
649 * create a new named object.
650 */
651 ExternalPath = AcpiNsGetNormalizedPathname (MethodInfo->Op->Asl.Node, TRUE);
652
653 /* No error for compiler temp variables (name starts with "_T_") */
654
655 if ((Op->Asl.NameSeg[0] != '_') &&
656 (Op->Asl.NameSeg[1] != 'T') &&
657 (Op->Asl.NameSeg[2] != '_'))
658 {
659 AslError (ASL_REMARK, ASL_MSG_NAMED_OBJECT_CREATION, Op,
660 ExternalPath);
661 }
662
663 MethodInfo->CreatesNamedObjects = TRUE;
664 if (!MethodInfo->ShouldBeSerialized)
665 {
666 AslError (ASL_REMARK, ASL_MSG_SERIALIZED_REQUIRED, MethodInfo->Op,
667 ExternalPath);
668
669 /* Emit message only ONCE per method */
670
671 MethodInfo->ShouldBeSerialized = TRUE;
672 }
673
674 if (ExternalPath)
675 {
676 ACPI_FREE (ExternalPath);
677 }
678 }
679 }
680
681
682 /*******************************************************************************
683 *
684 * FUNCTION: MtCheckStaticOperationRegionInMethod
685 *
686 * PARAMETERS: Op - Current parser op
687 *
688 * RETURN: None
689 *
690 * DESCRIPTION: Warns if an Operation Region with static address or length
691 * is declared inside a control method
692 *
693 ******************************************************************************/
694
695 static void
696 MtCheckStaticOperationRegionInMethod(
697 ACPI_PARSE_OBJECT* Op)
698 {
699 ACPI_PARSE_OBJECT* AddressOp;
700 ACPI_PARSE_OBJECT* LengthOp;
701
702
703 if (Op->Asl.ParseOpcode != PARSEOP_OPERATIONREGION)
704 {
705 return;
706 }
707
708 /*
709 * OperationRegion should have 4 arguments defined. At this point, we
710 * assume that the parse tree is well-formed.
711 */
712 AddressOp = Op->Asl.Child->Asl.Next->Asl.Next;
713 LengthOp = Op->Asl.Child->Asl.Next->Asl.Next->Asl.Next;
714
715 if (UtGetParentMethodOp (Op) &&
716 AddressOp->Asl.ParseOpcode == PARSEOP_INTEGER &&
717 LengthOp->Asl.ParseOpcode == PARSEOP_INTEGER)
718 {
719 /*
720 * At this point, a static operation region declared inside of a
721 * control method has been found. Throw a warning because this is
722 * highly inefficient.
723 */
724 AslError(ASL_WARNING, ASL_MSG_STATIC_OPREGION_IN_METHOD, Op, NULL);
725 }
726
727 return;
728 }
729
730
731 /*******************************************************************************
732 *
733 * FUNCTION: MtMethodAnalysisWalkEnd
734 *
735 * PARAMETERS: ASL_WALK_CALLBACK
736 *
737 * RETURN: Status
738 *
739 * DESCRIPTION: Ascending callback for analysis walk. Complete method
740 * return analysis.
741 *
742 ******************************************************************************/
743
744 ACPI_STATUS
745 MtMethodAnalysisWalkEnd (
746 ACPI_PARSE_OBJECT *Op,
747 UINT32 Level,
748 void *Context)
749 {
750 ASL_ANALYSIS_WALK_INFO *WalkInfo = (ASL_ANALYSIS_WALK_INFO *) Context;
751 ASL_METHOD_INFO *MethodInfo = WalkInfo->MethodStack;
752 char *ExternalPath;
753
754
755 switch (Op->Asl.ParseOpcode)
756 {
757 case PARSEOP_METHOD:
758 case PARSEOP_RETURN:
759
760 if (!MethodInfo)
761 {
762 printf ("No method info for method! [%s]\n", Op->Asl.Namepath);
763 AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL, Op,
764 "No method info for this method");
765
766 CmCleanupAndExit ();
767 return (AE_AML_INTERNAL);
768 }
769 break;
770
771 default:
772
773 break;
774 }
775
776 switch (Op->Asl.ParseOpcode)
777 {
778 case PARSEOP_METHOD:
779
780 WalkInfo->MethodStack = MethodInfo->Next;
781
782 /*
783 * Check if there is no return statement at the end of the
784 * method AND we can actually get there -- i.e., the execution
785 * of the method can possibly terminate without a return statement.
786 */
787 if ((!AnLastStatementIsReturn (Op)) &&
788 (!(Op->Asl.CompileFlags & OP_HAS_NO_EXIT)))
789 {
790 /*
791 * No return statement, and execution can possibly exit
792 * via this path. This is equivalent to Return ()
793 */
794 MethodInfo->NumReturnNoValue++;
795 }
796
797 /*
798 * Check for case where some return statements have a return value
799 * and some do not. Exit without a return statement is a return with
800 * no value
801 */
802 if (MethodInfo->NumReturnNoValue &&
803 MethodInfo->NumReturnWithValue)
804 {
805 ExternalPath = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE);
806
807 AslError (ASL_WARNING, ASL_MSG_RETURN_TYPES, Op,
808 ExternalPath);
809
810 if (ExternalPath)
811 {
812 ACPI_FREE (ExternalPath);
813 }
814 }
815
816 /*
817 * If there are any RETURN() statements with no value, or there is a
818 * control path that allows the method to exit without a return value,
819 * we mark the method as a method that does not return a value. This
820 * knowledge can be used to check method invocations that expect a
821 * returned value.
822 */
823 if (MethodInfo->NumReturnNoValue)
824 {
825 if (MethodInfo->NumReturnWithValue)
826 {
827 Op->Asl.CompileFlags |= OP_METHOD_SOME_NO_RETVAL;
828 }
829 else
830 {
831 Op->Asl.CompileFlags |= OP_METHOD_NO_RETVAL;
832 }
833 }
834
835 /*
836 * Check predefined method names for correct return behavior
837 * and correct number of arguments. Also, some special checks
838 * For GPE and _REG methods.
839 */
840 if (ApCheckForPredefinedMethod (Op, MethodInfo))
841 {
842 /* Special check for two names like _L01 and _E01 in same scope */
843
844 ApCheckForGpeNameConflict (Op);
845
846 /*
847 * Special check for _REG: Must have an operation region definition
848 * within the same scope!
849 */
850 ApCheckRegMethod (Op);
851 }
852
853 ACPI_FREE (MethodInfo);
854 break;
855
856 case PARSEOP_NAME:
857
858 /* Special check for two names like _L01 and _E01 in same scope */
859
860 ApCheckForGpeNameConflict (Op);
861 break;
862
863 case PARSEOP_RETURN:
864
865 /*
866 * If the parent is a predefined method name, attempt to typecheck
867 * the return value. Only static types can be validated.
868 */
869 ApCheckPredefinedReturnValue (Op, MethodInfo);
870
871 /*
872 * The parent block does not "exit" and continue execution -- the
873 * method is terminated here with the Return() statement.
874 */
875 Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
876
877 /* Used in the "typing" pass later */
878
879 Op->Asl.ParentMethod = MethodInfo->Op;
880
881 /*
882 * If there is a peer node after the return statement, then this
883 * node is unreachable code -- i.e., it won't be executed because of
884 * the preceding Return() statement.
885 */
886 if (Op->Asl.Next)
887 {
888 AslError (ASL_WARNING, ASL_MSG_UNREACHABLE_CODE,
889 Op->Asl.Next, NULL);
890 }
891 break;
892
893 case PARSEOP_IF:
894
895 if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
896 (Op->Asl.Next) &&
897 (Op->Asl.Next->Asl.ParseOpcode == PARSEOP_ELSE))
898 {
899 /*
900 * This IF has a corresponding ELSE. The IF block has no exit,
901 * (it contains an unconditional Return)
902 * mark the ELSE block to remember this fact.
903 */
904 Op->Asl.Next->Asl.CompileFlags |= OP_IF_HAS_NO_EXIT;
905 }
906 break;
907
908 case PARSEOP_ELSE:
909
910 if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
911 (Op->Asl.CompileFlags & OP_IF_HAS_NO_EXIT))
912 {
913 /*
914 * This ELSE block has no exit and the corresponding IF block
915 * has no exit either. Therefore, the parent node has no exit.
916 */
917 Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
918 }
919 break;
920
921
922 default:
923
924 if ((Op->Asl.CompileFlags & OP_HAS_NO_EXIT) &&
925 (Op->Asl.Parent))
926 {
927 /* If this node has no exit, then the parent has no exit either */
928
929 Op->Asl.Parent->Asl.CompileFlags |= OP_HAS_NO_EXIT;
930 }
931 break;
932 }
933
934 return (AE_OK);
935 }
936