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