]>
Commit | Line | Data |
---|---|---|
95857638 | 1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
1da177e4 LT |
2 | /****************************************************************************** |
3 | * | |
4 | * Module Name: exnames - interpreter/scanner name load/execute | |
5 | * | |
800ba7c5 | 6 | * Copyright (C) 2000 - 2020, Intel Corp. |
1da177e4 | 7 | * |
95857638 | 8 | *****************************************************************************/ |
1da177e4 | 9 | |
1da177e4 | 10 | #include <acpi/acpi.h> |
e2f7a777 LB |
11 | #include "accommon.h" |
12 | #include "acinterp.h" | |
13 | #include "amlcode.h" | |
1da177e4 LT |
14 | |
15 | #define _COMPONENT ACPI_EXECUTER | |
4be44fcd | 16 | ACPI_MODULE_NAME("exnames") |
1da177e4 | 17 | |
44f6c012 | 18 | /* Local prototypes */ |
4be44fcd | 19 | static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs); |
1da177e4 | 20 | |
1f86e8c1 | 21 | static acpi_status acpi_ex_name_segment(u8 **in_aml_address, char *name_string); |
1da177e4 LT |
22 | |
23 | /******************************************************************************* | |
24 | * | |
25 | * FUNCTION: acpi_ex_allocate_name_string | |
26 | * | |
27 | * PARAMETERS: prefix_count - Count of parent levels. Special cases: | |
44f6c012 | 28 | * (-1)==root, 0==none |
1da177e4 LT |
29 | * num_name_segs - count of 4-character name segments |
30 | * | |
73a3090a | 31 | * RETURN: A pointer to the allocated string segment. This segment must |
1da177e4 LT |
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 | ||
4be44fcd | 39 | static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs) |
1da177e4 | 40 | { |
4be44fcd LB |
41 | char *temp_ptr; |
42 | char *name_string; | |
43 | u32 size_needed; | |
1da177e4 | 44 | |
b229cf92 | 45 | ACPI_FUNCTION_TRACE(ex_allocate_name_string); |
1da177e4 LT |
46 | |
47 | /* | |
44f6c012 | 48 | * Allow room for all \ and ^ prefixes, all segments and a multi_name_prefix. |
1da177e4 LT |
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) { | |
52fc0b02 | 53 | |
1da177e4 LT |
54 | /* Special case for root */ |
55 | ||
32786755 | 56 | size_needed = 1 + (ACPI_NAMESEG_SIZE * num_name_segs) + 2 + 1; |
4be44fcd LB |
57 | } else { |
58 | size_needed = | |
32786755 | 59 | prefix_count + (ACPI_NAMESEG_SIZE * num_name_segs) + 2 + 1; |
1da177e4 LT |
60 | } |
61 | ||
62 | /* | |
63 | * Allocate a buffer for the name. | |
64 | * This buffer must be deleted by the caller! | |
65 | */ | |
8313524a | 66 | name_string = ACPI_ALLOCATE(size_needed); |
1da177e4 | 67 | if (!name_string) { |
b8e4d893 | 68 | ACPI_ERROR((AE_INFO, |
f6a22b0b | 69 | "Could not allocate size %u", size_needed)); |
4be44fcd | 70 | return_PTR(NULL); |
1da177e4 LT |
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; | |
4be44fcd | 79 | } else { |
1da177e4 LT |
80 | while (prefix_count--) { |
81 | *temp_ptr++ = AML_PARENT_PREFIX; | |
82 | } | |
83 | } | |
84 | ||
1da177e4 LT |
85 | /* Set up Dual or Multi prefixes if needed */ |
86 | ||
87 | if (num_name_segs > 2) { | |
52fc0b02 | 88 | |
1da177e4 LT |
89 | /* Set up multi prefixes */ |
90 | ||
9ff5a21a | 91 | *temp_ptr++ = AML_MULTI_NAME_PREFIX; |
4be44fcd LB |
92 | *temp_ptr++ = (char)num_name_segs; |
93 | } else if (2 == num_name_segs) { | |
52fc0b02 | 94 | |
1da177e4 LT |
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 | ||
4be44fcd | 106 | return_PTR(name_string); |
1da177e4 LT |
107 | } |
108 | ||
109 | /******************************************************************************* | |
110 | * | |
111 | * FUNCTION: acpi_ex_name_segment | |
112 | * | |
44f6c012 RM |
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 | |
1da177e4 LT |
116 | * |
117 | * RETURN: Status | |
118 | * | |
44f6c012 | 119 | * DESCRIPTION: Extract an ACPI name (4 bytes) from the AML byte stream |
1da177e4 LT |
120 | * |
121 | ******************************************************************************/ | |
122 | ||
4be44fcd | 123 | static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string) |
1da177e4 | 124 | { |
4be44fcd LB |
125 | char *aml_address = (void *)*in_aml_address; |
126 | acpi_status status = AE_OK; | |
127 | u32 index; | |
128 | char char_buf[5]; | |
1da177e4 | 129 | |
b229cf92 | 130 | ACPI_FUNCTION_TRACE(ex_name_segment); |
1da177e4 LT |
131 | |
132 | /* | |
1fad8738 BM |
133 | * If first character is a digit, then we know that we aren't looking |
134 | * at a valid name segment | |
1da177e4 LT |
135 | */ |
136 | char_buf[0] = *aml_address; | |
137 | ||
138 | if ('0' <= char_buf[0] && char_buf[0] <= '9') { | |
b8e4d893 | 139 | ACPI_ERROR((AE_INFO, "Invalid leading digit: %c", char_buf[0])); |
4be44fcd | 140 | return_ACPI_STATUS(AE_CTRL_PENDING); |
1da177e4 LT |
141 | } |
142 | ||
1f86e8c1 | 143 | for (index = 0; |
32786755 | 144 | (index < ACPI_NAMESEG_SIZE) |
6a0df32c | 145 | && (acpi_ut_valid_name_char(*aml_address, 0)); index++) { |
1da177e4 | 146 | char_buf[index] = *aml_address++; |
1da177e4 LT |
147 | } |
148 | ||
1da177e4 LT |
149 | /* Valid name segment */ |
150 | ||
151 | if (index == 4) { | |
52fc0b02 | 152 | |
1da177e4 LT |
153 | /* Found 4 valid characters */ |
154 | ||
155 | char_buf[4] = '\0'; | |
156 | ||
157 | if (name_string) { | |
4be44fcd | 158 | ACPI_DEBUG_PRINT((ACPI_DB_NAMES, |
1ef63231 BM |
159 | "Appending NameSeg %s\n", char_buf)); |
160 | strcat(name_string, char_buf); | |
4be44fcd LB |
161 | } else { |
162 | ACPI_DEBUG_PRINT((ACPI_DB_NAMES, | |
50eca3eb | 163 | "No Name string - %s\n", char_buf)); |
1da177e4 | 164 | } |
4be44fcd | 165 | } else if (index == 0) { |
1da177e4 LT |
166 | /* |
167 | * First character was not a valid name character, | |
168 | * so we are looking at something other than a name. | |
169 | */ | |
4be44fcd LB |
170 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, |
171 | "Leading character is not alpha: %02Xh (not a name)\n", | |
172 | char_buf[0])); | |
1da177e4 | 173 | status = AE_CTRL_PENDING; |
4be44fcd | 174 | } else { |
44f6c012 RM |
175 | /* |
176 | * Segment started with one or more valid characters, but fewer than | |
177 | * the required 4 | |
178 | */ | |
1da177e4 | 179 | status = AE_AML_BAD_NAME; |
b8e4d893 | 180 | ACPI_ERROR((AE_INFO, |
f6a22b0b | 181 | "Bad character 0x%02x in name, at %p", |
b8e4d893 | 182 | *aml_address, aml_address)); |
1da177e4 LT |
183 | } |
184 | ||
c51a4de8 | 185 | *in_aml_address = ACPI_CAST_PTR(u8, aml_address); |
4be44fcd | 186 | return_ACPI_STATUS(status); |
1da177e4 LT |
187 | } |
188 | ||
1da177e4 LT |
189 | /******************************************************************************* |
190 | * | |
191 | * FUNCTION: acpi_ex_get_name_string | |
192 | * | |
44f6c012 RM |
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 | |
1da177e4 | 198 | * |
44f6c012 | 199 | * RETURN: Status, namestring and length |
1da177e4 | 200 | * |
44f6c012 RM |
201 | * DESCRIPTION: Extract a full namepath from the AML byte stream, |
202 | * including any prefixes. | |
1da177e4 LT |
203 | * |
204 | ******************************************************************************/ | |
205 | ||
206 | acpi_status | |
4be44fcd LB |
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) | |
1da177e4 | 210 | { |
4be44fcd LB |
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 | ||
b229cf92 | 218 | ACPI_FUNCTION_TRACE_PTR(ex_get_name_string, aml_address); |
4be44fcd LB |
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) { | |
52fc0b02 | 223 | |
1da177e4 LT |
224 | /* Disallow prefixes for types associated with field_unit names */ |
225 | ||
4be44fcd | 226 | name_string = acpi_ex_allocate_name_string(0, 1); |
1da177e4 LT |
227 | if (!name_string) { |
228 | status = AE_NO_MEMORY; | |
4be44fcd LB |
229 | } else { |
230 | status = | |
231 | acpi_ex_name_segment(&aml_address, name_string); | |
1da177e4 | 232 | } |
4be44fcd | 233 | } else { |
1da177e4 LT |
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 | ||
4be44fcd | 241 | ACPI_DEBUG_PRINT((ACPI_DB_LOAD, |
b229cf92 | 242 | "RootPrefix(\\) at %p\n", |
4be44fcd | 243 | aml_address)); |
1da177e4 LT |
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 | ||
1da177e4 LT |
254 | case AML_PARENT_PREFIX: |
255 | ||
256 | /* Increment past possibly multiple parent prefixes */ | |
257 | ||
258 | do { | |
4be44fcd | 259 | ACPI_DEBUG_PRINT((ACPI_DB_LOAD, |
b229cf92 | 260 | "ParentPrefix (^) at %p\n", |
4be44fcd | 261 | aml_address)); |
1da177e4 LT |
262 | |
263 | aml_address++; | |
264 | prefix_count++; | |
265 | ||
266 | } while (*aml_address == AML_PARENT_PREFIX); | |
267 | ||
268 | has_prefix = TRUE; | |
269 | break; | |
270 | ||
1da177e4 LT |
271 | default: |
272 | ||
273 | /* Not a prefix character */ | |
274 | ||
275 | break; | |
276 | } | |
277 | ||
1da177e4 LT |
278 | /* Examine first character of name for name segment prefix operator */ |
279 | ||
280 | switch (*aml_address) { | |
281 | case AML_DUAL_NAME_PREFIX: | |
282 | ||
4be44fcd | 283 | ACPI_DEBUG_PRINT((ACPI_DB_LOAD, |
b229cf92 | 284 | "DualNamePrefix at %p\n", |
4be44fcd | 285 | aml_address)); |
1da177e4 LT |
286 | |
287 | aml_address++; | |
4be44fcd LB |
288 | name_string = |
289 | acpi_ex_allocate_name_string(prefix_count, 2); | |
1da177e4 LT |
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 | ||
4be44fcd LB |
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); | |
1da177e4 LT |
305 | } |
306 | break; | |
307 | ||
9ff5a21a | 308 | case AML_MULTI_NAME_PREFIX: |
1da177e4 | 309 | |
4be44fcd | 310 | ACPI_DEBUG_PRINT((ACPI_DB_LOAD, |
b229cf92 | 311 | "MultiNamePrefix at %p\n", |
4be44fcd | 312 | aml_address)); |
1da177e4 LT |
313 | |
314 | /* Fetch count of segments remaining in name path */ | |
315 | ||
316 | aml_address++; | |
317 | num_segments = *aml_address; | |
318 | ||
4be44fcd LB |
319 | name_string = |
320 | acpi_ex_allocate_name_string(prefix_count, | |
321 | num_segments); | |
1da177e4 LT |
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 && | |
4be44fcd LB |
333 | (status = |
334 | acpi_ex_name_segment(&aml_address, | |
335 | name_string)) == AE_OK) { | |
1da177e4 LT |
336 | num_segments--; |
337 | } | |
338 | ||
339 | break; | |
340 | ||
1da177e4 LT |
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) { | |
4be44fcd | 346 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
b229cf92 | 347 | "NameSeg is \"\\\" followed by NULL\n")); |
1da177e4 LT |
348 | } |
349 | ||
350 | /* Consume the NULL byte */ | |
351 | ||
352 | aml_address++; | |
4be44fcd LB |
353 | name_string = |
354 | acpi_ex_allocate_name_string(prefix_count, 0); | |
1da177e4 LT |
355 | if (!name_string) { |
356 | status = AE_NO_MEMORY; | |
357 | break; | |
358 | } | |
359 | ||
360 | break; | |
361 | ||
1da177e4 LT |
362 | default: |
363 | ||
364 | /* Name segment string */ | |
365 | ||
4be44fcd LB |
366 | name_string = |
367 | acpi_ex_allocate_name_string(prefix_count, 1); | |
1da177e4 LT |
368 | if (!name_string) { |
369 | status = AE_NO_MEMORY; | |
370 | break; | |
371 | } | |
372 | ||
4be44fcd LB |
373 | status = |
374 | acpi_ex_name_segment(&aml_address, name_string); | |
1da177e4 LT |
375 | break; |
376 | } | |
377 | } | |
378 | ||
379 | if (AE_CTRL_PENDING == status && has_prefix) { | |
52fc0b02 | 380 | |
1da177e4 LT |
381 | /* Ran out of segments after processing a prefix */ |
382 | ||
b8e4d893 | 383 | ACPI_ERROR((AE_INFO, "Malformed Name at %p", name_string)); |
1da177e4 LT |
384 | status = AE_AML_BAD_NAME; |
385 | } | |
386 | ||
4be44fcd | 387 | if (ACPI_FAILURE(status)) { |
88ac00f5 | 388 | if (name_string) { |
8313524a | 389 | ACPI_FREE(name_string); |
88ac00f5 | 390 | } |
4be44fcd | 391 | return_ACPI_STATUS(status); |
88ac00f5 RM |
392 | } |
393 | ||
1da177e4 LT |
394 | *out_name_string = name_string; |
395 | *out_name_length = (u32) (aml_address - in_aml_address); | |
396 | ||
4be44fcd | 397 | return_ACPI_STATUS(status); |
1da177e4 | 398 | } |