• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /******************************************************************************
3  *
4  * Module Name: exnames - interpreter/scanner name load/execute
5  *
6  * Copyright (C) 2000 - 2023, Intel Corp.
7  *
8  *****************************************************************************/
9 
10 #include <acpi/acpi.h>
11 #include "accommon.h"
12 #include "acinterp.h"
13 #include "amlcode.h"
14 
15 #define _COMPONENT          ACPI_EXECUTER
16 ACPI_MODULE_NAME("exnames")
17 
18 /* Local prototypes */
19 static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs);
20 
21 static acpi_status acpi_ex_name_segment(u8 **in_aml_address, char *name_string);
22 
23 /*******************************************************************************
24  *
25  * FUNCTION:    acpi_ex_allocate_name_string
26  *
27  * PARAMETERS:  prefix_count        - Count of parent levels. Special cases:
28  *                                    (-1)==root,  0==none
29  *              num_name_segs       - count of 4-character name segments
30  *
31  * RETURN:      A pointer to the allocated string segment. This segment must
32  *              be deleted by the caller.
33  *
34  * DESCRIPTION: Allocate a buffer for a name string. Ensure allocated name
35  *              string is long enough, and set up prefix if any.
36  *
37  ******************************************************************************/
38 
acpi_ex_allocate_name_string(u32 prefix_count,u32 num_name_segs)39 static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs)
40 {
41 	char *temp_ptr;
42 	char *name_string;
43 	u32 size_needed;
44 
45 	ACPI_FUNCTION_TRACE(ex_allocate_name_string);
46 
47 	/*
48 	 * Allow room for all \ and ^ prefixes, all segments and a multi_name_prefix.
49 	 * Also, one byte for the null terminator.
50 	 * This may actually be somewhat longer than needed.
51 	 */
52 	if (prefix_count == ACPI_UINT32_MAX) {
53 
54 		/* Special case for root */
55 
56 		size_needed = 1 + (ACPI_NAMESEG_SIZE * num_name_segs) + 2 + 1;
57 	} else {
58 		size_needed =
59 		    prefix_count + (ACPI_NAMESEG_SIZE * num_name_segs) + 2 + 1;
60 	}
61 
62 	/*
63 	 * Allocate a buffer for the name.
64 	 * This buffer must be deleted by the caller!
65 	 */
66 	name_string = ACPI_ALLOCATE(size_needed);
67 	if (!name_string) {
68 		ACPI_ERROR((AE_INFO,
69 			    "Could not allocate size %u", size_needed));
70 		return_PTR(NULL);
71 	}
72 
73 	temp_ptr = name_string;
74 
75 	/* Set up Root or Parent prefixes if needed */
76 
77 	if (prefix_count == ACPI_UINT32_MAX) {
78 		*temp_ptr++ = AML_ROOT_PREFIX;
79 	} else {
80 		while (prefix_count--) {
81 			*temp_ptr++ = AML_PARENT_PREFIX;
82 		}
83 	}
84 
85 	/* Set up Dual or Multi prefixes if needed */
86 
87 	if (num_name_segs > 2) {
88 
89 		/* Set up multi prefixes   */
90 
91 		*temp_ptr++ = AML_MULTI_NAME_PREFIX;
92 		*temp_ptr++ = (char)num_name_segs;
93 	} else if (2 == num_name_segs) {
94 
95 		/* Set up dual prefixes */
96 
97 		*temp_ptr++ = AML_DUAL_NAME_PREFIX;
98 	}
99 
100 	/*
101 	 * Terminate string following prefixes. acpi_ex_name_segment() will
102 	 * append the segment(s)
103 	 */
104 	*temp_ptr = 0;
105 
106 	return_PTR(name_string);
107 }
108 
109 /*******************************************************************************
110  *
111  * FUNCTION:    acpi_ex_name_segment
112  *
113  * PARAMETERS:  in_aml_address  - Pointer to the name in the AML code
114  *              name_string     - Where to return the name. The name is appended
115  *                                to any existing string to form a namepath
116  *
117  * RETURN:      Status
118  *
119  * DESCRIPTION: Extract an ACPI name (4 bytes) from the AML byte stream
120  *
121  ******************************************************************************/
122 
acpi_ex_name_segment(u8 ** in_aml_address,char * name_string)123 static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string)
124 {
125 	char *aml_address = (void *)*in_aml_address;
126 	acpi_status status = AE_OK;
127 	u32 index;
128 	char char_buf[5];
129 
130 	ACPI_FUNCTION_TRACE(ex_name_segment);
131 
132 	/*
133 	 * If first character is a digit, then we know that we aren't looking
134 	 * at a valid name segment
135 	 */
136 	char_buf[0] = *aml_address;
137 
138 	if ('0' <= char_buf[0] && char_buf[0] <= '9') {
139 		ACPI_ERROR((AE_INFO, "Invalid leading digit: %c", char_buf[0]));
140 		return_ACPI_STATUS(AE_CTRL_PENDING);
141 	}
142 
143 	for (index = 0;
144 	     (index < ACPI_NAMESEG_SIZE)
145 	     && (acpi_ut_valid_name_char(*aml_address, 0)); index++) {
146 		char_buf[index] = *aml_address++;
147 	}
148 
149 	/* Valid name segment  */
150 
151 	if (index == 4) {
152 
153 		/* Found 4 valid characters */
154 
155 		char_buf[4] = '\0';
156 
157 		if (name_string) {
158 			ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
159 					  "Appending NameSeg %s\n", char_buf));
160 			strcat(name_string, char_buf);
161 		} else {
162 			ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
163 					  "No Name string - %s\n", char_buf));
164 		}
165 	} else if (index == 0) {
166 		/*
167 		 * First character was not a valid name character,
168 		 * so we are looking at something other than a name.
169 		 */
170 		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
171 				  "Leading character is not alpha: %02Xh (not a name)\n",
172 				  char_buf[0]));
173 		status = AE_CTRL_PENDING;
174 	} else {
175 		/*
176 		 * Segment started with one or more valid characters, but fewer than
177 		 * the required 4
178 		 */
179 		status = AE_AML_BAD_NAME;
180 		ACPI_ERROR((AE_INFO,
181 			    "Bad character 0x%02x in name, at %p",
182 			    *aml_address, aml_address));
183 	}
184 
185 	*in_aml_address = ACPI_CAST_PTR(u8, aml_address);
186 	return_ACPI_STATUS(status);
187 }
188 
189 /*******************************************************************************
190  *
191  * FUNCTION:    acpi_ex_get_name_string
192  *
193  * PARAMETERS:  data_type           - Object type to be associated with this
194  *                                    name
195  *              in_aml_address      - Pointer to the namestring in the AML code
196  *              out_name_string     - Where the namestring is returned
197  *              out_name_length     - Length of the returned string
198  *
199  * RETURN:      Status, namestring and length
200  *
201  * DESCRIPTION: Extract a full namepath from the AML byte stream,
202  *              including any prefixes.
203  *
204  ******************************************************************************/
205 
206 acpi_status
acpi_ex_get_name_string(acpi_object_type data_type,u8 * in_aml_address,char ** out_name_string,u32 * out_name_length)207 acpi_ex_get_name_string(acpi_object_type data_type,
208 			u8 * in_aml_address,
209 			char **out_name_string, u32 * out_name_length)
210 {
211 	acpi_status status = AE_OK;
212 	u8 *aml_address = in_aml_address;
213 	char *name_string = NULL;
214 	u32 num_segments;
215 	u32 prefix_count = 0;
216 	u8 has_prefix = FALSE;
217 
218 	ACPI_FUNCTION_TRACE_PTR(ex_get_name_string, aml_address);
219 
220 	if (ACPI_TYPE_LOCAL_REGION_FIELD == data_type ||
221 	    ACPI_TYPE_LOCAL_BANK_FIELD == data_type ||
222 	    ACPI_TYPE_LOCAL_INDEX_FIELD == data_type) {
223 
224 		/* Disallow prefixes for types associated with field_unit names */
225 
226 		name_string = acpi_ex_allocate_name_string(0, 1);
227 		if (!name_string) {
228 			status = AE_NO_MEMORY;
229 		} else {
230 			status =
231 			    acpi_ex_name_segment(&aml_address, name_string);
232 		}
233 	} else {
234 		/*
235 		 * data_type is not a field name.
236 		 * Examine first character of name for root or parent prefix operators
237 		 */
238 		switch (*aml_address) {
239 		case AML_ROOT_PREFIX:
240 
241 			ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
242 					  "RootPrefix(\\) at %p\n",
243 					  aml_address));
244 
245 			/*
246 			 * Remember that we have a root_prefix --
247 			 * see comment in acpi_ex_allocate_name_string()
248 			 */
249 			aml_address++;
250 			prefix_count = ACPI_UINT32_MAX;
251 			has_prefix = TRUE;
252 			break;
253 
254 		case AML_PARENT_PREFIX:
255 
256 			/* Increment past possibly multiple parent prefixes */
257 
258 			do {
259 				ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
260 						  "ParentPrefix (^) at %p\n",
261 						  aml_address));
262 
263 				aml_address++;
264 				prefix_count++;
265 
266 			} while (*aml_address == AML_PARENT_PREFIX);
267 
268 			has_prefix = TRUE;
269 			break;
270 
271 		default:
272 
273 			/* Not a prefix character */
274 
275 			break;
276 		}
277 
278 		/* Examine first character of name for name segment prefix operator */
279 
280 		switch (*aml_address) {
281 		case AML_DUAL_NAME_PREFIX:
282 
283 			ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
284 					  "DualNamePrefix at %p\n",
285 					  aml_address));
286 
287 			aml_address++;
288 			name_string =
289 			    acpi_ex_allocate_name_string(prefix_count, 2);
290 			if (!name_string) {
291 				status = AE_NO_MEMORY;
292 				break;
293 			}
294 
295 			/* Indicate that we processed a prefix */
296 
297 			has_prefix = TRUE;
298 
299 			status =
300 			    acpi_ex_name_segment(&aml_address, name_string);
301 			if (ACPI_SUCCESS(status)) {
302 				status =
303 				    acpi_ex_name_segment(&aml_address,
304 							 name_string);
305 			}
306 			break;
307 
308 		case AML_MULTI_NAME_PREFIX:
309 
310 			ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
311 					  "MultiNamePrefix at %p\n",
312 					  aml_address));
313 
314 			/* Fetch count of segments remaining in name path */
315 
316 			aml_address++;
317 			num_segments = *aml_address;
318 
319 			name_string =
320 			    acpi_ex_allocate_name_string(prefix_count,
321 							 num_segments);
322 			if (!name_string) {
323 				status = AE_NO_MEMORY;
324 				break;
325 			}
326 
327 			/* Indicate that we processed a prefix */
328 
329 			aml_address++;
330 			has_prefix = TRUE;
331 
332 			while (num_segments &&
333 			       (status =
334 				acpi_ex_name_segment(&aml_address,
335 						     name_string)) == AE_OK) {
336 				num_segments--;
337 			}
338 
339 			break;
340 
341 		case 0:
342 
343 			/* null_name valid as of 8-12-98 ASL/AML Grammar Update */
344 
345 			if (prefix_count == ACPI_UINT32_MAX) {
346 				ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
347 						  "NameSeg is \"\\\" followed by NULL\n"));
348 			}
349 
350 			/* Consume the NULL byte */
351 
352 			aml_address++;
353 			name_string =
354 			    acpi_ex_allocate_name_string(prefix_count, 0);
355 			if (!name_string) {
356 				status = AE_NO_MEMORY;
357 				break;
358 			}
359 
360 			break;
361 
362 		default:
363 
364 			/* Name segment string */
365 
366 			name_string =
367 			    acpi_ex_allocate_name_string(prefix_count, 1);
368 			if (!name_string) {
369 				status = AE_NO_MEMORY;
370 				break;
371 			}
372 
373 			status =
374 			    acpi_ex_name_segment(&aml_address, name_string);
375 			break;
376 		}
377 	}
378 
379 	if (AE_CTRL_PENDING == status && has_prefix) {
380 
381 		/* Ran out of segments after processing a prefix */
382 
383 		ACPI_ERROR((AE_INFO, "Malformed Name at %p", name_string));
384 		status = AE_AML_BAD_NAME;
385 	}
386 
387 	if (ACPI_FAILURE(status)) {
388 		if (name_string) {
389 			ACPI_FREE(name_string);
390 		}
391 		return_ACPI_STATUS(status);
392 	}
393 
394 	*out_name_string = name_string;
395 	*out_name_length = (u32) (aml_address - in_aml_address);
396 
397 	return_ACPI_STATUS(status);
398 }
399