cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sbl-fw-update.c (3601B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Slim Bootloader(SBL) firmware update signaling driver
      4 *
      5 * Slim Bootloader is a small, open-source, non UEFI compliant, boot firmware
      6 * optimized for running on certain Intel platforms.
      7 *
      8 * SBL exposes an ACPI-WMI device via /sys/bus/wmi/devices/<INTEL_WMI_SBL_GUID>.
      9 * This driver further adds "firmware_update_request" device attribute.
     10 * This attribute normally has a value of 0 and userspace can signal SBL
     11 * to update firmware, on next reboot, by writing a value of 1.
     12 *
     13 * More details of SBL firmware update process is available at:
     14 * https://slimbootloader.github.io/security/firmware-update.html
     15 */
     16
     17#include <linux/acpi.h>
     18#include <linux/device.h>
     19#include <linux/module.h>
     20#include <linux/slab.h>
     21#include <linux/sysfs.h>
     22#include <linux/wmi.h>
     23
     24#define INTEL_WMI_SBL_GUID  "44FADEB1-B204-40F2-8581-394BBDC1B651"
     25
     26static int get_fwu_request(struct device *dev, u32 *out)
     27{
     28	struct acpi_buffer result = {ACPI_ALLOCATE_BUFFER, NULL};
     29	union acpi_object *obj;
     30	acpi_status status;
     31
     32	status = wmi_query_block(INTEL_WMI_SBL_GUID, 0, &result);
     33	if (ACPI_FAILURE(status)) {
     34		dev_err(dev, "wmi_query_block failed\n");
     35		return -ENODEV;
     36	}
     37
     38	obj = (union acpi_object *)result.pointer;
     39	if (!obj || obj->type != ACPI_TYPE_INTEGER) {
     40		dev_warn(dev, "wmi_query_block returned invalid value\n");
     41		kfree(obj);
     42		return -EINVAL;
     43	}
     44
     45	*out = obj->integer.value;
     46	kfree(obj);
     47
     48	return 0;
     49}
     50
     51static int set_fwu_request(struct device *dev, u32 in)
     52{
     53	struct acpi_buffer input;
     54	acpi_status status;
     55	u32 value;
     56
     57	value = in;
     58	input.length = sizeof(u32);
     59	input.pointer = &value;
     60
     61	status = wmi_set_block(INTEL_WMI_SBL_GUID, 0, &input);
     62	if (ACPI_FAILURE(status)) {
     63		dev_err(dev, "wmi_set_block failed\n");
     64		return -ENODEV;
     65	}
     66
     67	return 0;
     68}
     69
     70static ssize_t firmware_update_request_show(struct device *dev,
     71					    struct device_attribute *attr,
     72					    char *buf)
     73{
     74	u32 val;
     75	int ret;
     76
     77	ret = get_fwu_request(dev, &val);
     78	if (ret)
     79		return ret;
     80
     81	return sprintf(buf, "%d\n", val);
     82}
     83
     84static ssize_t firmware_update_request_store(struct device *dev,
     85					     struct device_attribute *attr,
     86					     const char *buf, size_t count)
     87{
     88	unsigned int val;
     89	int ret;
     90
     91	ret = kstrtouint(buf, 0, &val);
     92	if (ret)
     93		return ret;
     94
     95	/* May later be extended to support values other than 0 and 1 */
     96	if (val > 1)
     97		return -ERANGE;
     98
     99	ret = set_fwu_request(dev, val);
    100	if (ret)
    101		return ret;
    102
    103	return count;
    104}
    105static DEVICE_ATTR_RW(firmware_update_request);
    106
    107static struct attribute *firmware_update_attrs[] = {
    108	&dev_attr_firmware_update_request.attr,
    109	NULL
    110};
    111ATTRIBUTE_GROUPS(firmware_update);
    112
    113static int intel_wmi_sbl_fw_update_probe(struct wmi_device *wdev,
    114					 const void *context)
    115{
    116	dev_info(&wdev->dev, "Slim Bootloader signaling driver attached\n");
    117	return 0;
    118}
    119
    120static void intel_wmi_sbl_fw_update_remove(struct wmi_device *wdev)
    121{
    122	dev_info(&wdev->dev, "Slim Bootloader signaling driver removed\n");
    123}
    124
    125static const struct wmi_device_id intel_wmi_sbl_id_table[] = {
    126	{ .guid_string = INTEL_WMI_SBL_GUID },
    127	{}
    128};
    129MODULE_DEVICE_TABLE(wmi, intel_wmi_sbl_id_table);
    130
    131static struct wmi_driver intel_wmi_sbl_fw_update_driver = {
    132	.driver = {
    133		.name = "intel-wmi-sbl-fw-update",
    134		.dev_groups = firmware_update_groups,
    135	},
    136	.probe = intel_wmi_sbl_fw_update_probe,
    137	.remove = intel_wmi_sbl_fw_update_remove,
    138	.id_table = intel_wmi_sbl_id_table,
    139};
    140module_wmi_driver(intel_wmi_sbl_fw_update_driver);
    141
    142MODULE_AUTHOR("Jithu Joseph <jithu.joseph@intel.com>");
    143MODULE_DESCRIPTION("Slim Bootloader firmware update signaling driver");
    144MODULE_LICENSE("GPL v2");