diff options
author | Mark Kettenis <kettenis@cvs.openbsd.org> | 2019-07-22 11:51:31 +0000 |
---|---|---|
committer | Mark Kettenis <kettenis@cvs.openbsd.org> | 2019-07-22 11:51:31 +0000 |
commit | 9a7227e1825e7fea760c9283bd1c282952750c4b (patch) | |
tree | 67b9305f51ccefe1f3c77fcef4b4ecfdf04df325 /sys/arch/armv7/stand | |
parent | ee8f931e9b4b24427b764f1d6ae50875975abe75 (diff) |
Disable caches and MMU before jumping to the kernel entry point. Needed
because UEFI on 32-bit ARM is supposed to leave them enabled and U-boot
was changed (starting with release 2019.04) to follow the spec here. However
the OpenBSD/armv7 kernel expects to be booted with caches and MMU turned off.
Note that there are still issues on boards that enable the non-architected
L2 cache. UEFI demands that such caches are not turned on, but U-Boot
does turn them on and this makes our kernel fail to boot.
With help from jsg@
ok jsg@
Diffstat (limited to 'sys/arch/armv7/stand')
-rw-r--r-- | sys/arch/armv7/stand/efiboot/conf.c | 4 | ||||
-rw-r--r-- | sys/arch/armv7/stand/efiboot/exec.c | 109 |
2 files changed, 110 insertions, 3 deletions
diff --git a/sys/arch/armv7/stand/efiboot/conf.c b/sys/arch/armv7/stand/efiboot/conf.c index 67c78dd1128..2fd31d00912 100644 --- a/sys/arch/armv7/stand/efiboot/conf.c +++ b/sys/arch/armv7/stand/efiboot/conf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: conf.c,v 1.15 2019/04/10 04:19:32 deraadt Exp $ */ +/* $OpenBSD: conf.c,v 1.16 2019/07/22 11:51:30 kettenis Exp $ */ /* * Copyright (c) 1996 Michael Shalayeff @@ -36,7 +36,7 @@ #include "efidev.h" #include "efipxe.h" -const char version[] = "1.3"; +const char version[] = "1.4"; int debug = 0; struct fs_ops file_system[] = { diff --git a/sys/arch/armv7/stand/efiboot/exec.c b/sys/arch/armv7/stand/efiboot/exec.c index 2cf82dde6c1..d7dd1212da7 100644 --- a/sys/arch/armv7/stand/efiboot/exec.c +++ b/sys/arch/armv7/stand/efiboot/exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: exec.c,v 1.13 2019/04/10 04:17:34 deraadt Exp $ */ +/* $OpenBSD: exec.c,v 1.14 2019/07/22 11:51:30 kettenis Exp $ */ /* * Copyright (c) 2006, 2016 Mark Kettenis @@ -27,11 +27,112 @@ #include <efi.h> #include <stand/boot/cmd.h> +#include <arm/armreg.h> + #include "efiboot.h" #include "libsa.h" typedef void (*startfuncp)(void *, void *, void *) __attribute__ ((noreturn)); +#define CLIDR_LOC(x) ((x >> 24) & 0x7) +#define CLIDR_CTYPE(x, n) ((x >> (n * 3)) & 0x7) +#define CLIDR_CTYPE_NOCACHE 0x0 +#define CLIDR_CTYPE_ICACHE 0x1 +#define CLIDR_CTYPE_DCACHE 0x2 +#define CLIDR_CTYPE_SEP_CACHE 0x3 +#define CLIDR_CTYPE_UNI_CACHE 0x4 +#define CCSIDR_NUMSETS(x) ((x >> 13) & 0x7fff) +#define CCSIDR_ASSOCIATIVITY(x) ((x >> 3) & 0x3ff) +#define CCSIDR_LINESZ(x) (x & 0x7) + +void +dcache_wbinv_all(void) +{ + uint32_t clidr; + uint32_t ccsidr; + uint32_t val; + int nways, nsets; + int wshift, sshift; + int way, set; + int level; + + __asm volatile("mrc p15, 1, %0, c0, c0, 1" : "=r"(clidr)); + for (level = 0; level < CLIDR_LOC(clidr); level++) { + if (CLIDR_CTYPE(clidr, level) == CLIDR_CTYPE_NOCACHE) + break; + if (CLIDR_CTYPE(clidr, level) == CLIDR_CTYPE_ICACHE) + continue; + + __asm volatile("mcr p15, 2, %0, c0, c0, 0" :: "r"(level << 1)); + __asm volatile("isb"); + __asm volatile("mrc p15, 1, %0, c0, c0, 0" : "=r"(ccsidr)); + + nways = CCSIDR_ASSOCIATIVITY(ccsidr) + 1; + nsets = CCSIDR_NUMSETS(ccsidr) + 1; + + sshift = CCSIDR_LINESZ(ccsidr) + 4; + wshift = __builtin_clz(CCSIDR_ASSOCIATIVITY(ccsidr)); + + for (way = 0; way < nways; way++) { + for (set = 0; set < nsets; set++) { + val = (way << wshift) | (set << sshift) | + (level << 1); + __asm volatile("mcr p15, 0, %0, c7, c14, 2" + :: "r"(val)); + } + } + } + + __asm volatile("dsb"); +} + +void +icache_inv_all(void) +{ + __asm volatile("mcr p15, 0, r0, c7, c5, 0"); /* ICIALLU */ + __asm volatile("dsb"); + __asm volatile("isb"); +} + +void +dcache_disable(void) +{ + uint32_t sctlr; + + __asm volatile("mrc p15, 0, %0, c1, c0, 0" : "=r"(sctlr)); + sctlr &= ~CPU_CONTROL_DC_ENABLE; + __asm volatile("mcr p15, 0, %0, c1, c0, 0" :: "r"(sctlr)); + __asm volatile("dsb"); + __asm volatile("isb"); +} + +void +icache_disable(void) +{ + uint32_t sctlr; + + __asm volatile("mrc p15, 0, %0, c1, c0, 0" : "=r"(sctlr)); + sctlr &= ~CPU_CONTROL_IC_ENABLE; + __asm volatile("mcr p15, 0, %0, c1, c0, 0" :: "r"(sctlr)); + __asm volatile("dsb"); + __asm volatile("isb"); +} + +void +mmu_disable(void) +{ + uint32_t sctlr; + + __asm volatile("mrc p15, 0, %0, c1, c0, 0" : "=r"(sctlr)); + sctlr &= ~CPU_CONTROL_MMU_ENABLE; + __asm volatile("mcr p15, 0, %0, c1, c0, 0" :: "r"(sctlr)); + + __asm volatile("mcr p15, 0, r0, c8, c7, 0"); /* TLBIALL */ + __asm volatile("mcr p15, 0, r0, c7, c5, 6"); /* BPIALL */ + __asm volatile("dsb"); + __asm volatile("isb"); +} + void run_loadfile(uint64_t *marks, int howto) { @@ -82,6 +183,12 @@ run_loadfile(uint64_t *marks, int howto) efi_cleanup(); + dcache_disable(); + dcache_wbinv_all(); + icache_disable(); + icache_inv_all(); + mmu_disable(); + (*(startfuncp)(marks[MARK_ENTRY]))((void *)esym, (void *)board_id, fdt); /* NOTREACHED */ |