int armv7a_l1_d_cache_inval_virt(struct target *target, uint32_t virt, uint32_t size) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->dminline; uint32_t va_line, va_end; int retval; retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) return retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; va_line = virt & (-linelen); va_end = virt + size; /* handle unaligned start */ if (virt != va_line) { /* DCCIMVAC */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line); if (retval != ERROR_OK) goto done; va_line += linelen; } /* handle unaligned end */ if ((va_end & (linelen-1)) != 0) { va_end &= (-linelen); /* DCCIMVAC */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_end); if (retval != ERROR_OK) goto done; } while (va_line < va_end) { /* DCIMVAC - Invalidate data cache line by VA to PoC. */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 6, 1), va_line); if (retval != ERROR_OK) goto done; va_line += linelen; } dpm->finish(dpm); return retval; done: LOG_ERROR("d-cache invalidate failed"); dpm->finish(dpm); return retval; }
static int armv7a_l1_d_cache_flush_level(struct arm_dpm *dpm, struct armv7a_cachesize *size, int cl) { int retval = ERROR_OK; int32_t c_way, c_index = size->index; LOG_DEBUG("cl %" PRId32, cl); do { c_way = size->way; do { uint32_t value = (c_index << size->index_shift) | (c_way << size->way_shift) | (cl << 1); /* * DCCISW - Clean and invalidate data cache * line by Set/Way. */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 14, 2), value); if (retval != ERROR_OK) goto done; c_way -= 1; } while (c_way >= 0); c_index -= 1; } while (c_index >= 0); done: return retval; }
int armv7a_l1_i_cache_inval_virt(struct target *target, uint32_t virt, uint32_t size) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->iminline; uint32_t va_line, va_end; int retval; retval = armv7a_l1_i_cache_sanity_check(target); if (retval != ERROR_OK) return retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; va_line = virt & (-linelen); va_end = virt + size; while (va_line < va_end) { /* ICIMVAU - Invalidate instruction cache by VA to PoU. */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 5, 1), va_line); if (retval != ERROR_OK) goto done; /* BPIMVA */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 5, 7), va_line); if (retval != ERROR_OK) goto done; va_line += linelen; } return retval; done: LOG_ERROR("i-cache invalidate failed"); dpm->finish(dpm); return retval; }
/* just read the register -- rely on the core mode being right */ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) { uint32_t value; int retval; switch (regnum) { case 0 ... 14: /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */ retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, regnum, 0, 5, 0), &value); break; case 15:/* PC * "MOV r0, pc"; then return via DCC */ retval = dpm->instr_read_data_r0(dpm, 0xe1a0000f, &value); /* NOTE: this seems like a slightly awkward place to update * this value ... but if the PC gets written (the only way * to change what we compute), the arch spec says subsequent * reads return values which are "unpredictable". So this * is always right except in those broken-by-intent cases. */ switch (dpm->arm->core_state) { case ARM_STATE_ARM: value -= 8; break; case ARM_STATE_THUMB: case ARM_STATE_THUMB_EE: value -= 4; break; case ARM_STATE_JAZELLE: /* core-specific ... ? */ LOG_WARNING("Jazelle PC adjustment unknown"); break; } break; default: /* 16: "MRS r0, CPSR"; then return via DCC * 17: "MRS r0, SPSR"; then return via DCC */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, regnum & 1), &value); break; } if (retval == ERROR_OK) { buf_set_u32(r->value, 0, 32, value); r->valid = true; r->dirty = false; LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned) value); } return retval; }
int armv7a_l1_i_cache_inval_all(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; int retval; retval = armv7a_l1_i_cache_sanity_check(target); if (retval != ERROR_OK) return retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; if (target->smp) { /* ICIALLUIS */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 1, 0), 0); } else { /* ICIALLU */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 5, 0), 0); } if (retval != ERROR_OK) goto done; dpm->finish(dpm); return retval; done: LOG_ERROR("i-cache invalidate failed"); dpm->finish(dpm); return retval; }
static int arm920t_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value) { if (cpnum != 15) { LOG_ERROR("Only cp15 is supported"); return ERROR_FAIL; } /* write "from" r0 */ return arm920t_write_cp15_interpreted(target, ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2), 0, value); }
int armv7a_l1_d_cache_flush_virt(struct target *target, uint32_t virt, unsigned int size) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm_dpm *dpm = armv7a->arm.dpm; struct armv7a_cache_common *armv7a_cache = &armv7a->armv7a_mmu.armv7a_cache; uint32_t linelen = armv7a_cache->dminline; uint32_t va_line, va_end; int retval; retval = armv7a_l1_d_cache_sanity_check(target); if (retval != ERROR_OK) return retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; va_line = virt & (-linelen); va_end = virt + size; while (va_line < va_end) { /* DCCIMVAC */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 7, 14, 1), va_line); if (retval != ERROR_OK) goto done; va_line += linelen; } dpm->finish(dpm); return retval; done: LOG_ERROR("d-cache invalidate failed"); dpm->finish(dpm); return retval; }
static int dpm_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum, (int) op1, (int) CRn, (int) CRm, (int) op2); /* read DCC into r0; then write coprocessor register from R0 */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2), value); /* (void) */ dpm->finish(dpm); return retval; }
/** 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 retval; 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. * * Also it should be moved to the callbacks that handle breakpoints * specifically and not the generic memory write fn's. See XScale code. */ 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 */ uint32_t cb; uint32_t pa; /* * We need physical address and cb */ retval = armv4_5_mmu_translate_va(target, &arm920t->armv4_5_mmu, address, &cb, &pa); if (retval != ERROR_OK) return retval; if (arm920t->armv4_5_mmu.armv4_5_cache.d_u_cache_enabled) { 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 to clean cache lines 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 * mcr 15, 0, r0, cr7, cr5, {1} */ LOG_DEBUG("I-Cache enabled, " "invalidating affected I-Cache line"); 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 * 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; } } return ERROR_OK; }
static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t value) { struct arm_dpm *dpm = &armv8->dpm; int retval; switch (regnum) { case ARMV8_R0 ... ARMV8_R14: /* load register from DCC: "MRC p14, 0, Rnum, c0, c5, 0" */ retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, regnum, 0, 5, 0), value); break; case ARMV8_SP: retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 13, 0, 5, 0), value); break; case ARMV8_PC:/* PC * read r0 from DCC; then "MOV pc, r0" */ retval = dpm->instr_write_data_r0(dpm, ARMV8_MCR_DLR(0), value); break; case ARMV8_xPSR: /* CPSR */ /* read r0 from DCC, then "MCR r0, DSPSR" */ retval = dpm->instr_write_data_r0(dpm, ARMV8_MCR_DSPSR(0), value); break; case ARMV8_ELR_EL1: /* mapped to LR_svc */ retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 14, 0, 5, 0), value); break; case ARMV8_ELR_EL2: /* mapped to ELR_hyp */ retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP_T1(0, 14, 0, 1), value); break; case ARMV8_ELR_EL3: /* mapped to LR_mon */ retval = dpm->instr_write_data_dcc(dpm, ARMV4_5_MRC(14, 0, 14, 0, 5, 0), value); break; case ARMV8_ESR_EL1: /* mapped to DFSR */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 0, 0, 5, 0, 0), value); break; case ARMV8_ESR_EL2: /* mapped to HSR */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(15, 4, 0, 5, 2, 0), value); break; case ARMV8_ESR_EL3: /* FIXME: no equivalent in aarch32? */ retval = ERROR_FAIL; break; case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */ retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP_xPSR_T1(1, 0, 15), value); break; case ARMV8_SPSR_EL2: /* mapped to SPSR_hyp */ retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP_xPSR_T1(1, 0, 15), value); break; case ARMV8_SPSR_EL3: /* mapped to SPSR_mon */ retval = dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP_xPSR_T1(1, 0, 15), value); break; default: retval = ERROR_FAIL; break; } return retval; }
static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *regval) { struct arm_dpm *dpm = &armv8->dpm; uint32_t value = 0; int retval; switch (regnum) { case ARMV8_R0 ... ARMV8_R14: /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */ retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, regnum, 0, 5, 0), &value); break; case ARMV8_SP: retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, 13, 0, 5, 0), &value); break; case ARMV8_PC: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRC_DLR(0), &value); break; case ARMV8_xPSR: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRC_DSPSR(0), &value); break; case ARMV8_ELR_EL1: /* mapped to LR_svc */ retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, 14, 0, 5, 0), &value); break; case ARMV8_ELR_EL2: /* mapped to ELR_hyp */ retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS_T1(0, 14, 0, 1), &value); break; case ARMV8_ELR_EL3: /* mapped to LR_mon */ retval = dpm->instr_read_data_dcc(dpm, ARMV4_5_MCR(14, 0, 14, 0, 5, 0), &value); break; case ARMV8_ESR_EL1: /* mapped to DFSR */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 0, 0, 5, 0, 0), &value); break; case ARMV8_ESR_EL2: /* mapped to HSR */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(15, 4, 0, 5, 2, 0), &value); break; case ARMV8_ESR_EL3: /* FIXME: no equivalent in aarch32? */ retval = ERROR_FAIL; break; case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */ retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS_xPSR_T1(1, 0), &value); break; case ARMV8_SPSR_EL2: /* mapped to SPSR_hyp */ retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS_xPSR_T1(1, 0), &value); break; case ARMV8_SPSR_EL3: /* mapped to SPSR_mon */ retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS_xPSR_T1(1, 0), &value); break; default: retval = ERROR_FAIL; break; } if (retval == ERROR_OK && regval != NULL) *regval = value; return retval; }