All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] IOCTL support for dell-wmi-sysman driver
@ 2021-02-09 14:28 Prasanth, KSR
  2021-02-09 17:48   ` kernel test robot
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Prasanth, KSR @ 2021-02-09 14:28 UTC (permalink / raw)
  To: Hans de Goede, dvhart
  Cc: LKML, platform-driver-x86, Prasanth KSR, Divya Bharathi,
	Mario Limonciello

From: "Prasanth KSR" <prasanth.ksr@dell.com>

Perform BIOS Management calls on supported Dell machines
through the Dell WMI System Management interface.

This interface provides IOCTL's to perform bundled
BIOS Setting transactions.

Cc: Hans de Goede <hdegoede@redhat.com>

Signed-off-by: Prasanth KSR <prasanth.ksr@dell.com>
Co-developed-by: Divya Bharathi <divya.bharathi@dell.com>
Signed-off-by: Divya Bharathi <divya.bharathi@dell.com>
Co-developed-by: Mario Limonciello <mario.limonciello@dell.com>
Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
---
 Documentation/ABI/testing/dell-wmi-sysman     |  39 ++
 .../x86/dell-wmi-sysman/biosattr-interface.c  | 257 +++++++++--
 .../x86/dell-wmi-sysman/dell-wmi-sysman.h     |  20 +-
 .../x86/dell-wmi-sysman/enum-attributes.c     |  45 +-
 .../x86/dell-wmi-sysman/int-attributes.c      |  46 +-
 .../x86/dell-wmi-sysman/passobj-attributes.c  |  23 +
 .../x86/dell-wmi-sysman/string-attributes.c   |  50 +-
 drivers/platform/x86/dell-wmi-sysman/sysman.c |  48 +-
 include/uapi/linux/wmi.h                      |  56 +++
 tools/dell-wmi-sysman/Makefile                |  19 +
 .../dell-wmi-sysman/dell-wmi-sysman-example.c | 432 ++++++++++++++++++
 11 files changed, 946 insertions(+), 89 deletions(-)
 create mode 100644 Documentation/ABI/testing/dell-wmi-sysman
 create mode 100644 tools/dell-wmi-sysman/Makefile
 create mode 100644 tools/dell-wmi-sysman/dell-wmi-sysman-example.c

diff --git a/Documentation/ABI/testing/dell-wmi-sysman b/Documentation/ABI/testing/dell-wmi-sysman
new file mode 100644
index 000000000000..4f3883529a06
--- /dev/null
+++ b/Documentation/ABI/testing/dell-wmi-sysman
@@ -0,0 +1,39 @@
+What:		/dev/wmi/dell-wmi-sysman
+Date:		November 2021
+KernelVersion:	5.15
+Contact:	"Divya Bharathi" <divya.bharathi@dell.com>
+		"Mario Limonciello" <mario.limonciello@dell.com>
+		"Prasanth K S R" <prasanth.ksr@dell.com>
+Description:
+		Perform BIOS Management calls on supported Dell machines
+		through the Dell WMI System Management interface.
+
+		This interface provides IOCTL's to perform bundled
+		BIOS Setting transactions.
+
+		IOCTL's and buffer formats are defined in:
+		<uapi/linux/wmi.h>
+
+		1) To perform a BIOS System Management call from userspace,
+		you'll need to first determine the minimum size of the
+		system management interface buffer for your machine.
+		Platforms that contain larger buffers can return larger
+		objects from the system firmware.
+		Commonly this size is either 4k or 32k.
+
+		To determine the size of the buffer read() a u64 dword from
+		the WMI character device /dev/wmi/dell-wmi-sysman.
+
+		2) After you've determined the minimum size of the system management
+		interface buffer, you can allocate a structure that represents
+		the structure documented above (struct dell_wmi_sysman_buffer).
+
+		3) In this buffer object, prepare as necessary for the BIOS System
+		Management call you're interested in. Typically System Management
+		buffers have "length", "command" , "count" and "admin_password"
+		defined to values that coincide with the "data" you are interested in.
+
+		4) Run the call by using ioctl() as described in the header.
+
+		5) The output will be returned in the buffer object and
+		make sure to free up the allocated buffer.
diff --git a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
index f95d8ddace5a..9a82e78fe59e 100644
--- a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
+++ b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
@@ -6,12 +6,14 @@
  *  Copyright (c) 2020 Dell Inc.
  */
 
+#include <uapi/linux/wmi.h>
 #include <linux/wmi.h>
 #include "dell-wmi-sysman.h"
 
 #define SETDEFAULTVALUES_METHOD_ID					0x02
 #define SETBIOSDEFAULTS_METHOD_ID					0x03
 #define SETATTRIBUTE_METHOD_ID						0x04
+#define SETATTRIBUTES_METHOD_ID						0x05
 
 static int call_biosattributes_interface(struct wmi_device *wdev, char *in_args, size_t size,
 					int method_id)
@@ -41,17 +43,17 @@ static int call_biosattributes_interface(struct wmi_device *wdev, char *in_args,
 }
 
 /**
- * set_attribute() - Update an attribute value
- * @a_name: The attribute name
- * @a_value: The attribute value
+ * set_bios_defaults() - Resets BIOS defaults
+ * @deftype: the type of BIOS value reset to issue.
  *
- * Sets an attribute to new value
+ * Resets BIOS defaults
  */
-int set_attribute(const char *a_name, const char *a_value)
+int set_bios_defaults(u8 deftype)
 {
 	size_t security_area_size, buffer_size;
-	size_t a_name_size, a_value_size;
-	char *buffer = NULL, *start;
+	size_t integer_area_size = sizeof(u8);
+	char *buffer = NULL;
+	u8 *defaultType;
 	int ret;
 
 	mutex_lock(&wmi_priv.mutex);
@@ -60,11 +62,8 @@ int set_attribute(const char *a_name, const char *a_value)
 		goto out;
 	}
 
-	/* build/calculate buffer */
 	security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
-	a_name_size = calculate_string_buffer(a_name);
-	a_value_size = calculate_string_buffer(a_value);
-	buffer_size = security_area_size + a_name_size + a_value_size;
+	buffer_size = security_area_size + integer_area_size;
 	buffer = kzalloc(buffer_size, GFP_KERNEL);
 	if (!buffer) {
 		ret = -ENOMEM;
@@ -74,44 +73,51 @@ int set_attribute(const char *a_name, const char *a_value)
 	/* build security area */
 	populate_security_buffer(buffer, wmi_priv.current_admin_password);
 
-	/* build variables to set */
-	start = buffer + security_area_size;
-	ret = populate_string_buffer(start, a_name_size, a_name);
-	if (ret < 0)
-		goto out;
-	start += ret;
-	ret = populate_string_buffer(start, a_value_size, a_value);
-	if (ret < 0)
-		goto out;
+	defaultType = buffer + security_area_size;
+	*defaultType = deftype;
 
-	print_hex_dump_bytes("set attribute data: ", DUMP_PREFIX_NONE, buffer, buffer_size);
-	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev,
-					    buffer, buffer_size,
-					    SETATTRIBUTE_METHOD_ID);
-	if (ret == -EOPNOTSUPP)
-		dev_err(&wmi_priv.bios_attr_wdev->dev, "admin password must be configured\n");
-	else if (ret == -EACCES)
-		dev_err(&wmi_priv.bios_attr_wdev->dev, "invalid password\n");
+	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, buffer_size,
+					    SETBIOSDEFAULTS_METHOD_ID);
+	if (ret)
+		dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults failed: %d\n", ret);
 
-out:
 	kfree(buffer);
+out:
 	mutex_unlock(&wmi_priv.mutex);
 	return ret;
 }
 
 /**
- * set_bios_defaults() - Resets BIOS defaults
- * @deftype: the type of BIOS value reset to issue.
+ * calculate_array_length() - calculate total size of string array
+ * @str_arr: array of strings
+ * @str_count: string count
  *
- * Resets BIOS defaults
- */
-int set_bios_defaults(u8 deftype)
+ * Method to calculate the total size of array of string
+ **/
+static int calculate_array_length(char **str_arr, int str_count)
 {
-	size_t security_area_size, buffer_size;
-	size_t integer_area_size = sizeof(u8);
-	char *buffer = NULL;
-	u8 *defaultType;
-	int ret;
+	int ret = 0, i;
+
+	for (i = 0; i < str_count; ++i)
+		ret += calculate_string_buffer(str_arr[i]);
+	return ret;
+}
+
+/**
+ * set_attributes() - Update multiple attribute values
+ * @in_data: input set data
+ * @a_count: Number of atributes to be set
+ * @command: command to decide set user input value or default
+ *
+ * Sets attributes to user input value of defaut value
+ **/
+int set_attributes(struct dell_set_data *in_data, int a_count, unsigned short command)
+{
+	size_t security_area_size, string_area_size, buffer_size, attr_count_area;
+	char **a_names, **a_values;
+	char *buffer = NULL, *start;
+	int ret, method_id, i;
+	u32 *attr_count;
 
 	mutex_lock(&wmi_priv.mutex);
 	if (!wmi_priv.bios_attr_wdev) {
@@ -119,8 +125,34 @@ int set_bios_defaults(u8 deftype)
 		goto out;
 	}
 
+	//allocate memory to hold set inputs
+	a_names = kmalloc(a_count * (sizeof(char *)), GFP_KERNEL);
+	if (!a_names) {
+		ret = -ENOMEM;
+		goto out;
+	}
+	if (command == SET_ATTRIBUTES) {
+		a_values = kmalloc(a_count * (sizeof(char *)), GFP_KERNEL);
+		if (!a_values) {
+			ret = -ENOMEM;
+			goto out;
+		}
+	}
+
+	//assign inputs to single array and send to set functions
+	for (i = 0; i < a_count; i++) {
+		a_names[i] = in_data[i].attribute_name;
+		if (command == SET_ATTRIBUTES)
+			a_values[i] = in_data[i].attribute_value;
+	}
+
 	security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
-	buffer_size = security_area_size + integer_area_size;
+	attr_count_area = sizeof(u32);
+	string_area_size = (calculate_array_length(a_names, a_count));
+	if (command == SET_ATTRIBUTES)
+		string_area_size += (calculate_array_length(a_values, a_count));
+	buffer_size = security_area_size + attr_count_area + string_area_size
+					+ (sizeof(u16) * a_count);
 	buffer = kzalloc(buffer_size, GFP_KERNEL);
 	if (!buffer) {
 		ret = -ENOMEM;
@@ -130,26 +162,153 @@ int set_bios_defaults(u8 deftype)
 	/* build security area */
 	populate_security_buffer(buffer, wmi_priv.current_admin_password);
 
-	defaultType = buffer + security_area_size;
-	*defaultType = deftype;
+	/* build variables to set */
+	attr_count = (u32 *)(buffer + security_area_size);
+	*attr_count = (u32)a_count;
+	start =  (u8 *)(attr_count) + attr_count_area;
 
-	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, buffer_size,
-					    SETBIOSDEFAULTS_METHOD_ID);
-	if (ret)
-		dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults failed: %d\n", ret);
+	for (i = 0; i < a_count; i++) {
+		ret = populate_string_buffer(start, calculate_string_buffer(a_names[i]),
+						a_names[i]);
+		if (ret < 0)
+			goto out;
+		start += ret;
+	}
+
+	if (command == SET_ATTRIBUTES) {
+		for (i = 0; i < a_count; i++) {
+			ret = populate_string_buffer(start, calculate_string_buffer(a_values[i]),
+							a_values[i]);
+			if (ret < 0)
+				goto out;
+			start += ret;
+		}
+		method_id = SETATTRIBUTES_METHOD_ID;
+	} else {
+		method_id = SETDEFAULTVALUES_METHOD_ID;
+	}
+
+	print_hex_dump_bytes("set multiple attribute: ", DUMP_PREFIX_NONE, buffer, buffer_size);
+	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev,
+					    buffer, buffer_size, method_id);
+
+	if (ret == -EOPNOTSUPP)
+		dev_err(&wmi_priv.password_attr_wdev->dev, "admin password must be configured\n");
+	else if (ret == -EACCES)
+		dev_err(&wmi_priv.password_attr_wdev->dev, "invalid password\n");
 
-	kfree(buffer);
 out:
+	kfree(buffer);
+	kfree(a_names);
+	if (command == SET_ATTRIBUTES)
+		kfree(a_values);
 	mutex_unlock(&wmi_priv.mutex);
 	return ret;
 }
 
+__u64 get_attrs_size(void)
+{
+	__u64 size = sizeof(struct dell_attributes_data) *
+				(get_instance_count(DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID) +
+				get_instance_count(DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID) +
+				get_instance_count(DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID));
+	return size;
+}
+
+int run_sysman_call(struct dell_wmi_sysman_buffer *buf)
+{
+	struct dell_set_password *pass_set_data;
+	struct dell_set_data *in_data;
+	int ret = -ENOIOCTLCMD;
+	char *tmp_system = NULL;
+	char *tmp_admin = NULL;
+
+	switch (buf->command) {
+	case ENUMERATE_ALL:
+		buf->count = get_attrs_size() / sizeof(struct dell_attributes_data);
+		get_enumeration_data(buf);
+		get_integer_data(buf);
+		get_string_data(buf);
+		ret = 0;
+		break;
+	case SET_ATTRIBUTES:
+	case SET_DEFAULTS:
+		if (!buf->count)
+			goto out;
+		in_data = (struct dell_set_data *)buf->data;
+		tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
+		strlcpy_attr(wmi_priv.current_admin_password, buf->admin_password);
+		ret = set_attributes(in_data, buf->count, buf->command);
+		strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
+		kfree(tmp_admin);
+		break;
+	case GET_PASS:
+		get_po_data(buf);
+		ret = 0;
+		break;
+	case SET_PASS:
+		pass_set_data = (struct dell_set_password *)buf->data;
+		tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
+		strlcpy_attr(wmi_priv.current_admin_password, buf->admin_password);
+
+		if (strcmp(pass_set_data->attribute_name, "System") == 0) {
+			tmp_system = kstrdup(wmi_priv.current_system_password, GFP_KERNEL);
+			strlcpy_attr(wmi_priv.current_system_password,
+					pass_set_data->system_password);
+		}
+
+		ret = set_new_password(pass_set_data->attribute_name, pass_set_data->new_password);
+		strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
+		kfree(tmp_admin);
+
+		if (tmp_system != NULL) {
+			strlcpy_attr(wmi_priv.current_system_password, tmp_system);
+			kfree(tmp_system);
+		}
+		break;
+	}
+out:
+	return ret;
+}
+
+
+static long bios_attr_set_interface_filter(struct wmi_device *wdev, unsigned int cmd,
+				   struct wmi_ioctl_buffer *arg)
+{
+	struct dell_wmi_sysman_buffer *buf;
+	struct dell_resetBIOS *reset_buf;
+	char *tmp_admin = NULL;
+	int ret = -ENOIOCTLCMD;
+
+	switch (cmd) {
+	case DELL_WMI_SYSMAN_CMD:
+		buf = (struct dell_wmi_sysman_buffer *) arg;
+		ret = run_sysman_call(buf);
+		break;
+	case DELL_WMI_SYSMAN_RESET_BIOS:
+		reset_buf = (struct dell_resetBIOS *) arg;
+		if (reset_buf->option > 0) {
+			tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
+			strlcpy_attr(wmi_priv.current_admin_password, reset_buf->admin_password);
+			ret = set_bios_defaults(reset_buf->option);
+			strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
+			kfree(tmp_admin);
+		}
+		break;
+	}
+	return ret;
+}
+
 static int bios_attr_set_interface_probe(struct wmi_device *wdev, const void *context)
 {
+	__u32 req_buf_size;
 	mutex_lock(&wmi_priv.mutex);
 	wmi_priv.bios_attr_wdev = wdev;
 	mutex_unlock(&wmi_priv.mutex);
-	return 0;
+	req_buf_size = get_attrs_size();
+	/* add in size of struct dell_wmi_sysman_buffer which is used internally with ioctl */
+	req_buf_size += sizeof(struct dell_wmi_sysman_buffer);
+	return set_required_buffer_size(wdev, req_buf_size);
 }
 
 static int bios_attr_set_interface_remove(struct wmi_device *wdev)
@@ -171,6 +330,7 @@ static struct wmi_driver bios_attr_set_interface_driver = {
 	.probe = bios_attr_set_interface_probe,
 	.remove = bios_attr_set_interface_remove,
 	.id_table = bios_attr_set_interface_id_table,
+	.filter_callback = bios_attr_set_interface_filter
 };
 
 int init_bios_attr_set_interface(void)
@@ -184,3 +344,4 @@ void exit_bios_attr_set_interface(void)
 }
 
 MODULE_DEVICE_TABLE(wmi, bios_attr_set_interface_id_table);
+
diff --git a/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h b/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
index b80f2a62ea3f..13c216e6ddec 100644
--- a/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
+++ b/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
@@ -8,6 +8,7 @@
 #define _DELL_WMI_BIOS_ATTR_H_
 
 #include <linux/wmi.h>
+#include <uapi/linux/wmi.h>
 #include <linux/device.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -87,8 +88,6 @@ struct wmi_sysman_priv {
 /* global structure used by multiple WMI interfaces */
 extern struct wmi_sysman_priv wmi_priv;
 
-enum { ENUM, INT, STR, PO };
-
 enum {
 	ATTR_NAME,
 	DISPL_NAME_LANG_CODE,
@@ -134,6 +133,7 @@ static ssize_t curr_val##_store(struct kobject *kobj,				\
 				struct kobj_attribute *attr,			\
 				const char *buf, size_t count)			\
 {										\
+	struct dell_set_data *set_data;						\
 	char *p, *buf_cp;							\
 	int i, ret = -EIO;							\
 	buf_cp = kstrdup(buf, GFP_KERNEL);					\
@@ -146,15 +146,19 @@ static ssize_t curr_val##_store(struct kobject *kobj,				\
 	i = get_##type##_instance_id(kobj);					\
 	if (i >= 0)								\
 		ret = validate_##type##_input(i, buf_cp);			\
+	set_data = kzalloc(sizeof(*set_data), GFP_KERNEL);			\
+	strlcpy_attr(set_data[0].attribute_value, buf_cp);			\
+	strlcpy_attr(set_data[0].attribute_name, kobj->name);			\
 	if (!ret)								\
-		ret = set_attribute(kobj->name, buf_cp);			\
+		ret = set_attributes(set_data, 1, SET_ATTRIBUTES);		\
 	kfree(buf_cp);								\
 	return ret ? ret : count;						\
 }
 
 union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string);
 int get_instance_count(const char *guid_string);
-void strlcpy_attr(char *dest, char *src);
+int get_current_value(char *buf, int instance_id, const char *guid_string);
+void strlcpy_attr(char *dest, const char *src);
 
 int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
 			struct kobject *attr_name_kobj);
@@ -174,7 +178,7 @@ int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject
 int alloc_po_data(void);
 void exit_po_attributes(void);
 
-int set_attribute(const char *a_name, const char *a_value);
+int set_attributes(struct dell_set_data *in_data, int a_count, unsigned short command);
 int set_bios_defaults(u8 defType);
 
 void exit_bios_attr_set_interface(void);
@@ -188,4 +192,10 @@ int set_new_password(const char *password_type, const char *new);
 int init_bios_attr_pass_interface(void);
 void exit_bios_attr_pass_interface(void);
 
+__u64 get_attrs_size(void);
+void get_enumeration_data(struct dell_wmi_sysman_buffer *buf);
+void get_integer_data(struct dell_wmi_sysman_buffer *buf);
+void get_string_data(struct dell_wmi_sysman_buffer *buf);
+void get_po_data(struct dell_wmi_sysman_buffer *attr_data);
+
 #endif
diff --git a/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
index 80f4b7785c6c..b23e10ac00da 100644
--- a/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
+++ b/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
@@ -13,22 +13,17 @@ get_instance_id(enumeration);
 static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
 	int instance_id = get_enumeration_instance_id(kobj);
-	union acpi_object *obj;
-	ssize_t ret;
+	int ret;
 
 	if (instance_id < 0)
 		return instance_id;
 
-	/* need to use specific instance_id and guid combination to get right data */
-	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
-	if (!obj)
-		return -EIO;
-	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) {
-		kfree(obj);
-		return -EINVAL;
+	ret = get_current_value(buf, instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
+	if (ret > 0) {
+		strcat(buf, "\n");
+		return strlen(buf);
 	}
-	ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
-	kfree(obj);
+	/* read error */
 	return ret;
 }
 
@@ -171,6 +166,34 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
 	return sysfs_create_group(attr_name_kobj, &enumeration_attr_group);
 }
 
+void get_enumeration_data(struct dell_wmi_sysman_buffer *buf)
+{
+	struct dell_attributes_data *attr_data;
+	int i;
+
+	attr_data = (struct dell_attributes_data *)buf->data;
+	for (i = 0; i < wmi_priv.enumeration_instances_count; i++) {
+		attr_data[i].type = ENUM;
+		strlcpy_attr(attr_data[i].attribute_name,
+					wmi_priv.enumeration_data[i].attribute_name);
+		strlcpy_attr(attr_data[i].display_name,
+					wmi_priv.enumeration_data[i].display_name);
+		strlcpy_attr(attr_data[i].display_name_language_code,
+					wmi_priv.enumeration_data[i].display_name_language_code);
+		strlcpy_attr(attr_data[i].possible_values,
+					wmi_priv.enumeration_data[i].possible_values);
+		strlcpy_attr(attr_data[i].dell_modifier,
+					wmi_priv.enumeration_data[i].dell_modifier);
+		strlcpy_attr(attr_data[i].dell_value_modifier,
+					wmi_priv.enumeration_data[i].dell_value_modifier);
+		strlcpy_attr(attr_data[i].default_value,
+					wmi_priv.enumeration_data[i].default_value);
+		get_current_value(attr_data[i].current_value, i,
+					DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
+
+	}
+}
+
 /**
  * exit_enum_attributes() - Clear all attribute data
  *
diff --git a/drivers/platform/x86/dell-wmi-sysman/int-attributes.c b/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
index 75aedbb733be..0155f6189576 100644
--- a/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
+++ b/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
@@ -15,22 +15,17 @@ get_instance_id(integer);
 static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
 	int instance_id = get_integer_instance_id(kobj);
-	union acpi_object *obj;
-	ssize_t ret;
+	int ret;
 
 	if (instance_id < 0)
 		return instance_id;
 
-	/* need to use specific instance_id and guid combination to get right data */
-	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
-	if (!obj)
-		return -EIO;
-	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_INTEGER) {
-		kfree(obj);
-		return -EINVAL;
+	ret = get_current_value(buf, instance_id, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
+	if (ret > 0) {
+		strcat(buf, "\n");
+		return strlen(buf);
 	}
-	ret = snprintf(buf, PAGE_SIZE, "%lld\n", obj->package.elements[CURRENT_VAL].integer.value);
-	kfree(obj);
+	/* read error */
 	return ret;
 }
 
@@ -161,6 +156,35 @@ int populate_int_data(union acpi_object *integer_obj, int instance_id,
 	return sysfs_create_group(attr_name_kobj, &integer_attr_group);
 }
 
+void get_integer_data(struct dell_wmi_sysman_buffer *buf)
+{
+	struct dell_attributes_data *attr_data;
+	int i;
+	//To populate in same dell_attributes_data, increment after enum data
+	int a_count = wmi_priv.enumeration_instances_count;
+
+	attr_data = (struct dell_attributes_data *)buf->data;
+	for (i = 0; i < wmi_priv.integer_instances_count; i++) {
+		attr_data[a_count].type = INT;
+		strlcpy_attr(attr_data[a_count].attribute_name,
+					wmi_priv.integer_data[i].attribute_name);
+		strlcpy_attr(attr_data[a_count].display_name,
+					wmi_priv.integer_data[i].display_name);
+		strlcpy_attr(attr_data[a_count].display_name_language_code,
+					wmi_priv.integer_data[i].display_name_language_code);
+		strlcpy_attr(attr_data[a_count].dell_modifier,
+					wmi_priv.integer_data[i].dell_modifier);
+		attr_data[a_count].min = wmi_priv.integer_data[i].min_value;
+		attr_data[a_count].max = wmi_priv.integer_data[i].max_value;
+		attr_data[a_count].scalar_increment = wmi_priv.integer_data[i].scalar_increment;
+		snprintf(attr_data[a_count].default_value, PAGE_SIZE, "%d",
+				wmi_priv.integer_data[i].default_value);
+		get_current_value(attr_data[a_count].current_value, i,
+				DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
+		a_count++;
+	}
+}
+
 /**
  * exit_int_attributes() - Clear all attribute data
  *
diff --git a/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c b/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
index 3abcd95477c0..9f50989a9f44 100644
--- a/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
+++ b/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
@@ -169,6 +169,29 @@ int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject
 	return sysfs_create_group(attr_name_kobj, &po_attr_group);
 }
 
+void get_po_data(struct dell_wmi_sysman_buffer *in_data)
+{
+	int i;
+	struct dell_password_data *attr_data;
+
+	in_data->count = wmi_priv.po_instances_count;
+	attr_data = (struct dell_password_data *)in_data->data;
+	for (i = 0; i < wmi_priv.po_instances_count; i++) {
+		union acpi_object *obj;
+
+		strlcpy_attr(attr_data[i].attribute_name,
+						wmi_priv.po_data[i].attribute_name);
+		attr_data[i].min_length = wmi_priv.po_data[i].min_password_length;
+		attr_data[i].max_length = wmi_priv.po_data[i].max_password_length;
+
+		obj = get_wmiobj_pointer(i, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
+		if (!obj)
+			continue;
+		attr_data[i].is_set = obj->package.elements[IS_PASS_SET].integer.value;
+		kfree(obj);
+	}
+}
+
 /**
  * exit_po_attributes() - Clear all attribute data
  *
diff --git a/drivers/platform/x86/dell-wmi-sysman/string-attributes.c b/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
index ac75dce88a4c..a3847e4a6bf8 100644
--- a/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
+++ b/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
@@ -15,22 +15,17 @@ get_instance_id(str);
 static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
 {
 	int instance_id = get_str_instance_id(kobj);
-	union acpi_object *obj;
-	ssize_t ret;
+	int ret;
 
 	if (instance_id < 0)
-		return -EIO;
-
-	/* need to use specific instance_id and guid combination to get right data */
-	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
-	if (!obj)
-		return -EIO;
-	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) {
-		kfree(obj);
-		return -EINVAL;
+		return instance_id;
+
+	ret = get_current_value(buf, instance_id, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
+	if (ret > 0) {
+		strcat(buf, "\n");
+		return strlen(buf);
 	}
-	ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
-	kfree(obj);
+	/* read error */
 	return ret;
 }
 
@@ -141,6 +136,35 @@ int populate_str_data(union acpi_object *str_obj, int instance_id, struct kobjec
 	return sysfs_create_group(attr_name_kobj, &str_attr_group);
 }
 
+void get_string_data(struct dell_wmi_sysman_buffer *buf)
+{
+	struct dell_attributes_data *attr_data;
+	int i;
+	//To populate in same dell_attributes_data, increment after enum+int data
+	int a_count = wmi_priv.enumeration_instances_count +
+					wmi_priv.integer_instances_count;
+	attr_data = (struct dell_attributes_data *)buf->data;
+
+	for (i = 0; i < wmi_priv.str_instances_count; i++) {
+		attr_data[a_count].type = STR;
+		strlcpy_attr(attr_data[a_count].attribute_name,
+						wmi_priv.str_data[i].attribute_name);
+		strlcpy_attr(attr_data[a_count].display_name,
+						wmi_priv.str_data[i].display_name);
+		strlcpy_attr(attr_data[a_count].display_name_language_code,
+						wmi_priv.str_data[i].display_name_language_code);
+		strlcpy_attr(attr_data[a_count].dell_modifier,
+						wmi_priv.str_data[i].dell_modifier);
+		attr_data[a_count].min = wmi_priv.str_data[i].min_length;
+		attr_data[a_count].max = wmi_priv.str_data[i].max_length;
+		strlcpy_attr(attr_data[a_count].default_value,
+						wmi_priv.str_data[i].default_value);
+		get_current_value(attr_data[a_count].current_value, i,
+				DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
+		a_count++;
+	}
+}
+
 /**
  * exit_str_attributes() - Clear all attribute data
  *
diff --git a/drivers/platform/x86/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell-wmi-sysman/sysman.c
index cb81010ba1a2..0b77a6a0b8a8 100644
--- a/drivers/platform/x86/dell-wmi-sysman/sysman.c
+++ b/drivers/platform/x86/dell-wmi-sysman/sysman.c
@@ -275,7 +275,7 @@ static struct kobj_type attr_name_ktype = {
  * @dest: Where to copy the string to
  * @src: Where to copy the string from
  */
-void strlcpy_attr(char *dest, char *src)
+void strlcpy_attr(char *dest, const char *src)
 {
 	size_t len = strlen(src) + 1;
 
@@ -307,6 +307,52 @@ union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string)
 	return ACPI_SUCCESS(status) ? (union acpi_object *)out.pointer : NULL;
 }
 
+int validate_acpi_type(union acpi_object *obj, const char *guid_string)
+{
+	u32 acpi_type;
+
+	if (strcmp(guid_string, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID) == 0)
+		acpi_type = ACPI_TYPE_INTEGER;
+	else
+		acpi_type = ACPI_TYPE_STRING;
+
+	if (obj->package.elements[CURRENT_VAL].type != acpi_type)
+		return -EIO;
+
+	return 0;
+}
+
+/**
+ * get_curret_value() - Get current_value of an attribute
+ * @instance_id: WMI instance ID
+ * @guid_string: WMI GUID (in string form)
+ */
+int get_current_value(char *buf, int instance_id, const char *guid_string)
+{
+	union acpi_object *obj;
+	int ret;
+
+	/* need to use specific instance_id and guid combination to get right data */
+	obj = get_wmiobj_pointer(instance_id, guid_string);
+	if (!obj)
+		return -EIO;
+
+	ret = validate_acpi_type(obj, guid_string);
+	if (ret)
+		goto out;
+
+	if (strcmp(guid_string, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID) == 0)
+		ret = snprintf(buf, PAGE_SIZE, "%lld",
+				obj->package.elements[CURRENT_VAL].integer.value);
+	else
+		ret = snprintf(buf, PAGE_SIZE, "%s",
+				obj->package.elements[CURRENT_VAL].string.pointer);
+
+out:
+	kfree(obj);
+	return ret;
+}
+
 /**
  * get_instance_count() - Compute total number of instances under guid_string
  * @guid_string: WMI GUID (in string form)
diff --git a/include/uapi/linux/wmi.h b/include/uapi/linux/wmi.h
index 7085c5dca9fa..f160d1eef7cb 100644
--- a/include/uapi/linux/wmi.h
+++ b/include/uapi/linux/wmi.h
@@ -13,6 +13,11 @@
 /* WMI bus will filter all WMI vendor driver requests through this IOC */
 #define WMI_IOC 'W'
 
+enum BIOS_ATTRIBUTE_TYPE { ENUM, INT, STR, PO };
+enum IOCTL_COMMAND { ENUMERATE_ALL = 1, SET_ATTRIBUTES, SET_DEFAULTS, GET_PASS, SET_PASS };
+
+#define MAX_BUFF  512
+
 /* All ioctl requests through WMI should declare their size followed by
  * relevant data objects
  */
@@ -43,6 +48,53 @@ struct dell_wmi_smbios_buffer {
 	struct dell_wmi_extensions	ext;
 } __packed;
 
+struct dell_wmi_sysman_buffer {
+	__u64 length;
+	__u32 count;
+	__u16 command;
+	char admin_password[MAX_BUFF];
+	__u8 data[];
+} __packed;
+
+struct dell_attributes_data {
+	char display_name_language_code[MAX_BUFF];
+	char dell_value_modifier[MAX_BUFF];
+	char possible_values[MAX_BUFF];
+	char attribute_name[MAX_BUFF];
+	char current_value[MAX_BUFF];
+	char default_value[MAX_BUFF];
+	char dell_modifier[MAX_BUFF];
+	char display_name[MAX_BUFF];
+	int scalar_increment;
+	int type;
+	int min;
+	int max;
+} __packed;
+
+struct dell_set_data {
+	char attribute_name[MAX_BUFF];
+	char attribute_value[MAX_BUFF];
+} __packed;
+
+struct dell_set_password {
+	char attribute_name[MAX_BUFF];
+	char system_password[MAX_BUFF];
+	char new_password[MAX_BUFF];
+} __packed;
+
+struct dell_password_data {
+	char attribute_name[MAX_BUFF];
+	__u8 is_set;
+	int min_length;
+	int max_length;
+} __packed;
+
+struct dell_resetBIOS {
+	__u64 length;
+	__u8 option;
+	char admin_password[MAX_BUFF];
+} __packed;
+
 /* Whitelisted smbios class/select commands */
 #define CLASS_TOKEN_READ	0
 #define CLASS_TOKEN_WRITE	1
@@ -67,4 +119,8 @@ struct dell_wmi_smbios_buffer {
 /* Dell SMBIOS calling IOCTL command used by dell-smbios-wmi */
 #define DELL_WMI_SMBIOS_CMD	_IOWR(WMI_IOC, 0, struct dell_wmi_smbios_buffer)
 
+/* Dell WMI System Management calling IOCTL commands used by dell-wmi-sysman */
+#define DELL_WMI_SYSMAN_CMD _IOWR(WMI_IOC, 0, struct dell_wmi_sysman_buffer)
+#define DELL_WMI_SYSMAN_RESET_BIOS _IOW(WMI_IOC, 0, struct dell_resetBIOS)
+
 #endif
diff --git a/tools/dell-wmi-sysman/Makefile b/tools/dell-wmi-sysman/Makefile
new file mode 100644
index 000000000000..0a01a82a0745
--- /dev/null
+++ b/tools/dell-wmi-sysman/Makefile
@@ -0,0 +1,19 @@
+# SPDX-License-Identifier: GPL-2.0-only
+PREFIX ?= /usr
+SBINDIR ?= sbin
+INSTALL ?= install
+CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include -I./
+
+TARGET = dell-wmi-sysman-example
+
+all: $(TARGET)
+
+%: %.c
+	$(CC) $(CFLAGS) $(LDFLAGS) -g -o $@ $<
+
+clean:
+	$(RM) $(TARGET)
+
+install: dell-wmi-sysman-example
+	$(INSTALL) -D -m 755 $(TARGET) $(DESTDIR)$(PREFIX)/$(SBINDIR)/$(TARGET)
+
diff --git a/tools/dell-wmi-sysman/dell-wmi-sysman-example.c b/tools/dell-wmi-sysman/dell-wmi-sysman-example.c
new file mode 100644
index 000000000000..50db8835cea6
--- /dev/null
+++ b/tools/dell-wmi-sysman/dell-wmi-sysman-example.c
@@ -0,0 +1,432 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *  Sample application for system management over WMI interface
+ *  Performs the following:
+ *  - Enemeration of all BIOS attributes present in system
+ *  - Set BIOS atributes to user input or default
+ *	- Reset BIOS
+ *
+ *  Copyright (C) 2021 Dell, Inc.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ */
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/ioctl.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+
+/* if uapi header isn't installed, this might not yet exist */
+#ifndef __packed
+#define __packed __attribute__((packed))
+#endif
+#include <linux/wmi.h>
+
+enum USER_OPTS {GET_ATTRS = 1, SET_ATTRS, SET_DEFS, PASS_MAN, RESET, EXIT };
+enum PASS_OPTS {GET_PASSINFO = 1, SET_OR_CHANGE_PASS, CLEAR_PASS, BACK };
+
+static const char *ioctl_devfs = "/dev/wmi/dell-wmi-sysman";
+__u64 buff_size;
+
+static int query_buffer_size(__u64 *buffer_size)
+{
+	FILE *f = fopen(ioctl_devfs, "rb");
+
+	if (!f)
+		return -EINVAL;
+	fread(buffer_size, sizeof(__u64), 1, f);
+	fclose(f);
+	return EXIT_SUCCESS;
+}
+
+int read_integer_input(void)
+{
+	int val, in, c;
+	char follow;
+
+	while (1) {
+		in = scanf("%d%c", &val, &follow);
+		if (in == 2) {
+			if (isspace(follow))
+				return val;
+			printf("Invalid input! Try again...\nEnter - ");
+		} else if (in == 1) {
+			return val;
+		printf("Invalid input! Try again...\nEnter - ");
+		}
+
+		while ((c = getchar()) != '\n' && c != EOF)
+			;
+	}
+}
+
+static int call_ioctl(struct dell_wmi_sysman_buffer *buffer)
+{
+	int fd;
+	int ret;
+
+	fd = open(ioctl_devfs, O_NONBLOCK);
+	ret = ioctl(fd, DELL_WMI_SYSMAN_CMD, buffer);
+	close(fd);
+	return ret;
+}
+
+int is_password_set(unsigned char *password_type)
+{
+	int ret, i;
+	int is_set = 0;
+	struct dell_wmi_sysman_buffer *buff_pwd;
+	struct dell_password_data *indata;
+
+	buff_pwd = malloc(buff_size); //buff_size large enough to get password data
+	if (buff_pwd == NULL) {
+		printf("failed to alloc memory for ioctl\n");
+		return -ENOMEM;
+	}
+
+	buff_pwd->length = buff_size;
+	buff_pwd->command = GET_PASS;
+	call_ioctl(buff_pwd);
+
+	indata = (struct dell_password_data *)buff_pwd->data;
+
+	for (i = 0; i < buff_pwd->count; i++) {
+		if (strcmp(indata[i].attribute_name, password_type) == 0) {
+			is_set = indata[i].is_set;
+			break;
+		}
+	}
+
+	free(buff_pwd);
+	return is_set;
+}
+
+/* Enumerate functions start*/
+void display_attributes(struct dell_wmi_sysman_buffer *buff_all)
+{
+	struct dell_attributes_data *testdata;
+	int i;
+
+	testdata = (struct dell_attributes_data *)buff_all->data;
+	for (i = 0; i < buff_all->count; i++) {
+		printf("\n%d\n", (i + 1));
+		printf("AttributeName = %s\n", testdata[i].attribute_name);
+		printf("Display LangCode = %s\n", testdata[i].display_name_language_code);
+		printf("Display Name = %s\n", testdata[i].display_name);
+		printf("Modifier = %s\n", testdata[i].dell_modifier);
+		printf("Current Value = %s\n", testdata[i].current_value);
+		printf("Default Value = %s\n", testdata[i].default_value);
+		if (testdata[i].type == ENUM) {
+			printf("Value Modifier = %s\n", testdata[i].dell_value_modifier);
+			printf("PossibleValues = %s\n", testdata[i].possible_values);
+		}
+		if (testdata[i].type == INT) {
+			printf("Lower Bound = %d\n", testdata[i].min);
+			printf("Upper Bound = %d\n", testdata[i].max);
+			printf("Scalar incr = %d\n", testdata[i].scalar_increment);
+		}
+		if (testdata[i].type == STR) {
+			printf("Minimum Length = %d\n", testdata[i].min);
+			printf("Maximum Length = %d\n", testdata[i].max);
+		}
+	}
+	printf("---------------------------------------------------------\n");
+}
+
+void enumerate_all_attributes(void)
+{
+	struct dell_wmi_sysman_buffer *buff_all;
+	int ret;
+
+	buff_all = malloc(buff_size);
+	if (buff_all == NULL) {
+		printf("failed to alloc memory for ioctl\n");
+		return;
+	}
+	buff_all->length = buff_size;
+	buff_all->command = ENUMERATE_ALL;
+	ret = call_ioctl(buff_all);
+	if (ret) {
+		printf("smbios ioctl failed: %d\n", ret);
+		goto out;
+	}
+	display_attributes(buff_all);
+out:
+	if (buff_all != NULL)
+		free(buff_all);
+}
+/* Enumerate functions end*/
+
+/* SET functions start */
+int read_set_data(struct dell_wmi_sysman_buffer *buff_set, int option)
+{
+	int i, admin_pwd_set;
+	struct dell_set_data *indata;
+
+	admin_pwd_set = is_password_set("Admin");
+	if (admin_pwd_set < 0) {
+		printf("check password call failed!!!\n");
+		return EXIT_FAILURE;
+	}
+
+	printf("How many attributes to set: ");
+	scanf("%d", &buff_set->count);
+
+	indata = (struct dell_set_data *)buff_set->data;
+
+	if (admin_pwd_set) {
+		printf("Admin password is set, please enter password - ");
+		scanf("%s", buff_set->admin_password);
+	}
+
+	for (i = 0; i < buff_set->count; i++) {
+		printf("Enter Attribute Name: ");
+		scanf("%s", indata[i].attribute_name);
+
+		if (option == SET_ATTRIBUTES) {
+			printf("Enter Attribute Value: ");
+			scanf("%s", indata[i].attribute_value);
+		}
+	}
+	return 0;
+}
+
+void call_set_cmd(int cmd_opt)
+{
+	int i, ret;
+	struct dell_wmi_sysman_buffer *buff_set;
+
+	buff_set = malloc(buff_size);
+	if (buff_set == NULL) {
+		printf("failed to alloc memory for ioctl\n");
+		return;
+	}
+	buff_set->length = buff_size;
+	buff_set->command = cmd_opt;
+	if (read_set_data(buff_set, cmd_opt))
+		goto out;
+
+	ret = call_ioctl(buff_set);
+	if (!ret) {
+		printf("Set Successful...\n");
+		goto out;
+	}
+	printf("Set failed: %d\n", ret);
+out:
+	free(buff_set);
+}
+/* SET functions end */
+
+/* Password related functions start */
+void get_password_info(void)
+{
+	int i;
+	struct dell_wmi_sysman_buffer *buff_pwd;
+	struct dell_password_data *testdata;
+
+	buff_pwd = malloc(buff_size); //buff_size large enough to get password data
+	if (buff_pwd == NULL) {
+		printf("failed to alloc memory for ioctl\n");
+		return;
+	}
+	buff_pwd->length = buff_size;
+	buff_pwd->command = GET_PASS;
+	if (call_ioctl(buff_pwd)) {
+		free(buff_pwd);
+		printf("smbios ioctl failed!!!\n");
+		return;
+	}
+
+	testdata = (struct dell_password_data *)buff_pwd->data;
+	for (i = 0; i < buff_pwd->count; i++) {
+		printf("\n%d\n", (i + 1));
+		printf("AttributeName = %s\n", testdata[i].attribute_name);
+		printf("Minimum Length = %d\n", testdata[i].min_length);
+		printf("Maximum Length = %d\n", testdata[i].max_length);
+		printf("Is Password Set = %d\n", testdata[i].is_set);
+	}
+	if (buff_pwd != NULL)
+		free(buff_pwd);
+}
+
+void call_set_pasword_cmd(int clear_opt)
+{
+	int ret, is_admin_pwd_set, is_system_pwd_set;
+	struct dell_wmi_sysman_buffer *buff_pwd;
+	struct dell_set_password *indata;
+
+	buff_pwd = malloc(buff_size); //buff_size large enough to get password data
+	if (buff_pwd == NULL) {
+		printf("failed to alloc memory for ioctl\n");
+		return;
+	}
+	buff_pwd->length = buff_size;
+	buff_pwd->command = SET_PASS;
+	is_admin_pwd_set = is_password_set("Admin");
+	is_system_pwd_set = is_password_set("System");
+	if ((is_admin_pwd_set < 0) || (is_system_pwd_set < 0)) {
+		printf("check password call failed!!!\n");
+		goto out;
+	}
+
+	indata = (struct dell_set_password *)buff_pwd->data;
+
+	if (is_admin_pwd_set) {
+		printf("Admin password is set, please enter current admin password - ");
+		scanf("%s", buff_pwd->admin_password);
+	}
+
+	printf("Enter which password to set Admin/System - ");
+	scanf("%s", indata->attribute_name);
+
+	if (strcmp(indata->attribute_name, "System") == 0 && (is_system_pwd_set)) {
+		printf("System password is set, please enter current system password - ");
+		scanf("%s", indata->system_password);
+	}
+
+	if (clear_opt == 3) {
+		strcpy(indata->new_password, "");
+	} else {
+		printf("Enter new password - ");
+		scanf("%s", indata->new_password);
+	}
+	ret = call_ioctl(buff_pwd);
+	if (!ret) {
+		printf("Set Successful...\n");
+		ret = EXIT_SUCCESS;
+		goto out;
+	}
+	printf("Set failed: %d\n", ret);
+out:
+	free(buff_pwd);
+}
+
+void call_password_management(void)
+{
+	int opt, ret;
+
+	while (1) {
+		printf("\n##############################\n");
+		printf(" Password Management Menu\t\n");
+		printf("##############################\n");
+		printf("\n1 - Get Password Information\n"
+				"2 - Set/Change Password\n"
+				"3 - Clear Password\n"
+				"4 - Go to back to Main Menu\n\n"
+				"Enter - ");
+		opt = read_integer_input();
+
+		switch (opt) {
+		case GET_PASSINFO:
+			get_password_info();
+			break;
+		case SET_OR_CHANGE_PASS:
+		case CLEAR_PASS:
+			call_set_pasword_cmd(opt);
+			break;
+		case BACK:
+			return;
+		default:
+			printf("Invalid option!\n");
+			break;
+		}
+	}
+}
+/* Password related functions end */
+
+void call_reset_bios(void)
+{
+	struct dell_resetBIOS *buff_reset;
+	unsigned char reset_option;
+	int fd, ret, is_admin_pwd_set;
+
+	printf("\nReset Options:\n"
+			"0 - Built-in Safe Defaults\n"
+			"1 - Last Known Good\n"
+			"2 - Factory\n"
+			"3 - Custom\n\n"
+			"Enter - ");
+	scanf("%hhu", &reset_option);
+	buff_reset = malloc(buff_size);
+	if (buff_reset == NULL) {
+		printf("failed to alloc memory for ioctl\n");
+		return;
+	}
+	is_admin_pwd_set = is_password_set("Admin");
+	if ((is_admin_pwd_set < 0)) {
+		printf("check password call failed!!!\n");
+		goto out;
+	}
+
+	buff_reset->length = buff_size;
+	if (is_admin_pwd_set) {
+		printf("Admin password is set, please enter current admin password - ");
+		scanf("%s", buff_reset->admin_password);
+	}
+	fd = open(ioctl_devfs, O_NONBLOCK);
+	ret = ioctl(fd, DELL_WMI_SYSMAN_RESET_BIOS, buff_reset);
+	close(fd);
+	if (!ret) {
+		printf("Reset Successful. Reboot the system\n");
+		ret = EXIT_SUCCESS;
+		goto out;
+	}
+	printf("Reset Failed: %d\n", ret);
+out:
+	if (buff_reset != NULL)
+		free(buff_reset);
+}
+
+int main(void)
+{
+	int ret, opt;
+	__u64 value = 0;
+
+	ret = query_buffer_size(&value);
+	if (ret == EXIT_FAILURE || !value) {
+		printf("Unable to read buffer size\n");
+		return ret;
+	}
+	buff_size = value;
+	while (1) {
+		printf("\n\n\n##############################\n");
+		printf("Dell BIOS System Management Utility\n");
+		printf("##############################\n");
+		printf("\n1 - Enumerate All Attributes\n"
+				"2 - Set Attributes\n"
+				"3 - Set To Defaults\n"
+				"4 - Password Management\n"
+				"5 - Reset BIOS\n"
+				"6 - Exit\n"
+				"\n\nEnter - ");
+		opt = read_integer_input();
+
+		switch (opt) {
+		case GET_ATTRS:
+			enumerate_all_attributes();
+			break;
+		case SET_ATTRS:
+		case SET_DEFS:
+			call_set_cmd(opt);
+			break;
+		case PASS_MAN:
+			call_password_management();
+			break;
+		case RESET:
+			call_reset_bios();
+			break;
+		case EXIT:
+			exit(0);
+			break;
+		default:
+			break;
+		}
+	}
+	return 0;
+}
-- 
2.25.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH] IOCTL support for dell-wmi-sysman driver
  2021-02-09 14:28 [PATCH] IOCTL support for dell-wmi-sysman driver Prasanth, KSR
@ 2021-02-09 17:48   ` kernel test robot
  2021-02-09 17:57 ` Hans de Goede
  2021-02-09 22:34   ` kernel test robot
  2 siblings, 0 replies; 7+ messages in thread
From: kernel test robot @ 2021-02-09 17:48 UTC (permalink / raw)
  To: Prasanth, KSR, Hans de Goede, dvhart
  Cc: kbuild-all, LKML, platform-driver-x86, Prasanth KSR,
	Divya Bharathi, Mario Limonciello

[-- Attachment #1: Type: text/plain, Size: 4207 bytes --]

Hi KSR",

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v5.11-rc7 next-20210125]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Prasanth-KSR/IOCTL-support-for-dell-wmi-sysman-driver/20210209-223343
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 61556703b610a104de324e4f061dc6cf7b218b46
config: i386-randconfig-a002-20210209 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
reproduce (this is a W=1 build):
        # https://github.com/0day-ci/linux/commit/00141bcb2495c75a902d3070e149760b1050322e
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Prasanth-KSR/IOCTL-support-for-dell-wmi-sysman-driver/20210209-223343
        git checkout 00141bcb2495c75a902d3070e149760b1050322e
        # save the attached .config to linux build tree
        make W=1 ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All error/warnings (new ones prefixed by >>):

   ld: drivers/platform/x86/dell-wmi-sysman/biosattr-interface.o: in function `run_sysman_call':
>> drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c:228: undefined reference to `__udivdi3'
--
>> drivers/platform/x86/dell-wmi-sysman/sysman.c:310:5: warning: no previous prototype for 'validate_acpi_type' [-Wmissing-prototypes]
     310 | int validate_acpi_type(union acpi_object *obj, const char *guid_string)
         |     ^~~~~~~~~~~~~~~~~~
--
>> drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c:218:5: warning: no previous prototype for 'run_sysman_call' [-Wmissing-prototypes]
     218 | int run_sysman_call(struct dell_wmi_sysman_buffer *buf)
         |     ^~~~~~~~~~~~~~~


vim +228 drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c

   217	
 > 218	int run_sysman_call(struct dell_wmi_sysman_buffer *buf)
   219	{
   220		struct dell_set_password *pass_set_data;
   221		struct dell_set_data *in_data;
   222		int ret = -ENOIOCTLCMD;
   223		char *tmp_system = NULL;
   224		char *tmp_admin = NULL;
   225	
   226		switch (buf->command) {
   227		case ENUMERATE_ALL:
 > 228			buf->count = get_attrs_size() / sizeof(struct dell_attributes_data);
   229			get_enumeration_data(buf);
   230			get_integer_data(buf);
   231			get_string_data(buf);
   232			ret = 0;
   233			break;
   234		case SET_ATTRIBUTES:
   235		case SET_DEFAULTS:
   236			if (!buf->count)
   237				goto out;
   238			in_data = (struct dell_set_data *)buf->data;
   239			tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
   240			strlcpy_attr(wmi_priv.current_admin_password, buf->admin_password);
   241			ret = set_attributes(in_data, buf->count, buf->command);
   242			strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
   243			kfree(tmp_admin);
   244			break;
   245		case GET_PASS:
   246			get_po_data(buf);
   247			ret = 0;
   248			break;
   249		case SET_PASS:
   250			pass_set_data = (struct dell_set_password *)buf->data;
   251			tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
   252			strlcpy_attr(wmi_priv.current_admin_password, buf->admin_password);
   253	
   254			if (strcmp(pass_set_data->attribute_name, "System") == 0) {
   255				tmp_system = kstrdup(wmi_priv.current_system_password, GFP_KERNEL);
   256				strlcpy_attr(wmi_priv.current_system_password,
   257						pass_set_data->system_password);
   258			}
   259	
   260			ret = set_new_password(pass_set_data->attribute_name, pass_set_data->new_password);
   261			strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
   262			kfree(tmp_admin);
   263	
   264			if (tmp_system != NULL) {
   265				strlcpy_attr(wmi_priv.current_system_password, tmp_system);
   266				kfree(tmp_system);
   267			}
   268			break;
   269		}
   270	out:
   271		return ret;
   272	}
   273	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 37943 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] IOCTL support for dell-wmi-sysman driver
@ 2021-02-09 17:48   ` kernel test robot
  0 siblings, 0 replies; 7+ messages in thread
From: kernel test robot @ 2021-02-09 17:48 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 4311 bytes --]

Hi KSR",

Thank you for the patch! Yet something to improve:

[auto build test ERROR on linus/master]
[also build test ERROR on v5.11-rc7 next-20210125]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Prasanth-KSR/IOCTL-support-for-dell-wmi-sysman-driver/20210209-223343
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 61556703b610a104de324e4f061dc6cf7b218b46
config: i386-randconfig-a002-20210209 (attached as .config)
compiler: gcc-9 (Debian 9.3.0-15) 9.3.0
reproduce (this is a W=1 build):
        # https://github.com/0day-ci/linux/commit/00141bcb2495c75a902d3070e149760b1050322e
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Prasanth-KSR/IOCTL-support-for-dell-wmi-sysman-driver/20210209-223343
        git checkout 00141bcb2495c75a902d3070e149760b1050322e
        # save the attached .config to linux build tree
        make W=1 ARCH=i386 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All error/warnings (new ones prefixed by >>):

   ld: drivers/platform/x86/dell-wmi-sysman/biosattr-interface.o: in function `run_sysman_call':
>> drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c:228: undefined reference to `__udivdi3'
--
>> drivers/platform/x86/dell-wmi-sysman/sysman.c:310:5: warning: no previous prototype for 'validate_acpi_type' [-Wmissing-prototypes]
     310 | int validate_acpi_type(union acpi_object *obj, const char *guid_string)
         |     ^~~~~~~~~~~~~~~~~~
--
>> drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c:218:5: warning: no previous prototype for 'run_sysman_call' [-Wmissing-prototypes]
     218 | int run_sysman_call(struct dell_wmi_sysman_buffer *buf)
         |     ^~~~~~~~~~~~~~~


vim +228 drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c

   217	
 > 218	int run_sysman_call(struct dell_wmi_sysman_buffer *buf)
   219	{
   220		struct dell_set_password *pass_set_data;
   221		struct dell_set_data *in_data;
   222		int ret = -ENOIOCTLCMD;
   223		char *tmp_system = NULL;
   224		char *tmp_admin = NULL;
   225	
   226		switch (buf->command) {
   227		case ENUMERATE_ALL:
 > 228			buf->count = get_attrs_size() / sizeof(struct dell_attributes_data);
   229			get_enumeration_data(buf);
   230			get_integer_data(buf);
   231			get_string_data(buf);
   232			ret = 0;
   233			break;
   234		case SET_ATTRIBUTES:
   235		case SET_DEFAULTS:
   236			if (!buf->count)
   237				goto out;
   238			in_data = (struct dell_set_data *)buf->data;
   239			tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
   240			strlcpy_attr(wmi_priv.current_admin_password, buf->admin_password);
   241			ret = set_attributes(in_data, buf->count, buf->command);
   242			strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
   243			kfree(tmp_admin);
   244			break;
   245		case GET_PASS:
   246			get_po_data(buf);
   247			ret = 0;
   248			break;
   249		case SET_PASS:
   250			pass_set_data = (struct dell_set_password *)buf->data;
   251			tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
   252			strlcpy_attr(wmi_priv.current_admin_password, buf->admin_password);
   253	
   254			if (strcmp(pass_set_data->attribute_name, "System") == 0) {
   255				tmp_system = kstrdup(wmi_priv.current_system_password, GFP_KERNEL);
   256				strlcpy_attr(wmi_priv.current_system_password,
   257						pass_set_data->system_password);
   258			}
   259	
   260			ret = set_new_password(pass_set_data->attribute_name, pass_set_data->new_password);
   261			strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
   262			kfree(tmp_admin);
   263	
   264			if (tmp_system != NULL) {
   265				strlcpy_attr(wmi_priv.current_system_password, tmp_system);
   266				kfree(tmp_system);
   267			}
   268			break;
   269		}
   270	out:
   271		return ret;
   272	}
   273	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 37943 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] IOCTL support for dell-wmi-sysman driver
  2021-02-09 14:28 [PATCH] IOCTL support for dell-wmi-sysman driver Prasanth, KSR
  2021-02-09 17:48   ` kernel test robot
@ 2021-02-09 17:57 ` Hans de Goede
  2021-03-15  4:19   ` Prasanth, KSR
  2021-02-09 22:34   ` kernel test robot
  2 siblings, 1 reply; 7+ messages in thread
From: Hans de Goede @ 2021-02-09 17:57 UTC (permalink / raw)
  To: Prasanth, KSR, dvhart
  Cc: LKML, platform-driver-x86, Prasanth KSR, Divya Bharathi,
	Mario Limonciello

Hi,

On 2/9/21 3:28 PM, Prasanth, KSR wrote:
> From: "Prasanth KSR" <prasanth.ksr@dell.com>
> 
> Perform BIOS Management calls on supported Dell machines
> through the Dell WMI System Management interface.
> 
> This interface provides IOCTL's to perform bundled
> BIOS Setting transactions.

Why?

Adding new userspace API is not something which we do without
a very good reason for it.

We spend a lot of time on reviewing the sysfs API for this, so
I must say that I'm quite surprised to now see an IOCTL API
being proposed on top of the existing sysfs API.

This is going to need a long explanation why this is necessary
over the existing sysfs API.

To be honest ATM I'm not inclined to accept this patch and
it is going to take some very strong arguments to change my
mind.

Regards,

Hans




> 
> Cc: Hans de Goede <hdegoede@redhat.com>
> 
> Signed-off-by: Prasanth KSR <prasanth.ksr@dell.com>
> Co-developed-by: Divya Bharathi <divya.bharathi@dell.com>
> Signed-off-by: Divya Bharathi <divya.bharathi@dell.com>
> Co-developed-by: Mario Limonciello <mario.limonciello@dell.com>
> Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
> ---
>  Documentation/ABI/testing/dell-wmi-sysman     |  39 ++
>  .../x86/dell-wmi-sysman/biosattr-interface.c  | 257 +++++++++--
>  .../x86/dell-wmi-sysman/dell-wmi-sysman.h     |  20 +-
>  .../x86/dell-wmi-sysman/enum-attributes.c     |  45 +-
>  .../x86/dell-wmi-sysman/int-attributes.c      |  46 +-
>  .../x86/dell-wmi-sysman/passobj-attributes.c  |  23 +
>  .../x86/dell-wmi-sysman/string-attributes.c   |  50 +-
>  drivers/platform/x86/dell-wmi-sysman/sysman.c |  48 +-
>  include/uapi/linux/wmi.h                      |  56 +++
>  tools/dell-wmi-sysman/Makefile                |  19 +
>  .../dell-wmi-sysman/dell-wmi-sysman-example.c | 432 ++++++++++++++++++
>  11 files changed, 946 insertions(+), 89 deletions(-)
>  create mode 100644 Documentation/ABI/testing/dell-wmi-sysman
>  create mode 100644 tools/dell-wmi-sysman/Makefile
>  create mode 100644 tools/dell-wmi-sysman/dell-wmi-sysman-example.c
> 
> diff --git a/Documentation/ABI/testing/dell-wmi-sysman b/Documentation/ABI/testing/dell-wmi-sysman
> new file mode 100644
> index 000000000000..4f3883529a06
> --- /dev/null
> +++ b/Documentation/ABI/testing/dell-wmi-sysman
> @@ -0,0 +1,39 @@
> +What:		/dev/wmi/dell-wmi-sysman
> +Date:		November 2021
> +KernelVersion:	5.15
> +Contact:	"Divya Bharathi" <divya.bharathi@dell.com>
> +		"Mario Limonciello" <mario.limonciello@dell.com>
> +		"Prasanth K S R" <prasanth.ksr@dell.com>
> +Description:
> +		Perform BIOS Management calls on supported Dell machines
> +		through the Dell WMI System Management interface.
> +
> +		This interface provides IOCTL's to perform bundled
> +		BIOS Setting transactions.
> +
> +		IOCTL's and buffer formats are defined in:
> +		<uapi/linux/wmi.h>
> +
> +		1) To perform a BIOS System Management call from userspace,
> +		you'll need to first determine the minimum size of the
> +		system management interface buffer for your machine.
> +		Platforms that contain larger buffers can return larger
> +		objects from the system firmware.
> +		Commonly this size is either 4k or 32k.
> +
> +		To determine the size of the buffer read() a u64 dword from
> +		the WMI character device /dev/wmi/dell-wmi-sysman.
> +
> +		2) After you've determined the minimum size of the system management
> +		interface buffer, you can allocate a structure that represents
> +		the structure documented above (struct dell_wmi_sysman_buffer).
> +
> +		3) In this buffer object, prepare as necessary for the BIOS System
> +		Management call you're interested in. Typically System Management
> +		buffers have "length", "command" , "count" and "admin_password"
> +		defined to values that coincide with the "data" you are interested in.
> +
> +		4) Run the call by using ioctl() as described in the header.
> +
> +		5) The output will be returned in the buffer object and
> +		make sure to free up the allocated buffer.
> diff --git a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
> index f95d8ddace5a..9a82e78fe59e 100644
> --- a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
> +++ b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
> @@ -6,12 +6,14 @@
>   *  Copyright (c) 2020 Dell Inc.
>   */
>  
> +#include <uapi/linux/wmi.h>
>  #include <linux/wmi.h>
>  #include "dell-wmi-sysman.h"
>  
>  #define SETDEFAULTVALUES_METHOD_ID					0x02
>  #define SETBIOSDEFAULTS_METHOD_ID					0x03
>  #define SETATTRIBUTE_METHOD_ID						0x04
> +#define SETATTRIBUTES_METHOD_ID						0x05
>  
>  static int call_biosattributes_interface(struct wmi_device *wdev, char *in_args, size_t size,
>  					int method_id)
> @@ -41,17 +43,17 @@ static int call_biosattributes_interface(struct wmi_device *wdev, char *in_args,
>  }
>  
>  /**
> - * set_attribute() - Update an attribute value
> - * @a_name: The attribute name
> - * @a_value: The attribute value
> + * set_bios_defaults() - Resets BIOS defaults
> + * @deftype: the type of BIOS value reset to issue.
>   *
> - * Sets an attribute to new value
> + * Resets BIOS defaults
>   */
> -int set_attribute(const char *a_name, const char *a_value)
> +int set_bios_defaults(u8 deftype)
>  {
>  	size_t security_area_size, buffer_size;
> -	size_t a_name_size, a_value_size;
> -	char *buffer = NULL, *start;
> +	size_t integer_area_size = sizeof(u8);
> +	char *buffer = NULL;
> +	u8 *defaultType;
>  	int ret;
>  
>  	mutex_lock(&wmi_priv.mutex);
> @@ -60,11 +62,8 @@ int set_attribute(const char *a_name, const char *a_value)
>  		goto out;
>  	}
>  
> -	/* build/calculate buffer */
>  	security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
> -	a_name_size = calculate_string_buffer(a_name);
> -	a_value_size = calculate_string_buffer(a_value);
> -	buffer_size = security_area_size + a_name_size + a_value_size;
> +	buffer_size = security_area_size + integer_area_size;
>  	buffer = kzalloc(buffer_size, GFP_KERNEL);
>  	if (!buffer) {
>  		ret = -ENOMEM;
> @@ -74,44 +73,51 @@ int set_attribute(const char *a_name, const char *a_value)
>  	/* build security area */
>  	populate_security_buffer(buffer, wmi_priv.current_admin_password);
>  
> -	/* build variables to set */
> -	start = buffer + security_area_size;
> -	ret = populate_string_buffer(start, a_name_size, a_name);
> -	if (ret < 0)
> -		goto out;
> -	start += ret;
> -	ret = populate_string_buffer(start, a_value_size, a_value);
> -	if (ret < 0)
> -		goto out;
> +	defaultType = buffer + security_area_size;
> +	*defaultType = deftype;
>  
> -	print_hex_dump_bytes("set attribute data: ", DUMP_PREFIX_NONE, buffer, buffer_size);
> -	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev,
> -					    buffer, buffer_size,
> -					    SETATTRIBUTE_METHOD_ID);
> -	if (ret == -EOPNOTSUPP)
> -		dev_err(&wmi_priv.bios_attr_wdev->dev, "admin password must be configured\n");
> -	else if (ret == -EACCES)
> -		dev_err(&wmi_priv.bios_attr_wdev->dev, "invalid password\n");
> +	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, buffer_size,
> +					    SETBIOSDEFAULTS_METHOD_ID);
> +	if (ret)
> +		dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults failed: %d\n", ret);
>  
> -out:
>  	kfree(buffer);
> +out:
>  	mutex_unlock(&wmi_priv.mutex);
>  	return ret;
>  }
>  
>  /**
> - * set_bios_defaults() - Resets BIOS defaults
> - * @deftype: the type of BIOS value reset to issue.
> + * calculate_array_length() - calculate total size of string array
> + * @str_arr: array of strings
> + * @str_count: string count
>   *
> - * Resets BIOS defaults
> - */
> -int set_bios_defaults(u8 deftype)
> + * Method to calculate the total size of array of string
> + **/
> +static int calculate_array_length(char **str_arr, int str_count)
>  {
> -	size_t security_area_size, buffer_size;
> -	size_t integer_area_size = sizeof(u8);
> -	char *buffer = NULL;
> -	u8 *defaultType;
> -	int ret;
> +	int ret = 0, i;
> +
> +	for (i = 0; i < str_count; ++i)
> +		ret += calculate_string_buffer(str_arr[i]);
> +	return ret;
> +}
> +
> +/**
> + * set_attributes() - Update multiple attribute values
> + * @in_data: input set data
> + * @a_count: Number of atributes to be set
> + * @command: command to decide set user input value or default
> + *
> + * Sets attributes to user input value of defaut value
> + **/
> +int set_attributes(struct dell_set_data *in_data, int a_count, unsigned short command)
> +{
> +	size_t security_area_size, string_area_size, buffer_size, attr_count_area;
> +	char **a_names, **a_values;
> +	char *buffer = NULL, *start;
> +	int ret, method_id, i;
> +	u32 *attr_count;
>  
>  	mutex_lock(&wmi_priv.mutex);
>  	if (!wmi_priv.bios_attr_wdev) {
> @@ -119,8 +125,34 @@ int set_bios_defaults(u8 deftype)
>  		goto out;
>  	}
>  
> +	//allocate memory to hold set inputs
> +	a_names = kmalloc(a_count * (sizeof(char *)), GFP_KERNEL);
> +	if (!a_names) {
> +		ret = -ENOMEM;
> +		goto out;
> +	}
> +	if (command == SET_ATTRIBUTES) {
> +		a_values = kmalloc(a_count * (sizeof(char *)), GFP_KERNEL);
> +		if (!a_values) {
> +			ret = -ENOMEM;
> +			goto out;
> +		}
> +	}
> +
> +	//assign inputs to single array and send to set functions
> +	for (i = 0; i < a_count; i++) {
> +		a_names[i] = in_data[i].attribute_name;
> +		if (command == SET_ATTRIBUTES)
> +			a_values[i] = in_data[i].attribute_value;
> +	}
> +
>  	security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
> -	buffer_size = security_area_size + integer_area_size;
> +	attr_count_area = sizeof(u32);
> +	string_area_size = (calculate_array_length(a_names, a_count));
> +	if (command == SET_ATTRIBUTES)
> +		string_area_size += (calculate_array_length(a_values, a_count));
> +	buffer_size = security_area_size + attr_count_area + string_area_size
> +					+ (sizeof(u16) * a_count);
>  	buffer = kzalloc(buffer_size, GFP_KERNEL);
>  	if (!buffer) {
>  		ret = -ENOMEM;
> @@ -130,26 +162,153 @@ int set_bios_defaults(u8 deftype)
>  	/* build security area */
>  	populate_security_buffer(buffer, wmi_priv.current_admin_password);
>  
> -	defaultType = buffer + security_area_size;
> -	*defaultType = deftype;
> +	/* build variables to set */
> +	attr_count = (u32 *)(buffer + security_area_size);
> +	*attr_count = (u32)a_count;
> +	start =  (u8 *)(attr_count) + attr_count_area;
>  
> -	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, buffer_size,
> -					    SETBIOSDEFAULTS_METHOD_ID);
> -	if (ret)
> -		dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults failed: %d\n", ret);
> +	for (i = 0; i < a_count; i++) {
> +		ret = populate_string_buffer(start, calculate_string_buffer(a_names[i]),
> +						a_names[i]);
> +		if (ret < 0)
> +			goto out;
> +		start += ret;
> +	}
> +
> +	if (command == SET_ATTRIBUTES) {
> +		for (i = 0; i < a_count; i++) {
> +			ret = populate_string_buffer(start, calculate_string_buffer(a_values[i]),
> +							a_values[i]);
> +			if (ret < 0)
> +				goto out;
> +			start += ret;
> +		}
> +		method_id = SETATTRIBUTES_METHOD_ID;
> +	} else {
> +		method_id = SETDEFAULTVALUES_METHOD_ID;
> +	}
> +
> +	print_hex_dump_bytes("set multiple attribute: ", DUMP_PREFIX_NONE, buffer, buffer_size);
> +	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev,
> +					    buffer, buffer_size, method_id);
> +
> +	if (ret == -EOPNOTSUPP)
> +		dev_err(&wmi_priv.password_attr_wdev->dev, "admin password must be configured\n");
> +	else if (ret == -EACCES)
> +		dev_err(&wmi_priv.password_attr_wdev->dev, "invalid password\n");
>  
> -	kfree(buffer);
>  out:
> +	kfree(buffer);
> +	kfree(a_names);
> +	if (command == SET_ATTRIBUTES)
> +		kfree(a_values);
>  	mutex_unlock(&wmi_priv.mutex);
>  	return ret;
>  }
>  
> +__u64 get_attrs_size(void)
> +{
> +	__u64 size = sizeof(struct dell_attributes_data) *
> +				(get_instance_count(DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID) +
> +				get_instance_count(DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID) +
> +				get_instance_count(DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID));
> +	return size;
> +}
> +
> +int run_sysman_call(struct dell_wmi_sysman_buffer *buf)
> +{
> +	struct dell_set_password *pass_set_data;
> +	struct dell_set_data *in_data;
> +	int ret = -ENOIOCTLCMD;
> +	char *tmp_system = NULL;
> +	char *tmp_admin = NULL;
> +
> +	switch (buf->command) {
> +	case ENUMERATE_ALL:
> +		buf->count = get_attrs_size() / sizeof(struct dell_attributes_data);
> +		get_enumeration_data(buf);
> +		get_integer_data(buf);
> +		get_string_data(buf);
> +		ret = 0;
> +		break;
> +	case SET_ATTRIBUTES:
> +	case SET_DEFAULTS:
> +		if (!buf->count)
> +			goto out;
> +		in_data = (struct dell_set_data *)buf->data;
> +		tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
> +		strlcpy_attr(wmi_priv.current_admin_password, buf->admin_password);
> +		ret = set_attributes(in_data, buf->count, buf->command);
> +		strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
> +		kfree(tmp_admin);
> +		break;
> +	case GET_PASS:
> +		get_po_data(buf);
> +		ret = 0;
> +		break;
> +	case SET_PASS:
> +		pass_set_data = (struct dell_set_password *)buf->data;
> +		tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
> +		strlcpy_attr(wmi_priv.current_admin_password, buf->admin_password);
> +
> +		if (strcmp(pass_set_data->attribute_name, "System") == 0) {
> +			tmp_system = kstrdup(wmi_priv.current_system_password, GFP_KERNEL);
> +			strlcpy_attr(wmi_priv.current_system_password,
> +					pass_set_data->system_password);
> +		}
> +
> +		ret = set_new_password(pass_set_data->attribute_name, pass_set_data->new_password);
> +		strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
> +		kfree(tmp_admin);
> +
> +		if (tmp_system != NULL) {
> +			strlcpy_attr(wmi_priv.current_system_password, tmp_system);
> +			kfree(tmp_system);
> +		}
> +		break;
> +	}
> +out:
> +	return ret;
> +}
> +
> +
> +static long bios_attr_set_interface_filter(struct wmi_device *wdev, unsigned int cmd,
> +				   struct wmi_ioctl_buffer *arg)
> +{
> +	struct dell_wmi_sysman_buffer *buf;
> +	struct dell_resetBIOS *reset_buf;
> +	char *tmp_admin = NULL;
> +	int ret = -ENOIOCTLCMD;
> +
> +	switch (cmd) {
> +	case DELL_WMI_SYSMAN_CMD:
> +		buf = (struct dell_wmi_sysman_buffer *) arg;
> +		ret = run_sysman_call(buf);
> +		break;
> +	case DELL_WMI_SYSMAN_RESET_BIOS:
> +		reset_buf = (struct dell_resetBIOS *) arg;
> +		if (reset_buf->option > 0) {
> +			tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
> +			strlcpy_attr(wmi_priv.current_admin_password, reset_buf->admin_password);
> +			ret = set_bios_defaults(reset_buf->option);
> +			strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
> +			kfree(tmp_admin);
> +		}
> +		break;
> +	}
> +	return ret;
> +}
> +
>  static int bios_attr_set_interface_probe(struct wmi_device *wdev, const void *context)
>  {
> +	__u32 req_buf_size;
>  	mutex_lock(&wmi_priv.mutex);
>  	wmi_priv.bios_attr_wdev = wdev;
>  	mutex_unlock(&wmi_priv.mutex);
> -	return 0;
> +	req_buf_size = get_attrs_size();
> +	/* add in size of struct dell_wmi_sysman_buffer which is used internally with ioctl */
> +	req_buf_size += sizeof(struct dell_wmi_sysman_buffer);
> +	return set_required_buffer_size(wdev, req_buf_size);
>  }
>  
>  static int bios_attr_set_interface_remove(struct wmi_device *wdev)
> @@ -171,6 +330,7 @@ static struct wmi_driver bios_attr_set_interface_driver = {
>  	.probe = bios_attr_set_interface_probe,
>  	.remove = bios_attr_set_interface_remove,
>  	.id_table = bios_attr_set_interface_id_table,
> +	.filter_callback = bios_attr_set_interface_filter
>  };
>  
>  int init_bios_attr_set_interface(void)
> @@ -184,3 +344,4 @@ void exit_bios_attr_set_interface(void)
>  }
>  
>  MODULE_DEVICE_TABLE(wmi, bios_attr_set_interface_id_table);
> +
> diff --git a/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h b/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
> index b80f2a62ea3f..13c216e6ddec 100644
> --- a/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
> +++ b/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
> @@ -8,6 +8,7 @@
>  #define _DELL_WMI_BIOS_ATTR_H_
>  
>  #include <linux/wmi.h>
> +#include <uapi/linux/wmi.h>
>  #include <linux/device.h>
>  #include <linux/module.h>
>  #include <linux/kernel.h>
> @@ -87,8 +88,6 @@ struct wmi_sysman_priv {
>  /* global structure used by multiple WMI interfaces */
>  extern struct wmi_sysman_priv wmi_priv;
>  
> -enum { ENUM, INT, STR, PO };
> -
>  enum {
>  	ATTR_NAME,
>  	DISPL_NAME_LANG_CODE,
> @@ -134,6 +133,7 @@ static ssize_t curr_val##_store(struct kobject *kobj,				\
>  				struct kobj_attribute *attr,			\
>  				const char *buf, size_t count)			\
>  {										\
> +	struct dell_set_data *set_data;						\
>  	char *p, *buf_cp;							\
>  	int i, ret = -EIO;							\
>  	buf_cp = kstrdup(buf, GFP_KERNEL);					\
> @@ -146,15 +146,19 @@ static ssize_t curr_val##_store(struct kobject *kobj,				\
>  	i = get_##type##_instance_id(kobj);					\
>  	if (i >= 0)								\
>  		ret = validate_##type##_input(i, buf_cp);			\
> +	set_data = kzalloc(sizeof(*set_data), GFP_KERNEL);			\
> +	strlcpy_attr(set_data[0].attribute_value, buf_cp);			\
> +	strlcpy_attr(set_data[0].attribute_name, kobj->name);			\
>  	if (!ret)								\
> -		ret = set_attribute(kobj->name, buf_cp);			\
> +		ret = set_attributes(set_data, 1, SET_ATTRIBUTES);		\
>  	kfree(buf_cp);								\
>  	return ret ? ret : count;						\
>  }
>  
>  union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string);
>  int get_instance_count(const char *guid_string);
> -void strlcpy_attr(char *dest, char *src);
> +int get_current_value(char *buf, int instance_id, const char *guid_string);
> +void strlcpy_attr(char *dest, const char *src);
>  
>  int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
>  			struct kobject *attr_name_kobj);
> @@ -174,7 +178,7 @@ int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject
>  int alloc_po_data(void);
>  void exit_po_attributes(void);
>  
> -int set_attribute(const char *a_name, const char *a_value);
> +int set_attributes(struct dell_set_data *in_data, int a_count, unsigned short command);
>  int set_bios_defaults(u8 defType);
>  
>  void exit_bios_attr_set_interface(void);
> @@ -188,4 +192,10 @@ int set_new_password(const char *password_type, const char *new);
>  int init_bios_attr_pass_interface(void);
>  void exit_bios_attr_pass_interface(void);
>  
> +__u64 get_attrs_size(void);
> +void get_enumeration_data(struct dell_wmi_sysman_buffer *buf);
> +void get_integer_data(struct dell_wmi_sysman_buffer *buf);
> +void get_string_data(struct dell_wmi_sysman_buffer *buf);
> +void get_po_data(struct dell_wmi_sysman_buffer *attr_data);
> +
>  #endif
> diff --git a/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
> index 80f4b7785c6c..b23e10ac00da 100644
> --- a/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
> +++ b/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
> @@ -13,22 +13,17 @@ get_instance_id(enumeration);
>  static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
>  {
>  	int instance_id = get_enumeration_instance_id(kobj);
> -	union acpi_object *obj;
> -	ssize_t ret;
> +	int ret;
>  
>  	if (instance_id < 0)
>  		return instance_id;
>  
> -	/* need to use specific instance_id and guid combination to get right data */
> -	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
> -	if (!obj)
> -		return -EIO;
> -	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) {
> -		kfree(obj);
> -		return -EINVAL;
> +	ret = get_current_value(buf, instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
> +	if (ret > 0) {
> +		strcat(buf, "\n");
> +		return strlen(buf);
>  	}
> -	ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
> -	kfree(obj);
> +	/* read error */
>  	return ret;
>  }
>  
> @@ -171,6 +166,34 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
>  	return sysfs_create_group(attr_name_kobj, &enumeration_attr_group);
>  }
>  
> +void get_enumeration_data(struct dell_wmi_sysman_buffer *buf)
> +{
> +	struct dell_attributes_data *attr_data;
> +	int i;
> +
> +	attr_data = (struct dell_attributes_data *)buf->data;
> +	for (i = 0; i < wmi_priv.enumeration_instances_count; i++) {
> +		attr_data[i].type = ENUM;
> +		strlcpy_attr(attr_data[i].attribute_name,
> +					wmi_priv.enumeration_data[i].attribute_name);
> +		strlcpy_attr(attr_data[i].display_name,
> +					wmi_priv.enumeration_data[i].display_name);
> +		strlcpy_attr(attr_data[i].display_name_language_code,
> +					wmi_priv.enumeration_data[i].display_name_language_code);
> +		strlcpy_attr(attr_data[i].possible_values,
> +					wmi_priv.enumeration_data[i].possible_values);
> +		strlcpy_attr(attr_data[i].dell_modifier,
> +					wmi_priv.enumeration_data[i].dell_modifier);
> +		strlcpy_attr(attr_data[i].dell_value_modifier,
> +					wmi_priv.enumeration_data[i].dell_value_modifier);
> +		strlcpy_attr(attr_data[i].default_value,
> +					wmi_priv.enumeration_data[i].default_value);
> +		get_current_value(attr_data[i].current_value, i,
> +					DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
> +
> +	}
> +}
> +
>  /**
>   * exit_enum_attributes() - Clear all attribute data
>   *
> diff --git a/drivers/platform/x86/dell-wmi-sysman/int-attributes.c b/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
> index 75aedbb733be..0155f6189576 100644
> --- a/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
> +++ b/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
> @@ -15,22 +15,17 @@ get_instance_id(integer);
>  static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
>  {
>  	int instance_id = get_integer_instance_id(kobj);
> -	union acpi_object *obj;
> -	ssize_t ret;
> +	int ret;
>  
>  	if (instance_id < 0)
>  		return instance_id;
>  
> -	/* need to use specific instance_id and guid combination to get right data */
> -	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
> -	if (!obj)
> -		return -EIO;
> -	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_INTEGER) {
> -		kfree(obj);
> -		return -EINVAL;
> +	ret = get_current_value(buf, instance_id, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
> +	if (ret > 0) {
> +		strcat(buf, "\n");
> +		return strlen(buf);
>  	}
> -	ret = snprintf(buf, PAGE_SIZE, "%lld\n", obj->package.elements[CURRENT_VAL].integer.value);
> -	kfree(obj);
> +	/* read error */
>  	return ret;
>  }
>  
> @@ -161,6 +156,35 @@ int populate_int_data(union acpi_object *integer_obj, int instance_id,
>  	return sysfs_create_group(attr_name_kobj, &integer_attr_group);
>  }
>  
> +void get_integer_data(struct dell_wmi_sysman_buffer *buf)
> +{
> +	struct dell_attributes_data *attr_data;
> +	int i;
> +	//To populate in same dell_attributes_data, increment after enum data
> +	int a_count = wmi_priv.enumeration_instances_count;
> +
> +	attr_data = (struct dell_attributes_data *)buf->data;
> +	for (i = 0; i < wmi_priv.integer_instances_count; i++) {
> +		attr_data[a_count].type = INT;
> +		strlcpy_attr(attr_data[a_count].attribute_name,
> +					wmi_priv.integer_data[i].attribute_name);
> +		strlcpy_attr(attr_data[a_count].display_name,
> +					wmi_priv.integer_data[i].display_name);
> +		strlcpy_attr(attr_data[a_count].display_name_language_code,
> +					wmi_priv.integer_data[i].display_name_language_code);
> +		strlcpy_attr(attr_data[a_count].dell_modifier,
> +					wmi_priv.integer_data[i].dell_modifier);
> +		attr_data[a_count].min = wmi_priv.integer_data[i].min_value;
> +		attr_data[a_count].max = wmi_priv.integer_data[i].max_value;
> +		attr_data[a_count].scalar_increment = wmi_priv.integer_data[i].scalar_increment;
> +		snprintf(attr_data[a_count].default_value, PAGE_SIZE, "%d",
> +				wmi_priv.integer_data[i].default_value);
> +		get_current_value(attr_data[a_count].current_value, i,
> +				DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
> +		a_count++;
> +	}
> +}
> +
>  /**
>   * exit_int_attributes() - Clear all attribute data
>   *
> diff --git a/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c b/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
> index 3abcd95477c0..9f50989a9f44 100644
> --- a/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
> +++ b/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
> @@ -169,6 +169,29 @@ int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject
>  	return sysfs_create_group(attr_name_kobj, &po_attr_group);
>  }
>  
> +void get_po_data(struct dell_wmi_sysman_buffer *in_data)
> +{
> +	int i;
> +	struct dell_password_data *attr_data;
> +
> +	in_data->count = wmi_priv.po_instances_count;
> +	attr_data = (struct dell_password_data *)in_data->data;
> +	for (i = 0; i < wmi_priv.po_instances_count; i++) {
> +		union acpi_object *obj;
> +
> +		strlcpy_attr(attr_data[i].attribute_name,
> +						wmi_priv.po_data[i].attribute_name);
> +		attr_data[i].min_length = wmi_priv.po_data[i].min_password_length;
> +		attr_data[i].max_length = wmi_priv.po_data[i].max_password_length;
> +
> +		obj = get_wmiobj_pointer(i, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
> +		if (!obj)
> +			continue;
> +		attr_data[i].is_set = obj->package.elements[IS_PASS_SET].integer.value;
> +		kfree(obj);
> +	}
> +}
> +
>  /**
>   * exit_po_attributes() - Clear all attribute data
>   *
> diff --git a/drivers/platform/x86/dell-wmi-sysman/string-attributes.c b/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
> index ac75dce88a4c..a3847e4a6bf8 100644
> --- a/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
> +++ b/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
> @@ -15,22 +15,17 @@ get_instance_id(str);
>  static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
>  {
>  	int instance_id = get_str_instance_id(kobj);
> -	union acpi_object *obj;
> -	ssize_t ret;
> +	int ret;
>  
>  	if (instance_id < 0)
> -		return -EIO;
> -
> -	/* need to use specific instance_id and guid combination to get right data */
> -	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
> -	if (!obj)
> -		return -EIO;
> -	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) {
> -		kfree(obj);
> -		return -EINVAL;
> +		return instance_id;
> +
> +	ret = get_current_value(buf, instance_id, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
> +	if (ret > 0) {
> +		strcat(buf, "\n");
> +		return strlen(buf);
>  	}
> -	ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
> -	kfree(obj);
> +	/* read error */
>  	return ret;
>  }
>  
> @@ -141,6 +136,35 @@ int populate_str_data(union acpi_object *str_obj, int instance_id, struct kobjec
>  	return sysfs_create_group(attr_name_kobj, &str_attr_group);
>  }
>  
> +void get_string_data(struct dell_wmi_sysman_buffer *buf)
> +{
> +	struct dell_attributes_data *attr_data;
> +	int i;
> +	//To populate in same dell_attributes_data, increment after enum+int data
> +	int a_count = wmi_priv.enumeration_instances_count +
> +					wmi_priv.integer_instances_count;
> +	attr_data = (struct dell_attributes_data *)buf->data;
> +
> +	for (i = 0; i < wmi_priv.str_instances_count; i++) {
> +		attr_data[a_count].type = STR;
> +		strlcpy_attr(attr_data[a_count].attribute_name,
> +						wmi_priv.str_data[i].attribute_name);
> +		strlcpy_attr(attr_data[a_count].display_name,
> +						wmi_priv.str_data[i].display_name);
> +		strlcpy_attr(attr_data[a_count].display_name_language_code,
> +						wmi_priv.str_data[i].display_name_language_code);
> +		strlcpy_attr(attr_data[a_count].dell_modifier,
> +						wmi_priv.str_data[i].dell_modifier);
> +		attr_data[a_count].min = wmi_priv.str_data[i].min_length;
> +		attr_data[a_count].max = wmi_priv.str_data[i].max_length;
> +		strlcpy_attr(attr_data[a_count].default_value,
> +						wmi_priv.str_data[i].default_value);
> +		get_current_value(attr_data[a_count].current_value, i,
> +				DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
> +		a_count++;
> +	}
> +}
> +
>  /**
>   * exit_str_attributes() - Clear all attribute data
>   *
> diff --git a/drivers/platform/x86/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell-wmi-sysman/sysman.c
> index cb81010ba1a2..0b77a6a0b8a8 100644
> --- a/drivers/platform/x86/dell-wmi-sysman/sysman.c
> +++ b/drivers/platform/x86/dell-wmi-sysman/sysman.c
> @@ -275,7 +275,7 @@ static struct kobj_type attr_name_ktype = {
>   * @dest: Where to copy the string to
>   * @src: Where to copy the string from
>   */
> -void strlcpy_attr(char *dest, char *src)
> +void strlcpy_attr(char *dest, const char *src)
>  {
>  	size_t len = strlen(src) + 1;
>  
> @@ -307,6 +307,52 @@ union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string)
>  	return ACPI_SUCCESS(status) ? (union acpi_object *)out.pointer : NULL;
>  }
>  
> +int validate_acpi_type(union acpi_object *obj, const char *guid_string)
> +{
> +	u32 acpi_type;
> +
> +	if (strcmp(guid_string, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID) == 0)
> +		acpi_type = ACPI_TYPE_INTEGER;
> +	else
> +		acpi_type = ACPI_TYPE_STRING;
> +
> +	if (obj->package.elements[CURRENT_VAL].type != acpi_type)
> +		return -EIO;
> +
> +	return 0;
> +}
> +
> +/**
> + * get_curret_value() - Get current_value of an attribute
> + * @instance_id: WMI instance ID
> + * @guid_string: WMI GUID (in string form)
> + */
> +int get_current_value(char *buf, int instance_id, const char *guid_string)
> +{
> +	union acpi_object *obj;
> +	int ret;
> +
> +	/* need to use specific instance_id and guid combination to get right data */
> +	obj = get_wmiobj_pointer(instance_id, guid_string);
> +	if (!obj)
> +		return -EIO;
> +
> +	ret = validate_acpi_type(obj, guid_string);
> +	if (ret)
> +		goto out;
> +
> +	if (strcmp(guid_string, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID) == 0)
> +		ret = snprintf(buf, PAGE_SIZE, "%lld",
> +				obj->package.elements[CURRENT_VAL].integer.value);
> +	else
> +		ret = snprintf(buf, PAGE_SIZE, "%s",
> +				obj->package.elements[CURRENT_VAL].string.pointer);
> +
> +out:
> +	kfree(obj);
> +	return ret;
> +}
> +
>  /**
>   * get_instance_count() - Compute total number of instances under guid_string
>   * @guid_string: WMI GUID (in string form)
> diff --git a/include/uapi/linux/wmi.h b/include/uapi/linux/wmi.h
> index 7085c5dca9fa..f160d1eef7cb 100644
> --- a/include/uapi/linux/wmi.h
> +++ b/include/uapi/linux/wmi.h
> @@ -13,6 +13,11 @@
>  /* WMI bus will filter all WMI vendor driver requests through this IOC */
>  #define WMI_IOC 'W'
>  
> +enum BIOS_ATTRIBUTE_TYPE { ENUM, INT, STR, PO };
> +enum IOCTL_COMMAND { ENUMERATE_ALL = 1, SET_ATTRIBUTES, SET_DEFAULTS, GET_PASS, SET_PASS };
> +
> +#define MAX_BUFF  512
> +
>  /* All ioctl requests through WMI should declare their size followed by
>   * relevant data objects
>   */
> @@ -43,6 +48,53 @@ struct dell_wmi_smbios_buffer {
>  	struct dell_wmi_extensions	ext;
>  } __packed;
>  
> +struct dell_wmi_sysman_buffer {
> +	__u64 length;
> +	__u32 count;
> +	__u16 command;
> +	char admin_password[MAX_BUFF];
> +	__u8 data[];
> +} __packed;
> +
> +struct dell_attributes_data {
> +	char display_name_language_code[MAX_BUFF];
> +	char dell_value_modifier[MAX_BUFF];
> +	char possible_values[MAX_BUFF];
> +	char attribute_name[MAX_BUFF];
> +	char current_value[MAX_BUFF];
> +	char default_value[MAX_BUFF];
> +	char dell_modifier[MAX_BUFF];
> +	char display_name[MAX_BUFF];
> +	int scalar_increment;
> +	int type;
> +	int min;
> +	int max;
> +} __packed;
> +
> +struct dell_set_data {
> +	char attribute_name[MAX_BUFF];
> +	char attribute_value[MAX_BUFF];
> +} __packed;
> +
> +struct dell_set_password {
> +	char attribute_name[MAX_BUFF];
> +	char system_password[MAX_BUFF];
> +	char new_password[MAX_BUFF];
> +} __packed;
> +
> +struct dell_password_data {
> +	char attribute_name[MAX_BUFF];
> +	__u8 is_set;
> +	int min_length;
> +	int max_length;
> +} __packed;
> +
> +struct dell_resetBIOS {
> +	__u64 length;
> +	__u8 option;
> +	char admin_password[MAX_BUFF];
> +} __packed;
> +
>  /* Whitelisted smbios class/select commands */
>  #define CLASS_TOKEN_READ	0
>  #define CLASS_TOKEN_WRITE	1
> @@ -67,4 +119,8 @@ struct dell_wmi_smbios_buffer {
>  /* Dell SMBIOS calling IOCTL command used by dell-smbios-wmi */
>  #define DELL_WMI_SMBIOS_CMD	_IOWR(WMI_IOC, 0, struct dell_wmi_smbios_buffer)
>  
> +/* Dell WMI System Management calling IOCTL commands used by dell-wmi-sysman */
> +#define DELL_WMI_SYSMAN_CMD _IOWR(WMI_IOC, 0, struct dell_wmi_sysman_buffer)
> +#define DELL_WMI_SYSMAN_RESET_BIOS _IOW(WMI_IOC, 0, struct dell_resetBIOS)
> +
>  #endif
> diff --git a/tools/dell-wmi-sysman/Makefile b/tools/dell-wmi-sysman/Makefile
> new file mode 100644
> index 000000000000..0a01a82a0745
> --- /dev/null
> +++ b/tools/dell-wmi-sysman/Makefile
> @@ -0,0 +1,19 @@
> +# SPDX-License-Identifier: GPL-2.0-only
> +PREFIX ?= /usr
> +SBINDIR ?= sbin
> +INSTALL ?= install
> +CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include -I./
> +
> +TARGET = dell-wmi-sysman-example
> +
> +all: $(TARGET)
> +
> +%: %.c
> +	$(CC) $(CFLAGS) $(LDFLAGS) -g -o $@ $<
> +
> +clean:
> +	$(RM) $(TARGET)
> +
> +install: dell-wmi-sysman-example
> +	$(INSTALL) -D -m 755 $(TARGET) $(DESTDIR)$(PREFIX)/$(SBINDIR)/$(TARGET)
> +
> diff --git a/tools/dell-wmi-sysman/dell-wmi-sysman-example.c b/tools/dell-wmi-sysman/dell-wmi-sysman-example.c
> new file mode 100644
> index 000000000000..50db8835cea6
> --- /dev/null
> +++ b/tools/dell-wmi-sysman/dell-wmi-sysman-example.c
> @@ -0,0 +1,432 @@
> +// SPDX-License-Identifier: GPL-2.0-only
> +/*
> + *  Sample application for system management over WMI interface
> + *  Performs the following:
> + *  - Enemeration of all BIOS attributes present in system
> + *  - Set BIOS atributes to user input or default
> + *	- Reset BIOS
> + *
> + *  Copyright (C) 2021 Dell, Inc.
> + *
> + *  This program is free software; you can redistribute it and/or modify
> + *  it under the terms of the GNU General Public License version 2 as
> + *  published by the Free Software Foundation.
> + */
> +
> +#include <errno.h>
> +#include <fcntl.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <sys/ioctl.h>
> +#include <unistd.h>
> +#include <string.h>
> +#include <ctype.h>
> +
> +/* if uapi header isn't installed, this might not yet exist */
> +#ifndef __packed
> +#define __packed __attribute__((packed))
> +#endif
> +#include <linux/wmi.h>
> +
> +enum USER_OPTS {GET_ATTRS = 1, SET_ATTRS, SET_DEFS, PASS_MAN, RESET, EXIT };
> +enum PASS_OPTS {GET_PASSINFO = 1, SET_OR_CHANGE_PASS, CLEAR_PASS, BACK };
> +
> +static const char *ioctl_devfs = "/dev/wmi/dell-wmi-sysman";
> +__u64 buff_size;
> +
> +static int query_buffer_size(__u64 *buffer_size)
> +{
> +	FILE *f = fopen(ioctl_devfs, "rb");
> +
> +	if (!f)
> +		return -EINVAL;
> +	fread(buffer_size, sizeof(__u64), 1, f);
> +	fclose(f);
> +	return EXIT_SUCCESS;
> +}
> +
> +int read_integer_input(void)
> +{
> +	int val, in, c;
> +	char follow;
> +
> +	while (1) {
> +		in = scanf("%d%c", &val, &follow);
> +		if (in == 2) {
> +			if (isspace(follow))
> +				return val;
> +			printf("Invalid input! Try again...\nEnter - ");
> +		} else if (in == 1) {
> +			return val;
> +		printf("Invalid input! Try again...\nEnter - ");
> +		}
> +
> +		while ((c = getchar()) != '\n' && c != EOF)
> +			;
> +	}
> +}
> +
> +static int call_ioctl(struct dell_wmi_sysman_buffer *buffer)
> +{
> +	int fd;
> +	int ret;
> +
> +	fd = open(ioctl_devfs, O_NONBLOCK);
> +	ret = ioctl(fd, DELL_WMI_SYSMAN_CMD, buffer);
> +	close(fd);
> +	return ret;
> +}
> +
> +int is_password_set(unsigned char *password_type)
> +{
> +	int ret, i;
> +	int is_set = 0;
> +	struct dell_wmi_sysman_buffer *buff_pwd;
> +	struct dell_password_data *indata;
> +
> +	buff_pwd = malloc(buff_size); //buff_size large enough to get password data
> +	if (buff_pwd == NULL) {
> +		printf("failed to alloc memory for ioctl\n");
> +		return -ENOMEM;
> +	}
> +
> +	buff_pwd->length = buff_size;
> +	buff_pwd->command = GET_PASS;
> +	call_ioctl(buff_pwd);
> +
> +	indata = (struct dell_password_data *)buff_pwd->data;
> +
> +	for (i = 0; i < buff_pwd->count; i++) {
> +		if (strcmp(indata[i].attribute_name, password_type) == 0) {
> +			is_set = indata[i].is_set;
> +			break;
> +		}
> +	}
> +
> +	free(buff_pwd);
> +	return is_set;
> +}
> +
> +/* Enumerate functions start*/
> +void display_attributes(struct dell_wmi_sysman_buffer *buff_all)
> +{
> +	struct dell_attributes_data *testdata;
> +	int i;
> +
> +	testdata = (struct dell_attributes_data *)buff_all->data;
> +	for (i = 0; i < buff_all->count; i++) {
> +		printf("\n%d\n", (i + 1));
> +		printf("AttributeName = %s\n", testdata[i].attribute_name);
> +		printf("Display LangCode = %s\n", testdata[i].display_name_language_code);
> +		printf("Display Name = %s\n", testdata[i].display_name);
> +		printf("Modifier = %s\n", testdata[i].dell_modifier);
> +		printf("Current Value = %s\n", testdata[i].current_value);
> +		printf("Default Value = %s\n", testdata[i].default_value);
> +		if (testdata[i].type == ENUM) {
> +			printf("Value Modifier = %s\n", testdata[i].dell_value_modifier);
> +			printf("PossibleValues = %s\n", testdata[i].possible_values);
> +		}
> +		if (testdata[i].type == INT) {
> +			printf("Lower Bound = %d\n", testdata[i].min);
> +			printf("Upper Bound = %d\n", testdata[i].max);
> +			printf("Scalar incr = %d\n", testdata[i].scalar_increment);
> +		}
> +		if (testdata[i].type == STR) {
> +			printf("Minimum Length = %d\n", testdata[i].min);
> +			printf("Maximum Length = %d\n", testdata[i].max);
> +		}
> +	}
> +	printf("---------------------------------------------------------\n");
> +}
> +
> +void enumerate_all_attributes(void)
> +{
> +	struct dell_wmi_sysman_buffer *buff_all;
> +	int ret;
> +
> +	buff_all = malloc(buff_size);
> +	if (buff_all == NULL) {
> +		printf("failed to alloc memory for ioctl\n");
> +		return;
> +	}
> +	buff_all->length = buff_size;
> +	buff_all->command = ENUMERATE_ALL;
> +	ret = call_ioctl(buff_all);
> +	if (ret) {
> +		printf("smbios ioctl failed: %d\n", ret);
> +		goto out;
> +	}
> +	display_attributes(buff_all);
> +out:
> +	if (buff_all != NULL)
> +		free(buff_all);
> +}
> +/* Enumerate functions end*/
> +
> +/* SET functions start */
> +int read_set_data(struct dell_wmi_sysman_buffer *buff_set, int option)
> +{
> +	int i, admin_pwd_set;
> +	struct dell_set_data *indata;
> +
> +	admin_pwd_set = is_password_set("Admin");
> +	if (admin_pwd_set < 0) {
> +		printf("check password call failed!!!\n");
> +		return EXIT_FAILURE;
> +	}
> +
> +	printf("How many attributes to set: ");
> +	scanf("%d", &buff_set->count);
> +
> +	indata = (struct dell_set_data *)buff_set->data;
> +
> +	if (admin_pwd_set) {
> +		printf("Admin password is set, please enter password - ");
> +		scanf("%s", buff_set->admin_password);
> +	}
> +
> +	for (i = 0; i < buff_set->count; i++) {
> +		printf("Enter Attribute Name: ");
> +		scanf("%s", indata[i].attribute_name);
> +
> +		if (option == SET_ATTRIBUTES) {
> +			printf("Enter Attribute Value: ");
> +			scanf("%s", indata[i].attribute_value);
> +		}
> +	}
> +	return 0;
> +}
> +
> +void call_set_cmd(int cmd_opt)
> +{
> +	int i, ret;
> +	struct dell_wmi_sysman_buffer *buff_set;
> +
> +	buff_set = malloc(buff_size);
> +	if (buff_set == NULL) {
> +		printf("failed to alloc memory for ioctl\n");
> +		return;
> +	}
> +	buff_set->length = buff_size;
> +	buff_set->command = cmd_opt;
> +	if (read_set_data(buff_set, cmd_opt))
> +		goto out;
> +
> +	ret = call_ioctl(buff_set);
> +	if (!ret) {
> +		printf("Set Successful...\n");
> +		goto out;
> +	}
> +	printf("Set failed: %d\n", ret);
> +out:
> +	free(buff_set);
> +}
> +/* SET functions end */
> +
> +/* Password related functions start */
> +void get_password_info(void)
> +{
> +	int i;
> +	struct dell_wmi_sysman_buffer *buff_pwd;
> +	struct dell_password_data *testdata;
> +
> +	buff_pwd = malloc(buff_size); //buff_size large enough to get password data
> +	if (buff_pwd == NULL) {
> +		printf("failed to alloc memory for ioctl\n");
> +		return;
> +	}
> +	buff_pwd->length = buff_size;
> +	buff_pwd->command = GET_PASS;
> +	if (call_ioctl(buff_pwd)) {
> +		free(buff_pwd);
> +		printf("smbios ioctl failed!!!\n");
> +		return;
> +	}
> +
> +	testdata = (struct dell_password_data *)buff_pwd->data;
> +	for (i = 0; i < buff_pwd->count; i++) {
> +		printf("\n%d\n", (i + 1));
> +		printf("AttributeName = %s\n", testdata[i].attribute_name);
> +		printf("Minimum Length = %d\n", testdata[i].min_length);
> +		printf("Maximum Length = %d\n", testdata[i].max_length);
> +		printf("Is Password Set = %d\n", testdata[i].is_set);
> +	}
> +	if (buff_pwd != NULL)
> +		free(buff_pwd);
> +}
> +
> +void call_set_pasword_cmd(int clear_opt)
> +{
> +	int ret, is_admin_pwd_set, is_system_pwd_set;
> +	struct dell_wmi_sysman_buffer *buff_pwd;
> +	struct dell_set_password *indata;
> +
> +	buff_pwd = malloc(buff_size); //buff_size large enough to get password data
> +	if (buff_pwd == NULL) {
> +		printf("failed to alloc memory for ioctl\n");
> +		return;
> +	}
> +	buff_pwd->length = buff_size;
> +	buff_pwd->command = SET_PASS;
> +	is_admin_pwd_set = is_password_set("Admin");
> +	is_system_pwd_set = is_password_set("System");
> +	if ((is_admin_pwd_set < 0) || (is_system_pwd_set < 0)) {
> +		printf("check password call failed!!!\n");
> +		goto out;
> +	}
> +
> +	indata = (struct dell_set_password *)buff_pwd->data;
> +
> +	if (is_admin_pwd_set) {
> +		printf("Admin password is set, please enter current admin password - ");
> +		scanf("%s", buff_pwd->admin_password);
> +	}
> +
> +	printf("Enter which password to set Admin/System - ");
> +	scanf("%s", indata->attribute_name);
> +
> +	if (strcmp(indata->attribute_name, "System") == 0 && (is_system_pwd_set)) {
> +		printf("System password is set, please enter current system password - ");
> +		scanf("%s", indata->system_password);
> +	}
> +
> +	if (clear_opt == 3) {
> +		strcpy(indata->new_password, "");
> +	} else {
> +		printf("Enter new password - ");
> +		scanf("%s", indata->new_password);
> +	}
> +	ret = call_ioctl(buff_pwd);
> +	if (!ret) {
> +		printf("Set Successful...\n");
> +		ret = EXIT_SUCCESS;
> +		goto out;
> +	}
> +	printf("Set failed: %d\n", ret);
> +out:
> +	free(buff_pwd);
> +}
> +
> +void call_password_management(void)
> +{
> +	int opt, ret;
> +
> +	while (1) {
> +		printf("\n##############################\n");
> +		printf(" Password Management Menu\t\n");
> +		printf("##############################\n");
> +		printf("\n1 - Get Password Information\n"
> +				"2 - Set/Change Password\n"
> +				"3 - Clear Password\n"
> +				"4 - Go to back to Main Menu\n\n"
> +				"Enter - ");
> +		opt = read_integer_input();
> +
> +		switch (opt) {
> +		case GET_PASSINFO:
> +			get_password_info();
> +			break;
> +		case SET_OR_CHANGE_PASS:
> +		case CLEAR_PASS:
> +			call_set_pasword_cmd(opt);
> +			break;
> +		case BACK:
> +			return;
> +		default:
> +			printf("Invalid option!\n");
> +			break;
> +		}
> +	}
> +}
> +/* Password related functions end */
> +
> +void call_reset_bios(void)
> +{
> +	struct dell_resetBIOS *buff_reset;
> +	unsigned char reset_option;
> +	int fd, ret, is_admin_pwd_set;
> +
> +	printf("\nReset Options:\n"
> +			"0 - Built-in Safe Defaults\n"
> +			"1 - Last Known Good\n"
> +			"2 - Factory\n"
> +			"3 - Custom\n\n"
> +			"Enter - ");
> +	scanf("%hhu", &reset_option);
> +	buff_reset = malloc(buff_size);
> +	if (buff_reset == NULL) {
> +		printf("failed to alloc memory for ioctl\n");
> +		return;
> +	}
> +	is_admin_pwd_set = is_password_set("Admin");
> +	if ((is_admin_pwd_set < 0)) {
> +		printf("check password call failed!!!\n");
> +		goto out;
> +	}
> +
> +	buff_reset->length = buff_size;
> +	if (is_admin_pwd_set) {
> +		printf("Admin password is set, please enter current admin password - ");
> +		scanf("%s", buff_reset->admin_password);
> +	}
> +	fd = open(ioctl_devfs, O_NONBLOCK);
> +	ret = ioctl(fd, DELL_WMI_SYSMAN_RESET_BIOS, buff_reset);
> +	close(fd);
> +	if (!ret) {
> +		printf("Reset Successful. Reboot the system\n");
> +		ret = EXIT_SUCCESS;
> +		goto out;
> +	}
> +	printf("Reset Failed: %d\n", ret);
> +out:
> +	if (buff_reset != NULL)
> +		free(buff_reset);
> +}
> +
> +int main(void)
> +{
> +	int ret, opt;
> +	__u64 value = 0;
> +
> +	ret = query_buffer_size(&value);
> +	if (ret == EXIT_FAILURE || !value) {
> +		printf("Unable to read buffer size\n");
> +		return ret;
> +	}
> +	buff_size = value;
> +	while (1) {
> +		printf("\n\n\n##############################\n");
> +		printf("Dell BIOS System Management Utility\n");
> +		printf("##############################\n");
> +		printf("\n1 - Enumerate All Attributes\n"
> +				"2 - Set Attributes\n"
> +				"3 - Set To Defaults\n"
> +				"4 - Password Management\n"
> +				"5 - Reset BIOS\n"
> +				"6 - Exit\n"
> +				"\n\nEnter - ");
> +		opt = read_integer_input();
> +
> +		switch (opt) {
> +		case GET_ATTRS:
> +			enumerate_all_attributes();
> +			break;
> +		case SET_ATTRS:
> +		case SET_DEFS:
> +			call_set_cmd(opt);
> +			break;
> +		case PASS_MAN:
> +			call_password_management();
> +			break;
> +		case RESET:
> +			call_reset_bios();
> +			break;
> +		case EXIT:
> +			exit(0);
> +			break;
> +		default:
> +			break;
> +		}
> +	}
> +	return 0;
> +}
> 


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] IOCTL support for dell-wmi-sysman driver
  2021-02-09 14:28 [PATCH] IOCTL support for dell-wmi-sysman driver Prasanth, KSR
@ 2021-02-09 22:34   ` kernel test robot
  2021-02-09 17:57 ` Hans de Goede
  2021-02-09 22:34   ` kernel test robot
  2 siblings, 0 replies; 7+ messages in thread
From: kernel test robot @ 2021-02-09 22:34 UTC (permalink / raw)
  To: Prasanth, KSR, Hans de Goede, dvhart
  Cc: kbuild-all, clang-built-linux, LKML, platform-driver-x86,
	Prasanth KSR, Divya Bharathi, Mario Limonciello

[-- Attachment #1: Type: text/plain, Size: 3279 bytes --]

Hi KSR",

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.11-rc7 next-20210125]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Prasanth-KSR/IOCTL-support-for-dell-wmi-sysman-driver/20210209-223343
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 61556703b610a104de324e4f061dc6cf7b218b46
config: x86_64-randconfig-a015-20210209 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project c9439ca36342fb6013187d0a69aef92736951476)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install x86_64 cross compiling tool for clang build
        # apt-get install binutils-x86-64-linux-gnu
        # https://github.com/0day-ci/linux/commit/00141bcb2495c75a902d3070e149760b1050322e
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Prasanth-KSR/IOCTL-support-for-dell-wmi-sysman-driver/20210209-223343
        git checkout 00141bcb2495c75a902d3070e149760b1050322e
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/platform/x86/dell-wmi-sysman/sysman.c:310:5: warning: no previous prototype for function 'validate_acpi_type' [-Wmissing-prototypes]
   int validate_acpi_type(union acpi_object *obj, const char *guid_string)
       ^
   drivers/platform/x86/dell-wmi-sysman/sysman.c:310:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int validate_acpi_type(union acpi_object *obj, const char *guid_string)
   ^
   static 
   1 warning generated.
--
>> drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c:218:5: warning: no previous prototype for function 'run_sysman_call' [-Wmissing-prototypes]
   int run_sysman_call(struct dell_wmi_sysman_buffer *buf)
       ^
   drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c:218:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int run_sysman_call(struct dell_wmi_sysman_buffer *buf)
   ^
   static 
   1 warning generated.


vim +/validate_acpi_type +310 drivers/platform/x86/dell-wmi-sysman/sysman.c

   309	
 > 310	int validate_acpi_type(union acpi_object *obj, const char *guid_string)
   311	{
   312		u32 acpi_type;
   313	
   314		if (strcmp(guid_string, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID) == 0)
   315			acpi_type = ACPI_TYPE_INTEGER;
   316		else
   317			acpi_type = ACPI_TYPE_STRING;
   318	
   319		if (obj->package.elements[CURRENT_VAL].type != acpi_type)
   320			return -EIO;
   321	
   322		return 0;
   323	}
   324	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org

[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 41107 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] IOCTL support for dell-wmi-sysman driver
@ 2021-02-09 22:34   ` kernel test robot
  0 siblings, 0 replies; 7+ messages in thread
From: kernel test robot @ 2021-02-09 22:34 UTC (permalink / raw)
  To: kbuild-all

[-- Attachment #1: Type: text/plain, Size: 3353 bytes --]

Hi KSR",

Thank you for the patch! Perhaps something to improve:

[auto build test WARNING on linus/master]
[also build test WARNING on v5.11-rc7 next-20210125]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url:    https://github.com/0day-ci/linux/commits/Prasanth-KSR/IOCTL-support-for-dell-wmi-sysman-driver/20210209-223343
base:   https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git 61556703b610a104de324e4f061dc6cf7b218b46
config: x86_64-randconfig-a015-20210209 (attached as .config)
compiler: clang version 12.0.0 (https://github.com/llvm/llvm-project c9439ca36342fb6013187d0a69aef92736951476)
reproduce (this is a W=1 build):
        wget https://raw.githubusercontent.com/intel/lkp-tests/master/sbin/make.cross -O ~/bin/make.cross
        chmod +x ~/bin/make.cross
        # install x86_64 cross compiling tool for clang build
        # apt-get install binutils-x86-64-linux-gnu
        # https://github.com/0day-ci/linux/commit/00141bcb2495c75a902d3070e149760b1050322e
        git remote add linux-review https://github.com/0day-ci/linux
        git fetch --no-tags linux-review Prasanth-KSR/IOCTL-support-for-dell-wmi-sysman-driver/20210209-223343
        git checkout 00141bcb2495c75a902d3070e149760b1050322e
        # save the attached .config to linux build tree
        COMPILER_INSTALL_PATH=$HOME/0day COMPILER=clang make.cross ARCH=x86_64 

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <lkp@intel.com>

All warnings (new ones prefixed by >>):

>> drivers/platform/x86/dell-wmi-sysman/sysman.c:310:5: warning: no previous prototype for function 'validate_acpi_type' [-Wmissing-prototypes]
   int validate_acpi_type(union acpi_object *obj, const char *guid_string)
       ^
   drivers/platform/x86/dell-wmi-sysman/sysman.c:310:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int validate_acpi_type(union acpi_object *obj, const char *guid_string)
   ^
   static 
   1 warning generated.
--
>> drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c:218:5: warning: no previous prototype for function 'run_sysman_call' [-Wmissing-prototypes]
   int run_sysman_call(struct dell_wmi_sysman_buffer *buf)
       ^
   drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c:218:1: note: declare 'static' if the function is not intended to be used outside of this translation unit
   int run_sysman_call(struct dell_wmi_sysman_buffer *buf)
   ^
   static 
   1 warning generated.


vim +/validate_acpi_type +310 drivers/platform/x86/dell-wmi-sysman/sysman.c

   309	
 > 310	int validate_acpi_type(union acpi_object *obj, const char *guid_string)
   311	{
   312		u32 acpi_type;
   313	
   314		if (strcmp(guid_string, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID) == 0)
   315			acpi_type = ACPI_TYPE_INTEGER;
   316		else
   317			acpi_type = ACPI_TYPE_STRING;
   318	
   319		if (obj->package.elements[CURRENT_VAL].type != acpi_type)
   320			return -EIO;
   321	
   322		return 0;
   323	}
   324	

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all(a)lists.01.org

[-- Attachment #2: config.gz --]
[-- Type: application/gzip, Size: 41107 bytes --]

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH] IOCTL support for dell-wmi-sysman driver
  2021-02-09 17:57 ` Hans de Goede
@ 2021-03-15  4:19   ` Prasanth, KSR
  0 siblings, 0 replies; 7+ messages in thread
From: Prasanth, KSR @ 2021-03-15  4:19 UTC (permalink / raw)
  To: Hans de Goede, dvhart
  Cc: LKML, platform-driver-x86, Prasanth KSR, Divya Bharathi,
	Mario Limonciello

Hi,


We tried to run some performance tests to build the case and the numbers 
really did not support much.

So at this point to time we decided that IOCTL support is not making sense.


Regards,

Prasanth K S R


Regards,On 15/03/21 9:12 am, Ksr, Prasanth wrote:

> Hi,
>
> We tried to run some performance tests to build the case and the 
> numbers really did not support much.
>
> So at this point to time we decided that IOCTL support is not making 
> sense.
>
> Thanks,
>
> Prasanth K S R
>
> > Hi,
>
> >
>
> > On 2/9/21 3:28 PM, Prasanth, KSR wrote:
>
> > From: "Prasanth KSR" <prasanth.ksr@dell.com 
> <mailto:prasanth.ksr@dell.com>>
>
> >
>
> > Perform BIOS Management calls on supported Dell machines through the
>
> > Dell WMI System Management interface.
>
> >
>
> > This interface provides IOCTL's to perform bundled BIOS Setting
>
> > transactions.
>
> >
>
> > Why?
>
> >
>
> > Adding new userspace API is not something which we do without a very 
> good reason for it.
>
> >
>
> > We spend a lot of time on reviewing the sysfs API for this, so I 
> must say that I'm quite surprised to now see an IOCTL API being 
> proposed on top of the existing sysfs API.
>
> >
>
> > This is going to need a long explanation why this is necessary over 
> the existing sysfs API.
>
> >
>
> >To be honest ATM I'm not inclined to accept this patch and it is 
> going to take some very strong arguments to change my mind.
>
> >
>
> >Regards,
>
> >
>
> >Hans
>
> >
>
> > Cc: Hans de Goede <hdegoede@redhat.com <mailto:hdegoede@redhat.com>>
>
> >
>
> > Signed-off-by: Prasanth KSR <prasanth.ksr@dell.com 
> <mailto:prasanth.ksr@dell.com>>
>
> > Co-developed-by: Divya Bharathi <divya.bharathi@dell.com 
> <mailto:divya.bharathi@dell.com>>
>
> > Signed-off-by: Divya Bharathi <divya.bharathi@dell.com 
> <mailto:divya.bharathi@dell.com>>
>
> > Co-developed-by: Mario Limonciello <mario.limonciello@dell.com 
> <mailto:mario.limonciello@dell.com>>
>
> > Signed-off-by: Mario Limonciello <mario.limonciello@dell.com 
> <mailto:mario.limonciello@dell.com>>
>
> > ---
>
> > Documentation/ABI/testing/dell-wmi-sysman     |  39 ++
>
> > .../x86/dell-wmi-sysman/biosattr-interface.c  | 257 +++++++++--
>
> > .../x86/dell-wmi-sysman/dell-wmi-sysman.h     |  20 +-
>
> > .../x86/dell-wmi-sysman/enum-attributes.c     |  45 +-
>
> > .../x86/dell-wmi-sysman/int-attributes.c      |  46 +-
>
> > .../x86/dell-wmi-sysman/passobj-attributes.c  |  23 +
>
> > .../x86/dell-wmi-sysman/string-attributes.c   |  50 +-
>
> > drivers/platform/x86/dell-wmi-sysman/sysman.c |  48 +-
>
> > include/uapi/linux/wmi.h                      |  56 +++
>
> > tools/dell-wmi-sysman/Makefile                |  19 +
>
> > .../dell-wmi-sysman/dell-wmi-sysman-example.c | 432
>
> > ++++++++++++++++++
>
> >  11 files changed, 946 insertions(+), 89 deletions(-)  create mode
>
> > 100644 Documentation/ABI/testing/dell-wmi-sysman
>
> >  create mode 100644 tools/dell-wmi-sysman/Makefile  create mode 100644
>
> > tools/dell-wmi-sysman/dell-wmi-sysman-example.c
>
> >
>
> > diff --git a/Documentation/ABI/testing/dell-wmi-sysman
>
> > b/Documentation/ABI/testing/dell-wmi-sysman
>
> > new file mode 100644
>
> > index 000000000000..4f3883529a06
>
> > --- /dev/null
>
> > +++ b/Documentation/ABI/testing/dell-wmi-sysman
>
> > @@ -0,0 +1,39 @@
>
> > +What:                             /dev/wmi/dell-wmi-sysman
>
> > +Date:                               November 2021
>
> > +KernelVersion:            5.15
>
> > +Contact:         "Divya Bharathi" <divya.bharathi@dell.com 
> <mailto:divya.bharathi@dell.com>>
>
> > +                          "Mario Limonciello" 
> <mario.limonciello@dell.com <mailto:mario.limonciello@dell.com>>
>
> > + "Prasanth K S R" <prasanth.ksr@dell.com 
> <mailto:prasanth.ksr@dell.com>>
>
> > +Description:
>
> > + Perform BIOS Management calls on supported Dell machines
>
> > + through the Dell WMI System Management interface.
>
> > +
>
> > +                          This interface provides IOCTL's to 
> perform bundled
>
> > +                          BIOS Setting transactions.
>
> > +
>
> > + IOCTL's and buffer formats are defined in:
>
> > + <uapi/linux/wmi.h>
>
> > +
>
> > +                          1) To perform a BIOS System Management 
> call from userspace,
>
> > +                          you'll need to first determine the 
> minimum size of the
>
> > +                          system management interface buffer for 
> your machine.
>
> > + Platforms that contain larger buffers can return larger
>
> > + objects from the system firmware.
>
> > + Commonly this size is either 4k or 32k.
>
> > +
>
> > +                          To determine the size of the buffer 
> read() a u64 dword from
>
> > +                          the WMI character device 
> /dev/wmi/dell-wmi-sysman.
>
> > +
>
> > +                          2) After you've determined the minimum 
> size of the system management
>
> > + interface buffer, you can allocate a structure that represents
>
> > +                          the structure documented above (struct 
> dell_wmi_sysman_buffer).
>
> > +
>
> > +                          3) In this buffer object, prepare as 
> necessary for the BIOS System
>
> > + Management call you're interested in. Typically System Management
>
> > + buffers have "length", "command" , "count" and "admin_password"
>
> > + defined to values that coincide with the "data" you are interested in.
>
> > +
>
> > +                          4) Run the call by using ioctl() as 
> described in the header.
>
> > +
>
> > +                          5) The output will be returned in the 
> buffer object and
>
> > +                          make sure to free up the allocated buffer.
>
> > diff --git a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
>
> > b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
>
> > index f95d8ddace5a..9a82e78fe59e 100644
>
> > --- a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
>
> > +++ b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
>
> > @@ -6,12 +6,14 @@
>
> >   *  Copyright (c) 2020 Dell Inc.
>
> >   */
>
> >
>
> > +#include <uapi/linux/wmi.h>
>
> >  #include <linux/wmi.h>
>
> >  #include "dell-wmi-sysman.h"
>
> >
>
> >  #define SETDEFAULTVALUES_METHOD_ID 0x02
>
> >  #define SETBIOSDEFAULTS_METHOD_ID 0x03
>
> >  #define SETATTRIBUTE_METHOD_ID 0x04
>
> > +#define SETATTRIBUTES_METHOD_ID 0x05
>
> >
>
> >  static int call_biosattributes_interface(struct wmi_device *wdev, 
> char *in_args, size_t size,
>
> > int method_id)
>
> > @@ -41,17 +43,17 @@ static int call_biosattributes_interface(struct
>
> > wmi_device *wdev, char *in_args, }
>
> >
>
> >  /**
>
> > - * set_attribute() - Update an attribute value
>
> > - * @a_name: The attribute name
>
> > - * @a_value: The attribute value
>
> > + * set_bios_defaults() - Resets BIOS defaults
>
> > + * @deftype: the type of BIOS value reset to issue.
>
> >   *
>
> > - * Sets an attribute to new value
>
> > + * Resets BIOS defaults
>
> >   */
>
> > -int set_attribute(const char *a_name, const char *a_value)
>
> > +int set_bios_defaults(u8 deftype)
>
> >  {
>
> >             size_t security_area_size, buffer_size;
>
> > -           size_t a_name_size, a_value_size;
>
> > -           char *buffer = NULL, *start;
>
> > +          size_t integer_area_size = sizeof(u8);
>
> > +          char *buffer = NULL;
>
> > +          u8 *defaultType;
>
> >             int ret;
>
> >
>
> > mutex_lock(&wmi_priv.mutex);
>
> > @@ -60,11 +62,8 @@ int set_attribute(const char *a_name, const char 
> *a_value)
>
> >                             goto out;
>
> >             }
>
> >
>
> > -           /* build/calculate buffer */
>
> >             security_area_size = 
> calculate_security_buffer(wmi_priv.current_admin_password);
>
> > -           a_name_size = calculate_string_buffer(a_name);
>
> > -           a_value_size = calculate_string_buffer(a_value);
>
> > -           buffer_size = security_area_size + a_name_size + 
> a_value_size;
>
> > +          buffer_size = security_area_size + integer_area_size;
>
> >             buffer = kzalloc(buffer_size, GFP_KERNEL);
>
> >             if (!buffer) {
>
> >                             ret = -ENOMEM;
>
> > @@ -74,44 +73,51 @@ int set_attribute(const char *a_name, const char 
> *a_value)
>
> >             /* build security area */
>
> > populate_security_buffer(buffer, wmi_priv.current_admin_password);
>
> >
>
> > -           /* build variables to set */
>
> > -           start = buffer + security_area_size;
>
> > -           ret = populate_string_buffer(start, a_name_size, a_name);
>
> > -           if (ret < 0)
>
> > -                           goto out;
>
> > -           start += ret;
>
> > -           ret = populate_string_buffer(start, a_value_size, a_value);
>
> > -           if (ret < 0)
>
> > -                           goto out;
>
> > +          defaultType = buffer + security_area_size;
>
> > +          *defaultType = deftype;
>
> >
>
> > - print_hex_dump_bytes("set attribute data: ", DUMP_PREFIX_NONE, 
> buffer, buffer_size);
>
> > -           ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev,
>
> > -     buffer, buffer_size,
>
> > -     SETATTRIBUTE_METHOD_ID);
>
> > -           if (ret == -EOPNOTSUPP)
>
> > - dev_err(&wmi_priv.bios_attr_wdev->dev, "admin password must be 
> configured\n");
>
> > -           else if (ret == -EACCES)
>
> > - dev_err(&wmi_priv.bios_attr_wdev->dev, "invalid password\n");
>
> > +          ret = 
> call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, 
> buffer_size,
>
> > +     SETBIOSDEFAULTS_METHOD_ID);
>
> > +          if (ret)
>
> > + dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults failed:
>
> > +%d\n", ret);
>
> >
>
> > -out:
>
> >             kfree(buffer);
>
> > +out:
>
> > mutex_unlock(&wmi_priv.mutex);
>
> >             return ret;
>
> >  }
>
> >
>
> >  /**
>
> > - * set_bios_defaults() - Resets BIOS defaults
>
> > - * @deftype: the type of BIOS value reset to issue.
>
> > + * calculate_array_length() - calculate total size of string array
>
> > + * @str_arr: array of strings
>
> > + * @str_count: string count
>
> >   *
>
> > - * Resets BIOS defaults
>
> > - */
>
> > -int set_bios_defaults(u8 deftype)
>
> > + * Method to calculate the total size of array of string  **/ static
>
> > +int calculate_array_length(char **str_arr, int str_count)
>
> >  {
>
> > -           size_t security_area_size, buffer_size;
>
> > -           size_t integer_area_size = sizeof(u8);
>
> > -           char *buffer = NULL;
>
> > -           u8 *defaultType;
>
> > -           int ret;
>
> > +          int ret = 0, i;
>
> > +
>
> > +          for (i = 0; i < str_count; ++i)
>
> > +                          ret += calculate_string_buffer(str_arr[i]);
>
> > +          return ret;
>
> > +}
>
> > +
>
> > +/**
>
> > + * set_attributes() - Update multiple attribute values
>
> > + * @in_data: input set data
>
> > + * @a_count: Number of atributes to be set
>
> > + * @command: command to decide set user input value or default
>
> > + *
>
> > + * Sets attributes to user input value of defaut value  **/ int
>
> > +set_attributes(struct dell_set_data *in_data, int a_count, unsigned
>
> > +short command) {
>
> > +          size_t security_area_size, string_area_size, buffer_size, 
> attr_count_area;
>
> > +          char **a_names, **a_values;
>
> > +          char *buffer = NULL, *start;
>
> > +          int ret, method_id, i;
>
> > +          u32 *attr_count;
>
> >
>
> > mutex_lock(&wmi_priv.mutex);
>
> >             if (!wmi_priv.bios_attr_wdev) {
>
> > @@ -119,8 +125,34 @@ int set_bios_defaults(u8 deftype)
>
> >                             goto out;
>
> >             }
>
> >
>
> > +          //allocate memory to hold set inputs
>
> > +          a_names = kmalloc(a_count * (sizeof(char *)), GFP_KERNEL);
>
> > +          if (!a_names) {
>
> > +                          ret = -ENOMEM;
>
> > +                          goto out;
>
> > +          }
>
> > +          if (command == SET_ATTRIBUTES) {
>
> > + a_values = kmalloc(a_count * (sizeof(char *)), GFP_KERNEL);
>
> > +                          if (!a_values) {
>
> > +                                          ret = -ENOMEM;
>
> > +                                          goto out;
>
> > +                          }
>
> > +          }
>
> > +
>
> > +          //assign inputs to single array and send to set functions
>
> > +          for (i = 0; i < a_count; i++) {
>
> > + a_names[i] = in_data[i].attribute_name;
>
> > +                          if (command == SET_ATTRIBUTES)
>
> > +                                          a_values[i] = 
> in_data[i].attribute_value;
>
> > +          }
>
> > +
>
> >             security_area_size = 
> calculate_security_buffer(wmi_priv.current_admin_password);
>
> > -           buffer_size = security_area_size + integer_area_size;
>
> > +          attr_count_area = sizeof(u32);
>
> > +          string_area_size = (calculate_array_length(a_names, 
> a_count));
>
> > +          if (command == SET_ATTRIBUTES)
>
> > + string_area_size += (calculate_array_length(a_values, a_count));
>
> > +          buffer_size = security_area_size + attr_count_area + 
> string_area_size
>
> > + + (sizeof(u16) * a_count);
>
> >             buffer = kzalloc(buffer_size, GFP_KERNEL);
>
> >             if (!buffer) {
>
> >                             ret = -ENOMEM;
>
> > @@ -130,26 +162,153 @@ int set_bios_defaults(u8 deftype)
>
> >             /* build security area */
>
> > populate_security_buffer(buffer, wmi_priv.current_admin_password);
>
> >
>
> > -           defaultType = buffer + security_area_size;
>
> > -           *defaultType = deftype;
>
> > +          /* build variables to set */
>
> > +          attr_count = (u32 *)(buffer + security_area_size);
>
> > +          *attr_count = (u32)a_count;
>
> > +          start =  (u8 *)(attr_count) + attr_count_area;
>
> >
>
> > -           ret = 
> call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, 
> buffer_size,
>
> > -     SETBIOSDEFAULTS_METHOD_ID);
>
> > -           if (ret)
>
> > - dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults 
> failed: %d\n", ret);
>
> > +          for (i = 0; i < a_count; i++) {
>
> > +                          ret = populate_string_buffer(start, 
> calculate_string_buffer(a_names[i]),
>
> > + a_names[i]);
>
> > +                          if (ret < 0)
>
> > +                                          goto out;
>
> > +                          start += ret;
>
> > +          }
>
> > +
>
> > +          if (command == SET_ATTRIBUTES) {
>
> > +                          for (i = 0; i < a_count; i++) {
>
> > +                                          ret = 
> populate_string_buffer(start, calculate_string_buffer(a_values[i]),
>
> > + a_values[i]);
>
> > +                                          if (ret < 0)
>
> > + goto out;
>
> > +                                          start += ret;
>
> > +                          }
>
> > + method_id = SETATTRIBUTES_METHOD_ID;
>
> > +          } else {
>
> > + method_id = SETDEFAULTVALUES_METHOD_ID;
>
> > +          }
>
> > +
>
> > + print_hex_dump_bytes("set multiple attribute: ", DUMP_PREFIX_NONE, 
> buffer, buffer_size);
>
> > +          ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev,
>
> > +     buffer, buffer_size, method_id);
>
> > +
>
> > +          if (ret == -EOPNOTSUPP)
>
> > + dev_err(&wmi_priv.password_attr_wdev->dev, "admin password must be 
> configured\n");
>
> > +          else if (ret == -EACCES)
>
> > + dev_err(&wmi_priv.password_attr_wdev->dev, "invalid password\n");
>
> >
>
> > -           kfree(buffer);
>
> >  out:
>
> > +          kfree(buffer);
>
> > +          kfree(a_names);
>
> > +          if (command == SET_ATTRIBUTES)
>
> > + kfree(a_values);
>
> > mutex_unlock(&wmi_priv.mutex);
>
> >             return ret;
>
> >  }
>
> >
>
> > +__u64 get_attrs_size(void)
>
> > +{
>
> > +          __u64 size = sizeof(struct dell_attributes_data) *
>
> > + (get_instance_count(DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID) +
>
> > + get_instance_count(DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID) +
>
> > + get_instance_count(DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID));
>
> > +          return size;
>
> > +}
>
> > +
>
> > +int run_sysman_call(struct dell_wmi_sysman_buffer *buf) {
>
> > +          struct dell_set_password *pass_set_data;
>
> > +          struct dell_set_data *in_data;
>
> > +          int ret = -ENOIOCTLCMD;
>
> > +          char *tmp_system = NULL;
>
> > +          char *tmp_admin = NULL;
>
> > +
>
> > +          switch (buf->command) {
>
> > +          case ENUMERATE_ALL:
>
> > + buf->count = get_attrs_size() / sizeof(struct dell_attributes_data);
>
> > + get_enumeration_data(buf);
>
> > + get_integer_data(buf);
>
> > + get_string_data(buf);
>
> > +                          ret = 0;
>
> > +                          break;
>
> > +          case SET_ATTRIBUTES:
>
> > +          case SET_DEFAULTS:
>
> > +                          if (!buf->count)
>
> > +                                          goto out;
>
> > + in_data = (struct dell_set_data *)buf->data;
>
> > + tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
>
> > + strlcpy_attr(wmi_priv.current_admin_password, buf->admin_password);
>
> > +                          ret = set_attributes(in_data, buf->count, 
> buf->command);
>
> > + strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
>
> > + kfree(tmp_admin);
>
> > +                          break;
>
> > +          case GET_PASS:
>
> > + get_po_data(buf);
>
> > +                          ret = 0;
>
> > +                          break;
>
> > +          case SET_PASS:
>
> > + pass_set_data = (struct dell_set_password *)buf->data;
>
> > + tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
>
> > + strlcpy_attr(wmi_priv.current_admin_password, buf->admin_password);
>
> > +
>
> > +                          if (strcmp(pass_set_data->attribute_name, 
> "System") == 0) {
>
> > +                                          tmp_system = 
> kstrdup(wmi_priv.current_system_password, GFP_KERNEL);
>
> > + strlcpy_attr(wmi_priv.current_system_password,
>
> > + pass_set_data->system_password);
>
> > +                          }
>
> > +
>
> > +                          ret = 
> set_new_password(pass_set_data->attribute_name, 
> pass_set_data->new_password);
>
> > + strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
>
> > + kfree(tmp_admin);
>
> > +
>
> > +                          if (tmp_system != NULL) {
>
> > + strlcpy_attr(wmi_priv.current_system_password, tmp_system);
>
> > + kfree(tmp_system);
>
> > +                          }
>
> > +                          break;
>
> > +          }
>
> > +out:
>
> > +          return ret;
>
> > +}
>
> > +
>
> > +
>
> > +static long bios_attr_set_interface_filter(struct wmi_device *wdev, 
> unsigned int cmd,
>
> > +    struct wmi_ioctl_buffer *arg)
>
> > +{
>
> > +          struct dell_wmi_sysman_buffer *buf;
>
> > +          struct dell_resetBIOS *reset_buf;
>
> > +          char *tmp_admin = NULL;
>
> > +          int ret = -ENOIOCTLCMD;
>
> > +
>
> > +          switch (cmd) {
>
> > +          case DELL_WMI_SYSMAN_CMD:
>
> > +                          buf = (struct dell_wmi_sysman_buffer *) arg;
>
> > +                          ret = run_sysman_call(buf);
>
> > +                          break;
>
> > +          case DELL_WMI_SYSMAN_RESET_BIOS:
>
> > + reset_buf = (struct dell_resetBIOS *) arg;
>
> > +                          if (reset_buf->option > 0) {
>
> > +                                          tmp_admin = 
> kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
>
> > + strlcpy_attr(wmi_priv.current_admin_password, 
> reset_buf->admin_password);
>
> > +                                          ret = 
> set_bios_defaults(reset_buf->option);
>
> > + strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
>
> > +                                          kfree(tmp_admin);
>
> > +                          }
>
> > +                          break;
>
> > +          }
>
> > +          return ret;
>
> > +}
>
> > +
>
> >  static int bios_attr_set_interface_probe(struct wmi_device *wdev,
>
> > const void *context)  {
>
> > +          __u32 req_buf_size;
>
> > mutex_lock(&wmi_priv.mutex);
>
> > wmi_priv.bios_attr_wdev = wdev;
>
> > mutex_unlock(&wmi_priv.mutex);
>
> > -           return 0;
>
> > +          req_buf_size = get_attrs_size();
>
> > +          /* add in size of struct dell_wmi_sysman_buffer which is 
> used internally with ioctl */
>
> > +          req_buf_size += sizeof(struct dell_wmi_sysman_buffer);
>
> > +          return set_required_buffer_size(wdev, req_buf_size);
>
> >  }
>
> >
>
> >  static int bios_attr_set_interface_remove(struct wmi_device *wdev) @@
>
> > -171,6 +330,7 @@ static struct wmi_driver 
> bios_attr_set_interface_driver = {
>
> >             .probe = bios_attr_set_interface_probe,
>
> >             .remove = bios_attr_set_interface_remove,
>
> >             .id_table = bios_attr_set_interface_id_table,
>
> > +          .filter_callback = bios_attr_set_interface_filter
>
> >  };
>
> >
>
> >  int init_bios_attr_set_interface(void)
>
> > @@ -184,3 +344,4 @@ void exit_bios_attr_set_interface(void)
>
> >  }
>
> >
>
> >  MODULE_DEVICE_TABLE(wmi, bios_attr_set_interface_id_table);
>
> > +
>
> > diff --git a/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
>
> > b/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
>
> > index b80f2a62ea3f..13c216e6ddec 100644
>
> > --- a/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
>
> > +++ b/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
>
> > @@ -8,6 +8,7 @@
>
> >  #define _DELL_WMI_BIOS_ATTR_H_
>
> >
>
> >  #include <linux/wmi.h>
>
> > +#include <uapi/linux/wmi.h>
>
> >  #include <linux/device.h>
>
> >  #include <linux/module.h>
>
> >  #include <linux/kernel.h>
>
> > @@ -87,8 +88,6 @@ struct wmi_sysman_priv {
>
> >  /* global structure used by multiple WMI interfaces */  extern struct
>
> > wmi_sysman_priv wmi_priv;
>
> >
>
> > -enum { ENUM, INT, STR, PO };
>
> > -
>
> >  enum {
>
> >             ATTR_NAME,
>
> >             DISPL_NAME_LANG_CODE,
>
> > @@ -134,6 +133,7 @@ static ssize_t curr_val##_store(struct kobject 
> *kobj,                                                     \
>
> > struct kobj_attribute *attr,                                          \
>
> > const char *buf, size_t count)                                     \
>
> > { \
>
> > +          struct dell_set_data *set_data; \
>
> >             char *p, *buf_cp; \
>
> >             int i, ret = -EIO; \
>
> >             buf_cp = kstrdup(buf, GFP_KERNEL); \
>
> > @@ -146,15 +146,19 @@ static ssize_t curr_val##_store(struct kobject 
> *kobj,                                                \
>
> >             i = get_##type##_instance_id(kobj); \
>
> >             if (i >= 0) \
>
> >                             ret = validate_##type##_input(i, 
> buf_cp);                                             \
>
> > +          set_data = kzalloc(sizeof(*set_data), 
> GFP_KERNEL);                                         \
>
> > + strlcpy_attr(set_data[0].attribute_value, 
> buf_cp);                                             \
>
> > + strlcpy_attr(set_data[0].attribute_name, 
> kobj->name);                                  \
>
> >             if (!ret) \
>
> > -                           ret = set_attribute(kobj->name, 
> buf_cp);                                              \
>
> > +                          ret = set_attributes(set_data, 1, 
> SET_ATTRIBUTES);                          \
>
> > kfree(buf_cp); \
>
> >             return ret ? ret : count; \
>
> >  }
>
> >
>
> >  union acpi_object *get_wmiobj_pointer(int instance_id, const char
>
> > *guid_string);  int get_instance_count(const char *guid_string); -void
>
> > strlcpy_attr(char *dest, char *src);
>
> > +int get_current_value(char *buf, int instance_id, const char
>
> > +*guid_string); void strlcpy_attr(char *dest, const char *src);
>
> >
>
> >  int populate_enum_data(union acpi_object *enumeration_obj, int 
> instance_id,
>
> >                                            struct kobject 
> *attr_name_kobj);
>
> > @@ -174,7 +178,7 @@ int populate_po_data(union acpi_object *po_obj,
>
> > int instance_id, struct kobject int alloc_po_data(void);  void
>
> > exit_po_attributes(void);
>
> >
>
> > -int set_attribute(const char *a_name, const char *a_value);
>
> > +int set_attributes(struct dell_set_data *in_data, int a_count,
>
> > +unsigned short command);
>
> >  int set_bios_defaults(u8 defType);
>
> >
>
> >  void exit_bios_attr_set_interface(void);
>
> > @@ -188,4 +192,10 @@ int set_new_password(const char *password_type,
>
> > const char *new);  int init_bios_attr_pass_interface(void);
>
> >  void exit_bios_attr_pass_interface(void);
>
> >
>
> > +__u64 get_attrs_size(void);
>
> > +void get_enumeration_data(struct dell_wmi_sysman_buffer *buf); void
>
> > +get_integer_data(struct dell_wmi_sysman_buffer *buf); void
>
> > +get_string_data(struct dell_wmi_sysman_buffer *buf); void
>
> > +get_po_data(struct dell_wmi_sysman_buffer *attr_data);
>
> > +
>
> >  #endif
>
> > diff --git a/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
>
> > b/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
>
> > index 80f4b7785c6c..b23e10ac00da 100644
>
> > --- a/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
>
> > +++ b/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
>
> > @@ -13,22 +13,17 @@ get_instance_id(enumeration);  static ssize_t
>
> > current_value_show(struct kobject *kobj, struct kobj_attribute *attr,
>
> > char *buf)  {
>
> >             int instance_id = get_enumeration_instance_id(kobj);
>
> > -           union acpi_object *obj;
>
> > -           ssize_t ret;
>
> > +          int ret;
>
> >
>
> >             if (instance_id < 0)
>
> > return instance_id;
>
> >
>
> > -           /* need to use specific instance_id and guid combination 
> to get right data */
>
> > -           obj = get_wmiobj_pointer(instance_id, 
> DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
>
> > -           if (!obj)
>
> > - return -EIO;
>
> > -           if (obj->package.elements[CURRENT_VAL].type != 
> ACPI_TYPE_STRING) {
>
> > - kfree(obj);
>
> > - return -EINVAL;
>
> > +          ret = get_current_value(buf, instance_id, 
> DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
>
> > +          if (ret > 0) {
>
> > + strcat(buf, "\n");
>
> > +                          return strlen(buf);
>
> >             }
>
> > -           ret = snprintf(buf, PAGE_SIZE, "%s\n", 
> obj->package.elements[CURRENT_VAL].string.pointer);
>
> > -           kfree(obj);
>
> > +          /* read error */
>
> >             return ret;
>
> >  }
>
> >
>
> > @@ -171,6 +166,34 @@ int populate_enum_data(union acpi_object 
> *enumeration_obj, int instance_id,
>
> >             return sysfs_create_group(attr_name_kobj, 
> &enumeration_attr_group);
>
> > }
>
> >
>
> > +void get_enumeration_data(struct dell_wmi_sysman_buffer *buf) {
>
> > +          struct dell_attributes_data *attr_data;
>
> > +          int i;
>
> > +
>
> > +          attr_data = (struct dell_attributes_data *)buf->data;
>
> > +          for (i = 0; i < wmi_priv.enumeration_instances_count; i++) {
>
> > + attr_data[i].type = ENUM;
>
> > + strlcpy_attr(attr_data[i].attribute_name,
>
> > + wmi_priv.enumeration_data[i].attribute_name);
>
> > + strlcpy_attr(attr_data[i].display_name,
>
> > + wmi_priv.enumeration_data[i].display_name);
>
> > + strlcpy_attr(attr_data[i].display_name_language_code,
>
> > + wmi_priv.enumeration_data[i].display_name_language_code);
>
> > + strlcpy_attr(attr_data[i].possible_values,
>
> > + wmi_priv.enumeration_data[i].possible_values);
>
> > + strlcpy_attr(attr_data[i].dell_modifier,
>
> > + wmi_priv.enumeration_data[i].dell_modifier);
>
> > + strlcpy_attr(attr_data[i].dell_value_modifier,
>
> > + wmi_priv.enumeration_data[i].dell_value_modifier);
>
> > + strlcpy_attr(attr_data[i].default_value,
>
> > + wmi_priv.enumeration_data[i].default_value);
>
> > + get_current_value(attr_data[i].current_value, i,
>
> > + DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
>
> > +
>
> > +          }
>
> > +}
>
> > +
>
> >  /**
>
> >   * exit_enum_attributes() - Clear all attribute data
>
> >   *
>
> > diff --git a/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
>
> > b/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
>
> > index 75aedbb733be..0155f6189576 100644
>
> > --- a/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
>
> > +++ b/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
>
> > @@ -15,22 +15,17 @@ get_instance_id(integer);  static ssize_t
>
> > current_value_show(struct kobject *kobj, struct kobj_attribute *attr,
>
> > char *buf)  {
>
> >             int instance_id = get_integer_instance_id(kobj);
>
> > -           union acpi_object *obj;
>
> > -           ssize_t ret;
>
> > +          int ret;
>
> >
>
> >             if (instance_id < 0)
>
> > return instance_id;
>
> >
>
> > -           /* need to use specific instance_id and guid combination 
> to get right data */
>
> > -           obj = get_wmiobj_pointer(instance_id, 
> DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
>
> > -           if (!obj)
>
> > - return -EIO;
>
> > -           if (obj->package.elements[CURRENT_VAL].type != 
> ACPI_TYPE_INTEGER) {
>
> > - kfree(obj);
>
> > - return -EINVAL;
>
> > +          ret = get_current_value(buf, instance_id, 
> DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
>
> > +          if (ret > 0) {
>
> > + strcat(buf, "\n");
>
> > +                          return strlen(buf);
>
> >             }
>
> > -           ret = snprintf(buf, PAGE_SIZE, "%lld\n", 
> obj->package.elements[CURRENT_VAL].integer.value);
>
> > -           kfree(obj);
>
> > +          /* read error */
>
> >             return ret;
>
> >  }
>
> >
>
> > @@ -161,6 +156,35 @@ int populate_int_data(union acpi_object 
> *integer_obj, int instance_id,
>
> >             return sysfs_create_group(attr_name_kobj, 
> &integer_attr_group);  }
>
> >
>
> > +void get_integer_data(struct dell_wmi_sysman_buffer *buf) {
>
> > +          struct dell_attributes_data *attr_data;
>
> > +          int i;
>
> > +          //To populate in same dell_attributes_data, increment 
> after enum data
>
> > +          int a_count = wmi_priv.enumeration_instances_count;
>
> > +
>
> > +          attr_data = (struct dell_attributes_data *)buf->data;
>
> > +          for (i = 0; i < wmi_priv.integer_instances_count; i++) {
>
> > + attr_data[a_count].type = INT;
>
> > + strlcpy_attr(attr_data[a_count].attribute_name,
>
> > + wmi_priv.integer_data[i].attribute_name);
>
> > + strlcpy_attr(attr_data[a_count].display_name,
>
> > + wmi_priv.integer_data[i].display_name);
>
> > + strlcpy_attr(attr_data[a_count].display_name_language_code,
>
> > + wmi_priv.integer_data[i].display_name_language_code);
>
> > + strlcpy_attr(attr_data[a_count].dell_modifier,
>
> > + wmi_priv.integer_data[i].dell_modifier);
>
> > + attr_data[a_count].min = wmi_priv.integer_data[i].min_value;
>
> > + attr_data[a_count].max = wmi_priv.integer_data[i].max_value;
>
> > + attr_data[a_count].scalar_increment = 
> wmi_priv.integer_data[i].scalar_increment;
>
> > + snprintf(attr_data[a_count].default_value, PAGE_SIZE, "%d",
>
> > + wmi_priv.integer_data[i].default_value);
>
> > + get_current_value(attr_data[a_count].current_value, i,
>
> > + DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
>
> > + a_count++;
>
> > +          }
>
> > +}
>
> > +
>
> >  /**
>
> >   * exit_int_attributes() - Clear all attribute data
>
> >   *
>
> > diff --git a/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
>
> > b/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
>
> > index 3abcd95477c0..9f50989a9f44 100644
>
> > --- a/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
>
> > +++ b/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
>
> > @@ -169,6 +169,29 @@ int populate_po_data(union acpi_object *po_obj, 
> int instance_id, struct kobject
>
> >             return sysfs_create_group(attr_name_kobj, 
> &po_attr_group);  }
>
> >
>
> > +void get_po_data(struct dell_wmi_sysman_buffer *in_data) {
>
> > +          int i;
>
> > +          struct dell_password_data *attr_data;
>
> > +
>
> > +          in_data->count = wmi_priv.po_instances_count;
>
> > +          attr_data = (struct dell_password_data *)in_data->data;
>
> > +          for (i = 0; i < wmi_priv.po_instances_count; i++) {
>
> > +                          union acpi_object *obj;
>
> > +
>
> > + strlcpy_attr(attr_data[i].attribute_name,
>
> > + wmi_priv.po_data[i].attribute_name);
>
> > + attr_data[i].min_length = wmi_priv.po_data[i].min_password_length;
>
> > + attr_data[i].max_length = wmi_priv.po_data[i].max_password_length;
>
> > +
>
> > +                          obj = get_wmiobj_pointer(i, 
> DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
>
> > +                          if (!obj)
>
> > +                                          continue;
>
> > + attr_data[i].is_set = 
> obj->package.elements[IS_PASS_SET].integer.value;
>
> > + kfree(obj);
>
> > +          }
>
> > +}
>
> > +
>
> >  /**
>
> >   * exit_po_attributes() - Clear all attribute data
>
> >   *
>
> > diff --git a/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
>
> > b/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
>
> > index ac75dce88a4c..a3847e4a6bf8 100644
>
> > --- a/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
>
> > +++ b/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
>
> > @@ -15,22 +15,17 @@ get_instance_id(str);  static ssize_t
>
> > current_value_show(struct kobject *kobj, struct kobj_attribute *attr,
>
> > char *buf)  {
>
> >             int instance_id = get_str_instance_id(kobj);
>
> > -           union acpi_object *obj;
>
> > -           ssize_t ret;
>
> > +          int ret;
>
> >
>
> >             if (instance_id < 0)
>
> > - return -EIO;
>
> > -
>
> > -           /* need to use specific instance_id and guid combination 
> to get right data */
>
> > -           obj = get_wmiobj_pointer(instance_id, 
> DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
>
> > -           if (!obj)
>
> > - return -EIO;
>
> > -           if (obj->package.elements[CURRENT_VAL].type != 
> ACPI_TYPE_STRING) {
>
> > - kfree(obj);
>
> > - return -EINVAL;
>
> > +                          return instance_id;
>
> > +
>
> > +          ret = get_current_value(buf, instance_id, 
> DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
>
> > +          if (ret > 0) {
>
> > + strcat(buf, "\n");
>
> > +                          return strlen(buf);
>
> >             }
>
> > -           ret = snprintf(buf, PAGE_SIZE, "%s\n", 
> obj->package.elements[CURRENT_VAL].string.pointer);
>
> > -           kfree(obj);
>
> > +          /* read error */
>
> >             return ret;
>
> >  }
>
> >
>
> > @@ -141,6 +136,35 @@ int populate_str_data(union acpi_object 
> *str_obj, int instance_id, struct kobjec
>
> >             return sysfs_create_group(attr_name_kobj, 
> &str_attr_group);  }
>
> >
>
> > +void get_string_data(struct dell_wmi_sysman_buffer *buf) {
>
> > +          struct dell_attributes_data *attr_data;
>
> > +          int i;
>
> > +          //To populate in same dell_attributes_data, increment 
> after enum+int data
>
> > +          int a_count = wmi_priv.enumeration_instances_count +
>
> > + wmi_priv.integer_instances_count;
>
> > +          attr_data = (struct dell_attributes_data *)buf->data;
>
> > +
>
> > +          for (i = 0; i < wmi_priv.str_instances_count; i++) {
>
> > + attr_data[a_count].type = STR;
>
> > + strlcpy_attr(attr_data[a_count].attribute_name,
>
> > + wmi_priv.str_data[i].attribute_name);
>
> > + strlcpy_attr(attr_data[a_count].display_name,
>
> > + wmi_priv.str_data[i].display_name);
>
> > + strlcpy_attr(attr_data[a_count].display_name_language_code,
>
> > + wmi_priv.str_data[i].display_name_language_code);
>
> > + strlcpy_attr(attr_data[a_count].dell_modifier,
>
> > + wmi_priv.str_data[i].dell_modifier);
>
> > + attr_data[a_count].min = wmi_priv.str_data[i].min_length;
>
> > + attr_data[a_count].max = wmi_priv.str_data[i].max_length;
>
> > + strlcpy_attr(attr_data[a_count].default_value,
>
> > + wmi_priv.str_data[i].default_value);
>
> > + get_current_value(attr_data[a_count].current_value, i,
>
> > + DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
>
> > + a_count++;
>
> > +          }
>
> > +}
>
> > +
>
> >  /**
>
> >   * exit_str_attributes() - Clear all attribute data
>
> >   *
>
> > diff --git a/drivers/platform/x86/dell-wmi-sysman/sysman.c
>
> > b/drivers/platform/x86/dell-wmi-sysman/sysman.c
>
> > index cb81010ba1a2..0b77a6a0b8a8 100644
>
> > --- a/drivers/platform/x86/dell-wmi-sysman/sysman.c
>
> > +++ b/drivers/platform/x86/dell-wmi-sysman/sysman.c
>
> > @@ -275,7 +275,7 @@ static struct kobj_type attr_name_ktype = {
>
> >   * @dest: Where to copy the string to
>
> >   * @src: Where to copy the string from
>
> >   */
>
> > -void strlcpy_attr(char *dest, char *src)
>
> > +void strlcpy_attr(char *dest, const char *src)
>
> >  {
>
> >             size_t len = strlen(src) + 1;
>
> >
>
> > @@ -307,6 +307,52 @@ union acpi_object *get_wmiobj_pointer(int 
> instance_id, const char *guid_string)
>
> >             return ACPI_SUCCESS(status) ? (union acpi_object 
> *)out.pointer :
>
> > NULL;  }
>
> >
>
> > +int validate_acpi_type(union acpi_object *obj, const char
>
> > +*guid_string) {
>
> > +          u32 acpi_type;
>
> > +
>
> > +          if (strcmp(guid_string, 
> DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID) == 0)
>
> > + acpi_type = ACPI_TYPE_INTEGER;
>
> > +          else
>
> > + acpi_type = ACPI_TYPE_STRING;
>
> > +
>
> > +          if (obj->package.elements[CURRENT_VAL].type != acpi_type)
>
> > +                          return -EIO;
>
> > +
>
> > +          return 0;
>
> > +}
>
> > +
>
> > +/**
>
> > + * get_curret_value() - Get current_value of an attribute
>
> > + * @instance_id: WMI instance ID
>
> > + * @guid_string: WMI GUID (in string form)  */ int
>
> > +get_current_value(char *buf, int instance_id, const char
>
> > +*guid_string) {
>
> > +          union acpi_object *obj;
>
> > +          int ret;
>
> > +
>
> > +          /* need to use specific instance_id and guid combination 
> to get right data */
>
> > +          obj = get_wmiobj_pointer(instance_id, guid_string);
>
> > +          if (!obj)
>
> > +                          return -EIO;
>
> > +
>
> > +          ret = validate_acpi_type(obj, guid_string);
>
> > +          if (ret)
>
> > +                          goto out;
>
> > +
>
> > +          if (strcmp(guid_string, 
> DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID) == 0)
>
> > +                          ret = snprintf(buf, PAGE_SIZE, "%lld",
>
> > + obj->package.elements[CURRENT_VAL].integer.value);
>
> > +          else
>
> > +                          ret = snprintf(buf, PAGE_SIZE, "%s",
>
> > + obj->package.elements[CURRENT_VAL].string.pointer);
>
> > +
>
> > +out:
>
> > +          kfree(obj);
>
> > +          return ret;
>
> > +}
>
> > +
>
> >  /**
>
> >   * get_instance_count() - Compute total number of instances under 
> guid_string
>
> >   * @guid_string: WMI GUID (in string form) diff --git
>
> > a/include/uapi/linux/wmi.h b/include/uapi/linux/wmi.h index
>
> > 7085c5dca9fa..f160d1eef7cb 100644
>
> > --- a/include/uapi/linux/wmi.h
>
> > +++ b/include/uapi/linux/wmi.h
>
> > @@ -13,6 +13,11 @@
>
> >  /* WMI bus will filter all WMI vendor driver requests through this
>
> > IOC */  #define WMI_IOC 'W'
>
> >
>
> > +enum BIOS_ATTRIBUTE_TYPE { ENUM, INT, STR, PO }; enum IOCTL_COMMAND {
>
> > +ENUMERATE_ALL = 1, SET_ATTRIBUTES, SET_DEFAULTS, GET_PASS, SET_PASS
>
> > +};
>
> > +
>
> > +#define MAX_BUFF  512
>
> > +
>
> >  /* All ioctl requests through WMI should declare their size followed by
>
> >   * relevant data objects
>
> >   */
>
> > @@ -43,6 +48,53 @@ struct dell_wmi_smbios_buffer {
>
> >             struct dell_wmi_extensions        ext;
>
> >  } __packed;
>
> >
>
> > +struct dell_wmi_sysman_buffer {
>
> > +          __u64 length;
>
> > +          __u32 count;
>
> > +          __u16 command;
>
> > +          char admin_password[MAX_BUFF];
>
> > +          __u8 data[];
>
> > +} __packed;
>
> > +
>
> > +struct dell_attributes_data {
>
> > +          char display_name_language_code[MAX_BUFF];
>
> > +          char dell_value_modifier[MAX_BUFF];
>
> > +          char possible_values[MAX_BUFF];
>
> > +          char attribute_name[MAX_BUFF];
>
> > +          char current_value[MAX_BUFF];
>
> > +          char default_value[MAX_BUFF];
>
> > +          char dell_modifier[MAX_BUFF];
>
> > +          char display_name[MAX_BUFF];
>
> > +          int scalar_increment;
>
> > +          int type;
>
> > +          int min;
>
> > +          int max;
>
> > +} __packed;
>
> > +
>
> > +struct dell_set_data {
>
> > +          char attribute_name[MAX_BUFF];
>
> > +          char attribute_value[MAX_BUFF];
>
> > +} __packed;
>
> > +
>
> > +struct dell_set_password {
>
> > +          char attribute_name[MAX_BUFF];
>
> > +          char system_password[MAX_BUFF];
>
> > +          char new_password[MAX_BUFF];
>
> > +} __packed;
>
> > +
>
> > +struct dell_password_data {
>
> > +          char attribute_name[MAX_BUFF];
>
> > +          __u8 is_set;
>
> > +          int min_length;
>
> > +          int max_length;
>
> > +} __packed;
>
> > +
>
> > +struct dell_resetBIOS {
>
> > +          __u64 length;
>
> > +          __u8 option;
>
> > +          char admin_password[MAX_BUFF];
>
> > +} __packed;
>
> > +
>
> >  /* Whitelisted smbios class/select commands */
>
> >  #define CLASS_TOKEN_READ 0
>
> >  #define CLASS_TOKEN_WRITE               1
>
> > @@ -67,4 +119,8 @@ struct dell_wmi_smbios_buffer {
>
> >  /* Dell SMBIOS calling IOCTL command used by dell-smbios-wmi */
>
> >  #define DELL_WMI_SMBIOS_CMD _IOWR(WMI_IOC, 0, struct 
> dell_wmi_smbios_buffer)
>
> >
>
> > +/* Dell WMI System Management calling IOCTL commands used by
>
> > +dell-wmi-sysman */ #define DELL_WMI_SYSMAN_CMD _IOWR(WMI_IOC, 0,
>
> > +struct dell_wmi_sysman_buffer) #define DELL_WMI_SYSMAN_RESET_BIOS
>
> > +_IOW(WMI_IOC, 0, struct dell_resetBIOS)
>
> > +
>
> >  #endif
>
> > diff --git a/tools/dell-wmi-sysman/Makefile
>
> > b/tools/dell-wmi-sysman/Makefile new file mode 100644 index
>
> > 000000000000..0a01a82a0745
>
> > --- /dev/null
>
> > +++ b/tools/dell-wmi-sysman/Makefile
>
> > @@ -0,0 +1,19 @@
>
> > +# SPDX-License-Identifier: GPL-2.0-only PREFIX ?= /usr SBINDIR ?=
>
> > +sbin INSTALL ?= install CFLAGS += -D__EXPORTED_HEADERS__
>
> > +-I../../include/uapi -I../../include -I./
>
> > +
>
> > +TARGET = dell-wmi-sysman-example
>
> > +
>
> > +all: $(TARGET)
>
> > +
>
> > +%: %.c
>
> > +          $(CC) $(CFLAGS) $(LDFLAGS) -g -o $@ $<
>
> > +
>
> > +clean:
>
> > +          $(RM) $(TARGET)
>
> > +
>
> > +install: dell-wmi-sysman-example
>
> > +          $(INSTALL) -D -m 755 $(TARGET)
>
> > +$(DESTDIR)$(PREFIX)/$(SBINDIR)/$(TARGET)
>
> > +
>
> > diff --git a/tools/dell-wmi-sysman/dell-wmi-sysman-example.c
>
> > b/tools/dell-wmi-sysman/dell-wmi-sysman-example.c
>
> > new file mode 100644
>
> > index 000000000000..50db8835cea6
>
> > --- /dev/null
>
> > +++ b/tools/dell-wmi-sysman/dell-wmi-sysman-example.c
>
> > @@ -0,0 +1,432 @@
>
> > +// SPDX-License-Identifier: GPL-2.0-only
>
> > +/*
>
> > + *  Sample application for system management over WMI interface
>
> > + *  Performs the following:
>
> > + *  - Enemeration of all BIOS attributes present in system
>
> > + *  - Set BIOS atributes to user input or default
>
> > + *      - Reset BIOS
>
> > + *
>
> > + *  Copyright (C) 2021 Dell, Inc.
>
> > + *
>
> > + *  This program is free software; you can redistribute it and/or
>
> > +modify
>
> > + *  it under the terms of the GNU General Public License version 2 as
>
> > + *  published by the Free Software Foundation.
>
> > + */
>
> > +
>
> > +#include <errno.h>
>
> > +#include <fcntl.h>
>
> > +#include <stdio.h>
>
> > +#include <stdlib.h>
>
> > +#include <sys/ioctl.h>
>
> > +#include <unistd.h>
>
> > +#include <string.h>
>
> > +#include <ctype.h>
>
> > +
>
> > +/* if uapi header isn't installed, this might not yet exist */
>
> > +#ifndef __packed #define __packed __attribute__((packed)) #endif
>
> > +#include <linux/wmi.h>
>
> > +
>
> > +enum USER_OPTS {GET_ATTRS = 1, SET_ATTRS, SET_DEFS, PASS_MAN, RESET,
>
> > +EXIT }; enum PASS_OPTS {GET_PASSINFO = 1, SET_OR_CHANGE_PASS,
>
> > +CLEAR_PASS, BACK };
>
> > +
>
> > +static const char *ioctl_devfs = "/dev/wmi/dell-wmi-sysman";
>
> > +__u64 buff_size;
>
> > +
>
> > +static int query_buffer_size(__u64 *buffer_size) {
>
> > +          FILE *f = fopen(ioctl_devfs, "rb");
>
> > +
>
> > +          if (!f)
>
> > +                          return -EINVAL;
>
> > +          fread(buffer_size, sizeof(__u64), 1, f);
>
> > +          fclose(f);
>
> > +          return EXIT_SUCCESS;
>
> > +}
>
> > +
>
> > +int read_integer_input(void)
>
> > +{
>
> > +          int val, in, c;
>
> > +          char follow;
>
> > +
>
> > +          while (1) {
>
> > +                          in = scanf("%d%c", &val, &follow);
>
> > +                          if (in == 2) {
>
> > +                                          if (isspace(follow))
>
> > + return val;
>
> > +                                          printf("Invalid input! 
> Try again...\nEnter - ");
>
> > +                          } else if (in == 1) {
>
> > +                                          return val;
>
> > + printf("Invalid input! Try again...\nEnter - ");
>
> > +                          }
>
> > +
>
> > +                          while ((c = getchar()) != '\n' && c != EOF)
>
> > +                                          ;
>
> > +          }
>
> > +}
>
> > +
>
> > +static int call_ioctl(struct dell_wmi_sysman_buffer *buffer) {
>
> > +          int fd;
>
> > +          int ret;
>
> > +
>
> > +          fd = open(ioctl_devfs, O_NONBLOCK);
>
> > +          ret = ioctl(fd, DELL_WMI_SYSMAN_CMD, buffer);
>
> > +          close(fd);
>
> > +          return ret;
>
> > +}
>
> > +
>
> > +int is_password_set(unsigned char *password_type) {
>
> > +          int ret, i;
>
> > +          int is_set = 0;
>
> > +          struct dell_wmi_sysman_buffer *buff_pwd;
>
> > +          struct dell_password_data *indata;
>
> > +
>
> > +          buff_pwd = malloc(buff_size); //buff_size large enough to 
> get password data
>
> > +          if (buff_pwd == NULL) {
>
> > + printf("failed to alloc memory for ioctl\n");
>
> > +                          return -ENOMEM;
>
> > +          }
>
> > +
>
> > +          buff_pwd->length = buff_size;
>
> > +          buff_pwd->command = GET_PASS;
>
> > +          call_ioctl(buff_pwd);
>
> > +
>
> > +          indata = (struct dell_password_data *)buff_pwd->data;
>
> > +
>
> > +          for (i = 0; i < buff_pwd->count; i++) {
>
> > +                          if (strcmp(indata[i].attribute_name, 
> password_type) == 0) {
>
> > +                                          is_set = indata[i].is_set;
>
> > +                                          break;
>
> > +                          }
>
> > +          }
>
> > +
>
> > +          free(buff_pwd);
>
> > +          return is_set;
>
> > +}
>
> > +
>
> > +/* Enumerate functions start*/
>
> > +void display_attributes(struct dell_wmi_sysman_buffer *buff_all) {
>
> > +          struct dell_attributes_data *testdata;
>
> > +          int i;
>
> > +
>
> > +          testdata = (struct dell_attributes_data *)buff_all->data;
>
> > +          for (i = 0; i < buff_all->count; i++) {
>
> > + printf("\n%d\n", (i + 1));
>
> > + printf("AttributeName = %s\n", testdata[i].attribute_name);
>
> > + printf("Display LangCode = %s\n", 
> testdata[i].display_name_language_code);
>
> > + printf("Display Name = %s\n", testdata[i].display_name);
>
> > + printf("Modifier = %s\n", testdata[i].dell_modifier);
>
> > + printf("Current Value = %s\n", testdata[i].current_value);
>
> > + printf("Default Value = %s\n", testdata[i].default_value);
>
> > +                          if (testdata[i].type == ENUM) {
>
> > +                                          printf("Value Modifier = 
> %s\n", testdata[i].dell_value_modifier);
>
> > + printf("PossibleValues = %s\n", testdata[i].possible_values);
>
> > +                          }
>
> > +                          if (testdata[i].type == INT) {
>
> > +                                          printf("Lower Bound = 
> %d\n", testdata[i].min);
>
> > +                                          printf("Upper Bound = 
> %d\n", testdata[i].max);
>
> > +                                          printf("Scalar incr = 
> %d\n", testdata[i].scalar_increment);
>
> > +                          }
>
> > +                          if (testdata[i].type == STR) {
>
> > +                                          printf("Minimum Length = 
> %d\n", testdata[i].min);
>
> > +                                          printf("Maximum Length = 
> %d\n", testdata[i].max);
>
> > +                          }
>
> > +          }
>
> > +
>
> > +printf("---------------------------------------------------------\n")
>
> > +;
>
> > +}
>
> > +
>
> > +void enumerate_all_attributes(void)
>
> > +{
>
> > +          struct dell_wmi_sysman_buffer *buff_all;
>
> > +          int ret;
>
> > +
>
> > +          buff_all = malloc(buff_size);
>
> > +          if (buff_all == NULL) {
>
> > + printf("failed to alloc memory for ioctl\n");
>
> > + return;
>
> > +          }
>
> > +          buff_all->length = buff_size;
>
> > +          buff_all->command = ENUMERATE_ALL;
>
> > +          ret = call_ioctl(buff_all);
>
> > +          if (ret) {
>
> > + printf("smbios ioctl failed: %d\n", ret);
>
> > +                          goto out;
>
> > +          }
>
> > + display_attributes(buff_all);
>
> > +out:
>
> > +          if (buff_all != NULL)
>
> > + free(buff_all);
>
> > +}
>
> > +/* Enumerate functions end*/
>
> > +
>
> > +/* SET functions start */
>
> > +int read_set_data(struct dell_wmi_sysman_buffer *buff_set, int
>
> > +option) {
>
> > +          int i, admin_pwd_set;
>
> > +          struct dell_set_data *indata;
>
> > +
>
> > +          admin_pwd_set = is_password_set("Admin");
>
> > +          if (admin_pwd_set < 0) {
>
> > + printf("check password call failed!!!\n");
>
> > +                          return EXIT_FAILURE;
>
> > +          }
>
> > +
>
> > +          printf("How many attributes to set: ");
>
> > +          scanf("%d", &buff_set->count);
>
> > +
>
> > +          indata = (struct dell_set_data *)buff_set->data;
>
> > +
>
> > +          if (admin_pwd_set) {
>
> > + printf("Admin password is set, please enter password - ");
>
> > + scanf("%s", buff_set->admin_password);
>
> > +          }
>
> > +
>
> > +          for (i = 0; i < buff_set->count; i++) {
>
> > + printf("Enter Attribute Name: ");
>
> > + scanf("%s", indata[i].attribute_name);
>
> > +
>
> > +                          if (option == SET_ATTRIBUTES) {
>
> > +                                          printf("Enter Attribute 
> Value: ");
>
> > +                                          scanf("%s", 
> indata[i].attribute_value);
>
> > +                          }
>
> > +          }
>
> > +          return 0;
>
> > +}
>
> > +
>
> > +void call_set_cmd(int cmd_opt)
>
> > +{
>
> > +          int i, ret;
>
> > +          struct dell_wmi_sysman_buffer *buff_set;
>
> > +
>
> > +          buff_set = malloc(buff_size);
>
> > +          if (buff_set == NULL) {
>
> > + printf("failed to alloc memory for ioctl\n");
>
> > + return;
>
> > +          }
>
> > +          buff_set->length = buff_size;
>
> > +          buff_set->command = cmd_opt;
>
> > +          if (read_set_data(buff_set, cmd_opt))
>
> > +                          goto out;
>
> > +
>
> > +          ret = call_ioctl(buff_set);
>
> > +          if (!ret) {
>
> > + printf("Set Successful...\n");
>
> > +                          goto out;
>
> > +          }
>
> > +          printf("Set failed: %d\n", ret);
>
> > +out:
>
> > +          free(buff_set);
>
> > +}
>
> > +/* SET functions end */
>
> > +
>
> > +/* Password related functions start */ void get_password_info(void) {
>
> > +          int i;
>
> > +          struct dell_wmi_sysman_buffer *buff_pwd;
>
> > +          struct dell_password_data *testdata;
>
> > +
>
> > +          buff_pwd = malloc(buff_size); //buff_size large enough to 
> get password data
>
> > +          if (buff_pwd == NULL) {
>
> > + printf("failed to alloc memory for ioctl\n");
>
> > + return;
>
> > +          }
>
> > +          buff_pwd->length = buff_size;
>
> > +          buff_pwd->command = GET_PASS;
>
> > +          if (call_ioctl(buff_pwd)) {
>
> > + free(buff_pwd);
>
> > + printf("smbios ioctl failed!!!\n");
>
> > + return;
>
> > +          }
>
> > +
>
> > +          testdata = (struct dell_password_data *)buff_pwd->data;
>
> > +          for (i = 0; i < buff_pwd->count; i++) {
>
> > + printf("\n%d\n", (i + 1));
>
> > + printf("AttributeName = %s\n", testdata[i].attribute_name);
>
> > + printf("Minimum Length = %d\n", testdata[i].min_length);
>
> > + printf("Maximum Length = %d\n", testdata[i].max_length);
>
> > + printf("Is Password Set = %d\n", testdata[i].is_set);
>
> > +          }
>
> > +          if (buff_pwd != NULL)
>
> > + free(buff_pwd);
>
> > +}
>
> > +
>
> > +void call_set_pasword_cmd(int clear_opt) {
>
> > +          int ret, is_admin_pwd_set, is_system_pwd_set;
>
> > +          struct dell_wmi_sysman_buffer *buff_pwd;
>
> > +          struct dell_set_password *indata;
>
> > +
>
> > +          buff_pwd = malloc(buff_size); //buff_size large enough to 
> get password data
>
> > +          if (buff_pwd == NULL) {
>
> > + printf("failed to alloc memory for ioctl\n");
>
> > + return;
>
> > +          }
>
> > +          buff_pwd->length = buff_size;
>
> > +          buff_pwd->command = SET_PASS;
>
> > +          is_admin_pwd_set = is_password_set("Admin");
>
> > +          is_system_pwd_set = is_password_set("System");
>
> > +          if ((is_admin_pwd_set < 0) || (is_system_pwd_set < 0)) {
>
> > + printf("check password call failed!!!\n");
>
> > +                          goto out;
>
> > +          }
>
> > +
>
> > +          indata = (struct dell_set_password *)buff_pwd->data;
>
> > +
>
> > +          if (is_admin_pwd_set) {
>
> > + printf("Admin password is set, please enter current admin password 
> - ");
>
> > + scanf("%s", buff_pwd->admin_password);
>
> > +          }
>
> > +
>
> > +          printf("Enter which password to set Admin/System - ");
>
> > +          scanf("%s", indata->attribute_name);
>
> > +
>
> > +          if (strcmp(indata->attribute_name, "System") == 0 && 
> (is_system_pwd_set)) {
>
> > + printf("System password is set, please enter current system 
> password - ");
>
> > + scanf("%s", indata->system_password);
>
> > +          }
>
> > +
>
> > +          if (clear_opt == 3) {
>
> > + strcpy(indata->new_password, "");
>
> > +          } else {
>
> > + printf("Enter new password - ");
>
> > + scanf("%s", indata->new_password);
>
> > +          }
>
> > +          ret = call_ioctl(buff_pwd);
>
> > +          if (!ret) {
>
> > + printf("Set Successful...\n");
>
> > +                          ret = EXIT_SUCCESS;
>
> > +                          goto out;
>
> > +          }
>
> > +          printf("Set failed: %d\n", ret);
>
> > +out:
>
> > +          free(buff_pwd);
>
> > +}
>
> > +
>
> > +void call_password_management(void)
>
> > +{
>
> > +          int opt, ret;
>
> > +
>
> > +          while (1) {
>
> > + printf("\n##############################\n");
>
> > + printf(" Password Management Menu\t\n");
>
> > + printf("##############################\n");
>
> > + printf("\n1 - Get Password Information\n"
>
> > + "2 - Set/Change Password\n"
>
> > + "3 - Clear Password\n"
>
> > + "4 - Go to back to Main Menu\n\n"
>
> > + "Enter - ");
>
> > +                          opt = read_integer_input();
>
> > +
>
> > +                          switch (opt) {
>
> > +                          case GET_PASSINFO:
>
> > + get_password_info();
>
> > +                                          break;
>
> > +                          case SET_OR_CHANGE_PASS:
>
> > +                          case CLEAR_PASS:
>
> > + call_set_pasword_cmd(opt);
>
> > +                                          break;
>
> > +                          case BACK:
>
> > +                                          return;
>
> > + default:
>
> > +                                          printf("Invalid option!\n");
>
> > +                                          break;
>
> > +                          }
>
> > +          }
>
> > +}
>
> > +/* Password related functions end */
>
> > +
>
> > +void call_reset_bios(void)
>
> > +{
>
> > +          struct dell_resetBIOS *buff_reset;
>
> > +          unsigned char reset_option;
>
> > +          int fd, ret, is_admin_pwd_set;
>
> > +
>
> > +          printf("\nReset Options:\n"
>
> > +                                          "0 - Built-in Safe 
> Defaults\n"
>
> > +                                          "1 - Last Known Good\n"
>
> > +                                          "2 - Factory\n"
>
> > +                                          "3 - Custom\n\n"
>
> > +                                          "Enter - ");
>
> > +          scanf("%hhu", &reset_option);
>
> > +          buff_reset = malloc(buff_size);
>
> > +          if (buff_reset == NULL) {
>
> > + printf("failed to alloc memory for ioctl\n");
>
> > + return;
>
> > +          }
>
> > +          is_admin_pwd_set = is_password_set("Admin");
>
> > +          if ((is_admin_pwd_set < 0)) {
>
> > + printf("check password call failed!!!\n");
>
> > +                          goto out;
>
> > +          }
>
> > +
>
> > +          buff_reset->length = buff_size;
>
> > +          if (is_admin_pwd_set) {
>
> > + printf("Admin password is set, please enter current admin password 
> - ");
>
> > + scanf("%s", buff_reset->admin_password);
>
> > +          }
>
> > +          fd = open(ioctl_devfs, O_NONBLOCK);
>
> > +          ret = ioctl(fd, DELL_WMI_SYSMAN_RESET_BIOS, buff_reset);
>
> > +          close(fd);
>
> > +          if (!ret) {
>
> > + printf("Reset Successful. Reboot the system\n");
>
> > +                          ret = EXIT_SUCCESS;
>
> > +                          goto out;
>
> > +          }
>
> > +          printf("Reset Failed: %d\n", ret);
>
> > +out:
>
> > +          if (buff_reset != NULL)
>
> > + free(buff_reset);
>
> > +}
>
> > +
>
> > +int main(void)
>
> > +{
>
> > +          int ret, opt;
>
> > +          __u64 value = 0;
>
> > +
>
> > +          ret = query_buffer_size(&value);
>
> > +          if (ret == EXIT_FAILURE || !value) {
>
> > + printf("Unable to read buffer size\n");
>
> > +                          return ret;
>
> > +          }
>
> > +          buff_size = value;
>
> > +          while (1) {
>
> > + printf("\n\n\n##############################\n");
>
> > + printf("Dell BIOS System Management Utility\n");
>
> > + printf("##############################\n");
>
> > + printf("\n1 - Enumerate All Attributes\n"
>
> > + "2 - Set Attributes\n"
>
> > + "3 - Set To Defaults\n"
>
> > + "4 - Password Management\n"
>
> > + "5 - Reset BIOS\n"
>
> > + "6 - Exit\n"
>
> > + "\n\nEnter - ");
>
> > +                          opt = read_integer_input();
>
> > +
>
> > +                          switch (opt) {
>
> > +                          case GET_ATTRS:
>
> > + enumerate_all_attributes();
>
> > +                                          break;
>
> > +                          case SET_ATTRS:
>
> > +                          case SET_DEFS:
>
> > + call_set_cmd(opt);
>
> > +                                          break;
>
> > +                          case PASS_MAN:
>
> > + call_password_management();
>
> > +                                          break;
>
> > +                          case RESET:
>
> > + call_reset_bios();
>
> > +                                          break;
>
> > +                          case EXIT:
>
> > +                                          exit(0);
>
> > +                                          break;
>
> > + default:
>
> > +                                          break;
>
> > +                          }
>
> > +          }
>
> > +          return 0;
>
> > +}
>
> >
>

Prasanth K S R

On 09/02/21 11:27 pm, Hans de Goede wrote:
> Hi,
>
> On 2/9/21 3:28 PM, Prasanth, KSR wrote:
>> From: "Prasanth KSR" <prasanth.ksr@dell.com>
>>
>> Perform BIOS Management calls on supported Dell machines
>> through the Dell WMI System Management interface.
>>
>> This interface provides IOCTL's to perform bundled
>> BIOS Setting transactions.
> Why?
>
> Adding new userspace API is not something which we do without
> a very good reason for it.
>
> We spend a lot of time on reviewing the sysfs API for this, so
> I must say that I'm quite surprised to now see an IOCTL API
> being proposed on top of the existing sysfs API.
>
> This is going to need a long explanation why this is necessary
> over the existing sysfs API.
>
> To be honest ATM I'm not inclined to accept this patch and
> it is going to take some very strong arguments to change my
> mind.
>
> Regards,
>
> Hans
>
>
>
>
>> Cc: Hans de Goede <hdegoede@redhat.com>
>>
>> Signed-off-by: Prasanth KSR <prasanth.ksr@dell.com>
>> Co-developed-by: Divya Bharathi <divya.bharathi@dell.com>
>> Signed-off-by: Divya Bharathi <divya.bharathi@dell.com>
>> Co-developed-by: Mario Limonciello <mario.limonciello@dell.com>
>> Signed-off-by: Mario Limonciello <mario.limonciello@dell.com>
>> ---
>>   Documentation/ABI/testing/dell-wmi-sysman     |  39 ++
>>   .../x86/dell-wmi-sysman/biosattr-interface.c  | 257 +++++++++--
>>   .../x86/dell-wmi-sysman/dell-wmi-sysman.h     |  20 +-
>>   .../x86/dell-wmi-sysman/enum-attributes.c     |  45 +-
>>   .../x86/dell-wmi-sysman/int-attributes.c      |  46 +-
>>   .../x86/dell-wmi-sysman/passobj-attributes.c  |  23 +
>>   .../x86/dell-wmi-sysman/string-attributes.c   |  50 +-
>>   drivers/platform/x86/dell-wmi-sysman/sysman.c |  48 +-
>>   include/uapi/linux/wmi.h                      |  56 +++
>>   tools/dell-wmi-sysman/Makefile                |  19 +
>>   .../dell-wmi-sysman/dell-wmi-sysman-example.c | 432 ++++++++++++++++++
>>   11 files changed, 946 insertions(+), 89 deletions(-)
>>   create mode 100644 Documentation/ABI/testing/dell-wmi-sysman
>>   create mode 100644 tools/dell-wmi-sysman/Makefile
>>   create mode 100644 tools/dell-wmi-sysman/dell-wmi-sysman-example.c
>>
>> diff --git a/Documentation/ABI/testing/dell-wmi-sysman b/Documentation/ABI/testing/dell-wmi-sysman
>> new file mode 100644
>> index 000000000000..4f3883529a06
>> --- /dev/null
>> +++ b/Documentation/ABI/testing/dell-wmi-sysman
>> @@ -0,0 +1,39 @@
>> +What:		/dev/wmi/dell-wmi-sysman
>> +Date:		November 2021
>> +KernelVersion:	5.15
>> +Contact:	"Divya Bharathi" <divya.bharathi@dell.com>
>> +		"Mario Limonciello" <mario.limonciello@dell.com>
>> +		"Prasanth K S R" <prasanth.ksr@dell.com>
>> +Description:
>> +		Perform BIOS Management calls on supported Dell machines
>> +		through the Dell WMI System Management interface.
>> +
>> +		This interface provides IOCTL's to perform bundled
>> +		BIOS Setting transactions.
>> +
>> +		IOCTL's and buffer formats are defined in:
>> +		<uapi/linux/wmi.h>
>> +
>> +		1) To perform a BIOS System Management call from userspace,
>> +		you'll need to first determine the minimum size of the
>> +		system management interface buffer for your machine.
>> +		Platforms that contain larger buffers can return larger
>> +		objects from the system firmware.
>> +		Commonly this size is either 4k or 32k.
>> +
>> +		To determine the size of the buffer read() a u64 dword from
>> +		the WMI character device /dev/wmi/dell-wmi-sysman.
>> +
>> +		2) After you've determined the minimum size of the system management
>> +		interface buffer, you can allocate a structure that represents
>> +		the structure documented above (struct dell_wmi_sysman_buffer).
>> +
>> +		3) In this buffer object, prepare as necessary for the BIOS System
>> +		Management call you're interested in. Typically System Management
>> +		buffers have "length", "command" , "count" and "admin_password"
>> +		defined to values that coincide with the "data" you are interested in.
>> +
>> +		4) Run the call by using ioctl() as described in the header.
>> +
>> +		5) The output will be returned in the buffer object and
>> +		make sure to free up the allocated buffer.
>> diff --git a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
>> index f95d8ddace5a..9a82e78fe59e 100644
>> --- a/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
>> +++ b/drivers/platform/x86/dell-wmi-sysman/biosattr-interface.c
>> @@ -6,12 +6,14 @@
>>    *  Copyright (c) 2020 Dell Inc.
>>    */
>>   
>> +#include <uapi/linux/wmi.h>
>>   #include <linux/wmi.h>
>>   #include "dell-wmi-sysman.h"
>>   
>>   #define SETDEFAULTVALUES_METHOD_ID					0x02
>>   #define SETBIOSDEFAULTS_METHOD_ID					0x03
>>   #define SETATTRIBUTE_METHOD_ID						0x04
>> +#define SETATTRIBUTES_METHOD_ID						0x05
>>   
>>   static int call_biosattributes_interface(struct wmi_device *wdev, char *in_args, size_t size,
>>   					int method_id)
>> @@ -41,17 +43,17 @@ static int call_biosattributes_interface(struct wmi_device *wdev, char *in_args,
>>   }
>>   
>>   /**
>> - * set_attribute() - Update an attribute value
>> - * @a_name: The attribute name
>> - * @a_value: The attribute value
>> + * set_bios_defaults() - Resets BIOS defaults
>> + * @deftype: the type of BIOS value reset to issue.
>>    *
>> - * Sets an attribute to new value
>> + * Resets BIOS defaults
>>    */
>> -int set_attribute(const char *a_name, const char *a_value)
>> +int set_bios_defaults(u8 deftype)
>>   {
>>   	size_t security_area_size, buffer_size;
>> -	size_t a_name_size, a_value_size;
>> -	char *buffer = NULL, *start;
>> +	size_t integer_area_size = sizeof(u8);
>> +	char *buffer = NULL;
>> +	u8 *defaultType;
>>   	int ret;
>>   
>>   	mutex_lock(&wmi_priv.mutex);
>> @@ -60,11 +62,8 @@ int set_attribute(const char *a_name, const char *a_value)
>>   		goto out;
>>   	}
>>   
>> -	/* build/calculate buffer */
>>   	security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
>> -	a_name_size = calculate_string_buffer(a_name);
>> -	a_value_size = calculate_string_buffer(a_value);
>> -	buffer_size = security_area_size + a_name_size + a_value_size;
>> +	buffer_size = security_area_size + integer_area_size;
>>   	buffer = kzalloc(buffer_size, GFP_KERNEL);
>>   	if (!buffer) {
>>   		ret = -ENOMEM;
>> @@ -74,44 +73,51 @@ int set_attribute(const char *a_name, const char *a_value)
>>   	/* build security area */
>>   	populate_security_buffer(buffer, wmi_priv.current_admin_password);
>>   
>> -	/* build variables to set */
>> -	start = buffer + security_area_size;
>> -	ret = populate_string_buffer(start, a_name_size, a_name);
>> -	if (ret < 0)
>> -		goto out;
>> -	start += ret;
>> -	ret = populate_string_buffer(start, a_value_size, a_value);
>> -	if (ret < 0)
>> -		goto out;
>> +	defaultType = buffer + security_area_size;
>> +	*defaultType = deftype;
>>   
>> -	print_hex_dump_bytes("set attribute data: ", DUMP_PREFIX_NONE, buffer, buffer_size);
>> -	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev,
>> -					    buffer, buffer_size,
>> -					    SETATTRIBUTE_METHOD_ID);
>> -	if (ret == -EOPNOTSUPP)
>> -		dev_err(&wmi_priv.bios_attr_wdev->dev, "admin password must be configured\n");
>> -	else if (ret == -EACCES)
>> -		dev_err(&wmi_priv.bios_attr_wdev->dev, "invalid password\n");
>> +	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, buffer_size,
>> +					    SETBIOSDEFAULTS_METHOD_ID);
>> +	if (ret)
>> +		dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults failed: %d\n", ret);
>>   
>> -out:
>>   	kfree(buffer);
>> +out:
>>   	mutex_unlock(&wmi_priv.mutex);
>>   	return ret;
>>   }
>>   
>>   /**
>> - * set_bios_defaults() - Resets BIOS defaults
>> - * @deftype: the type of BIOS value reset to issue.
>> + * calculate_array_length() - calculate total size of string array
>> + * @str_arr: array of strings
>> + * @str_count: string count
>>    *
>> - * Resets BIOS defaults
>> - */
>> -int set_bios_defaults(u8 deftype)
>> + * Method to calculate the total size of array of string
>> + **/
>> +static int calculate_array_length(char **str_arr, int str_count)
>>   {
>> -	size_t security_area_size, buffer_size;
>> -	size_t integer_area_size = sizeof(u8);
>> -	char *buffer = NULL;
>> -	u8 *defaultType;
>> -	int ret;
>> +	int ret = 0, i;
>> +
>> +	for (i = 0; i < str_count; ++i)
>> +		ret += calculate_string_buffer(str_arr[i]);
>> +	return ret;
>> +}
>> +
>> +/**
>> + * set_attributes() - Update multiple attribute values
>> + * @in_data: input set data
>> + * @a_count: Number of atributes to be set
>> + * @command: command to decide set user input value or default
>> + *
>> + * Sets attributes to user input value of defaut value
>> + **/
>> +int set_attributes(struct dell_set_data *in_data, int a_count, unsigned short command)
>> +{
>> +	size_t security_area_size, string_area_size, buffer_size, attr_count_area;
>> +	char **a_names, **a_values;
>> +	char *buffer = NULL, *start;
>> +	int ret, method_id, i;
>> +	u32 *attr_count;
>>   
>>   	mutex_lock(&wmi_priv.mutex);
>>   	if (!wmi_priv.bios_attr_wdev) {
>> @@ -119,8 +125,34 @@ int set_bios_defaults(u8 deftype)
>>   		goto out;
>>   	}
>>   
>> +	//allocate memory to hold set inputs
>> +	a_names = kmalloc(a_count * (sizeof(char *)), GFP_KERNEL);
>> +	if (!a_names) {
>> +		ret = -ENOMEM;
>> +		goto out;
>> +	}
>> +	if (command == SET_ATTRIBUTES) {
>> +		a_values = kmalloc(a_count * (sizeof(char *)), GFP_KERNEL);
>> +		if (!a_values) {
>> +			ret = -ENOMEM;
>> +			goto out;
>> +		}
>> +	}
>> +
>> +	//assign inputs to single array and send to set functions
>> +	for (i = 0; i < a_count; i++) {
>> +		a_names[i] = in_data[i].attribute_name;
>> +		if (command == SET_ATTRIBUTES)
>> +			a_values[i] = in_data[i].attribute_value;
>> +	}
>> +
>>   	security_area_size = calculate_security_buffer(wmi_priv.current_admin_password);
>> -	buffer_size = security_area_size + integer_area_size;
>> +	attr_count_area = sizeof(u32);
>> +	string_area_size = (calculate_array_length(a_names, a_count));
>> +	if (command == SET_ATTRIBUTES)
>> +		string_area_size += (calculate_array_length(a_values, a_count));
>> +	buffer_size = security_area_size + attr_count_area + string_area_size
>> +					+ (sizeof(u16) * a_count);
>>   	buffer = kzalloc(buffer_size, GFP_KERNEL);
>>   	if (!buffer) {
>>   		ret = -ENOMEM;
>> @@ -130,26 +162,153 @@ int set_bios_defaults(u8 deftype)
>>   	/* build security area */
>>   	populate_security_buffer(buffer, wmi_priv.current_admin_password);
>>   
>> -	defaultType = buffer + security_area_size;
>> -	*defaultType = deftype;
>> +	/* build variables to set */
>> +	attr_count = (u32 *)(buffer + security_area_size);
>> +	*attr_count = (u32)a_count;
>> +	start =  (u8 *)(attr_count) + attr_count_area;
>>   
>> -	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, buffer_size,
>> -					    SETBIOSDEFAULTS_METHOD_ID);
>> -	if (ret)
>> -		dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults failed: %d\n", ret);
>> +	for (i = 0; i < a_count; i++) {
>> +		ret = populate_string_buffer(start, calculate_string_buffer(a_names[i]),
>> +						a_names[i]);
>> +		if (ret < 0)
>> +			goto out;
>> +		start += ret;
>> +	}
>> +
>> +	if (command == SET_ATTRIBUTES) {
>> +		for (i = 0; i < a_count; i++) {
>> +			ret = populate_string_buffer(start, calculate_string_buffer(a_values[i]),
>> +							a_values[i]);
>> +			if (ret < 0)
>> +				goto out;
>> +			start += ret;
>> +		}
>> +		method_id = SETATTRIBUTES_METHOD_ID;
>> +	} else {
>> +		method_id = SETDEFAULTVALUES_METHOD_ID;
>> +	}
>> +
>> +	print_hex_dump_bytes("set multiple attribute: ", DUMP_PREFIX_NONE, buffer, buffer_size);
>> +	ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev,
>> +					    buffer, buffer_size, method_id);
>> +
>> +	if (ret == -EOPNOTSUPP)
>> +		dev_err(&wmi_priv.password_attr_wdev->dev, "admin password must be configured\n");
>> +	else if (ret == -EACCES)
>> +		dev_err(&wmi_priv.password_attr_wdev->dev, "invalid password\n");
>>   
>> -	kfree(buffer);
>>   out:
>> +	kfree(buffer);
>> +	kfree(a_names);
>> +	if (command == SET_ATTRIBUTES)
>> +		kfree(a_values);
>>   	mutex_unlock(&wmi_priv.mutex);
>>   	return ret;
>>   }
>>   
>> +__u64 get_attrs_size(void)
>> +{
>> +	__u64 size = sizeof(struct dell_attributes_data) *
>> +				(get_instance_count(DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID) +
>> +				get_instance_count(DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID) +
>> +				get_instance_count(DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID));
>> +	return size;
>> +}
>> +
>> +int run_sysman_call(struct dell_wmi_sysman_buffer *buf)
>> +{
>> +	struct dell_set_password *pass_set_data;
>> +	struct dell_set_data *in_data;
>> +	int ret = -ENOIOCTLCMD;
>> +	char *tmp_system = NULL;
>> +	char *tmp_admin = NULL;
>> +
>> +	switch (buf->command) {
>> +	case ENUMERATE_ALL:
>> +		buf->count = get_attrs_size() / sizeof(struct dell_attributes_data);
>> +		get_enumeration_data(buf);
>> +		get_integer_data(buf);
>> +		get_string_data(buf);
>> +		ret = 0;
>> +		break;
>> +	case SET_ATTRIBUTES:
>> +	case SET_DEFAULTS:
>> +		if (!buf->count)
>> +			goto out;
>> +		in_data = (struct dell_set_data *)buf->data;
>> +		tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
>> +		strlcpy_attr(wmi_priv.current_admin_password, buf->admin_password);
>> +		ret = set_attributes(in_data, buf->count, buf->command);
>> +		strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
>> +		kfree(tmp_admin);
>> +		break;
>> +	case GET_PASS:
>> +		get_po_data(buf);
>> +		ret = 0;
>> +		break;
>> +	case SET_PASS:
>> +		pass_set_data = (struct dell_set_password *)buf->data;
>> +		tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
>> +		strlcpy_attr(wmi_priv.current_admin_password, buf->admin_password);
>> +
>> +		if (strcmp(pass_set_data->attribute_name, "System") == 0) {
>> +			tmp_system = kstrdup(wmi_priv.current_system_password, GFP_KERNEL);
>> +			strlcpy_attr(wmi_priv.current_system_password,
>> +					pass_set_data->system_password);
>> +		}
>> +
>> +		ret = set_new_password(pass_set_data->attribute_name, pass_set_data->new_password);
>> +		strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
>> +		kfree(tmp_admin);
>> +
>> +		if (tmp_system != NULL) {
>> +			strlcpy_attr(wmi_priv.current_system_password, tmp_system);
>> +			kfree(tmp_system);
>> +		}
>> +		break;
>> +	}
>> +out:
>> +	return ret;
>> +}
>> +
>> +
>> +static long bios_attr_set_interface_filter(struct wmi_device *wdev, unsigned int cmd,
>> +				   struct wmi_ioctl_buffer *arg)
>> +{
>> +	struct dell_wmi_sysman_buffer *buf;
>> +	struct dell_resetBIOS *reset_buf;
>> +	char *tmp_admin = NULL;
>> +	int ret = -ENOIOCTLCMD;
>> +
>> +	switch (cmd) {
>> +	case DELL_WMI_SYSMAN_CMD:
>> +		buf = (struct dell_wmi_sysman_buffer *) arg;
>> +		ret = run_sysman_call(buf);
>> +		break;
>> +	case DELL_WMI_SYSMAN_RESET_BIOS:
>> +		reset_buf = (struct dell_resetBIOS *) arg;
>> +		if (reset_buf->option > 0) {
>> +			tmp_admin = kstrdup(wmi_priv.current_admin_password, GFP_KERNEL);
>> +			strlcpy_attr(wmi_priv.current_admin_password, reset_buf->admin_password);
>> +			ret = set_bios_defaults(reset_buf->option);
>> +			strlcpy_attr(wmi_priv.current_admin_password, tmp_admin);
>> +			kfree(tmp_admin);
>> +		}
>> +		break;
>> +	}
>> +	return ret;
>> +}
>> +
>>   static int bios_attr_set_interface_probe(struct wmi_device *wdev, const void *context)
>>   {
>> +	__u32 req_buf_size;
>>   	mutex_lock(&wmi_priv.mutex);
>>   	wmi_priv.bios_attr_wdev = wdev;
>>   	mutex_unlock(&wmi_priv.mutex);
>> -	return 0;
>> +	req_buf_size = get_attrs_size();
>> +	/* add in size of struct dell_wmi_sysman_buffer which is used internally with ioctl */
>> +	req_buf_size += sizeof(struct dell_wmi_sysman_buffer);
>> +	return set_required_buffer_size(wdev, req_buf_size);
>>   }
>>   
>>   static int bios_attr_set_interface_remove(struct wmi_device *wdev)
>> @@ -171,6 +330,7 @@ static struct wmi_driver bios_attr_set_interface_driver = {
>>   	.probe = bios_attr_set_interface_probe,
>>   	.remove = bios_attr_set_interface_remove,
>>   	.id_table = bios_attr_set_interface_id_table,
>> +	.filter_callback = bios_attr_set_interface_filter
>>   };
>>   
>>   int init_bios_attr_set_interface(void)
>> @@ -184,3 +344,4 @@ void exit_bios_attr_set_interface(void)
>>   }
>>   
>>   MODULE_DEVICE_TABLE(wmi, bios_attr_set_interface_id_table);
>> +
>> diff --git a/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h b/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
>> index b80f2a62ea3f..13c216e6ddec 100644
>> --- a/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
>> +++ b/drivers/platform/x86/dell-wmi-sysman/dell-wmi-sysman.h
>> @@ -8,6 +8,7 @@
>>   #define _DELL_WMI_BIOS_ATTR_H_
>>   
>>   #include <linux/wmi.h>
>> +#include <uapi/linux/wmi.h>
>>   #include <linux/device.h>
>>   #include <linux/module.h>
>>   #include <linux/kernel.h>
>> @@ -87,8 +88,6 @@ struct wmi_sysman_priv {
>>   /* global structure used by multiple WMI interfaces */
>>   extern struct wmi_sysman_priv wmi_priv;
>>   
>> -enum { ENUM, INT, STR, PO };
>> -
>>   enum {
>>   	ATTR_NAME,
>>   	DISPL_NAME_LANG_CODE,
>> @@ -134,6 +133,7 @@ static ssize_t curr_val##_store(struct kobject *kobj,				\
>>   				struct kobj_attribute *attr,			\
>>   				const char *buf, size_t count)			\
>>   {										\
>> +	struct dell_set_data *set_data;						\
>>   	char *p, *buf_cp;							\
>>   	int i, ret = -EIO;							\
>>   	buf_cp = kstrdup(buf, GFP_KERNEL);					\
>> @@ -146,15 +146,19 @@ static ssize_t curr_val##_store(struct kobject *kobj,				\
>>   	i = get_##type##_instance_id(kobj);					\
>>   	if (i >= 0)								\
>>   		ret = validate_##type##_input(i, buf_cp);			\
>> +	set_data = kzalloc(sizeof(*set_data), GFP_KERNEL);			\
>> +	strlcpy_attr(set_data[0].attribute_value, buf_cp);			\
>> +	strlcpy_attr(set_data[0].attribute_name, kobj->name);			\
>>   	if (!ret)								\
>> -		ret = set_attribute(kobj->name, buf_cp);			\
>> +		ret = set_attributes(set_data, 1, SET_ATTRIBUTES);		\
>>   	kfree(buf_cp);								\
>>   	return ret ? ret : count;						\
>>   }
>>   
>>   union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string);
>>   int get_instance_count(const char *guid_string);
>> -void strlcpy_attr(char *dest, char *src);
>> +int get_current_value(char *buf, int instance_id, const char *guid_string);
>> +void strlcpy_attr(char *dest, const char *src);
>>   
>>   int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
>>   			struct kobject *attr_name_kobj);
>> @@ -174,7 +178,7 @@ int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject
>>   int alloc_po_data(void);
>>   void exit_po_attributes(void);
>>   
>> -int set_attribute(const char *a_name, const char *a_value);
>> +int set_attributes(struct dell_set_data *in_data, int a_count, unsigned short command);
>>   int set_bios_defaults(u8 defType);
>>   
>>   void exit_bios_attr_set_interface(void);
>> @@ -188,4 +192,10 @@ int set_new_password(const char *password_type, const char *new);
>>   int init_bios_attr_pass_interface(void);
>>   void exit_bios_attr_pass_interface(void);
>>   
>> +__u64 get_attrs_size(void);
>> +void get_enumeration_data(struct dell_wmi_sysman_buffer *buf);
>> +void get_integer_data(struct dell_wmi_sysman_buffer *buf);
>> +void get_string_data(struct dell_wmi_sysman_buffer *buf);
>> +void get_po_data(struct dell_wmi_sysman_buffer *attr_data);
>> +
>>   #endif
>> diff --git a/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c b/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
>> index 80f4b7785c6c..b23e10ac00da 100644
>> --- a/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
>> +++ b/drivers/platform/x86/dell-wmi-sysman/enum-attributes.c
>> @@ -13,22 +13,17 @@ get_instance_id(enumeration);
>>   static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
>>   {
>>   	int instance_id = get_enumeration_instance_id(kobj);
>> -	union acpi_object *obj;
>> -	ssize_t ret;
>> +	int ret;
>>   
>>   	if (instance_id < 0)
>>   		return instance_id;
>>   
>> -	/* need to use specific instance_id and guid combination to get right data */
>> -	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
>> -	if (!obj)
>> -		return -EIO;
>> -	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) {
>> -		kfree(obj);
>> -		return -EINVAL;
>> +	ret = get_current_value(buf, instance_id, DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
>> +	if (ret > 0) {
>> +		strcat(buf, "\n");
>> +		return strlen(buf);
>>   	}
>> -	ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
>> -	kfree(obj);
>> +	/* read error */
>>   	return ret;
>>   }
>>   
>> @@ -171,6 +166,34 @@ int populate_enum_data(union acpi_object *enumeration_obj, int instance_id,
>>   	return sysfs_create_group(attr_name_kobj, &enumeration_attr_group);
>>   }
>>   
>> +void get_enumeration_data(struct dell_wmi_sysman_buffer *buf)
>> +{
>> +	struct dell_attributes_data *attr_data;
>> +	int i;
>> +
>> +	attr_data = (struct dell_attributes_data *)buf->data;
>> +	for (i = 0; i < wmi_priv.enumeration_instances_count; i++) {
>> +		attr_data[i].type = ENUM;
>> +		strlcpy_attr(attr_data[i].attribute_name,
>> +					wmi_priv.enumeration_data[i].attribute_name);
>> +		strlcpy_attr(attr_data[i].display_name,
>> +					wmi_priv.enumeration_data[i].display_name);
>> +		strlcpy_attr(attr_data[i].display_name_language_code,
>> +					wmi_priv.enumeration_data[i].display_name_language_code);
>> +		strlcpy_attr(attr_data[i].possible_values,
>> +					wmi_priv.enumeration_data[i].possible_values);
>> +		strlcpy_attr(attr_data[i].dell_modifier,
>> +					wmi_priv.enumeration_data[i].dell_modifier);
>> +		strlcpy_attr(attr_data[i].dell_value_modifier,
>> +					wmi_priv.enumeration_data[i].dell_value_modifier);
>> +		strlcpy_attr(attr_data[i].default_value,
>> +					wmi_priv.enumeration_data[i].default_value);
>> +		get_current_value(attr_data[i].current_value, i,
>> +					DELL_WMI_BIOS_ENUMERATION_ATTRIBUTE_GUID);
>> +
>> +	}
>> +}
>> +
>>   /**
>>    * exit_enum_attributes() - Clear all attribute data
>>    *
>> diff --git a/drivers/platform/x86/dell-wmi-sysman/int-attributes.c b/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
>> index 75aedbb733be..0155f6189576 100644
>> --- a/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
>> +++ b/drivers/platform/x86/dell-wmi-sysman/int-attributes.c
>> @@ -15,22 +15,17 @@ get_instance_id(integer);
>>   static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
>>   {
>>   	int instance_id = get_integer_instance_id(kobj);
>> -	union acpi_object *obj;
>> -	ssize_t ret;
>> +	int ret;
>>   
>>   	if (instance_id < 0)
>>   		return instance_id;
>>   
>> -	/* need to use specific instance_id and guid combination to get right data */
>> -	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
>> -	if (!obj)
>> -		return -EIO;
>> -	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_INTEGER) {
>> -		kfree(obj);
>> -		return -EINVAL;
>> +	ret = get_current_value(buf, instance_id, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
>> +	if (ret > 0) {
>> +		strcat(buf, "\n");
>> +		return strlen(buf);
>>   	}
>> -	ret = snprintf(buf, PAGE_SIZE, "%lld\n", obj->package.elements[CURRENT_VAL].integer.value);
>> -	kfree(obj);
>> +	/* read error */
>>   	return ret;
>>   }
>>   
>> @@ -161,6 +156,35 @@ int populate_int_data(union acpi_object *integer_obj, int instance_id,
>>   	return sysfs_create_group(attr_name_kobj, &integer_attr_group);
>>   }
>>   
>> +void get_integer_data(struct dell_wmi_sysman_buffer *buf)
>> +{
>> +	struct dell_attributes_data *attr_data;
>> +	int i;
>> +	//To populate in same dell_attributes_data, increment after enum data
>> +	int a_count = wmi_priv.enumeration_instances_count;
>> +
>> +	attr_data = (struct dell_attributes_data *)buf->data;
>> +	for (i = 0; i < wmi_priv.integer_instances_count; i++) {
>> +		attr_data[a_count].type = INT;
>> +		strlcpy_attr(attr_data[a_count].attribute_name,
>> +					wmi_priv.integer_data[i].attribute_name);
>> +		strlcpy_attr(attr_data[a_count].display_name,
>> +					wmi_priv.integer_data[i].display_name);
>> +		strlcpy_attr(attr_data[a_count].display_name_language_code,
>> +					wmi_priv.integer_data[i].display_name_language_code);
>> +		strlcpy_attr(attr_data[a_count].dell_modifier,
>> +					wmi_priv.integer_data[i].dell_modifier);
>> +		attr_data[a_count].min = wmi_priv.integer_data[i].min_value;
>> +		attr_data[a_count].max = wmi_priv.integer_data[i].max_value;
>> +		attr_data[a_count].scalar_increment = wmi_priv.integer_data[i].scalar_increment;
>> +		snprintf(attr_data[a_count].default_value, PAGE_SIZE, "%d",
>> +				wmi_priv.integer_data[i].default_value);
>> +		get_current_value(attr_data[a_count].current_value, i,
>> +				DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID);
>> +		a_count++;
>> +	}
>> +}
>> +
>>   /**
>>    * exit_int_attributes() - Clear all attribute data
>>    *
>> diff --git a/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c b/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
>> index 3abcd95477c0..9f50989a9f44 100644
>> --- a/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
>> +++ b/drivers/platform/x86/dell-wmi-sysman/passobj-attributes.c
>> @@ -169,6 +169,29 @@ int populate_po_data(union acpi_object *po_obj, int instance_id, struct kobject
>>   	return sysfs_create_group(attr_name_kobj, &po_attr_group);
>>   }
>>   
>> +void get_po_data(struct dell_wmi_sysman_buffer *in_data)
>> +{
>> +	int i;
>> +	struct dell_password_data *attr_data;
>> +
>> +	in_data->count = wmi_priv.po_instances_count;
>> +	attr_data = (struct dell_password_data *)in_data->data;
>> +	for (i = 0; i < wmi_priv.po_instances_count; i++) {
>> +		union acpi_object *obj;
>> +
>> +		strlcpy_attr(attr_data[i].attribute_name,
>> +						wmi_priv.po_data[i].attribute_name);
>> +		attr_data[i].min_length = wmi_priv.po_data[i].min_password_length;
>> +		attr_data[i].max_length = wmi_priv.po_data[i].max_password_length;
>> +
>> +		obj = get_wmiobj_pointer(i, DELL_WMI_BIOS_PASSOBJ_ATTRIBUTE_GUID);
>> +		if (!obj)
>> +			continue;
>> +		attr_data[i].is_set = obj->package.elements[IS_PASS_SET].integer.value;
>> +		kfree(obj);
>> +	}
>> +}
>> +
>>   /**
>>    * exit_po_attributes() - Clear all attribute data
>>    *
>> diff --git a/drivers/platform/x86/dell-wmi-sysman/string-attributes.c b/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
>> index ac75dce88a4c..a3847e4a6bf8 100644
>> --- a/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
>> +++ b/drivers/platform/x86/dell-wmi-sysman/string-attributes.c
>> @@ -15,22 +15,17 @@ get_instance_id(str);
>>   static ssize_t current_value_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
>>   {
>>   	int instance_id = get_str_instance_id(kobj);
>> -	union acpi_object *obj;
>> -	ssize_t ret;
>> +	int ret;
>>   
>>   	if (instance_id < 0)
>> -		return -EIO;
>> -
>> -	/* need to use specific instance_id and guid combination to get right data */
>> -	obj = get_wmiobj_pointer(instance_id, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
>> -	if (!obj)
>> -		return -EIO;
>> -	if (obj->package.elements[CURRENT_VAL].type != ACPI_TYPE_STRING) {
>> -		kfree(obj);
>> -		return -EINVAL;
>> +		return instance_id;
>> +
>> +	ret = get_current_value(buf, instance_id, DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
>> +	if (ret > 0) {
>> +		strcat(buf, "\n");
>> +		return strlen(buf);
>>   	}
>> -	ret = snprintf(buf, PAGE_SIZE, "%s\n", obj->package.elements[CURRENT_VAL].string.pointer);
>> -	kfree(obj);
>> +	/* read error */
>>   	return ret;
>>   }
>>   
>> @@ -141,6 +136,35 @@ int populate_str_data(union acpi_object *str_obj, int instance_id, struct kobjec
>>   	return sysfs_create_group(attr_name_kobj, &str_attr_group);
>>   }
>>   
>> +void get_string_data(struct dell_wmi_sysman_buffer *buf)
>> +{
>> +	struct dell_attributes_data *attr_data;
>> +	int i;
>> +	//To populate in same dell_attributes_data, increment after enum+int data
>> +	int a_count = wmi_priv.enumeration_instances_count +
>> +					wmi_priv.integer_instances_count;
>> +	attr_data = (struct dell_attributes_data *)buf->data;
>> +
>> +	for (i = 0; i < wmi_priv.str_instances_count; i++) {
>> +		attr_data[a_count].type = STR;
>> +		strlcpy_attr(attr_data[a_count].attribute_name,
>> +						wmi_priv.str_data[i].attribute_name);
>> +		strlcpy_attr(attr_data[a_count].display_name,
>> +						wmi_priv.str_data[i].display_name);
>> +		strlcpy_attr(attr_data[a_count].display_name_language_code,
>> +						wmi_priv.str_data[i].display_name_language_code);
>> +		strlcpy_attr(attr_data[a_count].dell_modifier,
>> +						wmi_priv.str_data[i].dell_modifier);
>> +		attr_data[a_count].min = wmi_priv.str_data[i].min_length;
>> +		attr_data[a_count].max = wmi_priv.str_data[i].max_length;
>> +		strlcpy_attr(attr_data[a_count].default_value,
>> +						wmi_priv.str_data[i].default_value);
>> +		get_current_value(attr_data[a_count].current_value, i,
>> +				DELL_WMI_BIOS_STRING_ATTRIBUTE_GUID);
>> +		a_count++;
>> +	}
>> +}
>> +
>>   /**
>>    * exit_str_attributes() - Clear all attribute data
>>    *
>> diff --git a/drivers/platform/x86/dell-wmi-sysman/sysman.c b/drivers/platform/x86/dell-wmi-sysman/sysman.c
>> index cb81010ba1a2..0b77a6a0b8a8 100644
>> --- a/drivers/platform/x86/dell-wmi-sysman/sysman.c
>> +++ b/drivers/platform/x86/dell-wmi-sysman/sysman.c
>> @@ -275,7 +275,7 @@ static struct kobj_type attr_name_ktype = {
>>    * @dest: Where to copy the string to
>>    * @src: Where to copy the string from
>>    */
>> -void strlcpy_attr(char *dest, char *src)
>> +void strlcpy_attr(char *dest, const char *src)
>>   {
>>   	size_t len = strlen(src) + 1;
>>   
>> @@ -307,6 +307,52 @@ union acpi_object *get_wmiobj_pointer(int instance_id, const char *guid_string)
>>   	return ACPI_SUCCESS(status) ? (union acpi_object *)out.pointer : NULL;
>>   }
>>   
>> +int validate_acpi_type(union acpi_object *obj, const char *guid_string)
>> +{
>> +	u32 acpi_type;
>> +
>> +	if (strcmp(guid_string, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID) == 0)
>> +		acpi_type = ACPI_TYPE_INTEGER;
>> +	else
>> +		acpi_type = ACPI_TYPE_STRING;
>> +
>> +	if (obj->package.elements[CURRENT_VAL].type != acpi_type)
>> +		return -EIO;
>> +
>> +	return 0;
>> +}
>> +
>> +/**
>> + * get_curret_value() - Get current_value of an attribute
>> + * @instance_id: WMI instance ID
>> + * @guid_string: WMI GUID (in string form)
>> + */
>> +int get_current_value(char *buf, int instance_id, const char *guid_string)
>> +{
>> +	union acpi_object *obj;
>> +	int ret;
>> +
>> +	/* need to use specific instance_id and guid combination to get right data */
>> +	obj = get_wmiobj_pointer(instance_id, guid_string);
>> +	if (!obj)
>> +		return -EIO;
>> +
>> +	ret = validate_acpi_type(obj, guid_string);
>> +	if (ret)
>> +		goto out;
>> +
>> +	if (strcmp(guid_string, DELL_WMI_BIOS_INTEGER_ATTRIBUTE_GUID) == 0)
>> +		ret = snprintf(buf, PAGE_SIZE, "%lld",
>> +				obj->package.elements[CURRENT_VAL].integer.value);
>> +	else
>> +		ret = snprintf(buf, PAGE_SIZE, "%s",
>> +				obj->package.elements[CURRENT_VAL].string.pointer);
>> +
>> +out:
>> +	kfree(obj);
>> +	return ret;
>> +}
>> +
>>   /**
>>    * get_instance_count() - Compute total number of instances under guid_string
>>    * @guid_string: WMI GUID (in string form)
>> diff --git a/include/uapi/linux/wmi.h b/include/uapi/linux/wmi.h
>> index 7085c5dca9fa..f160d1eef7cb 100644
>> --- a/include/uapi/linux/wmi.h
>> +++ b/include/uapi/linux/wmi.h
>> @@ -13,6 +13,11 @@
>>   /* WMI bus will filter all WMI vendor driver requests through this IOC */
>>   #define WMI_IOC 'W'
>>   
>> +enum BIOS_ATTRIBUTE_TYPE { ENUM, INT, STR, PO };
>> +enum IOCTL_COMMAND { ENUMERATE_ALL = 1, SET_ATTRIBUTES, SET_DEFAULTS, GET_PASS, SET_PASS };
>> +
>> +#define MAX_BUFF  512
>> +
>>   /* All ioctl requests through WMI should declare their size followed by
>>    * relevant data objects
>>    */
>> @@ -43,6 +48,53 @@ struct dell_wmi_smbios_buffer {
>>   	struct dell_wmi_extensions	ext;
>>   } __packed;
>>   
>> +struct dell_wmi_sysman_buffer {
>> +	__u64 length;
>> +	__u32 count;
>> +	__u16 command;
>> +	char admin_password[MAX_BUFF];
>> +	__u8 data[];
>> +} __packed;
>> +
>> +struct dell_attributes_data {
>> +	char display_name_language_code[MAX_BUFF];
>> +	char dell_value_modifier[MAX_BUFF];
>> +	char possible_values[MAX_BUFF];
>> +	char attribute_name[MAX_BUFF];
>> +	char current_value[MAX_BUFF];
>> +	char default_value[MAX_BUFF];
>> +	char dell_modifier[MAX_BUFF];
>> +	char display_name[MAX_BUFF];
>> +	int scalar_increment;
>> +	int type;
>> +	int min;
>> +	int max;
>> +} __packed;
>> +
>> +struct dell_set_data {
>> +	char attribute_name[MAX_BUFF];
>> +	char attribute_value[MAX_BUFF];
>> +} __packed;
>> +
>> +struct dell_set_password {
>> +	char attribute_name[MAX_BUFF];
>> +	char system_password[MAX_BUFF];
>> +	char new_password[MAX_BUFF];
>> +} __packed;
>> +
>> +struct dell_password_data {
>> +	char attribute_name[MAX_BUFF];
>> +	__u8 is_set;
>> +	int min_length;
>> +	int max_length;
>> +} __packed;
>> +
>> +struct dell_resetBIOS {
>> +	__u64 length;
>> +	__u8 option;
>> +	char admin_password[MAX_BUFF];
>> +} __packed;
>> +
>>   /* Whitelisted smbios class/select commands */
>>   #define CLASS_TOKEN_READ	0
>>   #define CLASS_TOKEN_WRITE	1
>> @@ -67,4 +119,8 @@ struct dell_wmi_smbios_buffer {
>>   /* Dell SMBIOS calling IOCTL command used by dell-smbios-wmi */
>>   #define DELL_WMI_SMBIOS_CMD	_IOWR(WMI_IOC, 0, struct dell_wmi_smbios_buffer)
>>   
>> +/* Dell WMI System Management calling IOCTL commands used by dell-wmi-sysman */
>> +#define DELL_WMI_SYSMAN_CMD _IOWR(WMI_IOC, 0, struct dell_wmi_sysman_buffer)
>> +#define DELL_WMI_SYSMAN_RESET_BIOS _IOW(WMI_IOC, 0, struct dell_resetBIOS)
>> +
>>   #endif
>> diff --git a/tools/dell-wmi-sysman/Makefile b/tools/dell-wmi-sysman/Makefile
>> new file mode 100644
>> index 000000000000..0a01a82a0745
>> --- /dev/null
>> +++ b/tools/dell-wmi-sysman/Makefile
>> @@ -0,0 +1,19 @@
>> +# SPDX-License-Identifier: GPL-2.0-only
>> +PREFIX ?= /usr
>> +SBINDIR ?= sbin
>> +INSTALL ?= install
>> +CFLAGS += -D__EXPORTED_HEADERS__ -I../../include/uapi -I../../include -I./
>> +
>> +TARGET = dell-wmi-sysman-example
>> +
>> +all: $(TARGET)
>> +
>> +%: %.c
>> +	$(CC) $(CFLAGS) $(LDFLAGS) -g -o $@ $<
>> +
>> +clean:
>> +	$(RM) $(TARGET)
>> +
>> +install: dell-wmi-sysman-example
>> +	$(INSTALL) -D -m 755 $(TARGET) $(DESTDIR)$(PREFIX)/$(SBINDIR)/$(TARGET)
>> +
>> diff --git a/tools/dell-wmi-sysman/dell-wmi-sysman-example.c b/tools/dell-wmi-sysman/dell-wmi-sysman-example.c
>> new file mode 100644
>> index 000000000000..50db8835cea6
>> --- /dev/null
>> +++ b/tools/dell-wmi-sysman/dell-wmi-sysman-example.c
>> @@ -0,0 +1,432 @@
>> +// SPDX-License-Identifier: GPL-2.0-only
>> +/*
>> + *  Sample application for system management over WMI interface
>> + *  Performs the following:
>> + *  - Enemeration of all BIOS attributes present in system
>> + *  - Set BIOS atributes to user input or default
>> + *	- Reset BIOS
>> + *
>> + *  Copyright (C) 2021 Dell, Inc.
>> + *
>> + *  This program is free software; you can redistribute it and/or modify
>> + *  it under the terms of the GNU General Public License version 2 as
>> + *  published by the Free Software Foundation.
>> + */
>> +
>> +#include <errno.h>
>> +#include <fcntl.h>
>> +#include <stdio.h>
>> +#include <stdlib.h>
>> +#include <sys/ioctl.h>
>> +#include <unistd.h>
>> +#include <string.h>
>> +#include <ctype.h>
>> +
>> +/* if uapi header isn't installed, this might not yet exist */
>> +#ifndef __packed
>> +#define __packed __attribute__((packed))
>> +#endif
>> +#include <linux/wmi.h>
>> +
>> +enum USER_OPTS {GET_ATTRS = 1, SET_ATTRS, SET_DEFS, PASS_MAN, RESET, EXIT };
>> +enum PASS_OPTS {GET_PASSINFO = 1, SET_OR_CHANGE_PASS, CLEAR_PASS, BACK };
>> +
>> +static const char *ioctl_devfs = "/dev/wmi/dell-wmi-sysman";
>> +__u64 buff_size;
>> +
>> +static int query_buffer_size(__u64 *buffer_size)
>> +{
>> +	FILE *f = fopen(ioctl_devfs, "rb");
>> +
>> +	if (!f)
>> +		return -EINVAL;
>> +	fread(buffer_size, sizeof(__u64), 1, f);
>> +	fclose(f);
>> +	return EXIT_SUCCESS;
>> +}
>> +
>> +int read_integer_input(void)
>> +{
>> +	int val, in, c;
>> +	char follow;
>> +
>> +	while (1) {
>> +		in = scanf("%d%c", &val, &follow);
>> +		if (in == 2) {
>> +			if (isspace(follow))
>> +				return val;
>> +			printf("Invalid input! Try again...\nEnter - ");
>> +		} else if (in == 1) {
>> +			return val;
>> +		printf("Invalid input! Try again...\nEnter - ");
>> +		}
>> +
>> +		while ((c = getchar()) != '\n' && c != EOF)
>> +			;
>> +	}
>> +}
>> +
>> +static int call_ioctl(struct dell_wmi_sysman_buffer *buffer)
>> +{
>> +	int fd;
>> +	int ret;
>> +
>> +	fd = open(ioctl_devfs, O_NONBLOCK);
>> +	ret = ioctl(fd, DELL_WMI_SYSMAN_CMD, buffer);
>> +	close(fd);
>> +	return ret;
>> +}
>> +
>> +int is_password_set(unsigned char *password_type)
>> +{
>> +	int ret, i;
>> +	int is_set = 0;
>> +	struct dell_wmi_sysman_buffer *buff_pwd;
>> +	struct dell_password_data *indata;
>> +
>> +	buff_pwd = malloc(buff_size); //buff_size large enough to get password data
>> +	if (buff_pwd == NULL) {
>> +		printf("failed to alloc memory for ioctl\n");
>> +		return -ENOMEM;
>> +	}
>> +
>> +	buff_pwd->length = buff_size;
>> +	buff_pwd->command = GET_PASS;
>> +	call_ioctl(buff_pwd);
>> +
>> +	indata = (struct dell_password_data *)buff_pwd->data;
>> +
>> +	for (i = 0; i < buff_pwd->count; i++) {
>> +		if (strcmp(indata[i].attribute_name, password_type) == 0) {
>> +			is_set = indata[i].is_set;
>> +			break;
>> +		}
>> +	}
>> +
>> +	free(buff_pwd);
>> +	return is_set;
>> +}
>> +
>> +/* Enumerate functions start*/
>> +void display_attributes(struct dell_wmi_sysman_buffer *buff_all)
>> +{
>> +	struct dell_attributes_data *testdata;
>> +	int i;
>> +
>> +	testdata = (struct dell_attributes_data *)buff_all->data;
>> +	for (i = 0; i < buff_all->count; i++) {
>> +		printf("\n%d\n", (i + 1));
>> +		printf("AttributeName = %s\n", testdata[i].attribute_name);
>> +		printf("Display LangCode = %s\n", testdata[i].display_name_language_code);
>> +		printf("Display Name = %s\n", testdata[i].display_name);
>> +		printf("Modifier = %s\n", testdata[i].dell_modifier);
>> +		printf("Current Value = %s\n", testdata[i].current_value);
>> +		printf("Default Value = %s\n", testdata[i].default_value);
>> +		if (testdata[i].type == ENUM) {
>> +			printf("Value Modifier = %s\n", testdata[i].dell_value_modifier);
>> +			printf("PossibleValues = %s\n", testdata[i].possible_values);
>> +		}
>> +		if (testdata[i].type == INT) {
>> +			printf("Lower Bound = %d\n", testdata[i].min);
>> +			printf("Upper Bound = %d\n", testdata[i].max);
>> +			printf("Scalar incr = %d\n", testdata[i].scalar_increment);
>> +		}
>> +		if (testdata[i].type == STR) {
>> +			printf("Minimum Length = %d\n", testdata[i].min);
>> +			printf("Maximum Length = %d\n", testdata[i].max);
>> +		}
>> +	}
>> +	printf("---------------------------------------------------------\n");
>> +}
>> +
>> +void enumerate_all_attributes(void)
>> +{
>> +	struct dell_wmi_sysman_buffer *buff_all;
>> +	int ret;
>> +
>> +	buff_all = malloc(buff_size);
>> +	if (buff_all == NULL) {
>> +		printf("failed to alloc memory for ioctl\n");
>> +		return;
>> +	}
>> +	buff_all->length = buff_size;
>> +	buff_all->command = ENUMERATE_ALL;
>> +	ret = call_ioctl(buff_all);
>> +	if (ret) {
>> +		printf("smbios ioctl failed: %d\n", ret);
>> +		goto out;
>> +	}
>> +	display_attributes(buff_all);
>> +out:
>> +	if (buff_all != NULL)
>> +		free(buff_all);
>> +}
>> +/* Enumerate functions end*/
>> +
>> +/* SET functions start */
>> +int read_set_data(struct dell_wmi_sysman_buffer *buff_set, int option)
>> +{
>> +	int i, admin_pwd_set;
>> +	struct dell_set_data *indata;
>> +
>> +	admin_pwd_set = is_password_set("Admin");
>> +	if (admin_pwd_set < 0) {
>> +		printf("check password call failed!!!\n");
>> +		return EXIT_FAILURE;
>> +	}
>> +
>> +	printf("How many attributes to set: ");
>> +	scanf("%d", &buff_set->count);
>> +
>> +	indata = (struct dell_set_data *)buff_set->data;
>> +
>> +	if (admin_pwd_set) {
>> +		printf("Admin password is set, please enter password - ");
>> +		scanf("%s", buff_set->admin_password);
>> +	}
>> +
>> +	for (i = 0; i < buff_set->count; i++) {
>> +		printf("Enter Attribute Name: ");
>> +		scanf("%s", indata[i].attribute_name);
>> +
>> +		if (option == SET_ATTRIBUTES) {
>> +			printf("Enter Attribute Value: ");
>> +			scanf("%s", indata[i].attribute_value);
>> +		}
>> +	}
>> +	return 0;
>> +}
>> +
>> +void call_set_cmd(int cmd_opt)
>> +{
>> +	int i, ret;
>> +	struct dell_wmi_sysman_buffer *buff_set;
>> +
>> +	buff_set = malloc(buff_size);
>> +	if (buff_set == NULL) {
>> +		printf("failed to alloc memory for ioctl\n");
>> +		return;
>> +	}
>> +	buff_set->length = buff_size;
>> +	buff_set->command = cmd_opt;
>> +	if (read_set_data(buff_set, cmd_opt))
>> +		goto out;
>> +
>> +	ret = call_ioctl(buff_set);
>> +	if (!ret) {
>> +		printf("Set Successful...\n");
>> +		goto out;
>> +	}
>> +	printf("Set failed: %d\n", ret);
>> +out:
>> +	free(buff_set);
>> +}
>> +/* SET functions end */
>> +
>> +/* Password related functions start */
>> +void get_password_info(void)
>> +{
>> +	int i;
>> +	struct dell_wmi_sysman_buffer *buff_pwd;
>> +	struct dell_password_data *testdata;
>> +
>> +	buff_pwd = malloc(buff_size); //buff_size large enough to get password data
>> +	if (buff_pwd == NULL) {
>> +		printf("failed to alloc memory for ioctl\n");
>> +		return;
>> +	}
>> +	buff_pwd->length = buff_size;
>> +	buff_pwd->command = GET_PASS;
>> +	if (call_ioctl(buff_pwd)) {
>> +		free(buff_pwd);
>> +		printf("smbios ioctl failed!!!\n");
>> +		return;
>> +	}
>> +
>> +	testdata = (struct dell_password_data *)buff_pwd->data;
>> +	for (i = 0; i < buff_pwd->count; i++) {
>> +		printf("\n%d\n", (i + 1));
>> +		printf("AttributeName = %s\n", testdata[i].attribute_name);
>> +		printf("Minimum Length = %d\n", testdata[i].min_length);
>> +		printf("Maximum Length = %d\n", testdata[i].max_length);
>> +		printf("Is Password Set = %d\n", testdata[i].is_set);
>> +	}
>> +	if (buff_pwd != NULL)
>> +		free(buff_pwd);
>> +}
>> +
>> +void call_set_pasword_cmd(int clear_opt)
>> +{
>> +	int ret, is_admin_pwd_set, is_system_pwd_set;
>> +	struct dell_wmi_sysman_buffer *buff_pwd;
>> +	struct dell_set_password *indata;
>> +
>> +	buff_pwd = malloc(buff_size); //buff_size large enough to get password data
>> +	if (buff_pwd == NULL) {
>> +		printf("failed to alloc memory for ioctl\n");
>> +		return;
>> +	}
>> +	buff_pwd->length = buff_size;
>> +	buff_pwd->command = SET_PASS;
>> +	is_admin_pwd_set = is_password_set("Admin");
>> +	is_system_pwd_set = is_password_set("System");
>> +	if ((is_admin_pwd_set < 0) || (is_system_pwd_set < 0)) {
>> +		printf("check password call failed!!!\n");
>> +		goto out;
>> +	}
>> +
>> +	indata = (struct dell_set_password *)buff_pwd->data;
>> +
>> +	if (is_admin_pwd_set) {
>> +		printf("Admin password is set, please enter current admin password - ");
>> +		scanf("%s", buff_pwd->admin_password);
>> +	}
>> +
>> +	printf("Enter which password to set Admin/System - ");
>> +	scanf("%s", indata->attribute_name);
>> +
>> +	if (strcmp(indata->attribute_name, "System") == 0 && (is_system_pwd_set)) {
>> +		printf("System password is set, please enter current system password - ");
>> +		scanf("%s", indata->system_password);
>> +	}
>> +
>> +	if (clear_opt == 3) {
>> +		strcpy(indata->new_password, "");
>> +	} else {
>> +		printf("Enter new password - ");
>> +		scanf("%s", indata->new_password);
>> +	}
>> +	ret = call_ioctl(buff_pwd);
>> +	if (!ret) {
>> +		printf("Set Successful...\n");
>> +		ret = EXIT_SUCCESS;
>> +		goto out;
>> +	}
>> +	printf("Set failed: %d\n", ret);
>> +out:
>> +	free(buff_pwd);
>> +}
>> +
>> +void call_password_management(void)
>> +{
>> +	int opt, ret;
>> +
>> +	while (1) {
>> +		printf("\n##############################\n");
>> +		printf(" Password Management Menu\t\n");
>> +		printf("##############################\n");
>> +		printf("\n1 - Get Password Information\n"
>> +				"2 - Set/Change Password\n"
>> +				"3 - Clear Password\n"
>> +				"4 - Go to back to Main Menu\n\n"
>> +				"Enter - ");
>> +		opt = read_integer_input();
>> +
>> +		switch (opt) {
>> +		case GET_PASSINFO:
>> +			get_password_info();
>> +			break;
>> +		case SET_OR_CHANGE_PASS:
>> +		case CLEAR_PASS:
>> +			call_set_pasword_cmd(opt);
>> +			break;
>> +		case BACK:
>> +			return;
>> +		default:
>> +			printf("Invalid option!\n");
>> +			break;
>> +		}
>> +	}
>> +}
>> +/* Password related functions end */
>> +
>> +void call_reset_bios(void)
>> +{
>> +	struct dell_resetBIOS *buff_reset;
>> +	unsigned char reset_option;
>> +	int fd, ret, is_admin_pwd_set;
>> +
>> +	printf("\nReset Options:\n"
>> +			"0 - Built-in Safe Defaults\n"
>> +			"1 - Last Known Good\n"
>> +			"2 - Factory\n"
>> +			"3 - Custom\n\n"
>> +			"Enter - ");
>> +	scanf("%hhu", &reset_option);
>> +	buff_reset = malloc(buff_size);
>> +	if (buff_reset == NULL) {
>> +		printf("failed to alloc memory for ioctl\n");
>> +		return;
>> +	}
>> +	is_admin_pwd_set = is_password_set("Admin");
>> +	if ((is_admin_pwd_set < 0)) {
>> +		printf("check password call failed!!!\n");
>> +		goto out;
>> +	}
>> +
>> +	buff_reset->length = buff_size;
>> +	if (is_admin_pwd_set) {
>> +		printf("Admin password is set, please enter current admin password - ");
>> +		scanf("%s", buff_reset->admin_password);
>> +	}
>> +	fd = open(ioctl_devfs, O_NONBLOCK);
>> +	ret = ioctl(fd, DELL_WMI_SYSMAN_RESET_BIOS, buff_reset);
>> +	close(fd);
>> +	if (!ret) {
>> +		printf("Reset Successful. Reboot the system\n");
>> +		ret = EXIT_SUCCESS;
>> +		goto out;
>> +	}
>> +	printf("Reset Failed: %d\n", ret);
>> +out:
>> +	if (buff_reset != NULL)
>> +		free(buff_reset);
>> +}
>> +
>> +int main(void)
>> +{
>> +	int ret, opt;
>> +	__u64 value = 0;
>> +
>> +	ret = query_buffer_size(&value);
>> +	if (ret == EXIT_FAILURE || !value) {
>> +		printf("Unable to read buffer size\n");
>> +		return ret;
>> +	}
>> +	buff_size = value;
>> +	while (1) {
>> +		printf("\n\n\n##############################\n");
>> +		printf("Dell BIOS System Management Utility\n");
>> +		printf("##############################\n");
>> +		printf("\n1 - Enumerate All Attributes\n"
>> +				"2 - Set Attributes\n"
>> +				"3 - Set To Defaults\n"
>> +				"4 - Password Management\n"
>> +				"5 - Reset BIOS\n"
>> +				"6 - Exit\n"
>> +				"\n\nEnter - ");
>> +		opt = read_integer_input();
>> +
>> +		switch (opt) {
>> +		case GET_ATTRS:
>> +			enumerate_all_attributes();
>> +			break;
>> +		case SET_ATTRS:
>> +		case SET_DEFS:
>> +			call_set_cmd(opt);
>> +			break;
>> +		case PASS_MAN:
>> +			call_password_management();
>> +			break;
>> +		case RESET:
>> +			call_reset_bios();
>> +			break;
>> +		case EXIT:
>> +			exit(0);
>> +			break;
>> +		default:
>> +			break;
>> +		}
>> +	}
>> +	return 0;
>> +}
>>

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-03-15  4:20 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-02-09 14:28 [PATCH] IOCTL support for dell-wmi-sysman driver Prasanth, KSR
2021-02-09 17:48 ` kernel test robot
2021-02-09 17:48   ` kernel test robot
2021-02-09 17:57 ` Hans de Goede
2021-03-15  4:19   ` Prasanth, KSR
2021-02-09 22:34 ` kernel test robot
2021-02-09 22:34   ` kernel test robot

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.