• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
acpi_ut_walk_aml_resources(struct acpi_walk_state * walk_state,u8 * aml,acpi_size aml_length,acpi_walk_aml_callback user_function,void ** context)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
acpi_ut_validate_resource(struct acpi_walk_state * walk_state,void * aml,u8 * return_index)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 		/* Avoid undefined behavior: member access within misaligned address */
365 
366 		struct aml_resource_common_serialbus common_serial_bus;
367 		memcpy(&common_serial_bus, aml_resource,
368 		       sizeof(common_serial_bus));
369 
370 		/* Validate the bus_type field */
371 
372 		if ((common_serial_bus.type == 0) ||
373 		    (common_serial_bus.type > AML_RESOURCE_MAX_SERIALBUSTYPE)) {
374 			if (walk_state) {
375 				ACPI_ERROR((AE_INFO,
376 					    "Invalid/unsupported SerialBus resource descriptor: BusType 0x%2.2X",
377 					    common_serial_bus.type));
378 			}
379 			return (AE_AML_INVALID_RESOURCE_TYPE);
380 		}
381 	}
382 
383 	/* Optionally return the resource table index */
384 
385 	if (return_index) {
386 		*return_index = resource_index;
387 	}
388 
389 	return (AE_OK);
390 
391 invalid_resource:
392 
393 	if (walk_state) {
394 		ACPI_ERROR((AE_INFO,
395 			    "Invalid/unsupported resource descriptor: Type 0x%2.2X",
396 			    resource_type));
397 	}
398 	return (AE_AML_INVALID_RESOURCE_TYPE);
399 
400 bad_resource_length:
401 
402 	if (walk_state) {
403 		ACPI_ERROR((AE_INFO,
404 			    "Invalid resource descriptor length: Type "
405 			    "0x%2.2X, Length 0x%4.4X, MinLength 0x%4.4X",
406 			    resource_type, resource_length,
407 			    minimum_resource_length));
408 	}
409 	return (AE_AML_BAD_RESOURCE_LENGTH);
410 }
411 
412 /*******************************************************************************
413  *
414  * FUNCTION:    acpi_ut_get_resource_type
415  *
416  * PARAMETERS:  aml             - Pointer to the raw AML resource descriptor
417  *
418  * RETURN:      The Resource Type with no extraneous bits (except the
419  *              Large/Small descriptor bit -- this is left alone)
420  *
421  * DESCRIPTION: Extract the Resource Type/Name from the first byte of
422  *              a resource descriptor.
423  *
424  ******************************************************************************/
425 
acpi_ut_get_resource_type(void * aml)426 u8 acpi_ut_get_resource_type(void *aml)
427 {
428 	ACPI_FUNCTION_ENTRY();
429 
430 	/*
431 	 * Byte 0 contains the descriptor name (Resource Type)
432 	 * Examine the large/small bit in the resource header
433 	 */
434 	if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
435 
436 		/* Large Resource Type -- bits 6:0 contain the name */
437 
438 		return (ACPI_GET8(aml));
439 	} else {
440 		/* Small Resource Type -- bits 6:3 contain the name */
441 
442 		return ((u8) (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_SMALL_MASK));
443 	}
444 }
445 
446 /*******************************************************************************
447  *
448  * FUNCTION:    acpi_ut_get_resource_length
449  *
450  * PARAMETERS:  aml             - Pointer to the raw AML resource descriptor
451  *
452  * RETURN:      Byte Length
453  *
454  * DESCRIPTION: Get the "Resource Length" of a raw AML descriptor. By
455  *              definition, this does not include the size of the descriptor
456  *              header or the length field itself.
457  *
458  ******************************************************************************/
459 
acpi_ut_get_resource_length(void * aml)460 u16 acpi_ut_get_resource_length(void *aml)
461 {
462 	acpi_rs_length resource_length;
463 
464 	ACPI_FUNCTION_ENTRY();
465 
466 	/*
467 	 * Byte 0 contains the descriptor name (Resource Type)
468 	 * Examine the large/small bit in the resource header
469 	 */
470 	if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
471 
472 		/* Large Resource type -- bytes 1-2 contain the 16-bit length */
473 
474 		ACPI_MOVE_16_TO_16(&resource_length, ACPI_ADD_PTR(u8, aml, 1));
475 
476 	} else {
477 		/* Small Resource type -- bits 2:0 of byte 0 contain the length */
478 
479 		resource_length = (u16) (ACPI_GET8(aml) &
480 					 ACPI_RESOURCE_NAME_SMALL_LENGTH_MASK);
481 	}
482 
483 	return (resource_length);
484 }
485 
486 /*******************************************************************************
487  *
488  * FUNCTION:    acpi_ut_get_resource_header_length
489  *
490  * PARAMETERS:  aml             - Pointer to the raw AML resource descriptor
491  *
492  * RETURN:      Length of the AML header (depends on large/small descriptor)
493  *
494  * DESCRIPTION: Get the length of the header for this resource.
495  *
496  ******************************************************************************/
497 
acpi_ut_get_resource_header_length(void * aml)498 u8 acpi_ut_get_resource_header_length(void *aml)
499 {
500 	ACPI_FUNCTION_ENTRY();
501 
502 	/* Examine the large/small bit in the resource header */
503 
504 	if (ACPI_GET8(aml) & ACPI_RESOURCE_NAME_LARGE) {
505 		return (sizeof(struct aml_resource_large_header));
506 	} else {
507 		return (sizeof(struct aml_resource_small_header));
508 	}
509 }
510 
511 /*******************************************************************************
512  *
513  * FUNCTION:    acpi_ut_get_descriptor_length
514  *
515  * PARAMETERS:  aml             - Pointer to the raw AML resource descriptor
516  *
517  * RETURN:      Byte length
518  *
519  * DESCRIPTION: Get the total byte length of a raw AML descriptor, including the
520  *              length of the descriptor header and the length field itself.
521  *              Used to walk descriptor lists.
522  *
523  ******************************************************************************/
524 
acpi_ut_get_descriptor_length(void * aml)525 u32 acpi_ut_get_descriptor_length(void *aml)
526 {
527 	ACPI_FUNCTION_ENTRY();
528 
529 	/*
530 	 * Get the Resource Length (does not include header length) and add
531 	 * the header length (depends on if this is a small or large resource)
532 	 */
533 	return (acpi_ut_get_resource_length(aml) +
534 		acpi_ut_get_resource_header_length(aml));
535 }
536 
537 /*******************************************************************************
538  *
539  * FUNCTION:    acpi_ut_get_resource_end_tag
540  *
541  * PARAMETERS:  obj_desc        - The resource template buffer object
542  *              end_tag         - Where the pointer to the end_tag is returned
543  *
544  * RETURN:      Status, pointer to the end tag
545  *
546  * DESCRIPTION: Find the end_tag resource descriptor in an AML resource template
547  *              Note: allows a buffer length of zero.
548  *
549  ******************************************************************************/
550 
551 acpi_status
acpi_ut_get_resource_end_tag(union acpi_operand_object * obj_desc,u8 ** end_tag)552 acpi_ut_get_resource_end_tag(union acpi_operand_object *obj_desc, u8 **end_tag)
553 {
554 	acpi_status status;
555 
556 	ACPI_FUNCTION_TRACE(ut_get_resource_end_tag);
557 
558 	/* Allow a buffer length of zero */
559 
560 	if (!obj_desc->buffer.length) {
561 		*end_tag = obj_desc->buffer.pointer;
562 		return_ACPI_STATUS(AE_OK);
563 	}
564 
565 	/* Validate the template and get a pointer to the end_tag */
566 
567 	status = acpi_ut_walk_aml_resources(NULL, obj_desc->buffer.pointer,
568 					    obj_desc->buffer.length, NULL,
569 					    (void **)end_tag);
570 
571 	return_ACPI_STATUS(status);
572 }
573