diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig
index 097ad587c1cf643c769b7c071d27615b48578da9..d97930e577bb057a45ce62249871244440c9bdcf 100644
--- a/arch/mips/Kconfig
+++ b/arch/mips/Kconfig
@@ -20,6 +20,7 @@ config TARGET_QEMU_MIPS
 	select SUPPORTS_CPU_MIPS32_R2
 	select SUPPORTS_CPU_MIPS64_R1
 	select SUPPORTS_CPU_MIPS64_R2
+	select ROM_EXCEPTION_VECTORS
 
 config TARGET_MALTA
 	bool "Support malta"
@@ -40,6 +41,7 @@ config TARGET_MALTA
 	select SUPPORTS_CPU_MIPS64_R6
 	select SWAP_IO_SPACE
 	select MIPS_L1_CACHE_SHIFT_6
+	select ROM_EXCEPTION_VECTORS
 
 config TARGET_VCT
 	bool "Support vct"
@@ -47,6 +49,7 @@ config TARGET_VCT
 	select SUPPORTS_CPU_MIPS32_R1
 	select SUPPORTS_CPU_MIPS32_R2
 	select SYS_MIPS_CACHE_INIT_RAM_LOAD
+	select ROM_EXCEPTION_VECTORS
 
 config TARGET_DBAU1X00
 	bool "Support dbau1x00"
@@ -55,6 +58,7 @@ config TARGET_DBAU1X00
 	select SUPPORTS_CPU_MIPS32_R1
 	select SUPPORTS_CPU_MIPS32_R2
 	select SYS_MIPS_CACHE_INIT_RAM_LOAD
+	select ROM_EXCEPTION_VECTORS
 	select MIPS_TUNE_4KC
 
 config TARGET_PB1X00
@@ -63,6 +67,7 @@ config TARGET_PB1X00
 	select SUPPORTS_CPU_MIPS32_R1
 	select SUPPORTS_CPU_MIPS32_R2
 	select SYS_MIPS_CACHE_INIT_RAM_LOAD
+	select ROM_EXCEPTION_VECTORS
 	select MIPS_TUNE_4KC
 
 config ARCH_ATH79
@@ -91,6 +96,7 @@ config TARGET_BOSTON
 	select SUPPORTS_CPU_MIPS64_R1
 	select SUPPORTS_CPU_MIPS64_R2
 	select SUPPORTS_CPU_MIPS64_R6
+	select ROM_EXCEPTION_VECTORS
 
 config TARGET_XILFPGA
 	bool "Support Imagination Xilfpga"
@@ -103,6 +109,7 @@ config TARGET_XILFPGA
 	select SUPPORTS_CPU_MIPS32_R1
 	select SUPPORTS_CPU_MIPS32_R2
 	select MIPS_L1_CACHE_SHIFT_4
+	select ROM_EXCEPTION_VECTORS
 	help
 	  This supports IMGTEC MIPSfpga platform
 
@@ -192,6 +199,20 @@ config CPU_MIPS64_R6
 
 endchoice
 
+menu "General setup"
+
+config ROM_EXCEPTION_VECTORS
+	bool "Build U-Boot image with exception vectors"
+	help
+	  Enable this to include exception vectors in the U-Boot image. This is
+	  required if the U-Boot entry point is equal to the address of the
+	  CPU reset exception vector (e.g. U-Boot as ROM loader in Qemu,
+	  U-Boot booted from parallel NOR flash).
+	  Disable this, if the U-Boot image is booted from DRAM (e.g. by SPL).
+	  In that case the image size will be reduced by 0x500 bytes.
+
+endmenu
+
 menu "OS boot interface"
 
 config MIPS_BOOT_CMDLINE_LEGACY
@@ -281,6 +302,17 @@ config SWAP_IO_SPACE
 config SYS_MIPS_CACHE_INIT_RAM_LOAD
 	bool
 
+config MIPS_INIT_STACK_IN_SRAM
+	bool
+	default n
+	help
+	  Select this if the initial stack frame could be setup in SRAM.
+	  Normally the initial stack frame is set up in DRAM which is often
+	  only available after lowlevel_init. With this option the initial
+	  stack frame and the early C environment is set up before
+	  lowlevel_init. Thus lowlevel_init does not need to be implemented
+	  in assembler.
+
 config SYS_DCACHE_SIZE
 	int
 	default 0
diff --git a/arch/mips/cpu/start.S b/arch/mips/cpu/start.S
index 3f0fc125475271835456db3490bd47a61a3dbb1b..6740fdf9ed272eda6bc7213ad02db57fc68f7d7b 100644
--- a/arch/mips/cpu/start.S
+++ b/arch/mips/cpu/start.S
@@ -34,30 +34,57 @@
 # define STATUS_SET	ST0_KX
 #endif
 
-	/*
-	 * For the moment disable interrupts, mark the kernel mode and
-	 * set ST0_KX so that the CPU does not spit fire when using
-	 * 64-bit addresses.
-	 */
-	.macro	setup_c0_status set clr
-	.set	push
-	mfc0	t0, CP0_STATUS
-	or	t0, ST0_CU0 | \set | 0x1f | \clr
-	xor	t0, 0x1f | \clr
-	mtc0	t0, CP0_STATUS
-	.set	noreorder
-	sll	zero, 3				# ehb
-	.set	pop
+	.set noreorder
+
+	.macro init_wr sel
+	MTC0	zero, CP0_WATCHLO,\sel
+	mtc0	t1, CP0_WATCHHI,\sel
+	mfc0	t0, CP0_WATCHHI,\sel
+	bgez	t0, wr_done
+	 nop
 	.endm
 
-	.set noreorder
+	.macro uhi_mips_exception
+	move	k0, t9		# preserve t9 in k0
+	move	k1, a0		# preserve a0 in k1
+	li	t9, 15		# UHI exception operation
+	li	a0, 0		# Use hard register context
+	sdbbp	1		# Invoke UHI operation
+	.endm
+
+	.macro setup_stack_gd
+	li	t0, -16
+	PTR_LI	t1, CONFIG_SYS_INIT_SP_ADDR
+	and	sp, t1, t0		# force 16 byte alignment
+	PTR_SUBU \
+		sp, sp, GD_SIZE		# reserve space for gd
+	and	sp, sp, t0		# force 16 byte alignment
+	move	k0, sp			# save gd pointer
+#ifdef CONFIG_SYS_MALLOC_F_LEN
+	li	t2, CONFIG_SYS_MALLOC_F_LEN
+	PTR_SUBU \
+		sp, sp, t2		# reserve space for early malloc
+	and	sp, sp, t0		# force 16 byte alignment
+#endif
+	move	fp, sp
+
+	/* Clear gd */
+	move	t0, k0
+1:
+	PTR_S	zero, 0(t0)
+	blt	t0, t1, 1b
+	 PTR_ADDIU t0, PTRSIZE
+
+#ifdef CONFIG_SYS_MALLOC_F_LEN
+	PTR_S	sp, GD_MALLOC_BASE(k0)	# gd->malloc_base offset
+#endif
+	.endm
 
 ENTRY(_start)
 	/* U-Boot entry point */
 	b	reset
-	 nop
+	 mtc0	zero, CP0_COUNT	# clear cp0 count for most accurate boot timing
 
-	.org 0x10
 #if defined(CONFIG_SYS_XWAY_EBU_BOOTCFG)
 	/*
 	 * Almost all Lantiq XWAY SoC devices have an external bus unit (EBU) to
@@ -66,47 +93,53 @@ ENTRY(_start)
 	 * initial configuration for that EBU in order to access the flash
 	 * device with correct parameters. This config option is board-specific.
 	 */
+	.org 0x10
 	.word CONFIG_SYS_XWAY_EBU_BOOTCFG
 	.word 0x0
-#elif defined(CONFIG_MALTA)
+#endif
+#if defined(CONFIG_MALTA)
 	/*
 	 * Linux expects the Board ID here.
 	 */
+	.org 0x10
 	.word 0x00000420	# 0x420 (Malta Board with CoreLV)
 	.word 0x00000000
 #endif
 
+#if defined(CONFIG_ROM_EXCEPTION_VECTORS)
+	/*
+	 * Exception vector entry points. When running from ROM, an exception
+	 * cannot be handled. Halt execution and transfer control to debugger,
+	 * if one is attached.
+	 */
 	.org 0x200
 	/* TLB refill, 32 bit task */
-1:	b	1b
-	 nop
+	uhi_mips_exception
 
 	.org 0x280
 	/* XTLB refill, 64 bit task */
-1:	b	1b
-	 nop
+	uhi_mips_exception
 
 	.org 0x300
 	/* Cache error exception */
-1:	b	1b
-	 nop
+	uhi_mips_exception
 
 	.org 0x380
 	/* General exception */
-1:	b	1b
-	 nop
+	uhi_mips_exception
 
 	.org 0x400
 	/* Catch interrupt exceptions */
-1:	b	1b
-	 nop
+	uhi_mips_exception
 
 	.org 0x480
 	/* EJTAG debug exception */
 1:	b	1b
 	 nop
 
-	.align 4
+	.org 0x500
+#endif
+
 reset:
 #if __mips_isa_rev >= 6
 	mfc0	t0, CP0_CONFIG, 5
@@ -128,17 +161,51 @@ reset:
 	b	3b
 	 nop
 
-	/* Clear watch registers */
-4:	MTC0	zero, CP0_WATCHLO
+	/* Init CP0 Status */
+4:	mfc0	t0, CP0_STATUS
+	and	t0, ST0_IMPL
+	or	t0, ST0_BEV | ST0_ERL | STATUS_SET
+	mtc0	t0, CP0_STATUS
+
+	/*
+	 * Check whether CP0 Config1 is implemented. If not continue
+	 * with legacy Watch register initialization.
+	 */
+	mfc0	t0, CP0_CONFIG
+	bgez	t0, wr_legacy
+	 nop
+
+	/*
+	 * Check WR bit in CP0 Config1 to determine if Watch registers
+	 * are implemented.
+	 */
+	mfc0	t0, CP0_CONFIG, 1
+	andi	t0, (1 << 3)
+	beqz	t0, wr_done
+	 nop
+
+	/* Clear Watch Status bits and disable watch exceptions */
+	li	t1, 0x7		# Clear I, R and W conditions
+	init_wr	0
+	init_wr	1
+	init_wr	2
+	init_wr	3
+	init_wr	4
+	init_wr	5
+	init_wr	6
+	init_wr	7
+	b	wr_done
+	 nop
+
+wr_legacy:
+	MTC0	zero, CP0_WATCHLO
 	mtc0	zero, CP0_WATCHHI
 
-	/* WP(Watch Pending), SW0/1 should be cleared */
+wr_done:
+	/* Clear WP, IV and SW interrupts */
 	mtc0	zero, CP0_CAUSE
 
-	setup_c0_status STATUS_SET 0
-
-	/* Init Timer */
-	mtc0	zero, CP0_COUNT
+	/* Clear timer interrupt (CP0_COUNT cleared on branch to 'reset') */
 	mtc0	zero, CP0_COMPARE
 
 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
@@ -167,6 +234,11 @@ reset:
 	 nop
 #endif
 
+#ifdef CONFIG_MIPS_INIT_STACK_IN_SRAM
+	/* Set up initial stack and global data */
+	setup_stack_gd
+#endif
+
 #ifndef CONFIG_SKIP_LOWLEVEL_INIT
 # ifdef CONFIG_SYS_MIPS_CACHE_INIT_RAM_LOAD
 	/* Initialize any external memory */
@@ -188,35 +260,14 @@ reset:
 # endif
 #endif
 
-	/* Set up temporary stack */
-	li	t0, -16
-	PTR_LI	t1, CONFIG_SYS_INIT_SP_ADDR
-	and	sp, t1, t0		# force 16 byte alignment
-	PTR_SUBU \
-		sp, sp, GD_SIZE		# reserve space for gd
-	and	sp, sp, t0		# force 16 byte alignment
-	move	k0, sp			# save gd pointer
-#ifdef CONFIG_SYS_MALLOC_F_LEN
-	li	t2, CONFIG_SYS_MALLOC_F_LEN
-	PTR_SUBU \
-		sp, sp, t2		# reserve space for early malloc
-	and	sp, sp, t0		# force 16 byte alignment
-#endif
-	move	fp, sp
-
-	/* Clear gd */
-	move	t0, k0
-1:
-	PTR_S	zero, 0(t0)
-	blt	t0, t1, 1b
-	 PTR_ADDIU t0, PTRSIZE
-
-#ifdef CONFIG_SYS_MALLOC_F_LEN
-	PTR_S	sp, GD_MALLOC_BASE(k0)	# gd->malloc_base offset
+#ifndef CONFIG_MIPS_INIT_STACK_IN_SRAM
+	/* Set up initial stack and global data */
+	setup_stack_gd
 #endif
 
 	move	a0, zero		# a0 <-- boot_flags = 0
 	PTR_LA	t9, board_init_f
+
 	jr	t9
 	 move	ra, zero
 
diff --git a/arch/mips/include/asm/asm-offsets.h b/arch/mips/include/asm/asm-offsets.h
new file mode 100644
index 0000000000000000000000000000000000000000..5352b1cd3835e5c1ed37960acf4066929aee71cb
--- /dev/null
+++ b/arch/mips/include/asm/asm-offsets.h
@@ -0,0 +1,5 @@
+/*
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <generated/asm-offsets.h>
diff --git a/arch/mips/include/asm/cache.h b/arch/mips/include/asm/cache.h
index 669c362a52a563ab6f7dfcf43188b8559644b69d..83165d5c9705fcc2f41eb501eb363b15e556aba3 100644
--- a/arch/mips/include/asm/cache.h
+++ b/arch/mips/include/asm/cache.h
@@ -19,6 +19,7 @@
  */
 #define CONFIG_SYS_CACHELINE_SIZE ARCH_DMA_MINALIGN
 
+#ifndef __ASSEMBLY__
 /**
  * mips_cache_probe() - Probe the properties of the caches
  *
@@ -27,5 +28,6 @@
  * functions such as flush_cache may be called.
  */
 void mips_cache_probe(void);
+#endif
 
 #endif /* __MIPS_CACHE_H__ */
diff --git a/arch/mips/include/asm/io.h b/arch/mips/include/asm/io.h
index 5b86386bc1cb2fbd98a97581f1f44d57f78c3946..ee7a59290deb7290e2151b9905f894dfd045344c 100644
--- a/arch/mips/include/asm/io.h
+++ b/arch/mips/include/asm/io.h
@@ -501,7 +501,7 @@ map_physmem(phys_addr_t paddr, unsigned long len, unsigned long flags)
 	if (flags == MAP_NOCACHE)
 		return ioremap(paddr, len);
 
-	return (void *)paddr;
+	return (void *)CKSEG0ADDR(paddr);
 }
 
 /*
diff --git a/arch/mips/include/asm/mipsregs.h b/arch/mips/include/asm/mipsregs.h
index 9ab506361e7897fb76ad0c8cdd37ebf3e58afc7a..7a9d222aadecfc1ed32e91e12b46aefa49634511 100644
--- a/arch/mips/include/asm/mipsregs.h
+++ b/arch/mips/include/asm/mipsregs.h
@@ -299,6 +299,7 @@
 #define	 STATUSF_IP14		(_ULCAST_(1) <<	 6)
 #define	 STATUSB_IP15		7
 #define	 STATUSF_IP15		(_ULCAST_(1) <<	 7)
+#define ST0_IMPL		(_ULCAST_(3) <<	 16)
 #define ST0_CH			0x00040000
 #define ST0_NMI			0x00080000
 #define ST0_SR			0x00100000
diff --git a/arch/mips/include/asm/system.h b/arch/mips/include/asm/system.h
index e6435cce2944247b032e6f16f090fc4b7e24b482..c9c59614627df4196a938f08e33c010c637690e6 100644
--- a/arch/mips/include/asm/system.h
+++ b/arch/mips/include/asm/system.h
@@ -262,4 +262,12 @@ extern void __die_if_kernel(const char *, struct pt_regs *, const char *where,
 #define die_if_kernel(msg, regs)					\
 	__die_if_kernel(msg, regs, __FILE__ ":"__FUNCTION__, __LINE__)
 
+static inline void execution_hazard_barrier(void)
+{
+	__asm__ __volatile__(
+		".set noreorder\n"
+		"ehb\n"
+		".set reorder");
+}
+
 #endif /* _ASM_SYSTEM_H */
diff --git a/arch/mips/include/asm/u-boot-mips.h b/arch/mips/include/asm/u-boot-mips.h
index 1f527bb8ec0917e977efdb9890b5c049f2f961c1..71ff41dafecfe02f98cf8f7493114d3836797648 100644
--- a/arch/mips/include/asm/u-boot-mips.h
+++ b/arch/mips/include/asm/u-boot-mips.h
@@ -5,4 +5,8 @@
 #ifndef _U_BOOT_MIPS_H_
 #define _U_BOOT_MIPS_H_
 
+void exc_handler(void);
+void except_vec3_generic(void);
+void except_vec_ejtag_debug(void);
+
 #endif /* _U_BOOT_MIPS_H_ */
diff --git a/arch/mips/lib/Makefile b/arch/mips/lib/Makefile
index b7ce5df7652fe5e7e808be6780e653b164b0001f..659c6ad187cdfd025caaa75e4fc000ae6d50a63b 100644
--- a/arch/mips/lib/Makefile
+++ b/arch/mips/lib/Makefile
@@ -7,6 +7,9 @@
 
 obj-y	+= cache.o
 obj-y	+= cache_init.o
+obj-y	+= genex.o
+obj-y	+= stack.o
+obj-y	+= traps.o
 
 obj-$(CONFIG_CMD_BOOTM) += bootm.o
 
diff --git a/arch/mips/lib/asm-offsets.c b/arch/mips/lib/asm-offsets.c
new file mode 100644
index 0000000000000000000000000000000000000000..9ed295ace351acd0b7159cf0343d727729415fce
--- /dev/null
+++ b/arch/mips/lib/asm-offsets.c
@@ -0,0 +1,61 @@
+/*
+ * offset.c: Calculate pt_regs and task_struct offsets.
+ *
+ * Copyright (C) 1996 David S. Miller
+ * Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002, 2003 Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ *
+ * Kevin Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2000 MIPS Technologies, Inc.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <asm/ptrace.h>
+#include <linux/stddef.h>
+#include <linux/kbuild.h>
+
+void output_ptreg_defines(void)
+{
+	COMMENT("MIPS pt_regs offsets.");
+	OFFSET(PT_R0, pt_regs, regs[0]);
+	OFFSET(PT_R1, pt_regs, regs[1]);
+	OFFSET(PT_R2, pt_regs, regs[2]);
+	OFFSET(PT_R3, pt_regs, regs[3]);
+	OFFSET(PT_R4, pt_regs, regs[4]);
+	OFFSET(PT_R5, pt_regs, regs[5]);
+	OFFSET(PT_R6, pt_regs, regs[6]);
+	OFFSET(PT_R7, pt_regs, regs[7]);
+	OFFSET(PT_R8, pt_regs, regs[8]);
+	OFFSET(PT_R9, pt_regs, regs[9]);
+	OFFSET(PT_R10, pt_regs, regs[10]);
+	OFFSET(PT_R11, pt_regs, regs[11]);
+	OFFSET(PT_R12, pt_regs, regs[12]);
+	OFFSET(PT_R13, pt_regs, regs[13]);
+	OFFSET(PT_R14, pt_regs, regs[14]);
+	OFFSET(PT_R15, pt_regs, regs[15]);
+	OFFSET(PT_R16, pt_regs, regs[16]);
+	OFFSET(PT_R17, pt_regs, regs[17]);
+	OFFSET(PT_R18, pt_regs, regs[18]);
+	OFFSET(PT_R19, pt_regs, regs[19]);
+	OFFSET(PT_R20, pt_regs, regs[20]);
+	OFFSET(PT_R21, pt_regs, regs[21]);
+	OFFSET(PT_R22, pt_regs, regs[22]);
+	OFFSET(PT_R23, pt_regs, regs[23]);
+	OFFSET(PT_R24, pt_regs, regs[24]);
+	OFFSET(PT_R25, pt_regs, regs[25]);
+	OFFSET(PT_R26, pt_regs, regs[26]);
+	OFFSET(PT_R27, pt_regs, regs[27]);
+	OFFSET(PT_R28, pt_regs, regs[28]);
+	OFFSET(PT_R29, pt_regs, regs[29]);
+	OFFSET(PT_R30, pt_regs, regs[30]);
+	OFFSET(PT_R31, pt_regs, regs[31]);
+	OFFSET(PT_LO, pt_regs, lo);
+	OFFSET(PT_HI, pt_regs, hi);
+	OFFSET(PT_EPC, pt_regs, cp0_epc);
+	OFFSET(PT_BVADDR, pt_regs, cp0_badvaddr);
+	OFFSET(PT_STATUS, pt_regs, cp0_status);
+	OFFSET(PT_CAUSE, pt_regs, cp0_cause);
+	DEFINE(PT_SIZE, sizeof(struct pt_regs));
+	BLANK();
+}
diff --git a/arch/mips/lib/bootm.c b/arch/mips/lib/bootm.c
index 0c6a4ab3b329ba10d889384463acc23e5d75e1d9..9fec4ad43860717263ea04d1981d0711d3c44502 100644
--- a/arch/mips/lib/bootm.c
+++ b/arch/mips/lib/bootm.c
@@ -42,7 +42,7 @@ void arch_lmb_reserve(struct lmb *lmb)
 
 	/* adjust sp by 4K to be safe */
 	sp -= 4096;
-	lmb_reserve(lmb, sp, CONFIG_SYS_SDRAM_BASE + gd->ram_size - sp);
+	lmb_reserve(lmb, sp, gd->ram_top - sp);
 }
 
 static void linux_cmdline_init(void)
diff --git a/arch/mips/lib/genex.S b/arch/mips/lib/genex.S
new file mode 100644
index 0000000000000000000000000000000000000000..2d6d7b0c18ec3d35802180cd07dc4625fda56ae9
--- /dev/null
+++ b/arch/mips/lib/genex.S
@@ -0,0 +1,224 @@
+/*
+ * Copyright (C) 1994 - 2000, 2001, 2003 Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ * Copyright (C) 2002, 2007  Maciej W. Rozycki
+ * Copyright (C) 2001, 2012 MIPS Technologies, Inc.  All rights reserved.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <asm/asm.h>
+#include <asm/regdef.h>
+#include <asm/mipsregs.h>
+#include <asm/asm-offsets.h>
+
+#define STATMASK 0x1f
+
+	.set	noreorder
+
+	/*
+	 * Macros copied and adapted from Linux MIPS
+	 */
+	.macro	SAVE_AT
+	.set	push
+	.set	noat
+	LONG_S	$1, PT_R1(sp)
+	.set	pop
+	.endm
+
+	.macro	SAVE_TEMP
+#if __mips_isa_rev < 6
+	mfhi	v1
+#endif
+#ifdef CONFIG_32BIT
+	LONG_S	$8, PT_R8(sp)
+	LONG_S	$9, PT_R9(sp)
+#endif
+	LONG_S	$10, PT_R10(sp)
+	LONG_S	$11, PT_R11(sp)
+	LONG_S	$12, PT_R12(sp)
+#if __mips_isa_rev < 6
+	LONG_S	v1, PT_HI(sp)
+	mflo	v1
+#endif
+	LONG_S	$13, PT_R13(sp)
+	LONG_S	$14, PT_R14(sp)
+	LONG_S	$15, PT_R15(sp)
+	LONG_S	$24, PT_R24(sp)
+#if __mips_isa_rev < 6
+	LONG_S	v1, PT_LO(sp)
+#endif
+	.endm
+
+	.macro	SAVE_STATIC
+	LONG_S	$16, PT_R16(sp)
+	LONG_S	$17, PT_R17(sp)
+	LONG_S	$18, PT_R18(sp)
+	LONG_S	$19, PT_R19(sp)
+	LONG_S	$20, PT_R20(sp)
+	LONG_S	$21, PT_R21(sp)
+	LONG_S	$22, PT_R22(sp)
+	LONG_S	$23, PT_R23(sp)
+	LONG_S	$30, PT_R30(sp)
+	.endm
+
+	.macro	SAVE_SOME
+	.set	push
+	.set	noat
+	PTR_SUBU k1, sp, PT_SIZE
+	LONG_S	sp, PT_R29(k1)
+	move	sp, k1
+
+	LONG_S	$3, PT_R3(sp)
+	LONG_S	$0, PT_R0(sp)
+	mfc0	v1, CP0_STATUS
+	LONG_S	$2, PT_R2(sp)
+	LONG_S	v1, PT_STATUS(sp)
+	LONG_S	$4, PT_R4(sp)
+	mfc0	v1, CP0_CAUSE
+	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)
+	.set	pop
+	.endm
+
+	.macro	RESTORE_AT
+	.set	push
+	.set	noat
+	LONG_L	$1,  PT_R1(sp)
+	.set	pop
+	.endm
+
+	.macro	RESTORE_TEMP
+#if __mips_isa_rev < 6
+	LONG_L	$24, PT_LO(sp)
+	mtlo	$24
+	LONG_L	$24, PT_HI(sp)
+	mthi	$24
+#endif
+#ifdef CONFIG_32BIT
+	LONG_L	$8, PT_R8(sp)
+	LONG_L	$9, PT_R9(sp)
+#endif
+	LONG_L	$10, PT_R10(sp)
+	LONG_L	$11, PT_R11(sp)
+	LONG_L	$12, PT_R12(sp)
+	LONG_L	$13, PT_R13(sp)
+	LONG_L	$14, PT_R14(sp)
+	LONG_L	$15, PT_R15(sp)
+	LONG_L	$24, PT_R24(sp)
+	.endm
+
+	.macro	RESTORE_STATIC
+	LONG_L	$16, PT_R16(sp)
+	LONG_L	$17, PT_R17(sp)
+	LONG_L	$18, PT_R18(sp)
+	LONG_L	$19, PT_R19(sp)
+	LONG_L	$20, PT_R20(sp)
+	LONG_L	$21, PT_R21(sp)
+	LONG_L	$22, PT_R22(sp)
+	LONG_L	$23, PT_R23(sp)
+	LONG_L	$30, PT_R30(sp)
+	.endm
+
+	.macro	RESTORE_SOME
+	.set	push
+	.set	reorder
+	.set	noat
+	mfc0	a0, CP0_STATUS
+	ori	a0, STATMASK
+	xori	a0, STATMASK
+	mtc0	a0, CP0_STATUS
+	li	v1, ST0_CU1 | ST0_FR | ST0_IM
+	and	a0, v1
+	LONG_L	v0, PT_STATUS(sp)
+	nor	v1, $0, v1
+	and	v0, v1
+	or	v0, a0
+	mtc0	v0, CP0_STATUS
+	LONG_L	v1, PT_EPC(sp)
+	MTC0	v1, CP0_EPC
+	LONG_L	$31, PT_R31(sp)
+	LONG_L	$28, PT_R28(sp)
+	LONG_L	$25, PT_R25(sp)
+#ifdef CONFIG_64BIT
+	LONG_L	$8, PT_R8(sp)
+	LONG_L	$9, PT_R9(sp)
+#endif
+	LONG_L	$7,  PT_R7(sp)
+	LONG_L	$6,  PT_R6(sp)
+	LONG_L	$5,  PT_R5(sp)
+	LONG_L	$4,  PT_R4(sp)
+	LONG_L	$3,  PT_R3(sp)
+	LONG_L	$2,  PT_R2(sp)
+	.set	pop
+	.endm
+
+	.macro	RESTORE_SP
+	LONG_L	sp, PT_R29(sp)
+	.endm
+
+NESTED(except_vec3_generic, 0, sp)
+	PTR_LA	k1, handle_reserved
+	jr	k1
+	 nop
+	END(except_vec3_generic)
+
+NESTED(except_vec_ejtag_debug, 0, sp)
+	PTR_LA	k1, handle_ejtag_debug
+	jr	k1
+	 nop
+	END(except_vec_ejtag_debug)
+
+NESTED(handle_reserved, PT_SIZE, sp)
+	SAVE_SOME
+	SAVE_AT
+	SAVE_TEMP
+	SAVE_STATIC
+
+	PTR_LA	t9, do_reserved
+	jr	t9
+	 move	a0, sp
+	END(handle_reserved)
+
+NESTED(handle_ejtag_debug, PT_SIZE, sp)
+	.set	push
+	.set	noat
+	MTC0	k1, CP0_DESAVE
+
+	/* Check for SDBBP */
+	MFC0	k1, CP0_DEBUG
+	sll	k1, k1, 30
+	bgez	k1, ejtag_return
+	 nop
+
+	SAVE_SOME
+	SAVE_AT
+	SAVE_TEMP
+	SAVE_STATIC
+
+	PTR_LA	t9, do_ejtag_debug
+	jalr	t9
+	 move	a0, sp
+
+	RESTORE_TEMP
+	RESTORE_STATIC
+	RESTORE_AT
+	RESTORE_SOME
+	RESTORE_SP
+
+ejtag_return:
+	MFC0	k1, CP0_DESAVE
+	deret
+	.set pop
+	END(handle_ejtag_debug)
diff --git a/arch/mips/lib/stack.c b/arch/mips/lib/stack.c
new file mode 100644
index 0000000000000000000000000000000000000000..c80f5fe1465da72d886f91b2f2b76f0e2fc1b6ee
--- /dev/null
+++ b/arch/mips/lib/stack.c
@@ -0,0 +1,19 @@
+/*
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int arch_reserve_stacks(void)
+{
+	/* reserve space for exception vector table */
+	gd->start_addr_sp -= 0x500;
+	gd->start_addr_sp &= ~0xFFF;
+	gd->irq_sp = gd->start_addr_sp;
+	debug("Reserving %d Bytes for exception vector at: %08lx\n",
+	      0x500, gd->start_addr_sp);
+
+	return 0;
+}
diff --git a/arch/mips/lib/traps.c b/arch/mips/lib/traps.c
new file mode 100644
index 0000000000000000000000000000000000000000..18622c223d6aad65d9384cc452cd6fdc2fac0881
--- /dev/null
+++ b/arch/mips/lib/traps.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 1994 - 1999, 2000, 01, 06 Ralf Baechle
+ * Copyright (C) 1995, 1996 Paul M. Antoine
+ * Copyright (C) 1998 Ulf Carlsson
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Kevin D. Kissell, kevink@mips.com and Carsten Langgaard, carstenl@mips.com
+ * Copyright (C) 2002, 2003, 2004, 2005, 2007  Maciej W. Rozycki
+ * Copyright (C) 2000, 2001, 2012 MIPS Technologies, Inc.  All rights reserved.
+ * Copyright (C) 2014, Imagination Technologies Ltd.
+ *
+ * SPDX-License-Identifier:	GPL-2.0+
+ */
+
+#include <common.h>
+#include <asm/mipsregs.h>
+#include <asm/addrspace.h>
+#include <asm/system.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+static void show_regs(const struct pt_regs *regs)
+{
+	const int field = 2 * sizeof(unsigned long);
+	unsigned int cause = regs->cp0_cause;
+	unsigned int exccode;
+	int i;
+
+	/*
+	 * Saved main processor registers
+	 */
+	for (i = 0; i < 32; ) {
+		if ((i % 4) == 0)
+			printf("$%2d   :", i);
+		if (i == 0)
+			printf(" %0*lx", field, 0UL);
+		else if (i == 26 || i == 27)
+			printf(" %*s", field, "");
+		else
+			printf(" %0*lx", field, regs->regs[i]);
+
+		i++;
+		if ((i % 4) == 0)
+			puts("\n");
+	}
+
+	printf("Hi    : %0*lx\n", field, regs->hi);
+	printf("Lo    : %0*lx\n", field, regs->lo);
+
+	/*
+	 * Saved cp0 registers
+	 */
+	printf("epc   : %0*lx (text %0*lx)\n", field, regs->cp0_epc,
+	       field, regs->cp0_epc - gd->reloc_off);
+	printf("ra    : %0*lx (text %0*lx)\n", field, regs->regs[31],
+	       field, regs->regs[31] - gd->reloc_off);
+
+	printf("Status: %08x\n", (uint32_t) regs->cp0_status);
+
+	exccode = (cause & CAUSEF_EXCCODE) >> CAUSEB_EXCCODE;
+	printf("Cause : %08x (ExcCode %02x)\n", cause, exccode);
+
+	if (1 <= exccode && exccode <= 5)
+		printf("BadVA : %0*lx\n", field, regs->cp0_badvaddr);
+
+	printf("PrId  : %08x\n", read_c0_prid());
+}
+
+void do_reserved(const struct pt_regs *regs)
+{
+	puts("\nOoops:\n");
+	show_regs(regs);
+	hang();
+}
+
+void do_ejtag_debug(const struct pt_regs *regs)
+{
+	const int field = 2 * sizeof(unsigned long);
+	unsigned long depc;
+	unsigned int debug;
+
+	depc = read_c0_depc();
+	debug = read_c0_debug();
+
+	printf("SDBBP EJTAG debug exception: c0_depc = %0*lx, DEBUG = %08x\n",
+	       field, depc, debug);
+}
+
+static void set_handler(unsigned long offset, void *addr, unsigned long size)
+{
+	unsigned long ebase = gd->irq_sp;
+
+	memcpy((void *)(ebase + offset), addr, size);
+	flush_cache(ebase + offset, size);
+}
+
+void trap_init(ulong reloc_addr)
+{
+	unsigned long ebase = gd->irq_sp;
+
+	set_handler(0x180, &except_vec3_generic, 0x80);
+	set_handler(0x280, &except_vec_ejtag_debug, 0x80);
+
+	write_c0_ebase(ebase);
+	clear_c0_status(ST0_BEV);
+	execution_hazard_barrier();
+}
diff --git a/arch/mips/mach-ath79/Kconfig b/arch/mips/mach-ath79/Kconfig
index 7d483aa8dce398754df81efdba157d69e179cb75..d982b0f8e6978128d8950d6744a143b891b6a05d 100644
--- a/arch/mips/mach-ath79/Kconfig
+++ b/arch/mips/mach-ath79/Kconfig
@@ -9,6 +9,7 @@ config SOC_AR933X
 	select SUPPORTS_BIG_ENDIAN
 	select SUPPORTS_CPU_MIPS32_R1
 	select SUPPORTS_CPU_MIPS32_R2
+	select ROM_EXCEPTION_VECTORS
 	select MIPS_TUNE_24KC
 	help
 	  This supports QCA/Atheros ar933x family SOCs.
@@ -27,6 +28,7 @@ config SOC_QCA953X
 	select SUPPORTS_BIG_ENDIAN
 	select SUPPORTS_CPU_MIPS32_R1
 	select SUPPORTS_CPU_MIPS32_R2
+	select ROM_EXCEPTION_VECTORS
 	select MIPS_TUNE_24KC
 	help
 	  This supports QCA/Atheros qca953x family SOCs.
diff --git a/arch/mips/mach-pic32/Kconfig b/arch/mips/mach-pic32/Kconfig
index 2e38bb7ecafa84cdd1659f73c28e99d1ddee21cf..8fad4cff9126ab117479e70e7f55716c0dda812d 100644
--- a/arch/mips/mach-pic32/Kconfig
+++ b/arch/mips/mach-pic32/Kconfig
@@ -14,6 +14,7 @@ config SOC_PIC32MZDA
 	select SUPPORTS_CPU_MIPS32_R2
 	select MIPS_L1_CACHE_SHIFT_4
 	select SYS_MIPS_CACHE_INIT_RAM_LOAD
+	select ROM_EXCEPTION_VECTORS
 	help
 	  This supports Microchip PIC32MZ[DA] family of microcontrollers.
 
diff --git a/common/board_r.c b/common/board_r.c
index d959ad3c6f90ea2c2a422b6878c11a5437764a2c..5496f45cbd94d80cb8911bcaf331c1ec3eb88c32 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -191,7 +191,7 @@ static int initr_serial(void)
 	return 0;
 }
 
-#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
+#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_MIPS)
 static int initr_trap(void)
 {
 	/*
@@ -807,7 +807,7 @@ init_fnc_t init_sequence_r[] = {
 #ifdef CONFIG_NEEDS_MANUAL_RELOC
 	initr_manual_reloc_cmdtable,
 #endif
-#if defined(CONFIG_PPC) || defined(CONFIG_M68K)
+#if defined(CONFIG_PPC) || defined(CONFIG_M68K) || defined(CONFIG_MIPS)
 	initr_trap,
 #endif
 #ifdef CONFIG_ADDR_MAP