Branch data Line data Source code
1 : : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 : : /*******************************************************************************
3 : : *
4 : : * Module Name: utresrc - Resource management utilities
5 : : *
6 : : ******************************************************************************/
7 : :
8 : : #include <acpi/acpi.h>
9 : : #include "accommon.h"
10 : : #include "acresrc.h"
11 : :
12 : : #define _COMPONENT ACPI_UTILITIES
13 : : ACPI_MODULE_NAME("utresrc")
14 : :
15 : : /*
16 : : * Base sizes of the raw AML resource descriptors, indexed by resource type.
17 : : * Zero indicates a reserved (and therefore invalid) resource type.
18 : : */
19 : : const u8 acpi_gbl_resource_aml_sizes[] = {
20 : : /* Small descriptors */
21 : :
22 : : 0,
23 : : 0,
24 : : 0,
25 : : 0,
26 : : ACPI_AML_SIZE_SMALL(struct aml_resource_irq),
27 : : ACPI_AML_SIZE_SMALL(struct aml_resource_dma),
28 : : ACPI_AML_SIZE_SMALL(struct aml_resource_start_dependent),
29 : : ACPI_AML_SIZE_SMALL(struct aml_resource_end_dependent),
30 : : ACPI_AML_SIZE_SMALL(struct aml_resource_io),
31 : : ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_io),
32 : : ACPI_AML_SIZE_SMALL(struct aml_resource_fixed_dma),
33 : : 0,
34 : : 0,
35 : : 0,
36 : : ACPI_AML_SIZE_SMALL(struct aml_resource_vendor_small),
37 : : ACPI_AML_SIZE_SMALL(struct aml_resource_end_tag),
38 : :
39 : : /* Large descriptors */
40 : :
41 : : 0,
42 : : ACPI_AML_SIZE_LARGE(struct aml_resource_memory24),
43 : : ACPI_AML_SIZE_LARGE(struct aml_resource_generic_register),
44 : : 0,
45 : : ACPI_AML_SIZE_LARGE(struct aml_resource_vendor_large),
46 : : ACPI_AML_SIZE_LARGE(struct aml_resource_memory32),
47 : : ACPI_AML_SIZE_LARGE(struct aml_resource_fixed_memory32),
48 : : ACPI_AML_SIZE_LARGE(struct aml_resource_address32),
49 : : ACPI_AML_SIZE_LARGE(struct aml_resource_address16),
50 : : ACPI_AML_SIZE_LARGE(struct aml_resource_extended_irq),
51 : : ACPI_AML_SIZE_LARGE(struct aml_resource_address64),
52 : : ACPI_AML_SIZE_LARGE(struct aml_resource_extended_address64),
53 : : ACPI_AML_SIZE_LARGE(struct aml_resource_gpio),
54 : : ACPI_AML_SIZE_LARGE(struct aml_resource_pin_function),
55 : : ACPI_AML_SIZE_LARGE(struct aml_resource_common_serialbus),
56 : : ACPI_AML_SIZE_LARGE(struct aml_resource_pin_config),
57 : : ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group),
58 : : ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group_function),
59 : : ACPI_AML_SIZE_LARGE(struct aml_resource_pin_group_config),
60 : : };
61 : :
62 : : const u8 acpi_gbl_resource_aml_serial_bus_sizes[] = {
63 : : 0,
64 : : ACPI_AML_SIZE_LARGE(struct aml_resource_i2c_serialbus),
65 : : ACPI_AML_SIZE_LARGE(struct aml_resource_spi_serialbus),
66 : : ACPI_AML_SIZE_LARGE(struct aml_resource_uart_serialbus),
67 : : };
68 : :
69 : : /*
70 : : * Resource types, used to validate the resource length field.
71 : : * The length of fixed-length types must match exactly, variable
72 : : * lengths must meet the minimum required length, etc.
73 : : * Zero indicates a reserved (and therefore invalid) resource type.
74 : : */
75 : : static const u8 acpi_gbl_resource_types[] = {
76 : : /* Small descriptors */
77 : :
78 : : 0,
79 : : 0,
80 : : 0,
81 : : 0,
82 : : ACPI_SMALL_VARIABLE_LENGTH, /* 04 IRQ */
83 : : ACPI_FIXED_LENGTH, /* 05 DMA */
84 : : ACPI_SMALL_VARIABLE_LENGTH, /* 06 start_dependent_functions */
85 : : ACPI_FIXED_LENGTH, /* 07 end_dependent_functions */
86 : : ACPI_FIXED_LENGTH, /* 08 IO */
87 : : ACPI_FIXED_LENGTH, /* 09 fixed_IO */
88 : : ACPI_FIXED_LENGTH, /* 0A fixed_DMA */
89 : : 0,
90 : : 0,
91 : : 0,
92 : : ACPI_VARIABLE_LENGTH, /* 0E vendor_short */
93 : : ACPI_FIXED_LENGTH, /* 0F end_tag */
94 : :
95 : : /* Large descriptors */
96 : :
97 : : 0,
98 : : ACPI_FIXED_LENGTH, /* 01 Memory24 */
99 : : ACPI_FIXED_LENGTH, /* 02 generic_register */
100 : : 0,
101 : : ACPI_VARIABLE_LENGTH, /* 04 vendor_long */
102 : : ACPI_FIXED_LENGTH, /* 05 Memory32 */
103 : : ACPI_FIXED_LENGTH, /* 06 memory32_fixed */
104 : : ACPI_VARIABLE_LENGTH, /* 07 Dword* address */
105 : : ACPI_VARIABLE_LENGTH, /* 08 Word* address */
106 : : ACPI_VARIABLE_LENGTH, /* 09 extended_IRQ */
107 : : ACPI_VARIABLE_LENGTH, /* 0A Qword* address */
108 : : ACPI_FIXED_LENGTH, /* 0B Extended* address */
109 : : ACPI_VARIABLE_LENGTH, /* 0C Gpio* */
110 : : ACPI_VARIABLE_LENGTH, /* 0D pin_function */
111 : : ACPI_VARIABLE_LENGTH, /* 0E *serial_bus */
112 : : ACPI_VARIABLE_LENGTH, /* 0F pin_config */
113 : : ACPI_VARIABLE_LENGTH, /* 10 pin_group */
114 : : ACPI_VARIABLE_LENGTH, /* 11 pin_group_function */
115 : : ACPI_VARIABLE_LENGTH, /* 12 pin_group_config */
116 : : };
117 : :
118 : : /*******************************************************************************
119 : : *
120 : : * FUNCTION: acpi_ut_walk_aml_resources
121 : : *
122 : : * PARAMETERS: walk_state - Current walk info
123 : : * PARAMETERS: aml - Pointer to the raw AML resource template
124 : : * aml_length - Length of the entire template
125 : : * user_function - Called once for each descriptor found. If
126 : : * NULL, a pointer to the end_tag is returned
127 : : * context - Passed to user_function
128 : : *
129 : : * RETURN: Status
130 : : *
131 : : * DESCRIPTION: Walk a raw AML resource list(buffer). User function called
132 : : * once for each resource found.
133 : : *
134 : : ******************************************************************************/
135 : :
136 : : acpi_status
137 : 520 : acpi_ut_walk_aml_resources(struct acpi_walk_state *walk_state,
138 : : u8 *aml,
139 : : acpi_size aml_length,
140 : : acpi_walk_aml_callback user_function, void **context)
141 : : {
142 : 520 : acpi_status status;
143 : 520 : u8 *end_aml;
144 : 520 : u8 resource_index;
145 : 520 : u32 length;
146 : 520 : u32 offset = 0;
147 : 520 : u8 end_tag[2] = { 0x79, 0x00 };
148 : :
149 : 520 : ACPI_FUNCTION_TRACE(ut_walk_aml_resources);
150 : :
151 : : /* The absolute minimum resource template is one end_tag descriptor */
152 : :
153 [ + - ]: 520 : if (aml_length < sizeof(struct aml_resource_end_tag)) {
154 : : return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
155 : : }
156 : :
157 : : /* Point to the end of the resource template buffer */
158 : :
159 : 520 : end_aml = aml + aml_length;
160 : :
161 : : /* Walk the byte list, abort on any invalid descriptor type or length */
162 : :
163 [ + - ]: 1482 : while (aml < end_aml) {
164 : :
165 : : /* Validate the Resource Type and Resource Length */
166 : :
167 : 1482 : status =
168 : 1482 : acpi_ut_validate_resource(walk_state, aml, &resource_index);
169 [ - + ]: 1482 : if (ACPI_FAILURE(status)) {
170 : : /*
171 : : * Exit on failure. Cannot continue because the descriptor
172 : : * length may be bogus also.
173 : : */
174 : 0 : return_ACPI_STATUS(status);
175 : : }
176 : :
177 : : /* Get the length of this descriptor */
178 : :
179 : 1482 : length = acpi_ut_get_descriptor_length(aml);
180 : :
181 : : /* Invoke the user function */
182 : :
183 [ + - ]: 1482 : if (user_function) {
184 : 1482 : status =
185 : 1482 : user_function(aml, length, offset, resource_index,
186 : : context);
187 [ - + ]: 1482 : if (ACPI_FAILURE(status)) {
188 : 0 : return_ACPI_STATUS(status);
189 : : }
190 : : }
191 : :
192 : : /* An end_tag descriptor terminates this resource template */
193 : :
194 [ + + ]: 1482 : if (acpi_ut_get_resource_type(aml) ==
195 : : ACPI_RESOURCE_NAME_END_TAG) {
196 : : /*
197 : : * There must be at least one more byte in the buffer for
198 : : * the 2nd byte of the end_tag
199 : : */
200 [ + - ]: 520 : if ((aml + 1) >= end_aml) {
201 : : return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
202 : : }
203 : :
204 : : /*
205 : : * Don't attempt to perform any validation on the 2nd byte.
206 : : * Although all known ASL compilers insert a zero for the 2nd
207 : : * byte, it can also be a checksum (as per the ACPI spec),
208 : : * and this is occasionally seen in the field. July 2017.
209 : : */
210 : :
211 : : /* Return the pointer to the end_tag if requested */
212 : :
213 [ - + ]: 520 : if (!user_function) {
214 : 0 : *context = aml;
215 : : }
216 : :
217 : : /* Normal exit */
218 : :
219 : 520 : return_ACPI_STATUS(AE_OK);
220 : : }
221 : :
222 : 962 : aml += length;
223 : 962 : offset += length;
224 : : }
225 : :
226 : : /* Did not find an end_tag descriptor */
227 : :
228 [ # # ]: 0 : if (user_function) {
229 : :
230 : : /* Insert an end_tag anyway. acpi_rs_get_list_length always leaves room */
231 : :
232 : 0 : (void)acpi_ut_validate_resource(walk_state, end_tag,
233 : : &resource_index);
234 : 0 : status =
235 : 0 : user_function(end_tag, 2, offset, resource_index, context);
236 [ # # ]: 0 : if (ACPI_FAILURE(status)) {
237 : 0 : return_ACPI_STATUS(status);
238 : : }
239 : : }
240 : :
241 : : return_ACPI_STATUS(AE_AML_NO_RESOURCE_END_TAG);
242 : : }
243 : :
244 : : /*******************************************************************************
245 : : *
246 : : * FUNCTION: acpi_ut_validate_resource
247 : : *
248 : : * PARAMETERS: walk_state - Current walk info
249 : : * aml - Pointer to the raw AML resource descriptor
250 : : * return_index - Where the resource index is returned. NULL
251 : : * if the index is not required.
252 : : *
253 : : * RETURN: Status, and optionally the Index into the global resource tables
254 : : *
255 : : * DESCRIPTION: Validate an AML resource descriptor by checking the Resource
256 : : * Type and Resource Length. Returns an index into the global
257 : : * resource information/dispatch tables for later use.
258 : : *
259 : : ******************************************************************************/
260 : :
261 : : acpi_status
262 : 2990 : acpi_ut_validate_resource(struct acpi_walk_state *walk_state,
263 : : void *aml, u8 *return_index)
264 : : {
265 : 2990 : union aml_resource *aml_resource;
266 : 2990 : u8 resource_type;
267 : 2990 : u8 resource_index;
268 : 2990 : acpi_rs_length resource_length;
269 : 2990 : acpi_rs_length minimum_resource_length;
270 : :
271 : 2990 : ACPI_FUNCTION_ENTRY();
272 : :
273 : : /*
274 : : * 1) Validate the resource_type field (Byte 0)
275 : : */
276 : 2990 : resource_type = ACPI_GET8(aml);
277 : :
278 : : /*
279 : : * Byte 0 contains the descriptor name (Resource Type)
280 : : * Examine the large/small bit in the resource header
281 : : */
282 [ + + ]: 2990 : if (resource_type & ACPI_RESOURCE_NAME_LARGE) {
283 : :
284 : : /* Verify the large resource type (name) against the max */
285 : :
286 [ - + ]: 897 : if (resource_type > ACPI_RESOURCE_NAME_LARGE_MAX) {
287 : 0 : goto invalid_resource;
288 : : }
289 : :
290 : : /*
291 : : * Large Resource Type -- bits 6:0 contain the name
292 : : * Translate range 0x80-0x8B to index range 0x10-0x1B
293 : : */
294 : 897 : resource_index = (u8) (resource_type - 0x70);
295 : : } else {
296 : : /*
297 : : * Small Resource Type -- bits 6:3 contain the name
298 : : * Shift range to index range 0x00-0x0F
299 : : */
300 : 2093 : resource_index = (u8)
301 : 2093 : ((resource_type & ACPI_RESOURCE_NAME_SMALL_MASK) >> 3);
302 : : }
303 : :
304 : : /*
305 : : * Check validity of the resource type, via acpi_gbl_resource_types.
306 : : * Zero indicates an invalid resource.
307 : : */
308 [ - + ]: 2990 : if (!acpi_gbl_resource_types[resource_index]) {
309 : 0 : goto invalid_resource;
310 : : }
311 : :
312 : : /*
313 : : * Validate the resource_length field. This ensures that the length
314 : : * is at least reasonable, and guarantees that it is non-zero.
315 : : */
316 : 2990 : resource_length = acpi_ut_get_resource_length(aml);
317 : 2990 : minimum_resource_length = acpi_gbl_resource_aml_sizes[resource_index];
318 : :
319 : : /* Validate based upon the type of resource - fixed length or variable */
320 : :
321 [ + + + - ]: 2990 : switch (acpi_gbl_resource_types[resource_index]) {
322 : 1833 : case ACPI_FIXED_LENGTH:
323 : :
324 : : /* Fixed length resource, length must match exactly */
325 : :
326 [ - + ]: 1833 : if (resource_length != minimum_resource_length) {
327 : 0 : goto bad_resource_length;
328 : : }
329 : : break;
330 : :
331 : 819 : case ACPI_VARIABLE_LENGTH:
332 : :
333 : : /* Variable length resource, length must be at least the minimum */
334 : :
335 [ - + ]: 819 : if (resource_length < minimum_resource_length) {
336 : 0 : goto bad_resource_length;
337 : : }
338 : : break;
339 : :
340 : 338 : case ACPI_SMALL_VARIABLE_LENGTH:
341 : :
342 : : /* Small variable length resource, length can be (Min) or (Min-1) */
343 : :
344 [ + - ]: 338 : if ((resource_length > minimum_resource_length) ||
345 [ - + ]: 338 : (resource_length < (minimum_resource_length - 1))) {
346 : 0 : goto bad_resource_length;
347 : : }
348 : : break;
349 : :
350 : 0 : default:
351 : :
352 : : /* Shouldn't happen (because of validation earlier), but be sure */
353 : :
354 : 0 : goto invalid_resource;
355 : : }
356 : :
357 : 2990 : aml_resource = ACPI_CAST_PTR(union aml_resource, aml);
358 [ - + ]: 2990 : if (resource_type == ACPI_RESOURCE_NAME_SERIAL_BUS) {
359 : :
360 : : /* Validate the bus_type field */
361 : :
362 [ # # ]: 0 : if ((aml_resource->common_serial_bus.type == 0) ||
363 : : (aml_resource->common_serial_bus.type >
364 : : AML_RESOURCE_MAX_SERIALBUSTYPE)) {
365 [ # # ]: 0 : if (walk_state) {
366 : 0 : ACPI_ERROR((AE_INFO,
367 : : "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X",
368 : : aml_resource->common_serial_bus.
369 : : type));
370 : : }
371 : 0 : return (AE_AML_INVALID_RESOURCE_TYPE);
372 : : }
373 : : }
374 : :
375 : : /* Optionally return the resource table index */
376 : :
377 [ + + ]: 2990 : if (return_index) {
378 : 2964 : *return_index = resource_index;
379 : : }
380 : :
381 : : return (AE_OK);
382 : :
383 : 0 : invalid_resource:
384 : :
385 [ # # ]: 0 : if (walk_state) {
386 : 0 : ACPI_ERROR((AE_INFO,
387 : : "Invalid/unsupported resource descriptor: Type 0x%2.2X",
388 : : resource_type));
389 : : }
390 : : return (AE_AML_INVALID_RESOURCE_TYPE);
391 : :
392 : 0 : bad_resource_length:
393 : :
394 [ # # ]: 0 : if (walk_state) {
395 : 0 : ACPI_ERROR((AE_INFO,
396 : : "Invalid resource descriptor length: Type "
397 : : "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X",
398 : : resource_type, resource_length,
399 : : minimum_resource_length));
400 : : }
401 : : return (AE_AML_BAD_RESOURCE_LENGTH);
402 : : }
403 : :
404 : : /*******************************************************************************
405 : : *
406 : : * FUNCTION: acpi_ut_get_resource_type
407 : : *
408 : : * PARAMETERS: aml - Pointer to the raw AML resource descriptor
409 : : *
410 : : * RETURN: The Resource Type with no extraneous bits (except the
411 : : * Large/Small descriptor bit -- this is left alone)
412 : : *
413 : : * DESCRIPTION: Extract the Resource Type/Name from the first byte of
414 : : * a resource descriptor.
415 : : *
416 : : ******************************************************************************/
417 : :
418 : 5408 : u8 acpi_ut_get_resource_type(void *aml)
419 : : {
420 : 5408 : ACPI_FUNCTION_ENTRY();
421 : :
422 : : /*
423 : : * Byte 0 contains the descriptor name (Resource Type)
424 : : * Examine the large/small bit in the resource header
425 : : */
426 [ + + ]: 5408 : if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
427 : :
428 : : /* Large Resource Type -- bits 6:0 contain the name */
429 : :
430 : : return (ACPI_GET8(aml));
431 : : } else {
432 : : /* Small Resource Type -- bits 6:3 contain the name */
433 : :
434 : 3640 : return ((u8) (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_SMALL_MASK));
435 : : }
436 : : }
437 : :
438 : : /*******************************************************************************
439 : : *
440 : : * FUNCTION: acpi_ut_get_resource_length
441 : : *
442 : : * PARAMETERS: aml - Pointer to the raw AML resource descriptor
443 : : *
444 : : * RETURN: Byte Length
445 : : *
446 : : * DESCRIPTION: Get the "Resource Length" of a raw AML descriptor. By
447 : : * definition, this does not include the size of the descriptor
448 : : * header or the length field itself.
449 : : *
450 : : ******************************************************************************/
451 : :
452 : 8762 : u16 acpi_ut_get_resource_length(void *aml)
453 : : {
454 : 8762 : acpi_rs_length resource_length;
455 : :
456 : 8762 : ACPI_FUNCTION_ENTRY();
457 : :
458 : : /*
459 : : * Byte 0 contains the descriptor name (Resource Type)
460 : : * Examine the large/small bit in the resource header
461 : : */
462 [ + + ]: 8762 : if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
463 : :
464 : : /* Large Resource type -- bytes 1-2 contain the 16-bit length */
465 : :
466 : 3029 : ACPI_MOVE_16_TO_16(&resource_length, ACPI_ADD_PTR(u8, aml, 1));
467 : :
468 : : } else {
469 : : /* Small Resource type -- bits 2:0 of byte 0 contain the length */
470 : :
471 : 5733 : resource_length = (u16) (ACPI_GET8(aml) &
472 : : ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK);
473 : : }
474 : :
475 : 8762 : return (resource_length);
476 : : }
477 : :
478 : : /*******************************************************************************
479 : : *
480 : : * FUNCTION: acpi_ut_get_resource_header_length
481 : : *
482 : : * PARAMETERS: aml - Pointer to the raw AML resource descriptor
483 : : *
484 : : * RETURN: Length of the AML header (depends on large/small descriptor)
485 : : *
486 : : * DESCRIPTION: Get the length of the header for this resource.
487 : : *
488 : : ******************************************************************************/
489 : :
490 : 3978 : u8 acpi_ut_get_resource_header_length(void *aml)
491 : : {
492 : 3978 : ACPI_FUNCTION_ENTRY();
493 : :
494 : : /* Examine the large/small bit in the resource header */
495 : :
496 [ + + ]: 1521 : if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
497 : : return (sizeof(struct aml_resource_large_header));
498 : : } else {
499 : 2613 : return (sizeof(struct aml_resource_small_header));
500 : : }
501 : : }
502 : :
503 : : /*******************************************************************************
504 : : *
505 : : * FUNCTION: acpi_ut_get_descriptor_length
506 : : *
507 : : * PARAMETERS: aml - Pointer to the raw AML resource descriptor
508 : : *
509 : : * RETURN: Byte length
510 : : *
511 : : * DESCRIPTION: Get the total byte length of a raw AML descriptor, including the
512 : : * length of the descriptor header and the length field itself.
513 : : * Used to walk descriptor lists.
514 : : *
515 : : ******************************************************************************/
516 : :
517 : 2457 : u32 acpi_ut_get_descriptor_length(void *aml)
518 : : {
519 : 2457 : ACPI_FUNCTION_ENTRY();
520 : :
521 : : /*
522 : : * Get the Resource Length (does not include header length) and add
523 : : * the header length (depends on if this is a small or large resource)
524 : : */
525 [ + + ]: 2457 : return (acpi_ut_get_resource_length(aml) +
526 : 2457 : acpi_ut_get_resource_header_length(aml));
527 : : }
528 : :
529 : : /*******************************************************************************
530 : : *
531 : : * FUNCTION: acpi_ut_get_resource_end_tag
532 : : *
533 : : * PARAMETERS: obj_desc - The resource template buffer object
534 : : * end_tag - Where the pointer to the end_tag is returned
535 : : *
536 : : * RETURN: Status, pointer to the end tag
537 : : *
538 : : * DESCRIPTION: Find the end_tag resource descriptor in an AML resource template
539 : : * Note: allows a buffer length of zero.
540 : : *
541 : : ******************************************************************************/
542 : :
543 : : acpi_status
544 : 0 : acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag)
545 : : {
546 : 0 : acpi_status status;
547 : :
548 : 0 : ACPI_FUNCTION_TRACE(ut_get_resource_end_tag);
549 : :
550 : : /* Allow a buffer length of zero */
551 : :
552 [ # # ]: 0 : if (!obj_desc->buffer.length) {
553 : 0 : *end_tag = obj_desc->buffer.pointer;
554 : 0 : return_ACPI_STATUS(AE_OK);
555 : : }
556 : :
557 : : /* Validate the template and get a pointer to the end_tag */
558 : :
559 : 0 : status = acpi_ut_walk_aml_resources(NULL, obj_desc->buffer.pointer,
560 : : obj_desc->buffer.length, NULL,
561 : : (void **)end_tag);
562 : :
563 : 0 : return_ACPI_STATUS(status);
564 : : }
|