exnames.c 11.4 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8

/******************************************************************************
 *
 * Module Name: exnames - interpreter/scanner name load/execute
 *
 *****************************************************************************/

/*
L
Len Brown 已提交
9
 * Copyright (C) 2000 - 2008, Intel Corp.
L
Linus Torvalds 已提交
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions, and the following disclaimer,
 *    without modification.
 * 2. Redistributions in binary form must reproduce at minimum a disclaimer
 *    substantially similar to the "NO WARRANTY" disclaimer below
 *    ("Disclaimer") and any redistribution must be conditioned upon
 *    including a substantially similar Disclaimer requirement for further
 *    binary redistribution.
 * 3. Neither the names of the above-listed copyright holders nor the names
 *    of any contributors may be used to endorse or promote products derived
 *    from this software without specific prior written permission.
 *
 * Alternatively, this software may be distributed under the terms of the
 * GNU General Public License ("GPL") version 2 as published by the Free
 * Software Foundation.
 *
 * NO WARRANTY
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
 * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGES.
 */

#include <acpi/acpi.h>
L
Len Brown 已提交
46 47 48
#include "accommon.h"
#include "acinterp.h"
#include "amlcode.h"
L
Linus Torvalds 已提交
49 50

#define _COMPONENT          ACPI_EXECUTER
L
Len Brown 已提交
51
ACPI_MODULE_NAME("exnames")
L
Linus Torvalds 已提交
52

R
Robert Moore 已提交
53
/* Local prototypes */
L
Len Brown 已提交
54
static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs);
L
Linus Torvalds 已提交
55

R
Robert Moore 已提交
56
static acpi_status
L
Len Brown 已提交
57
acpi_ex_name_segment(u8 ** in_aml_address, char *name_string);
L
Linus Torvalds 已提交
58 59 60 61 62 63

/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_allocate_name_string
 *
 * PARAMETERS:  prefix_count        - Count of parent levels. Special cases:
R
Robert Moore 已提交
64
 *                                    (-1)==root,  0==none
L
Linus Torvalds 已提交
65 66 67 68 69 70 71 72 73 74
 *              num_name_segs       - count of 4-character name segments
 *
 * RETURN:      A pointer to the allocated string segment.  This segment must
 *              be deleted by the caller.
 *
 * DESCRIPTION: Allocate a buffer for a name string. Ensure allocated name
 *              string is long enough, and set up prefix if any.
 *
 ******************************************************************************/

L
Len Brown 已提交
75
static char *acpi_ex_allocate_name_string(u32 prefix_count, u32 num_name_segs)
L
Linus Torvalds 已提交
76
{
L
Len Brown 已提交
77 78 79
	char *temp_ptr;
	char *name_string;
	u32 size_needed;
L
Linus Torvalds 已提交
80

B
Bob Moore 已提交
81
	ACPI_FUNCTION_TRACE(ex_allocate_name_string);
L
Linus Torvalds 已提交
82 83

	/*
R
Robert Moore 已提交
84
	 * Allow room for all \ and ^ prefixes, all segments and a multi_name_prefix.
L
Linus Torvalds 已提交
85 86 87 88
	 * Also, one byte for the null terminator.
	 * This may actually be somewhat longer than needed.
	 */
	if (prefix_count == ACPI_UINT32_MAX) {
B
Bob Moore 已提交
89

L
Linus Torvalds 已提交
90 91 92
		/* Special case for root */

		size_needed = 1 + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1;
L
Len Brown 已提交
93 94 95
	} else {
		size_needed =
		    prefix_count + (ACPI_NAME_SIZE * num_name_segs) + 2 + 1;
L
Linus Torvalds 已提交
96 97 98 99 100 101
	}

	/*
	 * Allocate a buffer for the name.
	 * This buffer must be deleted by the caller!
	 */
B
Bob Moore 已提交
102
	name_string = ACPI_ALLOCATE(size_needed);
L
Linus Torvalds 已提交
103
	if (!name_string) {
B
Bob Moore 已提交
104 105
		ACPI_ERROR((AE_INFO,
			    "Could not allocate size %d", size_needed));
L
Len Brown 已提交
106
		return_PTR(NULL);
L
Linus Torvalds 已提交
107 108 109 110 111 112 113 114
	}

	temp_ptr = name_string;

	/* Set up Root or Parent prefixes if needed */

	if (prefix_count == ACPI_UINT32_MAX) {
		*temp_ptr++ = AML_ROOT_PREFIX;
L
Len Brown 已提交
115
	} else {
L
Linus Torvalds 已提交
116 117 118 119 120 121 122 123
		while (prefix_count--) {
			*temp_ptr++ = AML_PARENT_PREFIX;
		}
	}

	/* Set up Dual or Multi prefixes if needed */

	if (num_name_segs > 2) {
B
Bob Moore 已提交
124

L
Linus Torvalds 已提交
125 126 127
		/* Set up multi prefixes   */

		*temp_ptr++ = AML_MULTI_NAME_PREFIX_OP;
L
Len Brown 已提交
128 129
		*temp_ptr++ = (char)num_name_segs;
	} else if (2 == num_name_segs) {
B
Bob Moore 已提交
130

L
Linus Torvalds 已提交
131 132 133 134 135 136 137 138 139 140 141
		/* Set up dual prefixes */

		*temp_ptr++ = AML_DUAL_NAME_PREFIX;
	}

	/*
	 * Terminate string following prefixes. acpi_ex_name_segment() will
	 * append the segment(s)
	 */
	*temp_ptr = 0;

L
Len Brown 已提交
142
	return_PTR(name_string);
L
Linus Torvalds 已提交
143 144 145 146 147 148
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_name_segment
 *
R
Robert Moore 已提交
149 150 151
 * PARAMETERS:  in_aml_address  - Pointer to the name in the AML code
 *              name_string     - Where to return the name. The name is appended
 *                                to any existing string to form a namepath
L
Linus Torvalds 已提交
152 153 154
 *
 * RETURN:      Status
 *
R
Robert Moore 已提交
155
 * DESCRIPTION: Extract an ACPI name (4 bytes) from the AML byte stream
L
Linus Torvalds 已提交
156 157 158
 *
 ******************************************************************************/

L
Len Brown 已提交
159
static acpi_status acpi_ex_name_segment(u8 ** in_aml_address, char *name_string)
L
Linus Torvalds 已提交
160
{
L
Len Brown 已提交
161 162 163 164
	char *aml_address = (void *)*in_aml_address;
	acpi_status status = AE_OK;
	u32 index;
	char char_buf[5];
L
Linus Torvalds 已提交
165

B
Bob Moore 已提交
166
	ACPI_FUNCTION_TRACE(ex_name_segment);
L
Linus Torvalds 已提交
167 168 169 170 171 172 173 174

	/*
	 * If first character is a digit, then we know that we aren't looking at a
	 * valid name segment
	 */
	char_buf[0] = *aml_address;

	if ('0' <= char_buf[0] && char_buf[0] <= '9') {
B
Bob Moore 已提交
175
		ACPI_ERROR((AE_INFO, "Invalid leading digit: %c", char_buf[0]));
L
Len Brown 已提交
176
		return_ACPI_STATUS(AE_CTRL_PENDING);
L
Linus Torvalds 已提交
177 178
	}

L
Len Brown 已提交
179
	ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "Bytes from stream:\n"));
L
Linus Torvalds 已提交
180

L
Len Brown 已提交
181
	for (index = 0; (index < ACPI_NAME_SIZE)
B
Bob Moore 已提交
182
	     && (acpi_ut_valid_acpi_char(*aml_address, 0)); index++) {
L
Linus Torvalds 已提交
183
		char_buf[index] = *aml_address++;
L
Len Brown 已提交
184
		ACPI_DEBUG_PRINT((ACPI_DB_LOAD, "%c\n", char_buf[index]));
L
Linus Torvalds 已提交
185 186 187 188 189
	}

	/* Valid name segment  */

	if (index == 4) {
B
Bob Moore 已提交
190

L
Linus Torvalds 已提交
191 192 193 194 195
		/* Found 4 valid characters */

		char_buf[4] = '\0';

		if (name_string) {
L
Len Brown 已提交
196 197
			ACPI_STRCAT(name_string, char_buf);
			ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
B
Bob Moore 已提交
198
					  "Appended to - %s\n", name_string));
L
Len Brown 已提交
199 200
		} else {
			ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
B
Bob Moore 已提交
201
					  "No Name string - %s\n", char_buf));
L
Linus Torvalds 已提交
202
		}
L
Len Brown 已提交
203
	} else if (index == 0) {
L
Linus Torvalds 已提交
204 205 206 207
		/*
		 * First character was not a valid name character,
		 * so we are looking at something other than a name.
		 */
L
Len Brown 已提交
208 209 210
		ACPI_DEBUG_PRINT((ACPI_DB_INFO,
				  "Leading character is not alpha: %02Xh (not a name)\n",
				  char_buf[0]));
L
Linus Torvalds 已提交
211
		status = AE_CTRL_PENDING;
L
Len Brown 已提交
212
	} else {
R
Robert Moore 已提交
213 214 215 216
		/*
		 * Segment started with one or more valid characters, but fewer than
		 * the required 4
		 */
L
Linus Torvalds 已提交
217
		status = AE_AML_BAD_NAME;
B
Bob Moore 已提交
218 219 220
		ACPI_ERROR((AE_INFO,
			    "Bad character %02x in name, at %p",
			    *aml_address, aml_address));
L
Linus Torvalds 已提交
221 222
	}

B
Bob Moore 已提交
223
	*in_aml_address = ACPI_CAST_PTR(u8, aml_address);
L
Len Brown 已提交
224
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
225 226 227 228 229 230
}

/*******************************************************************************
 *
 * FUNCTION:    acpi_ex_get_name_string
 *
R
Robert Moore 已提交
231 232 233 234 235
 * PARAMETERS:  data_type           - Object type to be associated with this
 *                                    name
 *              in_aml_address      - Pointer to the namestring in the AML code
 *              out_name_string     - Where the namestring is returned
 *              out_name_length     - Length of the returned string
L
Linus Torvalds 已提交
236
 *
R
Robert Moore 已提交
237
 * RETURN:      Status, namestring and length
L
Linus Torvalds 已提交
238
 *
R
Robert Moore 已提交
239 240
 * DESCRIPTION: Extract a full namepath from the AML byte stream,
 *              including any prefixes.
L
Linus Torvalds 已提交
241 242 243 244
 *
 ******************************************************************************/

acpi_status
L
Len Brown 已提交
245 246 247
acpi_ex_get_name_string(acpi_object_type data_type,
			u8 * in_aml_address,
			char **out_name_string, u32 * out_name_length)
L
Linus Torvalds 已提交
248
{
L
Len Brown 已提交
249 250 251 252 253 254 255
	acpi_status status = AE_OK;
	u8 *aml_address = in_aml_address;
	char *name_string = NULL;
	u32 num_segments;
	u32 prefix_count = 0;
	u8 has_prefix = FALSE;

B
Bob Moore 已提交
256
	ACPI_FUNCTION_TRACE_PTR(ex_get_name_string, aml_address);
L
Len Brown 已提交
257 258 259 260

	if (ACPI_TYPE_LOCAL_REGION_FIELD == data_type ||
	    ACPI_TYPE_LOCAL_BANK_FIELD == data_type ||
	    ACPI_TYPE_LOCAL_INDEX_FIELD == data_type) {
B
Bob Moore 已提交
261

L
Linus Torvalds 已提交
262 263
		/* Disallow prefixes for types associated with field_unit names */

L
Len Brown 已提交
264
		name_string = acpi_ex_allocate_name_string(0, 1);
L
Linus Torvalds 已提交
265 266
		if (!name_string) {
			status = AE_NO_MEMORY;
L
Len Brown 已提交
267 268 269
		} else {
			status =
			    acpi_ex_name_segment(&aml_address, name_string);
L
Linus Torvalds 已提交
270
		}
L
Len Brown 已提交
271
	} else {
L
Linus Torvalds 已提交
272 273 274 275 276 277 278
		/*
		 * data_type is not a field name.
		 * Examine first character of name for root or parent prefix operators
		 */
		switch (*aml_address) {
		case AML_ROOT_PREFIX:

L
Len Brown 已提交
279
			ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
B
Bob Moore 已提交
280
					  "RootPrefix(\\) at %p\n",
L
Len Brown 已提交
281
					  aml_address));
L
Linus Torvalds 已提交
282 283 284 285 286 287 288 289 290 291 292 293 294 295 296

			/*
			 * Remember that we have a root_prefix --
			 * see comment in acpi_ex_allocate_name_string()
			 */
			aml_address++;
			prefix_count = ACPI_UINT32_MAX;
			has_prefix = TRUE;
			break;

		case AML_PARENT_PREFIX:

			/* Increment past possibly multiple parent prefixes */

			do {
L
Len Brown 已提交
297
				ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
B
Bob Moore 已提交
298
						  "ParentPrefix (^) at %p\n",
L
Len Brown 已提交
299
						  aml_address));
L
Linus Torvalds 已提交
300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320

				aml_address++;
				prefix_count++;

			} while (*aml_address == AML_PARENT_PREFIX);

			has_prefix = TRUE;
			break;

		default:

			/* Not a prefix character */

			break;
		}

		/* Examine first character of name for name segment prefix operator */

		switch (*aml_address) {
		case AML_DUAL_NAME_PREFIX:

L
Len Brown 已提交
321
			ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
B
Bob Moore 已提交
322
					  "DualNamePrefix at %p\n",
L
Len Brown 已提交
323
					  aml_address));
L
Linus Torvalds 已提交
324 325

			aml_address++;
L
Len Brown 已提交
326 327
			name_string =
			    acpi_ex_allocate_name_string(prefix_count, 2);
L
Linus Torvalds 已提交
328 329 330 331 332 333 334 335 336
			if (!name_string) {
				status = AE_NO_MEMORY;
				break;
			}

			/* Indicate that we processed a prefix */

			has_prefix = TRUE;

L
Len Brown 已提交
337 338 339 340 341 342
			status =
			    acpi_ex_name_segment(&aml_address, name_string);
			if (ACPI_SUCCESS(status)) {
				status =
				    acpi_ex_name_segment(&aml_address,
							 name_string);
L
Linus Torvalds 已提交
343 344 345 346 347
			}
			break;

		case AML_MULTI_NAME_PREFIX_OP:

L
Len Brown 已提交
348
			ACPI_DEBUG_PRINT((ACPI_DB_LOAD,
B
Bob Moore 已提交
349
					  "MultiNamePrefix at %p\n",
L
Len Brown 已提交
350
					  aml_address));
L
Linus Torvalds 已提交
351 352 353 354 355 356

			/* Fetch count of segments remaining in name path */

			aml_address++;
			num_segments = *aml_address;

L
Len Brown 已提交
357 358 359
			name_string =
			    acpi_ex_allocate_name_string(prefix_count,
							 num_segments);
L
Linus Torvalds 已提交
360 361 362 363 364 365 366 367 368 369 370
			if (!name_string) {
				status = AE_NO_MEMORY;
				break;
			}

			/* Indicate that we processed a prefix */

			aml_address++;
			has_prefix = TRUE;

			while (num_segments &&
L
Len Brown 已提交
371 372 373
			       (status =
				acpi_ex_name_segment(&aml_address,
						     name_string)) == AE_OK) {
L
Linus Torvalds 已提交
374 375 376 377 378 379 380 381 382 383
				num_segments--;
			}

			break;

		case 0:

			/* null_name valid as of 8-12-98 ASL/AML Grammar Update */

			if (prefix_count == ACPI_UINT32_MAX) {
L
Len Brown 已提交
384
				ACPI_DEBUG_PRINT((ACPI_DB_EXEC,
B
Bob Moore 已提交
385
						  "NameSeg is \"\\\" followed by NULL\n"));
L
Linus Torvalds 已提交
386 387 388 389 390
			}

			/* Consume the NULL byte */

			aml_address++;
L
Len Brown 已提交
391 392
			name_string =
			    acpi_ex_allocate_name_string(prefix_count, 0);
L
Linus Torvalds 已提交
393 394 395 396 397 398 399 400 401 402 403
			if (!name_string) {
				status = AE_NO_MEMORY;
				break;
			}

			break;

		default:

			/* Name segment string */

L
Len Brown 已提交
404 405
			name_string =
			    acpi_ex_allocate_name_string(prefix_count, 1);
L
Linus Torvalds 已提交
406 407 408 409 410
			if (!name_string) {
				status = AE_NO_MEMORY;
				break;
			}

L
Len Brown 已提交
411 412
			status =
			    acpi_ex_name_segment(&aml_address, name_string);
L
Linus Torvalds 已提交
413 414 415 416 417
			break;
		}
	}

	if (AE_CTRL_PENDING == status && has_prefix) {
B
Bob Moore 已提交
418

L
Linus Torvalds 已提交
419 420
		/* Ran out of segments after processing a prefix */

B
Bob Moore 已提交
421
		ACPI_ERROR((AE_INFO, "Malformed Name at %p", name_string));
L
Linus Torvalds 已提交
422 423 424
		status = AE_AML_BAD_NAME;
	}

L
Len Brown 已提交
425
	if (ACPI_FAILURE(status)) {
426
		if (name_string) {
B
Bob Moore 已提交
427
			ACPI_FREE(name_string);
428
		}
L
Len Brown 已提交
429
		return_ACPI_STATUS(status);
430 431
	}

L
Linus Torvalds 已提交
432 433 434
	*out_name_string = name_string;
	*out_name_length = (u32) (aml_address - in_aml_address);

L
Len Brown 已提交
435
	return_ACPI_STATUS(status);
L
Linus Torvalds 已提交
436
}