xref: /freebsd/sys/contrib/dev/acpica/components/disassembler/dmbuffer.c (revision ddd5b8e9b4d8957fce018c520657cdfa4ecffad3)
1 /*******************************************************************************
2  *
3  * Module Name: dmbuffer - AML disassembler, buffer and string support
4  *
5  ******************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2013, 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 <contrib/dev/acpica/include/acpi.h>
46 #include <contrib/dev/acpica/include/accommon.h>
47 #include <contrib/dev/acpica/include/acdisasm.h>
48 #include <contrib/dev/acpica/include/acparser.h>
49 #include <contrib/dev/acpica/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 static void
68 AcpiDmPldBuffer (
69     UINT32                  Level,
70     UINT8                   *ByteData,
71     UINT32                  ByteCount);
72 
73 
74 /*******************************************************************************
75  *
76  * FUNCTION:    AcpiDmDisasmByteList
77  *
78  * PARAMETERS:  Level               - Current source code indentation level
79  *              ByteData            - Pointer to the byte list
80  *              ByteCount           - Length of the byte list
81  *
82  * RETURN:      None
83  *
84  * DESCRIPTION: Dump an AML "ByteList" in Hex format. 8 bytes per line, prefixed
85  *              with the hex buffer offset.
86  *
87  ******************************************************************************/
88 
89 void
90 AcpiDmDisasmByteList (
91     UINT32                  Level,
92     UINT8                   *ByteData,
93     UINT32                  ByteCount)
94 {
95     UINT32                  i;
96 
97 
98     if (!ByteCount)
99     {
100         return;
101     }
102 
103     /* Dump the byte list */
104 
105     for (i = 0; i < ByteCount; i++)
106     {
107         /* New line every 8 bytes */
108 
109         if (((i % 8) == 0) && (i < ByteCount))
110         {
111             if (i > 0)
112             {
113                 AcpiOsPrintf ("\n");
114             }
115 
116             AcpiDmIndent (Level);
117             if (ByteCount > 8)
118             {
119                 AcpiOsPrintf ("/* %04X */  ", i);
120             }
121         }
122 
123         AcpiOsPrintf (" 0x%2.2X", (UINT32) ByteData[i]);
124 
125         /* Add comma if there are more bytes to display */
126 
127         if (i < (ByteCount -1))
128         {
129             AcpiOsPrintf (",");
130         }
131     }
132 
133     if (Level)
134     {
135         AcpiOsPrintf ("\n");
136     }
137 }
138 
139 
140 /*******************************************************************************
141  *
142  * FUNCTION:    AcpiDmByteList
143  *
144  * PARAMETERS:  Info            - Parse tree walk info
145  *              Op              - Byte list op
146  *
147  * RETURN:      None
148  *
149  * DESCRIPTION: Dump a buffer byte list, handling the various types of buffers.
150  *              Buffer type must be already set in the Op DisasmOpcode.
151  *
152  ******************************************************************************/
153 
154 void
155 AcpiDmByteList (
156     ACPI_OP_WALK_INFO       *Info,
157     ACPI_PARSE_OBJECT       *Op)
158 {
159     UINT8                   *ByteData;
160     UINT32                  ByteCount;
161 
162 
163     ByteData = Op->Named.Data;
164     ByteCount = (UINT32) Op->Common.Value.Integer;
165 
166     /*
167      * The byte list belongs to a buffer, and can be produced by either
168      * a ResourceTemplate, Unicode, quoted string, or a plain byte list.
169      */
170     switch (Op->Common.Parent->Common.DisasmOpcode)
171     {
172     case ACPI_DASM_RESOURCE:
173 
174         AcpiDmResourceTemplate (Info, Op->Common.Parent, ByteData, ByteCount);
175         break;
176 
177     case ACPI_DASM_STRING:
178 
179         AcpiDmIndent (Info->Level);
180         AcpiUtPrintString ((char *) ByteData, ACPI_UINT8_MAX);
181         AcpiOsPrintf ("\n");
182         break;
183 
184     case ACPI_DASM_UNICODE:
185 
186         AcpiDmUnicode (Op);
187         break;
188 
189     case ACPI_DASM_PLD_METHOD:
190 
191         AcpiDmDisasmByteList (Info->Level, ByteData, ByteCount);
192         AcpiDmPldBuffer (Info->Level, ByteData, ByteCount);
193         break;
194 
195     case ACPI_DASM_BUFFER:
196     default:
197 
198         /*
199          * Not a resource, string, or unicode string.
200          * Just dump the buffer
201          */
202         AcpiDmDisasmByteList (Info->Level, ByteData, ByteCount);
203         break;
204     }
205 }
206 
207 
208 /*******************************************************************************
209  *
210  * FUNCTION:    AcpiDmIsUnicodeBuffer
211  *
212  * PARAMETERS:  Op              - Buffer Object to be examined
213  *
214  * RETURN:      TRUE if buffer contains a UNICODE string
215  *
216  * DESCRIPTION: Determine if a buffer Op contains a Unicode string
217  *
218  ******************************************************************************/
219 
220 BOOLEAN
221 AcpiDmIsUnicodeBuffer (
222     ACPI_PARSE_OBJECT       *Op)
223 {
224     UINT8                   *ByteData;
225     UINT32                  ByteCount;
226     UINT32                  WordCount;
227     ACPI_PARSE_OBJECT       *SizeOp;
228     ACPI_PARSE_OBJECT       *NextOp;
229     UINT32                  i;
230 
231 
232     /* Buffer size is the buffer argument */
233 
234     SizeOp = Op->Common.Value.Arg;
235 
236     /* Next, the initializer byte list to examine */
237 
238     NextOp = SizeOp->Common.Next;
239     if (!NextOp)
240     {
241         return (FALSE);
242     }
243 
244     /* Extract the byte list info */
245 
246     ByteData = NextOp->Named.Data;
247     ByteCount = (UINT32) NextOp->Common.Value.Integer;
248     WordCount = ACPI_DIV_2 (ByteCount);
249 
250     /*
251      * Unicode string must have an even number of bytes and last
252      * word must be zero
253      */
254     if ((!ByteCount)     ||
255          (ByteCount < 4) ||
256          (ByteCount & 1) ||
257         ((UINT16 *) (void *) ByteData)[WordCount - 1] != 0)
258     {
259         return (FALSE);
260     }
261 
262     /* For each word, 1st byte must be ascii, 2nd byte must be zero */
263 
264     for (i = 0; i < (ByteCount - 2); i += 2)
265     {
266         if ((!ACPI_IS_PRINT (ByteData[i])) ||
267             (ByteData[(ACPI_SIZE) i + 1] != 0))
268         {
269             return (FALSE);
270         }
271     }
272 
273     /* Ignore the Size argument in the disassembly of this buffer op */
274 
275     SizeOp->Common.DisasmFlags |= ACPI_PARSEOP_IGNORE;
276     return (TRUE);
277 }
278 
279 
280 /*******************************************************************************
281  *
282  * FUNCTION:    AcpiDmIsStringBuffer
283  *
284  * PARAMETERS:  Op              - Buffer Object to be examined
285  *
286  * RETURN:      TRUE if buffer contains a ASCII string, FALSE otherwise
287  *
288  * DESCRIPTION: Determine if a buffer Op contains a ASCII string
289  *
290  ******************************************************************************/
291 
292 BOOLEAN
293 AcpiDmIsStringBuffer (
294     ACPI_PARSE_OBJECT       *Op)
295 {
296     UINT8                   *ByteData;
297     UINT32                  ByteCount;
298     ACPI_PARSE_OBJECT       *SizeOp;
299     ACPI_PARSE_OBJECT       *NextOp;
300     UINT32                  i;
301 
302 
303     /* Buffer size is the buffer argument */
304 
305     SizeOp = Op->Common.Value.Arg;
306 
307     /* Next, the initializer byte list to examine */
308 
309     NextOp = SizeOp->Common.Next;
310     if (!NextOp)
311     {
312         return (FALSE);
313     }
314 
315     /* Extract the byte list info */
316 
317     ByteData = NextOp->Named.Data;
318     ByteCount = (UINT32) NextOp->Common.Value.Integer;
319 
320     /* Last byte must be the null terminator */
321 
322     if ((!ByteCount)     ||
323          (ByteCount < 2) ||
324          (ByteData[ByteCount-1] != 0))
325     {
326         return (FALSE);
327     }
328 
329     for (i = 0; i < (ByteCount - 1); i++)
330     {
331         /* TBD: allow some escapes (non-ascii chars).
332          * they will be handled in the string output routine
333          */
334 
335         if (!ACPI_IS_PRINT (ByteData[i]))
336         {
337             return (FALSE);
338         }
339     }
340 
341     return (TRUE);
342 }
343 
344 
345 /*******************************************************************************
346  *
347  * FUNCTION:    AcpiDmIsPldBuffer
348  *
349  * PARAMETERS:  Op                  - Buffer Object to be examined
350  *
351  * RETURN:      TRUE if buffer contains a ASCII string, FALSE otherwise
352  *
353  * DESCRIPTION: Determine if a buffer Op contains a _PLD structure
354  *
355  ******************************************************************************/
356 
357 BOOLEAN
358 AcpiDmIsPldBuffer (
359     ACPI_PARSE_OBJECT       *Op)
360 {
361     ACPI_NAMESPACE_NODE     *Node;
362     ACPI_PARSE_OBJECT       *ParentOp;
363 
364 
365     ParentOp = Op->Common.Parent;
366     if (!ParentOp)
367     {
368         return (FALSE);
369     }
370 
371     /* Check for form: Name(_PLD, Buffer() {}). Not legal, however */
372 
373     if (ParentOp->Common.AmlOpcode == AML_NAME_OP)
374     {
375         Node = ParentOp->Common.Node;
376 
377         if (ACPI_COMPARE_NAME (Node->Name.Ascii, METHOD_NAME__PLD))
378         {
379             return (TRUE);
380         }
381 
382         return (FALSE);
383     }
384 
385     /* Check for proper form: Name(_PLD, Package() {Buffer() {}}) */
386 
387     if (ParentOp->Common.AmlOpcode == AML_PACKAGE_OP)
388     {
389         ParentOp = ParentOp->Common.Parent;
390         if (!ParentOp)
391         {
392             return (FALSE);
393         }
394 
395         if (ParentOp->Common.AmlOpcode == AML_NAME_OP)
396         {
397             Node = ParentOp->Common.Node;
398 
399             if (ACPI_COMPARE_NAME (Node->Name.Ascii, METHOD_NAME__PLD))
400             {
401                 return (TRUE);
402             }
403         }
404     }
405 
406     return (FALSE);
407 }
408 
409 
410 /*******************************************************************************
411  *
412  * FUNCTION:    AcpiDmPldBuffer
413  *
414  * PARAMETERS:  Level               - Current source code indentation level
415  *              ByteData            - Pointer to the byte list
416  *              ByteCount           - Length of the byte list
417  *
418  * RETURN:      None
419  *
420  * DESCRIPTION: Dump and format the contents of a _PLD buffer object
421  *
422  ******************************************************************************/
423 
424 #define ACPI_PLD_OUTPUT08     "%*.s/* %18s : %-6.2X */\n", ACPI_MUL_4 (Level), " "
425 #define ACPI_PLD_OUTPUT16   "%*.s/* %18s : %-6.4X */\n", ACPI_MUL_4 (Level), " "
426 #define ACPI_PLD_OUTPUT24   "%*.s/* %18s : %-6.6X */\n", ACPI_MUL_4 (Level), " "
427 
428 static void
429 AcpiDmPldBuffer (
430     UINT32                  Level,
431     UINT8                   *ByteData,
432     UINT32                  ByteCount)
433 {
434     ACPI_PLD_INFO           *PldInfo;
435     ACPI_STATUS             Status;
436 
437 
438     /* Check for valid byte count */
439 
440     if (ByteCount < ACPI_PLD_REV1_BUFFER_SIZE)
441     {
442         return;
443     }
444 
445     /* Convert _PLD buffer to local _PLD struct */
446 
447     Status = AcpiDecodePldBuffer (ByteData, ByteCount, &PldInfo);
448     if (ACPI_FAILURE (Status))
449     {
450         return;
451     }
452 
453     /* First 32-bit dword */
454 
455     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "Revision", PldInfo->Revision);
456     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "IgnoreColor", PldInfo->IgnoreColor);
457     AcpiOsPrintf (ACPI_PLD_OUTPUT24,"Color", PldInfo->Color);
458 
459     /* Second 32-bit dword */
460 
461     AcpiOsPrintf (ACPI_PLD_OUTPUT16,"Width", PldInfo->Width);
462     AcpiOsPrintf (ACPI_PLD_OUTPUT16,"Height", PldInfo->Height);
463 
464     /* Third 32-bit dword */
465 
466     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "UserVisible", PldInfo->UserVisible);
467     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "Dock", PldInfo->Dock);
468     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "Lid", PldInfo->Lid);
469     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "Panel", PldInfo->Panel);
470     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "VerticalPosition", PldInfo->VerticalPosition);
471     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "HorizontalPosition", PldInfo->HorizontalPosition);
472     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "Shape", PldInfo->Shape);
473     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "GroupOrientation", PldInfo->GroupOrientation);
474     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "GroupToken", PldInfo->GroupToken);
475     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "GroupPosition", PldInfo->GroupPosition);
476     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "Bay", PldInfo->Bay);
477 
478     /* Fourth 32-bit dword */
479 
480     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "Ejectable", PldInfo->Ejectable);
481     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "OspmEjectRequired", PldInfo->OspmEjectRequired);
482     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "CabinetNumber", PldInfo->CabinetNumber);
483     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "CardCageNumber", PldInfo->CardCageNumber);
484     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "Reference", PldInfo->Reference);
485     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "Rotation", PldInfo->Rotation);
486     AcpiOsPrintf (ACPI_PLD_OUTPUT08,  "Order", PldInfo->Order);
487 
488     /* Fifth 32-bit dword */
489 
490     if (ByteCount >= ACPI_PLD_REV1_BUFFER_SIZE)
491     {
492         AcpiOsPrintf (ACPI_PLD_OUTPUT16,"VerticalOffset", PldInfo->VerticalOffset);
493         AcpiOsPrintf (ACPI_PLD_OUTPUT16,"HorizontalOffset", PldInfo->HorizontalOffset);
494     }
495 
496     ACPI_FREE (PldInfo);
497 }
498 
499 
500 /*******************************************************************************
501  *
502  * FUNCTION:    AcpiDmUnicode
503  *
504  * PARAMETERS:  Op              - Byte List op containing Unicode string
505  *
506  * RETURN:      None
507  *
508  * DESCRIPTION: Dump Unicode string as a standard ASCII string. (Remove
509  *              the extra zero bytes).
510  *
511  ******************************************************************************/
512 
513 static void
514 AcpiDmUnicode (
515     ACPI_PARSE_OBJECT       *Op)
516 {
517     UINT16                  *WordData;
518     UINT32                  WordCount;
519     UINT32                  i;
520 
521 
522     /* Extract the buffer info as a WORD buffer */
523 
524     WordData = ACPI_CAST_PTR (UINT16, Op->Named.Data);
525     WordCount = ACPI_DIV_2 (((UINT32) Op->Common.Value.Integer));
526 
527 
528     AcpiOsPrintf ("\"");
529 
530     /* Write every other byte as an ASCII character */
531 
532     for (i = 0; i < (WordCount - 1); i++)
533     {
534         AcpiOsPrintf ("%c", (int) WordData[i]);
535     }
536 
537     AcpiOsPrintf ("\")");
538 }
539 
540 
541 /*******************************************************************************
542  *
543  * FUNCTION:    AcpiDmIsEisaIdElement
544  *
545  * PARAMETERS:  Op              - Op to be examined
546  *
547  * RETURN:      None
548  *
549  * DESCRIPTION: Determine if an Op (argument to _HID or _CID) can be converted
550  *              to an EISA ID.
551  *
552  ******************************************************************************/
553 
554 static void
555 AcpiDmIsEisaIdElement (
556     ACPI_PARSE_OBJECT       *Op)
557 {
558     UINT32                  BigEndianId;
559     UINT32                  Prefix[3];
560     UINT32                  i;
561 
562 
563     /* The parameter must be either a word or a dword */
564 
565     if ((Op->Common.AmlOpcode != AML_DWORD_OP) &&
566         (Op->Common.AmlOpcode != AML_WORD_OP))
567     {
568         return;
569     }
570 
571     /* Swap from little-endian to big-endian to simplify conversion */
572 
573     BigEndianId = AcpiUtDwordByteSwap ((UINT32) Op->Common.Value.Integer);
574 
575     /* Create the 3 leading ASCII letters */
576 
577     Prefix[0] = ((BigEndianId >> 26) & 0x1F) + 0x40;
578     Prefix[1] = ((BigEndianId >> 21) & 0x1F) + 0x40;
579     Prefix[2] = ((BigEndianId >> 16) & 0x1F) + 0x40;
580 
581     /* Verify that all 3 are ascii and alpha */
582 
583     for (i = 0; i < 3; i++)
584     {
585         if (!ACPI_IS_ASCII (Prefix[i]) ||
586             !ACPI_IS_ALPHA (Prefix[i]))
587         {
588             return;
589         }
590     }
591 
592     /* OK - mark this node as convertable to an EISA ID */
593 
594     Op->Common.DisasmOpcode = ACPI_DASM_EISAID;
595 }
596 
597 
598 /*******************************************************************************
599  *
600  * FUNCTION:    AcpiDmIsEisaId
601  *
602  * PARAMETERS:  Op              - Op to be examined
603  *
604  * RETURN:      None
605  *
606  * DESCRIPTION: Determine if a Name() Op can be converted to an EisaId.
607  *
608  ******************************************************************************/
609 
610 void
611 AcpiDmIsEisaId (
612     ACPI_PARSE_OBJECT       *Op)
613 {
614     UINT32                  Name;
615     ACPI_PARSE_OBJECT       *NextOp;
616 
617 
618     /* Get the NameSegment */
619 
620     Name = AcpiPsGetName (Op);
621     if (!Name)
622     {
623         return;
624     }
625 
626     NextOp = AcpiPsGetDepthNext (NULL, Op);
627     if (!NextOp)
628     {
629         return;
630     }
631 
632     /* Check for _HID - has one argument */
633 
634     if (ACPI_COMPARE_NAME (&Name, METHOD_NAME__HID))
635     {
636         AcpiDmIsEisaIdElement (NextOp);
637         return;
638     }
639 
640     /* Exit if not _CID */
641 
642     if (!ACPI_COMPARE_NAME (&Name, METHOD_NAME__CID))
643     {
644         return;
645     }
646 
647     /* _CID can contain a single argument or a package */
648 
649     if (NextOp->Common.AmlOpcode != AML_PACKAGE_OP)
650     {
651         AcpiDmIsEisaIdElement (NextOp);
652         return;
653     }
654 
655     /* _CID with Package: get the package length */
656 
657     NextOp = AcpiPsGetDepthNext (NULL, NextOp);
658 
659     /* Don't need to use the length, just walk the peer list */
660 
661     NextOp = NextOp->Common.Next;
662     while (NextOp)
663     {
664         AcpiDmIsEisaIdElement (NextOp);
665         NextOp = NextOp->Common.Next;
666     }
667 }
668 
669 
670 /*******************************************************************************
671  *
672  * FUNCTION:    AcpiDmEisaId
673  *
674  * PARAMETERS:  EncodedId       - Raw encoded EISA ID.
675  *
676  * RETURN:      None
677  *
678  * DESCRIPTION: Convert an encoded EISAID back to the original ASCII String.
679  *
680  ******************************************************************************/
681 
682 void
683 AcpiDmEisaId (
684     UINT32                  EncodedId)
685 {
686     UINT32                  BigEndianId;
687 
688 
689     /* Swap from little-endian to big-endian to simplify conversion */
690 
691     BigEndianId = AcpiUtDwordByteSwap (EncodedId);
692 
693 
694     /* Split to form "AAANNNN" string */
695 
696     AcpiOsPrintf ("EisaId (\"%c%c%c%4.4X\")",
697 
698         /* Three Alpha characters (AAA), 5 bits each */
699 
700         (int) ((BigEndianId >> 26) & 0x1F) + 0x40,
701         (int) ((BigEndianId >> 21) & 0x1F) + 0x40,
702         (int) ((BigEndianId >> 16) & 0x1F) + 0x40,
703 
704         /* Numeric part (NNNN) is simply the lower 16 bits */
705 
706         (UINT32) (BigEndianId & 0xFFFF));
707 }
708 
709 #endif
710