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