2a320780fbb4c01fb433aba834c55927efdc7108
[reactos.git] / reactos / drivers / bus / acpi / acpica / utilities / utresrc.c
1 /*******************************************************************************
2 *
3 * Module Name: utresrc - Resource management utilities
4 *
5 ******************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2017, 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 /*
199 * The absolute minimum resource template is one EndTag descriptor.
200 * However, we will treat a lone EndTag as just a simple buffer.
201 */
202 if (AmlLength <= sizeof (AML_RESOURCE_END_TAG))
203 {
204 return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG);
205 }
206
207 /* Point to the end of the resource template buffer */
208
209 EndAml = Aml + AmlLength;
210
211 /* Walk the byte list, abort on any invalid descriptor type or length */
212
213 while (Aml < EndAml)
214 {
215 /* Validate the Resource Type and Resource Length */
216
217 Status = AcpiUtValidateResource (WalkState, Aml, &ResourceIndex);
218 if (ACPI_FAILURE (Status))
219 {
220 /*
221 * Exit on failure. Cannot continue because the descriptor
222 * length may be bogus also.
223 */
224 return_ACPI_STATUS (Status);
225 }
226
227 /* Get the length of this descriptor */
228
229 Length = AcpiUtGetDescriptorLength (Aml);
230
231 /* Invoke the user function */
232
233 if (UserFunction)
234 {
235 Status = UserFunction (
236 Aml, Length, Offset, ResourceIndex, Context);
237 if (ACPI_FAILURE (Status))
238 {
239 return_ACPI_STATUS (Status);
240 }
241 }
242
243 /* An EndTag descriptor terminates this resource template */
244
245 if (AcpiUtGetResourceType (Aml) == ACPI_RESOURCE_NAME_END_TAG)
246 {
247 /*
248 * There must be at least one more byte in the buffer for
249 * the 2nd byte of the EndTag
250 */
251 if ((Aml + 1) >= EndAml)
252 {
253 return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG);
254 }
255
256 /*
257 * The EndTag opcode must be followed by a zero byte.
258 * Although this byte is technically defined to be a checksum,
259 * in practice, all ASL compilers set this byte to zero.
260 */
261 if (*(Aml + 1) != 0)
262 {
263 return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG);
264 }
265
266 /* Return the pointer to the EndTag if requested */
267
268 if (!UserFunction)
269 {
270 *Context = Aml;
271 }
272
273 /*
274 * Normal exit. Note: We allow the buffer to be larger than
275 * the resource template, as long as the END_TAG exists.
276 */
277 return_ACPI_STATUS (AE_OK);
278 }
279
280 Aml += Length;
281 Offset += Length;
282 }
283
284 /* Did not find an EndTag descriptor */
285
286 if (UserFunction)
287 {
288 /* Insert an EndTag anyway. AcpiRsGetListLength always leaves room */
289
290 (void) AcpiUtValidateResource (WalkState, EndTag, &ResourceIndex);
291 Status = UserFunction (EndTag, 2, Offset, ResourceIndex, Context);
292 if (ACPI_FAILURE (Status))
293 {
294 return_ACPI_STATUS (Status);
295 }
296 }
297
298 return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG);
299 }
300
301
302 /*******************************************************************************
303 *
304 * FUNCTION: AcpiUtValidateResource
305 *
306 * PARAMETERS: WalkState - Current walk info
307 * Aml - Pointer to the raw AML resource descriptor
308 * ReturnIndex - Where the resource index is returned. NULL
309 * if the index is not required.
310 *
311 * RETURN: Status, and optionally the Index into the global resource tables
312 *
313 * DESCRIPTION: Validate an AML resource descriptor by checking the Resource
314 * Type and Resource Length. Returns an index into the global
315 * resource information/dispatch tables for later use.
316 *
317 ******************************************************************************/
318
319 ACPI_STATUS
320 AcpiUtValidateResource (
321 ACPI_WALK_STATE *WalkState,
322 void *Aml,
323 UINT8 *ReturnIndex)
324 {
325 AML_RESOURCE *AmlResource;
326 UINT8 ResourceType;
327 UINT8 ResourceIndex;
328 ACPI_RS_LENGTH ResourceLength;
329 ACPI_RS_LENGTH MinimumResourceLength;
330
331
332 ACPI_FUNCTION_ENTRY ();
333
334
335 /*
336 * 1) Validate the ResourceType field (Byte 0)
337 */
338 ResourceType = ACPI_GET8 (Aml);
339
340 /*
341 * Byte 0 contains the descriptor name (Resource Type)
342 * Examine the large/small bit in the resource header
343 */
344 if (ResourceType & ACPI_RESOURCE_NAME_LARGE)
345 {
346 /* Verify the large resource type (name) against the max */
347
348 if (ResourceType > ACPI_RESOURCE_NAME_LARGE_MAX)
349 {
350 goto InvalidResource;
351 }
352
353 /*
354 * Large Resource Type -- bits 6:0 contain the name
355 * Translate range 0x80-0x8B to index range 0x10-0x1B
356 */
357 ResourceIndex = (UINT8) (ResourceType - 0x70);
358 }
359 else
360 {
361 /*
362 * Small Resource Type -- bits 6:3 contain the name
363 * Shift range to index range 0x00-0x0F
364 */
365 ResourceIndex = (UINT8)
366 ((ResourceType & ACPI_RESOURCE_NAME_SMALL_MASK) >> 3);
367 }
368
369 /*
370 * Check validity of the resource type, via AcpiGbl_ResourceTypes.
371 * Zero indicates an invalid resource.
372 */
373 if (!AcpiGbl_ResourceTypes[ResourceIndex])
374 {
375 goto InvalidResource;
376 }
377
378 /*
379 * Validate the ResourceLength field. This ensures that the length
380 * is at least reasonable, and guarantees that it is non-zero.
381 */
382 ResourceLength = AcpiUtGetResourceLength (Aml);
383 MinimumResourceLength = AcpiGbl_ResourceAmlSizes[ResourceIndex];
384
385 /* Validate based upon the type of resource - fixed length or variable */
386
387 switch (AcpiGbl_ResourceTypes[ResourceIndex])
388 {
389 case ACPI_FIXED_LENGTH:
390
391 /* Fixed length resource, length must match exactly */
392
393 if (ResourceLength != MinimumResourceLength)
394 {
395 goto BadResourceLength;
396 }
397 break;
398
399 case ACPI_VARIABLE_LENGTH:
400
401 /* Variable length resource, length must be at least the minimum */
402
403 if (ResourceLength < MinimumResourceLength)
404 {
405 goto BadResourceLength;
406 }
407 break;
408
409 case ACPI_SMALL_VARIABLE_LENGTH:
410
411 /* Small variable length resource, length can be (Min) or (Min-1) */
412
413 if ((ResourceLength > MinimumResourceLength) ||
414 (ResourceLength < (MinimumResourceLength - 1)))
415 {
416 goto BadResourceLength;
417 }
418 break;
419
420 default:
421
422 /* Shouldn't happen (because of validation earlier), but be sure */
423
424 goto InvalidResource;
425 }
426
427 AmlResource = ACPI_CAST_PTR (AML_RESOURCE, Aml);
428 if (ResourceType == ACPI_RESOURCE_NAME_SERIAL_BUS)
429 {
430 /* Validate the BusType field */
431
432 if ((AmlResource->CommonSerialBus.Type == 0) ||
433 (AmlResource->CommonSerialBus.Type > AML_RESOURCE_MAX_SERIALBUSTYPE))
434 {
435 if (WalkState)
436 {
437 ACPI_ERROR ((AE_INFO,
438 "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X",
439 AmlResource->CommonSerialBus.Type));
440 }
441 return (AE_AML_INVALID_RESOURCE_TYPE);
442 }
443 }
444
445 /* Optionally return the resource table index */
446
447 if (ReturnIndex)
448 {
449 *ReturnIndex = ResourceIndex;
450 }
451
452 return (AE_OK);
453
454
455 InvalidResource:
456
457 if (WalkState)
458 {
459 ACPI_ERROR ((AE_INFO,
460 "Invalid/unsupported resource descriptor: Type 0x%2.2X",
461 ResourceType));
462 }
463 return (AE_AML_INVALID_RESOURCE_TYPE);
464
465 BadResourceLength:
466
467 if (WalkState)
468 {
469 ACPI_ERROR ((AE_INFO,
470 "Invalid resource descriptor length: Type "
471 "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X",
472 ResourceType, ResourceLength, MinimumResourceLength));
473 }
474 return (AE_AML_BAD_RESOURCE_LENGTH);
475 }
476
477
478 /*******************************************************************************
479 *
480 * FUNCTION: AcpiUtGetResourceType
481 *
482 * PARAMETERS: Aml - Pointer to the raw AML resource descriptor
483 *
484 * RETURN: The Resource Type with no extraneous bits (except the
485 * Large/Small descriptor bit -- this is left alone)
486 *
487 * DESCRIPTION: Extract the Resource Type/Name from the first byte of
488 * a resource descriptor.
489 *
490 ******************************************************************************/
491
492 UINT8
493 AcpiUtGetResourceType (
494 void *Aml)
495 {
496 ACPI_FUNCTION_ENTRY ();
497
498
499 /*
500 * Byte 0 contains the descriptor name (Resource Type)
501 * Examine the large/small bit in the resource header
502 */
503 if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE)
504 {
505 /* Large Resource Type -- bits 6:0 contain the name */
506
507 return (ACPI_GET8 (Aml));
508 }
509 else
510 {
511 /* Small Resource Type -- bits 6:3 contain the name */
512
513 return ((UINT8) (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_SMALL_MASK));
514 }
515 }
516
517
518 /*******************************************************************************
519 *
520 * FUNCTION: AcpiUtGetResourceLength
521 *
522 * PARAMETERS: Aml - Pointer to the raw AML resource descriptor
523 *
524 * RETURN: Byte Length
525 *
526 * DESCRIPTION: Get the "Resource Length" of a raw AML descriptor. By
527 * definition, this does not include the size of the descriptor
528 * header or the length field itself.
529 *
530 ******************************************************************************/
531
532 UINT16
533 AcpiUtGetResourceLength (
534 void *Aml)
535 {
536 ACPI_RS_LENGTH ResourceLength;
537
538
539 ACPI_FUNCTION_ENTRY ();
540
541
542 /*
543 * Byte 0 contains the descriptor name (Resource Type)
544 * Examine the large/small bit in the resource header
545 */
546 if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE)
547 {
548 /* Large Resource type -- bytes 1-2 contain the 16-bit length */
549
550 ACPI_MOVE_16_TO_16 (&ResourceLength, ACPI_ADD_PTR (UINT8, Aml, 1));
551
552 }
553 else
554 {
555 /* Small Resource type -- bits 2:0 of byte 0 contain the length */
556
557 ResourceLength = (UINT16) (ACPI_GET8 (Aml) &
558 ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK);
559 }
560
561 return (ResourceLength);
562 }
563
564
565 /*******************************************************************************
566 *
567 * FUNCTION: AcpiUtGetResourceHeaderLength
568 *
569 * PARAMETERS: Aml - Pointer to the raw AML resource descriptor
570 *
571 * RETURN: Length of the AML header (depends on large/small descriptor)
572 *
573 * DESCRIPTION: Get the length of the header for this resource.
574 *
575 ******************************************************************************/
576
577 UINT8
578 AcpiUtGetResourceHeaderLength (
579 void *Aml)
580 {
581 ACPI_FUNCTION_ENTRY ();
582
583
584 /* Examine the large/small bit in the resource header */
585
586 if (ACPI_GET8 (Aml) & ACPI_RESOURCE_NAME_LARGE)
587 {
588 return (sizeof (AML_RESOURCE_LARGE_HEADER));
589 }
590 else
591 {
592 return (sizeof (AML_RESOURCE_SMALL_HEADER));
593 }
594 }
595
596
597 /*******************************************************************************
598 *
599 * FUNCTION: AcpiUtGetDescriptorLength
600 *
601 * PARAMETERS: Aml - Pointer to the raw AML resource descriptor
602 *
603 * RETURN: Byte length
604 *
605 * DESCRIPTION: Get the total byte length of a raw AML descriptor, including the
606 * length of the descriptor header and the length field itself.
607 * Used to walk descriptor lists.
608 *
609 ******************************************************************************/
610
611 UINT32
612 AcpiUtGetDescriptorLength (
613 void *Aml)
614 {
615 ACPI_FUNCTION_ENTRY ();
616
617
618 /*
619 * Get the Resource Length (does not include header length) and add
620 * the header length (depends on if this is a small or large resource)
621 */
622 return (AcpiUtGetResourceLength (Aml) +
623 AcpiUtGetResourceHeaderLength (Aml));
624 }
625
626
627 /*******************************************************************************
628 *
629 * FUNCTION: AcpiUtGetResourceEndTag
630 *
631 * PARAMETERS: ObjDesc - The resource template buffer object
632 * EndTag - Where the pointer to the EndTag is returned
633 *
634 * RETURN: Status, pointer to the end tag
635 *
636 * DESCRIPTION: Find the EndTag resource descriptor in an AML resource template
637 * Note: allows a buffer length of zero.
638 *
639 ******************************************************************************/
640
641 ACPI_STATUS
642 AcpiUtGetResourceEndTag (
643 ACPI_OPERAND_OBJECT *ObjDesc,
644 UINT8 **EndTag)
645 {
646 ACPI_STATUS Status;
647
648
649 ACPI_FUNCTION_TRACE (UtGetResourceEndTag);
650
651
652 /* Allow a buffer length of zero */
653
654 if (!ObjDesc->Buffer.Length)
655 {
656 *EndTag = ObjDesc->Buffer.Pointer;
657 return_ACPI_STATUS (AE_OK);
658 }
659
660 /* Validate the template and get a pointer to the EndTag */
661
662 Status = AcpiUtWalkAmlResources (NULL, ObjDesc->Buffer.Pointer,
663 ObjDesc->Buffer.Length, NULL, (void **) EndTag);
664
665 return_ACPI_STATUS (Status);
666 }