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