psloop.c revision 1.1.1.11 1 /******************************************************************************
2 *
3 * Module Name: psloop - Main AML parse loop
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2018, 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 /*
45 * Parse the AML and build an operation tree as most interpreters, (such as
46 * Perl) do. Parsing is done by hand rather than with a YACC generated parser
47 * to tightly constrain stack and dynamic memory usage. Parsing is kept
48 * flexible and the code fairly compact by parsing based on a list of AML
49 * opcode templates in AmlOpInfo[].
50 */
51
52 #include "acpi.h"
53 #include "accommon.h"
54 #include "acinterp.h"
55 #include "acparser.h"
56 #include "acdispat.h"
57 #include "amlcode.h"
58 #include "acconvert.h"
59
60 #define _COMPONENT ACPI_PARSER
61 ACPI_MODULE_NAME ("psloop")
62
63
64 /* Local prototypes */
65
66 static ACPI_STATUS
67 AcpiPsGetArguments (
68 ACPI_WALK_STATE *WalkState,
69 UINT8 *AmlOpStart,
70 ACPI_PARSE_OBJECT *Op);
71
72 static void
73 AcpiPsLinkModuleCode (
74 ACPI_PARSE_OBJECT *ParentOp,
75 UINT8 *AmlStart,
76 UINT32 AmlLength,
77 ACPI_OWNER_ID OwnerId);
78
79
80 /*******************************************************************************
81 *
82 * FUNCTION: AcpiPsGetArguments
83 *
84 * PARAMETERS: WalkState - Current state
85 * AmlOpStart - Op start in AML
86 * Op - Current Op
87 *
88 * RETURN: Status
89 *
90 * DESCRIPTION: Get arguments for passed Op.
91 *
92 ******************************************************************************/
93
94 static ACPI_STATUS
95 AcpiPsGetArguments (
96 ACPI_WALK_STATE *WalkState,
97 UINT8 *AmlOpStart,
98 ACPI_PARSE_OBJECT *Op)
99 {
100 ACPI_STATUS Status = AE_OK;
101 ACPI_PARSE_OBJECT *Arg = NULL;
102 const ACPI_OPCODE_INFO *OpInfo;
103
104
105 ACPI_FUNCTION_TRACE_PTR (PsGetArguments, WalkState);
106
107
108 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
109 "Get arguments for opcode [%s]\n", Op->Common.AmlOpName));
110
111 switch (Op->Common.AmlOpcode)
112 {
113 case AML_BYTE_OP: /* AML_BYTEDATA_ARG */
114 case AML_WORD_OP: /* AML_WORDDATA_ARG */
115 case AML_DWORD_OP: /* AML_DWORDATA_ARG */
116 case AML_QWORD_OP: /* AML_QWORDATA_ARG */
117 case AML_STRING_OP: /* AML_ASCIICHARLIST_ARG */
118
119 /* Fill in constant or string argument directly */
120
121 AcpiPsGetNextSimpleArg (&(WalkState->ParserState),
122 GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), Op);
123 break;
124
125 case AML_INT_NAMEPATH_OP: /* AML_NAMESTRING_ARG */
126
127 Status = AcpiPsGetNextNamepath (WalkState,
128 &(WalkState->ParserState), Op, ACPI_POSSIBLE_METHOD_CALL);
129 if (ACPI_FAILURE (Status))
130 {
131 return_ACPI_STATUS (Status);
132 }
133
134 WalkState->ArgTypes = 0;
135 break;
136
137 default:
138 /*
139 * Op is not a constant or string, append each argument to the Op
140 */
141 while (GET_CURRENT_ARG_TYPE (WalkState->ArgTypes) &&
142 !WalkState->ArgCount)
143 {
144 WalkState->Aml = WalkState->ParserState.Aml;
145
146 switch (Op->Common.AmlOpcode)
147 {
148 case AML_METHOD_OP:
149 case AML_BUFFER_OP:
150 case AML_PACKAGE_OP:
151 case AML_VARIABLE_PACKAGE_OP:
152 case AML_WHILE_OP:
153
154 break;
155
156 default:
157
158 ASL_CV_CAPTURE_COMMENTS (WalkState);
159 break;
160 }
161
162 Status = AcpiPsGetNextArg (WalkState, &(WalkState->ParserState),
163 GET_CURRENT_ARG_TYPE (WalkState->ArgTypes), &Arg);
164 if (ACPI_FAILURE (Status))
165 {
166 return_ACPI_STATUS (Status);
167 }
168
169 if (Arg)
170 {
171 AcpiPsAppendArg (Op, Arg);
172 }
173
174 INCREMENT_ARG_LIST (WalkState->ArgTypes);
175 }
176
177 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
178 "Final argument count: %8.8X pass %u\n",
179 WalkState->ArgCount, WalkState->PassNumber));
180
181 /*
182 * This case handles the legacy option that groups all module-level
183 * code blocks together and defers execution until all of the tables
184 * are loaded. Execute all of these blocks at this time.
185 * Execute any module-level code that was detected during the table
186 * load phase.
187 *
188 * Note: this option is deprecated and will be eliminated in the
189 * future. Use of this option can cause problems with AML code that
190 * depends upon in-order immediate execution of module-level code.
191 */
192 if (AcpiGbl_GroupModuleLevelCode &&
193 (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2) &&
194 ((WalkState->ParseFlags & ACPI_PARSE_DISASSEMBLE) == 0))
195 {
196 /*
197 * We want to skip If/Else/While constructs during Pass1 because we
198 * want to actually conditionally execute the code during Pass2.
199 *
200 * Except for disassembly, where we always want to walk the
201 * If/Else/While packages
202 */
203 switch (Op->Common.AmlOpcode)
204 {
205 case AML_IF_OP:
206 case AML_ELSE_OP:
207 case AML_WHILE_OP:
208 /*
209 * Currently supported module-level opcodes are:
210 * IF/ELSE/WHILE. These appear to be the most common,
211 * and easiest to support since they open an AML
212 * package.
213 */
214 if (WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1)
215 {
216 AcpiPsLinkModuleCode (Op->Common.Parent, AmlOpStart,
217 (UINT32) (WalkState->ParserState.PkgEnd - AmlOpStart),
218 WalkState->OwnerId);
219 }
220
221 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
222 "Pass1: Skipping an If/Else/While body\n"));
223
224 /* Skip body of if/else/while in pass 1 */
225
226 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
227 WalkState->ArgCount = 0;
228 break;
229
230 default:
231 /*
232 * Check for an unsupported executable opcode at module
233 * level. We must be in PASS1, the parent must be a SCOPE,
234 * The opcode class must be EXECUTE, and the opcode must
235 * not be an argument to another opcode.
236 */
237 if ((WalkState->PassNumber == ACPI_IMODE_LOAD_PASS1) &&
238 (Op->Common.Parent->Common.AmlOpcode == AML_SCOPE_OP))
239 {
240 OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
241 if ((OpInfo->Class == AML_CLASS_EXECUTE) &&
242 (!Arg))
243 {
244 ACPI_WARNING ((AE_INFO,
245 "Unsupported module-level executable opcode "
246 "0x%.2X at table offset 0x%.4X",
247 Op->Common.AmlOpcode,
248 (UINT32) (ACPI_PTR_DIFF (AmlOpStart,
249 WalkState->ParserState.AmlStart) +
250 sizeof (ACPI_TABLE_HEADER))));
251 }
252 }
253 break;
254 }
255 }
256
257 /* Special processing for certain opcodes */
258
259 switch (Op->Common.AmlOpcode)
260 {
261 case AML_METHOD_OP:
262 /*
263 * Skip parsing of control method because we don't have enough
264 * info in the first pass to parse it correctly.
265 *
266 * Save the length and address of the body
267 */
268 Op->Named.Data = WalkState->ParserState.Aml;
269 Op->Named.Length = (UINT32)
270 (WalkState->ParserState.PkgEnd - WalkState->ParserState.Aml);
271
272 /* Skip body of method */
273
274 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
275 WalkState->ArgCount = 0;
276 break;
277
278 case AML_BUFFER_OP:
279 case AML_PACKAGE_OP:
280 case AML_VARIABLE_PACKAGE_OP:
281
282 if ((Op->Common.Parent) &&
283 (Op->Common.Parent->Common.AmlOpcode == AML_NAME_OP) &&
284 (WalkState->PassNumber <= ACPI_IMODE_LOAD_PASS2))
285 {
286 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
287 "Setup Package/Buffer: Pass %u, AML Ptr: %p\n",
288 WalkState->PassNumber, AmlOpStart));
289
290 /*
291 * Skip parsing of Buffers and Packages because we don't have
292 * enough info in the first pass to parse them correctly.
293 */
294 Op->Named.Data = AmlOpStart;
295 Op->Named.Length = (UINT32)
296 (WalkState->ParserState.PkgEnd - AmlOpStart);
297
298 /* Skip body */
299
300 WalkState->ParserState.Aml = WalkState->ParserState.PkgEnd;
301 WalkState->ArgCount = 0;
302 }
303 break;
304
305 case AML_WHILE_OP:
306
307 if (WalkState->ControlState)
308 {
309 WalkState->ControlState->Control.PackageEnd =
310 WalkState->ParserState.PkgEnd;
311 }
312 break;
313
314 default:
315
316 /* No action for all other opcodes */
317
318 break;
319 }
320
321 break;
322 }
323
324 return_ACPI_STATUS (AE_OK);
325 }
326
327
328 /*******************************************************************************
329 *
330 * FUNCTION: AcpiPsLinkModuleCode
331 *
332 * PARAMETERS: ParentOp - Parent parser op
333 * AmlStart - Pointer to the AML
334 * AmlLength - Length of executable AML
335 * OwnerId - OwnerId of module level code
336 *
337 * RETURN: None.
338 *
339 * DESCRIPTION: Wrap the module-level code with a method object and link the
340 * object to the global list. Note, the mutex field of the method
341 * object is used to link multiple module-level code objects.
342 *
343 * NOTE: In this legacy option, each block of detected executable AML
344 * code that is outside of any control method is wrapped with a temporary
345 * control method object and placed on a global list below.
346 *
347 * This function executes the module-level code for all tables only after
348 * all of the tables have been loaded. It is a legacy option and is
349 * not compatible with other ACPI implementations. See AcpiNsLoadTable.
350 *
351 * This function will be removed when the legacy option is removed.
352 *
353 ******************************************************************************/
354
355 static void
356 AcpiPsLinkModuleCode (
357 ACPI_PARSE_OBJECT *ParentOp,
358 UINT8 *AmlStart,
359 UINT32 AmlLength,
360 ACPI_OWNER_ID OwnerId)
361 {
362 ACPI_OPERAND_OBJECT *Prev;
363 ACPI_OPERAND_OBJECT *Next;
364 ACPI_OPERAND_OBJECT *MethodObj;
365 ACPI_NAMESPACE_NODE *ParentNode;
366
367
368 ACPI_FUNCTION_TRACE (PsLinkModuleCode);
369
370
371 /* Get the tail of the list */
372
373 Prev = Next = AcpiGbl_ModuleCodeList;
374 while (Next)
375 {
376 Prev = Next;
377 Next = Next->Method.Mutex;
378 }
379
380 /*
381 * Insert the module level code into the list. Merge it if it is
382 * adjacent to the previous element.
383 */
384 if (!Prev ||
385 ((Prev->Method.AmlStart + Prev->Method.AmlLength) != AmlStart))
386 {
387 /* Create, initialize, and link a new temporary method object */
388
389 MethodObj = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
390 if (!MethodObj)
391 {
392 return_VOID;
393 }
394
395 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
396 "Create/Link new code block: %p\n", MethodObj));
397
398 if (ParentOp->Common.Node)
399 {
400 ParentNode = ParentOp->Common.Node;
401 }
402 else
403 {
404 ParentNode = AcpiGbl_RootNode;
405 }
406
407 MethodObj->Method.AmlStart = AmlStart;
408 MethodObj->Method.AmlLength = AmlLength;
409 MethodObj->Method.OwnerId = OwnerId;
410 MethodObj->Method.InfoFlags |= ACPI_METHOD_MODULE_LEVEL;
411
412 /*
413 * Save the parent node in NextObject. This is cheating, but we
414 * don't want to expand the method object.
415 */
416 MethodObj->Method.NextObject =
417 ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, ParentNode);
418
419 if (!Prev)
420 {
421 AcpiGbl_ModuleCodeList = MethodObj;
422 }
423 else
424 {
425 Prev->Method.Mutex = MethodObj;
426 }
427 }
428 else
429 {
430 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
431 "Appending to existing code block: %p\n", Prev));
432
433 Prev->Method.AmlLength += AmlLength;
434 }
435
436 return_VOID;
437 }
438
439 /*******************************************************************************
440 *
441 * FUNCTION: AcpiPsParseLoop
442 *
443 * PARAMETERS: WalkState - Current state
444 *
445 * RETURN: Status
446 *
447 * DESCRIPTION: Parse AML (pointed to by the current parser state) and return
448 * a tree of ops.
449 *
450 ******************************************************************************/
451
452 ACPI_STATUS
453 AcpiPsParseLoop (
454 ACPI_WALK_STATE *WalkState)
455 {
456 ACPI_STATUS Status = AE_OK;
457 ACPI_PARSE_OBJECT *Op = NULL; /* current op */
458 ACPI_PARSE_STATE *ParserState;
459 UINT8 *AmlOpStart = NULL;
460
461
462 ACPI_FUNCTION_TRACE_PTR (PsParseLoop, WalkState);
463
464
465 if (WalkState->DescendingCallback == NULL)
466 {
467 return_ACPI_STATUS (AE_BAD_PARAMETER);
468 }
469
470 ParserState = &WalkState->ParserState;
471 WalkState->ArgTypes = 0;
472
473 #if (!defined (ACPI_NO_METHOD_EXECUTION) && !defined (ACPI_CONSTANT_EVAL_ONLY))
474
475 if (WalkState->WalkType & ACPI_WALK_METHOD_RESTART)
476 {
477 /* We are restarting a preempted control method */
478
479 if (AcpiPsHasCompletedScope (ParserState))
480 {
481 /*
482 * We must check if a predicate to an IF or WHILE statement
483 * was just completed
484 */
485 if ((ParserState->Scope->ParseScope.Op) &&
486 ((ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_IF_OP) ||
487 (ParserState->Scope->ParseScope.Op->Common.AmlOpcode == AML_WHILE_OP)) &&
488 (WalkState->ControlState) &&
489 (WalkState->ControlState->Common.State ==
490 ACPI_CONTROL_PREDICATE_EXECUTING))
491 {
492 /*
493 * A predicate was just completed, get the value of the
494 * predicate and branch based on that value
495 */
496 WalkState->Op = NULL;
497 Status = AcpiDsGetPredicateValue (WalkState, ACPI_TO_POINTER (TRUE));
498 if (ACPI_FAILURE (Status) &&
499 ((Status & AE_CODE_MASK) != AE_CODE_CONTROL))
500 {
501 if (Status == AE_AML_NO_RETURN_VALUE)
502 {
503 ACPI_EXCEPTION ((AE_INFO, Status,
504 "Invoked method did not return a value"));
505 }
506
507 ACPI_EXCEPTION ((AE_INFO, Status, "GetPredicate Failed"));
508 return_ACPI_STATUS (Status);
509 }
510
511 Status = AcpiPsNextParseState (WalkState, Op, Status);
512 }
513
514 AcpiPsPopScope (ParserState, &Op,
515 &WalkState->ArgTypes, &WalkState->ArgCount);
516 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE, "Popped scope, Op=%p\n", Op));
517 }
518 else if (WalkState->PrevOp)
519 {
520 /* We were in the middle of an op */
521
522 Op = WalkState->PrevOp;
523 WalkState->ArgTypes = WalkState->PrevArgTypes;
524 }
525 }
526 #endif
527
528 /* Iterative parsing loop, while there is more AML to process: */
529
530 while ((ParserState->Aml < ParserState->AmlEnd) || (Op))
531 {
532 ASL_CV_CAPTURE_COMMENTS (WalkState);
533
534 AmlOpStart = ParserState->Aml;
535 if (!Op)
536 {
537 Status = AcpiPsCreateOp (WalkState, AmlOpStart, &Op);
538 if (ACPI_FAILURE (Status))
539 {
540 if (Status == AE_CTRL_PARSE_CONTINUE)
541 {
542 continue;
543 }
544
545 if (Status == AE_CTRL_PARSE_PENDING)
546 {
547 Status = AE_OK;
548 }
549
550 if (Status == AE_CTRL_TERMINATE)
551 {
552 return_ACPI_STATUS (Status);
553 }
554
555 Status = AcpiPsCompleteOp (WalkState, &Op, Status);
556 if (ACPI_FAILURE (Status))
557 {
558 return_ACPI_STATUS (Status);
559 }
560
561 continue;
562 }
563
564 AcpiExStartTraceOpcode (Op, WalkState);
565 }
566
567 /*
568 * Start ArgCount at zero because we don't know if there are
569 * any args yet
570 */
571 WalkState->ArgCount = 0;
572
573 switch (Op->Common.AmlOpcode)
574 {
575 case AML_BYTE_OP:
576 case AML_WORD_OP:
577 case AML_DWORD_OP:
578 case AML_QWORD_OP:
579
580 break;
581
582 default:
583
584 ASL_CV_CAPTURE_COMMENTS (WalkState);
585 break;
586 }
587
588 /* Are there any arguments that must be processed? */
589
590 if (WalkState->ArgTypes)
591 {
592 /* Get arguments */
593
594 Status = AcpiPsGetArguments (WalkState, AmlOpStart, Op);
595 if (ACPI_FAILURE (Status))
596 {
597 Status = AcpiPsCompleteOp (WalkState, &Op, Status);
598 if (ACPI_FAILURE (Status))
599 {
600 return_ACPI_STATUS (Status);
601 }
602
603 continue;
604 }
605 }
606
607 /* Check for arguments that need to be processed */
608
609 ACPI_DEBUG_PRINT ((ACPI_DB_PARSE,
610 "Parseloop: argument count: %8.8X\n", WalkState->ArgCount));
611
612 if (WalkState->ArgCount)
613 {
614 /*
615 * There are arguments (complex ones), push Op and
616 * prepare for argument
617 */
618 Status = AcpiPsPushScope (ParserState, Op,
619 WalkState->ArgTypes, WalkState->ArgCount);
620 if (ACPI_FAILURE (Status))
621 {
622 Status = AcpiPsCompleteOp (WalkState, &Op, Status);
623 if (ACPI_FAILURE (Status))
624 {
625 return_ACPI_STATUS (Status);
626 }
627
628 continue;
629 }
630
631 Op = NULL;
632 continue;
633 }
634
635 /*
636 * All arguments have been processed -- Op is complete,
637 * prepare for next
638 */
639 WalkState->OpInfo = AcpiPsGetOpcodeInfo (Op->Common.AmlOpcode);
640 if (WalkState->OpInfo->Flags & AML_NAMED)
641 {
642 if (Op->Common.AmlOpcode == AML_REGION_OP ||
643 Op->Common.AmlOpcode == AML_DATA_REGION_OP)
644 {
645 /*
646 * Skip parsing of control method or opregion body,
647 * because we don't have enough info in the first pass
648 * to parse them correctly.
649 *
650 * Completed parsing an OpRegion declaration, we now
651 * know the length.
652 */
653 Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
654 }
655 }
656
657 if (WalkState->OpInfo->Flags & AML_CREATE)
658 {
659 /*
660 * Backup to beginning of CreateXXXfield declaration (1 for
661 * Opcode)
662 *
663 * BodyLength is unknown until we parse the body
664 */
665 Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
666 }
667
668 if (Op->Common.AmlOpcode == AML_BANK_FIELD_OP)
669 {
670 /*
671 * Backup to beginning of BankField declaration
672 *
673 * BodyLength is unknown until we parse the body
674 */
675 Op->Named.Length = (UINT32) (ParserState->Aml - Op->Named.Data);
676 }
677
678 /* This op complete, notify the dispatcher */
679
680 if (WalkState->AscendingCallback != NULL)
681 {
682 WalkState->Op = Op;
683 WalkState->Opcode = Op->Common.AmlOpcode;
684
685 Status = WalkState->AscendingCallback (WalkState);
686 Status = AcpiPsNextParseState (WalkState, Op, Status);
687 if (Status == AE_CTRL_PENDING)
688 {
689 Status = AE_OK;
690 }
691 }
692
693 Status = AcpiPsCompleteOp (WalkState, &Op, Status);
694 if (ACPI_FAILURE (Status))
695 {
696 return_ACPI_STATUS (Status);
697 }
698
699 } /* while ParserState->Aml */
700
701 Status = AcpiPsCompleteFinalOp (WalkState, Op, Status);
702 return_ACPI_STATUS (Status);
703 }
704