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

dell-wmi-descriptor.c (4779B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2/*
      3 * Dell WMI descriptor driver
      4 *
      5 * Copyright (C) 2017 Dell Inc. All Rights Reserved.
      6 */
      7
      8#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
      9
     10#include <linux/acpi.h>
     11#include <linux/list.h>
     12#include <linux/module.h>
     13#include <linux/wmi.h>
     14#include "dell-wmi-descriptor.h"
     15
     16#define DELL_WMI_DESCRIPTOR_GUID "8D9DDCBC-A997-11DA-B012-B622A1EF5492"
     17
     18struct descriptor_priv {
     19	struct list_head list;
     20	u32 interface_version;
     21	u32 size;
     22	u32 hotfix;
     23};
     24static int descriptor_valid = -EPROBE_DEFER;
     25static LIST_HEAD(wmi_list);
     26static DEFINE_MUTEX(list_mutex);
     27
     28int dell_wmi_get_descriptor_valid(void)
     29{
     30	if (!wmi_has_guid(DELL_WMI_DESCRIPTOR_GUID))
     31		return -ENODEV;
     32
     33	return descriptor_valid;
     34}
     35EXPORT_SYMBOL_GPL(dell_wmi_get_descriptor_valid);
     36
     37bool dell_wmi_get_interface_version(u32 *version)
     38{
     39	struct descriptor_priv *priv;
     40	bool ret = false;
     41
     42	mutex_lock(&list_mutex);
     43	priv = list_first_entry_or_null(&wmi_list,
     44					struct descriptor_priv,
     45					list);
     46	if (priv) {
     47		*version = priv->interface_version;
     48		ret = true;
     49	}
     50	mutex_unlock(&list_mutex);
     51	return ret;
     52}
     53EXPORT_SYMBOL_GPL(dell_wmi_get_interface_version);
     54
     55bool dell_wmi_get_size(u32 *size)
     56{
     57	struct descriptor_priv *priv;
     58	bool ret = false;
     59
     60	mutex_lock(&list_mutex);
     61	priv = list_first_entry_or_null(&wmi_list,
     62					struct descriptor_priv,
     63					list);
     64	if (priv) {
     65		*size = priv->size;
     66		ret = true;
     67	}
     68	mutex_unlock(&list_mutex);
     69	return ret;
     70}
     71EXPORT_SYMBOL_GPL(dell_wmi_get_size);
     72
     73bool dell_wmi_get_hotfix(u32 *hotfix)
     74{
     75	struct descriptor_priv *priv;
     76	bool ret = false;
     77
     78	mutex_lock(&list_mutex);
     79	priv = list_first_entry_or_null(&wmi_list,
     80					struct descriptor_priv,
     81					list);
     82	if (priv) {
     83		*hotfix = priv->hotfix;
     84		ret = true;
     85	}
     86	mutex_unlock(&list_mutex);
     87	return ret;
     88}
     89EXPORT_SYMBOL_GPL(dell_wmi_get_hotfix);
     90
     91/*
     92 * Descriptor buffer is 128 byte long and contains:
     93 *
     94 *       Name             Offset  Length  Value
     95 * Vendor Signature          0       4    "DELL"
     96 * Object Signature          4       4    " WMI"
     97 * WMI Interface Version     8       4    <version>
     98 * WMI buffer length        12       4    <length>
     99 * WMI hotfix number        16       4    <hotfix>
    100 */
    101static int dell_wmi_descriptor_probe(struct wmi_device *wdev,
    102				     const void *context)
    103{
    104	union acpi_object *obj = NULL;
    105	struct descriptor_priv *priv;
    106	u32 *buffer;
    107	int ret;
    108
    109	obj = wmidev_block_query(wdev, 0);
    110	if (!obj) {
    111		dev_err(&wdev->dev, "failed to read Dell WMI descriptor\n");
    112		ret = -EIO;
    113		goto out;
    114	}
    115
    116	if (obj->type != ACPI_TYPE_BUFFER) {
    117		dev_err(&wdev->dev, "Dell descriptor has wrong type\n");
    118		ret = -EINVAL;
    119		descriptor_valid = ret;
    120		goto out;
    121	}
    122
    123	/* Although it's not technically a failure, this would lead to
    124	 * unexpected behavior
    125	 */
    126	if (obj->buffer.length != 128) {
    127		dev_err(&wdev->dev,
    128			"Dell descriptor buffer has unexpected length (%d)\n",
    129			obj->buffer.length);
    130		ret = -EINVAL;
    131		descriptor_valid = ret;
    132		goto out;
    133	}
    134
    135	buffer = (u32 *)obj->buffer.pointer;
    136
    137	if (strncmp(obj->string.pointer, "DELL WMI", 8) != 0) {
    138		dev_err(&wdev->dev, "Dell descriptor buffer has invalid signature (%8ph)\n",
    139			buffer);
    140		ret = -EINVAL;
    141		descriptor_valid = ret;
    142		goto out;
    143	}
    144	descriptor_valid = 0;
    145
    146	if (buffer[2] != 0 && buffer[2] != 1)
    147		dev_warn(&wdev->dev, "Dell descriptor buffer has unknown version (%lu)\n",
    148			(unsigned long) buffer[2]);
    149
    150	priv = devm_kzalloc(&wdev->dev, sizeof(struct descriptor_priv),
    151	GFP_KERNEL);
    152
    153	if (!priv) {
    154		ret = -ENOMEM;
    155		goto out;
    156	}
    157
    158	priv->interface_version = buffer[2];
    159	priv->size = buffer[3];
    160	priv->hotfix = buffer[4];
    161	ret = 0;
    162	dev_set_drvdata(&wdev->dev, priv);
    163	mutex_lock(&list_mutex);
    164	list_add_tail(&priv->list, &wmi_list);
    165	mutex_unlock(&list_mutex);
    166
    167	dev_dbg(&wdev->dev, "Detected Dell WMI interface version %lu, buffer size %lu, hotfix %lu\n",
    168		(unsigned long) priv->interface_version,
    169		(unsigned long) priv->size,
    170		(unsigned long) priv->hotfix);
    171
    172out:
    173	kfree(obj);
    174	return ret;
    175}
    176
    177static void dell_wmi_descriptor_remove(struct wmi_device *wdev)
    178{
    179	struct descriptor_priv *priv = dev_get_drvdata(&wdev->dev);
    180
    181	mutex_lock(&list_mutex);
    182	list_del(&priv->list);
    183	mutex_unlock(&list_mutex);
    184}
    185
    186static const struct wmi_device_id dell_wmi_descriptor_id_table[] = {
    187	{ .guid_string = DELL_WMI_DESCRIPTOR_GUID },
    188	{ },
    189};
    190
    191static struct wmi_driver dell_wmi_descriptor_driver = {
    192	.driver = {
    193		.name = "dell-wmi-descriptor",
    194	},
    195	.probe = dell_wmi_descriptor_probe,
    196	.remove = dell_wmi_descriptor_remove,
    197	.id_table = dell_wmi_descriptor_id_table,
    198};
    199
    200module_wmi_driver(dell_wmi_descriptor_driver);
    201
    202MODULE_DEVICE_TABLE(wmi, dell_wmi_descriptor_id_table);
    203MODULE_AUTHOR("Mario Limonciello <mario.limonciello@outlook.com>");
    204MODULE_DESCRIPTION("Dell WMI descriptor driver");
    205MODULE_LICENSE("GPL");