0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #include <acpi/acpi.h>
0012 #include "accommon.h"
0013 #include "acnamesp.h"
0014
0015 #define _COMPONENT ACPI_NAMESPACE
0016 ACPI_MODULE_NAME("nsrepair2")
0017
0018
0019
0020
0021
0022 typedef
0023 acpi_status (*acpi_repair_function) (struct acpi_evaluate_info * info,
0024 union acpi_operand_object **
0025 return_object_ptr);
0026
0027 typedef struct acpi_repair_info {
0028 char name[ACPI_NAMESEG_SIZE];
0029 acpi_repair_function repair_function;
0030
0031 } acpi_repair_info;
0032
0033
0034
0035 static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
0036 acpi_namespace_node
0037 *node);
0038
0039 static acpi_status
0040 acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
0041 union acpi_operand_object **return_object_ptr);
0042
0043 static acpi_status
0044 acpi_ns_repair_CID(struct acpi_evaluate_info *info,
0045 union acpi_operand_object **return_object_ptr);
0046
0047 static acpi_status
0048 acpi_ns_repair_CST(struct acpi_evaluate_info *info,
0049 union acpi_operand_object **return_object_ptr);
0050
0051 static acpi_status
0052 acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
0053 union acpi_operand_object **return_object_ptr);
0054
0055 static acpi_status
0056 acpi_ns_repair_HID(struct acpi_evaluate_info *info,
0057 union acpi_operand_object **return_object_ptr);
0058
0059 static acpi_status
0060 acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
0061 union acpi_operand_object **return_object_ptr);
0062
0063 static acpi_status
0064 acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
0065 union acpi_operand_object **return_object_ptr);
0066
0067 static acpi_status
0068 acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
0069 union acpi_operand_object **return_object_ptr);
0070
0071 static acpi_status
0072 acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
0073 union acpi_operand_object *return_object,
0074 u32 start_index,
0075 u32 expected_count,
0076 u32 sort_index,
0077 u8 sort_direction, char *sort_key_name);
0078
0079
0080
0081 #define ACPI_SORT_ASCENDING 0
0082 #define ACPI_SORT_DESCENDING 1
0083
0084 static void
0085 acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index);
0086
0087 static void
0088 acpi_ns_sort_list(union acpi_operand_object **elements,
0089 u32 count, u32 index, u8 sort_direction);
0090
0091
0092
0093
0094
0095
0096
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107
0108
0109
0110
0111
0112
0113
0114 static const struct acpi_repair_info acpi_ns_repairable_names[] = {
0115 {"_ALR", acpi_ns_repair_ALR},
0116 {"_CID", acpi_ns_repair_CID},
0117 {"_CST", acpi_ns_repair_CST},
0118 {"_FDE", acpi_ns_repair_FDE},
0119 {"_GTM", acpi_ns_repair_FDE},
0120 {"_HID", acpi_ns_repair_HID},
0121 {"_PRT", acpi_ns_repair_PRT},
0122 {"_PSS", acpi_ns_repair_PSS},
0123 {"_TSS", acpi_ns_repair_TSS},
0124 {{0, 0, 0, 0}, NULL}
0125 };
0126
0127 #define ACPI_FDE_FIELD_COUNT 5
0128 #define ACPI_FDE_BYTE_BUFFER_SIZE 5
0129 #define ACPI_FDE_DWORD_BUFFER_SIZE (ACPI_FDE_FIELD_COUNT * (u32) sizeof (u32))
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144
0145
0146
0147
0148
0149 acpi_status
0150 acpi_ns_complex_repairs(struct acpi_evaluate_info *info,
0151 struct acpi_namespace_node *node,
0152 acpi_status validate_status,
0153 union acpi_operand_object **return_object_ptr)
0154 {
0155 const struct acpi_repair_info *predefined;
0156 acpi_status status;
0157
0158 ACPI_FUNCTION_TRACE(ns_complex_repairs);
0159
0160
0161
0162 predefined = acpi_ns_match_complex_repair(node);
0163 if (!predefined) {
0164 return_ACPI_STATUS(validate_status);
0165 }
0166
0167 status = predefined->repair_function(info, return_object_ptr);
0168 return_ACPI_STATUS(status);
0169 }
0170
0171
0172
0173
0174
0175
0176
0177
0178
0179
0180
0181
0182
0183 static const struct acpi_repair_info *acpi_ns_match_complex_repair(struct
0184 acpi_namespace_node
0185 *node)
0186 {
0187 const struct acpi_repair_info *this_name;
0188
0189
0190
0191 this_name = acpi_ns_repairable_names;
0192 while (this_name->repair_function) {
0193 if (ACPI_COMPARE_NAMESEG(node->name.ascii, this_name->name)) {
0194 return (this_name);
0195 }
0196
0197 this_name++;
0198 }
0199
0200 return (NULL);
0201 }
0202
0203
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217
0218 static acpi_status
0219 acpi_ns_repair_ALR(struct acpi_evaluate_info *info,
0220 union acpi_operand_object **return_object_ptr)
0221 {
0222 union acpi_operand_object *return_object = *return_object_ptr;
0223 acpi_status status;
0224
0225 status = acpi_ns_check_sorted_list(info, return_object, 0, 2, 1,
0226 ACPI_SORT_ASCENDING,
0227 "AmbientIlluminance");
0228
0229 return (status);
0230 }
0231
0232
0233
0234
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245
0246
0247
0248
0249 static acpi_status
0250 acpi_ns_repair_FDE(struct acpi_evaluate_info *info,
0251 union acpi_operand_object **return_object_ptr)
0252 {
0253 union acpi_operand_object *return_object = *return_object_ptr;
0254 union acpi_operand_object *buffer_object;
0255 u8 *byte_buffer;
0256 u32 *dword_buffer;
0257 u32 i;
0258
0259 ACPI_FUNCTION_NAME(ns_repair_FDE);
0260
0261 switch (return_object->common.type) {
0262 case ACPI_TYPE_BUFFER:
0263
0264
0265
0266 if (return_object->buffer.length >= ACPI_FDE_DWORD_BUFFER_SIZE) {
0267 return (AE_OK);
0268 }
0269
0270
0271
0272 if (return_object->buffer.length != ACPI_FDE_BYTE_BUFFER_SIZE) {
0273 ACPI_WARN_PREDEFINED((AE_INFO,
0274 info->full_pathname,
0275 info->node_flags,
0276 "Incorrect return buffer length %u, expected %u",
0277 return_object->buffer.length,
0278 ACPI_FDE_DWORD_BUFFER_SIZE));
0279
0280 return (AE_AML_OPERAND_TYPE);
0281 }
0282
0283
0284
0285 buffer_object =
0286 acpi_ut_create_buffer_object(ACPI_FDE_DWORD_BUFFER_SIZE);
0287 if (!buffer_object) {
0288 return (AE_NO_MEMORY);
0289 }
0290
0291
0292
0293 byte_buffer = return_object->buffer.pointer;
0294 dword_buffer = ACPI_CAST_PTR(u32,
0295 buffer_object->buffer.pointer);
0296
0297 for (i = 0; i < ACPI_FDE_FIELD_COUNT; i++) {
0298 *dword_buffer = (u32) *byte_buffer;
0299 dword_buffer++;
0300 byte_buffer++;
0301 }
0302
0303 ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
0304 "%s Expanded Byte Buffer to expected DWord Buffer\n",
0305 info->full_pathname));
0306 break;
0307
0308 default:
0309
0310 return (AE_AML_OPERAND_TYPE);
0311 }
0312
0313
0314
0315 acpi_ut_remove_reference(return_object);
0316 *return_object_ptr = buffer_object;
0317
0318 info->return_flags |= ACPI_OBJECT_REPAIRED;
0319 return (AE_OK);
0320 }
0321
0322
0323
0324
0325
0326
0327
0328
0329
0330
0331
0332
0333
0334
0335
0336
0337
0338 static acpi_status
0339 acpi_ns_repair_CID(struct acpi_evaluate_info *info,
0340 union acpi_operand_object **return_object_ptr)
0341 {
0342 acpi_status status;
0343 union acpi_operand_object *return_object = *return_object_ptr;
0344 union acpi_operand_object **element_ptr;
0345 union acpi_operand_object *original_element;
0346 u16 original_ref_count;
0347 u32 i;
0348
0349 ACPI_FUNCTION_TRACE(ns_repair_CID);
0350
0351
0352
0353 if (return_object->common.type == ACPI_TYPE_STRING) {
0354 status = acpi_ns_repair_HID(info, return_object_ptr);
0355 return_ACPI_STATUS(status);
0356 }
0357
0358
0359
0360 if (return_object->common.type != ACPI_TYPE_PACKAGE) {
0361 return_ACPI_STATUS(AE_OK);
0362 }
0363
0364
0365
0366 element_ptr = return_object->package.elements;
0367 for (i = 0; i < return_object->package.count; i++) {
0368 original_element = *element_ptr;
0369 original_ref_count = original_element->common.reference_count;
0370
0371 status = acpi_ns_repair_HID(info, element_ptr);
0372 if (ACPI_FAILURE(status)) {
0373 return_ACPI_STATUS(status);
0374 }
0375
0376 if (original_element != *element_ptr) {
0377
0378
0379
0380 (*element_ptr)->common.reference_count =
0381 original_ref_count;
0382 }
0383
0384 element_ptr++;
0385 }
0386
0387 return_ACPI_STATUS(AE_OK);
0388 }
0389
0390
0391
0392
0393
0394
0395
0396
0397
0398
0399
0400
0401
0402
0403
0404
0405
0406
0407
0408 static acpi_status
0409 acpi_ns_repair_CST(struct acpi_evaluate_info *info,
0410 union acpi_operand_object **return_object_ptr)
0411 {
0412 union acpi_operand_object *return_object = *return_object_ptr;
0413 union acpi_operand_object **outer_elements;
0414 u32 outer_element_count;
0415 union acpi_operand_object *obj_desc;
0416 acpi_status status;
0417 u8 removing;
0418 u32 i;
0419
0420 ACPI_FUNCTION_NAME(ns_repair_CST);
0421
0422
0423
0424
0425 outer_element_count = return_object->package.count - 1;
0426 i = 0;
0427 while (i < outer_element_count) {
0428 outer_elements = &return_object->package.elements[i + 1];
0429 removing = FALSE;
0430
0431 if ((*outer_elements)->package.count == 0) {
0432 ACPI_WARN_PREDEFINED((AE_INFO,
0433 info->full_pathname,
0434 info->node_flags,
0435 "SubPackage[%u] - removing entry due to zero count",
0436 i));
0437 removing = TRUE;
0438 goto remove_element;
0439 }
0440
0441 obj_desc = (*outer_elements)->package.elements[1];
0442 if ((u32)obj_desc->integer.value == 0) {
0443 ACPI_WARN_PREDEFINED((AE_INFO,
0444 info->full_pathname,
0445 info->node_flags,
0446 "SubPackage[%u] - removing entry due to invalid Type(0)",
0447 i));
0448 removing = TRUE;
0449 }
0450
0451 remove_element:
0452 if (removing) {
0453 acpi_ns_remove_element(return_object, i + 1);
0454 outer_element_count--;
0455 } else {
0456 i++;
0457 }
0458 }
0459
0460
0461
0462 obj_desc = return_object->package.elements[0];
0463 obj_desc->integer.value = outer_element_count;
0464
0465
0466
0467
0468
0469 status = acpi_ns_check_sorted_list(info, return_object, 1, 4, 1,
0470 ACPI_SORT_ASCENDING, "C-State Type");
0471 if (ACPI_FAILURE(status)) {
0472 return (status);
0473 }
0474
0475 return (AE_OK);
0476 }
0477
0478
0479
0480
0481
0482
0483
0484
0485
0486
0487
0488
0489
0490
0491
0492
0493 static acpi_status
0494 acpi_ns_repair_HID(struct acpi_evaluate_info *info,
0495 union acpi_operand_object **return_object_ptr)
0496 {
0497 union acpi_operand_object *return_object = *return_object_ptr;
0498 union acpi_operand_object *new_string;
0499 char *source;
0500 char *dest;
0501
0502 ACPI_FUNCTION_NAME(ns_repair_HID);
0503
0504
0505
0506 if (return_object->common.type != ACPI_TYPE_STRING) {
0507 return_ACPI_STATUS(AE_OK);
0508 }
0509
0510 if (return_object->string.length == 0) {
0511 ACPI_WARN_PREDEFINED((AE_INFO,
0512 info->full_pathname, info->node_flags,
0513 "Invalid zero-length _HID or _CID string"));
0514
0515
0516
0517 info->return_flags |= ACPI_OBJECT_REPAIRED;
0518 return_ACPI_STATUS(AE_OK);
0519 }
0520
0521
0522
0523 new_string = acpi_ut_create_string_object(return_object->string.length);
0524 if (!new_string) {
0525 return_ACPI_STATUS(AE_NO_MEMORY);
0526 }
0527
0528
0529
0530
0531
0532
0533
0534 source = return_object->string.pointer;
0535 if (*source == '*') {
0536 source++;
0537 new_string->string.length--;
0538
0539 ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
0540 "%s: Removed invalid leading asterisk\n",
0541 info->full_pathname));
0542 }
0543
0544
0545
0546
0547
0548
0549
0550
0551
0552 for (dest = new_string->string.pointer; *source; dest++, source++) {
0553 *dest = (char)toupper((int)*source);
0554 }
0555
0556 acpi_ut_remove_reference(return_object);
0557 *return_object_ptr = new_string;
0558 return_ACPI_STATUS(AE_OK);
0559 }
0560
0561
0562
0563
0564
0565
0566
0567
0568
0569
0570
0571
0572
0573
0574
0575
0576 static acpi_status
0577 acpi_ns_repair_PRT(struct acpi_evaluate_info *info,
0578 union acpi_operand_object **return_object_ptr)
0579 {
0580 union acpi_operand_object *package_object = *return_object_ptr;
0581 union acpi_operand_object **top_object_list;
0582 union acpi_operand_object **sub_object_list;
0583 union acpi_operand_object *obj_desc;
0584 union acpi_operand_object *sub_package;
0585 u32 element_count;
0586 u32 index;
0587
0588
0589
0590 top_object_list = package_object->package.elements;
0591 element_count = package_object->package.count;
0592
0593
0594
0595 for (index = 0; index < element_count; index++, top_object_list++) {
0596 sub_package = *top_object_list;
0597 sub_object_list = sub_package->package.elements;
0598
0599
0600
0601 if (sub_package->package.count < 4) {
0602 continue;
0603 }
0604
0605
0606
0607
0608
0609
0610
0611 obj_desc = sub_object_list[3];
0612 if (!obj_desc || (obj_desc->common.type != ACPI_TYPE_INTEGER)) {
0613 sub_object_list[3] = sub_object_list[2];
0614 sub_object_list[2] = obj_desc;
0615 info->return_flags |= ACPI_OBJECT_REPAIRED;
0616
0617 ACPI_WARN_PREDEFINED((AE_INFO,
0618 info->full_pathname,
0619 info->node_flags,
0620 "PRT[%X]: Fixed reversed SourceName and SourceIndex",
0621 index));
0622 }
0623 }
0624
0625 return (AE_OK);
0626 }
0627
0628
0629
0630
0631
0632
0633
0634
0635
0636
0637
0638
0639
0640
0641
0642
0643
0644
0645 static acpi_status
0646 acpi_ns_repair_PSS(struct acpi_evaluate_info *info,
0647 union acpi_operand_object **return_object_ptr)
0648 {
0649 union acpi_operand_object *return_object = *return_object_ptr;
0650 union acpi_operand_object **outer_elements;
0651 u32 outer_element_count;
0652 union acpi_operand_object **elements;
0653 union acpi_operand_object *obj_desc;
0654 u32 previous_value;
0655 acpi_status status;
0656 u32 i;
0657
0658
0659
0660
0661
0662
0663
0664 status = acpi_ns_check_sorted_list(info, return_object, 0, 6, 0,
0665 ACPI_SORT_DESCENDING,
0666 "CpuFrequency");
0667 if (ACPI_FAILURE(status)) {
0668 return (status);
0669 }
0670
0671
0672
0673
0674
0675 previous_value = ACPI_UINT32_MAX;
0676 outer_elements = return_object->package.elements;
0677 outer_element_count = return_object->package.count;
0678
0679 for (i = 0; i < outer_element_count; i++) {
0680 elements = (*outer_elements)->package.elements;
0681 obj_desc = elements[1];
0682
0683 if ((u32)obj_desc->integer.value > previous_value) {
0684 ACPI_WARN_PREDEFINED((AE_INFO,
0685 info->full_pathname,
0686 info->node_flags,
0687 "SubPackage[%u,%u] - suspicious power dissipation values",
0688 i - 1, i));
0689 }
0690
0691 previous_value = (u32) obj_desc->integer.value;
0692 outer_elements++;
0693 }
0694
0695 return (AE_OK);
0696 }
0697
0698
0699
0700
0701
0702
0703
0704
0705
0706
0707
0708
0709
0710
0711
0712
0713 static acpi_status
0714 acpi_ns_repair_TSS(struct acpi_evaluate_info *info,
0715 union acpi_operand_object **return_object_ptr)
0716 {
0717 union acpi_operand_object *return_object = *return_object_ptr;
0718 acpi_status status;
0719 struct acpi_namespace_node *node;
0720
0721
0722
0723
0724
0725
0726
0727
0728
0729 status = acpi_ns_get_node(info->node, "^_PSS",
0730 ACPI_NS_NO_UPSEARCH, &node);
0731 if (ACPI_SUCCESS(status)) {
0732 return (AE_OK);
0733 }
0734
0735 status = acpi_ns_check_sorted_list(info, return_object, 0, 5, 1,
0736 ACPI_SORT_DESCENDING,
0737 "PowerDissipation");
0738
0739 return (status);
0740 }
0741
0742
0743
0744
0745
0746
0747
0748
0749
0750
0751
0752
0753
0754
0755
0756
0757
0758
0759
0760
0761
0762 static acpi_status
0763 acpi_ns_check_sorted_list(struct acpi_evaluate_info *info,
0764 union acpi_operand_object *return_object,
0765 u32 start_index,
0766 u32 expected_count,
0767 u32 sort_index,
0768 u8 sort_direction, char *sort_key_name)
0769 {
0770 u32 outer_element_count;
0771 union acpi_operand_object **outer_elements;
0772 union acpi_operand_object **elements;
0773 union acpi_operand_object *obj_desc;
0774 u32 i;
0775 u32 previous_value;
0776
0777 ACPI_FUNCTION_NAME(ns_check_sorted_list);
0778
0779
0780
0781 if (return_object->common.type != ACPI_TYPE_PACKAGE) {
0782 return (AE_AML_OPERAND_TYPE);
0783 }
0784
0785
0786
0787
0788
0789
0790 outer_element_count = return_object->package.count;
0791 if (!outer_element_count || start_index >= outer_element_count) {
0792 return (AE_AML_PACKAGE_LIMIT);
0793 }
0794
0795 outer_elements = &return_object->package.elements[start_index];
0796 outer_element_count -= start_index;
0797
0798 previous_value = 0;
0799 if (sort_direction == ACPI_SORT_DESCENDING) {
0800 previous_value = ACPI_UINT32_MAX;
0801 }
0802
0803
0804
0805 for (i = 0; i < outer_element_count; i++) {
0806
0807
0808
0809 if ((*outer_elements)->common.type != ACPI_TYPE_PACKAGE) {
0810 return (AE_AML_OPERAND_TYPE);
0811 }
0812
0813
0814
0815 if ((*outer_elements)->package.count < expected_count) {
0816 return (AE_AML_PACKAGE_LIMIT);
0817 }
0818
0819 elements = (*outer_elements)->package.elements;
0820 obj_desc = elements[sort_index];
0821
0822 if (obj_desc->common.type != ACPI_TYPE_INTEGER) {
0823 return (AE_AML_OPERAND_TYPE);
0824 }
0825
0826
0827
0828
0829
0830 if (((sort_direction == ACPI_SORT_ASCENDING) &&
0831 (obj_desc->integer.value < previous_value)) ||
0832 ((sort_direction == ACPI_SORT_DESCENDING) &&
0833 (obj_desc->integer.value > previous_value))) {
0834 acpi_ns_sort_list(&return_object->package.
0835 elements[start_index],
0836 outer_element_count, sort_index,
0837 sort_direction);
0838
0839 info->return_flags |= ACPI_OBJECT_REPAIRED;
0840
0841 ACPI_DEBUG_PRINT((ACPI_DB_REPAIR,
0842 "%s: Repaired unsorted list - now sorted by %s\n",
0843 info->full_pathname, sort_key_name));
0844 return (AE_OK);
0845 }
0846
0847 previous_value = (u32) obj_desc->integer.value;
0848 outer_elements++;
0849 }
0850
0851 return (AE_OK);
0852 }
0853
0854
0855
0856
0857
0858
0859
0860
0861
0862
0863
0864
0865
0866
0867
0868
0869
0870
0871
0872 static void
0873 acpi_ns_sort_list(union acpi_operand_object **elements,
0874 u32 count, u32 index, u8 sort_direction)
0875 {
0876 union acpi_operand_object *obj_desc1;
0877 union acpi_operand_object *obj_desc2;
0878 union acpi_operand_object *temp_obj;
0879 u32 i;
0880 u32 j;
0881
0882
0883
0884 for (i = 1; i < count; i++) {
0885 for (j = (count - 1); j >= i; j--) {
0886 obj_desc1 = elements[j - 1]->package.elements[index];
0887 obj_desc2 = elements[j]->package.elements[index];
0888
0889 if (((sort_direction == ACPI_SORT_ASCENDING) &&
0890 (obj_desc1->integer.value >
0891 obj_desc2->integer.value))
0892 || ((sort_direction == ACPI_SORT_DESCENDING)
0893 && (obj_desc1->integer.value <
0894 obj_desc2->integer.value))) {
0895 temp_obj = elements[j - 1];
0896 elements[j - 1] = elements[j];
0897 elements[j] = temp_obj;
0898 }
0899 }
0900 }
0901 }
0902
0903
0904
0905
0906
0907
0908
0909
0910
0911
0912
0913
0914
0915
0916 static void
0917 acpi_ns_remove_element(union acpi_operand_object *obj_desc, u32 index)
0918 {
0919 union acpi_operand_object **source;
0920 union acpi_operand_object **dest;
0921 u32 count;
0922 u32 new_count;
0923 u32 i;
0924
0925 ACPI_FUNCTION_NAME(ns_remove_element);
0926
0927 count = obj_desc->package.count;
0928 new_count = count - 1;
0929
0930 source = obj_desc->package.elements;
0931 dest = source;
0932
0933
0934
0935 for (i = 0; i < count; i++) {
0936 if (i == index) {
0937 acpi_ut_remove_reference(*source);
0938 acpi_ut_remove_reference(*source);
0939 } else {
0940 *dest = *source;
0941 dest++;
0942 }
0943
0944 source++;
0945 }
0946
0947
0948
0949 *dest = NULL;
0950 obj_desc->package.count = new_count;
0951 }