Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 081860b9 authored by Guo Ren's avatar Guo Ren
Browse files

csky: Exception handling and mm-fault



This patch adds exception handling code, cpuinfo and mm-fault code.

Signed-off-by: default avatarGuo Ren <ren_guo@c-sky.com>
Reviewed-by: default avatarArnd Bergmann <arnd@arndb.de>
parent 9143a935
Loading
Loading
Loading
Loading
+326 −0
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.

#include <linux/kernel.h>
#include <linux/uaccess.h>
#include <linux/ptrace.h>

static int align_enable = 1;
static int align_count;

static inline uint32_t get_ptreg(struct pt_regs *regs, uint32_t rx)
{
	return rx == 15 ? regs->lr : *((uint32_t *)&(regs->a0) - 2 + rx);
}

static inline void put_ptreg(struct pt_regs *regs, uint32_t rx, uint32_t val)
{
	if (rx == 15)
		regs->lr = val;
	else
		*((uint32_t *)&(regs->a0) - 2 + rx) = val;
}

/*
 * Get byte-value from addr and set it to *valp.
 *
 * Success: return 0
 * Failure: return 1
 */
static int ldb_asm(uint32_t addr, uint32_t *valp)
{
	uint32_t val;
	int err;

	if (!access_ok(VERIFY_READ, (void *)addr, 1))
		return 1;

	asm volatile (
		"movi	%0, 0\n"
		"1:\n"
		"ldb	%1, (%2)\n"
		"br	3f\n"
		"2:\n"
		"movi	%0, 1\n"
		"br	3f\n"
		".section __ex_table,\"a\"\n"
		".align 2\n"
		".long	1b, 2b\n"
		".previous\n"
		"3:\n"
		: "=&r"(err), "=r"(val)
		: "r" (addr)
	);

	*valp = val;

	return err;
}

/*
 * Put byte-value to addr.
 *
 * Success: return 0
 * Failure: return 1
 */
static int stb_asm(uint32_t addr, uint32_t val)
{
	int err;

	if (!access_ok(VERIFY_WRITE, (void *)addr, 1))
		return 1;

	asm volatile (
		"movi	%0, 0\n"
		"1:\n"
		"stb	%1, (%2)\n"
		"br	3f\n"
		"2:\n"
		"movi	%0, 1\n"
		"br	3f\n"
		".section __ex_table,\"a\"\n"
		".align 2\n"
		".long	1b, 2b\n"
		".previous\n"
		"3:\n"
		: "=&r"(err)
		: "r"(val), "r" (addr)
	);

	return err;
}

/*
 * Get half-word from [rx + imm]
 *
 * Success: return 0
 * Failure: return 1
 */
static int ldh_c(struct pt_regs *regs, uint32_t rz, uint32_t addr)
{
	uint32_t byte0, byte1;

	if (ldb_asm(addr, &byte0))
		return 1;
	addr += 1;
	if (ldb_asm(addr, &byte1))
		return 1;

	byte0 |= byte1 << 8;
	put_ptreg(regs, rz, byte0);

	return 0;
}

/*
 * Store half-word to [rx + imm]
 *
 * Success: return 0
 * Failure: return 1
 */
static int sth_c(struct pt_regs *regs, uint32_t rz, uint32_t addr)
{
	uint32_t byte0, byte1;

	byte0 = byte1 = get_ptreg(regs, rz);

	byte0 &= 0xff;

	if (stb_asm(addr, byte0))
		return 1;

	addr += 1;
	byte1 = (byte1 >> 8) & 0xff;
	if (stb_asm(addr, byte1))
		return 1;

	return 0;
}

/*
 * Get word from [rx + imm]
 *
 * Success: return 0
 * Failure: return 1
 */
static int ldw_c(struct pt_regs *regs, uint32_t rz, uint32_t addr)
{
	uint32_t byte0, byte1, byte2, byte3;

	if (ldb_asm(addr, &byte0))
		return 1;

	addr += 1;
	if (ldb_asm(addr, &byte1))
		return 1;

	addr += 1;
	if (ldb_asm(addr, &byte2))
		return 1;

	addr += 1;
	if (ldb_asm(addr, &byte3))
		return 1;

	byte0 |= byte1 << 8;
	byte0 |= byte2 << 16;
	byte0 |= byte3 << 24;

	put_ptreg(regs, rz, byte0);

	return 0;
}

/*
 * Store word to [rx + imm]
 *
 * Success: return 0
 * Failure: return 1
 */
static int stw_c(struct pt_regs *regs, uint32_t rz, uint32_t addr)
{
	uint32_t byte0, byte1, byte2, byte3;

	byte0 = byte1 = byte2 = byte3 = get_ptreg(regs, rz);

	byte0 &= 0xff;

	if (stb_asm(addr, byte0))
		return 1;

	addr += 1;
	byte1 = (byte1 >> 8) & 0xff;
	if (stb_asm(addr, byte1))
		return 1;

	addr += 1;
	byte2 = (byte2 >> 16) & 0xff;
	if (stb_asm(addr, byte2))
		return 1;

	addr += 1;
	byte3 = (byte3 >> 24) & 0xff;
	if (stb_asm(addr, byte3))
		return 1;

	align_count++;

	return 0;
}

extern int fixup_exception(struct pt_regs *regs);

#define OP_LDH 0xc000
#define OP_STH 0xd000
#define OP_LDW 0x8000
#define OP_STW 0x9000

void csky_alignment(struct pt_regs *regs)
{
	int ret;
	uint16_t tmp;
	uint32_t opcode = 0;
	uint32_t rx     = 0;
	uint32_t rz     = 0;
	uint32_t imm    = 0;
	uint32_t addr   = 0;

	if (!user_mode(regs))
		goto bad_area;

	ret = get_user(tmp, (uint16_t *)instruction_pointer(regs));
	if (ret) {
		pr_err("%s get_user failed.\n", __func__);
		goto bad_area;
	}

	opcode = (uint32_t)tmp;

	rx  = opcode & 0xf;
	imm = (opcode >> 4) & 0xf;
	rz  = (opcode >> 8) & 0xf;
	opcode &= 0xf000;

	if (rx == 0 || rx == 1 || rz == 0 || rz == 1)
		goto bad_area;

	switch (opcode) {
	case OP_LDH:
		addr = get_ptreg(regs, rx) + (imm << 1);
		ret = ldh_c(regs, rz, addr);
		break;
	case OP_LDW:
		addr = get_ptreg(regs, rx) + (imm << 2);
		ret = ldw_c(regs, rz, addr);
		break;
	case OP_STH:
		addr = get_ptreg(regs, rx) + (imm << 1);
		ret = sth_c(regs, rz, addr);
		break;
	case OP_STW:
		addr = get_ptreg(regs, rx) + (imm << 2);
		ret = stw_c(regs, rz, addr);
		break;
	}

	if (ret)
		goto bad_area;

	regs->pc += 2;

	return;

bad_area:
	if (!user_mode(regs)) {
		if (fixup_exception(regs))
			return;

		bust_spinlocks(1);
		pr_alert("%s opcode: %x, rz: %d, rx: %d, imm: %d, addr: %x.\n",
				__func__, opcode, rz, rx, imm, addr);
		show_regs(regs);
		bust_spinlocks(0);
		do_exit(SIGKILL);
	}

	force_sig_fault(SIGBUS, BUS_ADRALN, (void __user *)addr, current);
}

static struct ctl_table alignment_tbl[4] = {
	{
		.procname = "enable",
		.data = &align_enable,
		.maxlen = sizeof(align_enable),
		.mode = 0666,
		.proc_handler = &proc_dointvec
	},
	{
		.procname = "count",
		.data = &align_count,
		.maxlen = sizeof(align_count),
		.mode = 0666,
		.proc_handler = &proc_dointvec
	},
	{}
};

static struct ctl_table sysctl_table[2] = {
	{
	 .procname = "csky_alignment",
	 .mode = 0555,
	 .child = alignment_tbl},
	{}
};

static struct ctl_path sysctl_path[2] = {
	{.procname = "csky"},
	{}
};

static int __init csky_alignment_init(void)
{
	register_sysctl_paths(sysctl_path, sysctl_table);
	return 0;
}

arch_initcall(csky_alignment_init);
+160 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.

#ifndef __ASM_CSKY_ENTRY_H
#define __ASM_CSKY_ENTRY_H

#include <asm/setup.h>
#include <abi/regdef.h>

#define LSAVE_PC	8
#define LSAVE_PSR	12
#define LSAVE_A0	24
#define LSAVE_A1	28
#define LSAVE_A2	32
#define LSAVE_A3	36
#define LSAVE_A4	40
#define LSAVE_A5	44

#define EPC_INCREASE	2
#define EPC_KEEP	0

.macro USPTOKSP
	mtcr	sp, ss1
	mfcr	sp, ss0
.endm

.macro KSPTOUSP
	mtcr	sp, ss0
	mfcr	sp, ss1
.endm

.macro INCTRAP	rx
	addi	\rx, EPC_INCREASE
.endm

.macro	SAVE_ALL epc_inc
	mtcr    r13, ss2
	mfcr    r13, epsr
	btsti   r13, 31
	bt      1f
	USPTOKSP
1:
	subi    sp, 32
	subi    sp, 32
	subi    sp, 16
	stw     r13, (sp, 12)

	stw     lr, (sp, 4)

	mfcr	lr, epc
	movi	r13, \epc_inc
	add	lr, r13
	stw     lr, (sp, 8)

	mfcr	lr, ss1
	stw     lr, (sp, 16)

	stw     a0, (sp, 20)
	stw     a0, (sp, 24)
	stw     a1, (sp, 28)
	stw     a2, (sp, 32)
	stw     a3, (sp, 36)

	addi	sp, 32
	addi	sp, 8
	mfcr    r13, ss2
	stw	r6, (sp)
	stw	r7, (sp, 4)
	stw	r8, (sp, 8)
	stw	r9, (sp, 12)
	stw	r10, (sp, 16)
	stw	r11, (sp, 20)
	stw	r12, (sp, 24)
	stw	r13, (sp, 28)
	stw	r14, (sp, 32)
	stw	r1, (sp, 36)
	subi	sp, 32
	subi	sp, 8
.endm

.macro	RESTORE_ALL
	psrclr  ie
	ldw	lr, (sp, 4)
	ldw     a0, (sp, 8)
	mtcr    a0, epc
	ldw     a0, (sp, 12)
	mtcr    a0, epsr
	btsti   a0, 31
	ldw     a0, (sp, 16)
	mtcr	a0, ss1

	ldw     a0, (sp, 24)
	ldw     a1, (sp, 28)
	ldw     a2, (sp, 32)
	ldw     a3, (sp, 36)

	addi	sp, 32
	addi	sp, 8
	ldw	r6, (sp)
	ldw	r7, (sp, 4)
	ldw	r8, (sp, 8)
	ldw	r9, (sp, 12)
	ldw	r10, (sp, 16)
	ldw	r11, (sp, 20)
	ldw	r12, (sp, 24)
	ldw	r13, (sp, 28)
	ldw	r14, (sp, 32)
	ldw	r1, (sp, 36)
	addi	sp, 32
	addi	sp, 8

	bt      1f
	KSPTOUSP
1:
	rte
.endm

.macro SAVE_SWITCH_STACK
	subi    sp, 32
	stm     r8-r15, (sp)
.endm

.macro RESTORE_SWITCH_STACK
	ldm     r8-r15, (sp)
	addi    sp, 32
.endm

/* MMU registers operators. */
.macro RD_MIR	rx
	cprcr   \rx, cpcr0
.endm

.macro RD_MEH	rx
	cprcr   \rx, cpcr4
.endm

.macro RD_MCIR	rx
	cprcr   \rx, cpcr8
.endm

.macro RD_PGDR  rx
	cprcr   \rx, cpcr29
.endm

.macro WR_MEH	rx
	cpwcr   \rx, cpcr4
.endm

.macro WR_MCIR	rx
	cpwcr   \rx, cpcr8
.endm

.macro SETUP_MMU rx
	lrw	\rx, PHYS_OFFSET | 0xe
	cpwcr	\rx, cpcr30
	lrw	\rx, (PHYS_OFFSET + 0x20000000) | 0xe
	cpwcr	\rx, cpcr31
.endm

#endif /* __ASM_CSKY_ENTRY_H */
+156 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.

#ifndef __ASM_CSKY_ENTRY_H
#define __ASM_CSKY_ENTRY_H

#include <asm/setup.h>
#include <abi/regdef.h>

#define LSAVE_PC	8
#define LSAVE_PSR	12
#define LSAVE_A0	24
#define LSAVE_A1	28
#define LSAVE_A2	32
#define LSAVE_A3	36

#define EPC_INCREASE	4
#define EPC_KEEP	0

#define KSPTOUSP
#define USPTOKSP

#define usp cr<14, 1>

.macro INCTRAP	rx
	addi	\rx, EPC_INCREASE
.endm

.macro SAVE_ALL epc_inc
	subi    sp, 152
	stw	tls, (sp, 0)
	stw	lr, (sp, 4)

	mfcr	lr, epc
	movi	tls, \epc_inc
	add	lr, tls
	stw	lr, (sp, 8)

	mfcr	lr, epsr
	stw	lr, (sp, 12)
	mfcr	lr, usp
	stw	lr, (sp, 16)

	stw     a0, (sp, 20)
	stw     a0, (sp, 24)
	stw     a1, (sp, 28)
	stw     a2, (sp, 32)
	stw     a3, (sp, 36)

	addi	sp, 40
	stm	r4-r13, (sp)

	addi    sp, 40
	stm     r16-r30, (sp)
#ifdef CONFIG_CPU_HAS_HILO
	mfhi	lr
	stw	lr, (sp, 60)
	mflo	lr
	stw	lr, (sp, 64)
#endif
	subi	sp, 80
.endm

.macro	RESTORE_ALL
	psrclr  ie
	ldw	tls, (sp, 0)
	ldw	lr, (sp, 4)
	ldw	a0, (sp, 8)
	mtcr	a0, epc
	ldw	a0, (sp, 12)
	mtcr	a0, epsr
	ldw	a0, (sp, 16)
	mtcr	a0, usp

#ifdef CONFIG_CPU_HAS_HILO
	ldw	a0, (sp, 140)
	mthi	a0
	ldw	a0, (sp, 144)
	mtlo	a0
#endif

	ldw     a0, (sp, 24)
	ldw     a1, (sp, 28)
	ldw     a2, (sp, 32)
	ldw     a3, (sp, 36)

	addi	sp, 40
	ldm	r4-r13, (sp)
	addi    sp, 40
	ldm     r16-r30, (sp)
	addi    sp, 72
	rte
.endm

.macro SAVE_SWITCH_STACK
	subi	sp, 64
	stm	r4-r11, (sp)
	stw	r15, (sp, 32)
	stw	r16, (sp, 36)
	stw	r17, (sp, 40)
	stw	r26, (sp, 44)
	stw	r27, (sp, 48)
	stw	r28, (sp, 52)
	stw	r29, (sp, 56)
	stw	r30, (sp, 60)
.endm

.macro RESTORE_SWITCH_STACK
	ldm	r4-r11, (sp)
	ldw	r15, (sp, 32)
	ldw	r16, (sp, 36)
	ldw	r17, (sp, 40)
	ldw	r26, (sp, 44)
	ldw	r27, (sp, 48)
	ldw	r28, (sp, 52)
	ldw	r29, (sp, 56)
	ldw	r30, (sp, 60)
	addi	sp, 64
.endm

/* MMU registers operators. */
.macro RD_MIR rx
	mfcr	\rx, cr<0, 15>
.endm

.macro RD_MEH rx
	mfcr	\rx, cr<4, 15>
.endm

.macro RD_MCIR rx
	mfcr	\rx, cr<8, 15>
.endm

.macro RD_PGDR rx
	mfcr	\rx, cr<29, 15>
.endm

.macro RD_PGDR_K rx
	mfcr	\rx, cr<28, 15>
.endm

.macro WR_MEH rx
	mtcr	\rx, cr<4, 15>
.endm

.macro WR_MCIR rx
	mtcr	\rx, cr<8, 15>
.endm

.macro SETUP_MMU rx
	lrw	\rx, PHYS_OFFSET | 0xe
	mtcr	\rx, cr<30, 15>
	lrw	\rx, (PHYS_OFFSET + 0x20000000) | 0xe
	mtcr	\rx, cr<31, 15>
.endm
#endif /* __ASM_CSKY_ENTRY_H */
+44 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.

#ifndef __ASM_CSKY_TRAPS_H
#define __ASM_CSKY_TRAPS_H

#define VEC_RESET	0
#define VEC_ALIGN	1
#define VEC_ACCESS	2
#define VEC_ZERODIV	3
#define VEC_ILLEGAL	4
#define VEC_PRIV	5
#define VEC_TRACE	6
#define VEC_BREAKPOINT	7
#define VEC_UNRECOVER	8
#define VEC_SOFTRESET	9
#define VEC_AUTOVEC	10
#define VEC_FAUTOVEC	11
#define VEC_HWACCEL	12

#define	VEC_TLBMISS	14
#define	VEC_TLBMODIFIED	15

#define VEC_TRAP0	16
#define VEC_TRAP1	17
#define VEC_TRAP2	18
#define VEC_TRAP3	19

#define	VEC_TLBINVALIDL	20
#define	VEC_TLBINVALIDS	21

#define VEC_PRFL	29
#define VEC_FPE		30

extern void *vec_base[];

#define VEC_INIT(i, func) \
do { \
	vec_base[i] = (void *)func; \
} while (0)

void csky_alignment(struct pt_regs *regs);

#endif /* __ASM_CSKY_TRAPS_H */
+4 −0
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0 */
// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.

#include <uapi/asm/unistd.h>
Loading