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