atm920t : fix breakpoints and data cache handling

Breakpoints did not work because the data cache was not flushed
properly.

As a bonus add capability to write to memory marked as read only
by the MMU, which allows software breakpoints in such memory
regions.
This commit is contained in:
Marc Pignat 2010-02-16 10:08:18 +01:00 committed by Øyvind Harboe
parent aa8db989b9
commit 3f30563c88
1 changed files with 103 additions and 17 deletions

View File

@ -559,34 +559,120 @@ static int arm920t_write_phys_memory(struct target *target,
/** Writes a buffer, in the specified word size, with current MMU settings. */
int arm920t_write_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
int arm920t_write_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
int retval;
if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK)
return retval;
/* This fn is used to write breakpoints, so we need to make sure
* that the data cache is flushed and the instruction cache is
* invalidated
*/
if (((size == 4) || (size == 2)) && (count == 1))
{
const uint32_t cache_mask = ~0x1f; /* cache line size : 32 byte */
struct arm920t_common *arm920t = target_to_arm920(target);
/* FIX!!!! this should be cleaned up and made much more general. The
* plan is to write up and test on arm920t specifically and
* then generalize and clean up afterwards. */
if (arm920t->armv4_5_mmu.mmu_enabled && (count == 1) && ((size==2) || (size==4)))
{
/* special case the handling of single word writes to bypass MMU
* to allow implementation of breakpoints in memory marked read only
* by MMU */
int type;
uint32_t cb;
int domain;
uint32_t ap;
uint32_t pa;
/*
* We need physical address and cb
*/
pa = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu, address, &type, &cb, &domain, &ap);
if (type == -1)
{
return pa;
}
if (arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled)
{
LOG_DEBUG("D-Cache enabled, flush and invalidate cache line");
/* MCR p15,0,Rd,c7,c10,2 */
retval = arm920t_write_cp15_interpreted(target, 0xee070f5e, 0x0, address);
if (cb & 0x1)
{
LOG_DEBUG("D-Cache buffered, drain write buffer");
/*
* Buffered ?
* Drain write buffer - MCR p15,0,Rd,c7,c10,4
*/
retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 10, 4), 0x0, 0);
if (retval != ERROR_OK)
return retval;
}
if (cb == 0x3)
{
/*
* Write back memory ? -> clean cache
*
* There is no way for cleaning a data cache line using
* cp15 scan chain, so copy the full cache line from
* cache to physical memory.
*/
uint8_t data[32];
LOG_DEBUG("D-Cache in 'write back' mode, flush cache line");
retval = target_read_memory(target, address & cache_mask, 1, sizeof(data), &data[0]);
if (retval != ERROR_OK)
return retval;
retval = armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa & cache_mask, 1, sizeof(data), &data[0]);
if (retval != ERROR_OK)
return retval;
}
/* Cached ? */
if (cb & 0x2)
{
/*
* Cached ? -> Invalidate data cache using MVA
*
* MCR p15,0,Rd,c7,c6,1
*/
LOG_DEBUG("D-Cache enabled, invalidate cache line");
retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 6, 1), 0x0, address & cache_mask);
if (retval != ERROR_OK)
return retval;
}
}
/* write directly to physical memory bypassing any read only MMU bits, etc. */
retval = armv4_5_mmu_write_physical(target, &arm920t->armv4_5_mmu, pa, size, count, buffer);
if (retval != ERROR_OK)
return retval;
} else
{
if ((retval = arm7_9_write_memory(target, address, size, count, buffer)) != ERROR_OK)
return retval;
}
/* If ICache is enabled, we have to invalidate affected ICache lines
* the DCache is forced to write-through, so we don't have to clean it here
*/
if (arm920t->armv4_5_mmu.armv4_5_cache.i_cache_enabled)
{
if (count <= 1)
{
/* invalidate ICache single entry with MVA
* ee070f35 mcr 15, 0, r0, cr7, cr5, {1}
*/
LOG_DEBUG("I-Cache enabled, invalidating affected I-Cache line");
retval = arm920t_write_cp15_interpreted(target, 0xee070f35, 0x0, address);
retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 5, 1), 0x0, address & cache_mask);
if (retval != ERROR_OK)
return retval;
}
else
{
/* invalidate ICache
* 8: ee070f15 mcr 15, 0, r0, cr7, cr5, {0}
* */
retval = arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0x0, 0x0);
if (retval != ERROR_OK)
return retval;
}