1/******************************************************************************
2 *
3 * Module Name: nsconvert - Object conversions for objects returned by
4 *                          predefined methods
5 *
6 *****************************************************************************/
7
8/*
9 * Copyright (C) 2000 - 2023, Intel Corp.
10 * All rights reserved.
11 *
12 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 *    notice, this list of conditions, and the following disclaimer,
17 *    without modification.
18 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
19 *    substantially similar to the "NO WARRANTY" disclaimer below
20 *    ("Disclaimer") and any redistribution must be conditioned upon
21 *    including a substantially similar Disclaimer requirement for further
22 *    binary redistribution.
23 * 3. Neither the names of the above-listed copyright holders nor the names
24 *    of any contributors may be used to endorse or promote products derived
25 *    from this software without specific prior written permission.
26 *
27 * Alternatively, this software may be distributed under the terms of the
28 * GNU General Public License ("GPL") version 2 as published by the Free
29 * Software Foundation.
30 *
31 * NO WARRANTY
32 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
33 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
34 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
35 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
36 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
40 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
41 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
42 * POSSIBILITY OF SUCH DAMAGES.
43 */
44
45#include "acpi.h"
46#include "accommon.h"
47#include "acnamesp.h"
48#include "acinterp.h"
49#include "acpredef.h"
50#include "amlresrc.h"
51
52#define _COMPONENT          ACPI_NAMESPACE
53        ACPI_MODULE_NAME    ("nsconvert")
54
55
56/*******************************************************************************
57 *
58 * FUNCTION:    AcpiNsConvertToInteger
59 *
60 * PARAMETERS:  OriginalObject      - Object to be converted
61 *              ReturnObject        - Where the new converted object is returned
62 *
63 * RETURN:      Status. AE_OK if conversion was successful.
64 *
65 * DESCRIPTION: Attempt to convert a String/Buffer object to an Integer.
66 *
67 ******************************************************************************/
68
69ACPI_STATUS
70AcpiNsConvertToInteger (
71    ACPI_OPERAND_OBJECT     *OriginalObject,
72    ACPI_OPERAND_OBJECT     **ReturnObject)
73{
74    ACPI_OPERAND_OBJECT     *NewObject;
75    ACPI_STATUS             Status;
76    UINT64                  Value = 0;
77    UINT32                  i;
78
79
80    switch (OriginalObject->Common.Type)
81    {
82    case ACPI_TYPE_STRING:
83
84        /* String-to-Integer conversion */
85
86        Status = AcpiUtStrtoul64 (OriginalObject->String.Pointer, &Value);
87        if (ACPI_FAILURE (Status))
88        {
89            return (Status);
90        }
91        break;
92
93    case ACPI_TYPE_BUFFER:
94
95        /* Buffer-to-Integer conversion. Max buffer size is 64 bits. */
96
97        if (OriginalObject->Buffer.Length > 8)
98        {
99            return (AE_AML_OPERAND_TYPE);
100        }
101
102        /* Extract each buffer byte to create the integer */
103
104        for (i = 0; i < OriginalObject->Buffer.Length; i++)
105        {
106            Value |= ((UINT64)
107                OriginalObject->Buffer.Pointer[i] << (i * 8));
108        }
109        break;
110
111    default:
112
113        return (AE_AML_OPERAND_TYPE);
114    }
115
116    NewObject = AcpiUtCreateIntegerObject (Value);
117    if (!NewObject)
118    {
119        return (AE_NO_MEMORY);
120    }
121
122    *ReturnObject = NewObject;
123    return (AE_OK);
124}
125
126
127/*******************************************************************************
128 *
129 * FUNCTION:    AcpiNsConvertToString
130 *
131 * PARAMETERS:  OriginalObject      - Object to be converted
132 *              ReturnObject        - Where the new converted object is returned
133 *
134 * RETURN:      Status. AE_OK if conversion was successful.
135 *
136 * DESCRIPTION: Attempt to convert a Integer/Buffer object to a String.
137 *
138 ******************************************************************************/
139
140ACPI_STATUS
141AcpiNsConvertToString (
142    ACPI_OPERAND_OBJECT     *OriginalObject,
143    ACPI_OPERAND_OBJECT     **ReturnObject)
144{
145    ACPI_OPERAND_OBJECT     *NewObject;
146    ACPI_SIZE               Length;
147    ACPI_STATUS             Status;
148
149
150    switch (OriginalObject->Common.Type)
151    {
152    case ACPI_TYPE_INTEGER:
153        /*
154         * Integer-to-String conversion. Commonly, convert
155         * an integer of value 0 to a NULL string. The last element of
156         * _BIF and _BIX packages occasionally need this fix.
157         */
158        if (OriginalObject->Integer.Value == 0)
159        {
160            /* Allocate a new NULL string object */
161
162            NewObject = AcpiUtCreateStringObject (0);
163            if (!NewObject)
164            {
165                return (AE_NO_MEMORY);
166            }
167        }
168        else
169        {
170            Status = AcpiExConvertToString (OriginalObject,
171                &NewObject, ACPI_IMPLICIT_CONVERT_HEX);
172            if (ACPI_FAILURE (Status))
173            {
174                return (Status);
175            }
176        }
177        break;
178
179    case ACPI_TYPE_BUFFER:
180        /*
181         * Buffer-to-String conversion. Use a ToString
182         * conversion, no transform performed on the buffer data. The best
183         * example of this is the _BIF method, where the string data from
184         * the battery is often (incorrectly) returned as buffer object(s).
185         */
186        Length = 0;
187        while ((Length < OriginalObject->Buffer.Length) &&
188                (OriginalObject->Buffer.Pointer[Length]))
189        {
190            Length++;
191        }
192
193        /* Allocate a new string object */
194
195        NewObject = AcpiUtCreateStringObject (Length);
196        if (!NewObject)
197        {
198            return (AE_NO_MEMORY);
199        }
200
201        /*
202         * Copy the raw buffer data with no transform. String is already NULL
203         * terminated at Length+1.
204         */
205        memcpy (NewObject->String.Pointer,
206            OriginalObject->Buffer.Pointer, Length);
207        break;
208
209    default:
210
211        return (AE_AML_OPERAND_TYPE);
212    }
213
214    *ReturnObject = NewObject;
215    return (AE_OK);
216}
217
218
219/*******************************************************************************
220 *
221 * FUNCTION:    AcpiNsConvertToBuffer
222 *
223 * PARAMETERS:  OriginalObject      - Object to be converted
224 *              ReturnObject        - Where the new converted object is returned
225 *
226 * RETURN:      Status. AE_OK if conversion was successful.
227 *
228 * DESCRIPTION: Attempt to convert a Integer/String/Package object to a Buffer.
229 *
230 ******************************************************************************/
231
232ACPI_STATUS
233AcpiNsConvertToBuffer (
234    ACPI_OPERAND_OBJECT     *OriginalObject,
235    ACPI_OPERAND_OBJECT     **ReturnObject)
236{
237    ACPI_OPERAND_OBJECT     *NewObject;
238    ACPI_STATUS             Status;
239    ACPI_OPERAND_OBJECT     **Elements;
240    UINT32                  *DwordBuffer;
241    UINT32                  Count;
242    UINT32                  i;
243
244
245    switch (OriginalObject->Common.Type)
246    {
247    case ACPI_TYPE_INTEGER:
248        /*
249         * Integer-to-Buffer conversion.
250         * Convert the Integer to a packed-byte buffer. _MAT and other
251         * objects need this sometimes, if a read has been performed on a
252         * Field object that is less than or equal to the global integer
253         * size (32 or 64 bits).
254         */
255        Status = AcpiExConvertToBuffer (OriginalObject, &NewObject);
256        if (ACPI_FAILURE (Status))
257        {
258            return (Status);
259        }
260        break;
261
262    case ACPI_TYPE_STRING:
263
264        /* String-to-Buffer conversion. Simple data copy */
265
266        NewObject = AcpiUtCreateBufferObject
267            (OriginalObject->String.Length);
268        if (!NewObject)
269        {
270            return (AE_NO_MEMORY);
271        }
272
273        memcpy (NewObject->Buffer.Pointer,
274            OriginalObject->String.Pointer, OriginalObject->String.Length);
275        break;
276
277    case ACPI_TYPE_PACKAGE:
278        /*
279         * This case is often seen for predefined names that must return a
280         * Buffer object with multiple DWORD integers within. For example,
281         * _FDE and _GTM. The Package can be converted to a Buffer.
282         */
283
284        /* All elements of the Package must be integers */
285
286        Elements = OriginalObject->Package.Elements;
287        Count = OriginalObject->Package.Count;
288
289        for (i = 0; i < Count; i++)
290        {
291            if ((!*Elements) ||
292                ((*Elements)->Common.Type != ACPI_TYPE_INTEGER))
293            {
294                return (AE_AML_OPERAND_TYPE);
295            }
296            Elements++;
297        }
298
299        /* Create the new buffer object to replace the Package */
300
301        NewObject = AcpiUtCreateBufferObject (ACPI_MUL_4 (Count));
302        if (!NewObject)
303        {
304            return (AE_NO_MEMORY);
305        }
306
307        /* Copy the package elements (integers) to the buffer as DWORDs */
308
309        Elements = OriginalObject->Package.Elements;
310        DwordBuffer = ACPI_CAST_PTR (UINT32, NewObject->Buffer.Pointer);
311
312        for (i = 0; i < Count; i++)
313        {
314            *DwordBuffer = (UINT32) (*Elements)->Integer.Value;
315            DwordBuffer++;
316            Elements++;
317        }
318        break;
319
320    default:
321
322        return (AE_AML_OPERAND_TYPE);
323    }
324
325    *ReturnObject = NewObject;
326    return (AE_OK);
327}
328
329
330/*******************************************************************************
331 *
332 * FUNCTION:    AcpiNsConvertToUnicode
333 *
334 * PARAMETERS:  Scope               - Namespace node for the method/object
335 *              OriginalObject      - ASCII String Object to be converted
336 *              ReturnObject        - Where the new converted object is returned
337 *
338 * RETURN:      Status. AE_OK if conversion was successful.
339 *
340 * DESCRIPTION: Attempt to convert a String object to a Unicode string Buffer.
341 *
342 ******************************************************************************/
343
344ACPI_STATUS
345AcpiNsConvertToUnicode (
346    ACPI_NAMESPACE_NODE     *Scope,
347    ACPI_OPERAND_OBJECT     *OriginalObject,
348    ACPI_OPERAND_OBJECT     **ReturnObject)
349{
350    ACPI_OPERAND_OBJECT     *NewObject;
351    char                    *AsciiString;
352    UINT16                  *UnicodeBuffer;
353    UINT32                  UnicodeLength;
354    UINT32                  i;
355
356
357    if (!OriginalObject)
358    {
359        return (AE_OK);
360    }
361
362    /* If a Buffer was returned, it must be at least two bytes long */
363
364    if (OriginalObject->Common.Type == ACPI_TYPE_BUFFER)
365    {
366        if (OriginalObject->Buffer.Length < 2)
367        {
368            return (AE_AML_OPERAND_VALUE);
369        }
370
371        *ReturnObject = NULL;
372        return (AE_OK);
373    }
374
375    /*
376     * The original object is an ASCII string. Convert this string to
377     * a unicode buffer.
378     */
379    AsciiString = OriginalObject->String.Pointer;
380    UnicodeLength = (OriginalObject->String.Length * 2) + 2;
381
382    /* Create a new buffer object for the Unicode data */
383
384    NewObject = AcpiUtCreateBufferObject (UnicodeLength);
385    if (!NewObject)
386    {
387        return (AE_NO_MEMORY);
388    }
389
390    UnicodeBuffer = ACPI_CAST_PTR (UINT16, NewObject->Buffer.Pointer);
391
392    /* Convert ASCII to Unicode */
393
394    for (i = 0; i < OriginalObject->String.Length; i++)
395    {
396        UnicodeBuffer[i] = (UINT16) AsciiString[i];
397    }
398
399    *ReturnObject = NewObject;
400    return (AE_OK);
401}
402
403
404/*******************************************************************************
405 *
406 * FUNCTION:    AcpiNsConvertToResource
407 *
408 * PARAMETERS:  Scope               - Namespace node for the method/object
409 *              OriginalObject      - Object to be converted
410 *              ReturnObject        - Where the new converted object is returned
411 *
412 * RETURN:      Status. AE_OK if conversion was successful
413 *
414 * DESCRIPTION: Attempt to convert a Integer object to a ResourceTemplate
415 *              Buffer.
416 *
417 ******************************************************************************/
418
419ACPI_STATUS
420AcpiNsConvertToResource (
421    ACPI_NAMESPACE_NODE     *Scope,
422    ACPI_OPERAND_OBJECT     *OriginalObject,
423    ACPI_OPERAND_OBJECT     **ReturnObject)
424{
425    ACPI_OPERAND_OBJECT     *NewObject;
426    UINT8                   *Buffer;
427
428
429    /*
430     * We can fix the following cases for an expected resource template:
431     * 1. No return value (interpreter slack mode is disabled)
432     * 2. A "Return (Zero)" statement
433     * 3. A "Return empty buffer" statement
434     *
435     * We will return a buffer containing a single EndTag
436     * resource descriptor.
437     */
438    if (OriginalObject)
439    {
440        switch (OriginalObject->Common.Type)
441        {
442        case ACPI_TYPE_INTEGER:
443
444            /* We can only repair an Integer==0 */
445
446            if (OriginalObject->Integer.Value)
447            {
448                return (AE_AML_OPERAND_TYPE);
449            }
450            break;
451
452        case ACPI_TYPE_BUFFER:
453
454            if (OriginalObject->Buffer.Length)
455            {
456                /* Additional checks can be added in the future */
457
458                *ReturnObject = NULL;
459                return (AE_OK);
460            }
461            break;
462
463        case ACPI_TYPE_STRING:
464        default:
465
466            return (AE_AML_OPERAND_TYPE);
467        }
468    }
469
470    /* Create the new buffer object for the resource descriptor */
471
472    NewObject = AcpiUtCreateBufferObject (2);
473    if (!NewObject)
474    {
475        return (AE_NO_MEMORY);
476    }
477
478    Buffer = ACPI_CAST_PTR (UINT8, NewObject->Buffer.Pointer);
479
480    /* Initialize the Buffer with a single EndTag descriptor */
481
482    Buffer[0] = (ACPI_RESOURCE_NAME_END_TAG | ASL_RDESC_END_TAG_SIZE);
483    Buffer[1] = 0x00;
484
485    *ReturnObject = NewObject;
486    return (AE_OK);
487}
488
489
490/*******************************************************************************
491 *
492 * FUNCTION:    AcpiNsConvertToReference
493 *
494 * PARAMETERS:  Scope               - Namespace node for the method/object
495 *              OriginalObject      - Object to be converted
496 *              ReturnObject        - Where the new converted object is returned
497 *
498 * RETURN:      Status. AE_OK if conversion was successful
499 *
500 * DESCRIPTION: Attempt to convert a Integer object to a ObjectReference.
501 *              Buffer.
502 *
503 ******************************************************************************/
504
505ACPI_STATUS
506AcpiNsConvertToReference (
507    ACPI_NAMESPACE_NODE     *Scope,
508    ACPI_OPERAND_OBJECT     *OriginalObject,
509    ACPI_OPERAND_OBJECT     **ReturnObject)
510{
511    ACPI_OPERAND_OBJECT     *NewObject = NULL;
512    ACPI_STATUS             Status;
513    ACPI_NAMESPACE_NODE     *Node;
514    ACPI_GENERIC_STATE      ScopeInfo;
515    char                    *Name;
516
517
518    ACPI_FUNCTION_NAME (NsConvertToReference);
519
520
521    /* Convert path into internal presentation */
522
523    Status = AcpiNsInternalizeName (OriginalObject->String.Pointer, &Name);
524    if (ACPI_FAILURE (Status))
525    {
526        return_ACPI_STATUS (Status);
527    }
528
529    /* Find the namespace node */
530
531    ScopeInfo.Scope.Node = ACPI_CAST_PTR (ACPI_NAMESPACE_NODE, Scope);
532    Status = AcpiNsLookup (&ScopeInfo, Name,
533        ACPI_TYPE_ANY, ACPI_IMODE_EXECUTE,
534        ACPI_NS_SEARCH_PARENT | ACPI_NS_DONT_OPEN_SCOPE, NULL, &Node);
535    if (ACPI_FAILURE (Status))
536    {
537        /* Check if we are resolving a named reference within a package */
538
539        ACPI_ERROR_NAMESPACE (&ScopeInfo,
540            OriginalObject->String.Pointer, Status);
541        goto ErrorExit;
542    }
543
544    /* Create and init a new internal ACPI object */
545
546    NewObject = AcpiUtCreateInternalObject (ACPI_TYPE_LOCAL_REFERENCE);
547    if (!NewObject)
548    {
549        Status = AE_NO_MEMORY;
550        goto ErrorExit;
551    }
552    NewObject->Reference.Node = Node;
553    NewObject->Reference.Object = Node->Object;
554    NewObject->Reference.Class = ACPI_REFCLASS_NAME;
555
556    /*
557     * Increase reference of the object if needed (the object is likely a
558     * null for device nodes).
559     */
560    AcpiUtAddReference (Node->Object);
561
562ErrorExit:
563    ACPI_FREE (Name);
564    *ReturnObject = NewObject;
565    return (Status);
566}
567