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