162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Common methods for use with hp-bioscfg driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2022 HP Development Company, L.P. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/fs.h> 1162306a36Sopenharmony_ci#include <linux/module.h> 1262306a36Sopenharmony_ci#include <linux/kernel.h> 1362306a36Sopenharmony_ci#include <linux/wmi.h> 1462306a36Sopenharmony_ci#include "bioscfg.h" 1562306a36Sopenharmony_ci#include "../../firmware_attributes_class.h" 1662306a36Sopenharmony_ci#include <linux/nls.h> 1762306a36Sopenharmony_ci#include <linux/errno.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ciMODULE_AUTHOR("Jorge Lopez <jorge.lopez2@hp.com>"); 2062306a36Sopenharmony_ciMODULE_DESCRIPTION("HP BIOS Configuration Driver"); 2162306a36Sopenharmony_ciMODULE_LICENSE("GPL"); 2262306a36Sopenharmony_ci 2362306a36Sopenharmony_cistruct bioscfg_priv bioscfg_drv = { 2462306a36Sopenharmony_ci .mutex = __MUTEX_INITIALIZER(bioscfg_drv.mutex), 2562306a36Sopenharmony_ci}; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_cistatic struct class *fw_attr_class; 2862306a36Sopenharmony_ci 2962306a36Sopenharmony_cissize_t display_name_language_code_show(struct kobject *kobj, 3062306a36Sopenharmony_ci struct kobj_attribute *attr, 3162306a36Sopenharmony_ci char *buf) 3262306a36Sopenharmony_ci{ 3362306a36Sopenharmony_ci return sysfs_emit(buf, "%s\n", LANG_CODE_STR); 3462306a36Sopenharmony_ci} 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistruct kobj_attribute common_display_langcode = 3762306a36Sopenharmony_ci __ATTR_RO(display_name_language_code); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ciint hp_get_integer_from_buffer(u8 **buffer, u32 *buffer_size, u32 *integer) 4062306a36Sopenharmony_ci{ 4162306a36Sopenharmony_ci int *ptr = PTR_ALIGN((int *)*buffer, sizeof(int)); 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_ci /* Ensure there is enough space remaining to read the integer */ 4462306a36Sopenharmony_ci if (*buffer_size < sizeof(int)) 4562306a36Sopenharmony_ci return -EINVAL; 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_ci *integer = *(ptr++); 4862306a36Sopenharmony_ci *buffer = (u8 *)ptr; 4962306a36Sopenharmony_ci *buffer_size -= sizeof(int); 5062306a36Sopenharmony_ci 5162306a36Sopenharmony_ci return 0; 5262306a36Sopenharmony_ci} 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ciint hp_get_string_from_buffer(u8 **buffer, u32 *buffer_size, char *dst, u32 dst_size) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci u16 *src = (u16 *)*buffer; 5762306a36Sopenharmony_ci u16 src_size; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci u16 size; 6062306a36Sopenharmony_ci int i; 6162306a36Sopenharmony_ci int conv_dst_size; 6262306a36Sopenharmony_ci 6362306a36Sopenharmony_ci if (*buffer_size < sizeof(u16)) 6462306a36Sopenharmony_ci return -EINVAL; 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ci src_size = *(src++); 6762306a36Sopenharmony_ci /* size value in u16 chars */ 6862306a36Sopenharmony_ci size = src_size / sizeof(u16); 6962306a36Sopenharmony_ci 7062306a36Sopenharmony_ci /* Ensure there is enough space remaining to read and convert 7162306a36Sopenharmony_ci * the string 7262306a36Sopenharmony_ci */ 7362306a36Sopenharmony_ci if (*buffer_size < src_size) 7462306a36Sopenharmony_ci return -EINVAL; 7562306a36Sopenharmony_ci 7662306a36Sopenharmony_ci for (i = 0; i < size; i++) 7762306a36Sopenharmony_ci if (src[i] == '\\' || 7862306a36Sopenharmony_ci src[i] == '\r' || 7962306a36Sopenharmony_ci src[i] == '\n' || 8062306a36Sopenharmony_ci src[i] == '\t') 8162306a36Sopenharmony_ci size++; 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci /* 8462306a36Sopenharmony_ci * Conversion is limited to destination string max number of 8562306a36Sopenharmony_ci * bytes. 8662306a36Sopenharmony_ci */ 8762306a36Sopenharmony_ci conv_dst_size = size; 8862306a36Sopenharmony_ci if (size > dst_size) 8962306a36Sopenharmony_ci conv_dst_size = dst_size - 1; 9062306a36Sopenharmony_ci 9162306a36Sopenharmony_ci /* 9262306a36Sopenharmony_ci * convert from UTF-16 unicode to ASCII 9362306a36Sopenharmony_ci */ 9462306a36Sopenharmony_ci utf16s_to_utf8s(src, src_size, UTF16_HOST_ENDIAN, dst, conv_dst_size); 9562306a36Sopenharmony_ci dst[conv_dst_size] = 0; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci for (i = 0; i < conv_dst_size; i++) { 9862306a36Sopenharmony_ci if (*src == '\\' || 9962306a36Sopenharmony_ci *src == '\r' || 10062306a36Sopenharmony_ci *src == '\n' || 10162306a36Sopenharmony_ci *src == '\t') { 10262306a36Sopenharmony_ci dst[i++] = '\\'; 10362306a36Sopenharmony_ci if (i == conv_dst_size) 10462306a36Sopenharmony_ci break; 10562306a36Sopenharmony_ci } 10662306a36Sopenharmony_ci 10762306a36Sopenharmony_ci if (*src == '\r') 10862306a36Sopenharmony_ci dst[i] = 'r'; 10962306a36Sopenharmony_ci else if (*src == '\n') 11062306a36Sopenharmony_ci dst[i] = 'n'; 11162306a36Sopenharmony_ci else if (*src == '\t') 11262306a36Sopenharmony_ci dst[i] = 't'; 11362306a36Sopenharmony_ci else if (*src == '"') 11462306a36Sopenharmony_ci dst[i] = '\''; 11562306a36Sopenharmony_ci else 11662306a36Sopenharmony_ci dst[i] = *src; 11762306a36Sopenharmony_ci src++; 11862306a36Sopenharmony_ci } 11962306a36Sopenharmony_ci 12062306a36Sopenharmony_ci *buffer = (u8 *)src; 12162306a36Sopenharmony_ci *buffer_size -= size * sizeof(u16); 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci return size; 12462306a36Sopenharmony_ci} 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ciint hp_get_common_data_from_buffer(u8 **buffer_ptr, u32 *buffer_size, 12762306a36Sopenharmony_ci struct common_data *common_data) 12862306a36Sopenharmony_ci{ 12962306a36Sopenharmony_ci int ret = 0; 13062306a36Sopenharmony_ci int reqs; 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci // PATH: 13362306a36Sopenharmony_ci ret = hp_get_string_from_buffer(buffer_ptr, buffer_size, common_data->path, 13462306a36Sopenharmony_ci sizeof(common_data->path)); 13562306a36Sopenharmony_ci if (ret < 0) 13662306a36Sopenharmony_ci goto common_exit; 13762306a36Sopenharmony_ci 13862306a36Sopenharmony_ci // IS_READONLY: 13962306a36Sopenharmony_ci ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size, 14062306a36Sopenharmony_ci &common_data->is_readonly); 14162306a36Sopenharmony_ci if (ret < 0) 14262306a36Sopenharmony_ci goto common_exit; 14362306a36Sopenharmony_ci 14462306a36Sopenharmony_ci //DISPLAY_IN_UI: 14562306a36Sopenharmony_ci ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size, 14662306a36Sopenharmony_ci &common_data->display_in_ui); 14762306a36Sopenharmony_ci if (ret < 0) 14862306a36Sopenharmony_ci goto common_exit; 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_ci // REQUIRES_PHYSICAL_PRESENCE: 15162306a36Sopenharmony_ci ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size, 15262306a36Sopenharmony_ci &common_data->requires_physical_presence); 15362306a36Sopenharmony_ci if (ret < 0) 15462306a36Sopenharmony_ci goto common_exit; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_ci // SEQUENCE: 15762306a36Sopenharmony_ci ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size, 15862306a36Sopenharmony_ci &common_data->sequence); 15962306a36Sopenharmony_ci if (ret < 0) 16062306a36Sopenharmony_ci goto common_exit; 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci // PREREQUISITES_SIZE: 16362306a36Sopenharmony_ci ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size, 16462306a36Sopenharmony_ci &common_data->prerequisites_size); 16562306a36Sopenharmony_ci if (ret < 0) 16662306a36Sopenharmony_ci goto common_exit; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (common_data->prerequisites_size > MAX_PREREQUISITES_SIZE) { 16962306a36Sopenharmony_ci /* Report a message and limit prerequisite size to maximum value */ 17062306a36Sopenharmony_ci pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n"); 17162306a36Sopenharmony_ci common_data->prerequisites_size = MAX_PREREQUISITES_SIZE; 17262306a36Sopenharmony_ci } 17362306a36Sopenharmony_ci 17462306a36Sopenharmony_ci // PREREQUISITES: 17562306a36Sopenharmony_ci for (reqs = 0; reqs < common_data->prerequisites_size; reqs++) { 17662306a36Sopenharmony_ci ret = hp_get_string_from_buffer(buffer_ptr, buffer_size, 17762306a36Sopenharmony_ci common_data->prerequisites[reqs], 17862306a36Sopenharmony_ci sizeof(common_data->prerequisites[reqs])); 17962306a36Sopenharmony_ci if (ret < 0) 18062306a36Sopenharmony_ci break; 18162306a36Sopenharmony_ci } 18262306a36Sopenharmony_ci 18362306a36Sopenharmony_ci // SECURITY_LEVEL: 18462306a36Sopenharmony_ci ret = hp_get_integer_from_buffer(buffer_ptr, buffer_size, 18562306a36Sopenharmony_ci &common_data->security_level); 18662306a36Sopenharmony_ci 18762306a36Sopenharmony_cicommon_exit: 18862306a36Sopenharmony_ci return ret; 18962306a36Sopenharmony_ci} 19062306a36Sopenharmony_ci 19162306a36Sopenharmony_ciint hp_enforce_single_line_input(char *buf, size_t count) 19262306a36Sopenharmony_ci{ 19362306a36Sopenharmony_ci char *p; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci p = memchr(buf, '\n', count); 19662306a36Sopenharmony_ci 19762306a36Sopenharmony_ci if (p == buf + count - 1) 19862306a36Sopenharmony_ci *p = '\0'; /* strip trailing newline */ 19962306a36Sopenharmony_ci else if (p) 20062306a36Sopenharmony_ci return -EINVAL; /* enforce single line input */ 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci return 0; 20362306a36Sopenharmony_ci} 20462306a36Sopenharmony_ci 20562306a36Sopenharmony_ci/* Set pending reboot value and generate KOBJ_NAME event */ 20662306a36Sopenharmony_civoid hp_set_reboot_and_signal_event(void) 20762306a36Sopenharmony_ci{ 20862306a36Sopenharmony_ci bioscfg_drv.pending_reboot = true; 20962306a36Sopenharmony_ci kobject_uevent(&bioscfg_drv.class_dev->kobj, KOBJ_CHANGE); 21062306a36Sopenharmony_ci} 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci/** 21362306a36Sopenharmony_ci * hp_calculate_string_buffer() - determines size of string buffer for 21462306a36Sopenharmony_ci * use with BIOS communication 21562306a36Sopenharmony_ci * 21662306a36Sopenharmony_ci * @str: the string to calculate based upon 21762306a36Sopenharmony_ci */ 21862306a36Sopenharmony_cisize_t hp_calculate_string_buffer(const char *str) 21962306a36Sopenharmony_ci{ 22062306a36Sopenharmony_ci size_t length = strlen(str); 22162306a36Sopenharmony_ci 22262306a36Sopenharmony_ci /* BIOS expects 4 bytes when an empty string is found */ 22362306a36Sopenharmony_ci if (length == 0) 22462306a36Sopenharmony_ci return 4; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci /* u16 length field + one UTF16 char for each input char */ 22762306a36Sopenharmony_ci return sizeof(u16) + strlen(str) * sizeof(u16); 22862306a36Sopenharmony_ci} 22962306a36Sopenharmony_ci 23062306a36Sopenharmony_ciint hp_wmi_error_and_message(int error_code) 23162306a36Sopenharmony_ci{ 23262306a36Sopenharmony_ci char *error_msg = NULL; 23362306a36Sopenharmony_ci int ret; 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_ci switch (error_code) { 23662306a36Sopenharmony_ci case SUCCESS: 23762306a36Sopenharmony_ci error_msg = "Success"; 23862306a36Sopenharmony_ci ret = 0; 23962306a36Sopenharmony_ci break; 24062306a36Sopenharmony_ci case CMD_FAILED: 24162306a36Sopenharmony_ci error_msg = "Command failed"; 24262306a36Sopenharmony_ci ret = -EINVAL; 24362306a36Sopenharmony_ci break; 24462306a36Sopenharmony_ci case INVALID_SIGN: 24562306a36Sopenharmony_ci error_msg = "Invalid signature"; 24662306a36Sopenharmony_ci ret = -EINVAL; 24762306a36Sopenharmony_ci break; 24862306a36Sopenharmony_ci case INVALID_CMD_VALUE: 24962306a36Sopenharmony_ci error_msg = "Invalid command value/Feature not supported"; 25062306a36Sopenharmony_ci ret = -EOPNOTSUPP; 25162306a36Sopenharmony_ci break; 25262306a36Sopenharmony_ci case INVALID_CMD_TYPE: 25362306a36Sopenharmony_ci error_msg = "Invalid command type"; 25462306a36Sopenharmony_ci ret = -EINVAL; 25562306a36Sopenharmony_ci break; 25662306a36Sopenharmony_ci case INVALID_DATA_SIZE: 25762306a36Sopenharmony_ci error_msg = "Invalid data size"; 25862306a36Sopenharmony_ci ret = -EINVAL; 25962306a36Sopenharmony_ci break; 26062306a36Sopenharmony_ci case INVALID_CMD_PARAM: 26162306a36Sopenharmony_ci error_msg = "Invalid command parameter"; 26262306a36Sopenharmony_ci ret = -EINVAL; 26362306a36Sopenharmony_ci break; 26462306a36Sopenharmony_ci case ENCRYP_CMD_REQUIRED: 26562306a36Sopenharmony_ci error_msg = "Secure/encrypted command required"; 26662306a36Sopenharmony_ci ret = -EACCES; 26762306a36Sopenharmony_ci break; 26862306a36Sopenharmony_ci case NO_SECURE_SESSION: 26962306a36Sopenharmony_ci error_msg = "No secure session established"; 27062306a36Sopenharmony_ci ret = -EACCES; 27162306a36Sopenharmony_ci break; 27262306a36Sopenharmony_ci case SECURE_SESSION_FOUND: 27362306a36Sopenharmony_ci error_msg = "Secure session already established"; 27462306a36Sopenharmony_ci ret = -EACCES; 27562306a36Sopenharmony_ci break; 27662306a36Sopenharmony_ci case SECURE_SESSION_FAILED: 27762306a36Sopenharmony_ci error_msg = "Secure session failed"; 27862306a36Sopenharmony_ci ret = -EIO; 27962306a36Sopenharmony_ci break; 28062306a36Sopenharmony_ci case AUTH_FAILED: 28162306a36Sopenharmony_ci error_msg = "Other permission/Authentication failed"; 28262306a36Sopenharmony_ci ret = -EACCES; 28362306a36Sopenharmony_ci break; 28462306a36Sopenharmony_ci case INVALID_BIOS_AUTH: 28562306a36Sopenharmony_ci error_msg = "Invalid BIOS administrator password"; 28662306a36Sopenharmony_ci ret = -EINVAL; 28762306a36Sopenharmony_ci break; 28862306a36Sopenharmony_ci case NONCE_DID_NOT_MATCH: 28962306a36Sopenharmony_ci error_msg = "Nonce did not match"; 29062306a36Sopenharmony_ci ret = -EINVAL; 29162306a36Sopenharmony_ci break; 29262306a36Sopenharmony_ci case GENERIC_ERROR: 29362306a36Sopenharmony_ci error_msg = "Generic/Other error"; 29462306a36Sopenharmony_ci ret = -EIO; 29562306a36Sopenharmony_ci break; 29662306a36Sopenharmony_ci case BIOS_ADMIN_POLICY_NOT_MET: 29762306a36Sopenharmony_ci error_msg = "BIOS Admin password does not meet password policy requirements"; 29862306a36Sopenharmony_ci ret = -EINVAL; 29962306a36Sopenharmony_ci break; 30062306a36Sopenharmony_ci case BIOS_ADMIN_NOT_SET: 30162306a36Sopenharmony_ci error_msg = "BIOS Setup password is not set"; 30262306a36Sopenharmony_ci ret = -EPERM; 30362306a36Sopenharmony_ci break; 30462306a36Sopenharmony_ci case P21_NO_PROVISIONED: 30562306a36Sopenharmony_ci error_msg = "P21 is not provisioned"; 30662306a36Sopenharmony_ci ret = -EPERM; 30762306a36Sopenharmony_ci break; 30862306a36Sopenharmony_ci case P21_PROVISION_IN_PROGRESS: 30962306a36Sopenharmony_ci error_msg = "P21 is already provisioned or provisioning is in progress and a signing key has already been sent"; 31062306a36Sopenharmony_ci ret = -EINPROGRESS; 31162306a36Sopenharmony_ci break; 31262306a36Sopenharmony_ci case P21_IN_USE: 31362306a36Sopenharmony_ci error_msg = "P21 in use (cannot deprovision)"; 31462306a36Sopenharmony_ci ret = -EPERM; 31562306a36Sopenharmony_ci break; 31662306a36Sopenharmony_ci case HEP_NOT_ACTIVE: 31762306a36Sopenharmony_ci error_msg = "HEP not activated"; 31862306a36Sopenharmony_ci ret = -EPERM; 31962306a36Sopenharmony_ci break; 32062306a36Sopenharmony_ci case HEP_ALREADY_SET: 32162306a36Sopenharmony_ci error_msg = "HEP Transport already set"; 32262306a36Sopenharmony_ci ret = -EINVAL; 32362306a36Sopenharmony_ci break; 32462306a36Sopenharmony_ci case HEP_CHECK_STATE: 32562306a36Sopenharmony_ci error_msg = "Check the current HEP state"; 32662306a36Sopenharmony_ci ret = -EINVAL; 32762306a36Sopenharmony_ci break; 32862306a36Sopenharmony_ci default: 32962306a36Sopenharmony_ci error_msg = "Generic/Other error"; 33062306a36Sopenharmony_ci ret = -EIO; 33162306a36Sopenharmony_ci break; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci if (error_code) 33562306a36Sopenharmony_ci pr_warn_ratelimited("Returned error 0x%x, \"%s\"\n", error_code, error_msg); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci return ret; 33862306a36Sopenharmony_ci} 33962306a36Sopenharmony_ci 34062306a36Sopenharmony_cistatic ssize_t pending_reboot_show(struct kobject *kobj, 34162306a36Sopenharmony_ci struct kobj_attribute *attr, 34262306a36Sopenharmony_ci char *buf) 34362306a36Sopenharmony_ci{ 34462306a36Sopenharmony_ci return sysfs_emit(buf, "%d\n", bioscfg_drv.pending_reboot); 34562306a36Sopenharmony_ci} 34662306a36Sopenharmony_ci 34762306a36Sopenharmony_cistatic struct kobj_attribute pending_reboot = __ATTR_RO(pending_reboot); 34862306a36Sopenharmony_ci 34962306a36Sopenharmony_ci/* 35062306a36Sopenharmony_ci * create_attributes_level_sysfs_files() - Creates pending_reboot attributes 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_cistatic int create_attributes_level_sysfs_files(void) 35362306a36Sopenharmony_ci{ 35462306a36Sopenharmony_ci return sysfs_create_file(&bioscfg_drv.main_dir_kset->kobj, 35562306a36Sopenharmony_ci &pending_reboot.attr); 35662306a36Sopenharmony_ci} 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_cistatic void attr_name_release(struct kobject *kobj) 35962306a36Sopenharmony_ci{ 36062306a36Sopenharmony_ci kfree(kobj); 36162306a36Sopenharmony_ci} 36262306a36Sopenharmony_ci 36362306a36Sopenharmony_cistatic const struct kobj_type attr_name_ktype = { 36462306a36Sopenharmony_ci .release = attr_name_release, 36562306a36Sopenharmony_ci .sysfs_ops = &kobj_sysfs_ops, 36662306a36Sopenharmony_ci}; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci/** 36962306a36Sopenharmony_ci * hp_get_wmiobj_pointer() - Get Content of WMI block for particular instance 37062306a36Sopenharmony_ci * 37162306a36Sopenharmony_ci * @instance_id: WMI instance ID 37262306a36Sopenharmony_ci * @guid_string: WMI GUID (in str form) 37362306a36Sopenharmony_ci * 37462306a36Sopenharmony_ci * Fetches the content for WMI block (instance_id) under GUID (guid_string) 37562306a36Sopenharmony_ci * Caller must kfree the return 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_ciunion acpi_object *hp_get_wmiobj_pointer(int instance_id, const char *guid_string) 37862306a36Sopenharmony_ci{ 37962306a36Sopenharmony_ci struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL }; 38062306a36Sopenharmony_ci acpi_status status; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci status = wmi_query_block(guid_string, instance_id, &out); 38362306a36Sopenharmony_ci return ACPI_SUCCESS(status) ? (union acpi_object *)out.pointer : NULL; 38462306a36Sopenharmony_ci} 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci/** 38762306a36Sopenharmony_ci * hp_get_instance_count() - Compute total number of instances under guid_string 38862306a36Sopenharmony_ci * 38962306a36Sopenharmony_ci * @guid_string: WMI GUID (in string form) 39062306a36Sopenharmony_ci */ 39162306a36Sopenharmony_ciint hp_get_instance_count(const char *guid_string) 39262306a36Sopenharmony_ci{ 39362306a36Sopenharmony_ci union acpi_object *wmi_obj = NULL; 39462306a36Sopenharmony_ci int i = 0; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci do { 39762306a36Sopenharmony_ci kfree(wmi_obj); 39862306a36Sopenharmony_ci wmi_obj = hp_get_wmiobj_pointer(i, guid_string); 39962306a36Sopenharmony_ci i++; 40062306a36Sopenharmony_ci } while (wmi_obj); 40162306a36Sopenharmony_ci 40262306a36Sopenharmony_ci return i - 1; 40362306a36Sopenharmony_ci} 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/** 40662306a36Sopenharmony_ci * hp_alloc_attributes_data() - Allocate attributes data for a particular type 40762306a36Sopenharmony_ci * 40862306a36Sopenharmony_ci * @attr_type: Attribute type to allocate 40962306a36Sopenharmony_ci */ 41062306a36Sopenharmony_cistatic int hp_alloc_attributes_data(int attr_type) 41162306a36Sopenharmony_ci{ 41262306a36Sopenharmony_ci switch (attr_type) { 41362306a36Sopenharmony_ci case HPWMI_STRING_TYPE: 41462306a36Sopenharmony_ci return hp_alloc_string_data(); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_ci case HPWMI_INTEGER_TYPE: 41762306a36Sopenharmony_ci return hp_alloc_integer_data(); 41862306a36Sopenharmony_ci 41962306a36Sopenharmony_ci case HPWMI_ENUMERATION_TYPE: 42062306a36Sopenharmony_ci return hp_alloc_enumeration_data(); 42162306a36Sopenharmony_ci 42262306a36Sopenharmony_ci case HPWMI_ORDERED_LIST_TYPE: 42362306a36Sopenharmony_ci return hp_alloc_ordered_list_data(); 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci case HPWMI_PASSWORD_TYPE: 42662306a36Sopenharmony_ci return hp_alloc_password_data(); 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_ci default: 42962306a36Sopenharmony_ci return 0; 43062306a36Sopenharmony_ci } 43162306a36Sopenharmony_ci} 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ciint hp_convert_hexstr_to_str(const char *input, u32 input_len, char **str, int *len) 43462306a36Sopenharmony_ci{ 43562306a36Sopenharmony_ci int ret = 0; 43662306a36Sopenharmony_ci int new_len = 0; 43762306a36Sopenharmony_ci char tmp[] = "0x00"; 43862306a36Sopenharmony_ci char *new_str = NULL; 43962306a36Sopenharmony_ci long ch; 44062306a36Sopenharmony_ci int i; 44162306a36Sopenharmony_ci 44262306a36Sopenharmony_ci if (input_len <= 0 || !input || !str || !len) 44362306a36Sopenharmony_ci return -EINVAL; 44462306a36Sopenharmony_ci 44562306a36Sopenharmony_ci *len = 0; 44662306a36Sopenharmony_ci *str = NULL; 44762306a36Sopenharmony_ci 44862306a36Sopenharmony_ci new_str = kmalloc(input_len, GFP_KERNEL); 44962306a36Sopenharmony_ci if (!new_str) 45062306a36Sopenharmony_ci return -ENOMEM; 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci for (i = 0; i < input_len; i += 5) { 45362306a36Sopenharmony_ci strncpy(tmp, input + i, strlen(tmp)); 45462306a36Sopenharmony_ci if (kstrtol(tmp, 16, &ch) == 0) { 45562306a36Sopenharmony_ci // escape char 45662306a36Sopenharmony_ci if (ch == '\\' || 45762306a36Sopenharmony_ci ch == '\r' || 45862306a36Sopenharmony_ci ch == '\n' || ch == '\t') { 45962306a36Sopenharmony_ci if (ch == '\r') 46062306a36Sopenharmony_ci ch = 'r'; 46162306a36Sopenharmony_ci else if (ch == '\n') 46262306a36Sopenharmony_ci ch = 'n'; 46362306a36Sopenharmony_ci else if (ch == '\t') 46462306a36Sopenharmony_ci ch = 't'; 46562306a36Sopenharmony_ci new_str[new_len++] = '\\'; 46662306a36Sopenharmony_ci } 46762306a36Sopenharmony_ci new_str[new_len++] = ch; 46862306a36Sopenharmony_ci if (ch == '\0') 46962306a36Sopenharmony_ci break; 47062306a36Sopenharmony_ci } 47162306a36Sopenharmony_ci } 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ci if (new_len) { 47462306a36Sopenharmony_ci new_str[new_len] = '\0'; 47562306a36Sopenharmony_ci *str = krealloc(new_str, (new_len + 1) * sizeof(char), 47662306a36Sopenharmony_ci GFP_KERNEL); 47762306a36Sopenharmony_ci if (*str) 47862306a36Sopenharmony_ci *len = new_len; 47962306a36Sopenharmony_ci else 48062306a36Sopenharmony_ci ret = -ENOMEM; 48162306a36Sopenharmony_ci } else { 48262306a36Sopenharmony_ci ret = -EFAULT; 48362306a36Sopenharmony_ci } 48462306a36Sopenharmony_ci 48562306a36Sopenharmony_ci if (ret) 48662306a36Sopenharmony_ci kfree(new_str); 48762306a36Sopenharmony_ci return ret; 48862306a36Sopenharmony_ci} 48962306a36Sopenharmony_ci 49062306a36Sopenharmony_ci/* map output size to the corresponding WMI method id */ 49162306a36Sopenharmony_ciint hp_encode_outsize_for_pvsz(int outsize) 49262306a36Sopenharmony_ci{ 49362306a36Sopenharmony_ci if (outsize > 4096) 49462306a36Sopenharmony_ci return -EINVAL; 49562306a36Sopenharmony_ci if (outsize > 1024) 49662306a36Sopenharmony_ci return 5; 49762306a36Sopenharmony_ci if (outsize > 128) 49862306a36Sopenharmony_ci return 4; 49962306a36Sopenharmony_ci if (outsize > 4) 50062306a36Sopenharmony_ci return 3; 50162306a36Sopenharmony_ci if (outsize > 0) 50262306a36Sopenharmony_ci return 2; 50362306a36Sopenharmony_ci return 1; 50462306a36Sopenharmony_ci} 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci/* 50762306a36Sopenharmony_ci * Update friendly display name for several attributes associated to 50862306a36Sopenharmony_ci * 'Schedule Power-On' 50962306a36Sopenharmony_ci */ 51062306a36Sopenharmony_civoid hp_friendly_user_name_update(char *path, const char *attr_name, 51162306a36Sopenharmony_ci char *attr_display, int attr_size) 51262306a36Sopenharmony_ci{ 51362306a36Sopenharmony_ci if (strstr(path, SCHEDULE_POWER_ON)) 51462306a36Sopenharmony_ci snprintf(attr_display, attr_size, "%s - %s", SCHEDULE_POWER_ON, attr_name); 51562306a36Sopenharmony_ci else 51662306a36Sopenharmony_ci strscpy(attr_display, attr_name, attr_size); 51762306a36Sopenharmony_ci} 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci/** 52062306a36Sopenharmony_ci * hp_update_attribute_permissions() - Update attributes permissions when 52162306a36Sopenharmony_ci * isReadOnly value is 1 52262306a36Sopenharmony_ci * 52362306a36Sopenharmony_ci * @is_readonly: bool value to indicate if it a readonly attribute. 52462306a36Sopenharmony_ci * @current_val: kobj_attribute corresponding to attribute. 52562306a36Sopenharmony_ci * 52662306a36Sopenharmony_ci */ 52762306a36Sopenharmony_civoid hp_update_attribute_permissions(bool is_readonly, struct kobj_attribute *current_val) 52862306a36Sopenharmony_ci{ 52962306a36Sopenharmony_ci current_val->attr.mode = is_readonly ? 0444 : 0644; 53062306a36Sopenharmony_ci} 53162306a36Sopenharmony_ci 53262306a36Sopenharmony_ci/** 53362306a36Sopenharmony_ci * destroy_attribute_objs() - Free a kset of kobjects 53462306a36Sopenharmony_ci * @kset: The kset to destroy 53562306a36Sopenharmony_ci * 53662306a36Sopenharmony_ci * Fress kobjects created for each attribute_name under attribute type kset 53762306a36Sopenharmony_ci */ 53862306a36Sopenharmony_cistatic void destroy_attribute_objs(struct kset *kset) 53962306a36Sopenharmony_ci{ 54062306a36Sopenharmony_ci struct kobject *pos, *next; 54162306a36Sopenharmony_ci 54262306a36Sopenharmony_ci list_for_each_entry_safe(pos, next, &kset->list, entry) 54362306a36Sopenharmony_ci kobject_put(pos); 54462306a36Sopenharmony_ci} 54562306a36Sopenharmony_ci 54662306a36Sopenharmony_ci/** 54762306a36Sopenharmony_ci * release_attributes_data() - Clean-up all sysfs directories and files created 54862306a36Sopenharmony_ci */ 54962306a36Sopenharmony_cistatic void release_attributes_data(void) 55062306a36Sopenharmony_ci{ 55162306a36Sopenharmony_ci mutex_lock(&bioscfg_drv.mutex); 55262306a36Sopenharmony_ci 55362306a36Sopenharmony_ci hp_exit_string_attributes(); 55462306a36Sopenharmony_ci hp_exit_integer_attributes(); 55562306a36Sopenharmony_ci hp_exit_enumeration_attributes(); 55662306a36Sopenharmony_ci hp_exit_ordered_list_attributes(); 55762306a36Sopenharmony_ci hp_exit_password_attributes(); 55862306a36Sopenharmony_ci hp_exit_sure_start_attributes(); 55962306a36Sopenharmony_ci hp_exit_secure_platform_attributes(); 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci if (bioscfg_drv.authentication_dir_kset) { 56262306a36Sopenharmony_ci destroy_attribute_objs(bioscfg_drv.authentication_dir_kset); 56362306a36Sopenharmony_ci kset_unregister(bioscfg_drv.authentication_dir_kset); 56462306a36Sopenharmony_ci bioscfg_drv.authentication_dir_kset = NULL; 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci if (bioscfg_drv.main_dir_kset) { 56762306a36Sopenharmony_ci sysfs_remove_file(&bioscfg_drv.main_dir_kset->kobj, &pending_reboot.attr); 56862306a36Sopenharmony_ci destroy_attribute_objs(bioscfg_drv.main_dir_kset); 56962306a36Sopenharmony_ci kset_unregister(bioscfg_drv.main_dir_kset); 57062306a36Sopenharmony_ci bioscfg_drv.main_dir_kset = NULL; 57162306a36Sopenharmony_ci } 57262306a36Sopenharmony_ci mutex_unlock(&bioscfg_drv.mutex); 57362306a36Sopenharmony_ci} 57462306a36Sopenharmony_ci 57562306a36Sopenharmony_ci/** 57662306a36Sopenharmony_ci * hp_add_other_attributes() - Initialize HP custom attributes not 57762306a36Sopenharmony_ci * reported by BIOS and required to support Secure Platform and Sure 57862306a36Sopenharmony_ci * Start. 57962306a36Sopenharmony_ci * 58062306a36Sopenharmony_ci * @attr_type: Custom HP attribute not reported by BIOS 58162306a36Sopenharmony_ci * 58262306a36Sopenharmony_ci * Initialize all 2 types of attributes: Platform and Sure Start 58362306a36Sopenharmony_ci * object. Populates each attribute types respective properties 58462306a36Sopenharmony_ci * under sysfs files. 58562306a36Sopenharmony_ci * 58662306a36Sopenharmony_ci * Returns zero(0) if successful. Otherwise, a negative value. 58762306a36Sopenharmony_ci */ 58862306a36Sopenharmony_cistatic int hp_add_other_attributes(int attr_type) 58962306a36Sopenharmony_ci{ 59062306a36Sopenharmony_ci struct kobject *attr_name_kobj; 59162306a36Sopenharmony_ci union acpi_object *obj = NULL; 59262306a36Sopenharmony_ci int ret; 59362306a36Sopenharmony_ci char *attr_name; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL); 59662306a36Sopenharmony_ci if (!attr_name_kobj) 59762306a36Sopenharmony_ci return -ENOMEM; 59862306a36Sopenharmony_ci 59962306a36Sopenharmony_ci mutex_lock(&bioscfg_drv.mutex); 60062306a36Sopenharmony_ci 60162306a36Sopenharmony_ci /* Check if attribute type is supported */ 60262306a36Sopenharmony_ci switch (attr_type) { 60362306a36Sopenharmony_ci case HPWMI_SECURE_PLATFORM_TYPE: 60462306a36Sopenharmony_ci attr_name_kobj->kset = bioscfg_drv.authentication_dir_kset; 60562306a36Sopenharmony_ci attr_name = SPM_STR; 60662306a36Sopenharmony_ci break; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci case HPWMI_SURE_START_TYPE: 60962306a36Sopenharmony_ci attr_name_kobj->kset = bioscfg_drv.main_dir_kset; 61062306a36Sopenharmony_ci attr_name = SURE_START_STR; 61162306a36Sopenharmony_ci break; 61262306a36Sopenharmony_ci 61362306a36Sopenharmony_ci default: 61462306a36Sopenharmony_ci pr_err("Error: Unknown attr_type: %d\n", attr_type); 61562306a36Sopenharmony_ci ret = -EINVAL; 61662306a36Sopenharmony_ci kfree(attr_name_kobj); 61762306a36Sopenharmony_ci goto unlock_drv_mutex; 61862306a36Sopenharmony_ci } 61962306a36Sopenharmony_ci 62062306a36Sopenharmony_ci ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype, 62162306a36Sopenharmony_ci NULL, "%s", attr_name); 62262306a36Sopenharmony_ci if (ret) { 62362306a36Sopenharmony_ci pr_err("Error encountered [%d]\n", ret); 62462306a36Sopenharmony_ci goto err_other_attr_init; 62562306a36Sopenharmony_ci } 62662306a36Sopenharmony_ci 62762306a36Sopenharmony_ci /* Populate attribute data */ 62862306a36Sopenharmony_ci switch (attr_type) { 62962306a36Sopenharmony_ci case HPWMI_SECURE_PLATFORM_TYPE: 63062306a36Sopenharmony_ci ret = hp_populate_secure_platform_data(attr_name_kobj); 63162306a36Sopenharmony_ci break; 63262306a36Sopenharmony_ci 63362306a36Sopenharmony_ci case HPWMI_SURE_START_TYPE: 63462306a36Sopenharmony_ci ret = hp_populate_sure_start_data(attr_name_kobj); 63562306a36Sopenharmony_ci break; 63662306a36Sopenharmony_ci 63762306a36Sopenharmony_ci default: 63862306a36Sopenharmony_ci ret = -EINVAL; 63962306a36Sopenharmony_ci } 64062306a36Sopenharmony_ci 64162306a36Sopenharmony_ci if (ret) 64262306a36Sopenharmony_ci goto err_other_attr_init; 64362306a36Sopenharmony_ci 64462306a36Sopenharmony_ci mutex_unlock(&bioscfg_drv.mutex); 64562306a36Sopenharmony_ci return 0; 64662306a36Sopenharmony_ci 64762306a36Sopenharmony_cierr_other_attr_init: 64862306a36Sopenharmony_ci kobject_put(attr_name_kobj); 64962306a36Sopenharmony_ciunlock_drv_mutex: 65062306a36Sopenharmony_ci mutex_unlock(&bioscfg_drv.mutex); 65162306a36Sopenharmony_ci kfree(obj); 65262306a36Sopenharmony_ci return ret; 65362306a36Sopenharmony_ci} 65462306a36Sopenharmony_ci 65562306a36Sopenharmony_cistatic int hp_init_bios_package_attribute(enum hp_wmi_data_type attr_type, 65662306a36Sopenharmony_ci union acpi_object *obj, 65762306a36Sopenharmony_ci const char *guid, int min_elements, 65862306a36Sopenharmony_ci int instance_id) 65962306a36Sopenharmony_ci{ 66062306a36Sopenharmony_ci struct kobject *attr_name_kobj, *duplicate; 66162306a36Sopenharmony_ci union acpi_object *elements; 66262306a36Sopenharmony_ci struct kset *temp_kset; 66362306a36Sopenharmony_ci 66462306a36Sopenharmony_ci char *str_value = NULL; 66562306a36Sopenharmony_ci int str_len; 66662306a36Sopenharmony_ci int ret = 0; 66762306a36Sopenharmony_ci 66862306a36Sopenharmony_ci /* Take action appropriate to each ACPI TYPE */ 66962306a36Sopenharmony_ci if (obj->package.count < min_elements) { 67062306a36Sopenharmony_ci pr_err("ACPI-package does not have enough elements: %d < %d\n", 67162306a36Sopenharmony_ci obj->package.count, min_elements); 67262306a36Sopenharmony_ci goto pack_attr_exit; 67362306a36Sopenharmony_ci } 67462306a36Sopenharmony_ci 67562306a36Sopenharmony_ci elements = obj->package.elements; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci /* sanity checking */ 67862306a36Sopenharmony_ci if (elements[NAME].type != ACPI_TYPE_STRING) { 67962306a36Sopenharmony_ci pr_debug("incorrect element type\n"); 68062306a36Sopenharmony_ci goto pack_attr_exit; 68162306a36Sopenharmony_ci } 68262306a36Sopenharmony_ci if (strlen(elements[NAME].string.pointer) == 0) { 68362306a36Sopenharmony_ci pr_debug("empty attribute found\n"); 68462306a36Sopenharmony_ci goto pack_attr_exit; 68562306a36Sopenharmony_ci } 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (attr_type == HPWMI_PASSWORD_TYPE) 68862306a36Sopenharmony_ci temp_kset = bioscfg_drv.authentication_dir_kset; 68962306a36Sopenharmony_ci else 69062306a36Sopenharmony_ci temp_kset = bioscfg_drv.main_dir_kset; 69162306a36Sopenharmony_ci 69262306a36Sopenharmony_ci /* convert attribute name to string */ 69362306a36Sopenharmony_ci ret = hp_convert_hexstr_to_str(elements[NAME].string.pointer, 69462306a36Sopenharmony_ci elements[NAME].string.length, 69562306a36Sopenharmony_ci &str_value, &str_len); 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ci if (ret) { 69862306a36Sopenharmony_ci pr_debug("Failed to populate integer package data. Error [0%0x]\n", 69962306a36Sopenharmony_ci ret); 70062306a36Sopenharmony_ci kfree(str_value); 70162306a36Sopenharmony_ci return ret; 70262306a36Sopenharmony_ci } 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci /* All duplicate attributes found are ignored */ 70562306a36Sopenharmony_ci duplicate = kset_find_obj(temp_kset, str_value); 70662306a36Sopenharmony_ci if (duplicate) { 70762306a36Sopenharmony_ci pr_debug("Duplicate attribute name found - %s\n", str_value); 70862306a36Sopenharmony_ci /* kset_find_obj() returns a reference */ 70962306a36Sopenharmony_ci kobject_put(duplicate); 71062306a36Sopenharmony_ci goto pack_attr_exit; 71162306a36Sopenharmony_ci } 71262306a36Sopenharmony_ci 71362306a36Sopenharmony_ci /* build attribute */ 71462306a36Sopenharmony_ci attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL); 71562306a36Sopenharmony_ci if (!attr_name_kobj) { 71662306a36Sopenharmony_ci ret = -ENOMEM; 71762306a36Sopenharmony_ci goto pack_attr_exit; 71862306a36Sopenharmony_ci } 71962306a36Sopenharmony_ci 72062306a36Sopenharmony_ci attr_name_kobj->kset = temp_kset; 72162306a36Sopenharmony_ci 72262306a36Sopenharmony_ci ret = kobject_init_and_add(attr_name_kobj, &attr_name_ktype, 72362306a36Sopenharmony_ci NULL, "%s", str_value); 72462306a36Sopenharmony_ci 72562306a36Sopenharmony_ci if (ret) { 72662306a36Sopenharmony_ci kobject_put(attr_name_kobj); 72762306a36Sopenharmony_ci goto pack_attr_exit; 72862306a36Sopenharmony_ci } 72962306a36Sopenharmony_ci 73062306a36Sopenharmony_ci /* enumerate all of these attributes */ 73162306a36Sopenharmony_ci switch (attr_type) { 73262306a36Sopenharmony_ci case HPWMI_STRING_TYPE: 73362306a36Sopenharmony_ci ret = hp_populate_string_package_data(elements, 73462306a36Sopenharmony_ci instance_id, 73562306a36Sopenharmony_ci attr_name_kobj); 73662306a36Sopenharmony_ci break; 73762306a36Sopenharmony_ci case HPWMI_INTEGER_TYPE: 73862306a36Sopenharmony_ci ret = hp_populate_integer_package_data(elements, 73962306a36Sopenharmony_ci instance_id, 74062306a36Sopenharmony_ci attr_name_kobj); 74162306a36Sopenharmony_ci break; 74262306a36Sopenharmony_ci case HPWMI_ENUMERATION_TYPE: 74362306a36Sopenharmony_ci ret = hp_populate_enumeration_package_data(elements, 74462306a36Sopenharmony_ci instance_id, 74562306a36Sopenharmony_ci attr_name_kobj); 74662306a36Sopenharmony_ci break; 74762306a36Sopenharmony_ci case HPWMI_ORDERED_LIST_TYPE: 74862306a36Sopenharmony_ci ret = hp_populate_ordered_list_package_data(elements, 74962306a36Sopenharmony_ci instance_id, 75062306a36Sopenharmony_ci attr_name_kobj); 75162306a36Sopenharmony_ci break; 75262306a36Sopenharmony_ci case HPWMI_PASSWORD_TYPE: 75362306a36Sopenharmony_ci ret = hp_populate_password_package_data(elements, 75462306a36Sopenharmony_ci instance_id, 75562306a36Sopenharmony_ci attr_name_kobj); 75662306a36Sopenharmony_ci break; 75762306a36Sopenharmony_ci default: 75862306a36Sopenharmony_ci pr_debug("Unknown attribute type found: 0x%x\n", attr_type); 75962306a36Sopenharmony_ci break; 76062306a36Sopenharmony_ci } 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_cipack_attr_exit: 76362306a36Sopenharmony_ci kfree(str_value); 76462306a36Sopenharmony_ci return ret; 76562306a36Sopenharmony_ci} 76662306a36Sopenharmony_ci 76762306a36Sopenharmony_cistatic int hp_init_bios_buffer_attribute(enum hp_wmi_data_type attr_type, 76862306a36Sopenharmony_ci union acpi_object *obj, 76962306a36Sopenharmony_ci const char *guid, int min_elements, 77062306a36Sopenharmony_ci int instance_id) 77162306a36Sopenharmony_ci{ 77262306a36Sopenharmony_ci struct kobject *attr_name_kobj, *duplicate; 77362306a36Sopenharmony_ci struct kset *temp_kset; 77462306a36Sopenharmony_ci char str[MAX_BUFF_SIZE]; 77562306a36Sopenharmony_ci 77662306a36Sopenharmony_ci char *temp_str = NULL; 77762306a36Sopenharmony_ci char *str_value = NULL; 77862306a36Sopenharmony_ci u8 *buffer_ptr = NULL; 77962306a36Sopenharmony_ci int buffer_size; 78062306a36Sopenharmony_ci int ret = 0; 78162306a36Sopenharmony_ci 78262306a36Sopenharmony_ci buffer_size = obj->buffer.length; 78362306a36Sopenharmony_ci buffer_ptr = obj->buffer.pointer; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci ret = hp_get_string_from_buffer(&buffer_ptr, 78662306a36Sopenharmony_ci &buffer_size, str, MAX_BUFF_SIZE); 78762306a36Sopenharmony_ci 78862306a36Sopenharmony_ci if (ret < 0) 78962306a36Sopenharmony_ci goto buff_attr_exit; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci if (attr_type == HPWMI_PASSWORD_TYPE || 79262306a36Sopenharmony_ci attr_type == HPWMI_SECURE_PLATFORM_TYPE) 79362306a36Sopenharmony_ci temp_kset = bioscfg_drv.authentication_dir_kset; 79462306a36Sopenharmony_ci else 79562306a36Sopenharmony_ci temp_kset = bioscfg_drv.main_dir_kset; 79662306a36Sopenharmony_ci 79762306a36Sopenharmony_ci /* All duplicate attributes found are ignored */ 79862306a36Sopenharmony_ci duplicate = kset_find_obj(temp_kset, str); 79962306a36Sopenharmony_ci if (duplicate) { 80062306a36Sopenharmony_ci pr_debug("Duplicate attribute name found - %s\n", str); 80162306a36Sopenharmony_ci /* kset_find_obj() returns a reference */ 80262306a36Sopenharmony_ci kobject_put(duplicate); 80362306a36Sopenharmony_ci goto buff_attr_exit; 80462306a36Sopenharmony_ci } 80562306a36Sopenharmony_ci 80662306a36Sopenharmony_ci /* build attribute */ 80762306a36Sopenharmony_ci attr_name_kobj = kzalloc(sizeof(*attr_name_kobj), GFP_KERNEL); 80862306a36Sopenharmony_ci if (!attr_name_kobj) { 80962306a36Sopenharmony_ci ret = -ENOMEM; 81062306a36Sopenharmony_ci goto buff_attr_exit; 81162306a36Sopenharmony_ci } 81262306a36Sopenharmony_ci 81362306a36Sopenharmony_ci attr_name_kobj->kset = temp_kset; 81462306a36Sopenharmony_ci 81562306a36Sopenharmony_ci temp_str = str; 81662306a36Sopenharmony_ci if (attr_type == HPWMI_SECURE_PLATFORM_TYPE) 81762306a36Sopenharmony_ci temp_str = "SPM"; 81862306a36Sopenharmony_ci 81962306a36Sopenharmony_ci ret = kobject_init_and_add(attr_name_kobj, 82062306a36Sopenharmony_ci &attr_name_ktype, NULL, "%s", temp_str); 82162306a36Sopenharmony_ci if (ret) { 82262306a36Sopenharmony_ci kobject_put(attr_name_kobj); 82362306a36Sopenharmony_ci goto buff_attr_exit; 82462306a36Sopenharmony_ci } 82562306a36Sopenharmony_ci 82662306a36Sopenharmony_ci /* enumerate all of these attributes */ 82762306a36Sopenharmony_ci switch (attr_type) { 82862306a36Sopenharmony_ci case HPWMI_STRING_TYPE: 82962306a36Sopenharmony_ci ret = hp_populate_string_buffer_data(buffer_ptr, 83062306a36Sopenharmony_ci &buffer_size, 83162306a36Sopenharmony_ci instance_id, 83262306a36Sopenharmony_ci attr_name_kobj); 83362306a36Sopenharmony_ci break; 83462306a36Sopenharmony_ci case HPWMI_INTEGER_TYPE: 83562306a36Sopenharmony_ci ret = hp_populate_integer_buffer_data(buffer_ptr, 83662306a36Sopenharmony_ci &buffer_size, 83762306a36Sopenharmony_ci instance_id, 83862306a36Sopenharmony_ci attr_name_kobj); 83962306a36Sopenharmony_ci break; 84062306a36Sopenharmony_ci case HPWMI_ENUMERATION_TYPE: 84162306a36Sopenharmony_ci ret = hp_populate_enumeration_buffer_data(buffer_ptr, 84262306a36Sopenharmony_ci &buffer_size, 84362306a36Sopenharmony_ci instance_id, 84462306a36Sopenharmony_ci attr_name_kobj); 84562306a36Sopenharmony_ci break; 84662306a36Sopenharmony_ci case HPWMI_ORDERED_LIST_TYPE: 84762306a36Sopenharmony_ci ret = hp_populate_ordered_list_buffer_data(buffer_ptr, 84862306a36Sopenharmony_ci &buffer_size, 84962306a36Sopenharmony_ci instance_id, 85062306a36Sopenharmony_ci attr_name_kobj); 85162306a36Sopenharmony_ci break; 85262306a36Sopenharmony_ci case HPWMI_PASSWORD_TYPE: 85362306a36Sopenharmony_ci ret = hp_populate_password_buffer_data(buffer_ptr, 85462306a36Sopenharmony_ci &buffer_size, 85562306a36Sopenharmony_ci instance_id, 85662306a36Sopenharmony_ci attr_name_kobj); 85762306a36Sopenharmony_ci break; 85862306a36Sopenharmony_ci default: 85962306a36Sopenharmony_ci pr_debug("Unknown attribute type found: 0x%x\n", attr_type); 86062306a36Sopenharmony_ci break; 86162306a36Sopenharmony_ci } 86262306a36Sopenharmony_ci 86362306a36Sopenharmony_cibuff_attr_exit: 86462306a36Sopenharmony_ci kfree(str_value); 86562306a36Sopenharmony_ci return ret; 86662306a36Sopenharmony_ci} 86762306a36Sopenharmony_ci 86862306a36Sopenharmony_ci/** 86962306a36Sopenharmony_ci * hp_init_bios_attributes() - Initialize all attributes for a type 87062306a36Sopenharmony_ci * @attr_type: The attribute type to initialize 87162306a36Sopenharmony_ci * @guid: The WMI GUID associated with this type to initialize 87262306a36Sopenharmony_ci * 87362306a36Sopenharmony_ci * Initialize all 5 types of attributes: enumeration, integer, 87462306a36Sopenharmony_ci * string, password, ordered list object. Populates each attribute types 87562306a36Sopenharmony_ci * respective properties under sysfs files 87662306a36Sopenharmony_ci */ 87762306a36Sopenharmony_cistatic int hp_init_bios_attributes(enum hp_wmi_data_type attr_type, const char *guid) 87862306a36Sopenharmony_ci{ 87962306a36Sopenharmony_ci union acpi_object *obj = NULL; 88062306a36Sopenharmony_ci int min_elements; 88162306a36Sopenharmony_ci 88262306a36Sopenharmony_ci /* instance_id needs to be reset for each type GUID 88362306a36Sopenharmony_ci * also, instance IDs are unique within GUID but not across 88462306a36Sopenharmony_ci */ 88562306a36Sopenharmony_ci int instance_id = 0; 88662306a36Sopenharmony_ci int cur_instance_id = instance_id; 88762306a36Sopenharmony_ci int ret = 0; 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci ret = hp_alloc_attributes_data(attr_type); 89062306a36Sopenharmony_ci if (ret) 89162306a36Sopenharmony_ci return ret; 89262306a36Sopenharmony_ci 89362306a36Sopenharmony_ci switch (attr_type) { 89462306a36Sopenharmony_ci case HPWMI_STRING_TYPE: 89562306a36Sopenharmony_ci min_elements = STR_ELEM_CNT; 89662306a36Sopenharmony_ci break; 89762306a36Sopenharmony_ci case HPWMI_INTEGER_TYPE: 89862306a36Sopenharmony_ci min_elements = INT_ELEM_CNT; 89962306a36Sopenharmony_ci break; 90062306a36Sopenharmony_ci case HPWMI_ENUMERATION_TYPE: 90162306a36Sopenharmony_ci min_elements = ENUM_ELEM_CNT; 90262306a36Sopenharmony_ci break; 90362306a36Sopenharmony_ci case HPWMI_ORDERED_LIST_TYPE: 90462306a36Sopenharmony_ci min_elements = ORD_ELEM_CNT; 90562306a36Sopenharmony_ci break; 90662306a36Sopenharmony_ci case HPWMI_PASSWORD_TYPE: 90762306a36Sopenharmony_ci min_elements = PSWD_ELEM_CNT; 90862306a36Sopenharmony_ci break; 90962306a36Sopenharmony_ci default: 91062306a36Sopenharmony_ci pr_err("Error: Unknown attr_type: %d\n", attr_type); 91162306a36Sopenharmony_ci return -EINVAL; 91262306a36Sopenharmony_ci } 91362306a36Sopenharmony_ci 91462306a36Sopenharmony_ci /* need to use specific instance_id and guid combination to get right data */ 91562306a36Sopenharmony_ci obj = hp_get_wmiobj_pointer(instance_id, guid); 91662306a36Sopenharmony_ci if (!obj) 91762306a36Sopenharmony_ci return -ENODEV; 91862306a36Sopenharmony_ci 91962306a36Sopenharmony_ci mutex_lock(&bioscfg_drv.mutex); 92062306a36Sopenharmony_ci while (obj) { 92162306a36Sopenharmony_ci /* Take action appropriate to each ACPI TYPE */ 92262306a36Sopenharmony_ci if (obj->type == ACPI_TYPE_PACKAGE) { 92362306a36Sopenharmony_ci ret = hp_init_bios_package_attribute(attr_type, obj, 92462306a36Sopenharmony_ci guid, min_elements, 92562306a36Sopenharmony_ci cur_instance_id); 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci } else if (obj->type == ACPI_TYPE_BUFFER) { 92862306a36Sopenharmony_ci ret = hp_init_bios_buffer_attribute(attr_type, obj, 92962306a36Sopenharmony_ci guid, min_elements, 93062306a36Sopenharmony_ci cur_instance_id); 93162306a36Sopenharmony_ci 93262306a36Sopenharmony_ci } else { 93362306a36Sopenharmony_ci pr_err("Expected ACPI-package or buffer type, got: %d\n", 93462306a36Sopenharmony_ci obj->type); 93562306a36Sopenharmony_ci ret = -EIO; 93662306a36Sopenharmony_ci goto err_attr_init; 93762306a36Sopenharmony_ci } 93862306a36Sopenharmony_ci 93962306a36Sopenharmony_ci /* 94062306a36Sopenharmony_ci * Failure reported in one attribute must not 94162306a36Sopenharmony_ci * stop process of the remaining attribute values. 94262306a36Sopenharmony_ci */ 94362306a36Sopenharmony_ci if (ret >= 0) 94462306a36Sopenharmony_ci cur_instance_id++; 94562306a36Sopenharmony_ci 94662306a36Sopenharmony_ci kfree(obj); 94762306a36Sopenharmony_ci instance_id++; 94862306a36Sopenharmony_ci obj = hp_get_wmiobj_pointer(instance_id, guid); 94962306a36Sopenharmony_ci } 95062306a36Sopenharmony_ci 95162306a36Sopenharmony_cierr_attr_init: 95262306a36Sopenharmony_ci mutex_unlock(&bioscfg_drv.mutex); 95362306a36Sopenharmony_ci kfree(obj); 95462306a36Sopenharmony_ci return ret; 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_cistatic int __init hp_init(void) 95862306a36Sopenharmony_ci{ 95962306a36Sopenharmony_ci int ret; 96062306a36Sopenharmony_ci int hp_bios_capable = wmi_has_guid(HP_WMI_BIOS_GUID); 96162306a36Sopenharmony_ci int set_bios_settings = wmi_has_guid(HP_WMI_SET_BIOS_SETTING_GUID); 96262306a36Sopenharmony_ci 96362306a36Sopenharmony_ci if (!hp_bios_capable) { 96462306a36Sopenharmony_ci pr_err("Unable to run on non-HP system\n"); 96562306a36Sopenharmony_ci return -ENODEV; 96662306a36Sopenharmony_ci } 96762306a36Sopenharmony_ci 96862306a36Sopenharmony_ci if (!set_bios_settings) { 96962306a36Sopenharmony_ci pr_err("Unable to set BIOS settings on HP systems\n"); 97062306a36Sopenharmony_ci return -ENODEV; 97162306a36Sopenharmony_ci } 97262306a36Sopenharmony_ci 97362306a36Sopenharmony_ci ret = hp_init_attr_set_interface(); 97462306a36Sopenharmony_ci if (ret) 97562306a36Sopenharmony_ci return ret; 97662306a36Sopenharmony_ci 97762306a36Sopenharmony_ci ret = fw_attributes_class_get(&fw_attr_class); 97862306a36Sopenharmony_ci if (ret) 97962306a36Sopenharmony_ci goto err_unregister_class; 98062306a36Sopenharmony_ci 98162306a36Sopenharmony_ci bioscfg_drv.class_dev = device_create(fw_attr_class, NULL, MKDEV(0, 0), 98262306a36Sopenharmony_ci NULL, "%s", DRIVER_NAME); 98362306a36Sopenharmony_ci if (IS_ERR(bioscfg_drv.class_dev)) { 98462306a36Sopenharmony_ci ret = PTR_ERR(bioscfg_drv.class_dev); 98562306a36Sopenharmony_ci goto err_unregister_class; 98662306a36Sopenharmony_ci } 98762306a36Sopenharmony_ci 98862306a36Sopenharmony_ci bioscfg_drv.main_dir_kset = kset_create_and_add("attributes", NULL, 98962306a36Sopenharmony_ci &bioscfg_drv.class_dev->kobj); 99062306a36Sopenharmony_ci if (!bioscfg_drv.main_dir_kset) { 99162306a36Sopenharmony_ci ret = -ENOMEM; 99262306a36Sopenharmony_ci pr_debug("Failed to create and add attributes\n"); 99362306a36Sopenharmony_ci goto err_destroy_classdev; 99462306a36Sopenharmony_ci } 99562306a36Sopenharmony_ci 99662306a36Sopenharmony_ci bioscfg_drv.authentication_dir_kset = kset_create_and_add("authentication", NULL, 99762306a36Sopenharmony_ci &bioscfg_drv.class_dev->kobj); 99862306a36Sopenharmony_ci if (!bioscfg_drv.authentication_dir_kset) { 99962306a36Sopenharmony_ci ret = -ENOMEM; 100062306a36Sopenharmony_ci pr_debug("Failed to create and add authentication\n"); 100162306a36Sopenharmony_ci goto err_release_attributes_data; 100262306a36Sopenharmony_ci } 100362306a36Sopenharmony_ci 100462306a36Sopenharmony_ci /* 100562306a36Sopenharmony_ci * sysfs level attributes. 100662306a36Sopenharmony_ci * - pending_reboot 100762306a36Sopenharmony_ci */ 100862306a36Sopenharmony_ci ret = create_attributes_level_sysfs_files(); 100962306a36Sopenharmony_ci if (ret) 101062306a36Sopenharmony_ci pr_debug("Failed to create sysfs level attributes\n"); 101162306a36Sopenharmony_ci 101262306a36Sopenharmony_ci ret = hp_init_bios_attributes(HPWMI_STRING_TYPE, HP_WMI_BIOS_STRING_GUID); 101362306a36Sopenharmony_ci if (ret) 101462306a36Sopenharmony_ci pr_debug("Failed to populate string type attributes\n"); 101562306a36Sopenharmony_ci 101662306a36Sopenharmony_ci ret = hp_init_bios_attributes(HPWMI_INTEGER_TYPE, HP_WMI_BIOS_INTEGER_GUID); 101762306a36Sopenharmony_ci if (ret) 101862306a36Sopenharmony_ci pr_debug("Failed to populate integer type attributes\n"); 101962306a36Sopenharmony_ci 102062306a36Sopenharmony_ci ret = hp_init_bios_attributes(HPWMI_ENUMERATION_TYPE, HP_WMI_BIOS_ENUMERATION_GUID); 102162306a36Sopenharmony_ci if (ret) 102262306a36Sopenharmony_ci pr_debug("Failed to populate enumeration type attributes\n"); 102362306a36Sopenharmony_ci 102462306a36Sopenharmony_ci ret = hp_init_bios_attributes(HPWMI_ORDERED_LIST_TYPE, HP_WMI_BIOS_ORDERED_LIST_GUID); 102562306a36Sopenharmony_ci if (ret) 102662306a36Sopenharmony_ci pr_debug("Failed to populate ordered list object type attributes\n"); 102762306a36Sopenharmony_ci 102862306a36Sopenharmony_ci ret = hp_init_bios_attributes(HPWMI_PASSWORD_TYPE, HP_WMI_BIOS_PASSWORD_GUID); 102962306a36Sopenharmony_ci if (ret) 103062306a36Sopenharmony_ci pr_debug("Failed to populate password object type attributes\n"); 103162306a36Sopenharmony_ci 103262306a36Sopenharmony_ci bioscfg_drv.spm_data.attr_name_kobj = NULL; 103362306a36Sopenharmony_ci ret = hp_add_other_attributes(HPWMI_SECURE_PLATFORM_TYPE); 103462306a36Sopenharmony_ci if (ret) 103562306a36Sopenharmony_ci pr_debug("Failed to populate secure platform object type attribute\n"); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci bioscfg_drv.sure_start_attr_kobj = NULL; 103862306a36Sopenharmony_ci ret = hp_add_other_attributes(HPWMI_SURE_START_TYPE); 103962306a36Sopenharmony_ci if (ret) 104062306a36Sopenharmony_ci pr_debug("Failed to populate sure start object type attribute\n"); 104162306a36Sopenharmony_ci 104262306a36Sopenharmony_ci return 0; 104362306a36Sopenharmony_ci 104462306a36Sopenharmony_cierr_release_attributes_data: 104562306a36Sopenharmony_ci release_attributes_data(); 104662306a36Sopenharmony_ci 104762306a36Sopenharmony_cierr_destroy_classdev: 104862306a36Sopenharmony_ci device_destroy(fw_attr_class, MKDEV(0, 0)); 104962306a36Sopenharmony_ci 105062306a36Sopenharmony_cierr_unregister_class: 105162306a36Sopenharmony_ci fw_attributes_class_put(); 105262306a36Sopenharmony_ci hp_exit_attr_set_interface(); 105362306a36Sopenharmony_ci 105462306a36Sopenharmony_ci return ret; 105562306a36Sopenharmony_ci} 105662306a36Sopenharmony_ci 105762306a36Sopenharmony_cistatic void __exit hp_exit(void) 105862306a36Sopenharmony_ci{ 105962306a36Sopenharmony_ci release_attributes_data(); 106062306a36Sopenharmony_ci device_destroy(fw_attr_class, MKDEV(0, 0)); 106162306a36Sopenharmony_ci 106262306a36Sopenharmony_ci fw_attributes_class_put(); 106362306a36Sopenharmony_ci hp_exit_attr_set_interface(); 106462306a36Sopenharmony_ci} 106562306a36Sopenharmony_ci 106662306a36Sopenharmony_cimodule_init(hp_init); 106762306a36Sopenharmony_cimodule_exit(hp_exit); 1068