1066 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Common methods for use with hp-bioscfg driver4 *5 * Copyright (c) 2022 HP Development Company, L.P.6 */7 8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt9 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 19MODULE_AUTHOR("Jorge Lopez <jorge.lopez2@hp.com>");20MODULE_DESCRIPTION("HP BIOS Configuration Driver");21MODULE_LICENSE("GPL");22 23struct bioscfg_priv bioscfg_drv = {24 .mutex = __MUTEX_INITIALIZER(bioscfg_drv.mutex),25};26 27static const struct class *fw_attr_class;28 29ssize_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 36struct kobj_attribute common_display_langcode =37 __ATTR_RO(display_name_language_code);38 39int 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 54int 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 convert71 * the string72 */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 of85 * 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 ASCII93 */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 else116 dst[i] = *src;117 src++;118 }119 120 *buffer = (u8 *)src;121 *buffer_size -= size * sizeof(u16);122 123 return size;124}125 126int 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 187common_exit:188 return ret;189}190 191int 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 */206void 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 for214 * use with BIOS communication215 *216 * @str: the string to calculate based upon217 */218size_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 230int 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 340static 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 347static struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot);348 349/*350 * create_attributes_level_sysfs_files() - Creates pending_reboot attributes351 */352static 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 358static void attr_name_release(struct kobject *kobj)359{360 kfree(kobj);361}362 363static 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 instance370 *371 * @instance_id: WMI instance ID372 * @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 return376 */377union 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_string388 *389 * @guid_string: WMI GUID (in string form)390 */391int 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 type407 *408 * @attr_type: Attribute type to allocate409 */410static 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 433int 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 char456 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 else480 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 */491int 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 to508 * 'Schedule Power-On'509 */510void 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 else516 strscpy(attr_display, attr_name, attr_size);517}518 519/**520 * hp_update_attribute_permissions() - Update attributes permissions when521 * isReadOnly value is 1522 *523 * @is_readonly: bool value to indicate if it a readonly attribute.524 * @current_val: kobj_attribute corresponding to attribute.525 *526 */527void 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 kobjects534 * @kset: The kset to destroy535 *536 * Fress kobjects created for each attribute_name under attribute type kset537 */538static 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 created548 */549static 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 not577 * reported by BIOS and required to support Secure Platform and Sure578 * Start.579 *580 * @attr_type: Custom HP attribute not reported by BIOS581 *582 * Initialize all 2 types of attributes: Platform and Sure Start583 * object. Populates each attribute types respective properties584 * under sysfs files.585 *586 * Returns zero(0) if successful. Otherwise, a negative value.587 */588static int hp_add_other_attributes(int attr_type)589{590 struct kobject *attr_name_kobj;591 int ret;592 char *attr_name;593 594 attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);595 if (!attr_name_kobj)596 return -ENOMEM;597 598 mutex_lock(&bioscfg_drv.mutex);599 600 /* Check if attribute type is supported */601 switch (attr_type) {602 case HPWMI_SECURE_PLATFORM_TYPE:603 attr_name_kobj->kset = bioscfg_drv.authentication_dir_kset;604 attr_name = SPM_STR;605 break;606 607 case HPWMI_SURE_START_TYPE:608 attr_name_kobj->kset = bioscfg_drv.main_dir_kset;609 attr_name = SURE_START_STR;610 break;611 612 default:613 pr_err("Error: Unknown attr_type: %d\n", attr_type);614 ret = -EINVAL;615 kfree(attr_name_kobj);616 goto unlock_drv_mutex;617 }618 619 ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype,620 NULL, "%s", attr_name);621 if (ret) {622 pr_err("Error encountered [%d]\n", ret);623 goto err_other_attr_init;624 }625 626 /* Populate attribute data */627 switch (attr_type) {628 case HPWMI_SECURE_PLATFORM_TYPE:629 ret = hp_populate_secure_platform_data(attr_name_kobj);630 break;631 632 case HPWMI_SURE_START_TYPE:633 ret = hp_populate_sure_start_data(attr_name_kobj);634 break;635 636 default:637 ret = -EINVAL;638 }639 640 if (ret)641 goto err_other_attr_init;642 643 mutex_unlock(&bioscfg_drv.mutex);644 return 0;645 646err_other_attr_init:647 kobject_put(attr_name_kobj);648unlock_drv_mutex:649 mutex_unlock(&bioscfg_drv.mutex);650 return ret;651}652 653static int hp_init_bios_package_attribute(enum hp_wmi_data_type attr_type,654 union acpi_object *obj,655 const char *guid, int min_elements,656 int instance_id)657{658 struct kobject *attr_name_kobj, *duplicate;659 union acpi_object *elements;660 struct kset *temp_kset;661 662 char *str_value = NULL;663 int str_len;664 int ret = 0;665 666 /* Take action appropriate to each ACPI TYPE */667 if (obj->package.count < min_elements) {668 pr_err("ACPI-package does not have enough elements: %d < %d\n",669 obj->package.count, min_elements);670 goto pack_attr_exit;671 }672 673 elements = obj->package.elements;674 675 /* sanity checking */676 if (elements[NAME].type != ACPI_TYPE_STRING) {677 pr_debug("incorrect element type\n");678 goto pack_attr_exit;679 }680 if (strlen(elements[NAME].string.pointer) == 0) {681 pr_debug("empty attribute found\n");682 goto pack_attr_exit;683 }684 685 if (attr_type == HPWMI_PASSWORD_TYPE)686 temp_kset = bioscfg_drv.authentication_dir_kset;687 else688 temp_kset = bioscfg_drv.main_dir_kset;689 690 /* convert attribute name to string */691 ret = hp_convert_hexstr_to_str(elements[NAME].string.pointer,692 elements[NAME].string.length,693 &str_value, &str_len);694 695 if (ret) {696 pr_debug("Failed to populate integer package data. Error [0%0x]\n",697 ret);698 kfree(str_value);699 return ret;700 }701 702 /* All duplicate attributes found are ignored */703 duplicate = kset_find_obj(temp_kset, str_value);704 if (duplicate) {705 pr_debug("Duplicate attribute name found - %s\n", str_value);706 /* kset_find_obj() returns a reference */707 kobject_put(duplicate);708 goto pack_attr_exit;709 }710 711 /* build attribute */712 attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);713 if (!attr_name_kobj) {714 ret = -ENOMEM;715 goto pack_attr_exit;716 }717 718 attr_name_kobj->kset = temp_kset;719 720 ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype,721 NULL, "%s", str_value);722 723 if (ret) {724 kobject_put(attr_name_kobj);725 goto pack_attr_exit;726 }727 728 /* enumerate all of these attributes */729 switch (attr_type) {730 case HPWMI_STRING_TYPE:731 ret = hp_populate_string_package_data(elements,732 instance_id,733 attr_name_kobj);734 break;735 case HPWMI_INTEGER_TYPE:736 ret = hp_populate_integer_package_data(elements,737 instance_id,738 attr_name_kobj);739 break;740 case HPWMI_ENUMERATION_TYPE:741 ret = hp_populate_enumeration_package_data(elements,742 instance_id,743 attr_name_kobj);744 break;745 case HPWMI_ORDERED_LIST_TYPE:746 ret = hp_populate_ordered_list_package_data(elements,747 instance_id,748 attr_name_kobj);749 break;750 case HPWMI_PASSWORD_TYPE:751 ret = hp_populate_password_package_data(elements,752 instance_id,753 attr_name_kobj);754 break;755 default:756 pr_debug("Unknown attribute type found: 0x%x\n", attr_type);757 break;758 }759 760pack_attr_exit:761 kfree(str_value);762 return ret;763}764 765static int hp_init_bios_buffer_attribute(enum hp_wmi_data_type attr_type,766 union acpi_object *obj,767 const char *guid, int min_elements,768 int instance_id)769{770 struct kobject *attr_name_kobj, *duplicate;771 struct kset *temp_kset;772 char str[MAX_BUFF_SIZE];773 774 char *temp_str = NULL;775 char *str_value = NULL;776 u8 *buffer_ptr = NULL;777 int buffer_size;778 int ret = 0;779 780 buffer_size = obj->buffer.length;781 buffer_ptr = obj->buffer.pointer;782 783 ret = hp_get_string_from_buffer(&buffer_ptr,784 &buffer_size, str, MAX_BUFF_SIZE);785 786 if (ret < 0)787 goto buff_attr_exit;788 789 if (attr_type == HPWMI_PASSWORD_TYPE ||790 attr_type == HPWMI_SECURE_PLATFORM_TYPE)791 temp_kset = bioscfg_drv.authentication_dir_kset;792 else793 temp_kset = bioscfg_drv.main_dir_kset;794 795 /* All duplicate attributes found are ignored */796 duplicate = kset_find_obj(temp_kset, str);797 if (duplicate) {798 pr_debug("Duplicate attribute name found - %s\n", str);799 /* kset_find_obj() returns a reference */800 kobject_put(duplicate);801 goto buff_attr_exit;802 }803 804 /* build attribute */805 attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL);806 if (!attr_name_kobj) {807 ret = -ENOMEM;808 goto buff_attr_exit;809 }810 811 attr_name_kobj->kset = temp_kset;812 813 temp_str = str;814 if (attr_type == HPWMI_SECURE_PLATFORM_TYPE)815 temp_str = "SPM";816 817 ret = kobject_init_and_add(attr_name_kobj,818 &attr_name_ktype, NULL, "%s", temp_str);819 if (ret) {820 kobject_put(attr_name_kobj);821 goto buff_attr_exit;822 }823 824 /* enumerate all of these attributes */825 switch (attr_type) {826 case HPWMI_STRING_TYPE:827 ret = hp_populate_string_buffer_data(buffer_ptr,828 &buffer_size,829 instance_id,830 attr_name_kobj);831 break;832 case HPWMI_INTEGER_TYPE:833 ret = hp_populate_integer_buffer_data(buffer_ptr,834 &buffer_size,835 instance_id,836 attr_name_kobj);837 break;838 case HPWMI_ENUMERATION_TYPE:839 ret = hp_populate_enumeration_buffer_data(buffer_ptr,840 &buffer_size,841 instance_id,842 attr_name_kobj);843 break;844 case HPWMI_ORDERED_LIST_TYPE:845 ret = hp_populate_ordered_list_buffer_data(buffer_ptr,846 &buffer_size,847 instance_id,848 attr_name_kobj);849 break;850 case HPWMI_PASSWORD_TYPE:851 ret = hp_populate_password_buffer_data(buffer_ptr,852 &buffer_size,853 instance_id,854 attr_name_kobj);855 break;856 default:857 pr_debug("Unknown attribute type found: 0x%x\n", attr_type);858 break;859 }860 861buff_attr_exit:862 kfree(str_value);863 return ret;864}865 866/**867 * hp_init_bios_attributes() - Initialize all attributes for a type868 * @attr_type: The attribute type to initialize869 * @guid: The WMI GUID associated with this type to initialize870 *871 * Initialize all 5 types of attributes: enumeration, integer,872 * string, password, ordered list object. Populates each attribute types873 * respective properties under sysfs files874 */875static int hp_init_bios_attributes(enum hp_wmi_data_type attr_type, const char *guid)876{877 union acpi_object *obj = NULL;878 int min_elements;879 880 /* instance_id needs to be reset for each type GUID881 * also, instance IDs are unique within GUID but not across882 */883 int instance_id = 0;884 int cur_instance_id = instance_id;885 int ret = 0;886 887 ret = hp_alloc_attributes_data(attr_type);888 if (ret)889 return ret;890 891 switch (attr_type) {892 case HPWMI_STRING_TYPE:893 min_elements = STR_ELEM_CNT;894 break;895 case HPWMI_INTEGER_TYPE:896 min_elements = INT_ELEM_CNT;897 break;898 case HPWMI_ENUMERATION_TYPE:899 min_elements = ENUM_ELEM_CNT;900 break;901 case HPWMI_ORDERED_LIST_TYPE:902 min_elements = ORD_ELEM_CNT;903 break;904 case HPWMI_PASSWORD_TYPE:905 min_elements = PSWD_ELEM_CNT;906 break;907 default:908 pr_err("Error: Unknown attr_type: %d\n", attr_type);909 return -EINVAL;910 }911 912 /* need to use specific instance_id and guid combination to get right data */913 obj = hp_get_wmiobj_pointer(instance_id, guid);914 if (!obj)915 return -ENODEV;916 917 mutex_lock(&bioscfg_drv.mutex);918 while (obj) {919 /* Take action appropriate to each ACPI TYPE */920 if (obj->type == ACPI_TYPE_PACKAGE) {921 ret = hp_init_bios_package_attribute(attr_type, obj,922 guid, min_elements,923 cur_instance_id);924 925 } else if (obj->type == ACPI_TYPE_BUFFER) {926 ret = hp_init_bios_buffer_attribute(attr_type, obj,927 guid, min_elements,928 cur_instance_id);929 930 } else {931 pr_err("Expected ACPI-package or buffer type, got: %d\n",932 obj->type);933 ret = -EIO;934 goto err_attr_init;935 }936 937 /*938 * Failure reported in one attribute must not939 * stop process of the remaining attribute values.940 */941 if (ret >= 0)942 cur_instance_id++;943 944 kfree(obj);945 instance_id++;946 obj = hp_get_wmiobj_pointer(instance_id, guid);947 }948 949err_attr_init:950 mutex_unlock(&bioscfg_drv.mutex);951 kfree(obj);952 return ret;953}954 955static int __init hp_init(void)956{957 int ret;958 int hp_bios_capable = wmi_has_guid(HP_WMI_BIOS_GUID);959 int set_bios_settings = wmi_has_guid(HP_WMI_SET_BIOS_SETTING_GUID);960 961 if (!hp_bios_capable) {962 pr_err("Unable to run on non-HP system\n");963 return -ENODEV;964 }965 966 if (!set_bios_settings) {967 pr_err("Unable to set BIOS settings on HP systems\n");968 return -ENODEV;969 }970 971 ret = hp_init_attr_set_interface();972 if (ret)973 return ret;974 975 ret = fw_attributes_class_get(&fw_attr_class);976 if (ret)977 goto err_unregister_class;978 979 bioscfg_drv.class_dev = device_create(fw_attr_class, NULL, MKDEV(0, 0),980 NULL, "%s", DRIVER_NAME);981 if (IS_ERR(bioscfg_drv.class_dev)) {982 ret = PTR_ERR(bioscfg_drv.class_dev);983 goto err_unregister_class;984 }985 986 bioscfg_drv.main_dir_kset = kset_create_and_add("attributes", NULL,987 &bioscfg_drv.class_dev->kobj);988 if (!bioscfg_drv.main_dir_kset) {989 ret = -ENOMEM;990 pr_debug("Failed to create and add attributes\n");991 goto err_destroy_classdev;992 }993 994 bioscfg_drv.authentication_dir_kset = kset_create_and_add("authentication", NULL,995 &bioscfg_drv.class_dev->kobj);996 if (!bioscfg_drv.authentication_dir_kset) {997 ret = -ENOMEM;998 pr_debug("Failed to create and add authentication\n");999 goto err_release_attributes_data;1000 }1001 1002 /*1003 * sysfs level attributes.1004 * - pending_reboot1005 */1006 ret = create_attributes_level_sysfs_files();1007 if (ret)1008 pr_debug("Failed to create sysfs level attributes\n");1009 1010 ret = hp_init_bios_attributes(HPWMI_STRING_TYPE, HP_WMI_BIOS_STRING_GUID);1011 if (ret)1012 pr_debug("Failed to populate string type attributes\n");1013 1014 ret = hp_init_bios_attributes(HPWMI_INTEGER_TYPE, HP_WMI_BIOS_INTEGER_GUID);1015 if (ret)1016 pr_debug("Failed to populate integer type attributes\n");1017 1018 ret = hp_init_bios_attributes(HPWMI_ENUMERATION_TYPE, HP_WMI_BIOS_ENUMERATION_GUID);1019 if (ret)1020 pr_debug("Failed to populate enumeration type attributes\n");1021 1022 ret = hp_init_bios_attributes(HPWMI_ORDERED_LIST_TYPE, HP_WMI_BIOS_ORDERED_LIST_GUID);1023 if (ret)1024 pr_debug("Failed to populate ordered list object type attributes\n");1025 1026 ret = hp_init_bios_attributes(HPWMI_PASSWORD_TYPE, HP_WMI_BIOS_PASSWORD_GUID);1027 if (ret)1028 pr_debug("Failed to populate password object type attributes\n");1029 1030 bioscfg_drv.spm_data.attr_name_kobj = NULL;1031 ret = hp_add_other_attributes(HPWMI_SECURE_PLATFORM_TYPE);1032 if (ret)1033 pr_debug("Failed to populate secure platform object type attribute\n");1034 1035 bioscfg_drv.sure_start_attr_kobj = NULL;1036 ret = hp_add_other_attributes(HPWMI_SURE_START_TYPE);1037 if (ret)1038 pr_debug("Failed to populate sure start object type attribute\n");1039 1040 return 0;1041 1042err_release_attributes_data:1043 release_attributes_data();1044 1045err_destroy_classdev:1046 device_destroy(fw_attr_class, MKDEV(0, 0));1047 1048err_unregister_class:1049 fw_attributes_class_put();1050 hp_exit_attr_set_interface();1051 1052 return ret;1053}1054 1055static void __exit hp_exit(void)1056{1057 release_attributes_data();1058 device_destroy(fw_attr_class, MKDEV(0, 0));1059 1060 fw_attributes_class_put();1061 hp_exit_attr_set_interface();1062}1063 1064module_init(hp_init);1065module_exit(hp_exit);1066