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