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