diff --git a/src/system/boot/platform/efi/arch/arm/Jamfile b/src/system/boot/platform/efi/arch/arm/Jamfile index 960f44f84b..3f33160510 100644 --- a/src/system/boot/platform/efi/arch/arm/Jamfile +++ b/src/system/boot/platform/efi/arch/arm/Jamfile @@ -22,6 +22,7 @@ for platform in [ MultiBootSubDirSetup efi ] { local arch_src = crt0-efi-$(TARGET_ARCH).S entry.S + cache.S relocation_func.cpp arch_cpu.cpp arch_dtb.cpp diff --git a/src/system/boot/platform/efi/arch/arm/arch_start.cpp b/src/system/boot/platform/efi/arch/arm/arch_start.cpp index 37e0ed50d4..ef67f2ca56 100644 --- a/src/system/boot/platform/efi/arch/arm/arch_start.cpp +++ b/src/system/boot/platform/efi/arch/arm/arch_start.cpp @@ -26,6 +26,9 @@ #define ALIGN_MEMORY_MAP 4 +extern "C" void clean_dcache_all(void); +extern "C" void invalidate_icache_all(void); + extern "C" typedef void (*arch_enter_kernel_t)(uint32_t, addr_t, addr_t, addr_t); @@ -239,6 +242,9 @@ arch_start_kernel(addr_t kernelEntry) TRACE("DACR = 0x%08" B_PRIx32 "\n", mmu_read_DACR()); + clean_dcache_all(); + invalidate_icache_all(); + // Enter the kernel! dprintf("enter_kernel(ttbr0: 0x%08x, kernelArgs: 0x%08x, " "kernelEntry: 0x%08x, sp: 0x%08x)\n", diff --git a/src/system/boot/platform/efi/arch/arm/cache.S b/src/system/boot/platform/efi/arch/arm/cache.S new file mode 100644 index 0000000000..d82aa3a7d1 --- /dev/null +++ b/src/system/boot/platform/efi/arch/arm/cache.S @@ -0,0 +1,87 @@ +/* + * Copyright 2022 Haiku, Inc. All rights reserved. + * Released under the terms of the MIT License. + */ + +#include + + + // the following code is based on ARM ARM + // section B2.2.4, Cache maintenance functionality + +FUNCTION(clean_dcache_all): + dmb + stmfd sp!, {r4-r11, lr} + + // Query the number of cache levels to be cleaned + // this is encoded in LoC which is bits 26..24 of CLIDR + mrc p15, 1, r0, c0, c0, 1 + mov r3, r0, lsr #23 + ands r3, r3, #7 << 1 + beq cleaning_done + + // Start cleaning at cache level 0 + mov r10, #0 +clean_levels_loop: + // Get type of current cache level + add r2, r10, r10, lsr #1 + mov r1, r0, lsr r2 + and r1, r1, #7 + + // Skip this level if cache type is less than 2 i.e. no cache or only i-cache + cmp r1, #2 + blt clean_next_level + + // Select current level in Cache Size selection register + mcr p15, 2, r10, c0, c0, 0 + isb + + // Read Cache Size ID for the current level + mrc p15, 1, r1, c0, c0, 0 + + // Decode LineSize from bits[2:0] + and r2, r1, #7 + add r2, r2, #4 + + // Decode Associativity from bits[12:3] + movw r4, #0x3ff + ands r4, r4, r1, lsr #3 + clz r5, r4 + + // Decode NumSets from bits[27:13] + movw r7, #0x7fff + ands r7, r7, r1, lsr #13 + +clean_way_loop: + mov r9, r7 +clean_index_loop: + orr r11, r10, r4, lsl r5 + orr r11, r11, r9, lsl r2 + + // Clean and Invalidate by set/way + mcr p15, 0, r11, c7, c14, 2 + + subs r9, r9, #1 + bge clean_index_loop + + subs r4, r4, #1 + bge clean_way_loop +clean_next_level: + add r10, r10, #2 + cmp r3, r10 + bgt clean_levels_loop +cleaning_done: + dsb + isb + ldmfd sp!, {r4-r11, lr} + bx lr +FUNCTION_END(clean_dcache_all) + + +FUNCTION(invalidate_icache_all): + mov r0, #0 + mcr p15, 0, r0, c7, c5, 0 + dsb + isb + bx lr +FUNCTION_END(invalidate_icache_all)