File Index
Files and directories
Sign in
FILE

bioscfg.c

File preview with syntax highlighting.

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