arm64: Relax the kernel cache requirements for boot
authorCatalin Marinas <catalin.marinas@arm.com>
Wed, 26 Mar 2014 18:25:55 +0000 (18:25 +0000)
committerMark Brown <broonie@linaro.org>
Wed, 23 Jul 2014 11:55:36 +0000 (12:55 +0100)
With system caches for the host OS or architected caches for guest OS we
cannot easily guarantee that there are no dirty or stale cache lines for
the areas of memory written by the kernel during boot with the MMU off
(therefore non-cacheable accesses).

This patch adds the necessary cache maintenance during boot and relaxes
the booting requirements.

Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>
(cherry picked from commit c218bca74eeafa2f8528b6bbb34d112075fcf40a)
Signed-off-by: Mark Brown <broonie@linaro.org>
Conflicts:
arch/arm64/kernel/head.S

Documentation/arm64/booting.txt
arch/arm64/kernel/head.S
arch/arm64/mm/cache.S

index 5273c4d60e656ade8e4bbc8852c105ed8cdd2b24..1b0c968098aae73002d740a1cf56a87d3c890e4e 100644 (file)
@@ -111,8 +111,14 @@ Before jumping into the kernel, the following conditions must be met:
 - Caches, MMUs
   The MMU must be off.
   Instruction cache may be on or off.
-  Data cache must be off and invalidated.
-  External caches (if present) must be configured and disabled.
+  The address range corresponding to the loaded kernel image must be
+  cleaned to the PoC. In the presence of a system cache or other
+  coherent masters with caches enabled, this will typically require
+  cache maintenance by VA rather than set/way operations.
+  System caches which respect the architected cache maintenance by VA
+  operations must be configured and may be enabled.
+  System caches which do not respect architected cache maintenance by VA
+  operations (not recommended) must be configured and disabled.
 
 - Architected timers
   CNTFRQ must be programmed with the timer frequency.
index 669027367e7a8e886fd8b61980589010844534a0..30746fc16f8148e0da131b70dd90c825650f7aa0 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/assembler.h>
 #include <asm/ptrace.h>
 #include <asm/asm-offsets.h>
+#include <asm/cache.h>
 #include <asm/cputype.h>
 #include <asm/memory.h>
 #include <asm/thread_info.h>
@@ -218,7 +219,11 @@ ENTRY(set_cpu_boot_mode_flag)
        cmp     w20, #BOOT_CPU_MODE_EL2
        b.ne    1f
        add     x1, x1, #4
-1:     str     w20, [x1]                       // This CPU has booted in EL1
+1:     dc      cvac, x1                        // Clean potentially dirty cache line
+       dsb     sy
+       str     w20, [x1]                       // This CPU has booted in EL1
+       dc      civac, x1                       // Clean&invalidate potentially stale cache line
+       dsb     sy
        ret
 ENDPROC(set_cpu_boot_mode_flag)
 
@@ -229,8 +234,9 @@ ENDPROC(set_cpu_boot_mode_flag)
  * This is not in .bss, because we set it sufficiently early that the boot-time
  * zeroing of .bss would clobber it.
  */
-       .pushsection    .data
+       .pushsection    .data..cacheline_aligned
 ENTRY(__boot_cpu_mode)
+       .align  L1_CACHE_SHIFT
        .long   BOOT_CPU_MODE_EL2
        .long   0
        .popsection
@@ -401,6 +407,15 @@ ENDPROC(__calc_phys_offset)
  */
 __create_page_tables:
        pgtbl   x25, x26, x24                   // idmap_pg_dir and swapper_pg_dir addresses
+       mov     x27, lr
+
+       /*
+        * Invalidate the idmap and swapper page tables to avoid potential
+        * dirty cache lines being evicted.
+        */
+       mov     x0, x25
+       add     x1, x26, #SWAPPER_DIR_SIZE
+       bl      __inval_cache_range
 
        /*
         * Clear the idmap and swapper page tables.
@@ -460,6 +475,17 @@ __create_page_tables:
        ldr     x5, =FIXADDR_TOP                // Fixed mapping virtual address
        add     x0, x26, #2 * PAGE_SIZE         // section table address
        create_pgd_entry x26, x0, x5, x6, x7
+
+       /*
+        * Since the page tables have been populated with non-cacheable
+        * accesses (MMU disabled), invalidate the idmap and swapper page
+        * tables again to remove any speculatively loaded cache lines.
+        */
+       mov     x0, x25
+       add     x1, x26, #SWAPPER_DIR_SIZE
+       bl      __inval_cache_range
+
+       mov     lr, x27
        ret
 ENDPROC(__create_page_tables)
        .ltorg
index 0e379c44544bc2cd4f85bf7625a9f35d4a93998b..fda756875fa63e0fca640e99ca9a20ed789a20f4 100644 (file)
@@ -167,6 +167,14 @@ ENTRY(__flush_dcache_area)
        ret
 ENDPROC(__flush_dcache_area)
 
+/*
+ *     __inval_cache_range(start, end)
+ *     - start   - start address of region
+ *     - end     - end address of region
+ */
+ENTRY(__inval_cache_range)
+       /* FALLTHROUGH */
+
 /*
  *     __dma_inv_range(start, end)
  *     - start   - virtual start address of region
@@ -190,6 +198,7 @@ __dma_inv_range:
        b.lo    2b
        dsb     sy
        ret
+ENDPROC(__inval_cache_range)
 ENDPROC(__dma_inv_range)
 
 /*