aslexternal.c revision 1.1 1 /******************************************************************************
2 *
3 * Module Name: aslexternal - ASL External opcode compiler support
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2016, 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 = TrAllocateNode (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 & NODE_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 |= NODE_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 ACPI_OBJECT_TYPE ObjType;
329 UINT32 i;
330
331
332 if (!Gbl_ExternalsListHead)
333 {
334 return;
335 }
336
337 /* Remove the External nodes from the tree */
338
339 NextOp = Gbl_ExternalsListHead;
340 while (NextOp)
341 {
342 /*
343 * The External is stored in child pointer of each node in the
344 * list
345 */
346 ExternalOp = NextOp->Asl.Child;
347
348 /* Set line numbers (for listings, etc.) */
349
350 ExternalOp->Asl.LineNumber = 0;
351 ExternalOp->Asl.LogicalLineNumber = 0;
352
353 Next = ExternalOp->Asl.Child;
354 Next->Asl.LineNumber = 0;
355 Next->Asl.LogicalLineNumber = 0;
356
357 Next = Next->Asl.Next;
358 Next->Asl.LineNumber = 0;
359 Next->Asl.LogicalLineNumber = 0;
360
361 Next = Next->Asl.Next;
362 Next->Asl.LineNumber = 0;
363 Next->Asl.LogicalLineNumber = 0;
364
365 Next = Next->Asl.Next;
366 Next->Asl.LineNumber = 0;
367 Next->Asl.LogicalLineNumber = 0;
368
369 ParentOp = ExternalOp->Asl.Parent;
370 Prev = Next = ParentOp->Asl.Child;
371
372 /* Now find the External node's position in parse tree */
373
374 while (Next != ExternalOp)
375 {
376 Prev = Next;
377 Next = Next->Asl.Next;
378 }
379
380 /* Remove the External from the parse tree */
381
382 if (Prev == ExternalOp)
383 {
384 /* External was the first child node */
385
386 ParentOp->Asl.Child = ExternalOp->Asl.Next;
387 }
388
389 Prev->Asl.Next = ExternalOp->Asl.Next;
390 ExternalOp->Asl.Next = NULL;
391 ExternalOp->Asl.Parent = Gbl_ExternalsListHead;
392
393 /* Point the External to the next in the list */
394
395 if (NextOp->Asl.Next)
396 {
397 ExternalOp->Asl.Next = NextOp->Asl.Next->Asl.Child;
398 }
399
400 NextOp = NextOp->Asl.Next;
401 }
402
403 /*
404 * Loop again to remove MethodObj Externals for which
405 * a MethodCall was not found (dead external reference)
406 */
407 Prev = Gbl_ExternalsListHead->Asl.Child;
408 Next = Prev;
409 while (Next)
410 {
411 ObjType = (ACPI_OBJECT_TYPE)
412 Next->Asl.Child->Asl.Next->Asl.Value.Integer;
413
414 if (ObjType == ACPI_TYPE_METHOD &&
415 !(Next->Asl.CompileFlags & NODE_VISITED))
416 {
417 if (Next == Prev)
418 {
419 Gbl_ExternalsListHead->Asl.Child = Next->Asl.Next;
420 Next->Asl.Next = NULL;
421 Prev = Gbl_ExternalsListHead->Asl.Child;
422 Next = Prev;
423 continue;
424 }
425 else
426 {
427 Prev->Asl.Next = Next->Asl.Next;
428 Next->Asl.Next = NULL;
429 Next = Prev->Asl.Next;
430 continue;
431 }
432 }
433
434 Prev = Next;
435 Next = Next->Asl.Next;
436 }
437
438 /* If list is now empty, don't bother to make If (0) block */
439
440 if (!Gbl_ExternalsListHead->Asl.Child)
441 {
442 return;
443 }
444
445 /* Convert Gbl_ExternalsListHead parent to If(). */
446
447 Gbl_ExternalsListHead->Asl.ParseOpcode = PARSEOP_IF;
448 Gbl_ExternalsListHead->Asl.AmlOpcode = AML_IF_OP;
449 Gbl_ExternalsListHead->Asl.CompileFlags = NODE_AML_PACKAGE;
450 UtSetParseOpName (Gbl_ExternalsListHead);
451
452 /* Create a Zero op for the If predicate */
453
454 PredicateOp = TrAllocateNode (PARSEOP_ZERO);
455 PredicateOp->Asl.AmlOpcode = AML_ZERO_OP;
456
457 PredicateOp->Asl.Parent = Gbl_ExternalsListHead;
458 PredicateOp->Asl.Child = NULL;
459 PredicateOp->Asl.Next = Gbl_ExternalsListHead->Asl.Child;
460 Gbl_ExternalsListHead->Asl.Child = PredicateOp;
461
462 /* Set line numbers (for listings, etc.) */
463
464 Gbl_ExternalsListHead->Asl.LineNumber = 0;
465 Gbl_ExternalsListHead->Asl.LogicalLineNumber = 0;
466
467 PredicateOp->Asl.LineNumber = 0;
468 PredicateOp->Asl.LogicalLineNumber = 0;
469
470 /* Insert block back in the list */
471
472 Prev = DefinitionBlockOp->Asl.Child;
473 Next = Prev;
474
475 /* Find last default arg */
476
477 for (i = 0; i < 6; i++)
478 {
479 Prev = Next;
480 Next = Prev->Asl.Next;
481 }
482
483 if (Next)
484 {
485 /* Definition Block is not empty */
486
487 Gbl_ExternalsListHead->Asl.Next = Next;
488 }
489 else
490 {
491 /* Definition Block is empty. */
492
493 Gbl_ExternalsListHead->Asl.Next = NULL;
494 }
495
496 Prev->Asl.Next = Gbl_ExternalsListHead;
497 Gbl_ExternalsListHead->Asl.Parent = Prev->Asl.Parent;
498 }
499