brintos

brintos / linux-shallow public Read only

0
0
Text · 16.3 KiB · cff7901 Raw
573 lines · c
1// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.02/*******************************************************************************3 *4 * Module Name: utresrc - Resource management utilities5 *6 ******************************************************************************/7 8#include <acpi/acpi.h>9#include "accommon.h"10#include "acresrc.h"11 12#define _COMPONENT          ACPI_UTILITIES13ACPI_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 */19const 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 64const 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, variable75 * lengths must meet the minimum required length, etc.76 * Zero indicates a reserved (and therefore invalid) resource type.77 */78static 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_resources125 *126 * PARAMETERS:  walk_state          - Current walk info127 * PARAMETERS:  aml                 - Pointer to the raw AML resource template128 *              aml_length          - Length of the entire template129 *              user_function       - Called once for each descriptor found. If130 *                                    NULL, a pointer to the end_tag is returned131 *              context             - Passed to user_function132 *133 * RETURN:      Status134 *135 * DESCRIPTION: Walk a raw AML resource list(buffer). User function called136 *              once for each resource found.137 *138 ******************************************************************************/139 140acpi_status141acpi_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 descriptor176			 * 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 for202			 * the 2nd byte of the end_tag203			 */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 2nd211			 * 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_resource251 *252 * PARAMETERS:  walk_state          - Current walk info253 *              aml                 - Pointer to the raw AML resource descriptor254 *              return_index        - Where the resource index is returned. NULL255 *                                    if the index is not required.256 *257 * RETURN:      Status, and optionally the Index into the global resource tables258 *259 * DESCRIPTION: Validate an AML resource descriptor by checking the Resource260 *              Type and Resource Length. Returns an index into the global261 *              resource information/dispatch tables for later use.262 *263 ******************************************************************************/264 265acpi_status266acpi_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 header285	 */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 name296		 * Translate range 0x80-0x8B to index range 0x10-0x1B297		 */298		resource_index = (u8) (resource_type - 0x70);299	} else {300		/*301		 * Small Resource Type -- bits 6:3 contain the name302		 * Shift range to index range 0x00-0x0F303		 */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 length318	 * 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 391invalid_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 400bad_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_type415 *416 * PARAMETERS:  aml             - Pointer to the raw AML resource descriptor417 *418 * RETURN:      The Resource Type with no extraneous bits (except the419 *              Large/Small descriptor bit -- this is left alone)420 *421 * DESCRIPTION: Extract the Resource Type/Name from the first byte of422 *              a resource descriptor.423 *424 ******************************************************************************/425 426u8 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 header433	 */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_length449 *450 * PARAMETERS:  aml             - Pointer to the raw AML resource descriptor451 *452 * RETURN:      Byte Length453 *454 * DESCRIPTION: Get the "Resource Length" of a raw AML descriptor. By455 *              definition, this does not include the size of the descriptor456 *              header or the length field itself.457 *458 ******************************************************************************/459 460u16 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 header469	 */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_length489 *490 * PARAMETERS:  aml             - Pointer to the raw AML resource descriptor491 *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 498u8 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_length514 *515 * PARAMETERS:  aml             - Pointer to the raw AML resource descriptor516 *517 * RETURN:      Byte length518 *519 * DESCRIPTION: Get the total byte length of a raw AML descriptor, including the520 *              length of the descriptor header and the length field itself.521 *              Used to walk descriptor lists.522 *523 ******************************************************************************/524 525u32 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 add531	 * 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_tag540 *541 * PARAMETERS:  obj_desc        - The resource template buffer object542 *              end_tag         - Where the pointer to the end_tag is returned543 *544 * RETURN:      Status, pointer to the end tag545 *546 * DESCRIPTION: Find the end_tag resource descriptor in an AML resource template547 *              Note: allows a buffer length of zero.548 *549 ******************************************************************************/550 551acpi_status552acpi_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