Branch data Line data Source code
1 : : // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 : : /******************************************************************************
3 : : *
4 : : * Module Name: nsrepair - Repair for objects returned by predefined methods
5 : : *
6 : : * Copyright (C) 2000 - 2020, Intel Corp.
7 : : *
8 : : *****************************************************************************/
9 : :
10 : : #include <acpi/acpi.h>
11 : : #include "accommon.h"
12 : : #include "acnamesp.h"
13 : : #include "acinterp.h"
14 : : #include "acpredef.h"
15 : : #include "amlresrc.h"
16 : :
17 : : #define _COMPONENT ACPI_NAMESPACE
18 : : ACPI_MODULE_NAME("nsrepair")
19 : :
20 : : /*******************************************************************************
21 : : *
22 : : * This module attempts to repair or convert objects returned by the
23 : : * predefined methods to an object type that is expected, as per the ACPI
24 : : * specification. The need for this code is dictated by the many machines that
25 : : * return incorrect types for the standard predefined methods. Performing these
26 : : * conversions here, in one place, eliminates the need for individual ACPI
27 : : * device drivers to do the same. Note: Most of these conversions are different
28 : : * than the internal object conversion routines used for implicit object
29 : : * conversion.
30 : : *
31 : : * The following conversions can be performed as necessary:
32 : : *
33 : : * Integer -> String
34 : : * Integer -> Buffer
35 : : * String -> Integer
36 : : * String -> Buffer
37 : : * Buffer -> Integer
38 : : * Buffer -> String
39 : : * Buffer -> Package of Integers
40 : : * Package -> Package of one Package
41 : : *
42 : : * Additional conversions that are available:
43 : : * Convert a null return or zero return value to an end_tag descriptor
44 : : * Convert an ASCII string to a Unicode buffer
45 : : *
46 : : * An incorrect standalone object is wrapped with required outer package
47 : : *
48 : : * Additional possible repairs:
49 : : * Required package elements that are NULL replaced by Integer/String/Buffer
50 : : *
51 : : ******************************************************************************/
52 : : /* Local prototypes */
53 : : static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct
54 : : acpi_namespace_node
55 : : *node,
56 : : u32
57 : : return_btype,
58 : : u32
59 : : package_index);
60 : :
61 : : /*
62 : : * Special but simple repairs for some names.
63 : : *
64 : : * 2nd argument: Unexpected types that can be repaired
65 : : */
66 : : static const struct acpi_simple_repair_info acpi_object_repair_info[] = {
67 : : /* Resource descriptor conversions */
68 : :
69 : : {"_CRS",
70 : : ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER |
71 : : ACPI_RTYPE_NONE,
72 : : ACPI_NOT_PACKAGE_ELEMENT,
73 : : acpi_ns_convert_to_resource},
74 : : {"_DMA",
75 : : ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER |
76 : : ACPI_RTYPE_NONE,
77 : : ACPI_NOT_PACKAGE_ELEMENT,
78 : : acpi_ns_convert_to_resource},
79 : : {"_PRS",
80 : : ACPI_RTYPE_INTEGER | ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER |
81 : : ACPI_RTYPE_NONE,
82 : : ACPI_NOT_PACKAGE_ELEMENT,
83 : : acpi_ns_convert_to_resource},
84 : :
85 : : /* Object reference conversions */
86 : :
87 : : {"_DEP", ACPI_RTYPE_STRING, ACPI_ALL_PACKAGE_ELEMENTS,
88 : : acpi_ns_convert_to_reference},
89 : :
90 : : /* Unicode conversions */
91 : :
92 : : {"_MLS", ACPI_RTYPE_STRING, 1,
93 : : acpi_ns_convert_to_unicode},
94 : : {"_STR", ACPI_RTYPE_STRING | ACPI_RTYPE_BUFFER,
95 : : ACPI_NOT_PACKAGE_ELEMENT,
96 : : acpi_ns_convert_to_unicode},
97 : : {{0, 0, 0, 0}, 0, 0, NULL} /* Table terminator */
98 : : };
99 : :
100 : : /*******************************************************************************
101 : : *
102 : : * FUNCTION: acpi_ns_simple_repair
103 : : *
104 : : * PARAMETERS: info - Method execution information block
105 : : * expected_btypes - Object types expected
106 : : * package_index - Index of object within parent package (if
107 : : * applicable - ACPI_NOT_PACKAGE_ELEMENT
108 : : * otherwise)
109 : : * return_object_ptr - Pointer to the object returned from the
110 : : * evaluation of a method or object
111 : : *
112 : : * RETURN: Status. AE_OK if repair was successful.
113 : : *
114 : : * DESCRIPTION: Attempt to repair/convert a return object of a type that was
115 : : * not expected.
116 : : *
117 : : ******************************************************************************/
118 : :
119 : : acpi_status
120 : 33095 : acpi_ns_simple_repair(struct acpi_evaluate_info *info,
121 : : u32 expected_btypes,
122 : : u32 package_index,
123 : : union acpi_operand_object **return_object_ptr)
124 : : {
125 : 33095 : union acpi_operand_object *return_object = *return_object_ptr;
126 : 33095 : union acpi_operand_object *new_object = NULL;
127 : 33095 : acpi_status status;
128 : 33095 : const struct acpi_simple_repair_info *predefined;
129 : :
130 : 33095 : ACPI_FUNCTION_NAME(ns_simple_repair);
131 : :
132 : : /*
133 : : * Special repairs for certain names that are in the repair table.
134 : : * Check if this name is in the list of repairable names.
135 : : */
136 : 33095 : predefined = acpi_ns_match_simple_repair(info->node,
137 : : info->return_btype,
138 : : package_index);
139 [ + + ]: 33095 : if (predefined) {
140 [ - + ]: 1120 : if (!return_object) {
141 : 0 : ACPI_WARN_PREDEFINED((AE_INFO, info->full_pathname,
142 : : ACPI_WARN_ALWAYS,
143 : : "Missing expected return value"));
144 : : }
145 : :
146 : 1120 : status = predefined->object_converter(info->node, return_object,
147 : : &new_object);
148 [ - + ]: 1120 : if (ACPI_FAILURE(status)) {
149 : :
150 : : /* A fatal error occurred during a conversion */
151 : :
152 : 0 : ACPI_EXCEPTION((AE_INFO, status,
153 : : "During return object analysis"));
154 : 0 : return (status);
155 : : }
156 [ - + ]: 1120 : if (new_object) {
157 : 0 : goto object_repaired;
158 : : }
159 : : }
160 : :
161 : : /*
162 : : * Do not perform simple object repair unless the return type is not
163 : : * expected.
164 : : */
165 [ - + ]: 33095 : if (info->return_btype & expected_btypes) {
166 : : return (AE_OK);
167 : : }
168 : :
169 : : /*
170 : : * At this point, we know that the type of the returned object was not
171 : : * one of the expected types for this predefined name. Attempt to
172 : : * repair the object by converting it to one of the expected object
173 : : * types for this predefined name.
174 : : */
175 : :
176 : : /*
177 : : * If there is no return value, check if we require a return value for
178 : : * this predefined name. Either one return value is expected, or none,
179 : : * for both methods and other objects.
180 : : *
181 : : * Try to fix if there was no return object. Warning if failed to fix.
182 : : */
183 [ # # ]: 0 : if (!return_object) {
184 [ # # # # ]: 0 : if (expected_btypes && (!(expected_btypes & ACPI_RTYPE_NONE))) {
185 [ # # ]: 0 : if (package_index != ACPI_NOT_PACKAGE_ELEMENT) {
186 : 0 : ACPI_WARN_PREDEFINED((AE_INFO,
187 : : info->full_pathname,
188 : : ACPI_WARN_ALWAYS,
189 : : "Found unexpected NULL package element"));
190 : :
191 : 0 : status =
192 : 0 : acpi_ns_repair_null_element(info,
193 : : expected_btypes,
194 : : package_index,
195 : : return_object_ptr);
196 [ # # ]: 0 : if (ACPI_SUCCESS(status)) {
197 : : return (AE_OK); /* Repair was successful */
198 : : }
199 : : } else {
200 : 0 : ACPI_WARN_PREDEFINED((AE_INFO,
201 : : info->full_pathname,
202 : : ACPI_WARN_ALWAYS,
203 : : "Missing expected return value"));
204 : : }
205 : :
206 : 0 : return (AE_AML_NO_RETURN_VALUE);
207 : : }
208 : : }
209 : :
210 [ # # ]: 0 : if (expected_btypes & ACPI_RTYPE_INTEGER) {
211 : 0 : status = acpi_ns_convert_to_integer(return_object, &new_object);
212 [ # # ]: 0 : if (ACPI_SUCCESS(status)) {
213 : 0 : goto object_repaired;
214 : : }
215 : : }
216 [ # # ]: 0 : if (expected_btypes & ACPI_RTYPE_STRING) {
217 : 0 : status = acpi_ns_convert_to_string(return_object, &new_object);
218 [ # # ]: 0 : if (ACPI_SUCCESS(status)) {
219 : 0 : goto object_repaired;
220 : : }
221 : : }
222 [ # # ]: 0 : if (expected_btypes & ACPI_RTYPE_BUFFER) {
223 : 0 : status = acpi_ns_convert_to_buffer(return_object, &new_object);
224 [ # # ]: 0 : if (ACPI_SUCCESS(status)) {
225 : 0 : goto object_repaired;
226 : : }
227 : : }
228 [ # # ]: 0 : if (expected_btypes & ACPI_RTYPE_PACKAGE) {
229 : : /*
230 : : * A package is expected. We will wrap the existing object with a
231 : : * new package object. It is often the case that if a variable-length
232 : : * package is required, but there is only a single object needed, the
233 : : * BIOS will return that object instead of wrapping it with a Package
234 : : * object. Note: after the wrapping, the package will be validated
235 : : * for correct contents (expected object type or types).
236 : : */
237 : 0 : status =
238 : 0 : acpi_ns_wrap_with_package(info, return_object, &new_object);
239 [ # # ]: 0 : if (ACPI_SUCCESS(status)) {
240 : : /*
241 : : * The original object just had its reference count
242 : : * incremented for being inserted into the new package.
243 : : */
244 : 0 : *return_object_ptr = new_object; /* New Package object */
245 : 0 : info->return_flags |= ACPI_OBJECT_REPAIRED;
246 : 0 : return (AE_OK);
247 : : }
248 : : }
249 : :
250 : : /* We cannot repair this object */
251 : :
252 : : return (AE_AML_OPERAND_TYPE);
253 : :
254 : 0 : object_repaired:
255 : :
256 : : /* Object was successfully repaired */
257 : :
258 [ # # ]: 0 : if (package_index != ACPI_NOT_PACKAGE_ELEMENT) {
259 : :
260 : : /* Update reference count of new object */
261 : :
262 [ # # ]: 0 : if (!(info->return_flags & ACPI_OBJECT_WRAPPED)) {
263 : 0 : new_object->common.reference_count =
264 : 0 : return_object->common.reference_count;
265 : : }
266 : :
267 : : ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
268 : : "%s: Converted %s to expected %s at Package index %u\n",
269 : : info->full_pathname,
270 : : acpi_ut_get_object_type_name(return_object),
271 : : acpi_ut_get_object_type_name(new_object),
272 : : package_index));
273 : : } else {
274 : : ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
275 : : "%s: Converted %s to expected %s\n",
276 : : info->full_pathname,
277 : : acpi_ut_get_object_type_name(return_object),
278 : 0 : acpi_ut_get_object_type_name(new_object)));
279 : : }
280 : :
281 : : /* Delete old object, install the new return object */
282 : :
283 : 0 : acpi_ut_remove_reference(return_object);
284 : 0 : *return_object_ptr = new_object;
285 : 0 : info->return_flags |= ACPI_OBJECT_REPAIRED;
286 : 0 : return (AE_OK);
287 : : }
288 : :
289 : : /******************************************************************************
290 : : *
291 : : * FUNCTION: acpi_ns_match_simple_repair
292 : : *
293 : : * PARAMETERS: node - Namespace node for the method/object
294 : : * return_btype - Object type that was returned
295 : : * package_index - Index of object within parent package (if
296 : : * applicable - ACPI_NOT_PACKAGE_ELEMENT
297 : : * otherwise)
298 : : *
299 : : * RETURN: Pointer to entry in repair table. NULL indicates not found.
300 : : *
301 : : * DESCRIPTION: Check an object name against the repairable object list.
302 : : *
303 : : *****************************************************************************/
304 : :
305 : 33095 : static const struct acpi_simple_repair_info *acpi_ns_match_simple_repair(struct
306 : : acpi_namespace_node
307 : : *node,
308 : : u32
309 : : return_btype,
310 : : u32
311 : : package_index)
312 : : {
313 : 33095 : const struct acpi_simple_repair_info *this_name;
314 : :
315 : : /* Search info table for a repairable predefined method/object name */
316 : :
317 : 33095 : this_name = acpi_object_repair_info;
318 [ + + ]: 225225 : while (this_name->object_converter) {
319 [ + + ]: 193250 : if (ACPI_COMPARE_NAMESEG(node->name.ascii, this_name->name)) {
320 : :
321 : : /* Check if we can actually repair this name/type combination */
322 : :
323 [ + - ]: 1120 : if ((return_btype & this_name->unexpected_btypes) &&
324 [ + - ]: 1120 : (this_name->package_index ==
325 : : ACPI_ALL_PACKAGE_ELEMENTS
326 [ - + ]: 1120 : || package_index == this_name->package_index)) {
327 : : return (this_name);
328 : : }
329 : :
330 : 0 : return (NULL);
331 : : }
332 : :
333 : 192130 : this_name++;
334 : : }
335 : :
336 : : return (NULL); /* Name was not found in the repair table */
337 : : }
338 : :
339 : : /*******************************************************************************
340 : : *
341 : : * FUNCTION: acpi_ns_repair_null_element
342 : : *
343 : : * PARAMETERS: info - Method execution information block
344 : : * expected_btypes - Object types expected
345 : : * package_index - Index of object within parent package (if
346 : : * applicable - ACPI_NOT_PACKAGE_ELEMENT
347 : : * otherwise)
348 : : * return_object_ptr - Pointer to the object returned from the
349 : : * evaluation of a method or object
350 : : *
351 : : * RETURN: Status. AE_OK if repair was successful.
352 : : *
353 : : * DESCRIPTION: Attempt to repair a NULL element of a returned Package object.
354 : : *
355 : : ******************************************************************************/
356 : :
357 : : acpi_status
358 : 0 : acpi_ns_repair_null_element(struct acpi_evaluate_info *info,
359 : : u32 expected_btypes,
360 : : u32 package_index,
361 : : union acpi_operand_object **return_object_ptr)
362 : : {
363 : 0 : union acpi_operand_object *return_object = *return_object_ptr;
364 : 0 : union acpi_operand_object *new_object;
365 : :
366 : 0 : ACPI_FUNCTION_NAME(ns_repair_null_element);
367 : :
368 : : /* No repair needed if return object is non-NULL */
369 : :
370 [ # # ]: 0 : if (return_object) {
371 : : return (AE_OK);
372 : : }
373 : :
374 : : /*
375 : : * Attempt to repair a NULL element of a Package object. This applies to
376 : : * predefined names that return a fixed-length package and each element
377 : : * is required. It does not apply to variable-length packages where NULL
378 : : * elements are allowed, especially at the end of the package.
379 : : */
380 [ # # ]: 0 : if (expected_btypes & ACPI_RTYPE_INTEGER) {
381 : :
382 : : /* Need an integer - create a zero-value integer */
383 : :
384 : 0 : new_object = acpi_ut_create_integer_object((u64)0);
385 [ # # ]: 0 : } else if (expected_btypes & ACPI_RTYPE_STRING) {
386 : :
387 : : /* Need a string - create a NULL string */
388 : :
389 : 0 : new_object = acpi_ut_create_string_object(0);
390 [ # # ]: 0 : } else if (expected_btypes & ACPI_RTYPE_BUFFER) {
391 : :
392 : : /* Need a buffer - create a zero-length buffer */
393 : :
394 : 0 : new_object = acpi_ut_create_buffer_object(0);
395 : : } else {
396 : : /* Error for all other expected types */
397 : :
398 : : return (AE_AML_OPERAND_TYPE);
399 : : }
400 : :
401 [ # # ]: 0 : if (!new_object) {
402 : : return (AE_NO_MEMORY);
403 : : }
404 : :
405 : : /* Set the reference count according to the parent Package object */
406 : :
407 : 0 : new_object->common.reference_count =
408 : 0 : info->parent_package->common.reference_count;
409 : :
410 : : ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
411 : : "%s: Converted NULL package element to expected %s at index %u\n",
412 : : info->full_pathname,
413 : : acpi_ut_get_object_type_name(new_object),
414 : 0 : package_index));
415 : :
416 : 0 : *return_object_ptr = new_object;
417 : 0 : info->return_flags |= ACPI_OBJECT_REPAIRED;
418 : 0 : return (AE_OK);
419 : : }
420 : :
421 : : /******************************************************************************
422 : : *
423 : : * FUNCTION: acpi_ns_remove_null_elements
424 : : *
425 : : * PARAMETERS: info - Method execution information block
426 : : * package_type - An acpi_return_package_types value
427 : : * obj_desc - A Package object
428 : : *
429 : : * RETURN: None.
430 : : *
431 : : * DESCRIPTION: Remove all NULL package elements from packages that contain
432 : : * a variable number of subpackages. For these types of
433 : : * packages, NULL elements can be safely removed.
434 : : *
435 : : *****************************************************************************/
436 : :
437 : : void
438 : 115 : acpi_ns_remove_null_elements(struct acpi_evaluate_info *info,
439 : : u8 package_type,
440 : : union acpi_operand_object *obj_desc)
441 : : {
442 : 115 : union acpi_operand_object **source;
443 : 115 : union acpi_operand_object **dest;
444 : 115 : u32 count;
445 : 115 : u32 new_count;
446 : 115 : u32 i;
447 : :
448 : 115 : ACPI_FUNCTION_NAME(ns_remove_null_elements);
449 : :
450 : : /*
451 : : * We can safely remove all NULL elements from these package types:
452 : : * PTYPE1_VAR packages contain a variable number of simple data types.
453 : : * PTYPE2 packages contain a variable number of subpackages.
454 : : */
455 [ + - ]: 115 : switch (package_type) {
456 : : case ACPI_PTYPE1_VAR:
457 : : case ACPI_PTYPE2:
458 : : case ACPI_PTYPE2_COUNT:
459 : : case ACPI_PTYPE2_PKG_COUNT:
460 : : case ACPI_PTYPE2_FIXED:
461 : : case ACPI_PTYPE2_MIN:
462 : : case ACPI_PTYPE2_REV_FIXED:
463 : : case ACPI_PTYPE2_FIX_VAR:
464 : 115 : break;
465 : :
466 : : default:
467 : : case ACPI_PTYPE2_VAR_VAR:
468 : : case ACPI_PTYPE1_FIXED:
469 : : case ACPI_PTYPE1_OPTION:
470 : : return;
471 : : }
472 : :
473 : 115 : count = obj_desc->package.count;
474 : 115 : new_count = count;
475 : :
476 : 115 : source = obj_desc->package.elements;
477 : 115 : dest = source;
478 : :
479 : : /* Examine all elements of the package object, remove nulls */
480 : :
481 [ + + ]: 4419 : for (i = 0; i < count; i++) {
482 [ - + ]: 4304 : if (!*source) {
483 : 0 : new_count--;
484 : : } else {
485 : 4304 : *dest = *source;
486 : 4304 : dest++;
487 : : }
488 : :
489 : 4304 : source++;
490 : : }
491 : :
492 : : /* Update parent package if any null elements were removed */
493 : :
494 [ - + ]: 115 : if (new_count < count) {
495 : : ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
496 : : "%s: Found and removed %u NULL elements\n",
497 : 0 : info->full_pathname, (count - new_count)));
498 : :
499 : : /* NULL terminate list and update the package count */
500 : :
501 : 0 : *dest = NULL;
502 : 0 : obj_desc->package.count = new_count;
503 : : }
504 : : }
505 : :
506 : : /*******************************************************************************
507 : : *
508 : : * FUNCTION: acpi_ns_wrap_with_package
509 : : *
510 : : * PARAMETERS: info - Method execution information block
511 : : * original_object - Pointer to the object to repair.
512 : : * obj_desc_ptr - The new package object is returned here
513 : : *
514 : : * RETURN: Status, new object in *obj_desc_ptr
515 : : *
516 : : * DESCRIPTION: Repair a common problem with objects that are defined to
517 : : * return a variable-length Package of sub-objects. If there is
518 : : * only one sub-object, some BIOS code mistakenly simply declares
519 : : * the single object instead of a Package with one sub-object.
520 : : * This function attempts to repair this error by wrapping a
521 : : * Package object around the original object, creating the
522 : : * correct and expected Package with one sub-object.
523 : : *
524 : : * Names that can be repaired in this manner include:
525 : : * _ALR, _CSD, _HPX, _MLS, _PLD, _PRT, _PSS, _TRT, _TSS,
526 : : * _BCL, _DOD, _FIX, _Sx
527 : : *
528 : : ******************************************************************************/
529 : :
530 : : acpi_status
531 : 0 : acpi_ns_wrap_with_package(struct acpi_evaluate_info *info,
532 : : union acpi_operand_object *original_object,
533 : : union acpi_operand_object **obj_desc_ptr)
534 : : {
535 : 0 : union acpi_operand_object *pkg_obj_desc;
536 : :
537 : 0 : ACPI_FUNCTION_NAME(ns_wrap_with_package);
538 : :
539 : : /*
540 : : * Create the new outer package and populate it. The new
541 : : * package will have a single element, the lone sub-object.
542 : : */
543 : 0 : pkg_obj_desc = acpi_ut_create_package_object(1);
544 [ # # ]: 0 : if (!pkg_obj_desc) {
545 : : return (AE_NO_MEMORY);
546 : : }
547 : :
548 : 0 : pkg_obj_desc->package.elements[0] = original_object;
549 : :
550 : : ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
551 : : "%s: Wrapped %s with expected Package object\n",
552 : : info->full_pathname,
553 : 0 : acpi_ut_get_object_type_name(original_object)));
554 : :
555 : : /* Return the new object in the object pointer */
556 : :
557 : 0 : *obj_desc_ptr = pkg_obj_desc;
558 : 0 : info->return_flags |= ACPI_OBJECT_REPAIRED | ACPI_OBJECT_WRAPPED;
559 : 0 : return (AE_OK);
560 : : }
|