* Simple cache maintenance functions
*/
-dlinesz_addr:
- .long EXT_C(grub_arch_cache_dlinesz)
-ilinesz_addr:
- .long EXT_C(grub_arch_cache_ilinesz)
-
@ r0 - *beg (inclusive)
@ r1 - *end (exclusive)
-clean_dcache_range:
+@void grub_arm_clean_dcache_range (grub_addr_t start, grub_addr_t end, grub_addr_t dlinesz)
+#ifdef ARMV6
+FUNCTION(grub_arm_clean_dcache_range_armv6)
+#else
+FUNCTION(grub_arm_clean_dcache_range_armv7)
+#endif
+ DSB
@ Clean data cache for range to point-of-unification
- ldr r2, dlinesz_addr
- ldr r2, [r2]
- sub r3, r2, #1 @ align "beg" to start of line
- mvn r3, r3
- and r0, r0, r3
1: cmp r0, r1
bge 2f
#ifdef ARMV6
@ r0 - *beg (inclusive)
@ r1 - *end (exclusive)
-invalidate_icache_range:
+#ifdef ARMV6
+FUNCTION(grub_arm_invalidate_icache_range_armv6)
+#else
+FUNCTION(grub_arm_invalidate_icache_range_armv7)
+#endif
@ Invalidate instruction cache for range to point-of-unification
- ldr r2, ilinesz_addr
- ldr r2, [r2]
- sub r3, r2, #1 @ align "beg" to start of line
- mvn r3, r3
- and r0, r0, r3
1: cmp r0, r1
bge 2f
mcr p15, 0, r0, c7, c5, 1 @ ICIMVAU
ISB
bx lr
-@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
- DSB
- add r1, r0, r1
- push {r0-r2, lr}
- bl clean_dcache_range
- pop {r0, r1}
- bl invalidate_icache_range
- pop {r2, lr}
- bx lr
-
#ifdef ARMV6
FUNCTION(grub_arm_disable_caches_mmu_armv6)
#else
ARCH_ARMV7
} type = ARCH_UNKNOWN;
-grub_uint32_t grub_arch_cache_dlinesz;
-grub_uint32_t grub_arch_cache_ilinesz;
+static grub_uint32_t grub_arch_cache_dlinesz;
+static grub_uint32_t grub_arch_cache_ilinesz;
+static grub_uint32_t grub_arch_cache_max_linesz;
/* 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_clean_dcache_range_armv6 (grub_addr_t start, grub_addr_t end,
+ grub_addr_t dlinesz);
+void grub_arm_clean_dcache_range_armv7 (grub_addr_t start, grub_addr_t end,
+ grub_addr_t dlinesz);
+void grub_arm_invalidate_icache_range_armv6 (grub_addr_t start, grub_addr_t end,
+ grub_addr_t dlinesz);
+void grub_arm_invalidate_icache_range_armv7 (grub_addr_t start, grub_addr_t end,
+ grub_addr_t dlinesz);
void grub_arm_disable_caches_mmu_armv6 (void);
void grub_arm_disable_caches_mmu_armv7 (void);
grub_uint32_t grub_arm_main_id (void);
default:
grub_fatal ("Unsupported cache type 0x%x", cache_type);
}
+ if (grub_arch_cache_dlinesz > grub_arch_cache_ilinesz)
+ grub_arch_cache_max_linesz = grub_arch_cache_dlinesz;
+ else
+ grub_arch_cache_max_linesz = grub_arch_cache_ilinesz;
}
void
grub_arch_sync_caches (void *address, grub_size_t len)
{
+ grub_addr_t start = (grub_addr_t) address;
+ grub_addr_t end = start + len;
+
if (type == ARCH_UNKNOWN)
probe_caches ();
+ start = ALIGN_DOWN (start, grub_arch_cache_max_linesz);
+ end = ALIGN_UP (end, grub_arch_cache_max_linesz);
switch (type)
{
case ARCH_ARMV6:
- grub_arch_sync_caches_armv6 (address, len);
+ grub_arm_clean_dcache_range_armv6 (start, end, grub_arch_cache_dlinesz);
+ grub_arm_invalidate_icache_range_armv6 (start, end,
+ grub_arch_cache_ilinesz);
break;
case ARCH_ARMV7:
- grub_arch_sync_caches_armv7 (address, len);
+ grub_arm_clean_dcache_range_armv7 (start, end, grub_arch_cache_dlinesz);
+ grub_arm_invalidate_icache_range_armv7 (start, end,
+ grub_arch_cache_ilinesz);
break;
/* Nothing to do. */
case ARCH_ARMV5_WRITE_THROUGH: