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 int ret; 392 393 ret = wmi_instance_count(guid_string); 394 if (ret < 0) 395 return 0; 396 397 return ret; 398 } 399 400 /** 401 * hp_alloc_attributes_data() - Allocate attributes data for a particular type 402 * 403 * @attr_type: Attribute type to allocate 404 */ 405 static int hp_alloc_attributes_data(int attr_type) 406 { 407 switch (attr_type) { 408 case HPWMI_STRING_TYPE: 409 return hp_alloc_string_data(); 410 411 case HPWMI_INTEGER_TYPE: 412 return hp_alloc_integer_data(); 413 414 case HPWMI_ENUMERATION_TYPE: 415 return hp_alloc_enumeration_data(); 416 417 case HPWMI_ORDERED_LIST_TYPE: 418 return hp_alloc_ordered_list_data(); 419 420 case HPWMI_PASSWORD_TYPE: 421 return hp_alloc_password_data(); 422 423 default: 424 return 0; 425 } 426 } 427 428 int hp_convert_hexstr_to_str(const char *input, u32 input_len, char **str, int *len) 429 { 430 int ret = 0; 431 int new_len = 0; 432 char tmp[] = "0x00"; 433 char *new_str = NULL; 434 long ch; 435 int i; 436 437 if (input_len <= 0 || !input || !str || !len) 438 return -EINVAL; 439 440 *len = 0; 441 *str = NULL; 442 443 new_str = kmalloc(input_len, GFP_KERNEL); 444 if (!new_str) 445 return -ENOMEM; 446 447 for (i = 0; i < input_len; i += 5) { 448 strscpy(tmp, input + i); 449 if (kstrtol(tmp, 16, &ch) == 0) { 450 // escape char 451 if (ch == '\\' || 452 ch == '\r' || 453 ch == '\n' || ch == '\t') { 454 if (ch == '\r') 455 ch = 'r'; 456 else if (ch == '\n') 457 ch = 'n'; 458 else if (ch == '\t') 459 ch = 't'; 460 new_str[new_len++] = '\\'; 461 } 462 new_str[new_len++] = ch; 463 if (ch == '\0') 464 break; 465 } 466 } 467 468 if (new_len) { 469 new_str[new_len] = '\0'; 470 *str = krealloc(new_str, (new_len + 1) * sizeof(char), 471 GFP_KERNEL); 472 if (*str) 473 *len = new_len; 474 else 475 ret = -ENOMEM; 476 } else { 477 ret = -EFAULT; 478 } 479 480 if (ret) 481 kfree(new_str); 482 return ret; 483 } 484 485 /* map output size to the corresponding WMI method id */ 486 int hp_encode_outsize_for_pvsz(int outsize) 487 { 488 if (outsize > 4096) 489 return -EINVAL; 490 if (outsize > 1024) 491 return 5; 492 if (outsize > 128) 493 return 4; 494 if (outsize > 4) 495 return 3; 496 if (outsize > 0) 497 return 2; 498 return 1; 499 } 500 501 /* 502 * Update friendly display name for several attributes associated to 503 * 'Schedule Power-On' 504 */ 505 void hp_friendly_user_name_update(char *path, const char *attr_name, 506 char *attr_display, int attr_size) 507 { 508 if (strstr(path, SCHEDULE_POWER_ON)) 509 snprintf(attr_display, attr_size, "%s - %s", SCHEDULE_POWER_ON, attr_name); 510 else 511 strscpy(attr_display, attr_name, attr_size); 512 } 513 514 /** 515 * hp_update_attribute_permissions() - Update attributes permissions when 516 * isReadOnly value is 1 517 * 518 * @is_readonly: bool value to indicate if it a readonly attribute. 519 * @current_val: kobj_attribute corresponding to attribute. 520 * 521 */ 522 void hp_update_attribute_permissions(bool is_readonly, struct kobj_attribute *current_val) 523 { 524 current_val->attr.mode = is_readonly ? 0444 : 0644; 525 } 526 527 /** 528 * destroy_attribute_objs() - Free a kset of kobjects 529 * @kset: The kset to destroy 530 * 531 * Fress kobjects created for each attribute_name under attribute type kset 532 */ 533 static void destroy_attribute_objs(struct kset *kset) 534 { 535 struct kobject *pos, *next; 536 537 list_for_each_entry_safe(pos, next, &kset->list, entry) 538 kobject_put(pos); 539 } 540 541 /** 542 * release_attributes_data() - Clean-up all sysfs directories and files created 543 */ 544 static void release_attributes_data(void) 545 { 546 mutex_lock(&bioscfg_drv.mutex); 547 548 hp_exit_string_attributes(); 549 hp_exit_integer_attributes(); 550 hp_exit_enumeration_attributes(); 551 hp_exit_ordered_list_attributes(); 552 hp_exit_password_attributes(); 553 hp_exit_sure_start_attributes(); 554 hp_exit_secure_platform_attributes(); 555 556 if (bioscfg_drv.authentication_dir_kset) { 557 destroy_attribute_objs(bioscfg_drv.authentication_dir_kset); 558 kset_unregister(bioscfg_drv.authentication_dir_kset); 559 bioscfg_drv.authentication_dir_kset = NULL; 560 } 561 if (bioscfg_drv.main_dir_kset) { 562 sysfs_remove_file(&bioscfg_drv.main_dir_kset->kobj, &pending_reboot.attr); 563 destroy_attribute_objs(bioscfg_drv.main_dir_kset); 564 kset_unregister(bioscfg_drv.main_dir_kset); 565 bioscfg_drv.main_dir_kset = NULL; 566 } 567 mutex_unlock(&bioscfg_drv.mutex); 568 } 569 570 /** 571 * hp_add_other_attributes() - Initialize HP custom attributes not 572 * reported by BIOS and required to support Secure Platform and Sure 573 * Start. 574 * 575 * @attr_type: Custom HP attribute not reported by BIOS 576 * 577 * Initialize all 2 types of attributes: Platform and Sure Start 578 * object. Populates each attribute types respective properties 579 * under sysfs files. 580 * 581 * Returns zero(0) if successful. Otherwise, a negative value. 582 */ 583 static int hp_add_other_attributes(int attr_type) 584 { 585 struct kobject *attr_name_kobj; 586 int ret; 587 char *attr_name; 588 589 attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL); 590 if (!attr_name_kobj) 591 return -ENOMEM; 592 593 mutex_lock(&bioscfg_drv.mutex); 594 595 /* Check if attribute type is supported */ 596 switch (attr_type) { 597 case HPWMI_SECURE_PLATFORM_TYPE: 598 attr_name_kobj->kset = bioscfg_drv.authentication_dir_kset; 599 attr_name = SPM_STR; 600 break; 601 602 case HPWMI_SURE_START_TYPE: 603 attr_name_kobj->kset = bioscfg_drv.main_dir_kset; 604 attr_name = SURE_START_STR; 605 break; 606 607 default: 608 pr_err("Error: Unknown attr_type: %d\n", attr_type); 609 ret = -EINVAL; 610 kfree(attr_name_kobj); 611 goto unlock_drv_mutex; 612 } 613 614 ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype, 615 NULL, "%s", attr_name); 616 if (ret) { 617 pr_err("Error encountered [%d]\n", ret); 618 goto err_other_attr_init; 619 } 620 621 /* Populate attribute data */ 622 switch (attr_type) { 623 case HPWMI_SECURE_PLATFORM_TYPE: 624 ret = hp_populate_secure_platform_data(attr_name_kobj); 625 break; 626 627 case HPWMI_SURE_START_TYPE: 628 ret = hp_populate_sure_start_data(attr_name_kobj); 629 break; 630 631 default: 632 ret = -EINVAL; 633 } 634 635 if (ret) 636 goto err_other_attr_init; 637 638 mutex_unlock(&bioscfg_drv.mutex); 639 return 0; 640 641 err_other_attr_init: 642 kobject_put(attr_name_kobj); 643 unlock_drv_mutex: 644 mutex_unlock(&bioscfg_drv.mutex); 645 return ret; 646 } 647 648 static int hp_init_bios_package_attribute(enum hp_wmi_data_type attr_type, 649 union acpi_object *obj, 650 const char *guid, int min_elements, 651 int instance_id) 652 { 653 struct kobject *attr_name_kobj, *duplicate; 654 union acpi_object *elements; 655 struct kset *temp_kset; 656 657 char *str_value = NULL; 658 int str_len; 659 int ret = 0; 660 661 /* Take action appropriate to each ACPI TYPE */ 662 if (obj->package.count < min_elements) { 663 pr_err("ACPI-package does not have enough elements: %d < %d\n", 664 obj->package.count, min_elements); 665 goto pack_attr_exit; 666 } 667 668 elements = obj->package.elements; 669 670 /* sanity checking */ 671 if (elements[NAME].type != ACPI_TYPE_STRING) { 672 pr_debug("incorrect element type\n"); 673 goto pack_attr_exit; 674 } 675 if (strlen(elements[NAME].string.pointer) == 0) { 676 pr_debug("empty attribute found\n"); 677 goto pack_attr_exit; 678 } 679 680 if (attr_type == HPWMI_PASSWORD_TYPE) 681 temp_kset = bioscfg_drv.authentication_dir_kset; 682 else 683 temp_kset = bioscfg_drv.main_dir_kset; 684 685 /* convert attribute name to string */ 686 ret = hp_convert_hexstr_to_str(elements[NAME].string.pointer, 687 elements[NAME].string.length, 688 &str_value, &str_len); 689 690 if (ret) { 691 pr_debug("Failed to populate integer package data. Error [0%0x]\n", 692 ret); 693 kfree(str_value); 694 return ret; 695 } 696 697 /* All duplicate attributes found are ignored */ 698 duplicate = kset_find_obj(temp_kset, str_value); 699 if (duplicate) { 700 pr_debug("Duplicate attribute name found - %s\n", str_value); 701 /* kset_find_obj() returns a reference */ 702 kobject_put(duplicate); 703 goto pack_attr_exit; 704 } 705 706 /* build attribute */ 707 attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL); 708 if (!attr_name_kobj) { 709 ret = -ENOMEM; 710 goto pack_attr_exit; 711 } 712 713 attr_name_kobj->kset = temp_kset; 714 715 ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype, 716 NULL, "%s", str_value); 717 718 if (ret) { 719 kobject_put(attr_name_kobj); 720 goto pack_attr_exit; 721 } 722 723 /* enumerate all of these attributes */ 724 switch (attr_type) { 725 case HPWMI_STRING_TYPE: 726 ret = hp_populate_string_package_data(elements, 727 instance_id, 728 attr_name_kobj); 729 break; 730 case HPWMI_INTEGER_TYPE: 731 ret = hp_populate_integer_package_data(elements, 732 instance_id, 733 attr_name_kobj); 734 break; 735 case HPWMI_ENUMERATION_TYPE: 736 ret = hp_populate_enumeration_package_data(elements, 737 instance_id, 738 attr_name_kobj); 739 break; 740 case HPWMI_ORDERED_LIST_TYPE: 741 ret = hp_populate_ordered_list_package_data(elements, 742 instance_id, 743 attr_name_kobj); 744 break; 745 case HPWMI_PASSWORD_TYPE: 746 ret = hp_populate_password_package_data(elements, 747 instance_id, 748 attr_name_kobj); 749 break; 750 default: 751 pr_debug("Unknown attribute type found: 0x%x\n", attr_type); 752 break; 753 } 754 755 pack_attr_exit: 756 kfree(str_value); 757 return ret; 758 } 759 760 static int hp_init_bios_buffer_attribute(enum hp_wmi_data_type attr_type, 761 union acpi_object *obj, 762 const char *guid, int min_elements, 763 int instance_id) 764 { 765 struct kobject *attr_name_kobj, *duplicate; 766 struct kset *temp_kset; 767 char str[MAX_BUFF_SIZE]; 768 769 char *temp_str = NULL; 770 char *str_value = NULL; 771 u8 *buffer_ptr = NULL; 772 int buffer_size; 773 int ret = 0; 774 775 buffer_size = obj->buffer.length; 776 buffer_ptr = obj->buffer.pointer; 777 778 ret = hp_get_string_from_buffer(&buffer_ptr, 779 &buffer_size, str, MAX_BUFF_SIZE); 780 781 if (ret < 0) 782 goto buff_attr_exit; 783 784 if (attr_type == HPWMI_PASSWORD_TYPE || 785 attr_type == HPWMI_SECURE_PLATFORM_TYPE) 786 temp_kset = bioscfg_drv.authentication_dir_kset; 787 else 788 temp_kset = bioscfg_drv.main_dir_kset; 789 790 /* All duplicate attributes found are ignored */ 791 duplicate = kset_find_obj(temp_kset, str); 792 if (duplicate) { 793 pr_debug("Duplicate attribute name found - %s\n", str); 794 /* kset_find_obj() returns a reference */ 795 kobject_put(duplicate); 796 goto buff_attr_exit; 797 } 798 799 /* build attribute */ 800 attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL); 801 if (!attr_name_kobj) { 802 ret = -ENOMEM; 803 goto buff_attr_exit; 804 } 805 806 attr_name_kobj->kset = temp_kset; 807 808 temp_str = str; 809 if (attr_type == HPWMI_SECURE_PLATFORM_TYPE) 810 temp_str = "SPM"; 811 812 ret = kobject_init_and_add(attr_name_kobj, 813 &attr_name_ktype, NULL, "%s", temp_str); 814 if (ret) { 815 kobject_put(attr_name_kobj); 816 goto buff_attr_exit; 817 } 818 819 /* enumerate all of these attributes */ 820 switch (attr_type) { 821 case HPWMI_STRING_TYPE: 822 ret = hp_populate_string_buffer_data(buffer_ptr, 823 &buffer_size, 824 instance_id, 825 attr_name_kobj); 826 break; 827 case HPWMI_INTEGER_TYPE: 828 ret = hp_populate_integer_buffer_data(buffer_ptr, 829 &buffer_size, 830 instance_id, 831 attr_name_kobj); 832 break; 833 case HPWMI_ENUMERATION_TYPE: 834 ret = hp_populate_enumeration_buffer_data(buffer_ptr, 835 &buffer_size, 836 instance_id, 837 attr_name_kobj); 838 break; 839 case HPWMI_ORDERED_LIST_TYPE: 840 ret = hp_populate_ordered_list_buffer_data(buffer_ptr, 841 &buffer_size, 842 instance_id, 843 attr_name_kobj); 844 break; 845 case HPWMI_PASSWORD_TYPE: 846 ret = hp_populate_password_buffer_data(buffer_ptr, 847 &buffer_size, 848 instance_id, 849 attr_name_kobj); 850 break; 851 default: 852 pr_debug("Unknown attribute type found: 0x%x\n", attr_type); 853 break; 854 } 855 856 buff_attr_exit: 857 kfree(str_value); 858 return ret; 859 } 860 861 /** 862 * hp_init_bios_attributes() - Initialize all attributes for a type 863 * @attr_type: The attribute type to initialize 864 * @guid: The WMI GUID associated with this type to initialize 865 * 866 * Initialize all 5 types of attributes: enumeration, integer, 867 * string, password, ordered list object. Populates each attribute types 868 * respective properties under sysfs files 869 */ 870 static int hp_init_bios_attributes(enum hp_wmi_data_type attr_type, const char *guid) 871 { 872 union acpi_object *obj = NULL; 873 int min_elements; 874 875 /* instance_id needs to be reset for each type GUID 876 * also, instance IDs are unique within GUID but not across 877 */ 878 int instance_id = 0; 879 int cur_instance_id = instance_id; 880 int ret = 0; 881 882 ret = hp_alloc_attributes_data(attr_type); 883 if (ret) 884 return ret; 885 886 switch (attr_type) { 887 case HPWMI_STRING_TYPE: 888 min_elements = STR_ELEM_CNT; 889 break; 890 case HPWMI_INTEGER_TYPE: 891 min_elements = INT_ELEM_CNT; 892 break; 893 case HPWMI_ENUMERATION_TYPE: 894 min_elements = ENUM_ELEM_CNT; 895 break; 896 case HPWMI_ORDERED_LIST_TYPE: 897 min_elements = ORD_ELEM_CNT; 898 break; 899 case HPWMI_PASSWORD_TYPE: 900 min_elements = PSWD_ELEM_CNT; 901 break; 902 default: 903 pr_err("Error: Unknown attr_type: %d\n", attr_type); 904 return -EINVAL; 905 } 906 907 /* need to use specific instance_id and guid combination to get right data */ 908 obj = hp_get_wmiobj_pointer(instance_id, guid); 909 if (!obj) 910 return -ENODEV; 911 912 mutex_lock(&bioscfg_drv.mutex); 913 while (obj) { 914 /* Take action appropriate to each ACPI TYPE */ 915 if (obj->type == ACPI_TYPE_PACKAGE) { 916 ret = hp_init_bios_package_attribute(attr_type, obj, 917 guid, min_elements, 918 cur_instance_id); 919 920 } else if (obj->type == ACPI_TYPE_BUFFER) { 921 ret = hp_init_bios_buffer_attribute(attr_type, obj, 922 guid, min_elements, 923 cur_instance_id); 924 925 } else { 926 pr_err("Expected ACPI-package or buffer type, got: %d\n", 927 obj->type); 928 ret = -EIO; 929 goto err_attr_init; 930 } 931 932 /* 933 * Failure reported in one attribute must not 934 * stop process of the remaining attribute values. 935 */ 936 if (ret >= 0) 937 cur_instance_id++; 938 939 kfree(obj); 940 instance_id++; 941 obj = hp_get_wmiobj_pointer(instance_id, guid); 942 } 943 944 err_attr_init: 945 mutex_unlock(&bioscfg_drv.mutex); 946 kfree(obj); 947 return ret; 948 } 949 950 static int __init hp_init(void) 951 { 952 int ret; 953 int hp_bios_capable = wmi_has_guid(HP_WMI_BIOS_GUID); 954 int set_bios_settings = wmi_has_guid(HP_WMI_SET_BIOS_SETTING_GUID); 955 956 if (!hp_bios_capable) { 957 pr_err("Unable to run on non-HP system\n"); 958 return -ENODEV; 959 } 960 961 if (!set_bios_settings) { 962 pr_err("Unable to set BIOS settings on HP systems\n"); 963 return -ENODEV; 964 } 965 966 ret = hp_init_attr_set_interface(); 967 if (ret) 968 return ret; 969 970 bioscfg_drv.class_dev = device_create(&firmware_attributes_class, NULL, MKDEV(0, 0), 971 NULL, "%s", DRIVER_NAME); 972 if (IS_ERR(bioscfg_drv.class_dev)) { 973 ret = PTR_ERR(bioscfg_drv.class_dev); 974 goto err_unregister_class; 975 } 976 977 bioscfg_drv.main_dir_kset = kset_create_and_add("attributes", NULL, 978 &bioscfg_drv.class_dev->kobj); 979 if (!bioscfg_drv.main_dir_kset) { 980 ret = -ENOMEM; 981 pr_debug("Failed to create and add attributes\n"); 982 goto err_destroy_classdev; 983 } 984 985 bioscfg_drv.authentication_dir_kset = kset_create_and_add("authentication", NULL, 986 &bioscfg_drv.class_dev->kobj); 987 if (!bioscfg_drv.authentication_dir_kset) { 988 ret = -ENOMEM; 989 pr_debug("Failed to create and add authentication\n"); 990 goto err_release_attributes_data; 991 } 992 993 /* 994 * sysfs level attributes. 995 * - pending_reboot 996 */ 997 ret = create_attributes_level_sysfs_files(); 998 if (ret) 999 pr_debug("Failed to create sysfs level attributes\n"); 1000 1001 ret = hp_init_bios_attributes(HPWMI_STRING_TYPE, HP_WMI_BIOS_STRING_GUID); 1002 if (ret) 1003 pr_debug("Failed to populate string type attributes\n"); 1004 1005 ret = hp_init_bios_attributes(HPWMI_INTEGER_TYPE, HP_WMI_BIOS_INTEGER_GUID); 1006 if (ret) 1007 pr_debug("Failed to populate integer type attributes\n"); 1008 1009 ret = hp_init_bios_attributes(HPWMI_ENUMERATION_TYPE, HP_WMI_BIOS_ENUMERATION_GUID); 1010 if (ret) 1011 pr_debug("Failed to populate enumeration type attributes\n"); 1012 1013 ret = hp_init_bios_attributes(HPWMI_ORDERED_LIST_TYPE, HP_WMI_BIOS_ORDERED_LIST_GUID); 1014 if (ret) 1015 pr_debug("Failed to populate ordered list object type attributes\n"); 1016 1017 ret = hp_init_bios_attributes(HPWMI_PASSWORD_TYPE, HP_WMI_BIOS_PASSWORD_GUID); 1018 if (ret) 1019 pr_debug("Failed to populate password object type attributes\n"); 1020 1021 bioscfg_drv.spm_data.attr_name_kobj = NULL; 1022 ret = hp_add_other_attributes(HPWMI_SECURE_PLATFORM_TYPE); 1023 if (ret) 1024 pr_debug("Failed to populate secure platform object type attribute\n"); 1025 1026 bioscfg_drv.sure_start_attr_kobj = NULL; 1027 ret = hp_add_other_attributes(HPWMI_SURE_START_TYPE); 1028 if (ret) 1029 pr_debug("Failed to populate sure start object type attribute\n"); 1030 1031 return 0; 1032 1033 err_release_attributes_data: 1034 release_attributes_data(); 1035 1036 err_destroy_classdev: 1037 device_destroy(&firmware_attributes_class, MKDEV(0, 0)); 1038 1039 err_unregister_class: 1040 hp_exit_attr_set_interface(); 1041 1042 return ret; 1043 } 1044 1045 static void __exit hp_exit(void) 1046 { 1047 release_attributes_data(); 1048 device_destroy(&firmware_attributes_class, MKDEV(0, 0)); 1049 1050 hp_exit_attr_set_interface(); 1051 } 1052 1053 module_init(hp_init); 1054 module_exit(hp_exit); 1055