Commit 2a0b24f5 authored by Steven J. Hill's avatar Steven J. Hill Committed by Ralf Baechle

MIPS: microMIPS: Add support for exception handling.

All exceptions must be taken in microMIPS mode, never in classic
MIPS mode or the kernel falls apart. A few NOP instructions are
used to maintain the correct alignment of microMIPS versions of
the exception vectors.
Signed-off-by: default avatarSteven J. Hill <Steven.Hill@imgtec.com>
parent 102cedc3
......@@ -596,6 +596,7 @@
#define MIPS_CONF3_RXI (_ULCAST_(1) << 12)
#define MIPS_CONF3_ULRI (_ULCAST_(1) << 13)
#define MIPS_CONF3_ISA (_ULCAST_(3) << 14)
#define MIPS_CONF3_ISA_OE (_ULCAST_(3) << 16)
#define MIPS_CONF3_VZ (_ULCAST_(1) << 23)
#define MIPS_CONF4_MMUSIZEEXT (_ULCAST_(255) << 0)
......
......@@ -139,7 +139,7 @@
1: move ra, k0
li k0, 3
mtc0 k0, $22
#endif /* CONFIG_CPU_LOONGSON2F */
#endif /* CONFIG_CPU_JUMP_WORKAROUNDS */
#if defined(CONFIG_32BIT) || defined(KBUILD_64BIT_SYM32)
lui k1, %hi(kernelsp)
#else
......@@ -189,6 +189,7 @@
LONG_S $0, PT_R0(sp)
mfc0 v1, CP0_STATUS
LONG_S $2, PT_R2(sp)
LONG_S v1, PT_STATUS(sp)
#ifdef CONFIG_MIPS_MT_SMTC
/*
* Ideally, these instructions would be shuffled in
......@@ -200,21 +201,20 @@
LONG_S k0, PT_TCSTATUS(sp)
#endif /* CONFIG_MIPS_MT_SMTC */
LONG_S $4, PT_R4(sp)
LONG_S $5, PT_R5(sp)
LONG_S v1, PT_STATUS(sp)
mfc0 v1, CP0_CAUSE
LONG_S $6, PT_R6(sp)
LONG_S $7, PT_R7(sp)
LONG_S $5, PT_R5(sp)
LONG_S v1, PT_CAUSE(sp)
LONG_S $6, PT_R6(sp)
MFC0 v1, CP0_EPC
LONG_S $7, PT_R7(sp)
#ifdef CONFIG_64BIT
LONG_S $8, PT_R8(sp)
LONG_S $9, PT_R9(sp)
#endif
LONG_S v1, PT_EPC(sp)
LONG_S $25, PT_R25(sp)
LONG_S $28, PT_R28(sp)
LONG_S $31, PT_R31(sp)
LONG_S v1, PT_EPC(sp)
ori $28, sp, _THREAD_MASK
xori $28, _THREAD_MASK
#ifdef CONFIG_CPU_CAVIUM_OCTEON
......
......@@ -470,6 +470,9 @@ static inline unsigned int decode_config3(struct cpuinfo_mips *c)
c->options |= MIPS_CPU_ULRI;
if (config3 & MIPS_CONF3_ISA)
c->options |= MIPS_CPU_MICROMIPS;
#ifdef CONFIG_CPU_MICROMIPS
write_c0_config3(read_c0_config3() | MIPS_CONF3_ISA_OE);
#endif
if (config3 & MIPS_CONF3_VZ)
c->ases |= MIPS_ASE_VZ;
......
......@@ -5,8 +5,8 @@
*
* Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle
* Copyright (C) 1999, 2000 Silicon Graphics, Inc.
* Copyright (C) 2001 MIPS Technologies, Inc.
* Copyright (C) 2002, 2007 Maciej W. Rozycki
* Copyright (C) 2001, 2012 MIPS Technologies, Inc. All rights reserved.
*/
#include <linux/init.h>
......@@ -21,8 +21,10 @@
#include <asm/war.h>
#include <asm/thread_info.h>
#ifdef CONFIG_MIPS_MT_SMTC
#define PANIC_PIC(msg) \
.set push; \
.set push; \
.set nomicromips; \
.set reorder; \
PTR_LA a0,8f; \
.set noat; \
......@@ -31,17 +33,10 @@
9: b 9b; \
.set pop; \
TEXT(msg)
#endif
__INIT
NESTED(except_vec0_generic, 0, sp)
PANIC_PIC("Exception vector 0 called")
END(except_vec0_generic)
NESTED(except_vec1_generic, 0, sp)
PANIC_PIC("Exception vector 1 called")
END(except_vec1_generic)
/*
* General exception vector for all other CPUs.
*
......@@ -138,12 +133,19 @@ LEAF(r4k_wait)
nop
nop
nop
#ifdef CONFIG_CPU_MICROMIPS
nop
nop
nop
nop
#endif
.set mips3
wait
/* end of rollback region (the region size must be power of two) */
.set pop
1:
jr ra
nop
.set pop
END(r4k_wait)
.macro BUILD_ROLLBACK_PROLOGUE handler
......@@ -201,7 +203,11 @@ NESTED(handle_int, PT_SIZE, sp)
LONG_L s0, TI_REGS($28)
LONG_S sp, TI_REGS($28)
PTR_LA ra, ret_from_irq
j plat_irq_dispatch
PTR_LA v0, plat_irq_dispatch
jr v0
#ifdef CONFIG_CPU_MICROMIPS
nop
#endif
END(handle_int)
__INIT
......@@ -222,11 +228,14 @@ NESTED(except_vec4, 0, sp)
/*
* EJTAG debug exception handler.
* The EJTAG debug exception entry point is 0xbfc00480, which
* normally is in the boot PROM, so the boot PROM must do a
* normally is in the boot PROM, so the boot PROM must do an
* unconditional jump to this vector.
*/
NESTED(except_vec_ejtag_debug, 0, sp)
j ejtag_debug_handler
#ifdef CONFIG_CPU_MICROMIPS
nop
#endif
END(except_vec_ejtag_debug)
__FINIT
......@@ -251,9 +260,10 @@ NESTED(except_vec_vi, 0, sp)
FEXPORT(except_vec_vi_mori)
ori a0, $0, 0
#endif /* CONFIG_MIPS_MT_SMTC */
PTR_LA v1, except_vec_vi_handler
FEXPORT(except_vec_vi_lui)
lui v0, 0 /* Patched */
j except_vec_vi_handler
jr v1
FEXPORT(except_vec_vi_ori)
ori v0, 0 /* Patched */
.set pop
......@@ -354,6 +364,9 @@ EXPORT(ejtag_debug_buffer)
*/
NESTED(except_vec_nmi, 0, sp)
j nmi_handler
#ifdef CONFIG_CPU_MICROMIPS
nop
#endif
END(except_vec_nmi)
__FINIT
......@@ -500,13 +513,35 @@ NESTED(nmi_handler, PT_SIZE, sp)
.set push
.set noat
.set noreorder
/* 0x7c03e83b: rdhwr v1,$29 */
/* MIPS32: 0x7c03e83b: rdhwr v1,$29 */
/* microMIPS: 0x007d6b3c: rdhwr v1,$29 */
MFC0 k1, CP0_EPC
lui k0, 0x7c03
lw k1, (k1)
ori k0, 0xe83b
.set reorder
#if defined(CONFIG_CPU_MICROMIPS) || defined(CONFIG_CPU_MIPS32_R2) || defined(CONFIG_CPU_MIPS64_R2)
and k0, k1, 1
beqz k0, 1f
xor k1, k0
lhu k0, (k1)
lhu k1, 2(k1)
ins k1, k0, 16, 16
lui k0, 0x007d
b docheck
ori k0, 0x6b3c
1:
lui k0, 0x7c03
lw k1, (k1)
ori k0, 0xe83b
#else
andi k0, k1, 1
bnez k0, handle_ri
lui k0, 0x7c03
lw k1, (k1)
ori k0, 0xe83b
#endif
.set reorder
docheck:
bne k0, k1, handle_ri /* if not ours */
isrdhwr:
/* The insn is rdhwr. No need to check CAUSE.BD here. */
get_saved_sp /* k1 := current_thread_info */
.set noreorder
......
......@@ -138,9 +138,18 @@ stackargs:
5: jr t1
sw t5, 16(sp) # argument #5 to ksp
#ifdef CONFIG_CPU_MICROMIPS
sw t8, 28(sp) # argument #8 to ksp
nop
sw t7, 24(sp) # argument #7 to ksp
nop
sw t6, 20(sp) # argument #6 to ksp
nop
#else
sw t8, 28(sp) # argument #8 to ksp
sw t7, 24(sp) # argument #7 to ksp
sw t6, 20(sp) # argument #6 to ksp
#endif
6: j stack_done # go back
nop
.set pop
......
......@@ -49,6 +49,9 @@ CAN WE PROVE THAT WE WON'T DO THIS IF INTS DISABLED??
.text
.align 5
FEXPORT(__smtc_ipi_vector)
#ifdef CONFIG_CPU_MICROMIPS
nop
#endif
.set noat
/* Disable thread scheduling to make Status update atomic */
DMT 27 # dmt k1
......
This diff is collapsed.
......@@ -2103,6 +2103,13 @@ static void __cpuinit build_r4000_tlb_load_handler(void)
uasm_l_nopage_tlbl(&l, p);
build_restore_work_registers(&p);
#ifdef CONFIG_CPU_MICROMIPS
if ((unsigned long)tlb_do_page_fault_0 & 1) {
uasm_i_lui(&p, K0, uasm_rel_hi((long)tlb_do_page_fault_0));
uasm_i_addiu(&p, K0, K0, uasm_rel_lo((long)tlb_do_page_fault_0));
uasm_i_jr(&p, K0);
} else
#endif
uasm_i_j(&p, (unsigned long)tlb_do_page_fault_0 & 0x0fffffff);
uasm_i_nop(&p);
......@@ -2150,6 +2157,13 @@ static void __cpuinit build_r4000_tlb_store_handler(void)
uasm_l_nopage_tlbs(&l, p);
build_restore_work_registers(&p);
#ifdef CONFIG_CPU_MICROMIPS
if ((unsigned long)tlb_do_page_fault_1 & 1) {
uasm_i_lui(&p, K0, uasm_rel_hi((long)tlb_do_page_fault_1));
uasm_i_addiu(&p, K0, K0, uasm_rel_lo((long)tlb_do_page_fault_1));
uasm_i_jr(&p, K0);
} else
#endif
uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
uasm_i_nop(&p);
......@@ -2198,6 +2212,13 @@ static void __cpuinit build_r4000_tlb_modify_handler(void)
uasm_l_nopage_tlbm(&l, p);
build_restore_work_registers(&p);
#ifdef CONFIG_CPU_MICROMIPS
if ((unsigned long)tlb_do_page_fault_1 & 1) {
uasm_i_lui(&p, K0, uasm_rel_hi((long)tlb_do_page_fault_1));
uasm_i_addiu(&p, K0, K0, uasm_rel_lo((long)tlb_do_page_fault_1));
uasm_i_jr(&p, K0);
} else
#endif
uasm_i_j(&p, (unsigned long)tlb_do_page_fault_1 & 0x0fffffff);
uasm_i_nop(&p);
......
......@@ -65,7 +65,41 @@ static void __init mips_nmi_setup(void)
base = cpu_has_veic ?
(void *)(CAC_BASE + 0xa80) :
(void *)(CAC_BASE + 0x380);
#ifdef CONFIG_CPU_MICROMIPS
/*
* Decrement the exception vector address by one for microMIPS.
*/
memcpy(base, (&except_vec_nmi - 1), 0x80);
/*
* This is a hack. We do not know if the boot loader was built with
* microMIPS instructions or not. If it was not, the NMI exception
* code at 0x80000a80 will be taken in MIPS32 mode. The hand coded
* assembly below forces us into microMIPS mode if we are a pure
* microMIPS kernel. The assembly instructions are:
*
* 3C1A8000 lui k0,0x8000
* 375A0381 ori k0,k0,0x381
* 03400008 jr k0
* 00000000 nop
*
* The mode switch occurs by jumping to the unaligned exception
* vector address at 0x80000381 which would have been 0x80000380
* in MIPS32 mode. The jump to the unaligned address transitions
* us into microMIPS mode.
*/
if (!cpu_has_veic) {
void *base2 = (void *)(CAC_BASE + 0xa80);
*((unsigned int *)base2) = 0x3c1a8000;
*((unsigned int *)base2 + 1) = 0x375a0381;
*((unsigned int *)base2 + 2) = 0x03400008;
*((unsigned int *)base2 + 3) = 0x00000000;
flush_icache_range((unsigned long)base2,
(unsigned long)base2 + 0x10);
}
#else
memcpy(base, &except_vec_nmi, 0x80);
#endif
flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
}
......@@ -76,7 +110,21 @@ static void __init mips_ejtag_setup(void)
base = cpu_has_veic ?
(void *)(CAC_BASE + 0xa00) :
(void *)(CAC_BASE + 0x300);
#ifdef CONFIG_CPU_MICROMIPS
/* Deja vu... */
memcpy(base, (&except_vec_ejtag_debug - 1), 0x80);
if (!cpu_has_veic) {
void *base2 = (void *)(CAC_BASE + 0xa00);
*((unsigned int *)base2) = 0x3c1a8000;
*((unsigned int *)base2 + 1) = 0x375a0301;
*((unsigned int *)base2 + 2) = 0x03400008;
*((unsigned int *)base2 + 3) = 0x00000000;
flush_icache_range((unsigned long)base2,
(unsigned long)base2 + 0x10);
}
#else
memcpy(base, &except_vec_ejtag_debug, 0x80);
#endif
flush_icache_range((unsigned long)base, (unsigned long)base + 0x80);
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment