1 /*******************************************************************************
2  *
3  * Module Name: dmbuffer - AML disassembler, buffer and string support
4  *
5  ******************************************************************************/
6 
7 /*
8  * Copyright (C) 2000 - 2014, 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 #include "acinterp.h"
51 
52 
53 #ifdef ACPI_DISASSEMBLER
54 
55 #define _COMPONENT          ACPI_CA_DEBUGGER
56         ACPI_MODULE_NAME    ("dmbuffer")
57 
58 /* Local prototypes */
59 
60 static void
61 AcpiDmUnicode (
62     ACPI_PARSE_OBJECT       *Op);
63 
64 static void
65 AcpiDmGetHardwareIdType (
66     ACPI_PARSE_OBJECT       *Op);
67 
68 static void
69 AcpiDmPldBuffer (
70     UINT32                  Level,
71     UINT8                   *ByteData,
72     UINT32                  ByteCount);
73 
74 
75 /*******************************************************************************
76  *
77  * FUNCTION:    AcpiDmDisasmByteList
78  *
79  * PARAMETERS:  Level               - Current source code indentation level
80  *              ByteData            - Pointer to the byte list
81  *              ByteCount           - Length of the byte list
82  *
83  * RETURN:      None
84  *
85  * DESCRIPTION: Dump an AML "ByteList" in Hex format. 8 bytes per line, prefixed
86  *              with the hex buffer offset.
87  *
88  ******************************************************************************/
89 
90 void
91 AcpiDmDisasmByteList (
92     UINT32                  Level,
93     UINT8                   *ByteData,
94     UINT32                  ByteCount)
95 {
96     UINT32                  i;
97 
98 
99     if (!ByteCount)
100     {
101         return;
102     }
103 
104     /* Dump the byte list */
105 
106     for (i = 0; i < ByteCount; i++)
107     {
108         /* New line every 8 bytes */
109 
110         if (((i % 8) == 0) && (i < ByteCount))
111         {
112             if (i > 0)
113             {
114                 AcpiOsPrintf ("\n");
115             }
116 
117             AcpiDmIndent (Level);
118             if (ByteCount > 8)
119             {
120                 AcpiOsPrintf ("/* %04X */  ", i);
121             }
122         }
123 
124         AcpiOsPrintf (" 0x%2.2X", (UINT32) ByteData[i]);
125 
126         /* Add comma if there are more bytes to display */
127 
128         if (i < (ByteCount -1))
129         {
130             AcpiOsPrintf (",");
131         }
132     }
133 
134     if (Level)
135     {
136         AcpiOsPrintf ("\n");
137     }
138 }
139 
140 
141 /*******************************************************************************
142  *
143  * FUNCTION:    AcpiDmByteList
144  *
145  * PARAMETERS:  Info            - Parse tree walk info
146  *              Op              - Byte list op
147  *
148  * RETURN:      None
149  *
150  * DESCRIPTION: Dump a buffer byte list, handling the various types of buffers.
151  *              Buffer type must be already set in the Op DisasmOpcode.
152  *
153  ******************************************************************************/
154 
155 void
156 AcpiDmByteList (
157     ACPI_OP_WALK_INFO       *Info,
158     ACPI_PARSE_OBJECT       *Op)
159 {
160     UINT8                   *ByteData;
161     UINT32                  ByteCount;
162 
163 
164     ByteData = Op->Named.Data;
165     ByteCount = (UINT32) Op->Common.Value.Integer;
166 
167     /*
168      * The byte list belongs to a buffer, and can be produced by either
169      * a ResourceTemplate, Unicode, quoted string, or a plain byte list.
170      */
171     switch (Op->Common.Parent->Common.DisasmOpcode)
172     {
173     case ACPI_DASM_RESOURCE:
174 
175         AcpiDmResourceTemplate (Info, Op->Common.Parent, ByteData, ByteCount);
176         break;
177 
178     case ACPI_DASM_STRING:
179 
180         AcpiDmIndent (Info->Level);
181         AcpiUtPrintString ((char *) ByteData, ACPI_UINT16_MAX);
182         AcpiOsPrintf ("\n");
183         break;
184 
185     case ACPI_DASM_UNICODE:
186 
187         AcpiDmUnicode (Op);
188         break;
189 
190     case ACPI_DASM_PLD_METHOD:
191 
192         AcpiDmDisasmByteList (Info->Level, ByteData, ByteCount);
193         AcpiDmPldBuffer (Info->Level, ByteData, ByteCount);
194         break;
195 
196     case ACPI_DASM_BUFFER:
197     default:
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     /* Write every other byte as an ASCII character */
528 
529     AcpiOsPrintf ("\"");
530     for (i = 0; i < (WordCount - 1); i++)
531     {
532         AcpiOsPrintf ("%c", (int) WordData[i]);
533     }
534 
535     AcpiOsPrintf ("\")");
536 }
537 
538 
539 /*******************************************************************************
540  *
541  * FUNCTION:    AcpiDmGetHardwareIdType
542  *
543  * PARAMETERS:  Op              - Op to be examined
544  *
545  * RETURN:      None
546  *
547  * DESCRIPTION: Determine the type of the argument to a _HID or _CID
548  *              1) Strings are allowed
549  *              2) If Integer, determine if it is a valid EISAID
550  *
551  ******************************************************************************/
552 
553 static void
554 AcpiDmGetHardwareIdType (
555     ACPI_PARSE_OBJECT       *Op)
556 {
557     UINT32                  BigEndianId;
558     UINT32                  Prefix[3];
559     UINT32                  i;
560 
561 
562     switch (Op->Common.AmlOpcode)
563     {
564     case AML_STRING_OP:
565 
566         /* Mark this string as an _HID/_CID string */
567 
568         Op->Common.DisasmOpcode = ACPI_DASM_HID_STRING;
569         break;
570 
571     case AML_WORD_OP:
572     case AML_DWORD_OP:
573 
574         /* Determine if a Word/Dword is a valid encoded EISAID */
575 
576         /* Swap from little-endian to big-endian to simplify conversion */
577 
578         BigEndianId = AcpiUtDwordByteSwap ((UINT32) Op->Common.Value.Integer);
579 
580         /* Create the 3 leading ASCII letters */
581 
582         Prefix[0] = ((BigEndianId >> 26) & 0x1F) + 0x40;
583         Prefix[1] = ((BigEndianId >> 21) & 0x1F) + 0x40;
584         Prefix[2] = ((BigEndianId >> 16) & 0x1F) + 0x40;
585 
586         /* Verify that all 3 are ascii and alpha */
587 
588         for (i = 0; i < 3; i++)
589         {
590             if (!ACPI_IS_ASCII (Prefix[i]) ||
591                 !ACPI_IS_ALPHA (Prefix[i]))
592             {
593                 return;
594             }
595         }
596 
597         /* Mark this node as convertable to an EISA ID string */
598 
599         Op->Common.DisasmOpcode = ACPI_DASM_EISAID;
600         break;
601 
602     default:
603         break;
604     }
605 }
606 
607 
608 /*******************************************************************************
609  *
610  * FUNCTION:    AcpiDmCheckForHardwareId
611  *
612  * PARAMETERS:  Op              - Op to be examined
613  *
614  * RETURN:      None
615  *
616  * DESCRIPTION: Determine if a Name() Op is a _HID/_CID.
617  *
618  ******************************************************************************/
619 
620 void
621 AcpiDmCheckForHardwareId (
622     ACPI_PARSE_OBJECT       *Op)
623 {
624     UINT32                  Name;
625     ACPI_PARSE_OBJECT       *NextOp;
626 
627 
628     /* Get the NameSegment */
629 
630     Name = AcpiPsGetName (Op);
631     if (!Name)
632     {
633         return;
634     }
635 
636     NextOp = AcpiPsGetDepthNext (NULL, Op);
637     if (!NextOp)
638     {
639         return;
640     }
641 
642     /* Check for _HID - has one argument */
643 
644     if (ACPI_COMPARE_NAME (&Name, METHOD_NAME__HID))
645     {
646         AcpiDmGetHardwareIdType (NextOp);
647         return;
648     }
649 
650     /* Exit if not _CID */
651 
652     if (!ACPI_COMPARE_NAME (&Name, METHOD_NAME__CID))
653     {
654         return;
655     }
656 
657     /* _CID can contain a single argument or a package */
658 
659     if (NextOp->Common.AmlOpcode != AML_PACKAGE_OP)
660     {
661         AcpiDmGetHardwareIdType (NextOp);
662         return;
663     }
664 
665     /* _CID with Package: get the package length, check all elements */
666 
667     NextOp = AcpiPsGetDepthNext (NULL, NextOp);
668 
669     /* Don't need to use the length, just walk the peer list */
670 
671     NextOp = NextOp->Common.Next;
672     while (NextOp)
673     {
674         AcpiDmGetHardwareIdType (NextOp);
675         NextOp = NextOp->Common.Next;
676     }
677 }
678 
679 
680 /*******************************************************************************
681  *
682  * FUNCTION:    AcpiDmDecompressEisaId
683  *
684  * PARAMETERS:  EncodedId       - Raw encoded EISA ID.
685  *
686  * RETURN:      None
687  *
688  * DESCRIPTION: Convert an encoded EISAID back to the original ASCII String
689  *              and emit the correct ASL statement. If the ID is known, emit
690  *              a description of the ID as a comment.
691  *
692  ******************************************************************************/
693 
694 void
695 AcpiDmDecompressEisaId (
696     UINT32                  EncodedId)
697 {
698     char                    IdBuffer[ACPI_EISAID_STRING_SIZE];
699     const AH_DEVICE_ID      *Info;
700 
701 
702     /* Convert EISAID to a string an emit the statement */
703 
704     AcpiExEisaIdToString (IdBuffer, EncodedId);
705     AcpiOsPrintf ("EisaId (\"%s\")", IdBuffer);
706 
707     /* If we know about the ID, emit the description */
708 
709     Info = AcpiAhMatchHardwareId (IdBuffer);
710     if (Info)
711     {
712         AcpiOsPrintf (" /* %s */", Info->Description);
713     }
714 }
715 
716 #endif
717