]> git.ipfire.org Git - thirdparty/grub.git/commitdiff
Detect cache type on runtime rather than compile time
authorVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Thu, 16 May 2013 23:33:22 +0000 (01:33 +0200)
committerVladimir 'phcoder' Serbinenko <phcoder@gmail.com>
Thu, 16 May 2013 23:33:22 +0000 (01:33 +0200)
grub-core/Makefile.core.def
grub-core/kern/arm/cache.S
grub-core/kern/arm/cache.c [new file with mode: 0644]
grub-core/kern/arm/cache_armv6.S [new file with mode: 0644]
grub-core/kern/arm/cache_armv7.S [new file with mode: 0644]

index b444042b3576f451572b926e799ed7749d9c3fb9..d01667d8be4da91e28dee51ce5462ee9b53f9c20 100644 (file)
@@ -227,7 +227,9 @@ kernel = {
 
   arm = kern/arm/dl.c;
   arm = kern/arm/dl_helper.c;
-  arm = kern/arm/cache.S;
+  arm = kern/arm/cache_armv6.S;
+  arm = kern/arm/cache_armv7.S;
+  arm = kern/arm/cache.c;
   arm = kern/arm/misc.S;
 
   emu = disk/host.c;
index 15d7b14e6d7063a889c02cb85344c80060f155ff..cd28dd9081aa2b471bc31771e37401b621926d3d 100644 (file)
        .text
        .syntax unified
        .arm
-#if (__ARM_ARCH_6__ == 1)
-       .arch   armv6
-# define DMB   mcr     p15, 0, r0, c7, c10, 5
-# define DSB   mcr     p15, 0, r0, c7, c10, 4
-# define ISB   mcr     p15, 0, r0, c7, c5, 4
-#elif (__ARM_ARCH_7A__ == 1)
-# define DMB   dmb
-# define DSB   dsb
-# define ISB   isb
-#else
+#if !defined (ARMV6) && !defined (ARMV7)
 # error Unsupported architecture version!
 #endif
 
 @ r1 - *end (exclusive)
 clean_dcache_range:
        @ Clean data cache for range to point-of-unification
-       ldr     r2, dlinesz
+       ldr     r2, =EXT_C(grub_arch_cache_dlinesz)
        sub     r3, r2, #1              @ align "beg" to start of line
        mvn     r3, r3
        and     r0, r0, r3
 1:     cmp     r0, r1
        bge     2f
-#if (__ARM_ARCH_6__ == 1)
+#ifdef ARMV6
        mcr     p15, 0, r0, c7, c10, 1  @ Clean data cache line by MVA
 #else
        mcr     p15, 0, r0, c7, c11, 1  @ DCCMVAU
@@ -65,7 +56,7 @@ clean_dcache_range:
 @ r1 - *end (exclusive)
 invalidate_icache_range:
        @ Invalidate instruction cache for range to point-of-unification
-       ldr     r2, ilinesz
+       ldr     r2, =EXT_C(grub_arch_cache_ilinesz)
        sub     r3, r2, #1              @ align "beg" to start of line
        mvn     r3, r3
        and     r0, r0, r3
@@ -80,151 +71,27 @@ invalidate_icache_range:
        ISB
        bx      lr
 
-sync_caches:
+@void grub_arch_sync_caches (void *address, grub_size_t len)
+#ifdef ARMV6
+FUNCTION(grub_arch_sync_caches_armv6)
+#else
+FUNCTION(grub_arch_sync_caches_armv7)
+#endif
+       add     r1, r0, r1
        DSB
        push    {r0-r1, r4-r6, lr}
-       ldr     r2, probed      @ If first call, probe cache sizes
-       cmp     r2, #0
-       bleq    probe_caches
        ldrdeq  r0, r1, [sp]
        bl      clean_dcache_range
        pop     {r0, r1}
        bl      invalidate_icache_range
        pop     {r4-r6, pc}
 
-probe_caches:
-       push    {r4-r6, lr}
-       mrc     p15, 0, r0, c0, c0, 1   @ Read Cache Type Register
-       mov     r1, #1
-@ Cache Type Register format changed in ARMv7
-@ r5 - dlinesz
-@ r6 - ilinesz
-#if (__ARM_ARCH_6__ == 1)
-       lsl     r2, r0, #12
-       and     r2, r2, #3              @ Dsize 'len'
-       lsl     r2, r1, r2              @ Convert to num 8-byte blocks
-       lsl     r5, r2, #3              @ Convert to num bytes
-       and     r2, r0, #3              @ Isize 'len'
-       lsl     r2, r1, r2              @ Convert to num 8-byte blocks
-       lsl     r6, r2, #3              @ Convert to num bytes
+#ifdef ARMV6
+FUNCTION(grub_arm_disable_caches_mmu_armv6)
 #else
-       lsr     r2, r0, #16             @ Extract min D-cache num word log2
-       and     r2, r2, #0xf
-       add     r2, r2, #2              @ words->bytes
-       lsl     r5, r1, r2              @ Convert to num bytes
-       and     r2, r0, #0xf            @ Extract min I-cache num word log2
-       add     r2, r2, #2              @ words->bytes
-       lsl     r6, r1, r2              @ Convert to num bytes
-#endif
-       ldr     r3, =dlinesz
-       str     r5, [r3]
-       ldr     r3, =ilinesz
-       str     r6, [r3]
-       ldr     r3, =probed             @ Flag cache probing done
-       str     r1, [r3]
-       pop     {r4-r6, pc}
-
-       .align  3
-probed:        .long   0
-dlinesz:
-       .long   0
-ilinesz:
-       .long   0
-
-@void grub_arch_sync_caches (void *address, grub_size_t len)
-FUNCTION(grub_arch_sync_caches)
-       add     r1, r0, r1
-       b       sync_caches
-
-       @ r0  - CLIDR
-       @ r1  - LoC
-       @ r2  - current level
-       @ r3  - num sets
-       @ r4  - num ways
-       @ r5  - current set
-       @ r6  - current way
-       @ r7  - line size
-       @ r8  - scratch
-       @ r9  - scratch
-       @ r10 - scratch
-       @ r11 - scratch
-clean_invalidate_dcache:
-#if (__ARM_ARCH_6__ == 1)
-       mcr     p15, 0, r0, c7, c14, 0  @ Clean/Invalidate D-cache
-       bx      lr
-#elif (__ARM_ARCH_7A__ == 1)
-       push    {r4-r12, lr}
-       mrc     p15, 1, r0, c0, c0, 1   @ Read CLIDR
-       lsr     r1, r0, #24             @ Extract LoC
-       and     r1, r1, #0x7
-
-       mov     r2, #0                  @ First level, L1
-2:     and     r8, r0, #7              @ cache type at current level
-       cmp     r8, #2
-       blt     5f                      @ instruction only, or none, skip level
-
-       @ set current cache level/type (for CCSIDR read)
-       lsl     r8, r2, #1
-       mcr     p15, 2, r8, c0, c0, 0   @ Write CSSELR (level, type: data/uni)
-
-       @ read current cache information
-       mrc     p15, 1, r8, c0, c0, 0   @ Read CCSIDR
-       lsr     r3, r8, #13             @ Number of sets -1
-       ldr     r9, =0x3fff
-       and     r3, r3, r9
-       lsr     r4, r8, #3              @ Number of ways -1
-       ldr     r9, =0x1ff
-       and     r4, r4, r9
-       and     r7, r8, #7              @ log2(line size in words) - 2
-       add     r7, r7, #2              @  adjust
-       mov     r8, #1
-       lsl     r7, r8, r7              @  -> line size in words
-       lsl     r7, r7, #2              @  -> bytes
-
-       @ set loop
-       mov     r5, #0                  @ current set = 0
-3:     lsl     r8, r2, #1              @ insert level
-       clz     r9, r7                  @ calculate set field offset
-       mov     r10, #31
-       sub     r9, r10, r9
-       lsl     r10, r5, r9
-       orr     r8, r8, r10             @ insert set field
-
-       @ way loop
-       @ calculate way field offset
-       mov     r6, #0                  @ current way = 0
-       add     r10, r4, #1
-       clz     r9, r10                 @ r9 = way field offset
-       add     r9, r9, #1
-4:     lsl     r10, r6, r9
-       orr     r11, r8, r10            @ insert way field
-
-       @ clean and invalidate line by set/way
-       mcr     p15, 0, r11, c7, c14, 2 @ DCCISW
-
-       @ next way
-       add     r6, r6, #1
-       cmp     r6, r4
-       ble     4b
-
-       @ next set
-       add     r5, r5, #1
-       cmp     r5, r3
-       ble     3b
-
-       @ next level
-5:     lsr     r0, r0, #3              @ align next level CLIDR 'type' field
-       add     r2, r2, #1              @ increment cache level counter
-       cmp     r2, r1
-       blt     2b                      @ outer loop
-
-       @ return
-6:     DSB
-       ISB
-       pop     {r4-r12, pc}
+FUNCTION(grub_arm_disable_caches_mmu_armv7)
 #endif
 
-FUNCTION(grub_arm_disable_caches_mmu)
        push    {r4, lr}
 
        @ disable D-cache
diff --git a/grub-core/kern/arm/cache.c b/grub-core/kern/arm/cache.c
new file mode 100644 (file)
index 0000000..4849d24
--- /dev/null
@@ -0,0 +1,72 @@
+#include <grub/dl.h>
+#include <grub/cache.h>
+#include <grub/arm/system.h>
+
+static enum
+  {
+    ARCH_UNKNOWN,
+    ARCH_ARMV6,
+    ARCH_ARMV7
+  } type = ARCH_UNKNOWN;
+
+grub_uint32_t grub_arch_cache_dlinesz;
+grub_uint32_t grub_arch_cache_ilinesz;
+
+/* Prototypes for asm functions.  */
+void grub_arch_sync_caches_armv6 (void *address, grub_size_t len);
+void grub_arch_sync_caches_armv7 (void *address, grub_size_t len);
+void grub_arm_disable_caches_mmu_armv6 (void);
+void grub_arm_disable_caches_mmu_armv7 (void);
+
+static void
+probe_caches (void)
+{
+  grub_uint32_t main_id, cache_type;
+
+  /* Read Cache Type Register */
+  asm volatile ("mrc   p15, 0, %0, c0, c0, 0": "=r"(main_id));
+
+  if (((main_id >> 12) & 0xf) == 0x0 || ((main_id >> 12) & 0xf) == 0x7
+      || (((main_id >> 16) & 0x7) != 0x7))
+    grub_fatal ("Unsupported ARM ID 0x%x", main_id);
+
+  /* Read Cache Type Register */
+  asm volatile ("mrc   p15, 0, %0, c0, c0, 1": "=r"(cache_type));
+
+  switch (cache_type >> 29)
+    {
+    case 0:
+      grub_arch_cache_dlinesz = 8 << ((cache_type >> 12) & 3);
+      grub_arch_cache_ilinesz = 8 << (cache_type & 3);
+      type = ARCH_ARMV6;
+      break;
+    case 4:
+      grub_arch_cache_dlinesz = 4 << ((cache_type >> 16) & 0xf);
+      grub_arch_cache_ilinesz = 4 << (cache_type & 0xf);
+      type = ARCH_ARMV7;
+    default:
+      grub_fatal ("Unsupported cache type 0x%x", cache_type);
+    }
+}
+
+void
+grub_arch_sync_caches (void *address, grub_size_t len)
+{
+  if (type == ARCH_UNKNOWN)
+    probe_caches ();
+  if (type == ARCH_ARMV6)
+    grub_arch_sync_caches_armv6 (address, len);
+  if (type == ARCH_ARMV7)
+    grub_arch_sync_caches_armv7 (address, len);
+}
+
+void
+grub_arm_disable_caches_mmu (void)
+{
+  if (type == ARCH_UNKNOWN)
+    probe_caches ();
+  if (type == ARCH_ARMV6)
+    grub_arm_disable_caches_mmu_armv6 ();
+  if (type == ARCH_ARMV7)
+    grub_arm_disable_caches_mmu_armv7 ();
+}
diff --git a/grub-core/kern/arm/cache_armv6.S b/grub-core/kern/arm/cache_armv6.S
new file mode 100644 (file)
index 0000000..e9da423
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2013  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+
+       .file   "cache_armv6.S"
+       .text
+       .syntax unified
+       .arm
+       .arch   armv6
+# define DMB   mcr     p15, 0, r0, c7, c10, 5
+# define DSB   mcr     p15, 0, r0, c7, c10, 4
+# define ISB   mcr     p15, 0, r0, c7, c5, 4
+#define ARMV6 1
+
+clean_invalidate_dcache:
+       mcr     p15, 0, r0, c7, c14, 0  @ Clean/Invalidate D-cache
+       bx      lr
+
+#include "cache.S"
\ No newline at end of file
diff --git a/grub-core/kern/arm/cache_armv7.S b/grub-core/kern/arm/cache_armv7.S
new file mode 100644 (file)
index 0000000..0c16b10
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ *  GRUB  --  GRand Unified Bootloader
+ *  Copyright (C) 2013  Free Software Foundation, Inc.
+ *
+ *  GRUB is free software: you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation, either version 3 of the License, or
+ *  (at your option) any later version.
+ *
+ *  GRUB is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <grub/symbol.h>
+
+       .file   "cache_armv7.S"
+       .text
+       .syntax unified
+       .arm
+       .arch   armv7a
+# define DMB   dmb
+# define DSB   dsb
+# define ISB   isb
+#define ARMV7 1
+
+       @ r0  - CLIDR
+       @ r1  - LoC
+       @ r2  - current level
+       @ r3  - num sets
+       @ r4  - num ways
+       @ r5  - current set
+       @ r6  - current way
+       @ r7  - line size
+       @ r8  - scratch
+       @ r9  - scratch
+       @ r10 - scratch
+       @ r11 - scratch
+clean_invalidate_dcache:
+       push    {r4-r12, lr}
+       mrc     p15, 1, r0, c0, c0, 1   @ Read CLIDR
+       lsr     r1, r0, #24             @ Extract LoC
+       and     r1, r1, #0x7
+
+       mov     r2, #0                  @ First level, L1
+2:     and     r8, r0, #7              @ cache type at current level
+       cmp     r8, #2
+       blt     5f                      @ instruction only, or none, skip level
+
+       @ set current cache level/type (for CCSIDR read)
+       lsl     r8, r2, #1
+       mcr     p15, 2, r8, c0, c0, 0   @ Write CSSELR (level, type: data/uni)
+
+       @ read current cache information
+       mrc     p15, 1, r8, c0, c0, 0   @ Read CCSIDR
+       lsr     r3, r8, #13             @ Number of sets -1
+       ldr     r9, =0x3fff
+       and     r3, r3, r9
+       lsr     r4, r8, #3              @ Number of ways -1
+       ldr     r9, =0x1ff
+       and     r4, r4, r9
+       and     r7, r8, #7              @ log2(line size in words) - 2
+       add     r7, r7, #2              @  adjust
+       mov     r8, #1
+       lsl     r7, r8, r7              @  -> line size in words
+       lsl     r7, r7, #2              @  -> bytes
+
+       @ set loop
+       mov     r5, #0                  @ current set = 0
+3:     lsl     r8, r2, #1              @ insert level
+       clz     r9, r7                  @ calculate set field offset
+       mov     r10, #31
+       sub     r9, r10, r9
+       lsl     r10, r5, r9
+       orr     r8, r8, r10             @ insert set field
+
+       @ way loop
+       @ calculate way field offset
+       mov     r6, #0                  @ current way = 0
+       add     r10, r4, #1
+       clz     r9, r10                 @ r9 = way field offset
+       add     r9, r9, #1
+4:     lsl     r10, r6, r9
+       orr     r11, r8, r10            @ insert way field
+
+       @ clean and invalidate line by set/way
+       mcr     p15, 0, r11, c7, c14, 2 @ DCCISW
+
+       @ next way
+       add     r6, r6, #1
+       cmp     r6, r4
+       ble     4b
+
+       @ next set
+       add     r5, r5, #1
+       cmp     r5, r3
+       ble     3b
+
+       @ next level
+5:     lsr     r0, r0, #3              @ align next level CLIDR 'type' field
+       add     r2, r2, #1              @ increment cache level counter
+       cmp     r2, r1
+       blt     2b                      @ outer loop
+
+       @ return
+6:     DSB
+       ISB
+       pop     {r4-r12, pc}
+
+#include "cache.S"
\ No newline at end of file