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

ibm_rtl.c (7592B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 * IBM Real-Time Linux driver
      4 *
      5 * Copyright (C) IBM Corporation, 2010
      6 *
      7 * Author: Keith Mannthey <kmannth@us.ibm.com>
      8 *         Vernon Mauery <vernux@us.ibm.com>
      9 */
     10
     11#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     12
     13#include <linux/kernel.h>
     14#include <linux/delay.h>
     15#include <linux/module.h>
     16#include <linux/io.h>
     17#include <linux/dmi.h>
     18#include <linux/efi.h>
     19#include <linux/mutex.h>
     20#include <asm/bios_ebda.h>
     21
     22#include <linux/io-64-nonatomic-lo-hi.h>
     23
     24static bool force;
     25module_param(force, bool, 0);
     26MODULE_PARM_DESC(force, "Force driver load, ignore DMI data");
     27
     28static bool debug;
     29module_param(debug, bool, 0644);
     30MODULE_PARM_DESC(debug, "Show debug output");
     31
     32MODULE_LICENSE("GPL");
     33MODULE_AUTHOR("Keith Mannthey <kmmanth@us.ibm.com>");
     34MODULE_AUTHOR("Vernon Mauery <vernux@us.ibm.com>");
     35
     36#define RTL_ADDR_TYPE_IO    1
     37#define RTL_ADDR_TYPE_MMIO  2
     38
     39#define RTL_CMD_ENTER_PRTM  1
     40#define RTL_CMD_EXIT_PRTM   2
     41
     42/* The RTL table as presented by the EBDA: */
     43struct ibm_rtl_table {
     44	char signature[5]; /* signature should be "_RTL_" */
     45	u8 version;
     46	u8 rt_status;
     47	u8 command;
     48	u8 command_status;
     49	u8 cmd_address_type;
     50	u8 cmd_granularity;
     51	u8 cmd_offset;
     52	u16 reserve1;
     53	u32 cmd_port_address; /* platform dependent address */
     54	u32 cmd_port_value;   /* platform dependent value */
     55} __attribute__((packed));
     56
     57/* to locate "_RTL_" signature do a masked 5-byte integer compare */
     58#define RTL_SIGNATURE 0x0000005f4c54525fULL
     59#define RTL_MASK      0x000000ffffffffffULL
     60
     61#define RTL_DEBUG(fmt, ...)				\
     62do {							\
     63	if (debug)					\
     64		pr_info(fmt, ##__VA_ARGS__);		\
     65} while (0)
     66
     67static DEFINE_MUTEX(rtl_lock);
     68static struct ibm_rtl_table __iomem *rtl_table;
     69static void __iomem *ebda_map;
     70static void __iomem *rtl_cmd_addr;
     71static u8 rtl_cmd_type;
     72static u8 rtl_cmd_width;
     73
     74static void __iomem *rtl_port_map(phys_addr_t addr, unsigned long len)
     75{
     76	if (rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
     77		return ioremap(addr, len);
     78	return ioport_map(addr, len);
     79}
     80
     81static void rtl_port_unmap(void __iomem *addr)
     82{
     83	if (addr && rtl_cmd_type == RTL_ADDR_TYPE_MMIO)
     84		iounmap(addr);
     85	else
     86		ioport_unmap(addr);
     87}
     88
     89static int ibm_rtl_write(u8 value)
     90{
     91	int ret = 0, count = 0;
     92	u32 cmd_port_val;
     93
     94	RTL_DEBUG("%s(%d)\n", __func__, value);
     95
     96	value = value == 1 ? RTL_CMD_ENTER_PRTM : RTL_CMD_EXIT_PRTM;
     97
     98	mutex_lock(&rtl_lock);
     99
    100	if (ioread8(&rtl_table->rt_status) != value) {
    101		iowrite8(value, &rtl_table->command);
    102
    103		switch (rtl_cmd_width) {
    104		case 8:
    105			cmd_port_val = ioread8(&rtl_table->cmd_port_value);
    106			RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
    107			iowrite8((u8)cmd_port_val, rtl_cmd_addr);
    108			break;
    109		case 16:
    110			cmd_port_val = ioread16(&rtl_table->cmd_port_value);
    111			RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
    112			iowrite16((u16)cmd_port_val, rtl_cmd_addr);
    113			break;
    114		case 32:
    115			cmd_port_val = ioread32(&rtl_table->cmd_port_value);
    116			RTL_DEBUG("cmd_port_val = %u\n", cmd_port_val);
    117			iowrite32(cmd_port_val, rtl_cmd_addr);
    118			break;
    119		}
    120
    121		while (ioread8(&rtl_table->command)) {
    122			msleep(10);
    123			if (count++ > 500) {
    124				pr_err("Hardware not responding to "
    125				       "mode switch request\n");
    126				ret = -EIO;
    127				break;
    128			}
    129
    130		}
    131
    132		if (ioread8(&rtl_table->command_status)) {
    133			RTL_DEBUG("command_status reports failed command\n");
    134			ret = -EIO;
    135		}
    136	}
    137
    138	mutex_unlock(&rtl_lock);
    139	return ret;
    140}
    141
    142static ssize_t rtl_show_version(struct device *dev,
    143                                struct device_attribute *attr,
    144                                char *buf)
    145{
    146	return sprintf(buf, "%d\n", (int)ioread8(&rtl_table->version));
    147}
    148
    149static ssize_t rtl_show_state(struct device *dev,
    150                              struct device_attribute *attr,
    151                              char *buf)
    152{
    153	return sprintf(buf, "%d\n", ioread8(&rtl_table->rt_status));
    154}
    155
    156static ssize_t rtl_set_state(struct device *dev,
    157                             struct device_attribute *attr,
    158                             const char *buf,
    159                             size_t count)
    160{
    161	ssize_t ret;
    162
    163	if (count < 1 || count > 2)
    164		return -EINVAL;
    165
    166	switch (buf[0]) {
    167	case '0':
    168		ret = ibm_rtl_write(0);
    169		break;
    170	case '1':
    171		ret = ibm_rtl_write(1);
    172		break;
    173	default:
    174		ret = -EINVAL;
    175	}
    176	if (ret >= 0)
    177		ret = count;
    178
    179	return ret;
    180}
    181
    182static struct bus_type rtl_subsys = {
    183	.name = "ibm_rtl",
    184	.dev_name = "ibm_rtl",
    185};
    186
    187static DEVICE_ATTR(version, S_IRUGO, rtl_show_version, NULL);
    188static DEVICE_ATTR(state, 0600, rtl_show_state, rtl_set_state);
    189
    190static struct device_attribute *rtl_attributes[] = {
    191	&dev_attr_version,
    192	&dev_attr_state,
    193	NULL
    194};
    195
    196
    197static int rtl_setup_sysfs(void) {
    198	int ret, i;
    199
    200	ret = subsys_system_register(&rtl_subsys, NULL);
    201	if (!ret) {
    202		for (i = 0; rtl_attributes[i]; i ++)
    203			device_create_file(rtl_subsys.dev_root, rtl_attributes[i]);
    204	}
    205	return ret;
    206}
    207
    208static void rtl_teardown_sysfs(void) {
    209	int i;
    210	for (i = 0; rtl_attributes[i]; i ++)
    211		device_remove_file(rtl_subsys.dev_root, rtl_attributes[i]);
    212	bus_unregister(&rtl_subsys);
    213}
    214
    215
    216static const struct dmi_system_id ibm_rtl_dmi_table[] __initconst = {
    217	{                                                  \
    218		.matches = {                               \
    219			DMI_MATCH(DMI_SYS_VENDOR, "IBM"),  \
    220		},                                         \
    221	},
    222	{ }
    223};
    224
    225static int __init ibm_rtl_init(void) {
    226	unsigned long ebda_addr, ebda_size;
    227	unsigned int ebda_kb;
    228	int ret = -ENODEV, i;
    229
    230	if (force)
    231		pr_warn("module loaded by force\n");
    232	/* first ensure that we are running on IBM HW */
    233	else if (efi_enabled(EFI_BOOT) || !dmi_check_system(ibm_rtl_dmi_table))
    234		return -ENODEV;
    235
    236	/* Get the address for the Extended BIOS Data Area */
    237	ebda_addr = get_bios_ebda();
    238	if (!ebda_addr) {
    239		RTL_DEBUG("no BIOS EBDA found\n");
    240		return -ENODEV;
    241	}
    242
    243	ebda_map = ioremap(ebda_addr, 4);
    244	if (!ebda_map)
    245		return -ENOMEM;
    246
    247	/* First word in the EDBA is the Size in KB */
    248	ebda_kb = ioread16(ebda_map);
    249	RTL_DEBUG("EBDA is %d kB\n", ebda_kb);
    250
    251	if (ebda_kb == 0)
    252		goto out;
    253
    254	iounmap(ebda_map);
    255	ebda_size = ebda_kb*1024;
    256
    257	/* Remap the whole table */
    258	ebda_map = ioremap(ebda_addr, ebda_size);
    259	if (!ebda_map)
    260		return -ENOMEM;
    261
    262	/* search for the _RTL_ signature at the start of the table */
    263	for (i = 0 ; i < ebda_size/sizeof(unsigned int); i++) {
    264		struct ibm_rtl_table __iomem * tmp;
    265		tmp = (struct ibm_rtl_table __iomem *) (ebda_map+i);
    266		if ((readq(&tmp->signature) & RTL_MASK) == RTL_SIGNATURE) {
    267			phys_addr_t addr;
    268			unsigned int plen;
    269			RTL_DEBUG("found RTL_SIGNATURE at %p\n", tmp);
    270			rtl_table = tmp;
    271			/* The address, value, width and offset are platform
    272			 * dependent and found in the ibm_rtl_table */
    273			rtl_cmd_width = ioread8(&rtl_table->cmd_granularity);
    274			rtl_cmd_type = ioread8(&rtl_table->cmd_address_type);
    275			RTL_DEBUG("rtl_cmd_width = %u, rtl_cmd_type = %u\n",
    276				  rtl_cmd_width, rtl_cmd_type);
    277			addr = ioread32(&rtl_table->cmd_port_address);
    278			RTL_DEBUG("addr = %#llx\n", (unsigned long long)addr);
    279			plen = rtl_cmd_width/sizeof(char);
    280			rtl_cmd_addr = rtl_port_map(addr, plen);
    281			RTL_DEBUG("rtl_cmd_addr = %p\n", rtl_cmd_addr);
    282			if (!rtl_cmd_addr) {
    283				ret = -ENOMEM;
    284				break;
    285			}
    286			ret = rtl_setup_sysfs();
    287			break;
    288		}
    289	}
    290
    291out:
    292	if (ret) {
    293		iounmap(ebda_map);
    294		rtl_port_unmap(rtl_cmd_addr);
    295	}
    296
    297	return ret;
    298}
    299
    300static void __exit ibm_rtl_exit(void)
    301{
    302	if (rtl_table) {
    303		RTL_DEBUG("cleaning up");
    304		/* do not leave the machine in SMI-free mode */
    305		ibm_rtl_write(0);
    306		/* unmap, unlink and remove all traces */
    307		rtl_teardown_sysfs();
    308		iounmap(ebda_map);
    309		rtl_port_unmap(rtl_cmd_addr);
    310	}
    311}
    312
    313module_init(ibm_rtl_init);
    314module_exit(ibm_rtl_exit);