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