brintos

brintos / linux-shallow public Read only

0
0
Text · 12.6 KiB · c6e57bb Raw
434 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * Functions corresponding to ordered list type attributes under4 * BIOS ORDERED LIST GUID for use with hp-bioscfg driver.5 *6 * Copyright (c) 2022 HP Development Company, L.P.7 */8 9#include "bioscfg.h"10 11GET_INSTANCE_ID(ordered_list);12 13static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)14{15	int instance_id = get_ordered_list_instance_id(kobj);16 17	if (instance_id < 0)18		return -EIO;19 20	return sysfs_emit(buf, "%s\n",21			 bioscfg_drv.ordered_list_data[instance_id].current_value);22}23 24static int replace_char_str(u8 *buffer, char *repl_char, char *repl_with)25{26	char *src = buffer;27	int buflen = strlen(buffer);28	int item;29 30	if (buflen < 1)31		return -EINVAL;32 33	for (item = 0; item < buflen; item++)34		if (src[item] == *repl_char)35			src[item] = *repl_with;36 37	return 0;38}39 40/**41 * validate_ordered_list_input() -42 * Validate input of current_value against possible values43 *44 * @instance: The instance on which input is validated45 * @buf: Input value46 */47static int validate_ordered_list_input(int instance, char *buf)48{49	/* validation is done by BIOS. This validation function will50	 * convert semicolon to commas. BIOS uses commas as51	 * separators when reporting ordered-list values.52	 */53	return replace_char_str(buf, SEMICOLON_SEP, COMMA_SEP);54}55 56static void update_ordered_list_value(int instance, char *attr_value)57{58	struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance];59 60	strscpy(ordered_list_data->current_value, attr_value);61}62 63ATTRIBUTE_S_COMMON_PROPERTY_SHOW(display_name, ordered_list);64static struct kobj_attribute ordered_list_display_name =65	__ATTR_RO(display_name);66 67ATTRIBUTE_PROPERTY_STORE(current_value, ordered_list);68static struct kobj_attribute ordered_list_current_val =69	__ATTR_RW_MODE(current_value, 0644);70 71ATTRIBUTE_VALUES_PROPERTY_SHOW(elements, ordered_list, SEMICOLON_SEP);72static struct kobj_attribute ordered_list_elements_val =73	__ATTR_RO(elements);74 75static ssize_t type_show(struct kobject *kobj, struct kobj_attribute *attr,76			 char *buf)77{78	return sysfs_emit(buf, "ordered-list\n");79}80 81static struct kobj_attribute ordered_list_type =82	__ATTR_RO(type);83 84static struct attribute *ordered_list_attrs[] = {85	&common_display_langcode.attr,86	&ordered_list_display_name.attr,87	&ordered_list_current_val.attr,88	&ordered_list_elements_val.attr,89	&ordered_list_type.attr,90	NULL91};92 93static const struct attribute_group ordered_list_attr_group = {94	.attrs = ordered_list_attrs,95};96 97int hp_alloc_ordered_list_data(void)98{99	bioscfg_drv.ordered_list_instances_count =100		hp_get_instance_count(HP_WMI_BIOS_ORDERED_LIST_GUID);101	bioscfg_drv.ordered_list_data = kcalloc(bioscfg_drv.ordered_list_instances_count,102						sizeof(*bioscfg_drv.ordered_list_data),103						GFP_KERNEL);104	if (!bioscfg_drv.ordered_list_data) {105		bioscfg_drv.ordered_list_instances_count = 0;106		return -ENOMEM;107	}108	return 0;109}110 111/* Expected Values types associated with each element */112static const acpi_object_type expected_order_types[] = {113	[NAME]	= ACPI_TYPE_STRING,114	[VALUE] = ACPI_TYPE_STRING,115	[PATH] = ACPI_TYPE_STRING,116	[IS_READONLY] = ACPI_TYPE_INTEGER,117	[DISPLAY_IN_UI] = ACPI_TYPE_INTEGER,118	[REQUIRES_PHYSICAL_PRESENCE] = ACPI_TYPE_INTEGER,119	[SEQUENCE] = ACPI_TYPE_INTEGER,120	[PREREQUISITES_SIZE] = ACPI_TYPE_INTEGER,121	[PREREQUISITES] = ACPI_TYPE_STRING,122	[SECURITY_LEVEL] = ACPI_TYPE_INTEGER,123	[ORD_LIST_SIZE] = ACPI_TYPE_INTEGER,124	[ORD_LIST_ELEMENTS] = ACPI_TYPE_STRING,125};126 127static int hp_populate_ordered_list_elements_from_package(union acpi_object *order_obj,128							  int order_obj_count,129							  int instance_id)130{131	char *str_value = NULL;132	int value_len = 0;133	int ret;134	u32 size;135	u32 int_value = 0;136	int elem;137	int olist_elem;138	int reqs;139	int eloc;140	char *tmpstr = NULL;141	char *part_tmp = NULL;142	int tmp_len = 0;143	char *part = NULL;144	struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id];145 146	if (!order_obj)147		return -EINVAL;148 149	for (elem = 1, eloc = 1; eloc < ORD_ELEM_CNT; elem++, eloc++) {150 151		switch (order_obj[elem].type) {152		case ACPI_TYPE_STRING:153			if (elem != PREREQUISITES && elem != ORD_LIST_ELEMENTS) {154				ret = hp_convert_hexstr_to_str(order_obj[elem].string.pointer,155							       order_obj[elem].string.length,156							       &str_value, &value_len);157				if (ret)158					continue;159			}160			break;161		case ACPI_TYPE_INTEGER:162			int_value = (u32)order_obj[elem].integer.value;163			break;164		default:165			pr_warn("Unsupported object type [%d]\n", order_obj[elem].type);166			continue;167		}168 169		/* Check that both expected and read object type match */170		if (expected_order_types[eloc] != order_obj[elem].type) {171			pr_err("Error expected type %d for elem %d, but got type %d instead\n",172			       expected_order_types[eloc], elem, order_obj[elem].type);173			kfree(str_value);174			return -EIO;175		}176 177		/* Assign appropriate element value to corresponding field*/178		switch (eloc) {179		case VALUE:180			strscpy(ordered_list_data->current_value, str_value);181			replace_char_str(ordered_list_data->current_value, COMMA_SEP, SEMICOLON_SEP);182			break;183		case PATH:184			strscpy(ordered_list_data->common.path, str_value);185			break;186		case IS_READONLY:187			ordered_list_data->common.is_readonly = int_value;188			break;189		case DISPLAY_IN_UI:190			ordered_list_data->common.display_in_ui = int_value;191			break;192		case REQUIRES_PHYSICAL_PRESENCE:193			ordered_list_data->common.requires_physical_presence = int_value;194			break;195		case SEQUENCE:196			ordered_list_data->common.sequence = int_value;197			break;198		case PREREQUISITES_SIZE:199			if (int_value > MAX_PREREQUISITES_SIZE) {200				pr_warn("Prerequisites size value exceeded the maximum number of elements supported or data may be malformed\n");201				int_value = MAX_PREREQUISITES_SIZE;202			}203			ordered_list_data->common.prerequisites_size = int_value;204 205			/*206			 * This step is needed to keep the expected207			 * element list pointing to the right obj[elem].type208			 * when the size is zero. PREREQUISITES209			 * object is omitted by BIOS when the size is210			 * zero.211			 */212			if (int_value == 0)213				eloc++;214			break;215		case PREREQUISITES:216			size = min_t(u32, ordered_list_data->common.prerequisites_size,217				     MAX_PREREQUISITES_SIZE);218			for (reqs = 0; reqs < size; reqs++) {219				ret = hp_convert_hexstr_to_str(order_obj[elem + reqs].string.pointer,220							       order_obj[elem + reqs].string.length,221							       &str_value, &value_len);222 223				if (ret)224					continue;225 226				strscpy(ordered_list_data->common.prerequisites[reqs], str_value);227 228				kfree(str_value);229				str_value = NULL;230			}231			break;232 233		case SECURITY_LEVEL:234			ordered_list_data->common.security_level = int_value;235			break;236 237		case ORD_LIST_SIZE:238			if (int_value > MAX_ELEMENTS_SIZE) {239				pr_warn("Order List size value exceeded the maximum number of elements supported or data may be malformed\n");240				int_value = MAX_ELEMENTS_SIZE;241			}242			ordered_list_data->elements_size = int_value;243 244			/*245			 * This step is needed to keep the expected246			 * element list pointing to the right obj[elem].type247			 * when the size is zero. ORD_LIST_ELEMENTS248			 * object is omitted by BIOS when the size is249			 * zero.250			 */251			if (int_value == 0)252				eloc++;253			break;254		case ORD_LIST_ELEMENTS:255 256			/*257			 * Ordered list data is stored in hex and comma separated format258			 * Convert the data and split it to show each element259			 */260			ret = hp_convert_hexstr_to_str(str_value, value_len, &tmpstr, &tmp_len);261			if (ret)262				goto exit_list;263 264			part_tmp = tmpstr;265			part = strsep(&part_tmp, COMMA_SEP);266 267			for (olist_elem = 0; olist_elem < MAX_ELEMENTS_SIZE && part; olist_elem++) {268				strscpy(ordered_list_data->elements[olist_elem], part);269				part = strsep(&part_tmp, COMMA_SEP);270			}271			ordered_list_data->elements_size = olist_elem;272 273			kfree(str_value);274			str_value = NULL;275			break;276		default:277			pr_warn("Invalid element: %d found in Ordered_List attribute or data may be malformed\n", elem);278			break;279		}280		kfree(tmpstr);281		tmpstr = NULL;282		kfree(str_value);283		str_value = NULL;284	}285 286exit_list:287	kfree(tmpstr);288	kfree(str_value);289	return 0;290}291 292/**293 * hp_populate_ordered_list_package_data() -294 * Populate all properties of an instance under ordered_list attribute295 *296 * @order_obj: ACPI object with ordered_list data297 * @instance_id: The instance to enumerate298 * @attr_name_kobj: The parent kernel object299 */300int hp_populate_ordered_list_package_data(union acpi_object *order_obj, int instance_id,301					  struct kobject *attr_name_kobj)302{303	struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id];304 305	ordered_list_data->attr_name_kobj = attr_name_kobj;306 307	hp_populate_ordered_list_elements_from_package(order_obj,308						       order_obj->package.count,309						       instance_id);310	hp_update_attribute_permissions(ordered_list_data->common.is_readonly,311					&ordered_list_current_val);312	hp_friendly_user_name_update(ordered_list_data->common.path,313				     attr_name_kobj->name,314				     ordered_list_data->common.display_name,315				     sizeof(ordered_list_data->common.display_name));316	return sysfs_create_group(attr_name_kobj, &ordered_list_attr_group);317}318 319static int hp_populate_ordered_list_elements_from_buffer(u8 *buffer_ptr, u32 *buffer_size,320							 int instance_id)321{322	int values;323	struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id];324	int ret = 0;325 326	/*327	 * Only data relevant to this driver and its functionality is328	 * read. BIOS defines the order in which each * element is329	 * read. Element 0 data is not relevant to this330	 * driver hence it is ignored. For clarity, all element names331	 * (DISPLAY_IN_UI) which defines the order in which is read332	 * and the name matches the variable where the data is stored.333	 *334	 * In earlier implementation, reported errors were ignored335	 * causing the data to remain uninitialized. It is not336	 * possible to determine if data read from BIOS is valid or337	 * not. It is for this reason functions may return a error338	 * without validating the data itself.339	 */340 341	// VALUE:342	ret = hp_get_string_from_buffer(&buffer_ptr, buffer_size, ordered_list_data->current_value,343					sizeof(ordered_list_data->current_value));344	if (ret < 0)345		goto buffer_exit;346 347	replace_char_str(ordered_list_data->current_value, COMMA_SEP, SEMICOLON_SEP);348 349	// COMMON:350	ret = hp_get_common_data_from_buffer(&buffer_ptr, buffer_size,351					     &ordered_list_data->common);352	if (ret < 0)353		goto buffer_exit;354 355	// ORD_LIST_SIZE:356	ret = hp_get_integer_from_buffer(&buffer_ptr, buffer_size,357					 &ordered_list_data->elements_size);358 359	if (ordered_list_data->elements_size > MAX_ELEMENTS_SIZE) {360		/* Report a message and limit elements size to maximum value */361		pr_warn("Ordered List size value exceeded the maximum number of elements supported or data may be malformed\n");362		ordered_list_data->elements_size = MAX_ELEMENTS_SIZE;363	}364 365	// ORD_LIST_ELEMENTS:366	for (values = 0; values < ordered_list_data->elements_size; values++) {367		ret = hp_get_string_from_buffer(&buffer_ptr, buffer_size,368						ordered_list_data->elements[values],369						sizeof(ordered_list_data->elements[values]));370		if (ret < 0)371			break;372	}373 374buffer_exit:375	return ret;376}377 378/**379 * hp_populate_ordered_list_buffer_data() - Populate all properties of an380 * instance under ordered list attribute381 *382 * @buffer_ptr: Buffer pointer383 * @buffer_size: Buffer size384 * @instance_id: The instance to enumerate385 * @attr_name_kobj: The parent kernel object386 */387int hp_populate_ordered_list_buffer_data(u8 *buffer_ptr, u32 *buffer_size, int instance_id,388					 struct kobject *attr_name_kobj)389{390	struct ordered_list_data *ordered_list_data = &bioscfg_drv.ordered_list_data[instance_id];391	int ret = 0;392 393	ordered_list_data->attr_name_kobj = attr_name_kobj;394 395	/* Populate ordered list elements */396	ret = hp_populate_ordered_list_elements_from_buffer(buffer_ptr, buffer_size,397							    instance_id);398	if (ret < 0)399		return ret;400 401	hp_update_attribute_permissions(ordered_list_data->common.is_readonly,402					&ordered_list_current_val);403	hp_friendly_user_name_update(ordered_list_data->common.path,404				     attr_name_kobj->name,405				     ordered_list_data->common.display_name,406				     sizeof(ordered_list_data->common.display_name));407 408	return sysfs_create_group(attr_name_kobj, &ordered_list_attr_group);409}410 411/**412 * hp_exit_ordered_list_attributes() - Clear all attribute data413 *414 * Clears all data allocated for this group of attributes415 */416void hp_exit_ordered_list_attributes(void)417{418	int instance_id;419 420	for (instance_id = 0; instance_id < bioscfg_drv.ordered_list_instances_count;421	     instance_id++) {422		struct kobject *attr_name_kobj =423			bioscfg_drv.ordered_list_data[instance_id].attr_name_kobj;424 425		if (attr_name_kobj)426			sysfs_remove_group(attr_name_kobj,427					   &ordered_list_attr_group);428	}429	bioscfg_drv.ordered_list_instances_count = 0;430 431	kfree(bioscfg_drv.ordered_list_data);432	bioscfg_drv.ordered_list_data = NULL;433}434