xref: /titanic_44/usr/src/uts/intel/io/acpica/executer/exconvrt.c (revision cb56572868bfc488bbd3ab847b09db2a25554d44)
1 /******************************************************************************
2  *
3  * Module Name: exconvrt - Object conversion routines
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 "acpi.h"
45 #include "accommon.h"
46 #include "acinterp.h"
47 #include "amlcode.h"
48 
49 
50 #define _COMPONENT          ACPI_EXECUTER
51         ACPI_MODULE_NAME    ("exconvrt")
52 
53 /* Local prototypes */
54 
55 static UINT32
56 AcpiExConvertToAscii (
57     UINT64                  Integer,
58     UINT16                  Base,
59     UINT8                   *String,
60     UINT8                   MaxLength);
61 
62 
63 /*******************************************************************************
64  *
65  * FUNCTION:    AcpiExConvertToInteger
66  *
67  * PARAMETERS:  ObjDesc         - Object to be converted. Must be an
68  *                                Integer, Buffer, or String
69  *              ResultDesc      - Where the new Integer object is returned
70  *              Flags           - Used for string conversion
71  *
72  * RETURN:      Status
73  *
74  * DESCRIPTION: Convert an ACPI Object to an integer.
75  *
76  ******************************************************************************/
77 
78 ACPI_STATUS
AcpiExConvertToInteger(ACPI_OPERAND_OBJECT * ObjDesc,ACPI_OPERAND_OBJECT ** ResultDesc,UINT32 Flags)79 AcpiExConvertToInteger (
80     ACPI_OPERAND_OBJECT     *ObjDesc,
81     ACPI_OPERAND_OBJECT     **ResultDesc,
82     UINT32                  Flags)
83 {
84     ACPI_OPERAND_OBJECT     *ReturnDesc;
85     UINT8                   *Pointer;
86     UINT64                  Result;
87     UINT32                  i;
88     UINT32                  Count;
89     ACPI_STATUS             Status;
90 
91 
92     ACPI_FUNCTION_TRACE_PTR (ExConvertToInteger, ObjDesc);
93 
94 
95     switch (ObjDesc->Common.Type)
96     {
97     case ACPI_TYPE_INTEGER:
98 
99         /* No conversion necessary */
100 
101         *ResultDesc = ObjDesc;
102         return_ACPI_STATUS (AE_OK);
103 
104     case ACPI_TYPE_BUFFER:
105     case ACPI_TYPE_STRING:
106 
107         /* Note: Takes advantage of common buffer/string fields */
108 
109         Pointer = ObjDesc->Buffer.Pointer;
110         Count   = ObjDesc->Buffer.Length;
111         break;
112 
113     default:
114 
115         return_ACPI_STATUS (AE_TYPE);
116     }
117 
118     /*
119      * Convert the buffer/string to an integer. Note that both buffers and
120      * strings are treated as raw data - we don't convert ascii to hex for
121      * strings.
122      *
123      * There are two terminating conditions for the loop:
124      * 1) The size of an integer has been reached, or
125      * 2) The end of the buffer or string has been reached
126      */
127     Result = 0;
128 
129     /* String conversion is different than Buffer conversion */
130 
131     switch (ObjDesc->Common.Type)
132     {
133     case ACPI_TYPE_STRING:
134         /*
135          * Convert string to an integer - for most cases, the string must be
136          * hexadecimal as per the ACPI specification. The only exception (as
137          * of ACPI 3.0) is that the ToInteger() operator allows both decimal
138          * and hexadecimal strings (hex prefixed with "0x").
139          */
140         Status = AcpiUtStrtoul64 ((char *) Pointer, Flags,
141             AcpiGbl_IntegerByteWidth, &Result);
142         if (ACPI_FAILURE (Status))
143         {
144             return_ACPI_STATUS (Status);
145         }
146         break;
147 
148     case ACPI_TYPE_BUFFER:
149 
150         /* Check for zero-length buffer */
151 
152         if (!Count)
153         {
154             return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
155         }
156 
157         /* Transfer no more than an integer's worth of data */
158 
159         if (Count > AcpiGbl_IntegerByteWidth)
160         {
161             Count = AcpiGbl_IntegerByteWidth;
162         }
163 
164         /*
165          * Convert buffer to an integer - we simply grab enough raw data
166          * from the buffer to fill an integer
167          */
168         for (i = 0; i < Count; i++)
169         {
170             /*
171              * Get next byte and shift it into the Result.
172              * Little endian is used, meaning that the first byte of the buffer
173              * is the LSB of the integer
174              */
175             Result |= (((UINT64) Pointer[i]) << (i * 8));
176         }
177         break;
178 
179     default:
180 
181         /* No other types can get here */
182 
183         break;
184     }
185 
186     /* Create a new integer */
187 
188     ReturnDesc = AcpiUtCreateIntegerObject (Result);
189     if (!ReturnDesc)
190     {
191         return_ACPI_STATUS (AE_NO_MEMORY);
192     }
193 
194     ACPI_DEBUG_PRINT ((ACPI_DB_EXEC, "Converted value: %8.8X%8.8X\n",
195         ACPI_FORMAT_UINT64 (Result)));
196 
197     /* Save the Result */
198 
199     (void) AcpiExTruncateFor32bitTable (ReturnDesc);
200     *ResultDesc = ReturnDesc;
201     return_ACPI_STATUS (AE_OK);
202 }
203 
204 
205 /*******************************************************************************
206  *
207  * FUNCTION:    AcpiExConvertToBuffer
208  *
209  * PARAMETERS:  ObjDesc         - Object to be converted. Must be an
210  *                                Integer, Buffer, or String
211  *              ResultDesc      - Where the new buffer object is returned
212  *
213  * RETURN:      Status
214  *
215  * DESCRIPTION: Convert an ACPI Object to a Buffer
216  *
217  ******************************************************************************/
218 
219 ACPI_STATUS
AcpiExConvertToBuffer(ACPI_OPERAND_OBJECT * ObjDesc,ACPI_OPERAND_OBJECT ** ResultDesc)220 AcpiExConvertToBuffer (
221     ACPI_OPERAND_OBJECT     *ObjDesc,
222     ACPI_OPERAND_OBJECT     **ResultDesc)
223 {
224     ACPI_OPERAND_OBJECT     *ReturnDesc;
225     UINT8                   *NewBuf;
226 
227 
228     ACPI_FUNCTION_TRACE_PTR (ExConvertToBuffer, ObjDesc);
229 
230 
231     switch (ObjDesc->Common.Type)
232     {
233     case ACPI_TYPE_BUFFER:
234 
235         /* No conversion necessary */
236 
237         *ResultDesc = ObjDesc;
238         return_ACPI_STATUS (AE_OK);
239 
240 
241     case ACPI_TYPE_INTEGER:
242         /*
243          * Create a new Buffer object.
244          * Need enough space for one integer
245          */
246         ReturnDesc = AcpiUtCreateBufferObject (AcpiGbl_IntegerByteWidth);
247         if (!ReturnDesc)
248         {
249             return_ACPI_STATUS (AE_NO_MEMORY);
250         }
251 
252         /* Copy the integer to the buffer, LSB first */
253 
254         NewBuf = ReturnDesc->Buffer.Pointer;
255         memcpy (NewBuf, &ObjDesc->Integer.Value, AcpiGbl_IntegerByteWidth);
256         break;
257 
258     case ACPI_TYPE_STRING:
259         /*
260          * Create a new Buffer object
261          * Size will be the string length
262          *
263          * NOTE: Add one to the string length to include the null terminator.
264          * The ACPI spec is unclear on this subject, but there is existing
265          * ASL/AML code that depends on the null being transferred to the new
266          * buffer.
267          */
268         ReturnDesc = AcpiUtCreateBufferObject ((ACPI_SIZE)
269             ObjDesc->String.Length + 1);
270         if (!ReturnDesc)
271         {
272             return_ACPI_STATUS (AE_NO_MEMORY);
273         }
274 
275         /* Copy the string to the buffer */
276 
277         NewBuf = ReturnDesc->Buffer.Pointer;
278         strncpy ((char *) NewBuf, (char *) ObjDesc->String.Pointer,
279             ObjDesc->String.Length);
280         break;
281 
282     default:
283 
284         return_ACPI_STATUS (AE_TYPE);
285     }
286 
287     /* Mark buffer initialized */
288 
289     ReturnDesc->Common.Flags |= AOPOBJ_DATA_VALID;
290     *ResultDesc = ReturnDesc;
291     return_ACPI_STATUS (AE_OK);
292 }
293 
294 
295 /*******************************************************************************
296  *
297  * FUNCTION:    AcpiExConvertToAscii
298  *
299  * PARAMETERS:  Integer         - Value to be converted
300  *              Base            - ACPI_STRING_DECIMAL or ACPI_STRING_HEX
301  *              String          - Where the string is returned
302  *              DataWidth       - Size of data item to be converted, in bytes
303  *
304  * RETURN:      Actual string length
305  *
306  * DESCRIPTION: Convert an ACPI Integer to a hex or decimal string
307  *
308  ******************************************************************************/
309 
310 static UINT32
AcpiExConvertToAscii(UINT64 Integer,UINT16 Base,UINT8 * String,UINT8 DataWidth)311 AcpiExConvertToAscii (
312     UINT64                  Integer,
313     UINT16                  Base,
314     UINT8                   *String,
315     UINT8                   DataWidth)
316 {
317     UINT64                  Digit;
318     UINT32                  i;
319     UINT32                  j;
320     UINT32                  k = 0;
321     UINT32                  HexLength;
322     UINT32                  DecimalLength;
323     UINT32                  Remainder;
324     BOOLEAN                 SupressZeros;
325 
326 
327     ACPI_FUNCTION_ENTRY ();
328 
329 
330     switch (Base)
331     {
332     case 10:
333 
334         /* Setup max length for the decimal number */
335 
336         switch (DataWidth)
337         {
338         case 1:
339 
340             DecimalLength = ACPI_MAX8_DECIMAL_DIGITS;
341             break;
342 
343         case 4:
344 
345             DecimalLength = ACPI_MAX32_DECIMAL_DIGITS;
346             break;
347 
348         case 8:
349         default:
350 
351             DecimalLength = ACPI_MAX64_DECIMAL_DIGITS;
352             break;
353         }
354 
355         SupressZeros = TRUE;     /* No leading zeros */
356         Remainder = 0;
357 
358         for (i = DecimalLength; i > 0; i--)
359         {
360             /* Divide by nth factor of 10 */
361 
362             Digit = Integer;
363             for (j = 0; j < i; j++)
364             {
365                 (void) AcpiUtShortDivide (Digit, 10, &Digit, &Remainder);
366             }
367 
368             /* Handle leading zeros */
369 
370             if (Remainder != 0)
371             {
372                 SupressZeros = FALSE;
373             }
374 
375             if (!SupressZeros)
376             {
377                 String[k] = (UINT8) (ACPI_ASCII_ZERO + Remainder);
378                 k++;
379             }
380         }
381         break;
382 
383     case 16:
384 
385         /* HexLength: 2 ascii hex chars per data byte */
386 
387         HexLength = ACPI_MUL_2 (DataWidth);
388         for (i = 0, j = (HexLength-1); i < HexLength; i++, j--)
389         {
390             /* Get one hex digit, most significant digits first */
391 
392             String[k] = (UINT8)
393                 AcpiUtHexToAsciiChar (Integer, ACPI_MUL_4 (j));
394             k++;
395         }
396         break;
397 
398     default:
399         return (0);
400     }
401 
402     /*
403      * Since leading zeros are suppressed, we must check for the case where
404      * the integer equals 0
405      *
406      * Finally, null terminate the string and return the length
407      */
408     if (!k)
409     {
410         String [0] = ACPI_ASCII_ZERO;
411         k = 1;
412     }
413 
414     String [k] = 0;
415     return ((UINT32) k);
416 }
417 
418 
419 /*******************************************************************************
420  *
421  * FUNCTION:    AcpiExConvertToString
422  *
423  * PARAMETERS:  ObjDesc         - Object to be converted. Must be an
424  *                                Integer, Buffer, or String
425  *              ResultDesc      - Where the string object is returned
426  *              Type            - String flags (base and conversion type)
427  *
428  * RETURN:      Status
429  *
430  * DESCRIPTION: Convert an ACPI Object to a string
431  *
432  ******************************************************************************/
433 
434 ACPI_STATUS
AcpiExConvertToString(ACPI_OPERAND_OBJECT * ObjDesc,ACPI_OPERAND_OBJECT ** ResultDesc,UINT32 Type)435 AcpiExConvertToString (
436     ACPI_OPERAND_OBJECT     *ObjDesc,
437     ACPI_OPERAND_OBJECT     **ResultDesc,
438     UINT32                  Type)
439 {
440     ACPI_OPERAND_OBJECT     *ReturnDesc;
441     UINT8                   *NewBuf;
442     UINT32                  i;
443     UINT32                  StringLength = 0;
444     UINT16                  Base = 16;
445     UINT8                   Separator = ',';
446 
447 
448     ACPI_FUNCTION_TRACE_PTR (ExConvertToString, ObjDesc);
449 
450 
451     switch (ObjDesc->Common.Type)
452     {
453     case ACPI_TYPE_STRING:
454 
455         /* No conversion necessary */
456 
457         *ResultDesc = ObjDesc;
458         return_ACPI_STATUS (AE_OK);
459 
460     case ACPI_TYPE_INTEGER:
461 
462         switch (Type)
463         {
464         case ACPI_EXPLICIT_CONVERT_DECIMAL:
465 
466             /* Make room for maximum decimal number */
467 
468             StringLength = ACPI_MAX_DECIMAL_DIGITS;
469             Base = 10;
470             break;
471 
472         default:
473 
474             /* Two hex string characters for each integer byte */
475 
476             StringLength = ACPI_MUL_2 (AcpiGbl_IntegerByteWidth);
477             break;
478         }
479 
480         /*
481          * Create a new String
482          * Need enough space for one ASCII integer (plus null terminator)
483          */
484         ReturnDesc = AcpiUtCreateStringObject ((ACPI_SIZE) StringLength);
485         if (!ReturnDesc)
486         {
487             return_ACPI_STATUS (AE_NO_MEMORY);
488         }
489 
490         NewBuf = ReturnDesc->Buffer.Pointer;
491 
492         /* Convert integer to string */
493 
494         StringLength = AcpiExConvertToAscii (
495             ObjDesc->Integer.Value, Base, NewBuf, AcpiGbl_IntegerByteWidth);
496 
497         /* Null terminate at the correct place */
498 
499         ReturnDesc->String.Length = StringLength;
500         NewBuf [StringLength] = 0;
501         break;
502 
503     case ACPI_TYPE_BUFFER:
504 
505         /* Setup string length, base, and separator */
506 
507         switch (Type)
508         {
509         case ACPI_EXPLICIT_CONVERT_DECIMAL: /* Used by ToDecimalString */
510             /*
511              * From ACPI: "If Data is a buffer, it is converted to a string of
512              * decimal values separated by commas."
513              */
514             Base = 10;
515 
516             /*
517              * Calculate the final string length. Individual string values
518              * are variable length (include separator for each)
519              */
520             for (i = 0; i < ObjDesc->Buffer.Length; i++)
521             {
522                 if (ObjDesc->Buffer.Pointer[i] >= 100)
523                 {
524                     StringLength += 4;
525                 }
526                 else if (ObjDesc->Buffer.Pointer[i] >= 10)
527                 {
528                     StringLength += 3;
529                 }
530                 else
531                 {
532                     StringLength += 2;
533                 }
534             }
535             break;
536 
537         case ACPI_IMPLICIT_CONVERT_HEX:
538             /*
539              * From the ACPI spec:
540              *"The entire contents of the buffer are converted to a string of
541              * two-character hexadecimal numbers, each separated by a space."
542              */
543             Separator = ' ';
544             StringLength = (ObjDesc->Buffer.Length * 3);
545             break;
546 
547         case ACPI_EXPLICIT_CONVERT_HEX:     /* Used by ToHexString */
548             /*
549              * From ACPI: "If Data is a buffer, it is converted to a string of
550              * hexadecimal values separated by commas."
551              */
552             StringLength = (ObjDesc->Buffer.Length * 3);
553             break;
554 
555         default:
556             return_ACPI_STATUS (AE_BAD_PARAMETER);
557         }
558 
559         /*
560          * Create a new string object and string buffer
561          * (-1 because of extra separator included in StringLength from above)
562          * Allow creation of zero-length strings from zero-length buffers.
563          */
564         if (StringLength)
565         {
566             StringLength--;
567         }
568 
569         ReturnDesc = AcpiUtCreateStringObject ((ACPI_SIZE) StringLength);
570         if (!ReturnDesc)
571         {
572             return_ACPI_STATUS (AE_NO_MEMORY);
573         }
574 
575         NewBuf = ReturnDesc->Buffer.Pointer;
576 
577         /*
578          * Convert buffer bytes to hex or decimal values
579          * (separated by commas or spaces)
580          */
581         for (i = 0; i < ObjDesc->Buffer.Length; i++)
582         {
583             NewBuf += AcpiExConvertToAscii (
584                 (UINT64) ObjDesc->Buffer.Pointer[i], Base, NewBuf, 1);
585             *NewBuf++ = Separator; /* each separated by a comma or space */
586         }
587 
588         /*
589          * Null terminate the string
590          * (overwrites final comma/space from above)
591          */
592         if (ObjDesc->Buffer.Length)
593         {
594             NewBuf--;
595         }
596         *NewBuf = 0;
597         break;
598 
599     default:
600 
601         return_ACPI_STATUS (AE_TYPE);
602     }
603 
604     *ResultDesc = ReturnDesc;
605     return_ACPI_STATUS (AE_OK);
606 }
607 
608 
609 /*******************************************************************************
610  *
611  * FUNCTION:    AcpiExConvertToTargetType
612  *
613  * PARAMETERS:  DestinationType     - Current type of the destination
614  *              SourceDesc          - Source object to be converted.
615  *              ResultDesc          - Where the converted object is returned
616  *              WalkState           - Current method state
617  *
618  * RETURN:      Status
619  *
620  * DESCRIPTION: Implements "implicit conversion" rules for storing an object.
621  *
622  ******************************************************************************/
623 
624 ACPI_STATUS
AcpiExConvertToTargetType(ACPI_OBJECT_TYPE DestinationType,ACPI_OPERAND_OBJECT * SourceDesc,ACPI_OPERAND_OBJECT ** ResultDesc,ACPI_WALK_STATE * WalkState)625 AcpiExConvertToTargetType (
626     ACPI_OBJECT_TYPE        DestinationType,
627     ACPI_OPERAND_OBJECT     *SourceDesc,
628     ACPI_OPERAND_OBJECT     **ResultDesc,
629     ACPI_WALK_STATE         *WalkState)
630 {
631     ACPI_STATUS             Status = AE_OK;
632 
633 
634     ACPI_FUNCTION_TRACE (ExConvertToTargetType);
635 
636 
637     /* Default behavior */
638 
639     *ResultDesc = SourceDesc;
640 
641     /*
642      * If required by the target,
643      * perform implicit conversion on the source before we store it.
644      */
645     switch (GET_CURRENT_ARG_TYPE (WalkState->OpInfo->RuntimeArgs))
646     {
647     case ARGI_SIMPLE_TARGET:
648     case ARGI_FIXED_TARGET:
649     case ARGI_INTEGER_REF:      /* Handles Increment, Decrement cases */
650 
651         switch (DestinationType)
652         {
653         case ACPI_TYPE_LOCAL_REGION_FIELD:
654             /*
655              * Named field can always handle conversions
656              */
657             break;
658 
659         default:
660 
661             /* No conversion allowed for these types */
662 
663             if (DestinationType != SourceDesc->Common.Type)
664             {
665                 ACPI_DEBUG_PRINT ((ACPI_DB_INFO,
666                     "Explicit operator, will store (%s) over existing type (%s)\n",
667                     AcpiUtGetObjectTypeName (SourceDesc),
668                     AcpiUtGetTypeName (DestinationType)));
669                 Status = AE_TYPE;
670             }
671         }
672         break;
673 
674     case ARGI_TARGETREF:
675     case ARGI_STORE_TARGET:
676 
677         switch (DestinationType)
678         {
679         case ACPI_TYPE_INTEGER:
680         case ACPI_TYPE_BUFFER_FIELD:
681         case ACPI_TYPE_LOCAL_BANK_FIELD:
682         case ACPI_TYPE_LOCAL_INDEX_FIELD:
683             /*
684              * These types require an Integer operand. We can convert
685              * a Buffer or a String to an Integer if necessary.
686              */
687             Status = AcpiExConvertToInteger (SourceDesc, ResultDesc, 16);
688             break;
689 
690         case ACPI_TYPE_STRING:
691             /*
692              * The operand must be a String. We can convert an
693              * Integer or Buffer if necessary
694              */
695             Status = AcpiExConvertToString (SourceDesc, ResultDesc,
696                 ACPI_IMPLICIT_CONVERT_HEX);
697             break;
698 
699         case ACPI_TYPE_BUFFER:
700             /*
701              * The operand must be a Buffer. We can convert an
702              * Integer or String if necessary
703              */
704             Status = AcpiExConvertToBuffer (SourceDesc, ResultDesc);
705             break;
706 
707         default:
708 
709             ACPI_ERROR ((AE_INFO,
710                 "Bad destination type during conversion: 0x%X",
711                 DestinationType));
712             Status = AE_AML_INTERNAL;
713             break;
714         }
715         break;
716 
717     case ARGI_REFERENCE:
718         /*
719          * CreateXxxxField cases - we are storing the field object into the name
720          */
721         break;
722 
723     default:
724 
725         ACPI_ERROR ((AE_INFO,
726             "Unknown Target type ID 0x%X AmlOpcode 0x%X DestType %s",
727             GET_CURRENT_ARG_TYPE (WalkState->OpInfo->RuntimeArgs),
728             WalkState->Opcode, AcpiUtGetTypeName (DestinationType)));
729         Status = AE_AML_INTERNAL;
730     }
731 
732     /*
733      * Source-to-Target conversion semantics:
734      *
735      * If conversion to the target type cannot be performed, then simply
736      * overwrite the target with the new object and type.
737      */
738     if (Status == AE_TYPE)
739     {
740         Status = AE_OK;
741     }
742 
743     return_ACPI_STATUS (Status);
744 }
745