Fix ARM cache maintainance.

More code was converted from ASM to C for easier handling.
This commit is contained in:
Vladimir Serbinenko 2013-12-23 04:27:53 +01:00
parent adabfb5418
commit 943981ff65
3 changed files with 44 additions and 38 deletions

View file

@ -1,3 +1,9 @@
2013-12-23 Vladimir Serbinenko <phcoder@gmail.com>
Fix ARM cache maintainance.
More code was converted from ASM to C for easier handling.
2013-12-22 Vladimir Serbinenko <phcoder@gmail.com> 2013-12-22 Vladimir Serbinenko <phcoder@gmail.com>
* grub-core/kern/arm/cache.c (grub_arm_disable_caches_mmu): Use v6 * grub-core/kern/arm/cache.c (grub_arm_disable_caches_mmu): Use v6

View file

@ -37,20 +37,16 @@
* Simple cache maintenance functions * 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) @ r0 - *beg (inclusive)
@ r1 - *end (exclusive) @ 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 @ 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 1: cmp r0, r1
bge 2f bge 2f
#ifdef ARMV6 #ifdef ARMV6
@ -65,13 +61,12 @@ clean_dcache_range:
@ r0 - *beg (inclusive) @ r0 - *beg (inclusive)
@ r1 - *end (exclusive) @ 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 @ 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 1: cmp r0, r1
bge 2f bge 2f
mcr p15, 0, r0, c7, c5, 1 @ ICIMVAU mcr p15, 0, r0, c7, c5, 1 @ ICIMVAU
@ -83,21 +78,6 @@ invalidate_icache_range:
ISB ISB
bx lr 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 #ifdef ARMV6
FUNCTION(grub_arm_disable_caches_mmu_armv6) FUNCTION(grub_arm_disable_caches_mmu_armv6)
#else #else

View file

@ -13,12 +13,19 @@ static enum
ARCH_ARMV7 ARCH_ARMV7
} type = ARCH_UNKNOWN; } type = ARCH_UNKNOWN;
grub_uint32_t grub_arch_cache_dlinesz; static grub_uint32_t grub_arch_cache_dlinesz;
grub_uint32_t grub_arch_cache_ilinesz; static grub_uint32_t grub_arch_cache_ilinesz;
static grub_uint32_t grub_arch_cache_max_linesz;
/* Prototypes for asm functions. */ /* Prototypes for asm functions. */
void grub_arch_sync_caches_armv6 (void *address, grub_size_t len); void grub_arm_clean_dcache_range_armv6 (grub_addr_t start, grub_addr_t end,
void grub_arch_sync_caches_armv7 (void *address, grub_size_t len); 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_armv6 (void);
void grub_arm_disable_caches_mmu_armv7 (void); void grub_arm_disable_caches_mmu_armv7 (void);
grub_uint32_t grub_arm_main_id (void); grub_uint32_t grub_arm_main_id (void);
@ -82,20 +89,33 @@ probe_caches (void)
default: default:
grub_fatal ("Unsupported cache type 0x%x", cache_type); 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 void
grub_arch_sync_caches (void *address, grub_size_t len) 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) if (type == ARCH_UNKNOWN)
probe_caches (); probe_caches ();
start = ALIGN_DOWN (start, grub_arch_cache_max_linesz);
end = ALIGN_UP (end, grub_arch_cache_max_linesz);
switch (type) switch (type)
{ {
case ARCH_ARMV6: 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; break;
case ARCH_ARMV7: 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; break;
/* Nothing to do. */ /* Nothing to do. */
case ARCH_ARMV5_WRITE_THROUGH: case ARCH_ARMV5_WRITE_THROUGH: