Skip to content

Commit bd67b71

Browse files
committed
MIPS: kernel: Reserve exception base early to prevent corruption
BMIPS is one of the few platforms that do change the exception base. After commit 2dcb396 ("memblock: do not start bottom-up allocations with kernel_end") we started seeing BMIPS boards fail to boot with the built-in FDT being corrupted. Before the cited commit, early allocations would be in the [kernel_end, RAM_END] range, but after commit they would be within [RAM_START + PAGE_SIZE, RAM_END]. The custom exception base handler that is installed by bmips_ebase_setup() done for BMIPS5000 CPUs ends-up trampling on the memory region allocated by unflatten_and_copy_device_tree() thus corrupting the FDT used by the kernel. To fix this, we need to perform an early reservation of the custom exception space. Additional we reserve the first 4k (1k for R3k) for either normal exception vector space (legacy CPUs) or special vectors like cache exceptions. Huge thanks to Serge for analysing and proposing a solution to this issue. Fixes: 2dcb396 ("memblock: do not start bottom-up allocations with kernel_end") Reported-by: Kamal Dasu <kdasu.kdev@gmail.com> Debugged-by: Serge Semin <Sergey.Semin@baikalelectronics.ru> Acked-by: Mike Rapoport <rppt@linux.ibm.com> Tested-by: Florian Fainelli <f.fainelli@gmail.com> Reviewed-by: Serge Semin <fancer.lancer@gmail.com> Signed-off-by: Thomas Bogendoerfer <tsbogend@alpha.franken.de>
1 parent 6654111 commit bd67b71

File tree

4 files changed

+17
-5
lines changed

4 files changed

+17
-5
lines changed

arch/mips/include/asm/traps.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,11 @@ extern void (*board_ebase_setup)(void);
2424
extern void (*board_cache_error_setup)(void);
2525

2626
extern int register_nmi_notifier(struct notifier_block *nb);
27+
extern void reserve_exception_space(phys_addr_t addr, unsigned long size);
2728
extern char except_vec_nmi[];
2829

30+
#define VECTORSPACING 0x100 /* for EI/VI mode */
31+
2932
#define nmi_notifier(fn, pri) \
3033
({ \
3134
static struct notifier_block fn##_nb = { \

arch/mips/kernel/cpu-probe.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <asm/elf.h>
2727
#include <asm/pgtable-bits.h>
2828
#include <asm/spram.h>
29+
#include <asm/traps.h>
2930
#include <linux/uaccess.h>
3031

3132
#include "fpu-probe.h"
@@ -1628,6 +1629,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
16281629
c->cputype = CPU_BMIPS3300;
16291630
__cpu_name[cpu] = "Broadcom BMIPS3300";
16301631
set_elf_platform(cpu, "bmips3300");
1632+
reserve_exception_space(0x400, VECTORSPACING * 64);
16311633
break;
16321634
case PRID_IMP_BMIPS43XX: {
16331635
int rev = c->processor_id & PRID_REV_MASK;
@@ -1638,6 +1640,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
16381640
__cpu_name[cpu] = "Broadcom BMIPS4380";
16391641
set_elf_platform(cpu, "bmips4380");
16401642
c->options |= MIPS_CPU_RIXI;
1643+
reserve_exception_space(0x400, VECTORSPACING * 64);
16411644
} else {
16421645
c->cputype = CPU_BMIPS4350;
16431646
__cpu_name[cpu] = "Broadcom BMIPS4350";
@@ -1654,6 +1657,7 @@ static inline void cpu_probe_broadcom(struct cpuinfo_mips *c, unsigned int cpu)
16541657
__cpu_name[cpu] = "Broadcom BMIPS5000";
16551658
set_elf_platform(cpu, "bmips5000");
16561659
c->options |= MIPS_CPU_ULRI | MIPS_CPU_RIXI;
1660+
reserve_exception_space(0x1000, VECTORSPACING * 64);
16571661
break;
16581662
}
16591663
}
@@ -2133,6 +2137,8 @@ void cpu_probe(void)
21332137
if (cpu == 0)
21342138
__ua_limit = ~((1ull << cpu_vmbits) - 1);
21352139
#endif
2140+
2141+
reserve_exception_space(0, 0x1000);
21362142
}
21372143

21382144
void cpu_report(void)

arch/mips/kernel/cpu-r3k-probe.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <asm/fpu.h>
2222
#include <asm/mipsregs.h>
2323
#include <asm/elf.h>
24+
#include <asm/traps.h>
2425

2526
#include "fpu-probe.h"
2627

@@ -158,6 +159,8 @@ void cpu_probe(void)
158159
cpu_set_fpu_opts(c);
159160
else
160161
cpu_set_nofpu_opts(c);
162+
163+
reserve_exception_space(0, 0x400);
161164
}
162165

163166
void cpu_report(void)

arch/mips/kernel/traps.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2009,13 +2009,16 @@ void __noreturn nmi_exception_handler(struct pt_regs *regs)
20092009
nmi_exit();
20102010
}
20112011

2012-
#define VECTORSPACING 0x100 /* for EI/VI mode */
2013-
20142012
unsigned long ebase;
20152013
EXPORT_SYMBOL_GPL(ebase);
20162014
unsigned long exception_handlers[32];
20172015
unsigned long vi_handlers[64];
20182016

2017+
void reserve_exception_space(phys_addr_t addr, unsigned long size)
2018+
{
2019+
memblock_reserve(addr, size);
2020+
}
2021+
20192022
void __init *set_except_vector(int n, void *addr)
20202023
{
20212024
unsigned long handler = (unsigned long) addr;
@@ -2367,10 +2370,7 @@ void __init trap_init(void)
23672370

23682371
if (!cpu_has_mips_r2_r6) {
23692372
ebase = CAC_BASE;
2370-
ebase_pa = virt_to_phys((void *)ebase);
23712373
vec_size = 0x400;
2372-
2373-
memblock_reserve(ebase_pa, vec_size);
23742374
} else {
23752375
if (cpu_has_veic || cpu_has_vint)
23762376
vec_size = 0x200 + VECTORSPACING*64;

0 commit comments

Comments
 (0)