dmextern.c revision 1.1.1.2.8.2 1 /******************************************************************************
2 *
3 * Module Name: dmextern - Support for External() ASL statements
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2011, 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 "acpi.h"
45 #include "accommon.h"
46 #include "amlcode.h"
47 #include "acnamesp.h"
48 #include "acdisasm.h"
49
50
51 /*
52 * This module is used for application-level code (iASL disassembler) only.
53 *
54 * It contains the code to create and emit any necessary External() ASL
55 * statements for the module being disassembled.
56 */
57 #define _COMPONENT ACPI_CA_DISASSEMBLER
58 ACPI_MODULE_NAME ("dmextern")
59
60
61 /*
62 * This table maps ACPI_OBJECT_TYPEs to the corresponding ASL
63 * ObjectTypeKeyword. Used to generate typed external declarations
64 */
65 static const char *AcpiGbl_DmTypeNames[] =
66 {
67 /* 00 */ "", /* Type ANY */
68 /* 01 */ ", IntObj",
69 /* 02 */ ", StrObj",
70 /* 03 */ ", BuffObj",
71 /* 04 */ ", PkgObj",
72 /* 05 */ ", FieldUnitObj",
73 /* 06 */ ", DeviceObj",
74 /* 07 */ ", EventObj",
75 /* 08 */ ", MethodObj",
76 /* 09 */ ", MutexObj",
77 /* 10 */ ", OpRegionObj",
78 /* 11 */ ", PowerResObj",
79 /* 12 */ ", ProcessorObj",
80 /* 13 */ ", ThermalZoneObj",
81 /* 14 */ ", BuffFieldObj",
82 /* 15 */ ", DDBHandleObj",
83 /* 16 */ "", /* Debug object */
84 /* 17 */ ", FieldUnitObj",
85 /* 18 */ ", FieldUnitObj",
86 /* 19 */ ", FieldUnitObj"
87 };
88
89
90 /* Local prototypes */
91
92 static const char *
93 AcpiDmGetObjectTypeName (
94 ACPI_OBJECT_TYPE Type);
95
96 static char *
97 AcpiDmNormalizeParentPrefix (
98 ACPI_PARSE_OBJECT *Op,
99 char *Path);
100
101
102 /*******************************************************************************
103 *
104 * FUNCTION: AcpiDmGetObjectTypeName
105 *
106 * PARAMETERS: Type - An ACPI_OBJECT_TYPE
107 *
108 * RETURN: Pointer to a string
109 *
110 * DESCRIPTION: Map an object type to the ASL object type string.
111 *
112 ******************************************************************************/
113
114 static const char *
115 AcpiDmGetObjectTypeName (
116 ACPI_OBJECT_TYPE Type)
117 {
118
119 if (Type == ACPI_TYPE_LOCAL_SCOPE)
120 {
121 Type = ACPI_TYPE_DEVICE;
122 }
123
124 else if (Type > ACPI_TYPE_LOCAL_INDEX_FIELD)
125 {
126 return ("");
127 }
128
129 return (AcpiGbl_DmTypeNames[Type]);
130 }
131
132
133 /*******************************************************************************
134 *
135 * FUNCTION: AcpiDmNormalizeParentPrefix
136 *
137 * PARAMETERS: Op - Parse op
138 * Path - Path with parent prefix
139 *
140 * RETURN: The full pathname to the object (from the namespace root)
141 *
142 * DESCRIPTION: Returns the full pathname of a path with parent prefix
143 * The caller must free the fullpath returned.
144 *
145 ******************************************************************************/
146
147 static char *
148 AcpiDmNormalizeParentPrefix (
149 ACPI_PARSE_OBJECT *Op,
150 char *Path)
151 {
152 ACPI_NAMESPACE_NODE *Node;
153 char *Fullpath;
154 char *ParentPath;
155 ACPI_SIZE Length;
156
157
158 /* Search upwards in the parse tree until we reach a namespace node */
159
160 while (Op)
161 {
162 if (Op->Common.Node)
163 {
164 break;
165 }
166
167 Op = Op->Common.Parent;
168 }
169
170 if (!Op)
171 {
172 return (NULL);
173 }
174
175 /*
176 * Find the actual parent node for the reference:
177 * Remove all carat prefixes from the input path.
178 * There may be multiple parent prefixes (For example, ^^^M000)
179 */
180 Node = Op->Common.Node;
181 while (Node && (*Path == (UINT8) AML_PARENT_PREFIX))
182 {
183 Node = Node->Parent;
184 Path++;
185 }
186
187 if (!Node)
188 {
189 return (NULL);
190 }
191
192 /* Get the full pathname for the parent node */
193
194 ParentPath = AcpiNsGetExternalPathname (Node);
195 if (!ParentPath)
196 {
197 return (NULL);
198 }
199
200 Length = (ACPI_STRLEN (ParentPath) + ACPI_STRLEN (Path) + 1);
201 if (ParentPath[1])
202 {
203 /*
204 * If ParentPath is not just a simple '\', increment the length
205 * for the required dot separator (ParentPath.Path)
206 */
207 Length++;
208 }
209
210 Fullpath = ACPI_ALLOCATE_ZEROED (Length);
211 if (!Fullpath)
212 {
213 goto Cleanup;
214 }
215
216 /*
217 * Concatenate parent fullpath and path. For example,
218 * parent fullpath "\_SB_", Path "^INIT", Fullpath "\_SB_.INIT"
219 *
220 * Copy the parent path
221 */
222 ACPI_STRCAT (Fullpath, ParentPath);
223
224 /* Add dot separator (don't need dot if parent fullpath is a single "\") */
225
226 if (ParentPath[1])
227 {
228 ACPI_STRCAT (Fullpath, ".");
229 }
230
231 /* Copy child path (carat parent prefix(es) were skipped above) */
232
233 ACPI_STRCAT (Fullpath, Path);
234
235 Cleanup:
236 ACPI_FREE (ParentPath);
237 return (Fullpath);
238 }
239
240
241 /*******************************************************************************
242 *
243 * FUNCTION: AcpiDmAddToExternalFileList
244 *
245 * PARAMETERS: PathList - Single path or list separated by comma
246 *
247 * RETURN: None
248 *
249 * DESCRIPTION: Add external files to global list
250 *
251 ******************************************************************************/
252
253 ACPI_STATUS
254 AcpiDmAddToExternalFileList (
255 char *PathList)
256 {
257 ACPI_EXTERNAL_FILE *ExternalFile;
258 char *Path;
259 char *TmpPath;
260
261
262 if (!PathList)
263 {
264 return (AE_OK);
265 }
266
267 Path = strtok (PathList, ",");
268
269 while (Path)
270 {
271 TmpPath = ACPI_ALLOCATE_ZEROED (ACPI_STRLEN (Path) + 1);
272 if (!TmpPath)
273 {
274 return (AE_NO_MEMORY);
275 }
276
277 ACPI_STRCPY (TmpPath, Path);
278
279 ExternalFile = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_FILE));
280 if (!ExternalFile)
281 {
282 ACPI_FREE (TmpPath);
283 return (AE_NO_MEMORY);
284 }
285
286 ExternalFile->Path = TmpPath;
287
288 if (AcpiGbl_ExternalFileList)
289 {
290 ExternalFile->Next = AcpiGbl_ExternalFileList;
291 }
292
293 AcpiGbl_ExternalFileList = ExternalFile;
294 Path = strtok (NULL, ",");
295 }
296
297 return (AE_OK);
298 }
299
300
301 /*******************************************************************************
302 *
303 * FUNCTION: AcpiDmClearExternalFileList
304 *
305 * PARAMETERS: None
306 *
307 * RETURN: None
308 *
309 * DESCRIPTION: Clear the external file list
310 *
311 ******************************************************************************/
312
313 void
314 AcpiDmClearExternalFileList (
315 void)
316 {
317 ACPI_EXTERNAL_FILE *NextExternal;
318
319
320 while (AcpiGbl_ExternalFileList)
321 {
322 NextExternal = AcpiGbl_ExternalFileList->Next;
323 ACPI_FREE (AcpiGbl_ExternalFileList->Path);
324 ACPI_FREE (AcpiGbl_ExternalFileList);
325 AcpiGbl_ExternalFileList = NextExternal;
326 }
327 }
328
329
330 /*******************************************************************************
331 *
332 * FUNCTION: AcpiDmAddToExternalList
333 *
334 * PARAMETERS: Op - Current parser Op
335 * Path - Internal (AML) path to the object
336 * Type - ACPI object type to be added
337 * Value - Arg count if adding a Method object
338 *
339 * RETURN: None
340 *
341 * DESCRIPTION: Insert a new name into the global list of Externals which
342 * will in turn be later emitted as an External() declaration
343 * in the disassembled output.
344 *
345 ******************************************************************************/
346
347 void
348 AcpiDmAddToExternalList (
349 ACPI_PARSE_OBJECT *Op,
350 char *Path,
351 UINT8 Type,
352 UINT32 Value)
353 {
354 char *ExternalPath;
355 char *Fullpath = NULL;
356 ACPI_EXTERNAL_LIST *NewExternal;
357 ACPI_EXTERNAL_LIST *NextExternal;
358 ACPI_EXTERNAL_LIST *PrevExternal = NULL;
359 ACPI_STATUS Status;
360
361
362 if (!Path)
363 {
364 return;
365 }
366
367 /* Externalize the ACPI path */
368
369 Status = AcpiNsExternalizeName (ACPI_UINT32_MAX, Path,
370 NULL, &ExternalPath);
371 if (ACPI_FAILURE (Status))
372 {
373 return;
374 }
375
376 /* Get the full pathname from root if "Path" has a parent prefix */
377
378 if (*Path == (UINT8) AML_PARENT_PREFIX)
379 {
380 Fullpath = AcpiDmNormalizeParentPrefix (Op, ExternalPath);
381 if (Fullpath)
382 {
383 /* Set new external path */
384
385 ACPI_FREE (ExternalPath);
386 ExternalPath = Fullpath;
387 }
388 }
389
390 /* Check all existing externals to ensure no duplicates */
391
392 NextExternal = AcpiGbl_ExternalList;
393 while (NextExternal)
394 {
395 if (!ACPI_STRCMP (ExternalPath, NextExternal->Path))
396 {
397 /* Duplicate method, check that the Value (ArgCount) is the same */
398
399 if ((NextExternal->Type == ACPI_TYPE_METHOD) &&
400 (NextExternal->Value != Value))
401 {
402 ACPI_ERROR ((AE_INFO,
403 "Argument count mismatch for method %s %u %u",
404 NextExternal->Path, NextExternal->Value, Value));
405 }
406
407 /* Allow upgrade of type from ANY */
408
409 else if (NextExternal->Type == ACPI_TYPE_ANY)
410 {
411 NextExternal->Type = Type;
412 NextExternal->Value = Value;
413 }
414
415 ACPI_FREE (ExternalPath);
416 return;
417 }
418
419 NextExternal = NextExternal->Next;
420 }
421
422 /* Allocate and init a new External() descriptor */
423
424 NewExternal = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_EXTERNAL_LIST));
425 if (!NewExternal)
426 {
427 ACPI_FREE (ExternalPath);
428 return;
429 }
430
431 NewExternal->Path = ExternalPath;
432 NewExternal->Type = Type;
433 NewExternal->Value = Value;
434 NewExternal->Length = (UINT16) ACPI_STRLEN (ExternalPath);
435
436 /* Was the external path with parent prefix normalized to a fullpath? */
437
438 if (Fullpath == ExternalPath)
439 {
440 /* Get new internal path */
441
442 Status = AcpiNsInternalizeName (ExternalPath, &Path);
443 if (ACPI_FAILURE (Status))
444 {
445 ACPI_FREE (ExternalPath);
446 ACPI_FREE (NewExternal);
447 return;
448 }
449
450 /* Set flag to indicate External->InternalPath need to be freed */
451
452 NewExternal->Flags |= ACPI_IPATH_ALLOCATED;
453 }
454
455 NewExternal->InternalPath = Path;
456
457 /* Link the new descriptor into the global list, ordered by string length */
458
459 NextExternal = AcpiGbl_ExternalList;
460 while (NextExternal)
461 {
462 if (NewExternal->Length <= NextExternal->Length)
463 {
464 if (PrevExternal)
465 {
466 PrevExternal->Next = NewExternal;
467 }
468 else
469 {
470 AcpiGbl_ExternalList = NewExternal;
471 }
472
473 NewExternal->Next = NextExternal;
474 return;
475 }
476
477 PrevExternal = NextExternal;
478 NextExternal = NextExternal->Next;
479 }
480
481 if (PrevExternal)
482 {
483 PrevExternal->Next = NewExternal;
484 }
485 else
486 {
487 AcpiGbl_ExternalList = NewExternal;
488 }
489 }
490
491
492 /*******************************************************************************
493 *
494 * FUNCTION: AcpiDmAddExternalsToNamespace
495 *
496 * PARAMETERS: None
497 *
498 * RETURN: None
499 *
500 * DESCRIPTION: Add all externals to the namespace. Allows externals to be
501 * "resolved".
502 *
503 ******************************************************************************/
504
505 void
506 AcpiDmAddExternalsToNamespace (
507 void)
508 {
509 ACPI_STATUS Status;
510 ACPI_NAMESPACE_NODE *Node;
511 ACPI_OPERAND_OBJECT *MethodDesc;
512 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList;
513
514
515 while (External)
516 {
517 /* Add the external name (object) into the namespace */
518
519 Status = AcpiNsLookup (NULL, External->InternalPath, External->Type,
520 ACPI_IMODE_LOAD_PASS1,
521 ACPI_NS_EXTERNAL | ACPI_NS_DONT_OPEN_SCOPE,
522 NULL, &Node);
523
524 if (ACPI_FAILURE (Status))
525 {
526 ACPI_EXCEPTION ((AE_INFO, Status,
527 "while adding external to namespace [%s]",
528 External->Path));
529 }
530 else if (External->Type == ACPI_TYPE_METHOD)
531 {
532 /* For methods, we need to save the argument count */
533
534 MethodDesc = AcpiUtCreateInternalObject (ACPI_TYPE_METHOD);
535 MethodDesc->Method.ParamCount = (UINT8) External->Value;
536 Node->Object = MethodDesc;
537 }
538
539 External = External->Next;
540 }
541 }
542
543
544 /*******************************************************************************
545 *
546 * FUNCTION: AcpiDmGetExternalMethodCount
547 *
548 * PARAMETERS: None
549 *
550 * RETURN: The number of control method externals in the external list
551 *
552 * DESCRIPTION: Return the number of method externals that have been generated.
553 * If any control method externals have been found, we must
554 * re-parse the entire definition block with the new information
555 * (number of arguments for the methods.) This is limitation of
556 * AML, we don't know the number of arguments from the control
557 * method invocation itself.
558 *
559 ******************************************************************************/
560
561 UINT32
562 AcpiDmGetExternalMethodCount (
563 void)
564 {
565 ACPI_EXTERNAL_LIST *External = AcpiGbl_ExternalList;
566 UINT32 Count = 0;
567
568
569 while (External)
570 {
571 if (External->Type == ACPI_TYPE_METHOD)
572 {
573 Count++;
574 }
575
576 External = External->Next;
577 }
578
579 return (Count);
580 }
581
582
583 /*******************************************************************************
584 *
585 * FUNCTION: AcpiDmClearExternalList
586 *
587 * PARAMETERS: None
588 *
589 * RETURN: None
590 *
591 * DESCRIPTION: Free the entire External info list
592 *
593 ******************************************************************************/
594
595 void
596 AcpiDmClearExternalList (
597 void)
598 {
599 ACPI_EXTERNAL_LIST *NextExternal;
600
601
602 while (AcpiGbl_ExternalList)
603 {
604 NextExternal = AcpiGbl_ExternalList->Next;
605 ACPI_FREE (AcpiGbl_ExternalList->Path);
606 ACPI_FREE (AcpiGbl_ExternalList);
607 AcpiGbl_ExternalList = NextExternal;
608 }
609 }
610
611
612 /*******************************************************************************
613 *
614 * FUNCTION: AcpiDmEmitExternals
615 *
616 * PARAMETERS: None
617 *
618 * RETURN: None
619 *
620 * DESCRIPTION: Emit an External() ASL statement for each of the externals in
621 * the global external info list.
622 *
623 ******************************************************************************/
624
625 void
626 AcpiDmEmitExternals (
627 void)
628 {
629 ACPI_EXTERNAL_LIST *NextExternal;
630
631
632 if (!AcpiGbl_ExternalList)
633 {
634 return;
635 }
636
637 /*
638 * Walk the list of externals (unresolved references)
639 * found during the AML parsing
640 */
641 while (AcpiGbl_ExternalList)
642 {
643 AcpiOsPrintf (" External (%s%s",
644 AcpiGbl_ExternalList->Path,
645 AcpiDmGetObjectTypeName (AcpiGbl_ExternalList->Type));
646
647 if (AcpiGbl_ExternalList->Type == ACPI_TYPE_METHOD)
648 {
649 AcpiOsPrintf (") // %u Arguments\n",
650 AcpiGbl_ExternalList->Value);
651 }
652 else
653 {
654 AcpiOsPrintf (")\n");
655 }
656
657 /* Free this external info block and move on to next external */
658
659 NextExternal = AcpiGbl_ExternalList->Next;
660 if (AcpiGbl_ExternalList->Flags & ACPI_IPATH_ALLOCATED)
661 {
662 ACPI_FREE (AcpiGbl_ExternalList->InternalPath);
663 }
664
665 ACPI_FREE (AcpiGbl_ExternalList->Path);
666 ACPI_FREE (AcpiGbl_ExternalList);
667 AcpiGbl_ExternalList = NextExternal;
668 }
669
670 AcpiOsPrintf ("\n");
671 }
672
673