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;
.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
@ 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
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
--- /dev/null
+#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 ();
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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