brintos

brintos / linux-shallow public Read only

0
0
Text · 25.1 KiB · 2dc5015 Raw
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