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