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