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

alignment.c (6073B)


      1// SPDX-License-Identifier: GPL-2.0
      2// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
      3
      4#include <linux/kernel.h>
      5#include <linux/uaccess.h>
      6#include <linux/ptrace.h>
      7
      8static int align_kern_enable = 1;
      9static int align_usr_enable = 1;
     10static int align_kern_count = 0;
     11static int align_usr_count = 0;
     12
     13static inline uint32_t get_ptreg(struct pt_regs *regs, uint32_t rx)
     14{
     15	return rx == 15 ? regs->lr : *((uint32_t *)&(regs->a0) - 2 + rx);
     16}
     17
     18static inline void put_ptreg(struct pt_regs *regs, uint32_t rx, uint32_t val)
     19{
     20	if (rx == 15)
     21		regs->lr = val;
     22	else
     23		*((uint32_t *)&(regs->a0) - 2 + rx) = val;
     24}
     25
     26/*
     27 * Get byte-value from addr and set it to *valp.
     28 *
     29 * Success: return 0
     30 * Failure: return 1
     31 */
     32static int ldb_asm(uint32_t addr, uint32_t *valp)
     33{
     34	uint32_t val;
     35	int err;
     36
     37	asm volatile (
     38		"movi	%0, 0\n"
     39		"1:\n"
     40		"ldb	%1, (%2)\n"
     41		"br	3f\n"
     42		"2:\n"
     43		"movi	%0, 1\n"
     44		"br	3f\n"
     45		".section __ex_table,\"a\"\n"
     46		".align 2\n"
     47		".long	1b, 2b\n"
     48		".previous\n"
     49		"3:\n"
     50		: "=&r"(err), "=r"(val)
     51		: "r" (addr)
     52	);
     53
     54	*valp = val;
     55
     56	return err;
     57}
     58
     59/*
     60 * Put byte-value to addr.
     61 *
     62 * Success: return 0
     63 * Failure: return 1
     64 */
     65static int stb_asm(uint32_t addr, uint32_t val)
     66{
     67	int err;
     68
     69	asm volatile (
     70		"movi	%0, 0\n"
     71		"1:\n"
     72		"stb	%1, (%2)\n"
     73		"br	3f\n"
     74		"2:\n"
     75		"movi	%0, 1\n"
     76		"br	3f\n"
     77		".section __ex_table,\"a\"\n"
     78		".align 2\n"
     79		".long	1b, 2b\n"
     80		".previous\n"
     81		"3:\n"
     82		: "=&r"(err)
     83		: "r"(val), "r" (addr)
     84	);
     85
     86	return err;
     87}
     88
     89/*
     90 * Get half-word from [rx + imm]
     91 *
     92 * Success: return 0
     93 * Failure: return 1
     94 */
     95static int ldh_c(struct pt_regs *regs, uint32_t rz, uint32_t addr)
     96{
     97	uint32_t byte0, byte1;
     98
     99	if (ldb_asm(addr, &byte0))
    100		return 1;
    101	addr += 1;
    102	if (ldb_asm(addr, &byte1))
    103		return 1;
    104
    105	byte0 |= byte1 << 8;
    106	put_ptreg(regs, rz, byte0);
    107
    108	return 0;
    109}
    110
    111/*
    112 * Store half-word to [rx + imm]
    113 *
    114 * Success: return 0
    115 * Failure: return 1
    116 */
    117static int sth_c(struct pt_regs *regs, uint32_t rz, uint32_t addr)
    118{
    119	uint32_t byte0, byte1;
    120
    121	byte0 = byte1 = get_ptreg(regs, rz);
    122
    123	byte0 &= 0xff;
    124
    125	if (stb_asm(addr, byte0))
    126		return 1;
    127
    128	addr += 1;
    129	byte1 = (byte1 >> 8) & 0xff;
    130	if (stb_asm(addr, byte1))
    131		return 1;
    132
    133	return 0;
    134}
    135
    136/*
    137 * Get word from [rx + imm]
    138 *
    139 * Success: return 0
    140 * Failure: return 1
    141 */
    142static int ldw_c(struct pt_regs *regs, uint32_t rz, uint32_t addr)
    143{
    144	uint32_t byte0, byte1, byte2, byte3;
    145
    146	if (ldb_asm(addr, &byte0))
    147		return 1;
    148
    149	addr += 1;
    150	if (ldb_asm(addr, &byte1))
    151		return 1;
    152
    153	addr += 1;
    154	if (ldb_asm(addr, &byte2))
    155		return 1;
    156
    157	addr += 1;
    158	if (ldb_asm(addr, &byte3))
    159		return 1;
    160
    161	byte0 |= byte1 << 8;
    162	byte0 |= byte2 << 16;
    163	byte0 |= byte3 << 24;
    164
    165	put_ptreg(regs, rz, byte0);
    166
    167	return 0;
    168}
    169
    170/*
    171 * Store word to [rx + imm]
    172 *
    173 * Success: return 0
    174 * Failure: return 1
    175 */
    176static int stw_c(struct pt_regs *regs, uint32_t rz, uint32_t addr)
    177{
    178	uint32_t byte0, byte1, byte2, byte3;
    179
    180	byte0 = byte1 = byte2 = byte3 = get_ptreg(regs, rz);
    181
    182	byte0 &= 0xff;
    183
    184	if (stb_asm(addr, byte0))
    185		return 1;
    186
    187	addr += 1;
    188	byte1 = (byte1 >> 8) & 0xff;
    189	if (stb_asm(addr, byte1))
    190		return 1;
    191
    192	addr += 1;
    193	byte2 = (byte2 >> 16) & 0xff;
    194	if (stb_asm(addr, byte2))
    195		return 1;
    196
    197	addr += 1;
    198	byte3 = (byte3 >> 24) & 0xff;
    199	if (stb_asm(addr, byte3))
    200		return 1;
    201
    202	return 0;
    203}
    204
    205extern int fixup_exception(struct pt_regs *regs);
    206
    207#define OP_LDH 0xc000
    208#define OP_STH 0xd000
    209#define OP_LDW 0x8000
    210#define OP_STW 0x9000
    211
    212void csky_alignment(struct pt_regs *regs)
    213{
    214	int ret;
    215	uint16_t tmp;
    216	uint32_t opcode = 0;
    217	uint32_t rx     = 0;
    218	uint32_t rz     = 0;
    219	uint32_t imm    = 0;
    220	uint32_t addr   = 0;
    221
    222	if (!user_mode(regs))
    223		goto kernel_area;
    224
    225	if (!align_usr_enable) {
    226		pr_err("%s user disabled.\n", __func__);
    227		goto bad_area;
    228	}
    229
    230	align_usr_count++;
    231
    232	ret = get_user(tmp, (uint16_t *)instruction_pointer(regs));
    233	if (ret) {
    234		pr_err("%s get_user failed.\n", __func__);
    235		goto bad_area;
    236	}
    237
    238	goto good_area;
    239
    240kernel_area:
    241	if (!align_kern_enable) {
    242		pr_err("%s kernel disabled.\n", __func__);
    243		goto bad_area;
    244	}
    245
    246	align_kern_count++;
    247
    248	tmp = *(uint16_t *)instruction_pointer(regs);
    249
    250good_area:
    251	opcode = (uint32_t)tmp;
    252
    253	rx  = opcode & 0xf;
    254	imm = (opcode >> 4) & 0xf;
    255	rz  = (opcode >> 8) & 0xf;
    256	opcode &= 0xf000;
    257
    258	if (rx == 0 || rx == 1 || rz == 0 || rz == 1)
    259		goto bad_area;
    260
    261	switch (opcode) {
    262	case OP_LDH:
    263		addr = get_ptreg(regs, rx) + (imm << 1);
    264		ret = ldh_c(regs, rz, addr);
    265		break;
    266	case OP_LDW:
    267		addr = get_ptreg(regs, rx) + (imm << 2);
    268		ret = ldw_c(regs, rz, addr);
    269		break;
    270	case OP_STH:
    271		addr = get_ptreg(regs, rx) + (imm << 1);
    272		ret = sth_c(regs, rz, addr);
    273		break;
    274	case OP_STW:
    275		addr = get_ptreg(regs, rx) + (imm << 2);
    276		ret = stw_c(regs, rz, addr);
    277		break;
    278	}
    279
    280	if (ret)
    281		goto bad_area;
    282
    283	regs->pc += 2;
    284
    285	return;
    286
    287bad_area:
    288	if (!user_mode(regs)) {
    289		if (fixup_exception(regs))
    290			return;
    291
    292		bust_spinlocks(1);
    293		pr_alert("%s opcode: %x, rz: %d, rx: %d, imm: %d, addr: %x.\n",
    294				__func__, opcode, rz, rx, imm, addr);
    295		show_regs(regs);
    296		bust_spinlocks(0);
    297		make_task_dead(SIGKILL);
    298	}
    299
    300	force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)addr);
    301}
    302
    303static struct ctl_table alignment_tbl[5] = {
    304	{
    305		.procname = "kernel_enable",
    306		.data = &align_kern_enable,
    307		.maxlen = sizeof(align_kern_enable),
    308		.mode = 0666,
    309		.proc_handler = &proc_dointvec
    310	},
    311	{
    312		.procname = "user_enable",
    313		.data = &align_usr_enable,
    314		.maxlen = sizeof(align_usr_enable),
    315		.mode = 0666,
    316		.proc_handler = &proc_dointvec
    317	},
    318	{
    319		.procname = "kernel_count",
    320		.data = &align_kern_count,
    321		.maxlen = sizeof(align_kern_count),
    322		.mode = 0666,
    323		.proc_handler = &proc_dointvec
    324	},
    325	{
    326		.procname = "user_count",
    327		.data = &align_usr_count,
    328		.maxlen = sizeof(align_usr_count),
    329		.mode = 0666,
    330		.proc_handler = &proc_dointvec
    331	},
    332	{}
    333};
    334
    335static struct ctl_table sysctl_table[2] = {
    336	{
    337	 .procname = "csky_alignment",
    338	 .mode = 0555,
    339	 .child = alignment_tbl},
    340	{}
    341};
    342
    343static struct ctl_path sysctl_path[2] = {
    344	{.procname = "csky"},
    345	{}
    346};
    347
    348static int __init csky_alignment_init(void)
    349{
    350	register_sysctl_paths(sysctl_path, sysctl_table);
    351	return 0;
    352}
    353
    354arch_initcall(csky_alignment_init);