[PATCH] IOCTL support for dell-wmi-sysman driver
From: Prasanth, KSR
Date: Tue Feb 09 2021 - 09:29:46 EST
From: "Prasanth KSR" <prasanth.ksr@xxxxxxxx>
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@xxxxxxxxxx>
Signed-off-by: Prasanth KSR <prasanth.ksr@xxxxxxxx>
Co-developed-by: Divya Bharathi <divya.bharathi@xxxxxxxx>
Signed-off-by: Divya Bharathi <divya.bharathi@xxxxxxxx>
Co-developed-by: Mario Limonciello <mario.limonciello@xxxxxxxx>
Signed-off-by: Mario Limonciello <mario.limonciello@xxxxxxxx>
---
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@xxxxxxxx>
+ "Mario Limonciello" <mario.limonciello@xxxxxxxx>
+ "Prasanth K S R" <prasanth.ksr@xxxxxxxx>
+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