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

err_inject.c (7208B)


      1/*
      2 * err_inject.c -
      3 *	1.) Inject errors to a processor.
      4 *	2.) Query error injection capabilities.
      5 * This driver along with user space code can be acting as an error
      6 * injection tool.
      7 *
      8 * This program is free software; you can redistribute it and/or modify
      9 * it under the terms of the GNU General Public License as published by
     10 * the Free Software Foundation; either version 2 of the License, or
     11 * (at your option) any later version.
     12 *
     13 * This program is distributed in the hope that it will be useful, but
     14 * WITHOUT ANY WARRANTY; without even the implied warranty of
     15 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
     16 * NON INFRINGEMENT.  See the GNU General Public License for more
     17 * details.
     18 *
     19 * You should have received a copy of the GNU General Public License
     20 * along with this program; if not, write to the Free Software
     21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
     22 *
     23 * Written by: Fenghua Yu <fenghua.yu@intel.com>, Intel Corporation
     24 * Copyright (C) 2006, Intel Corp.  All rights reserved.
     25 *
     26 */
     27#include <linux/device.h>
     28#include <linux/init.h>
     29#include <linux/mm.h>
     30#include <linux/cpu.h>
     31#include <linux/module.h>
     32
     33#define ERR_INJ_DEBUG
     34
     35#define ERR_DATA_BUFFER_SIZE 3 		// Three 8-byte;
     36
     37#define define_one_ro(name) 						\
     38static DEVICE_ATTR(name, 0444, show_##name, NULL)
     39
     40#define define_one_rw(name) 						\
     41static DEVICE_ATTR(name, 0644, show_##name, store_##name)
     42
     43static u64 call_start[NR_CPUS];
     44static u64 phys_addr[NR_CPUS];
     45static u64 err_type_info[NR_CPUS];
     46static u64 err_struct_info[NR_CPUS];
     47static struct {
     48	u64 data1;
     49	u64 data2;
     50	u64 data3;
     51} __attribute__((__aligned__(16))) err_data_buffer[NR_CPUS];
     52static s64 status[NR_CPUS];
     53static u64 capabilities[NR_CPUS];
     54static u64 resources[NR_CPUS];
     55
     56#define show(name) 							\
     57static ssize_t 								\
     58show_##name(struct device *dev, struct device_attribute *attr,	\
     59		char *buf)						\
     60{									\
     61	u32 cpu=dev->id;						\
     62	return sprintf(buf, "%llx\n", name[cpu]);			\
     63}
     64
     65#define store(name)							\
     66static ssize_t 								\
     67store_##name(struct device *dev, struct device_attribute *attr,	\
     68					const char *buf, size_t size)	\
     69{									\
     70	unsigned int cpu=dev->id;					\
     71	name[cpu] = simple_strtoull(buf, NULL, 16);			\
     72	return size;							\
     73}
     74
     75show(call_start)
     76
     77/* It's user's responsibility to call the PAL procedure on a specific
     78 * processor. The cpu number in driver is only used for storing data.
     79 */
     80static ssize_t
     81store_call_start(struct device *dev, struct device_attribute *attr,
     82		const char *buf, size_t size)
     83{
     84	unsigned int cpu=dev->id;
     85	unsigned long call_start = simple_strtoull(buf, NULL, 16);
     86
     87#ifdef ERR_INJ_DEBUG
     88	printk(KERN_DEBUG "pal_mc_err_inject for cpu%d:\n", cpu);
     89	printk(KERN_DEBUG "err_type_info=%llx,\n", err_type_info[cpu]);
     90	printk(KERN_DEBUG "err_struct_info=%llx,\n", err_struct_info[cpu]);
     91	printk(KERN_DEBUG "err_data_buffer=%llx, %llx, %llx.\n",
     92			  err_data_buffer[cpu].data1,
     93			  err_data_buffer[cpu].data2,
     94			  err_data_buffer[cpu].data3);
     95#endif
     96	switch (call_start) {
     97	    case 0: /* Do nothing. */
     98		break;
     99	    case 1: /* Call pal_mc_error_inject in physical mode. */
    100		status[cpu]=ia64_pal_mc_error_inject_phys(err_type_info[cpu],
    101					err_struct_info[cpu],
    102					ia64_tpa(&err_data_buffer[cpu]),
    103					&capabilities[cpu],
    104			 		&resources[cpu]);
    105		break;
    106	    case 2: /* Call pal_mc_error_inject in virtual mode. */
    107		status[cpu]=ia64_pal_mc_error_inject_virt(err_type_info[cpu],
    108					err_struct_info[cpu],
    109					ia64_tpa(&err_data_buffer[cpu]),
    110					&capabilities[cpu],
    111			 		&resources[cpu]);
    112		break;
    113	    default:
    114		status[cpu] = -EINVAL;
    115		break;
    116	}
    117
    118#ifdef ERR_INJ_DEBUG
    119	printk(KERN_DEBUG "Returns: status=%d,\n", (int)status[cpu]);
    120	printk(KERN_DEBUG "capabilities=%llx,\n", capabilities[cpu]);
    121	printk(KERN_DEBUG "resources=%llx\n", resources[cpu]);
    122#endif
    123	return size;
    124}
    125
    126show(err_type_info)
    127store(err_type_info)
    128
    129static ssize_t
    130show_virtual_to_phys(struct device *dev, struct device_attribute *attr,
    131			char *buf)
    132{
    133	unsigned int cpu=dev->id;
    134	return sprintf(buf, "%llx\n", phys_addr[cpu]);
    135}
    136
    137static ssize_t
    138store_virtual_to_phys(struct device *dev, struct device_attribute *attr,
    139			const char *buf, size_t size)
    140{
    141	unsigned int cpu=dev->id;
    142	u64 virt_addr=simple_strtoull(buf, NULL, 16);
    143	int ret;
    144
    145	ret = get_user_pages_fast(virt_addr, 1, FOLL_WRITE, NULL);
    146	if (ret<=0) {
    147#ifdef ERR_INJ_DEBUG
    148		printk("Virtual address %llx is not existing.\n", virt_addr);
    149#endif
    150		return -EINVAL;
    151	}
    152
    153	phys_addr[cpu] = ia64_tpa(virt_addr);
    154	return size;
    155}
    156
    157show(err_struct_info)
    158store(err_struct_info)
    159
    160static ssize_t
    161show_err_data_buffer(struct device *dev,
    162			struct device_attribute *attr, char *buf)
    163{
    164	unsigned int cpu=dev->id;
    165
    166	return sprintf(buf, "%llx, %llx, %llx\n",
    167			err_data_buffer[cpu].data1,
    168			err_data_buffer[cpu].data2,
    169			err_data_buffer[cpu].data3);
    170}
    171
    172static ssize_t
    173store_err_data_buffer(struct device *dev,
    174			struct device_attribute *attr,
    175			const char *buf, size_t size)
    176{
    177	unsigned int cpu=dev->id;
    178	int ret;
    179
    180#ifdef ERR_INJ_DEBUG
    181	printk("write err_data_buffer=[%llx,%llx,%llx] on cpu%d\n",
    182		 err_data_buffer[cpu].data1,
    183		 err_data_buffer[cpu].data2,
    184		 err_data_buffer[cpu].data3,
    185		 cpu);
    186#endif
    187	ret = sscanf(buf, "%llx, %llx, %llx",
    188			&err_data_buffer[cpu].data1,
    189			&err_data_buffer[cpu].data2,
    190			&err_data_buffer[cpu].data3);
    191	if (ret!=ERR_DATA_BUFFER_SIZE)
    192		return -EINVAL;
    193
    194	return size;
    195}
    196
    197show(status)
    198show(capabilities)
    199show(resources)
    200
    201define_one_rw(call_start);
    202define_one_rw(err_type_info);
    203define_one_rw(err_struct_info);
    204define_one_rw(err_data_buffer);
    205define_one_rw(virtual_to_phys);
    206define_one_ro(status);
    207define_one_ro(capabilities);
    208define_one_ro(resources);
    209
    210static struct attribute *default_attrs[] = {
    211	&dev_attr_call_start.attr,
    212	&dev_attr_virtual_to_phys.attr,
    213	&dev_attr_err_type_info.attr,
    214	&dev_attr_err_struct_info.attr,
    215	&dev_attr_err_data_buffer.attr,
    216	&dev_attr_status.attr,
    217	&dev_attr_capabilities.attr,
    218	&dev_attr_resources.attr,
    219	NULL
    220};
    221
    222static struct attribute_group err_inject_attr_group = {
    223	.attrs = default_attrs,
    224	.name = "err_inject"
    225};
    226/* Add/Remove err_inject interface for CPU device */
    227static int err_inject_add_dev(unsigned int cpu)
    228{
    229	struct device *sys_dev = get_cpu_device(cpu);
    230
    231	return sysfs_create_group(&sys_dev->kobj, &err_inject_attr_group);
    232}
    233
    234static int err_inject_remove_dev(unsigned int cpu)
    235{
    236	struct device *sys_dev = get_cpu_device(cpu);
    237
    238	sysfs_remove_group(&sys_dev->kobj, &err_inject_attr_group);
    239	return 0;
    240}
    241
    242static enum cpuhp_state hp_online;
    243
    244static int __init err_inject_init(void)
    245{
    246	int ret;
    247#ifdef ERR_INJ_DEBUG
    248	printk(KERN_INFO "Enter error injection driver.\n");
    249#endif
    250
    251	ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "ia64/err_inj:online",
    252				err_inject_add_dev, err_inject_remove_dev);
    253	if (ret >= 0) {
    254		hp_online = ret;
    255		ret = 0;
    256	}
    257	return ret;
    258}
    259
    260static void __exit err_inject_exit(void)
    261{
    262#ifdef ERR_INJ_DEBUG
    263	printk(KERN_INFO "Exit error injection driver.\n");
    264#endif
    265	cpuhp_remove_state(hp_online);
    266}
    267
    268module_init(err_inject_init);
    269module_exit(err_inject_exit);
    270
    271MODULE_AUTHOR("Fenghua Yu <fenghua.yu@intel.com>");
    272MODULE_DESCRIPTION("MC error injection kernel sysfs interface");
    273MODULE_LICENSE("GPL");