git: c1381f07f61a - main - Don't sync the I/D caches when they are coherent
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 20 Dec 2021 13:59:16 UTC
The branch main has been updated by andrew: URL: https://cgit.FreeBSD.org/src/commit/?id=c1381f07f61a66979f1569995f37f2a0413c0413 commit c1381f07f61a66979f1569995f37f2a0413c0413 Author: Andrew Turner <andrew@FreeBSD.org> AuthorDate: 2021-12-17 09:33:57 +0000 Commit: Andrew Turner <andrew@FreeBSD.org> CommitDate: 2021-12-20 13:58:13 +0000 Don't sync the I/D caches when they are coherent In the arm64 loader we need to syncronise the I and D caches. On some newer CPUs the I and D caches are coherent so we don't need to perform these operations. While here remove the arguments to cpu_inval_icache as they are unneeded. Reported by: cperciva Tested by: cperciva Sponsored by: Innovate UK --- stand/arm64/libarm64/cache.c | 67 ++++++++++++++++++++++++-------------- stand/arm64/libarm64/cache.h | 2 +- stand/efi/loader/arch/arm64/exec.c | 2 +- 3 files changed, 45 insertions(+), 26 deletions(-) diff --git a/stand/arm64/libarm64/cache.c b/stand/arm64/libarm64/cache.c index 25766ef564dd..ff52572399ac 100644 --- a/stand/arm64/libarm64/cache.c +++ b/stand/arm64/libarm64/cache.c @@ -32,21 +32,30 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> #include <machine/armreg.h> +#include <machine/atomic.h> #include <stand.h> #include <efi.h> #include "cache.h" +static bool +get_cache_dic(uint64_t ctr) +{ + return (CTR_DIC_VAL(ctr) != 0); +} + +static bool +get_cache_idc(uint64_t ctr) +{ + return (CTR_IDC_VAL(ctr) != 0); +} + static unsigned int -get_dcache_line_size(void) +get_dcache_line_size(uint64_t ctr) { - 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 @@ -60,36 +69,46 @@ get_dcache_line_size(void) void cpu_flush_dcache(const void *ptr, size_t len) { - - uint64_t cl_size; + uint64_t cl_size, ctr; vm_offset_t addr, end; - cl_size = get_dcache_line_size(); - - /* Calculate end address to clean */ - end = (vm_offset_t)ptr + (vm_offset_t)len; - /* Align start address to cache line */ - addr = (vm_offset_t)ptr; - addr = rounddown2(addr, cl_size); + /* Accessible from all security levels */ + ctr = READ_SPECIALREG(ctr_el0); - for (; addr < end; addr += cl_size) - __asm __volatile("dc civac, %0" : : "r" (addr) : "memory"); - /* Full system DSB */ - __asm __volatile("dsb sy" : : : "memory"); + if (get_cache_idc(ctr)) { + dsb(ishst); + } else { + cl_size = get_dcache_line_size(ctr); + + /* Calculate end address to clean */ + end = (vm_offset_t)ptr + (vm_offset_t)len; + /* Align start address to cache line */ + addr = (vm_offset_t)ptr; + addr = rounddown2(addr, cl_size); + + for (; addr < end; addr += cl_size) + __asm __volatile("dc civac, %0" : : "r" (addr) : + "memory"); + /* Full system DSB */ + dsb(ish); + } } void -cpu_inval_icache(const void *ptr, size_t len) +cpu_inval_icache(void) { + uint64_t ctr; - /* NULL ptr or 0 len means all */ - if (ptr == NULL || len == 0) { + /* Accessible from all security levels */ + ctr = READ_SPECIALREG(ctr_el0); + + if (get_cache_dic(ctr)) { + isb(); + } else { __asm __volatile( "ic ialluis \n" "dsb ish \n" + "isb \n" : : : "memory"); - return; } - - /* TODO: Other cache ranges if necessary */ } diff --git a/stand/arm64/libarm64/cache.h b/stand/arm64/libarm64/cache.h index 89b094b19c18..5e560c4d578d 100644 --- a/stand/arm64/libarm64/cache.h +++ b/stand/arm64/libarm64/cache.h @@ -33,6 +33,6 @@ /* cache.c */ void cpu_flush_dcache(const void *, size_t); -void cpu_inval_icache(const void *, size_t); +void cpu_inval_icache(void); #endif /* _CACHE_H_ */ diff --git a/stand/efi/loader/arch/arm64/exec.c b/stand/efi/loader/arch/arm64/exec.c index 7783d46cd8e1..6cf4a4fd8e4d 100644 --- a/stand/efi/loader/arch/arm64/exec.c +++ b/stand/efi/loader/arch/arm64/exec.c @@ -128,7 +128,7 @@ elf64_exec(struct preloaded_file *fp) clean_size = (vm_offset_t)efi_translate(kernendp) - clean_addr; cpu_flush_dcache((void *)clean_addr, clean_size); - cpu_inval_icache(NULL, 0); + cpu_inval_icache(); (*entry)(modulep); panic("exec returned");