summaryrefslogtreecommitdiff
path: root/sys/arch/armv7
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2019-07-22 11:51:31 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2019-07-22 11:51:31 +0000
commit9a7227e1825e7fea760c9283bd1c282952750c4b (patch)
tree67b9305f51ccefe1f3c77fcef4b4ecfdf04df325 /sys/arch/armv7
parentee8f931e9b4b24427b764f1d6ae50875975abe75 (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')
-rw-r--r--sys/arch/armv7/stand/efiboot/conf.c4
-rw-r--r--sys/arch/armv7/stand/efiboot/exec.c109
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 */