diff options
author | Bob Moore <robert.moore@intel.com> | 2007-02-02 11:48:18 -0500 |
---|---|---|
committer | Len Brown <len.brown@intel.com> | 2007-02-02 21:14:20 -0500 |
commit | 8f9337c88335846b01801b1047a4caf10527a320 (patch) | |
tree | adcd64df3b0949f2bec91adcec749c1a5b36510d | |
parent | 24058054d781934df526be114c612cf2b29cf4e7 (diff) |
ACPICA: Handle case NumElements > Package length
Additional update for NumElements fix. Must handle
case where NumElements > Package list length, pad package
with null elements.
Signed-off-by: Alexey Starikovskiy <alexey.y.starikovskiy@intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>
-rw-r--r-- | drivers/acpi/dispatcher/dsobject.c | 87 |
1 files changed, 41 insertions, 46 deletions
diff --git a/drivers/acpi/dispatcher/dsobject.c b/drivers/acpi/dispatcher/dsobject.c index aaeb9f987ecc..f9f6862b1dff 100644 --- a/drivers/acpi/dispatcher/dsobject.c +++ b/drivers/acpi/dispatcher/dsobject.c | |||
@@ -260,7 +260,7 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, | |||
260 | } | 260 | } |
261 | 261 | ||
262 | obj_desc->buffer.flags |= AOPOBJ_DATA_VALID; | 262 | obj_desc->buffer.flags |= AOPOBJ_DATA_VALID; |
263 | op->common.node = (struct acpi_namespace_node *)obj_desc; | 263 | op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc); |
264 | return_ACPI_STATUS(AE_OK); | 264 | return_ACPI_STATUS(AE_OK); |
265 | } | 265 | } |
266 | 266 | ||
@@ -270,7 +270,8 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, | |||
270 | * | 270 | * |
271 | * PARAMETERS: walk_state - Current walk state | 271 | * PARAMETERS: walk_state - Current walk state |
272 | * Op - Parser object to be translated | 272 | * Op - Parser object to be translated |
273 | * package_length - Number of elements in the package | 273 | * element_count - Number of elements in the package - this is |
274 | * the num_elements argument to Package() | ||
274 | * obj_desc_ptr - Where the ACPI internal object is returned | 275 | * obj_desc_ptr - Where the ACPI internal object is returned |
275 | * | 276 | * |
276 | * RETURN: Status | 277 | * RETURN: Status |
@@ -278,18 +279,29 @@ acpi_ds_build_internal_buffer_obj(struct acpi_walk_state *walk_state, | |||
278 | * DESCRIPTION: Translate a parser Op package object to the equivalent | 279 | * DESCRIPTION: Translate a parser Op package object to the equivalent |
279 | * namespace object | 280 | * namespace object |
280 | * | 281 | * |
282 | * NOTE: The number of elements in the package will be always be the num_elements | ||
283 | * count, regardless of the number of elements in the package list. If | ||
284 | * num_elements is smaller, only that many package list elements are used. | ||
285 | * if num_elements is larger, the Package object is padded out with | ||
286 | * objects of type Uninitialized (as per ACPI spec.) | ||
287 | * | ||
288 | * Even though the ASL compilers do not allow num_elements to be smaller | ||
289 | * than the Package list length (for the fixed length package opcode), some | ||
290 | * BIOS code modifies the AML on the fly to adjust the num_elements, and | ||
291 | * this code compensates for that. This also provides compatibility with | ||
292 | * other AML interpreters. | ||
293 | * | ||
281 | ******************************************************************************/ | 294 | ******************************************************************************/ |
282 | 295 | ||
283 | acpi_status | 296 | acpi_status |
284 | acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, | 297 | acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, |
285 | union acpi_parse_object *op, | 298 | union acpi_parse_object *op, |
286 | u32 package_length, | 299 | u32 element_count, |
287 | union acpi_operand_object **obj_desc_ptr) | 300 | union acpi_operand_object **obj_desc_ptr) |
288 | { | 301 | { |
289 | union acpi_parse_object *arg; | 302 | union acpi_parse_object *arg; |
290 | union acpi_parse_object *parent; | 303 | union acpi_parse_object *parent; |
291 | union acpi_operand_object *obj_desc = NULL; | 304 | union acpi_operand_object *obj_desc = NULL; |
292 | u32 package_list_length; | ||
293 | acpi_status status = AE_OK; | 305 | acpi_status status = AE_OK; |
294 | acpi_native_uint i; | 306 | acpi_native_uint i; |
295 | 307 | ||
@@ -318,43 +330,13 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, | |||
318 | obj_desc->package.node = parent->common.node; | 330 | obj_desc->package.node = parent->common.node; |
319 | } | 331 | } |
320 | 332 | ||
321 | /* Count the *actual* number of items in the package list */ | ||
322 | |||
323 | arg = op->common.value.arg; | ||
324 | arg = arg->common.next; | ||
325 | for (package_list_length = 0; arg; package_list_length++) { | ||
326 | arg = arg->common.next; | ||
327 | } | ||
328 | |||
329 | /* | ||
330 | * The number of elements in the package will be the lesser of the | ||
331 | * specified element count and the length of the initializer list. | ||
332 | * | ||
333 | * Even though the ASL compilers do not allow this to happen (for the | ||
334 | * fixed length package opcode), some BIOS code modifies the AML on the | ||
335 | * fly to adjust the package length, and this code compensates for that. | ||
336 | * This also provides compatibility with other AML interpreters. | ||
337 | */ | ||
338 | obj_desc->package.count = package_length; | ||
339 | |||
340 | if (package_list_length != package_length) { | ||
341 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
342 | "Package length mismatch, using lesser of %X(Length Arg) and %X(AML Length)\n", | ||
343 | package_length, package_list_length)); | ||
344 | |||
345 | if (package_list_length < package_length) { | ||
346 | obj_desc->package.count = package_list_length; | ||
347 | } | ||
348 | } | ||
349 | |||
350 | /* | 333 | /* |
351 | * Allocate the pointer array (array of pointers to the | 334 | * Allocate the element array (array of pointers to the individual |
352 | * individual objects). Add an extra pointer slot so | 335 | * objects) based on the num_elements parameter. Add an extra pointer slot |
353 | * that the list is always null terminated. | 336 | * so that the list is always null terminated. |
354 | */ | 337 | */ |
355 | obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) | 338 | obj_desc->package.elements = ACPI_ALLOCATE_ZEROED(((acpi_size) |
356 | obj_desc->package. | 339 | element_count + |
357 | count + | ||
358 | 1) * sizeof(void *)); | 340 | 1) * sizeof(void *)); |
359 | 341 | ||
360 | if (!obj_desc->package.elements) { | 342 | if (!obj_desc->package.elements) { |
@@ -362,15 +344,20 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, | |||
362 | return_ACPI_STATUS(AE_NO_MEMORY); | 344 | return_ACPI_STATUS(AE_NO_MEMORY); |
363 | } | 345 | } |
364 | 346 | ||
347 | obj_desc->package.count = element_count; | ||
348 | |||
365 | /* | 349 | /* |
366 | * Initialize all elements of the package | 350 | * Initialize the elements of the package, up to the num_elements count. |
351 | * Package is automatically padded with uninitialized (NULL) elements | ||
352 | * if num_elements is greater than the package list length. Likewise, | ||
353 | * Package is truncated if num_elements is less than the list length. | ||
367 | */ | 354 | */ |
368 | arg = op->common.value.arg; | 355 | arg = op->common.value.arg; |
369 | arg = arg->common.next; | 356 | arg = arg->common.next; |
370 | for (i = 0; i < obj_desc->package.count; i++) { | 357 | for (i = 0; arg && (i < element_count); i++) { |
371 | if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { | 358 | if (arg->common.aml_opcode == AML_INT_RETURN_VALUE_OP) { |
372 | 359 | ||
373 | /* Object (package or buffer) is already built */ | 360 | /* This package element is already built, just get it */ |
374 | 361 | ||
375 | obj_desc->package.elements[i] = | 362 | obj_desc->package.elements[i] = |
376 | ACPI_CAST_PTR(union acpi_operand_object, | 363 | ACPI_CAST_PTR(union acpi_operand_object, |
@@ -384,8 +371,14 @@ acpi_ds_build_internal_package_obj(struct acpi_walk_state *walk_state, | |||
384 | arg = arg->common.next; | 371 | arg = arg->common.next; |
385 | } | 372 | } |
386 | 373 | ||
374 | if (!arg) { | ||
375 | ACPI_DEBUG_PRINT((ACPI_DB_INFO, | ||
376 | "Package List length larger than NumElements count (%X), truncated\n", | ||
377 | element_count)); | ||
378 | } | ||
379 | |||
387 | obj_desc->package.flags |= AOPOBJ_DATA_VALID; | 380 | obj_desc->package.flags |= AOPOBJ_DATA_VALID; |
388 | op->common.node = (struct acpi_namespace_node *)obj_desc; | 381 | op->common.node = ACPI_CAST_PTR(struct acpi_namespace_node, obj_desc); |
389 | return_ACPI_STATUS(status); | 382 | return_ACPI_STATUS(status); |
390 | } | 383 | } |
391 | 384 | ||
@@ -499,8 +492,9 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, | |||
499 | /* | 492 | /* |
500 | * Defer evaluation of Buffer term_arg operand | 493 | * Defer evaluation of Buffer term_arg operand |
501 | */ | 494 | */ |
502 | obj_desc->buffer.node = (struct acpi_namespace_node *) | 495 | obj_desc->buffer.node = |
503 | walk_state->operands[0]; | 496 | ACPI_CAST_PTR(struct acpi_namespace_node, |
497 | walk_state->operands[0]); | ||
504 | obj_desc->buffer.aml_start = op->named.data; | 498 | obj_desc->buffer.aml_start = op->named.data; |
505 | obj_desc->buffer.aml_length = op->named.length; | 499 | obj_desc->buffer.aml_length = op->named.length; |
506 | break; | 500 | break; |
@@ -510,8 +504,9 @@ acpi_ds_init_object_from_op(struct acpi_walk_state *walk_state, | |||
510 | /* | 504 | /* |
511 | * Defer evaluation of Package term_arg operand | 505 | * Defer evaluation of Package term_arg operand |
512 | */ | 506 | */ |
513 | obj_desc->package.node = (struct acpi_namespace_node *) | 507 | obj_desc->package.node = |
514 | walk_state->operands[0]; | 508 | ACPI_CAST_PTR(struct acpi_namespace_node, |
509 | walk_state->operands[0]); | ||
515 | obj_desc->package.aml_start = op->named.data; | 510 | obj_desc->package.aml_start = op->named.data; |
516 | obj_desc->package.aml_length = op->named.length; | 511 | obj_desc->package.aml_length = op->named.length; |
517 | break; | 512 | break; |