1 /******************************************************************************
2 *
3 * Module Name: aslexternal - ASL External opcode compiler support
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 "acparser.h"
47 #include "amlcode.h"
48 #include "acnamesp.h"
49
50
51 #define _COMPONENT ACPI_COMPILER
52 ACPI_MODULE_NAME ("aslexternal")
53
54
55 /* Local prototypes */
56
57 static void
58 ExInsertArgCount (
59 ACPI_PARSE_OBJECT *Op);
60
61 static void
62 ExMoveExternals (
63 ACPI_PARSE_OBJECT *DefinitionBlockOp);
64
65
66 /*******************************************************************************
67 *
68 * FUNCTION: ExDoExternal
69 *
70 * PARAMETERS: Op - Current Parse node
71 *
72 * RETURN: None
73 *
74 * DESCRIPTION: Add an External() definition to the global list. This list
75 * is used to generate External opcodes.
76 *
77 ******************************************************************************/
78
79 void
ExDoExternal(ACPI_PARSE_OBJECT * Op)80 ExDoExternal (
81 ACPI_PARSE_OBJECT *Op)
82 {
83 ACPI_PARSE_OBJECT *ListOp;
84 ACPI_PARSE_OBJECT *Prev;
85 ACPI_PARSE_OBJECT *Next;
86 ACPI_PARSE_OBJECT *ArgCountOp;
87 ACPI_PARSE_OBJECT *TypeOp;
88 ACPI_PARSE_OBJECT *ExternTypeOp = Op->Asl.Child->Asl.Next;
89 UINT32 ExternType;
90 UINT8 ParamCount = ASL_EXTERNAL_METHOD_UNKNOWN_PARAMS;
91 UINT32 ParamTypes[ACPI_METHOD_NUM_ARGS];
92
93
94 ExternType = AnMapObjTypeToBtype (ExternTypeOp);
95 if (ExternType != ACPI_BTYPE_METHOD)
96 {
97 /*
98 * If this is not a method, it has zero parameters this local variable
99 * is used only for methods
100 */
101 ParamCount = 0;
102 }
103
104 /*
105 * The parser allows optional parameter return types regardless of the
106 * type. Check object type keyword emit error if optional parameter/return
107 * types exist.
108 *
109 * Check the parameter return type
110 */
111 TypeOp = ExternTypeOp->Asl.Next;
112 if (TypeOp->Asl.Child)
113 {
114 /* Ignore the return type for now. */
115
116 (void) MtProcessTypeOp (TypeOp->Asl.Child);
117 if (ExternType != ACPI_BTYPE_METHOD)
118 {
119 sprintf (AslGbl_MsgBuffer, "Found type [%s]", AcpiUtGetTypeName(ExternType));
120 AslError (ASL_ERROR, ASL_MSG_EXTERN_INVALID_RET_TYPE, TypeOp,
121 AslGbl_MsgBuffer);
122 }
123 }
124
125 /* Check the parameter types */
126
127 TypeOp = TypeOp->Asl.Next;
128 if (TypeOp->Asl.Child)
129 {
130 ParamCount = MtProcessParameterTypeList (TypeOp->Asl.Child, ParamTypes);
131 if (ExternType != ACPI_BTYPE_METHOD)
132 {
133 sprintf (AslGbl_MsgBuffer, "Found type [%s]", AcpiUtGetTypeName(ExternType));
134 AslError (ASL_ERROR, ASL_MSG_EXTERN_INVALID_PARAM_TYPE, TypeOp,
135 AslGbl_MsgBuffer);
136 }
137 }
138
139 ArgCountOp = Op->Asl.Child->Asl.Next->Asl.Next;
140 ArgCountOp->Asl.AmlOpcode = AML_RAW_DATA_BYTE;
141 ArgCountOp->Asl.ParseOpcode = PARSEOP_BYTECONST;
142 ArgCountOp->Asl.Value.Integer = ParamCount;
143 UtSetParseOpName (ArgCountOp);
144
145 /* Create new list node of arbitrary type */
146
147 ListOp = TrAllocateOp (PARSEOP_DEFAULT_ARG);
148
149 /* Store External node as child */
150
151 ListOp->Asl.Child = Op;
152 ListOp->Asl.Next = NULL;
153
154 if (AslGbl_ExternalsListHead)
155 {
156 /* Link new External to end of list */
157
158 Prev = AslGbl_ExternalsListHead;
159 Next = Prev;
160 while (Next)
161 {
162 Prev = Next;
163 Next = Next->Asl.Next;
164 }
165
166 Prev->Asl.Next = ListOp;
167 }
168 else
169 {
170 AslGbl_ExternalsListHead = ListOp;
171 }
172 }
173
174
175 /*******************************************************************************
176 *
177 * FUNCTION: ExInsertArgCount
178 *
179 * PARAMETERS: Op - Op for a method invocation
180 *
181 * RETURN: None
182 *
183 * DESCRIPTION: Obtain the number of arguments for a control method -- from
184 * the actual invocation.
185 *
186 ******************************************************************************/
187
188 static void
ExInsertArgCount(ACPI_PARSE_OBJECT * Op)189 ExInsertArgCount (
190 ACPI_PARSE_OBJECT *Op)
191 {
192 ACPI_PARSE_OBJECT *Next;
193 ACPI_PARSE_OBJECT *NameOp;
194 ACPI_PARSE_OBJECT *Child;
195 ACPI_PARSE_OBJECT *ArgCountOp;
196 char * ExternalName;
197 char * CallName;
198 UINT16 ArgCount = 0;
199 ACPI_STATUS Status;
200
201
202 CallName = AcpiNsGetNormalizedPathname (Op->Asl.Node, TRUE);
203
204 Next = AslGbl_ExternalsListHead;
205 while (Next)
206 {
207 ArgCount = 0;
208
209 /* Skip if External node already handled */
210
211 if (Next->Asl.Child->Asl.CompileFlags & OP_VISITED)
212 {
213 Next = Next->Asl.Next;
214 continue;
215 }
216
217 NameOp = Next->Asl.Child->Asl.Child;
218 ExternalName = AcpiNsGetNormalizedPathname (NameOp->Asl.Node, TRUE);
219
220 if (strcmp (CallName, ExternalName))
221 {
222 ACPI_FREE (ExternalName);
223 Next = Next->Asl.Next;
224 continue;
225 }
226
227 Next->Asl.Child->Asl.CompileFlags |= OP_VISITED;
228
229 /*
230 * Since we will reposition Externals to the Root, set Namepath
231 * to the fully qualified name and recalculate the aml length
232 */
233 Status = UtInternalizeName (ExternalName,
234 &NameOp->Asl.Value.String);
235
236 ACPI_FREE (ExternalName);
237 if (ACPI_FAILURE (Status))
238 {
239 AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
240 NULL, "- Could not Internalize External");
241 break;
242 }
243
244 NameOp->Asl.AmlLength = strlen (NameOp->Asl.Value.String);
245
246 /* Get argument count */
247
248 Child = Op->Asl.Child;
249 while (Child)
250 {
251 ArgCount++;
252 Child = Child->Asl.Next;
253 }
254
255 /* Setup ArgCount operand */
256
257 ArgCountOp = Next->Asl.Child->Asl.Child->Asl.Next->Asl.Next;
258 ArgCountOp->Asl.Value.Integer = ArgCount;
259 break;
260 }
261
262 ACPI_FREE (CallName);
263 }
264
265
266 /*******************************************************************************
267 *
268 * FUNCTION: ExAmlExternalWalkBegin
269 *
270 * PARAMETERS: ASL_WALK_CALLBACK
271 *
272 * RETURN: None
273 *
274 * DESCRIPTION: Parse tree walk to create external opcode list for methods.
275 *
276 ******************************************************************************/
277
278 ACPI_STATUS
ExAmlExternalWalkBegin(ACPI_PARSE_OBJECT * Op,UINT32 Level,void * Context)279 ExAmlExternalWalkBegin (
280 ACPI_PARSE_OBJECT *Op,
281 UINT32 Level,
282 void *Context)
283 {
284
285 /* External list head saved in the definition block op */
286
287 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
288 {
289 AslGbl_ExternalsListHead = Op->Asl.Value.Arg;
290 }
291
292 if (!AslGbl_ExternalsListHead)
293 {
294 return (AE_OK);
295 }
296
297 if (Op->Asl.ParseOpcode != PARSEOP_METHODCALL)
298 {
299 return (AE_OK);
300 }
301
302 /*
303 * The NameOp child under an ExternalOp gets turned into PARSE_METHODCALL
304 * by XfNamespaceLocateBegin(). Ignore these.
305 */
306 if (Op->Asl.Parent &&
307 Op->Asl.Parent->Asl.ParseOpcode == PARSEOP_EXTERNAL)
308 {
309 return (AE_OK);
310 }
311
312 ExInsertArgCount (Op);
313 return (AE_OK);
314 }
315
316
317 /*******************************************************************************
318 *
319 * FUNCTION: ExAmlExternalWalkEnd
320 *
321 * PARAMETERS: ASL_WALK_CALLBACK
322 *
323 * RETURN: None
324 *
325 * DESCRIPTION: Parse tree walk to create external opcode list for methods.
326 * Here, we just want to catch the case where a definition block
327 * has been completed. Then we move all of the externals into
328 * a single block in the parse tree and thus the AML code.
329 *
330 ******************************************************************************/
331
332 ACPI_STATUS
ExAmlExternalWalkEnd(ACPI_PARSE_OBJECT * Op,UINT32 Level,void * Context)333 ExAmlExternalWalkEnd (
334 ACPI_PARSE_OBJECT *Op,
335 UINT32 Level,
336 void *Context)
337 {
338
339 if (Op->Asl.ParseOpcode == PARSEOP_DEFINITION_BLOCK)
340 {
341 /*
342 * Process any existing external list. (Support for
343 * multiple definition blocks in a single file/compile)
344 */
345 ExMoveExternals (Op);
346 AslGbl_ExternalsListHead = NULL;
347 }
348
349 return (AE_OK);
350 }
351
352
353 /*******************************************************************************
354 *
355 * FUNCTION: ExMoveExternals
356 *
357 * PARAMETERS: DefinitionBlockOp - Op for current definition block
358 *
359 * RETURN: None
360 *
361 * DESCRIPTION: Move all externals present in the source file into a single
362 * block of AML code, surrounded by an "If (0)" to prevent
363 * AML interpreters from attempting to execute the External
364 * opcodes.
365 *
366 ******************************************************************************/
367
368 static void
ExMoveExternals(ACPI_PARSE_OBJECT * DefinitionBlockOp)369 ExMoveExternals (
370 ACPI_PARSE_OBJECT *DefinitionBlockOp)
371 {
372 ACPI_PARSE_OBJECT *ParentOp;
373 ACPI_PARSE_OBJECT *ExternalOp;
374 ACPI_PARSE_OBJECT *PredicateOp;
375 ACPI_PARSE_OBJECT *NextOp;
376 ACPI_PARSE_OBJECT *Prev;
377 ACPI_PARSE_OBJECT *Next;
378 char *ExternalName;
379 ACPI_OBJECT_TYPE ObjType;
380 ACPI_STATUS Status;
381 UINT32 i;
382
383
384 if (!AslGbl_ExternalsListHead)
385 {
386 return;
387 }
388
389 /* Remove the External nodes from the tree */
390
391 NextOp = AslGbl_ExternalsListHead;
392 while (NextOp)
393 {
394 /*
395 * The External is stored in child pointer of each node in the
396 * list
397 */
398 ExternalOp = NextOp->Asl.Child;
399
400 /* Get/set the fully qualified name */
401
402 ExternalName = AcpiNsGetNormalizedPathname (ExternalOp->Asl.Node, TRUE);
403 ExternalOp->Asl.ExternalName = ExternalName;
404 ExternalOp->Asl.Namepath = ExternalName;
405
406 /* Set line numbers (for listings, etc.) */
407
408 ExternalOp->Asl.LineNumber = 0;
409 ExternalOp->Asl.LogicalLineNumber = 0;
410
411 Next = ExternalOp->Asl.Child;
412 Next->Asl.LineNumber = 0;
413 Next->Asl.LogicalLineNumber = 0;
414
415 if (Next->Asl.ParseOpcode == PARSEOP_NAMESEG)
416 {
417 Next->Asl.ParseOpcode = PARSEOP_NAMESTRING;
418 }
419
420 Next->Asl.ExternalName = ExternalName;
421 Status = UtInternalizeName (ExternalName, &Next->Asl.Value.String);
422 if (ACPI_FAILURE (Status))
423 {
424 AslError (ASL_ERROR, ASL_MSG_COMPILER_INTERNAL,
425 Next, "Could not internalize namestring");
426 return;
427 }
428
429 Next->Asl.AmlLength = strlen (Next->Asl.Value.String);
430
431 Next = Next->Asl.Next;
432 Next->Asl.LineNumber = 0;
433 Next->Asl.LogicalLineNumber = 0;
434
435 Next = Next->Asl.Next;
436 Next->Asl.LineNumber = 0;
437 Next->Asl.LogicalLineNumber = 0;
438
439 Next = Next->Asl.Next;
440 Next->Asl.LineNumber = 0;
441 Next->Asl.LogicalLineNumber = 0;
442
443 ParentOp = ExternalOp->Asl.Parent;
444 Prev = Next = ParentOp->Asl.Child;
445
446 /* Now find the External node's position in parse tree */
447
448 while (Next != ExternalOp)
449 {
450 Prev = Next;
451 Next = Next->Asl.Next;
452 }
453
454 /* Remove the External from the parse tree */
455
456 if (Prev == ExternalOp)
457 {
458 /* External was the first child node */
459
460 ParentOp->Asl.Child = ExternalOp->Asl.Next;
461 }
462
463 Prev->Asl.Next = ExternalOp->Asl.Next;
464 ExternalOp->Asl.Next = NULL;
465 ExternalOp->Asl.Parent = AslGbl_ExternalsListHead;
466
467 /* Point the External to the next in the list */
468
469 if (NextOp->Asl.Next)
470 {
471 ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child;
472 }
473
474 NextOp = NextOp->Asl.Next;
475 }
476
477 /*
478 * Loop again to remove MethodObj Externals for which
479 * a MethodCall was not found (dead external reference)
480 */
481 Prev = AslGbl_ExternalsListHead->Asl.Child;
482 Next = Prev;
483 while (Next)
484 {
485 ObjType = (ACPI_OBJECT_TYPE)
486 Next->Asl.Child->Asl.Next->Asl.Value.Integer;
487
488 if (ObjType == ACPI_TYPE_METHOD &&
489 !(Next->Asl.CompileFlags & OP_VISITED))
490 {
491 if (Next == Prev)
492 {
493 AslGbl_ExternalsListHead->Asl.Child = Next->Asl.Next;
494 Next->Asl.Next = NULL;
495 Prev = AslGbl_ExternalsListHead->Asl.Child;
496 Next = Prev;
497 continue;
498 }
499 else
500 {
501 Prev->Asl.Next = Next->Asl.Next;
502 Next->Asl.Next = NULL;
503 Next = Prev->Asl.Next;
504 continue;
505 }
506 }
507
508 Prev = Next;
509 Next = Next->Asl.Next;
510 }
511
512 /* If list is now empty, don't bother to make If (0) block */
513
514 if (!AslGbl_ExternalsListHead->Asl.Child)
515 {
516 return;
517 }
518
519 /* Convert Gbl_ExternalsListHead parent to If(). */
520
521 AslGbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF;
522 AslGbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP;
523 AslGbl_ExternalsListHead->Asl.CompileFlags = OP_AML_PACKAGE;
524 UtSetParseOpName (AslGbl_ExternalsListHead);
525
526 /* Create a Zero op for the If predicate */
527
528 PredicateOp = TrAllocateOp (PARSEOP_ZERO);
529 PredicateOp->Asl.AmlOpcode = AML_ZERO_OP;
530
531 PredicateOp->Asl.Parent = AslGbl_ExternalsListHead;
532 PredicateOp->Asl.Child = NULL;
533 PredicateOp->Asl.Next = AslGbl_ExternalsListHead->Asl.Child;
534 AslGbl_ExternalsListHead->Asl.Child = PredicateOp;
535
536 /* Set line numbers (for listings, etc.) */
537
538 AslGbl_ExternalsListHead->Asl.LineNumber = 0;
539 AslGbl_ExternalsListHead->Asl.LogicalLineNumber = 0;
540
541 PredicateOp->Asl.LineNumber = 0;
542 PredicateOp->Asl.LogicalLineNumber = 0;
543
544 /* Insert block back in the list */
545
546 Prev = DefinitionBlockOp->Asl.Child;
547 Next = Prev;
548
549 /* Find last default arg */
550
551 for (i = 0; i < 6; i++)
552 {
553 Prev = Next;
554 Next = Prev->Asl.Next;
555 }
556
557 if (Next)
558 {
559 /* Definition Block is not empty */
560
561 AslGbl_ExternalsListHead->Asl.Next = Next;
562 }
563 else
564 {
565 /* Definition Block is empty. */
566
567 AslGbl_ExternalsListHead->Asl.Next = NULL;
568 }
569
570 Prev->Asl.Next = AslGbl_ExternalsListHead;
571 AslGbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent;
572 }
573