xref: /titanic_50/usr/src/uts/intel/io/acpica/disassembler/dmbuffer.c (revision a9478106a12424322498e53cf7cd75bd8a4d6004)
1 /*******************************************************************************
2  *
3  * Module Name: dmbuffer - AML disassembler, buffer and string support
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 
45 #include "acpi.h"
46 #include "accommon.h"
47 #include "acdisasm.h"
48 #include "acparser.h"
49 #include "amlcode.h"
50 
51 
52 #ifdef ACPI_DISASSEMBLER
53 
54 #define _COMPONENT          ACPI_CA_DEBUGGER
55         ACPI_MODULE_NAME    ("dmbuffer")
56 
57 /* Local prototypes */
58 
59 static void
60 AcpiDmUnicode (
61     ACPI_PARSE_OBJECT       *Op);
62 
63 static void
64 AcpiDmIsEisaIdElement (
65     ACPI_PARSE_OBJECT       *Op);
66 
67 
68 /*******************************************************************************
69  *
70  * FUNCTION:    AcpiDmDisasmByteList
71  *
72  * PARAMETERS:  Level               - Current source code indentation level
73  *              ByteData            - Pointer to the byte list
74  *              ByteCount           - Length of the byte list
75  *
76  * RETURN:      None
77  *
78  * DESCRIPTION: Dump an AML "ByteList" in Hex format. 8 bytes per line, prefixed
79  *              with the hex buffer offset.
80  *
81  ******************************************************************************/
82 
83 void
84 AcpiDmDisasmByteList (
85     UINT32                  Level,
86     UINT8                   *ByteData,
87     UINT32                  ByteCount)
88 {
89     UINT32                  i;
90 
91 
92     if (!ByteCount)
93     {
94         return;
95     }
96 
97     /* Dump the byte list */
98 
99     for (i = 0; i < ByteCount; i++)
100     {
101         /* New line every 8 bytes */
102 
103         if (((i % 8) == 0) && (i < ByteCount))
104         {
105             if (i > 0)
106             {
107                 AcpiOsPrintf ("\n");
108             }
109 
110             AcpiDmIndent (Level);
111             if (ByteCount > 7)
112             {
113                 AcpiOsPrintf ("/* %04X */    ", i);
114             }
115         }
116 
117         AcpiOsPrintf ("0x%2.2X", (UINT32) ByteData[i]);
118 
119         /* Add comma if there are more bytes to display */
120 
121         if (i < (ByteCount -1))
122         {
123             AcpiOsPrintf (", ");
124         }
125     }
126 
127     if (Level)
128     {
129         AcpiOsPrintf ("\n");
130     }
131 }
132 
133 
134 /*******************************************************************************
135  *
136  * FUNCTION:    AcpiDmByteList
137  *
138  * PARAMETERS:  Info            - Parse tree walk info
139  *              Op              - Byte list op
140  *
141  * RETURN:      None
142  *
143  * DESCRIPTION: Dump a buffer byte list, handling the various types of buffers.
144  *              Buffer type must be already set in the Op DisasmOpcode.
145  *
146  ******************************************************************************/
147 
148 void
149 AcpiDmByteList (
150     ACPI_OP_WALK_INFO       *Info,
151     ACPI_PARSE_OBJECT       *Op)
152 {
153     UINT8                   *ByteData;
154     UINT32                  ByteCount;
155 
156 
157     ByteData = Op->Named.Data;
158     ByteCount = (UINT32) Op->Common.Value.Integer;
159 
160     /*
161      * The byte list belongs to a buffer, and can be produced by either
162      * a ResourceTemplate, Unicode, quoted string, or a plain byte list.
163      */
164     switch (Op->Common.Parent->Common.DisasmOpcode)
165     {
166     case ACPI_DASM_RESOURCE:
167 
168         AcpiDmResourceTemplate (Info, Op->Common.Parent, ByteData, ByteCount);
169         break;
170 
171     case ACPI_DASM_STRING:
172 
173         AcpiDmIndent (Info->Level);
174         AcpiUtPrintString ((char *) ByteData, ACPI_UINT8_MAX);
175         AcpiOsPrintf ("\n");
176         break;
177 
178     case ACPI_DASM_UNICODE:
179 
180         AcpiDmUnicode (Op);
181         break;
182 
183     case ACPI_DASM_BUFFER:
184     default:
185 
186         /*
187          * Not a resource, string, or unicode string.
188          * Just dump the buffer
189          */
190         AcpiDmDisasmByteList (Info->Level, ByteData, ByteCount);
191         break;
192     }
193 }
194 
195 
196 /*******************************************************************************
197  *
198  * FUNCTION:    AcpiDmIsUnicodeBuffer
199  *
200  * PARAMETERS:  Op              - Buffer Object to be examined
201  *
202  * RETURN:      TRUE if buffer contains a UNICODE string
203  *
204  * DESCRIPTION: Determine if a buffer Op contains a Unicode string
205  *
206  ******************************************************************************/
207 
208 BOOLEAN
209 AcpiDmIsUnicodeBuffer (
210     ACPI_PARSE_OBJECT       *Op)
211 {
212     UINT8                   *ByteData;
213     UINT32                  ByteCount;
214     UINT32                  WordCount;
215     ACPI_PARSE_OBJECT       *SizeOp;
216     ACPI_PARSE_OBJECT       *NextOp;
217     UINT32                  i;
218 
219 
220     /* Buffer size is the buffer argument */
221 
222     SizeOp = Op->Common.Value.Arg;
223 
224     /* Next, the initializer byte list to examine */
225 
226     NextOp = SizeOp->Common.Next;
227     if (!NextOp)
228     {
229         return (FALSE);
230     }
231 
232     /* Extract the byte list info */
233 
234     ByteData = NextOp->Named.Data;
235     ByteCount = (UINT32) NextOp->Common.Value.Integer;
236     WordCount = ACPI_DIV_2 (ByteCount);
237 
238     /*
239      * Unicode string must have an even number of bytes and last
240      * word must be zero
241      */
242     if ((!ByteCount)     ||
243          (ByteCount < 4) ||
244          (ByteCount & 1) ||
245         ((UINT16 *) (void *) ByteData)[WordCount - 1] != 0)
246     {
247         return (FALSE);
248     }
249 
250     /* For each word, 1st byte must be ascii, 2nd byte must be zero */
251 
252     for (i = 0; i < (ByteCount - 2); i += 2)
253     {
254         if ((!ACPI_IS_PRINT (ByteData[i])) ||
255             (ByteData[(ACPI_SIZE) i + 1] != 0))
256         {
257             return (FALSE);
258         }
259     }
260 
261     /* Ignore the Size argument in the disassembly of this buffer op */
262 
263     SizeOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
264     return (TRUE);
265 }
266 
267 
268 /*******************************************************************************
269  *
270  * FUNCTION:    AcpiDmIsStringBuffer
271  *
272  * PARAMETERS:  Op              - Buffer Object to be examined
273  *
274  * RETURN:      TRUE if buffer contains a ASCII string, FALSE otherwise
275  *
276  * DESCRIPTION: Determine if a buffer Op contains a ASCII string
277  *
278  ******************************************************************************/
279 
280 BOOLEAN
281 AcpiDmIsStringBuffer (
282     ACPI_PARSE_OBJECT       *Op)
283 {
284     UINT8                   *ByteData;
285     UINT32                  ByteCount;
286     ACPI_PARSE_OBJECT       *SizeOp;
287     ACPI_PARSE_OBJECT       *NextOp;
288     UINT32                  i;
289 
290 
291     /* Buffer size is the buffer argument */
292 
293     SizeOp = Op->Common.Value.Arg;
294 
295     /* Next, the initializer byte list to examine */
296 
297     NextOp = SizeOp->Common.Next;
298     if (!NextOp)
299     {
300         return (FALSE);
301     }
302 
303     /* Extract the byte list info */
304 
305     ByteData = NextOp->Named.Data;
306     ByteCount = (UINT32) NextOp->Common.Value.Integer;
307 
308     /* Last byte must be the null terminator */
309 
310     if ((!ByteCount)     ||
311          (ByteCount < 2) ||
312          (ByteData[ByteCount-1] != 0))
313     {
314         return (FALSE);
315     }
316 
317     for (i = 0; i < (ByteCount - 1); i++)
318     {
319         /* TBD: allow some escapes (non-ascii chars).
320          * they will be handled in the string output routine
321          */
322 
323         if (!ACPI_IS_PRINT (ByteData[i]))
324         {
325             return (FALSE);
326         }
327     }
328 
329     return (TRUE);
330 }
331 
332 
333 /*******************************************************************************
334  *
335  * FUNCTION:    AcpiDmUnicode
336  *
337  * PARAMETERS:  Op              - Byte List op containing Unicode string
338  *
339  * RETURN:      None
340  *
341  * DESCRIPTION: Dump Unicode string as a standard ASCII string.  (Remove
342  *              the extra zero bytes).
343  *
344  ******************************************************************************/
345 
346 static void
347 AcpiDmUnicode (
348     ACPI_PARSE_OBJECT       *Op)
349 {
350     UINT16                  *WordData;
351     UINT32                  WordCount;
352     UINT32                  i;
353 
354 
355     /* Extract the buffer info as a WORD buffer */
356 
357     WordData = ACPI_CAST_PTR (UINT16, Op->Named.Data);
358     WordCount = ACPI_DIV_2 (((UINT32) Op->Common.Value.Integer));
359 
360 
361     AcpiOsPrintf ("\"");
362 
363     /* Write every other byte as an ASCII character */
364 
365     for (i = 0; i < (WordCount - 1); i++)
366     {
367         AcpiOsPrintf ("%c", (int) WordData[i]);
368     }
369 
370     AcpiOsPrintf ("\")");
371 }
372 
373 
374 /*******************************************************************************
375  *
376  * FUNCTION:    AcpiDmIsEisaIdElement
377  *
378  * PARAMETERS:  Op              - Op to be examined
379  *
380  * RETURN:      None
381  *
382  * DESCRIPTION: Determine if an Op (argument to _HID or _CID) can be converted
383  *              to an EISA ID.
384  *
385  ******************************************************************************/
386 
387 static void
388 AcpiDmIsEisaIdElement (
389     ACPI_PARSE_OBJECT       *Op)
390 {
391     UINT32                  BigEndianId;
392     UINT32                  Prefix[3];
393     UINT32                  i;
394 
395 
396     /* The parameter must be either a word or a dword */
397 
398     if ((Op->Common.AmlOpcode != AML_DWORD_OP) &&
399         (Op->Common.AmlOpcode != AML_WORD_OP))
400     {
401         return;
402     }
403 
404     /* Swap from little-endian to big-endian to simplify conversion */
405 
406     BigEndianId = AcpiUtDwordByteSwap ((UINT32) Op->Common.Value.Integer);
407 
408     /* Create the 3 leading ASCII letters */
409 
410     Prefix[0] = ((BigEndianId >> 26) & 0x1F) + 0x40;
411     Prefix[1] = ((BigEndianId >> 21) & 0x1F) + 0x40;
412     Prefix[2] = ((BigEndianId >> 16) & 0x1F) + 0x40;
413 
414     /* Verify that all 3 are ascii and alpha */
415 
416     for (i = 0; i < 3; i++)
417     {
418         if (!ACPI_IS_ASCII (Prefix[i]) ||
419             !ACPI_IS_ALPHA (Prefix[i]))
420         {
421             return;
422         }
423     }
424 
425     /* OK - mark this node as convertable to an EISA ID */
426 
427     Op->Common.DisasmOpcode = ACPI_DASM_EISAID;
428 }
429 
430 
431 /*******************************************************************************
432  *
433  * FUNCTION:    AcpiDmIsEisaId
434  *
435  * PARAMETERS:  Op              - Op to be examined
436  *
437  * RETURN:      None
438  *
439  * DESCRIPTION: Determine if a Name() Op can be converted to an EisaId.
440  *
441  ******************************************************************************/
442 
443 void
444 AcpiDmIsEisaId (
445     ACPI_PARSE_OBJECT       *Op)
446 {
447     UINT32                  Name;
448     ACPI_PARSE_OBJECT       *NextOp;
449 
450 
451     /* Get the NameSegment */
452 
453     Name = AcpiPsGetName (Op);
454     if (!Name)
455     {
456         return;
457     }
458 
459     NextOp = AcpiPsGetDepthNext (NULL, Op);
460     if (!NextOp)
461     {
462         return;
463     }
464 
465     /* Check for _HID - has one argument */
466 
467     if (ACPI_COMPARE_NAME (&Name, METHOD_NAME__HID))
468     {
469         AcpiDmIsEisaIdElement (NextOp);
470         return;
471     }
472 
473     /* Exit if not _CID */
474 
475     if (!ACPI_COMPARE_NAME (&Name, METHOD_NAME__CID))
476     {
477         return;
478     }
479 
480     /* _CID can contain a single argument or a package */
481 
482     if (NextOp->Common.AmlOpcode != AML_PACKAGE_OP)
483     {
484         AcpiDmIsEisaIdElement (NextOp);
485         return;
486     }
487 
488     /* _CID with Package: get the package length */
489 
490     NextOp = AcpiPsGetDepthNext (NULL, NextOp);
491 
492     /* Don't need to use the length, just walk the peer list */
493 
494     NextOp = NextOp->Common.Next;
495     while (NextOp)
496     {
497         AcpiDmIsEisaIdElement (NextOp);
498         NextOp = NextOp->Common.Next;
499     }
500 }
501 
502 
503 /*******************************************************************************
504  *
505  * FUNCTION:    AcpiDmEisaId
506  *
507  * PARAMETERS:  EncodedId       - Raw encoded EISA ID.
508  *
509  * RETURN:      None
510  *
511  * DESCRIPTION: Convert an encoded EISAID back to the original ASCII String.
512  *
513  ******************************************************************************/
514 
515 void
516 AcpiDmEisaId (
517     UINT32                  EncodedId)
518 {
519     UINT32                  BigEndianId;
520 
521 
522     /* Swap from little-endian to big-endian to simplify conversion */
523 
524     BigEndianId = AcpiUtDwordByteSwap (EncodedId);
525 
526 
527     /* Split to form "AAANNNN" string */
528 
529     AcpiOsPrintf ("EisaId (\"%c%c%c%4.4X\")",
530 
531         /* Three Alpha characters (AAA), 5 bits each */
532 
533         (int) ((BigEndianId >> 26) & 0x1F) + 0x40,
534         (int) ((BigEndianId >> 21) & 0x1F) + 0x40,
535         (int) ((BigEndianId >> 16) & 0x1F) + 0x40,
536 
537         /* Numeric part (NNNN) is simply the lower 16 bits */
538 
539         (UINT32) (BigEndianId & 0xFFFF));
540 }
541 
542 #endif
543