1/*******************************************************************************
2 *
3 * Module Name: utresrc - Resource management utilities
4 *
5 ******************************************************************************/
6
7/*
8 * Copyright (C) 2000 - 2023, 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 MERCHANTABILITY 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 "acresrc.h"
47
48
49#define _COMPONENT          ACPI_UTILITIES
50        ACPI_MODULE_NAME    ("utresrc")
51
52
53/*
54 * Base sizes of the raw AML resource descriptors, indexed by resource type.
55 * Zero indicates a reserved (and therefore invalid) resource type.
56 */
57const UINT8                 AcpiGbl_ResourceAmlSizes[] =
58{
59    /* Small descriptors */
60
61    0,
62    0,
63    0,
64    0,
65    ACPI_AML_SIZE_SMALL (AML_RESOURCE_IRQ),
66    ACPI_AML_SIZE_SMALL (AML_RESOURCE_DMA),
67    ACPI_AML_SIZE_SMALL (AML_RESOURCE_START_DEPENDENT),
68    ACPI_AML_SIZE_SMALL (AML_RESOURCE_END_DEPENDENT),
69    ACPI_AML_SIZE_SMALL (AML_RESOURCE_IO),
70    ACPI_AML_SIZE_SMALL (AML_RESOURCE_FIXED_IO),
71    ACPI_AML_SIZE_SMALL (AML_RESOURCE_FIXED_DMA),
72    0,
73    0,
74    0,
75    ACPI_AML_SIZE_SMALL (AML_RESOURCE_VENDOR_SMALL),
76    ACPI_AML_SIZE_SMALL (AML_RESOURCE_END_TAG),
77
78    /* Large descriptors */
79
80    0,
81    ACPI_AML_SIZE_LARGE (AML_RESOURCE_MEMORY24),
82    ACPI_AML_SIZE_LARGE (AML_RESOURCE_GENERIC_REGISTER),
83    0,
84    ACPI_AML_SIZE_LARGE (AML_RESOURCE_VENDOR_LARGE),
85    ACPI_AML_SIZE_LARGE (AML_RESOURCE_MEMORY32),
86    ACPI_AML_SIZE_LARGE (AML_RESOURCE_FIXED_MEMORY32),
87    ACPI_AML_SIZE_LARGE (AML_RESOURCE_ADDRESS32),
88    ACPI_AML_SIZE_LARGE (AML_RESOURCE_ADDRESS16),
89    ACPI_AML_SIZE_LARGE (AML_RESOURCE_EXTENDED_IRQ),
90    ACPI_AML_SIZE_LARGE (AML_RESOURCE_ADDRESS64),
91    ACPI_AML_SIZE_LARGE (AML_RESOURCE_EXTENDED_ADDRESS64),
92    ACPI_AML_SIZE_LARGE (AML_RESOURCE_GPIO),
93    ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_FUNCTION),
94    ACPI_AML_SIZE_LARGE (AML_RESOURCE_COMMON_SERIALBUS),
95    ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_CONFIG),
96    ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_GROUP),
97    ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_GROUP_FUNCTION),
98    ACPI_AML_SIZE_LARGE (AML_RESOURCE_PIN_GROUP_CONFIG),
99    ACPI_AML_SIZE_LARGE (AML_RESOURCE_CLOCK_INPUT),
100
101};
102
103const UINT8                 AcpiGbl_ResourceAmlSerialBusSizes[] =
104{
105    0,
106    ACPI_AML_SIZE_LARGE (AML_RESOURCE_I2C_SERIALBUS),
107    ACPI_AML_SIZE_LARGE (AML_RESOURCE_SPI_SERIALBUS),
108    ACPI_AML_SIZE_LARGE (AML_RESOURCE_UART_SERIALBUS),
109    ACPI_AML_SIZE_LARGE (AML_RESOURCE_CSI2_SERIALBUS),
110};
111
112
113/*
114 * Resource types, used to validate the resource length field.
115 * The length of fixed-length types must match exactly, variable
116 * lengths must meet the minimum required length, etc.
117 * Zero indicates a reserved (and therefore invalid) resource type.
118 */
119static const UINT8          AcpiGbl_ResourceTypes[] =
120{
121    /* Small descriptors */
122
123    0,
124    0,
125    0,
126    0,
127    ACPI_SMALL_VARIABLE_LENGTH,     /* 04 IRQ */
128    ACPI_FIXED_LENGTH,              /* 05 DMA */
129    ACPI_SMALL_VARIABLE_LENGTH,     /* 06 StartDependentFunctions */
130    ACPI_FIXED_LENGTH,              /* 07 EndDependentFunctions */
131    ACPI_FIXED_LENGTH,              /* 08 IO */
132    ACPI_FIXED_LENGTH,              /* 09 FixedIO */
133    ACPI_FIXED_LENGTH,              /* 0A FixedDMA */
134    0,
135    0,
136    0,
137    ACPI_VARIABLE_LENGTH,           /* 0E VendorShort */
138    ACPI_FIXED_LENGTH,              /* 0F EndTag */
139
140    /* Large descriptors */
141
142    0,
143    ACPI_FIXED_LENGTH,              /* 01 Memory24 */
144    ACPI_FIXED_LENGTH,              /* 02 GenericRegister */
145    0,
146    ACPI_VARIABLE_LENGTH,           /* 04 VendorLong */
147    ACPI_FIXED_LENGTH,              /* 05 Memory32 */
148    ACPI_FIXED_LENGTH,              /* 06 Memory32Fixed */
149    ACPI_VARIABLE_LENGTH,           /* 07 Dword* address */
150    ACPI_VARIABLE_LENGTH,           /* 08 Word* address */
151    ACPI_VARIABLE_LENGTH,           /* 09 ExtendedIRQ */
152    ACPI_VARIABLE_LENGTH,           /* 0A Qword* address */
153    ACPI_FIXED_LENGTH,              /* 0B Extended* address */
154    ACPI_VARIABLE_LENGTH,           /* 0C Gpio* */
155    ACPI_VARIABLE_LENGTH,           /* 0D PinFunction */
156    ACPI_VARIABLE_LENGTH,           /* 0E *SerialBus */
157    ACPI_VARIABLE_LENGTH,           /* 0F PinConfig */
158    ACPI_VARIABLE_LENGTH,           /* 10 PinGroup */
159    ACPI_VARIABLE_LENGTH,           /* 11 PinGroupFunction */
160    ACPI_VARIABLE_LENGTH,           /* 12 PinGroupConfig */
161    ACPI_VARIABLE_LENGTH,           /* 13 ClockInput */
162};
163
164
165/*******************************************************************************
166 *
167 * FUNCTION:    AcpiUtWalkAmlResources
168 *
169 * PARAMETERS:  WalkState           - Current walk info
170 * PARAMETERS:  Aml                 - Pointer to the raw AML resource template
171 *              AmlLength           - Length of the entire template
172 *              UserFunction        - Called once for each descriptor found. If
173 *                                    NULL, a pointer to the EndTag is returned
174 *              Context             - Passed to UserFunction
175 *
176 * RETURN:      Status
177 *
178 * DESCRIPTION: Walk a raw AML resource list(buffer). User function called
179 *              once for each resource found.
180 *
181 ******************************************************************************/
182
183ACPI_STATUS
184AcpiUtWalkAmlResources (
185    ACPI_WALK_STATE         *WalkState,
186    UINT8                   *Aml,
187    ACPI_SIZE               AmlLength,
188    ACPI_WALK_AML_CALLBACK  UserFunction,
189    void                    **Context)
190{
191    ACPI_STATUS             Status;
192    UINT8                   *EndAml;
193    UINT8                   ResourceIndex;
194    UINT32                  Length;
195    UINT32                  Offset = 0;
196    UINT8                   EndTag[2] = {0x79, 0x00};
197
198
199    ACPI_FUNCTION_TRACE (UtWalkAmlResources);
200
201
202    /* The absolute minimum resource template is one EndTag descriptor */
203
204    if (AmlLength < sizeof (AML_RESOURCE_END_TAG))
205    {
206        return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG);
207    }
208
209    /* Point to the end of the resource template buffer */
210
211    EndAml = Aml + AmlLength;
212
213    /* Walk the byte list, abort on any invalid descriptor type or length */
214
215    while (Aml < EndAml)
216    {
217        /* Validate the Resource Type and Resource Length */
218
219        Status = AcpiUtValidateResource (WalkState, Aml, &ResourceIndex);
220        if (ACPI_FAILURE (Status))
221        {
222            /*
223             * Exit on failure. Cannot continue because the descriptor
224             * length may be bogus also.
225             */
226            return_ACPI_STATUS (Status);
227        }
228
229        /* Get the length of this descriptor */
230
231        Length = AcpiUtGetDescriptorLength (Aml);
232
233        /* Invoke the user function */
234
235        if (UserFunction)
236        {
237            Status = UserFunction (
238                Aml, Length, Offset, ResourceIndex, Context);
239            if (ACPI_FAILURE (Status))
240            {
241                return_ACPI_STATUS (Status);
242            }
243        }
244
245        /* An EndTag descriptor terminates this resource template */
246
247        if (AcpiUtGetResourceType (Aml) == ACPI_RESOURCE_NAME_END_TAG)
248        {
249            /*
250             * There must be at least one more byte in the buffer for
251             * the 2nd byte of the EndTag
252             */
253            if ((Aml + 1) >= EndAml)
254            {
255                return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG);
256            }
257
258            /*
259             * Don't attempt to perform any validation on the 2nd byte.
260             * Although all known ASL compilers insert a zero for the 2nd
261             * byte, it can also be a checksum (as per the ACPI spec),
262             * and this is occasionally seen in the field. July 2017.
263             */
264
265            /* Return the pointer to the EndTag if requested */
266
267            if (!UserFunction)
268            {
269                *Context = Aml;
270            }
271
272            /* Normal exit */
273
274            return_ACPI_STATUS (AE_OK);
275        }
276
277        Aml += Length;
278        Offset += Length;
279    }
280
281    /* Did not find an EndTag descriptor */
282
283    if (UserFunction)
284    {
285        /* Insert an EndTag anyway. AcpiRsGetListLength always leaves room */
286
287        (void) AcpiUtValidateResource (WalkState, EndTag, &ResourceIndex);
288        Status = UserFunction (EndTag, 2, Offset, ResourceIndex, Context);
289        if (ACPI_FAILURE (Status))
290        {
291            return_ACPI_STATUS (Status);
292        }
293    }
294
295    return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG);
296}
297
298
299/*******************************************************************************
300 *
301 * FUNCTION:    AcpiUtValidateResource
302 *
303 * PARAMETERS:  WalkState           - Current walk info
304 *              Aml                 - Pointer to the raw AML resource descriptor
305 *              ReturnIndex         - Where the resource index is returned. NULL
306 *                                    if the index is not required.
307 *
308 * RETURN:      Status, and optionally the Index into the global resource tables
309 *
310 * DESCRIPTION: Validate an AML resource descriptor by checking the Resource
311 *              Type and Resource Length. Returns an index into the global
312 *              resource information/dispatch tables for later use.
313 *
314 ******************************************************************************/
315
316ACPI_STATUS
317AcpiUtValidateResource (
318    ACPI_WALK_STATE         *WalkState,
319    void                    *Aml,
320    UINT8                   *ReturnIndex)
321{
322    AML_RESOURCE            *AmlResource;
323    UINT8                   ResourceType;
324    UINT8                   ResourceIndex;
325    ACPI_RS_LENGTH          ResourceLength;
326    ACPI_RS_LENGTH          MinimumResourceLength;
327
328
329    ACPI_FUNCTION_ENTRY ();
330
331
332    /*
333     * 1) Validate the ResourceType field (Byte 0)
334     */
335    ResourceType = ACPI_GET8 (Aml);
336
337    /*
338     * Byte 0 contains the descriptor name (Resource Type)
339     * Examine the large/small bit in the resource header
340     */
341    if (ResourceType & ACPI_RESOURCE_NAME_LARGE)
342    {
343        /* Verify the large resource type (name) against the max */
344
345        if (ResourceType > ACPI_RESOURCE_NAME_LARGE_MAX)
346        {
347            goto InvalidResource;
348        }
349
350        /*
351         * Large Resource Type -- bits 6:0 contain the name
352         * Translate range 0x80-0x8B to index range 0x10-0x1B
353         */
354        ResourceIndex = (UINT8) (ResourceType - 0x70);
355    }
356    else
357    {
358        /*
359         * Small Resource Type -- bits 6:3 contain the name
360         * Shift range to index range 0x00-0x0F
361         */
362        ResourceIndex = (UINT8)
363            ((ResourceType & ACPI_RESOURCE_NAME_SMALL_MASK) >> 3);
364    }
365
366    /*
367     * Check validity of the resource type, via AcpiGbl_ResourceTypes.
368     * Zero indicates an invalid resource.
369     */
370    if (!AcpiGbl_ResourceTypes[ResourceIndex])
371    {
372        goto InvalidResource;
373    }
374
375    /*
376     * Validate the ResourceLength field. This ensures that the length
377     * is at least reasonable, and guarantees that it is non-zero.
378     */
379    ResourceLength = AcpiUtGetResourceLength (Aml);
380    MinimumResourceLength = AcpiGbl_ResourceAmlSizes[ResourceIndex];
381
382    /* Validate based upon the type of resource - fixed length or variable */
383
384    switch (AcpiGbl_ResourceTypes[ResourceIndex])
385    {
386    case ACPI_FIXED_LENGTH:
387
388        /* Fixed length resource, length must match exactly */
389
390        if (ResourceLength != MinimumResourceLength)
391        {
392            goto BadResourceLength;
393        }
394        break;
395
396    case ACPI_VARIABLE_LENGTH:
397
398        /* Variable length resource, length must be at least the minimum */
399
400        if (ResourceLength < MinimumResourceLength)
401        {
402            goto BadResourceLength;
403        }
404        break;
405
406    case ACPI_SMALL_VARIABLE_LENGTH:
407
408        /* Small variable length resource, length can be (Min) or (Min-1) */
409
410        if ((ResourceLength > MinimumResourceLength) ||
411            (ResourceLength < (MinimumResourceLength - 1)))
412        {
413            goto BadResourceLength;
414        }
415        break;
416
417    default:
418
419        /* Shouldn't happen (because of validation earlier), but be sure */
420
421        goto InvalidResource;
422    }
423
424    AmlResource = ACPI_CAST_PTR (AML_RESOURCE, Aml);
425    if (ResourceType == ACPI_RESOURCE_NAME_SERIAL_BUS)
426    {
427        /* Avoid undefined behavior: member access within misaligned address */
428
429        AML_RESOURCE_COMMON_SERIALBUS CommonSerialBus;
430        memcpy(&CommonSerialBus, AmlResource, sizeof(CommonSerialBus));
431
432        /* Validate the BusType field */
433
434        if ((CommonSerialBus.Type == 0) ||
435            (CommonSerialBus.Type > AML_RESOURCE_MAX_SERIALBUSTYPE))
436        {
437            if (WalkState)
438            {
439                ACPI_ERROR ((AE_INFO,
440                    "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X",
441                    CommonSerialBus.Type));
442            }
443            return (AE_AML_INVALID_RESOURCE_TYPE);
444        }
445    }
446
447    /* Optionally return the resource table index */
448
449    if (ReturnIndex)
450    {
451        *ReturnIndex = ResourceIndex;
452    }
453
454    return (AE_OK);
455
456
457InvalidResource:
458
459    if (WalkState)
460    {
461        ACPI_ERROR ((AE_INFO,
462            "Invalid/unsupported resource descriptor: Type 0x%2.2X",
463            ResourceType));
464    }
465    return (AE_AML_INVALID_RESOURCE_TYPE);
466
467BadResourceLength:
468
469    if (WalkState)
470    {
471        ACPI_ERROR ((AE_INFO,
472            "Invalid resource descriptor length: Type "
473            "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X",
474            ResourceType, ResourceLength, MinimumResourceLength));
475    }
476    return (AE_AML_BAD_RESOURCE_LENGTH);
477}
478
479
480/*******************************************************************************
481 *
482 * FUNCTION:    AcpiUtGetResourceType
483 *
484 * PARAMETERS:  Aml             - Pointer to the raw AML resource descriptor
485 *
486 * RETURN:      The Resource Type with no extraneous bits (except the
487 *              Large/Small descriptor bit -- this is left alone)
488 *
489 * DESCRIPTION: Extract the Resource Type/Name from the first byte of
490 *              a resource descriptor.
491 *
492 ******************************************************************************/
493
494UINT8
495AcpiUtGetResourceType (
496    void                    *Aml)
497{
498    ACPI_FUNCTION_ENTRY ();
499
500
501    /*
502     * Byte 0 contains the descriptor name (Resource Type)
503     * Examine the large/small bit in the resource header
504     */
505    if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE)
506    {
507        /* Large Resource Type -- bits 6:0 contain the name */
508
509        return (ACPI_GET8 (Aml));
510    }
511    else
512    {
513        /* Small Resource Type -- bits 6:3 contain the name */
514
515        return ((UINT8) (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_SMALL_MASK));
516    }
517}
518
519
520/*******************************************************************************
521 *
522 * FUNCTION:    AcpiUtGetResourceLength
523 *
524 * PARAMETERS:  Aml             - Pointer to the raw AML resource descriptor
525 *
526 * RETURN:      Byte Length
527 *
528 * DESCRIPTION: Get the "Resource Length" of a raw AML descriptor. By
529 *              definition, this does not include the size of the descriptor
530 *              header or the length field itself.
531 *
532 ******************************************************************************/
533
534UINT16
535AcpiUtGetResourceLength (
536    void                    *Aml)
537{
538    ACPI_RS_LENGTH          ResourceLength;
539
540
541    ACPI_FUNCTION_ENTRY ();
542
543
544    /*
545     * Byte 0 contains the descriptor name (Resource Type)
546     * Examine the large/small bit in the resource header
547     */
548    if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE)
549    {
550        /* Large Resource type -- bytes 1-2 contain the 16-bit length */
551
552        ACPI_MOVE_16_TO_16 (&ResourceLength, ACPI_ADD_PTR (UINT8, Aml, 1));
553
554    }
555    else
556    {
557        /* Small Resource type -- bits 2:0 of byte 0 contain the length */
558
559        ResourceLength = (UINT16) (ACPI_GET8 (Aml) &
560            ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK);
561    }
562
563    return (ResourceLength);
564}
565
566
567/*******************************************************************************
568 *
569 * FUNCTION:    AcpiUtGetResourceHeaderLength
570 *
571 * PARAMETERS:  Aml             - Pointer to the raw AML resource descriptor
572 *
573 * RETURN:      Length of the AML header (depends on large/small descriptor)
574 *
575 * DESCRIPTION: Get the length of the header for this resource.
576 *
577 ******************************************************************************/
578
579UINT8
580AcpiUtGetResourceHeaderLength (
581    void                    *Aml)
582{
583    ACPI_FUNCTION_ENTRY ();
584
585
586    /* Examine the large/small bit in the resource header */
587
588    if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE)
589    {
590        return (sizeof (AML_RESOURCE_LARGE_HEADER));
591    }
592    else
593    {
594        return (sizeof (AML_RESOURCE_SMALL_HEADER));
595    }
596}
597
598
599/*******************************************************************************
600 *
601 * FUNCTION:    AcpiUtGetDescriptorLength
602 *
603 * PARAMETERS:  Aml             - Pointer to the raw AML resource descriptor
604 *
605 * RETURN:      Byte length
606 *
607 * DESCRIPTION: Get the total byte length of a raw AML descriptor, including the
608 *              length of the descriptor header and the length field itself.
609 *              Used to walk descriptor lists.
610 *
611 ******************************************************************************/
612
613UINT32
614AcpiUtGetDescriptorLength (
615    void                    *Aml)
616{
617    ACPI_FUNCTION_ENTRY ();
618
619
620    /*
621     * Get the Resource Length (does not include header length) and add
622     * the header length (depends on if this is a small or large resource)
623     */
624    return (AcpiUtGetResourceLength (Aml) +
625        AcpiUtGetResourceHeaderLength (Aml));
626}
627
628
629/*******************************************************************************
630 *
631 * FUNCTION:    AcpiUtGetResourceEndTag
632 *
633 * PARAMETERS:  ObjDesc         - The resource template buffer object
634 *              EndTag          - Where the pointer to the EndTag is returned
635 *
636 * RETURN:      Status, pointer to the end tag
637 *
638 * DESCRIPTION: Find the EndTag resource descriptor in an AML resource template
639 *              Note: allows a buffer length of zero.
640 *
641 ******************************************************************************/
642
643ACPI_STATUS
644AcpiUtGetResourceEndTag (
645    ACPI_OPERAND_OBJECT     *ObjDesc,
646    UINT8                   **EndTag)
647{
648    ACPI_STATUS             Status;
649
650
651    ACPI_FUNCTION_TRACE (UtGetResourceEndTag);
652
653
654    /* Allow a buffer length of zero */
655
656    if (!ObjDesc->Buffer.Length)
657    {
658        *EndTag = ObjDesc->Buffer.Pointer;
659        return_ACPI_STATUS (AE_OK);
660    }
661
662    /* Validate the template and get a pointer to the EndTag */
663
664    Status = AcpiUtWalkAmlResources (NULL, ObjDesc->Buffer.Pointer,
665        ObjDesc->Buffer.Length, NULL, (void **) EndTag);
666
667    return_ACPI_STATUS (Status);
668}
669