1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Common methods for use with hp-bioscfg driver 4 * 5 * Copyright (c) 2022 HP Development Company, L.P. 6 */ 7 8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 9 10 #include <linux/fs.h> 11 #include <linux/module.h> 12 #include <linux/kernel.h> 13 #include <linux/wmi.h> 14 #include "bioscfg.h" 15 #include "../../firmware_attributes_class.h" 16 #include <linux/nls.h> 17 #include <linux/errno.h> 18 19 MODULE_AUTHOR("Jorge Lopez <jorge.lopez2@hp.com>"); 20 MODULE_DESCRIPTION("HP BIOS Configuration Driver"); 21 MODULE_LICENSE("GPL"); 22 23 struct bioscfg_priv bioscfg_drv = { 24 .mutex = __MUTEX_INITIALIZER(bioscfg_drv.mutex), 25 }; 26 27 static const struct class *fw_attr_class; 28 29 ssize_t display_name_language_code_show(struct kobject *kobj, 30 struct kobj_attribute *attr, 31 char *buf) 32 { 33 return sysfs_emit(buf, "%s\n", LANG_CODE_STR); 34 } 35 36 struct kobj_attribute common_display_langcode = 37 __ATTR_RO(display_name_language_code); 38 39 int hp_get_integer_from_buffer(u8 **buffer, u32 *buffer_size, u32 *integer) 40 { 41 int *ptr = PTR_ALIGN((int *)*buffer, sizeof(int)); 42 43 /* Ensure there is enough space remaining to read the integer */ 44 if (*buffer_size < sizeof(int)) 45 return -EINVAL; 46 47 *integer = *(ptr++); 48 *buffer = (u8 *)ptr; 49 *buffer_size -= sizeof(int); 50 51 return 0; 52 } 53 54 int hp_get_string_from_buffer(u8 **buffer, u32 *buffer_size, char *dst, u32 dst_size) 55 { 56 u16 *src = (u16 *)*buffer; 57 u16 src_size; 58 59 u16 size; 60 int i; 61 int conv_dst_size; 62 63 if (*buffer_size < sizeof(u16)) 64 return -EINVAL; 65 66 src_size = *(src++); 67 /* size value in u16 chars */ 68 size = src_size / sizeof(u16); 69 70 /* Ensure there is enough space remaining to read and convert 71 * the string 72 */ 73 if (*buffer_size < src_size) 74 return -EINVAL; 75 76 for (i = 0; i < size; i++) 77 if (src[i] == '\\' || 78 src[i] == '\r' || 79 src[i] == '\n' || 80 src[i] == '\t') 81 size++; 82 83 /* 84 * Conversion is limited to destination string max number of 85 * bytes. 86 */ 87 conv_dst_size = size; 88 if (size > dst_size) 89 conv_dst_size = dst_size - 1; 90 91 /* 92 * convert from UTF-16 unicode to ASCII 93 */ 94 utf16s_to_utf8s(src, src_size, UTF16_HOST_ENDIAN, dst, conv_dst_size); 95 dst[conv_dst_size] = 0; 96 97 for (i = 0; i < conv_dst_size; i++) { 98 if (*src == '\\' || 99 *src == '\r' || 100 *src == '\n' || 101 *src == '\t') { 102 dst[i++] = '\\'; 103 if (i == conv_dst_size) 104 break; 105 } 106 107 if (*src == '\r') 108 dst[i] = 'r'; 109 else if (*src == '\n') 110 dst[i] = 'n'; 111 else if (*src == '\t') 112 dst[i] = 't'; 113 else if (*src == '"') 114 dst[i] = '\''; 115 else 116 dst[i] = *src; 117 src++; 118 } 119 120 *buffer = (u8 *)src; 121 *buffer_size -= size * sizeof(u16); 122 123 return size; 124 } 125 126 int hp_get_common_data_from_buffer(u8 **buffer_ptr, u32 *buffer_size, 127 struct common_data *common_data) 128 { 129 int ret = 0; 130 int reqs; 131 132 // PATH: 133 ret = hp_get_string_from_buffer(buffer_ptr, buffer_size, common_data->path, 134 sizeof(common_data->path)); 135 if (ret < 0) 136 goto common_exit; 137 138 // IS_READONLY: 139 ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size, 140 &common_data->is_readonly); 141 if (ret < 0) 142 goto common_exit; 143 144 //DISPLAY_IN_UI: 145 ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size, 146 &common_data->display_in_ui); 147 if (ret < 0) 148 goto common_exit; 149 150 // REQUIRES_PHYSICAL_PRESENCE: 151 ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size, 152 &common_data->requires_physical_presence); 153 if (ret < 0) 154 goto common_exit; 155 156 // SEQUENCE: 157 ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size, 158 &common_data->sequence); 159 if (ret < 0) 160 goto common_exit; 161 162 // PREREQUISITES_SIZE: 163 ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size, 164 &common_data->prerequisites_size); 165 if (ret < 0) 166 goto common_exit; 167 168 if (common_data->prerequisites_size > MAX_PREREQUISITES_SIZE) { 169 /* Report a message and limit prerequisite size to maximum value */ 170 pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n"); 171 common_data->prerequisites_size = MAX_PREREQUISITES_SIZE; 172 } 173 174 // PREREQUISITES: 175 for (reqs = 0; reqs < common_data->prerequisites_size; reqs++) { 176 ret = hp_get_string_from_buffer(buffer_ptr, buffer_size, 177 common_data->prerequisites[reqs], 178 sizeof(common_data->prerequisites[reqs])); 179 if (ret < 0) 180 break; 181 } 182 183 // SECURITY_LEVEL: 184 ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size, 185 &common_data->security_level); 186 187 common_exit: 188 return ret; 189 } 190 191 int hp_enforce_single_line_input(char *buf, size_t count) 192 { 193 char *p; 194 195 p = memchr(buf, '\n', count); 196 197 if (p == buf + count - 1) 198 *p = '\0'; /* strip trailing newline */ 199 else if (p) 200 return -EINVAL; /* enforce single line input */ 201 202 return 0; 203 } 204 205 /* Set pending reboot value and generate KOBJ_NAME event */ 206 void hp_set_reboot_and_signal_event(void) 207 { 208 bioscfg_drv.pending_reboot = true; 209 kobject_uevent(&bioscfg_drv.class_dev->kobj, KOBJ_CHANGE); 210 } 211 212 /** 213 * hp_calculate_string_buffer() - determines size of string buffer for 214 * use with BIOS communication 215 * 216 * @str: the string to calculate based upon 217 */ 218 size_t hp_calculate_string_buffer(const char *str) 219 { 220 size_t length = strlen(str); 221 222 /* BIOS expects 4 bytes when an empty string is found */ 223 if (length == 0) 224 return 4; 225 226 /* u16 length field + one UTF16 char for each input char */ 227 return sizeof(u16) + strlen(str) * sizeof(u16); 228 } 229 230 int hp_wmi_error_and_message(int error_code) 231 { 232 char *error_msg = NULL; 233 int ret; 234 235 switch (error_code) { 236 case SUCCESS: 237 error_msg = "Success"; 238 ret = 0; 239 break; 240 case CMD_FAILED: 241 error_msg = "Command failed"; 242 ret = -EINVAL; 243 break; 244 case INVALID_SIGN: 245 error_msg = "Invalid signature"; 246 ret = -EINVAL; 247 break; 248 case INVALID_CMD_VALUE: 249 error_msg = "Invalid command value/Feature not supported"; 250 ret = -EOPNOTSUPP; 251 break; 252 case INVALID_CMD_TYPE: 253 error_msg = "Invalid command type"; 254 ret = -EINVAL; 255 break; 256 case INVALID_DATA_SIZE: 257 error_msg = "Invalid data size"; 258 ret = -EINVAL; 259 break; 260 case INVALID_CMD_PARAM: 261 error_msg = "Invalid command parameter"; 262 ret = -EINVAL; 263 break; 264 case ENCRYP_CMD_REQUIRED: 265 error_msg = "Secure/encrypted command required"; 266 ret = -EACCES; 267 break; 268 case NO_SECURE_SESSION: 269 error_msg = "No secure session established"; 270 ret = -EACCES; 271 break; 272 case SECURE_SESSION_FOUND: 273 error_msg = "Secure session already established"; 274 ret = -EACCES; 275 break; 276 case SECURE_SESSION_FAILED: 277 error_msg = "Secure session failed"; 278 ret = -EIO; 279 break; 280 case AUTH_FAILED: 281 error_msg = "Other permission/Authentication failed"; 282 ret = -EACCES; 283 break; 284 case INVALID_BIOS_AUTH: 285 error_msg = "Invalid BIOS administrator password"; 286 ret = -EINVAL; 287 break; 288 case NONCE_DID_NOT_MATCH: 289 error_msg = "Nonce did not match"; 290 ret = -EINVAL; 291 break; 292 case GENERIC_ERROR: 293 error_msg = "Generic/Other error"; 294 ret = -EIO; 295 break; 296 case BIOS_ADMIN_POLICY_NOT_MET: 297 error_msg = "BIOS Admin password does not meet password policy requirements"; 298 ret = -EINVAL; 299 break; 300 case BIOS_ADMIN_NOT_SET: 301 error_msg = "BIOS Setup password is not set"; 302 ret = -EPERM; 303 break; 304 case P21_NO_PROVISIONED: 305 error_msg = "P21 is not provisioned"; 306 ret = -EPERM; 307 break; 308 case P21_PROVISION_IN_PROGRESS: 309 error_msg = "P21 is already provisioned or provisioning is in progress and a signing key has already been sent"; 310 ret = -EINPROGRESS; 311 break; 312 case P21_IN_USE: 313 error_msg = "P21 in use (cannot deprovision)"; 314 ret = -EPERM; 315 break; 316 case HEP_NOT_ACTIVE: 317 error_msg = "HEP not activated"; 318 ret = -EPERM; 319 break; 320 case HEP_ALREADY_SET: 321 error_msg = "HEP Transport already set"; 322 ret = -EINVAL; 323 break; 324 case HEP_CHECK_STATE: 325 error_msg = "Check the current HEP state"; 326 ret = -EINVAL; 327 break; 328 default: 329 error_msg = "Generic/Other error"; 330 ret = -EIO; 331 break; 332 } 333 334 if (error_code) 335 pr_warn_ratelimited("Returned error 0x%x, \"%s\"\n", error_code, error_msg); 336 337 return ret; 338 } 339 340 static ssize_t pending_reboot_show(struct kobject *kobj, 341 struct kobj_attribute *attr, 342 char *buf) 343 { 344 return sysfs_emit(buf, "%d\n", bioscfg_drv.pending_reboot); 345 } 346 347 static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot); 348 349 /* 350 * create_attributes_level_sysfs_files() - Creates pending_reboot attributes 351 */ 352 static int create_attributes_level_sysfs_files(void) 353 { 354 return sysfs_create_file(&bioscfg_drv.main_dir_kset->kobj, 355 &pending_reboot.attr); 356 } 357 358 static void attr_name_release(struct kobject *kobj) 359 { 360 kfree(kobj); 361 } 362 363 static const struct kobj_type attr_name_ktype = { 364 .release = attr_name_release, 365 .sysfs_ops = &kobj_sysfs_ops, 366 }; 367 368 /** 369 * hp_get_wmiobj_pointer() - Get Content of WMI block for particular instance 370 * 371 * @instance_id: WMI instance ID 372 * @guid_string: WMI GUID (in str form) 373 * 374 * Fetches the content for WMI block (instance_id) under GUID (guid_string) 375 * Caller must kfree the return 376 */ 377 union acpi_object *hp_get_wmiobj_pointer(int instance_id, const char *guid_string) 378 { 379 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 380 acpi_status status; 381 382 status = wmi_query_block(guid_string, instance_id, &out); 383 return ACPI_SUCCESS(status) ? (union acpi_object *)out.pointer : NULL; 384 } 385 386 /** 387 * hp_get_instance_count() - Compute total number of instances under guid_string 388 * 389 * @guid_string: WMI GUID (in string form) 390 */ 391 int hp_get_instance_count(const char *guid_string) 392 { 393 union acpi_object *wmi_obj = NULL; 394 int i = 0; 395 396 do { 397 kfree(wmi_obj); 398 wmi_obj = hp_get_wmiobj_pointer(i, guid_string); 399 i++; 400 } while (wmi_obj); 401 402 return i - 1; 403 } 404 405 /** 406 * hp_alloc_attributes_data() - Allocate attributes data for a particular type 407 * 408 * @attr_type: Attribute type to allocate 409 */ 410 static int hp_alloc_attributes_data(int attr_type) 411 { 412 switch (attr_type) { 413 case HPWMI_STRING_TYPE: 414 return hp_alloc_string_data(); 415 416 case HPWMI_INTEGER_TYPE: 417 return hp_alloc_integer_data(); 418 419 case HPWMI_ENUMERATION_TYPE: 420 return hp_alloc_enumeration_data(); 421 422 case HPWMI_ORDERED_LIST_TYPE: 423 return hp_alloc_ordered_list_data(); 424 425 case HPWMI_PASSWORD_TYPE: 426 return hp_alloc_password_data(); 427 428 default: 429 return 0; 430 } 431 } 432 433 int hp_convert_hexstr_to_str(const char *input, u32 input_len, char **str, int *len) 434 { 435 int ret = 0; 436 int new_len = 0; 437 char tmp[] = "0x00"; 438 char *new_str = NULL; 439 long ch; 440 int i; 441 442 if (input_len <= 0 || !input || !str || !len) 443 return -EINVAL; 444 445 *len = 0; 446 *str = NULL; 447 448 new_str = kmalloc(input_len, GFP_KERNEL); 449 if (!new_str) 450 return -ENOMEM; 451 452 for (i = 0; i < input_len; i += 5) { 453 strncpy(tmp, input + i, strlen(tmp)); 454 if (kstrtol(tmp, 16, &ch) == 0) { 455 // escape char 456 if (ch == '\\' || 457 ch == '\r' || 458 ch == '\n' || ch == '\t') { 459 if (ch == '\r') 460 ch = 'r'; 461 else if (ch == '\n') 462 ch = 'n'; 463 else if (ch == '\t') 464 ch = 't'; 465 new_str[new_len++] = '\\'; 466 } 467 new_str[new_len++] = ch; 468 if (ch == '\0') 469 break; 470 } 471 } 472 473 if (new_len) { 474 new_str[new_len] = '\0'; 475 *str = krealloc(new_str, (new_len + 1) * sizeof(char), 476 GFP_KERNEL); 477 if (*str) 478 *len = new_len; 479 else 480 ret = -ENOMEM; 481 } else { 482 ret = -EFAULT; 483 } 484 485 if (ret) 486 kfree(new_str); 487 return ret; 488 } 489 490 /* map output size to the corresponding WMI method id */ 491 int hp_encode_outsize_for_pvsz(int outsize) 492 { 493 if (outsize > 4096) 494 return -EINVAL; 495 if (outsize > 1024) 496 return 5; 497 if (outsize > 128) 498 return 4; 499 if (outsize > 4) 500 return 3; 501 if (outsize > 0) 502 return 2; 503 return 1; 504 } 505 506 /* 507 * Update friendly display name for several attributes associated to 508 * 'Schedule Power-On' 509 */ 510 void hp_friendly_user_name_update(char *path, const char *attr_name, 511 char *attr_display, int attr_size) 512 { 513 if (strstr(path, SCHEDULE_POWER_ON)) 514 snprintf(attr_display, attr_size, "%s - %s", SCHEDULE_POWER_ON, attr_name); 515 else 516 strscpy(attr_display, attr_name, attr_size); 517 } 518 519 /** 520 * hp_update_attribute_permissions() - Update attributes permissions when 521 * isReadOnly value is 1 522 * 523 * @is_readonly: bool value to indicate if it a readonly attribute. 524 * @current_val: kobj_attribute corresponding to attribute. 525 * 526 */ 527 void hp_update_attribute_permissions(bool is_readonly, struct kobj_attribute *current_val) 528 { 529 current_val->attr.mode = is_readonly ? 0444 : 0644; 530 } 531 532 /** 533 * destroy_attribute_objs() - Free a kset of kobjects 534 * @kset: The kset to destroy 535 * 536 * Fress kobjects created for each attribute_name under attribute type kset 537 */ 538 static void destroy_attribute_objs(struct kset *kset) 539 { 540 struct kobject *pos, *next; 541 542 list_for_each_entry_safe(pos, next, &kset->list, entry) 543 kobject_put(pos); 544 } 545 546 /** 547 * release_attributes_data() - Clean-up all sysfs directories and files created 548 */ 549 static void release_attributes_data(void) 550 { 551 mutex_lock(&bioscfg_drv.mutex); 552 553 hp_exit_string_attributes(); 554 hp_exit_integer_attributes(); 555 hp_exit_enumeration_attributes(); 556 hp_exit_ordered_list_attributes(); 557 hp_exit_password_attributes(); 558 hp_exit_sure_start_attributes(); 559 hp_exit_secure_platform_attributes(); 560 561 if (bioscfg_drv.authentication_dir_kset) { 562 destroy_attribute_objs(bioscfg_drv.authentication_dir_kset); 563 kset_unregister(bioscfg_drv.authentication_dir_kset); 564 bioscfg_drv.authentication_dir_kset = NULL; 565 } 566 if (bioscfg_drv.main_dir_kset) { 567 sysfs_remove_file(&bioscfg_drv.main_dir_kset->kobj, &pending_reboot.attr); 568 destroy_attribute_objs(bioscfg_drv.main_dir_kset); 569 kset_unregister(bioscfg_drv.main_dir_kset); 570 bioscfg_drv.main_dir_kset = NULL; 571 } 572 mutex_unlock(&bioscfg_drv.mutex); 573 } 574 575 /** 576 * hp_add_other_attributes() - Initialize HP custom attributes not 577 * reported by BIOS and required to support Secure Platform and Sure 578 * Start. 579 * 580 * @attr_type: Custom HP attribute not reported by BIOS 581 * 582 * Initialize all 2 types of attributes: Platform and Sure Start 583 * object. Populates each attribute types respective properties 584 * under sysfs files. 585 * 586 * Returns zero(0) if successful. Otherwise, a negative value. 587 */ 588 static int hp_add_other_attributes(int attr_type) 589 { 590 struct kobject *attr_name_kobj; 591 int ret; 592 char *attr_name; 593 594 attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL); 595 if (!attr_name_kobj) 596 return -ENOMEM; 597 598 mutex_lock(&bioscfg_drv.mutex); 599 600 /* Check if attribute type is supported */ 601 switch (attr_type) { 602 case HPWMI_SECURE_PLATFORM_TYPE: 603 attr_name_kobj->kset = bioscfg_drv.authentication_dir_kset; 604 attr_name = SPM_STR; 605 break; 606 607 case HPWMI_SURE_START_TYPE: 608 attr_name_kobj->kset = bioscfg_drv.main_dir_kset; 609 attr_name = SURE_START_STR; 610 break; 611 612 default: 613 pr_err("Error: Unknown attr_type: %d\n", attr_type); 614 ret = -EINVAL; 615 kfree(attr_name_kobj); 616 goto unlock_drv_mutex; 617 } 618 619 ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype, 620 NULL, "%s", attr_name); 621 if (ret) { 622 pr_err("Error encountered [%d]\n", ret); 623 goto err_other_attr_init; 624 } 625 626 /* Populate attribute data */ 627 switch (attr_type) { 628 case HPWMI_SECURE_PLATFORM_TYPE: 629 ret = hp_populate_secure_platform_data(attr_name_kobj); 630 break; 631 632 case HPWMI_SURE_START_TYPE: 633 ret = hp_populate_sure_start_data(attr_name_kobj); 634 break; 635 636 default: 637 ret = -EINVAL; 638 } 639 640 if (ret) 641 goto err_other_attr_init; 642 643 mutex_unlock(&bioscfg_drv.mutex); 644 return 0; 645 646 err_other_attr_init: 647 kobject_put(attr_name_kobj); 648 unlock_drv_mutex: 649 mutex_unlock(&bioscfg_drv.mutex); 650 return ret; 651 } 652 653 static int hp_init_bios_package_attribute(enum hp_wmi_data_type attr_type, 654 union acpi_object *obj, 655 const char *guid, int min_elements, 656 int instance_id) 657 { 658 struct kobject *attr_name_kobj, *duplicate; 659 union acpi_object *elements; 660 struct kset *temp_kset; 661 662 char *str_value = NULL; 663 int str_len; 664 int ret = 0; 665 666 /* Take action appropriate to each ACPI TYPE */ 667 if (obj->package.count < min_elements) { 668 pr_err("ACPI-package does not have enough elements: %d < %d\n", 669 obj->package.count, min_elements); 670 goto pack_attr_exit; 671 } 672 673 elements = obj->package.elements; 674 675 /* sanity checking */ 676 if (elements[NAME].type != ACPI_TYPE_STRING) { 677 pr_debug("incorrect element type\n"); 678 goto pack_attr_exit; 679 } 680 if (strlen(elements[NAME].string.pointer) == 0) { 681 pr_debug("empty attribute found\n"); 682 goto pack_attr_exit; 683 } 684 685 if (attr_type == HPWMI_PASSWORD_TYPE) 686 temp_kset = bioscfg_drv.authentication_dir_kset; 687 else 688 temp_kset = bioscfg_drv.main_dir_kset; 689 690 /* convert attribute name to string */ 691 ret = hp_convert_hexstr_to_str(elements[NAME].string.pointer, 692 elements[NAME].string.length, 693 &str_value, &str_len); 694 695 if (ret) { 696 pr_debug("Failed to populate integer package data. Error [0%0x]\n", 697 ret); 698 kfree(str_value); 699 return ret; 700 } 701 702 /* All duplicate attributes found are ignored */ 703 duplicate = kset_find_obj(temp_kset, str_value); 704 if (duplicate) { 705 pr_debug("Duplicate attribute name found - %s\n", str_value); 706 /* kset_find_obj() returns a reference */ 707 kobject_put(duplicate); 708 goto pack_attr_exit; 709 } 710 711 /* build attribute */ 712 attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL); 713 if (!attr_name_kobj) { 714 ret = -ENOMEM; 715 goto pack_attr_exit; 716 } 717 718 attr_name_kobj->kset = temp_kset; 719 720 ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype, 721 NULL, "%s", str_value); 722 723 if (ret) { 724 kobject_put(attr_name_kobj); 725 goto pack_attr_exit; 726 } 727 728 /* enumerate all of these attributes */ 729 switch (attr_type) { 730 case HPWMI_STRING_TYPE: 731 ret = hp_populate_string_package_data(elements, 732 instance_id, 733 attr_name_kobj); 734 break; 735 case HPWMI_INTEGER_TYPE: 736 ret = hp_populate_integer_package_data(elements, 737 instance_id, 738 attr_name_kobj); 739 break; 740 case HPWMI_ENUMERATION_TYPE: 741 ret = hp_populate_enumeration_package_data(elements, 742 instance_id, 743 attr_name_kobj); 744 break; 745 case HPWMI_ORDERED_LIST_TYPE: 746 ret = hp_populate_ordered_list_package_data(elements, 747 instance_id, 748 attr_name_kobj); 749 break; 750 case HPWMI_PASSWORD_TYPE: 751 ret = hp_populate_password_package_data(elements, 752 instance_id, 753 attr_name_kobj); 754 break; 755 default: 756 pr_debug("Unknown attribute type found: 0x%x\n", attr_type); 757 break; 758 } 759 760 pack_attr_exit: 761 kfree(str_value); 762 return ret; 763 } 764 765 static int hp_init_bios_buffer_attribute(enum hp_wmi_data_type attr_type, 766 union acpi_object *obj, 767 const char *guid, int min_elements, 768 int instance_id) 769 { 770 struct kobject *attr_name_kobj, *duplicate; 771 struct kset *temp_kset; 772 char str[MAX_BUFF_SIZE]; 773 774 char *temp_str = NULL; 775 char *str_value = NULL; 776 u8 *buffer_ptr = NULL; 777 int buffer_size; 778 int ret = 0; 779 780 buffer_size = obj->buffer.length; 781 buffer_ptr = obj->buffer.pointer; 782 783 ret = hp_get_string_from_buffer(&buffer_ptr, 784 &buffer_size, str, MAX_BUFF_SIZE); 785 786 if (ret < 0) 787 goto buff_attr_exit; 788 789 if (attr_type == HPWMI_PASSWORD_TYPE || 790 attr_type == HPWMI_SECURE_PLATFORM_TYPE) 791 temp_kset = bioscfg_drv.authentication_dir_kset; 792 else 793 temp_kset = bioscfg_drv.main_dir_kset; 794 795 /* All duplicate attributes found are ignored */ 796 duplicate = kset_find_obj(temp_kset, str); 797 if (duplicate) { 798 pr_debug("Duplicate attribute name found - %s\n", str); 799 /* kset_find_obj() returns a reference */ 800 kobject_put(duplicate); 801 goto buff_attr_exit; 802 } 803 804 /* build attribute */ 805 attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL); 806 if (!attr_name_kobj) { 807 ret = -ENOMEM; 808 goto buff_attr_exit; 809 } 810 811 attr_name_kobj->kset = temp_kset; 812 813 temp_str = str; 814 if (attr_type == HPWMI_SECURE_PLATFORM_TYPE) 815 temp_str = "SPM"; 816 817 ret = kobject_init_and_add(attr_name_kobj, 818 &attr_name_ktype, NULL, "%s", temp_str); 819 if (ret) { 820 kobject_put(attr_name_kobj); 821 goto buff_attr_exit; 822 } 823 824 /* enumerate all of these attributes */ 825 switch (attr_type) { 826 case HPWMI_STRING_TYPE: 827 ret = hp_populate_string_buffer_data(buffer_ptr, 828 &buffer_size, 829 instance_id, 830 attr_name_kobj); 831 break; 832 case HPWMI_INTEGER_TYPE: 833 ret = hp_populate_integer_buffer_data(buffer_ptr, 834 &buffer_size, 835 instance_id, 836 attr_name_kobj); 837 break; 838 case HPWMI_ENUMERATION_TYPE: 839 ret = hp_populate_enumeration_buffer_data(buffer_ptr, 840 &buffer_size, 841 instance_id, 842 attr_name_kobj); 843 break; 844 case HPWMI_ORDERED_LIST_TYPE: 845 ret = hp_populate_ordered_list_buffer_data(buffer_ptr, 846 &buffer_size, 847 instance_id, 848 attr_name_kobj); 849 break; 850 case HPWMI_PASSWORD_TYPE: 851 ret = hp_populate_password_buffer_data(buffer_ptr, 852 &buffer_size, 853 instance_id, 854 attr_name_kobj); 855 break; 856 default: 857 pr_debug("Unknown attribute type found: 0x%x\n", attr_type); 858 break; 859 } 860 861 buff_attr_exit: 862 kfree(str_value); 863 return ret; 864 } 865 866 /** 867 * hp_init_bios_attributes() - Initialize all attributes for a type 868 * @attr_type: The attribute type to initialize 869 * @guid: The WMI GUID associated with this type to initialize 870 * 871 * Initialize all 5 types of attributes: enumeration, integer, 872 * string, password, ordered list object. Populates each attribute types 873 * respective properties under sysfs files 874 */ 875 static int hp_init_bios_attributes(enum hp_wmi_data_type attr_type, const char *guid) 876 { 877 union acpi_object *obj = NULL; 878 int min_elements; 879 880 /* instance_id needs to be reset for each type GUID 881 * also, instance IDs are unique within GUID but not across 882 */ 883 int instance_id = 0; 884 int cur_instance_id = instance_id; 885 int ret = 0; 886 887 ret = hp_alloc_attributes_data(attr_type); 888 if (ret) 889 return ret; 890 891 switch (attr_type) { 892 case HPWMI_STRING_TYPE: 893 min_elements = STR_ELEM_CNT; 894 break; 895 case HPWMI_INTEGER_TYPE: 896 min_elements = INT_ELEM_CNT; 897 break; 898 case HPWMI_ENUMERATION_TYPE: 899 min_elements = ENUM_ELEM_CNT; 900 break; 901 case HPWMI_ORDERED_LIST_TYPE: 902 min_elements = ORD_ELEM_CNT; 903 break; 904 case HPWMI_PASSWORD_TYPE: 905 min_elements = PSWD_ELEM_CNT; 906 break; 907 default: 908 pr_err("Error: Unknown attr_type: %d\n", attr_type); 909 return -EINVAL; 910 } 911 912 /* need to use specific instance_id and guid combination to get right data */ 913 obj = hp_get_wmiobj_pointer(instance_id, guid); 914 if (!obj) 915 return -ENODEV; 916 917 mutex_lock(&bioscfg_drv.mutex); 918 while (obj) { 919 /* Take action appropriate to each ACPI TYPE */ 920 if (obj->type == ACPI_TYPE_PACKAGE) { 921 ret = hp_init_bios_package_attribute(attr_type, obj, 922 guid, min_elements, 923 cur_instance_id); 924 925 } else if (obj->type == ACPI_TYPE_BUFFER) { 926 ret = hp_init_bios_buffer_attribute(attr_type, obj, 927 guid, min_elements, 928 cur_instance_id); 929 930 } else { 931 pr_err("Expected ACPI-package or buffer type, got: %d\n", 932 obj->type); 933 ret = -EIO; 934 goto err_attr_init; 935 } 936 937 /* 938 * Failure reported in one attribute must not 939 * stop process of the remaining attribute values. 940 */ 941 if (ret >= 0) 942 cur_instance_id++; 943 944 kfree(obj); 945 instance_id++; 946 obj = hp_get_wmiobj_pointer(instance_id, guid); 947 } 948 949 err_attr_init: 950 mutex_unlock(&bioscfg_drv.mutex); 951 kfree(obj); 952 return ret; 953 } 954 955 static int __init hp_init(void) 956 { 957 int ret; 958 int hp_bios_capable = wmi_has_guid(HP_WMI_BIOS_GUID); 959 int set_bios_settings = wmi_has_guid(HP_WMI_SET_BIOS_SETTING_GUID); 960 961 if (!hp_bios_capable) { 962 pr_err("Unable to run on non-HP system\n"); 963 return -ENODEV; 964 } 965 966 if (!set_bios_settings) { 967 pr_err("Unable to set BIOS settings on HP systems\n"); 968 return -ENODEV; 969 } 970 971 ret = hp_init_attr_set_interface(); 972 if (ret) 973 return ret; 974 975 ret = fw_attributes_class_get(&fw_attr_class); 976 if (ret) 977 goto err_unregister_class; 978 979 bioscfg_drv.class_dev = device_create(fw_attr_class, NULL, MKDEV(0, 0), 980 NULL, "%s", DRIVER_NAME); 981 if (IS_ERR(bioscfg_drv.class_dev)) { 982 ret = PTR_ERR(bioscfg_drv.class_dev); 983 goto err_unregister_class; 984 } 985 986 bioscfg_drv.main_dir_kset = kset_create_and_add("attributes", NULL, 987 &bioscfg_drv.class_dev->kobj); 988 if (!bioscfg_drv.main_dir_kset) { 989 ret = -ENOMEM; 990 pr_debug("Failed to create and add attributes\n"); 991 goto err_destroy_classdev; 992 } 993 994 bioscfg_drv.authentication_dir_kset = kset_create_and_add("authentication", NULL, 995 &bioscfg_drv.class_dev->kobj); 996 if (!bioscfg_drv.authentication_dir_kset) { 997 ret = -ENOMEM; 998 pr_debug("Failed to create and add authentication\n"); 999 goto err_release_attributes_data; 1000 } 1001 1002 /* 1003 * sysfs level attributes. 1004 * - pending_reboot 1005 */ 1006 ret = create_attributes_level_sysfs_files(); 1007 if (ret) 1008 pr_debug("Failed to create sysfs level attributes\n"); 1009 1010 ret = hp_init_bios_attributes(HPWMI_STRING_TYPE, HP_WMI_BIOS_STRING_GUID); 1011 if (ret) 1012 pr_debug("Failed to populate string type attributes\n"); 1013 1014 ret = hp_init_bios_attributes(HPWMI_INTEGER_TYPE, HP_WMI_BIOS_INTEGER_GUID); 1015 if (ret) 1016 pr_debug("Failed to populate integer type attributes\n"); 1017 1018 ret = hp_init_bios_attributes(HPWMI_ENUMERATION_TYPE, HP_WMI_BIOS_ENUMERATION_GUID); 1019 if (ret) 1020 pr_debug("Failed to populate enumeration type attributes\n"); 1021 1022 ret = hp_init_bios_attributes(HPWMI_ORDERED_LIST_TYPE, HP_WMI_BIOS_ORDERED_LIST_GUID); 1023 if (ret) 1024 pr_debug("Failed to populate ordered list object type attributes\n"); 1025 1026 ret = hp_init_bios_attributes(HPWMI_PASSWORD_TYPE, HP_WMI_BIOS_PASSWORD_GUID); 1027 if (ret) 1028 pr_debug("Failed to populate password object type attributes\n"); 1029 1030 bioscfg_drv.spm_data.attr_name_kobj = NULL; 1031 ret = hp_add_other_attributes(HPWMI_SECURE_PLATFORM_TYPE); 1032 if (ret) 1033 pr_debug("Failed to populate secure platform object type attribute\n"); 1034 1035 bioscfg_drv.sure_start_attr_kobj = NULL; 1036 ret = hp_add_other_attributes(HPWMI_SURE_START_TYPE); 1037 if (ret) 1038 pr_debug("Failed to populate sure start object type attribute\n"); 1039 1040 return 0; 1041 1042 err_release_attributes_data: 1043 release_attributes_data(); 1044 1045 err_destroy_classdev: 1046 device_destroy(fw_attr_class, MKDEV(0, 0)); 1047 1048 err_unregister_class: 1049 fw_attributes_class_put(); 1050 hp_exit_attr_set_interface(); 1051 1052 return ret; 1053 } 1054 1055 static void __exit hp_exit(void) 1056 { 1057 release_attributes_data(); 1058 device_destroy(fw_attr_class, MKDEV(0, 0)); 1059 1060 fw_attributes_class_put(); 1061 hp_exit_attr_set_interface(); 1062 } 1063 1064 module_init(hp_init); 1065 module_exit(hp_exit); 1066