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