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 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 union acpi_object *obj = NULL; 592 int ret; 593 char *attr_name; 594 595 attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL); 596 if (!attr_name_kobj) 597 return -ENOMEM; 598 599 mutex_lock(&bioscfg_drv.mutex); 600 601 /* Check if attribute type is supported */ 602 switch (attr_type) { 603 case HPWMI_SECURE_PLATFORM_TYPE: 604 attr_name_kobj->kset = bioscfg_drv.authentication_dir_kset; 605 attr_name = SPM_STR; 606 break; 607 608 case HPWMI_SURE_START_TYPE: 609 attr_name_kobj->kset = bioscfg_drv.main_dir_kset; 610 attr_name = SURE_START_STR; 611 break; 612 613 default: 614 pr_err("Error: Unknown attr_type: %d\n", attr_type); 615 ret = -EINVAL; 616 kfree(attr_name_kobj); 617 goto unlock_drv_mutex; 618 } 619 620 ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype, 621 NULL, "%s", attr_name); 622 if (ret) { 623 pr_err("Error encountered [%d]\n", ret); 624 goto err_other_attr_init; 625 } 626 627 /* Populate attribute data */ 628 switch (attr_type) { 629 case HPWMI_SECURE_PLATFORM_TYPE: 630 ret = hp_populate_secure_platform_data(attr_name_kobj); 631 break; 632 633 case HPWMI_SURE_START_TYPE: 634 ret = hp_populate_sure_start_data(attr_name_kobj); 635 break; 636 637 default: 638 ret = -EINVAL; 639 } 640 641 if (ret) 642 goto err_other_attr_init; 643 644 mutex_unlock(&bioscfg_drv.mutex); 645 return 0; 646 647 err_other_attr_init: 648 kobject_put(attr_name_kobj); 649 unlock_drv_mutex: 650 mutex_unlock(&bioscfg_drv.mutex); 651 kfree(obj); 652 return ret; 653 } 654 655 static int hp_init_bios_package_attribute(enum hp_wmi_data_type attr_type, 656 union acpi_object *obj, 657 const char *guid, int min_elements, 658 int instance_id) 659 { 660 struct kobject *attr_name_kobj, *duplicate; 661 union acpi_object *elements; 662 struct kset *temp_kset; 663 664 char *str_value = NULL; 665 int str_len; 666 int ret = 0; 667 668 /* Take action appropriate to each ACPI TYPE */ 669 if (obj->package.count < min_elements) { 670 pr_err("ACPI-package does not have enough elements: %d < %d\n", 671 obj->package.count, min_elements); 672 goto pack_attr_exit; 673 } 674 675 elements = obj->package.elements; 676 677 /* sanity checking */ 678 if (elements[NAME].type != ACPI_TYPE_STRING) { 679 pr_debug("incorrect element type\n"); 680 goto pack_attr_exit; 681 } 682 if (strlen(elements[NAME].string.pointer) == 0) { 683 pr_debug("empty attribute found\n"); 684 goto pack_attr_exit; 685 } 686 687 if (attr_type == HPWMI_PASSWORD_TYPE) 688 temp_kset = bioscfg_drv.authentication_dir_kset; 689 else 690 temp_kset = bioscfg_drv.main_dir_kset; 691 692 /* convert attribute name to string */ 693 ret = hp_convert_hexstr_to_str(elements[NAME].string.pointer, 694 elements[NAME].string.length, 695 &str_value, &str_len); 696 697 if (ret) { 698 pr_debug("Failed to populate integer package data. Error [0%0x]\n", 699 ret); 700 kfree(str_value); 701 return ret; 702 } 703 704 /* All duplicate attributes found are ignored */ 705 duplicate = kset_find_obj(temp_kset, str_value); 706 if (duplicate) { 707 pr_debug("Duplicate attribute name found - %s\n", str_value); 708 /* kset_find_obj() returns a reference */ 709 kobject_put(duplicate); 710 goto pack_attr_exit; 711 } 712 713 /* build attribute */ 714 attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL); 715 if (!attr_name_kobj) { 716 ret = -ENOMEM; 717 goto pack_attr_exit; 718 } 719 720 attr_name_kobj->kset = temp_kset; 721 722 ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype, 723 NULL, "%s", str_value); 724 725 if (ret) { 726 kobject_put(attr_name_kobj); 727 goto pack_attr_exit; 728 } 729 730 /* enumerate all of these attributes */ 731 switch (attr_type) { 732 case HPWMI_STRING_TYPE: 733 ret = hp_populate_string_package_data(elements, 734 instance_id, 735 attr_name_kobj); 736 break; 737 case HPWMI_INTEGER_TYPE: 738 ret = hp_populate_integer_package_data(elements, 739 instance_id, 740 attr_name_kobj); 741 break; 742 case HPWMI_ENUMERATION_TYPE: 743 ret = hp_populate_enumeration_package_data(elements, 744 instance_id, 745 attr_name_kobj); 746 break; 747 case HPWMI_ORDERED_LIST_TYPE: 748 ret = hp_populate_ordered_list_package_data(elements, 749 instance_id, 750 attr_name_kobj); 751 break; 752 case HPWMI_PASSWORD_TYPE: 753 ret = hp_populate_password_package_data(elements, 754 instance_id, 755 attr_name_kobj); 756 break; 757 default: 758 pr_debug("Unknown attribute type found: 0x%x\n", attr_type); 759 break; 760 } 761 762 pack_attr_exit: 763 kfree(str_value); 764 return ret; 765 } 766 767 static int hp_init_bios_buffer_attribute(enum hp_wmi_data_type attr_type, 768 union acpi_object *obj, 769 const char *guid, int min_elements, 770 int instance_id) 771 { 772 struct kobject *attr_name_kobj, *duplicate; 773 struct kset *temp_kset; 774 char str[MAX_BUFF_SIZE]; 775 776 char *temp_str = NULL; 777 char *str_value = NULL; 778 u8 *buffer_ptr = NULL; 779 int buffer_size; 780 int ret = 0; 781 782 buffer_size = obj->buffer.length; 783 buffer_ptr = obj->buffer.pointer; 784 785 ret = hp_get_string_from_buffer(&buffer_ptr, 786 &buffer_size, str, MAX_BUFF_SIZE); 787 788 if (ret < 0) 789 goto buff_attr_exit; 790 791 if (attr_type == HPWMI_PASSWORD_TYPE || 792 attr_type == HPWMI_SECURE_PLATFORM_TYPE) 793 temp_kset = bioscfg_drv.authentication_dir_kset; 794 else 795 temp_kset = bioscfg_drv.main_dir_kset; 796 797 /* All duplicate attributes found are ignored */ 798 duplicate = kset_find_obj(temp_kset, str); 799 if (duplicate) { 800 pr_debug("Duplicate attribute name found - %s\n", str); 801 /* kset_find_obj() returns a reference */ 802 kobject_put(duplicate); 803 goto buff_attr_exit; 804 } 805 806 /* build attribute */ 807 attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL); 808 if (!attr_name_kobj) { 809 ret = -ENOMEM; 810 goto buff_attr_exit; 811 } 812 813 attr_name_kobj->kset = temp_kset; 814 815 temp_str = str; 816 if (attr_type == HPWMI_SECURE_PLATFORM_TYPE) 817 temp_str = "SPM"; 818 819 ret = kobject_init_and_add(attr_name_kobj, 820 &attr_name_ktype, NULL, "%s", temp_str); 821 if (ret) { 822 kobject_put(attr_name_kobj); 823 goto buff_attr_exit; 824 } 825 826 /* enumerate all of these attributes */ 827 switch (attr_type) { 828 case HPWMI_STRING_TYPE: 829 ret = hp_populate_string_buffer_data(buffer_ptr, 830 &buffer_size, 831 instance_id, 832 attr_name_kobj); 833 break; 834 case HPWMI_INTEGER_TYPE: 835 ret = hp_populate_integer_buffer_data(buffer_ptr, 836 &buffer_size, 837 instance_id, 838 attr_name_kobj); 839 break; 840 case HPWMI_ENUMERATION_TYPE: 841 ret = hp_populate_enumeration_buffer_data(buffer_ptr, 842 &buffer_size, 843 instance_id, 844 attr_name_kobj); 845 break; 846 case HPWMI_ORDERED_LIST_TYPE: 847 ret = hp_populate_ordered_list_buffer_data(buffer_ptr, 848 &buffer_size, 849 instance_id, 850 attr_name_kobj); 851 break; 852 case HPWMI_PASSWORD_TYPE: 853 ret = hp_populate_password_buffer_data(buffer_ptr, 854 &buffer_size, 855 instance_id, 856 attr_name_kobj); 857 break; 858 default: 859 pr_debug("Unknown attribute type found: 0x%x\n", attr_type); 860 break; 861 } 862 863 buff_attr_exit: 864 kfree(str_value); 865 return ret; 866 } 867 868 /** 869 * hp_init_bios_attributes() - Initialize all attributes for a type 870 * @attr_type: The attribute type to initialize 871 * @guid: The WMI GUID associated with this type to initialize 872 * 873 * Initialize all 5 types of attributes: enumeration, integer, 874 * string, password, ordered list object. Populates each attribute types 875 * respective properties under sysfs files 876 */ 877 static int hp_init_bios_attributes(enum hp_wmi_data_type attr_type, const char *guid) 878 { 879 union acpi_object *obj = NULL; 880 int min_elements; 881 882 /* instance_id needs to be reset for each type GUID 883 * also, instance IDs are unique within GUID but not across 884 */ 885 int instance_id = 0; 886 int cur_instance_id = instance_id; 887 int ret = 0; 888 889 ret = hp_alloc_attributes_data(attr_type); 890 if (ret) 891 return ret; 892 893 switch (attr_type) { 894 case HPWMI_STRING_TYPE: 895 min_elements = STR_ELEM_CNT; 896 break; 897 case HPWMI_INTEGER_TYPE: 898 min_elements = INT_ELEM_CNT; 899 break; 900 case HPWMI_ENUMERATION_TYPE: 901 min_elements = ENUM_ELEM_CNT; 902 break; 903 case HPWMI_ORDERED_LIST_TYPE: 904 min_elements = ORD_ELEM_CNT; 905 break; 906 case HPWMI_PASSWORD_TYPE: 907 min_elements = PSWD_ELEM_CNT; 908 break; 909 default: 910 pr_err("Error: Unknown attr_type: %d\n", attr_type); 911 return -EINVAL; 912 } 913 914 /* need to use specific instance_id and guid combination to get right data */ 915 obj = hp_get_wmiobj_pointer(instance_id, guid); 916 if (!obj) 917 return -ENODEV; 918 919 mutex_lock(&bioscfg_drv.mutex); 920 while (obj) { 921 /* Take action appropriate to each ACPI TYPE */ 922 if (obj->type == ACPI_TYPE_PACKAGE) { 923 ret = hp_init_bios_package_attribute(attr_type, obj, 924 guid, min_elements, 925 cur_instance_id); 926 927 } else if (obj->type == ACPI_TYPE_BUFFER) { 928 ret = hp_init_bios_buffer_attribute(attr_type, obj, 929 guid, min_elements, 930 cur_instance_id); 931 932 } else { 933 pr_err("Expected ACPI-package or buffer type, got: %d\n", 934 obj->type); 935 ret = -EIO; 936 goto err_attr_init; 937 } 938 939 /* 940 * Failure reported in one attribute must not 941 * stop process of the remaining attribute values. 942 */ 943 if (ret >= 0) 944 cur_instance_id++; 945 946 kfree(obj); 947 instance_id++; 948 obj = hp_get_wmiobj_pointer(instance_id, guid); 949 } 950 951 err_attr_init: 952 mutex_unlock(&bioscfg_drv.mutex); 953 kfree(obj); 954 return ret; 955 } 956 957 static int __init hp_init(void) 958 { 959 int ret; 960 int hp_bios_capable = wmi_has_guid(HP_WMI_BIOS_GUID); 961 int set_bios_settings = wmi_has_guid(HP_WMI_SET_BIOS_SETTING_GUID); 962 963 if (!hp_bios_capable) { 964 pr_err("Unable to run on non-HP system\n"); 965 return -ENODEV; 966 } 967 968 if (!set_bios_settings) { 969 pr_err("Unable to set BIOS settings on HP systems\n"); 970 return -ENODEV; 971 } 972 973 ret = hp_init_attr_set_interface(); 974 if (ret) 975 return ret; 976 977 ret = fw_attributes_class_get(&fw_attr_class); 978 if (ret) 979 goto err_unregister_class; 980 981 bioscfg_drv.class_dev = device_create(fw_attr_class, NULL, MKDEV(0, 0), 982 NULL, "%s", DRIVER_NAME); 983 if (IS_ERR(bioscfg_drv.class_dev)) { 984 ret = PTR_ERR(bioscfg_drv.class_dev); 985 goto err_unregister_class; 986 } 987 988 bioscfg_drv.main_dir_kset = kset_create_and_add("attributes", NULL, 989 &bioscfg_drv.class_dev->kobj); 990 if (!bioscfg_drv.main_dir_kset) { 991 ret = -ENOMEM; 992 pr_debug("Failed to create and add attributes\n"); 993 goto err_destroy_classdev; 994 } 995 996 bioscfg_drv.authentication_dir_kset = kset_create_and_add("authentication", NULL, 997 &bioscfg_drv.class_dev->kobj); 998 if (!bioscfg_drv.authentication_dir_kset) { 999 ret = -ENOMEM; 1000 pr_debug("Failed to create and add authentication\n"); 1001 goto err_release_attributes_data; 1002 } 1003 1004 /* 1005 * sysfs level attributes. 1006 * - pending_reboot 1007 */ 1008 ret = create_attributes_level_sysfs_files(); 1009 if (ret) 1010 pr_debug("Failed to create sysfs level attributes\n"); 1011 1012 ret = hp_init_bios_attributes(HPWMI_STRING_TYPE, HP_WMI_BIOS_STRING_GUID); 1013 if (ret) 1014 pr_debug("Failed to populate string type attributes\n"); 1015 1016 ret = hp_init_bios_attributes(HPWMI_INTEGER_TYPE, HP_WMI_BIOS_INTEGER_GUID); 1017 if (ret) 1018 pr_debug("Failed to populate integer type attributes\n"); 1019 1020 ret = hp_init_bios_attributes(HPWMI_ENUMERATION_TYPE, HP_WMI_BIOS_ENUMERATION_GUID); 1021 if (ret) 1022 pr_debug("Failed to populate enumeration type attributes\n"); 1023 1024 ret = hp_init_bios_attributes(HPWMI_ORDERED_LIST_TYPE, HP_WMI_BIOS_ORDERED_LIST_GUID); 1025 if (ret) 1026 pr_debug("Failed to populate ordered list object type attributes\n"); 1027 1028 ret = hp_init_bios_attributes(HPWMI_PASSWORD_TYPE, HP_WMI_BIOS_PASSWORD_GUID); 1029 if (ret) 1030 pr_debug("Failed to populate password object type attributes\n"); 1031 1032 bioscfg_drv.spm_data.attr_name_kobj = NULL; 1033 ret = hp_add_other_attributes(HPWMI_SECURE_PLATFORM_TYPE); 1034 if (ret) 1035 pr_debug("Failed to populate secure platform object type attribute\n"); 1036 1037 bioscfg_drv.sure_start_attr_kobj = NULL; 1038 ret = hp_add_other_attributes(HPWMI_SURE_START_TYPE); 1039 if (ret) 1040 pr_debug("Failed to populate sure start object type attribute\n"); 1041 1042 return 0; 1043 1044 err_release_attributes_data: 1045 release_attributes_data(); 1046 1047 err_destroy_classdev: 1048 device_destroy(fw_attr_class, MKDEV(0, 0)); 1049 1050 err_unregister_class: 1051 fw_attributes_class_put(); 1052 hp_exit_attr_set_interface(); 1053 1054 return ret; 1055 } 1056 1057 static void __exit hp_exit(void) 1058 { 1059 release_attributes_data(); 1060 device_destroy(fw_attr_class, MKDEV(0, 0)); 1061 1062 fw_attributes_class_put(); 1063 hp_exit_attr_set_interface(); 1064 } 1065 1066 module_init(hp_init); 1067 module_exit(hp_exit); 1068