1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Functions corresponding to SET methods under BIOS attributes interface GUID for use 4 * with dell-wmi-sysman 5 * 6 * Copyright (c) 2020 Dell Inc. 7 */ 8 9 #include <linux/wmi.h> 10 #include "dell-wmi-sysman.h" 11 12 #define SETDEFAULTVALUES_METHOD_ID 0x02 13 #define SETBIOSDEFAULTS_METHOD_ID 0x03 14 #define SETATTRIBUTE_METHOD_ID 0x04 15 16 static int call_biosattributes_interface(struct wmi_device *wdev, char *in_args, size_t size, 17 int method_id) 18 { 19 struct acpi_buffer output = {ACPI_ALLOCATE_BUFFER, NULL}; 20 struct acpi_buffer input; 21 union acpi_object *obj; 22 acpi_status status; 23 int ret = -EIO; 24 25 input.length = (acpi_size) size; 26 input.pointer = in_args; 27 status = wmidev_evaluate_method(wdev, 0, method_id, &input, &output); 28 if (ACPI_FAILURE(status)) 29 return -EIO; 30 obj = (union acpi_object *)output.pointer; 31 if (obj->type == ACPI_TYPE_INTEGER) 32 ret = obj->integer.value; 33 34 if (wmi_priv.pending_changes == 0) { 35 wmi_priv.pending_changes = 1; 36 /* let userland know it may need to check reboot pending again */ 37 kobject_uevent(&wmi_priv.class_dev->kobj, KOBJ_CHANGE); 38 } 39 kfree(output.pointer); 40 return map_wmi_error(ret); 41 } 42 43 /** 44 * set_attribute() - Update an attribute value 45 * @a_name: The attribute name 46 * @a_value: The attribute value 47 * 48 * Sets an attribute to new value 49 */ 50 int set_attribute(const char *a_name, const char *a_value) 51 { 52 size_t security_area_size, buffer_size; 53 size_t a_name_size, a_value_size; 54 char *buffer = NULL, *start; 55 int ret; 56 57 mutex_lock(&wmi_priv.mutex); 58 if (!wmi_priv.bios_attr_wdev) { 59 ret = -ENODEV; 60 goto out; 61 } 62 63 /* build/calculate buffer */ 64 security_area_size = calculate_security_buffer(wmi_priv.current_admin_password); 65 a_name_size = calculate_string_buffer(a_name); 66 a_value_size = calculate_string_buffer(a_value); 67 buffer_size = security_area_size + a_name_size + a_value_size; 68 buffer = kzalloc(buffer_size, GFP_KERNEL); 69 if (!buffer) { 70 ret = -ENOMEM; 71 goto out; 72 } 73 74 /* build security area */ 75 populate_security_buffer(buffer, wmi_priv.current_admin_password); 76 77 /* build variables to set */ 78 start = buffer + security_area_size; 79 ret = populate_string_buffer(start, a_name_size, a_name); 80 if (ret < 0) 81 goto out; 82 start += ret; 83 ret = populate_string_buffer(start, a_value_size, a_value); 84 if (ret < 0) 85 goto out; 86 87 print_hex_dump_bytes("set attribute data: ", DUMP_PREFIX_NONE, buffer, buffer_size); 88 ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev, 89 buffer, buffer_size, 90 SETATTRIBUTE_METHOD_ID); 91 if (ret == -EOPNOTSUPP) 92 dev_err(&wmi_priv.bios_attr_wdev->dev, "admin password must be configured\n"); 93 else if (ret == -EACCES) 94 dev_err(&wmi_priv.bios_attr_wdev->dev, "invalid password\n"); 95 96 out: 97 kfree(buffer); 98 mutex_unlock(&wmi_priv.mutex); 99 return ret; 100 } 101 102 /** 103 * set_bios_defaults() - Resets BIOS defaults 104 * @deftype: the type of BIOS value reset to issue. 105 * 106 * Resets BIOS defaults 107 */ 108 int set_bios_defaults(u8 deftype) 109 { 110 size_t security_area_size, buffer_size; 111 size_t integer_area_size = sizeof(u8); 112 char *buffer = NULL; 113 u8 *defaultType; 114 int ret; 115 116 mutex_lock(&wmi_priv.mutex); 117 if (!wmi_priv.bios_attr_wdev) { 118 ret = -ENODEV; 119 goto out; 120 } 121 122 security_area_size = calculate_security_buffer(wmi_priv.current_admin_password); 123 buffer_size = security_area_size + integer_area_size; 124 buffer = kzalloc(buffer_size, GFP_KERNEL); 125 if (!buffer) { 126 ret = -ENOMEM; 127 goto out; 128 } 129 130 /* build security area */ 131 populate_security_buffer(buffer, wmi_priv.current_admin_password); 132 133 defaultType = buffer + security_area_size; 134 *defaultType = deftype; 135 136 ret = call_biosattributes_interface(wmi_priv.bios_attr_wdev, buffer, buffer_size, 137 SETBIOSDEFAULTS_METHOD_ID); 138 if (ret) 139 dev_err(&wmi_priv.bios_attr_wdev->dev, "reset BIOS defaults failed: %d\n", ret); 140 141 kfree(buffer); 142 out: 143 mutex_unlock(&wmi_priv.mutex); 144 return ret; 145 } 146 147 static int bios_attr_set_interface_probe(struct wmi_device *wdev, const void *context) 148 { 149 mutex_lock(&wmi_priv.mutex); 150 wmi_priv.bios_attr_wdev = wdev; 151 mutex_unlock(&wmi_priv.mutex); 152 return 0; 153 } 154 155 static int bios_attr_set_interface_remove(struct wmi_device *wdev) 156 { 157 mutex_lock(&wmi_priv.mutex); 158 wmi_priv.bios_attr_wdev = NULL; 159 mutex_unlock(&wmi_priv.mutex); 160 return 0; 161 } 162 163 static const struct wmi_device_id bios_attr_set_interface_id_table[] = { 164 { .guid_string = DELL_WMI_BIOS_ATTRIBUTES_INTERFACE_GUID }, 165 { }, 166 }; 167 static struct wmi_driver bios_attr_set_interface_driver = { 168 .driver = { 169 .name = DRIVER_NAME 170 }, 171 .probe = bios_attr_set_interface_probe, 172 .remove = bios_attr_set_interface_remove, 173 .id_table = bios_attr_set_interface_id_table, 174 }; 175 176 int init_bios_attr_set_interface(void) 177 { 178 return wmi_driver_register(&bios_attr_set_interface_driver); 179 } 180 181 void exit_bios_attr_set_interface(void) 182 { 183 wmi_driver_unregister(&bios_attr_set_interface_driver); 184 } 185 186 MODULE_DEVICE_TABLE(wmi, bios_attr_set_interface_id_table); 187