Hi,

turns out that machines (in my case the AMD machine) can have the MMU
and caches enabled while running EFI.  This means that once we jump into
the kernel and disable the MMU, the cache is lost and we kind of crash.

To fix that, make sure to clean the data cache and flush the instruction
cache before jumping into kernel.  This fixes issues on my AMD machine
where it "hangs" 3 instructions in.

Based on FreeBSD code.

ok?

Patrick


diff --git a/sys/arch/arm64/stand/efiboot/exec.c 
b/sys/arch/arm64/stand/efiboot/exec.c
index 088401a48eb..88c1355f030 100644
--- a/sys/arch/arm64/stand/efiboot/exec.c
+++ b/sys/arch/arm64/stand/efiboot/exec.c
@@ -27,11 +27,65 @@
 #include <efi.h>
 #include <stand/boot/cmd.h>
 
+#include <machine/armreg.h>
+
 #include "efiboot.h"
 #include "libsa.h"
 
 typedef void (*startfuncp)(void *, void *, void *) __attribute__ ((noreturn));
 
+unsigned int cpu_get_dcache_line_size(void);
+void cpu_flush_dcache(vaddr_t, vsize_t);
+void cpu_inval_icache(void);
+
+unsigned int
+cpu_get_dcache_line_size(void)
+{
+       uint64_t ctr;
+       unsigned int dcl_size;
+
+       /* Accessible from all security levels */
+       ctr = READ_SPECIALREG(ctr_el0);
+
+       /*
+        * Relevant field [19:16] is LOG2
+        * of the number of words in DCache line
+        */
+       dcl_size = CTR_DLINE_SIZE(ctr);
+
+       /* Size of word shifted by cache line size */
+       return (sizeof(int) << dcl_size);
+}
+
+void
+cpu_flush_dcache(vaddr_t addr, vsize_t len)
+{
+       uint64_t cl_size;
+       vaddr_t end;
+
+       cl_size = cpu_get_dcache_line_size();
+
+       /* Calculate end address to clean */
+       end = addr + len;
+       /* Align start address to cache line */
+       addr = addr & ~(cl_size - 1);
+
+       for (; addr < end; addr += cl_size)
+               __asm volatile("dc civac, %0" :: "r" (addr) : "memory");
+
+       /* Full system DSB */
+       __asm volatile("dsb sy" ::: "memory");
+}
+
+void
+cpu_inval_icache(void)
+{
+       __asm volatile(
+           "ic         ialluis \n"
+           "dsb        ish     \n"
+           : : : "memory");
+}
+
 void
 run_loadfile(u_long *marks, int howto)
 {
@@ -81,6 +135,9 @@ run_loadfile(u_long *marks, int howto)
 
        efi_cleanup();
 
+       cpu_flush_dcache(marks[MARK_ENTRY], marks[MARK_END] - 
marks[MARK_ENTRY]);
+       cpu_inval_icache();
+
        (*(startfuncp)(marks[MARK_ENTRY]))((void *)esym, 0, fdt);
 
        /* NOTREACHED */

Reply via email to