mips: add support to restore exception vector base before booting linux
authorWeijie Gao <weijie.gao@mediatek.com>
Tue, 21 Apr 2020 07:28:25 +0000 (09:28 +0200)
committerDaniel Schwierzeck <daniel.schwierzeck@gmail.com>
Mon, 27 Apr 2020 18:29:33 +0000 (20:29 +0200)
In U-Boot the exception vector base will be moved to top of memory, to be
used to display register dump when exception occurs.

But some old linux kernel does not honor the base set in CP0_EBASE. A
modified exception vector base will cause kernel crash.

This patch adds an option to enable reset exception vector base to its
previous value, or a user configured value before booting linux kernel.

Reviewed-by: Daniel Schwierzeck <daniel.schwierzeck@gmail.com>
Signed-off-by: Weijie Gao <weijie.gao@mediatek.com>
arch/mips/Kconfig
arch/mips/include/asm/u-boot-mips.h
arch/mips/lib/bootm.c
arch/mips/lib/traps.c

index a3ae6030448523eb5dff8ecdaeffe1f7c6324b5c..5e20feeefb8b021d9903e56eb13d99ffaacc80f7 100644 (file)
@@ -287,6 +287,36 @@ config MIPS_RELOCATION_TABLE_SIZE
 
          If unsure, leave at the default value.
 
+config RESTORE_EXCEPTION_VECTOR_BASE
+       bool "Restore exception vector base before booting linux kernel"
+       default n
+       help
+         In U-Boot the exception vector base will be moved to top of memory,
+         to be used to display register dump when exception occurs.
+         But some old linux kernel does not honor the base set in CP0_EBASE.
+         A modified exception vector base will cause kernel crash.
+
+         This option will restore the exception vector base to its previous
+         value.
+
+         If unsure, say N.
+
+config OVERRIDE_EXCEPTION_VECTOR_BASE
+       bool "Override the exception vector base to be restored"
+       depends on RESTORE_EXCEPTION_VECTOR_BASE
+       default n
+       help
+         Enable this option if you want to use a different exception vector
+         base rather than the previously saved one.
+
+config NEW_EXCEPTION_VECTOR_BASE
+       hex "New exception vector base"
+       depends on OVERRIDE_EXCEPTION_VECTOR_BASE
+       range 0x80000000 0xbffff000
+       default 0x80000000
+       help
+         The exception vector base to be restored before booting linux kernel
+
 endmenu
 
 menu "OS boot interface"
index 88438b9576bbcf8bb9a4520d34c091e62d5d0b6e..8b37cc4029c7c477f3c5d20a77f33bf2dc1b7b33 100644 (file)
@@ -9,4 +9,6 @@ void except_vec_ejtag_debug(void);
 
 int arch_misc_init(void);
 
+void trap_restore(void);
+
 #endif /* _U_BOOT_MIPS_H_ */
index 8c0d7672f24ceab122c70e54236748f366b4eb25..f1db6d23b84e091fa098baada15e5f12ac3228a6 100644 (file)
@@ -294,6 +294,9 @@ static void boot_jump_linux(bootm_headers_t *images)
        bootstage_report();
 #endif
 
+       if (CONFIG_IS_ENABLED(RESTORE_EXCEPTION_VECTOR_BASE))
+               trap_restore();
+
        if (images->ft_len)
                kernel(-2, (ulong)images->ft_addr, 0, 0);
        else
index b8568c00fed53034ce48c6a368c6ebfd28bc392b..8fff7541e3c1e59d8cc8f709db01a713149cc923 100644 (file)
@@ -20,6 +20,8 @@
 
 DECLARE_GLOBAL_DATA_PTR;
 
+static unsigned long saved_ebase;
+
 static void show_regs(const struct pt_regs *regs)
 {
        const int field = 2 * sizeof(unsigned long);
@@ -102,7 +104,24 @@ void trap_init(ulong reloc_addr)
        set_handler(0x180, &except_vec3_generic, 0x80);
        set_handler(0x280, &except_vec_ejtag_debug, 0x80);
 
+       saved_ebase = read_c0_ebase() & 0xfffff000;
+
        write_c0_ebase(ebase);
        clear_c0_status(ST0_BEV);
        execution_hazard_barrier();
 }
+
+void trap_restore(void)
+{
+       set_c0_status(ST0_BEV);
+       execution_hazard_barrier();
+
+#ifdef CONFIG_OVERRIDE_EXCEPTION_VECTOR_BASE
+       write_c0_ebase(CONFIG_NEW_EXCEPTION_VECTOR_BASE & 0xfffff000);
+#else
+       write_c0_ebase(saved_ebase);
+#endif
+
+       clear_c0_status(ST0_BEV);
+       execution_hazard_barrier();
+}