From b69750fd0ded4ee19861673106761627d88734e4 Mon Sep 17 00:00:00 2001 From: Matthias Welwarsky Date: Thu, 22 Sep 2016 21:29:42 +0200 Subject: [PATCH] aarch64: armv8 cache functions update Update cache identification to match functionality present in armv7a_cache.c Change-Id: I2dc4bee80f5a22b8728334d40331c183d1406f27 Signed-off-by: Matthias Welwarsky --- src/target/aarch64.c | 6 +- src/target/armv8.c | 301 +++++-------------------------------- src/target/armv8.h | 17 ++- src/target/armv8_cache.c | 299 +++++++++++++++++++++++++++++++++++- src/target/armv8_opcodes.h | 1 + 5 files changed, 353 insertions(+), 271 deletions(-) diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 1d2abc70..05abe6b7 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -735,8 +735,10 @@ static int aarch64_post_debug_entry(struct target *target) LOG_DEBUG("System_register: %8.8" PRIx32, aarch64->system_control_reg); aarch64->system_control_reg_curr = aarch64->system_control_reg; - if (armv8->armv8_mmu.armv8_cache.ctype == -1) - armv8_identify_cache(target); + if (armv8->armv8_mmu.armv8_cache.info == -1) { + armv8_identify_cache(armv8); + armv8_read_mpidr(armv8); + } armv8->armv8_mmu.mmu_enabled = (aarch64->system_control_reg & 0x1U) ? 1 : 0; diff --git a/src/target/armv8.c b/src/target/armv8.c index 306a06e7..467c7716 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -37,6 +37,8 @@ #include "target.h" #include "target_type.h" +#define __unused __attribute__((unused)) + static const char * const armv8_state_strings[] = { "AArch32", "Thumb", "Jazelle", "ThumbEE", "AArch64", }; @@ -208,6 +210,38 @@ static int armv8_write_core_reg(struct target *target, struct reg *r, return ERROR_OK; } #endif + +/* retrieve core id cluster id */ +int armv8_read_mpidr(struct armv8_common *armv8) +{ + int retval = ERROR_FAIL; + struct arm_dpm *dpm = armv8->arm.dpm; + uint32_t mpidr; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr); + if (retval != ERROR_OK) + goto done; + if (mpidr & 1<<31) { + armv8->multi_processor_system = (mpidr >> 30) & 1; + armv8->cluster_id = (mpidr >> 8) & 0xf; + armv8->cpu_id = mpidr & 0x3; + LOG_INFO("%s cluster %x core %x %s", target_name(armv8->arm.target), + armv8->cluster_id, + armv8->cpu_id, + armv8->multi_processor_system == 0 ? "multi core" : "mono core"); + + } else + LOG_ERROR("mpdir not in multiprocessor format"); + +done: + dpm->finish(dpm); + return retval; +} + /** * Configures host-side ARM records to reflect the specified CPSR. * Later, code can use arm_reg_current() to map register numbers @@ -368,7 +402,7 @@ static uint8_t armv8_pa_size(uint32_t ps) return ret; } -static int armv8_read_ttbcr32(struct target *target) +static __unused int armv8_read_ttbcr32(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); struct arm_dpm *dpm = armv8->arm.dpm; @@ -528,103 +562,10 @@ int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va, return ERROR_OK; } -static int armv8_handle_inner_cache_info_command(struct command_context *cmd_ctx, - struct armv8_cache_common *armv8_cache) -{ - if (armv8_cache->ctype == -1) { - command_print(cmd_ctx, "cache not yet identified"); - return ERROR_OK; - } - - command_print(cmd_ctx, - "D-Cache: linelen %" PRIi32 ", associativity %" PRIi32 ", nsets %" PRIi32 ", cachesize %" PRId32 " KBytes", - armv8_cache->d_u_size.linelen, - armv8_cache->d_u_size.associativity, - armv8_cache->d_u_size.nsets, - armv8_cache->d_u_size.cachesize); - - command_print(cmd_ctx, - "I-Cache: linelen %" PRIi32 ", associativity %" PRIi32 ", nsets %" PRIi32 ", cachesize %" PRId32 " KBytes", - armv8_cache->i_size.linelen, - armv8_cache->i_size.associativity, - armv8_cache->i_size.nsets, - armv8_cache->i_size.cachesize); - - return ERROR_OK; -} - -static int _armv8_flush_all_data(struct target *target) -{ - struct armv8_common *armv8 = target_to_armv8(target); - struct arm_dpm *dpm = armv8->arm.dpm; - struct armv8_cachesize *d_u_size = - &(armv8->armv8_mmu.armv8_cache.d_u_size); - int32_t c_way, c_index = d_u_size->index; - int retval; - /* check that cache data is on at target halt */ - if (!armv8->armv8_mmu.armv8_cache.d_u_cache_enabled) { - LOG_INFO("flushed not performed :cache not on at target halt"); - return ERROR_OK; - } - retval = dpm->prepare(dpm); - if (retval != ERROR_OK) - goto done; - do { - c_way = d_u_size->way; - do { - uint32_t value = (c_index << d_u_size->index_shift) - | (c_way << d_u_size->way_shift); - /* DCCISW */ - /* LOG_INFO ("%d %d %x",c_way,c_index,value); */ - retval = dpm->instr_write_data_r0(dpm, - ARMV8_MSR_GP(SYSTEM_DCCISW, 0), - value); - if (retval != ERROR_OK) - goto done; - c_way -= 1; - } while (c_way >= 0); - c_index -= 1; - } while (c_index >= 0); - return retval; -done: - LOG_ERROR("flushed failed"); - dpm->finish(dpm); - return retval; -} - -static int armv8_flush_all_data(struct target *target) -{ - int retval = ERROR_FAIL; - /* check that armv8_cache is correctly identify */ - struct armv8_common *armv8 = target_to_armv8(target); - if (armv8->armv8_mmu.armv8_cache.ctype == -1) { - LOG_ERROR("trying to flush un-identified cache"); - return retval; - } - - if (target->smp) { - /* look if all the other target have been flushed in order to flush level - * 2 */ - struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; - if (curr->state == TARGET_HALTED) { - LOG_INFO("Wait flushing data l1 on core %" PRId32, curr->coreid); - retval = _armv8_flush_all_data(curr); - } - head = head->next; - } - } else - retval = _armv8_flush_all_data(target); - return retval; -} - int armv8_handle_cache_info_command(struct command_context *cmd_ctx, struct armv8_cache_common *armv8_cache) { - if (armv8_cache->ctype == -1) { + if (armv8_cache->info == -1) { command_print(cmd_ctx, "cache not yet identified"); return ERROR_OK; } @@ -634,174 +575,6 @@ int armv8_handle_cache_info_command(struct command_context *cmd_ctx, return ERROR_OK; } -/* retrieve core id cluster id */ -static int armv8_read_mpidr(struct target *target) -{ - int retval = ERROR_FAIL; - struct armv8_common *armv8 = target_to_armv8(target); - struct arm_dpm *dpm = armv8->arm.dpm; - uint32_t mpidr; - - retval = dpm->prepare(dpm); - if (retval != ERROR_OK) - goto done; - /* MRC p15,0,,c0,c0,5; read Multiprocessor ID register*/ - - retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr); - if (retval != ERROR_OK) - goto done; - if (mpidr & 1<<31) { - armv8->multi_processor_system = (mpidr >> 30) & 1; - armv8->cluster_id = (mpidr >> 8) & 0xf; - armv8->cpu_id = mpidr & 0x3; - LOG_INFO("%s cluster %x core %x %s", target_name(target), - armv8->cluster_id, - armv8->cpu_id, - armv8->multi_processor_system == 0 ? "multi core" : "mono core"); - - } else - LOG_ERROR("mpdir not in multiprocessor format"); - -done: - dpm->finish(dpm); - return retval; - - -} - -int armv8_identify_cache(struct target *target) -{ - /* read cache descriptor */ - int retval = ERROR_FAIL; - struct armv8_common *armv8 = target_to_armv8(target); - struct arm_dpm *dpm = armv8->arm.dpm; - uint32_t cache_selected, clidr; - uint32_t cache_i_reg, cache_d_reg; - struct armv8_cache_common *cache = &(armv8->armv8_mmu.armv8_cache); - int is_aarch64 = armv8->arm.core_state == ARM_STATE_AARCH64; - - retval = is_aarch64 ? armv8_read_ttbcr(target) : armv8_read_ttbcr32(target); - if (retval != ERROR_OK) - return retval; - - retval = dpm->prepare(dpm); - if (retval != ERROR_OK) - goto done; - - /* retrieve CLIDR */ - retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_CLIDR), &clidr); - if (retval != ERROR_OK) - goto done; - - clidr = (clidr & 0x7000000) >> 23; - LOG_INFO("number of cache level %" PRIx32, (uint32_t)(clidr / 2)); - if ((clidr / 2) > 1) { - /* FIXME not supported present in cortex A8 and later */ - /* in cortex A7, A15 */ - LOG_ERROR("cache l2 present :not supported"); - } - /* retrieve selected cache*/ - retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_CSSELR), &cache_selected); - if (retval != ERROR_OK) - goto done; - - /* select instruction cache - * [0] : 1 instruction cache selection , 0 data cache selection */ - retval = dpm->instr_write_data_r0(dpm, armv8_opcode(armv8, WRITE_REG_CSSELR), 1); - if (retval != ERROR_OK) - goto done; - - /* read CCSIDR - * MRC P15,1,,C0, C0,0 ;on cortex A9 read CCSIDR - * [2:0] line size 001 eight word per line - * [27:13] NumSet 0x7f 16KB, 0xff 32Kbytes, 0x1ff 64Kbytes */ - retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_CCSIDR), &cache_i_reg); - if (retval != ERROR_OK) - goto done; - - /* select data cache*/ - retval = dpm->instr_write_data_r0(dpm, armv8_opcode(armv8, WRITE_REG_CSSELR), 0); - if (retval != ERROR_OK) - goto done; - - retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_CCSIDR), &cache_d_reg); - if (retval != ERROR_OK) - goto done; - - /* restore selected cache */ - dpm->instr_write_data_r0(dpm, armv8_opcode(armv8, WRITE_REG_CSSELR), cache_selected); - if (retval != ERROR_OK) - goto done; - dpm->finish(dpm); - - /* put fake type */ - cache->d_u_size.linelen = 16 << (cache_d_reg & 0x7); - cache->d_u_size.cachesize = (((cache_d_reg >> 13) & 0x7fff)+1)/8; - cache->d_u_size.nsets = (cache_d_reg >> 13) & 0x7fff; - cache->d_u_size.associativity = ((cache_d_reg >> 3) & 0x3ff) + 1; - /* compute info for set way operation on cache */ - cache->d_u_size.index_shift = (cache_d_reg & 0x7) + 4; - cache->d_u_size.index = (cache_d_reg >> 13) & 0x7fff; - cache->d_u_size.way = ((cache_d_reg >> 3) & 0x3ff); - cache->d_u_size.way_shift = cache->d_u_size.way + 1; - { - int i = 0; - while (((cache->d_u_size.way_shift >> i) & 1) != 1) - i++; - cache->d_u_size.way_shift = 32-i; - } -#if 0 - LOG_INFO("data cache index %d << %d, way %d << %d", - cache->d_u_size.index, cache->d_u_size.index_shift, - cache->d_u_size.way, - cache->d_u_size.way_shift); - - LOG_INFO("data cache %d bytes %d KBytes asso %d ways", - cache->d_u_size.linelen, - cache->d_u_size.cachesize, - cache->d_u_size.associativity); -#endif - cache->i_size.linelen = 16 << (cache_i_reg & 0x7); - cache->i_size.associativity = ((cache_i_reg >> 3) & 0x3ff) + 1; - cache->i_size.nsets = (cache_i_reg >> 13) & 0x7fff; - cache->i_size.cachesize = (((cache_i_reg >> 13) & 0x7fff)+1)/8; - /* compute info for set way operation on cache */ - cache->i_size.index_shift = (cache_i_reg & 0x7) + 4; - cache->i_size.index = (cache_i_reg >> 13) & 0x7fff; - cache->i_size.way = ((cache_i_reg >> 3) & 0x3ff); - cache->i_size.way_shift = cache->i_size.way + 1; - { - int i = 0; - while (((cache->i_size.way_shift >> i) & 1) != 1) - i++; - cache->i_size.way_shift = 32-i; - } -#if 0 - LOG_INFO("instruction cache index %d << %d, way %d << %d", - cache->i_size.index, cache->i_size.index_shift, - cache->i_size.way, cache->i_size.way_shift); - - LOG_INFO("instruction cache %d bytes %d KBytes asso %d ways", - cache->i_size.linelen, - cache->i_size.cachesize, - cache->i_size.associativity); -#endif - /* if no l2 cache initialize l1 data cache flush function function */ - if (armv8->armv8_mmu.armv8_cache.flush_all_data_cache == NULL) { - armv8->armv8_mmu.armv8_cache.display_cache_info = - armv8_handle_inner_cache_info_command; - armv8->armv8_mmu.armv8_cache.flush_all_data_cache = - armv8_flush_all_data; - } - armv8->armv8_mmu.armv8_cache.ctype = 0; - -done: - dpm->finish(dpm); - armv8_read_mpidr(target); - return retval; - -} - int armv8_init_arch_info(struct target *target, struct armv8_common *armv8) { struct arm *arm = &armv8->arm; @@ -818,7 +591,7 @@ int armv8_init_arch_info(struct target *target, struct armv8_common *armv8) #endif armv8->armv8_mmu.armv8_cache.l2_cache = NULL; - armv8->armv8_mmu.armv8_cache.ctype = -1; + armv8->armv8_mmu.armv8_cache.info = -1; armv8->armv8_mmu.armv8_cache.flush_all_data_cache = NULL; armv8->armv8_mmu.armv8_cache.display_cache_info = NULL; return ERROR_OK; diff --git a/src/target/armv8.h b/src/target/armv8.h index fa3674b1..2862ebd8 100644 --- a/src/target/armv8.h +++ b/src/target/armv8.h @@ -97,12 +97,22 @@ struct armv8_cachesize { uint32_t way_shift; }; -struct armv8_cache_common { - int ctype; +/* information about one architecture cache at any level */ +struct armv8_arch_cache { + int ctype; /* cache type, CLIDR encoding */ struct armv8_cachesize d_u_size; /* data cache */ struct armv8_cachesize i_size; /* instruction cache */ +}; + +struct armv8_cache_common { + int info; + int loc; + uint32_t iminline; + uint32_t dminline; + struct armv8_arch_cache arch[6]; /* cache info, L1 - L7 */ int i_cache_enabled; int d_u_cache_enabled; + /* l2 external unified cache if some */ void *l2_cache; int (*flush_all_data_cache)(struct target *target); @@ -249,7 +259,8 @@ target_to_armv8(struct target *target) #define PAGE_SIZE_4KB_TRBBASE_MASK 0xFFFFFFFFF000 int armv8_arch_state(struct target *target); -int armv8_identify_cache(struct target *target); +int armv8_read_mpidr(struct armv8_common *armv8); +int armv8_identify_cache(struct armv8_common *armv8); int armv8_init_arch_info(struct target *target, struct armv8_common *armv8); int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va, target_addr_t *val, int meminfo); diff --git a/src/target/armv8_cache.c b/src/target/armv8_cache.c index fb188046..f496c3cf 100644 --- a/src/target/armv8_cache.c +++ b/src/target/armv8_cache.c @@ -24,6 +24,11 @@ #include "armv8_dpm.h" #include "armv8_opcodes.h" +/* CLIDR cache types */ +#define CACHE_LEVEL_HAS_UNIFIED_CACHE 0x4 +#define CACHE_LEVEL_HAS_D_CACHE 0x2 +#define CACHE_LEVEL_HAS_I_CACHE 0x1 + static int armv8_d_cache_sanity_check(struct armv8_common *armv8) { struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache; @@ -44,11 +49,72 @@ static int armv8_i_cache_sanity_check(struct armv8_common *armv8) return ERROR_TARGET_INVALID; } +static int armv8_cache_d_inner_flush_level(struct arm_dpm *dpm, struct armv8_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); + /* + * DC CISW - Clean and invalidate data cache + * line by Set/Way. + */ + retval = dpm->instr_write_data_r0(dpm, + ARMV8_SYS(SYSTEM_DCCISW, 0), value); + if (retval != ERROR_OK) + goto done; + c_way -= 1; + } while (c_way >= 0); + c_index -= 1; + } while (c_index >= 0); + + done: + return retval; +} + +static int armv8_cache_d_inner_clean_inval_all(struct armv8_common *armv8) +{ + struct armv8_cache_common *cache = &(armv8->armv8_mmu.armv8_cache); + struct arm_dpm *dpm = armv8->arm.dpm; + int cl; + int retval; + + retval = armv8_d_cache_sanity_check(armv8); + if (retval != ERROR_OK) + return retval; + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + for (cl = 0; cl < cache->loc; cl++) { + /* skip i-only caches */ + if (cache->arch[cl].ctype < CACHE_LEVEL_HAS_D_CACHE) + continue; + + armv8_cache_d_inner_flush_level(dpm, &cache->arch[cl].d_u_size, cl); + } + + retval = dpm->finish(dpm); + return retval; + +done: + LOG_ERROR("clean invalidate failed"); + dpm->finish(dpm); + + return retval; +} + int armv8_cache_d_inner_flush_virt(struct armv8_common *armv8, target_addr_t va, size_t size) { struct arm_dpm *dpm = armv8->arm.dpm; struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache; - uint64_t linelen = armv8_cache->d_u_size.linelen; + uint64_t linelen = armv8_cache->dminline; target_addr_t va_line, va_end; int retval; @@ -87,7 +153,7 @@ int armv8_cache_i_inner_inval_virt(struct armv8_common *armv8, target_addr_t va, { struct arm_dpm *dpm = armv8->arm.dpm; struct armv8_cache_common *armv8_cache = &armv8->armv8_mmu.armv8_cache; - uint64_t linelen = armv8_cache->i_size.linelen; + uint64_t linelen = armv8_cache->iminline; target_addr_t va_line, va_end; int retval; @@ -120,3 +186,232 @@ done: return retval; } + +static int armv8_handle_inner_cache_info_command(struct command_context *cmd_ctx, + struct armv8_cache_common *armv8_cache) +{ + int cl; + + if (armv8_cache->info == -1) { + command_print(cmd_ctx, "cache not yet identified"); + return ERROR_OK; + } + + for (cl = 0; cl < armv8_cache->loc; cl++) { + struct armv8_arch_cache *arch = &(armv8_cache->arch[cl]); + + if (arch->ctype & 1) { + command_print(cmd_ctx, + "L%d I-Cache: linelen %" PRIi32 + ", associativity %" PRIi32 + ", nsets %" PRIi32 + ", cachesize %" PRId32 " KBytes", + cl+1, + arch->i_size.linelen, + arch->i_size.associativity, + arch->i_size.nsets, + arch->i_size.cachesize); + } + + if (arch->ctype >= 2) { + command_print(cmd_ctx, + "L%d D-Cache: linelen %" PRIi32 + ", associativity %" PRIi32 + ", nsets %" PRIi32 + ", cachesize %" PRId32 " KBytes", + cl+1, + arch->d_u_size.linelen, + arch->d_u_size.associativity, + arch->d_u_size.nsets, + arch->d_u_size.cachesize); + } + } + + return ERROR_OK; +} + +static int _armv8_flush_all_data(struct target *target) +{ + return armv8_cache_d_inner_clean_inval_all(target_to_armv8(target)); +} + +static int armv8_flush_all_data(struct target *target) +{ + int retval = ERROR_FAIL; + /* check that armv8_cache is correctly identify */ + struct armv8_common *armv8 = target_to_armv8(target); + if (armv8->armv8_mmu.armv8_cache.info == -1) { + LOG_ERROR("trying to flush un-identified cache"); + return retval; + } + + if (target->smp) { + /* look if all the other target have been flushed in order to flush level + * 2 */ + struct target_list *head; + struct target *curr; + head = target->head; + while (head != (struct target_list *)NULL) { + curr = head->target; + if (curr->state == TARGET_HALTED) { + LOG_INFO("Wait flushing data l1 on core %" PRId32, curr->coreid); + retval = _armv8_flush_all_data(curr); + } + head = head->next; + } + } else + retval = _armv8_flush_all_data(target); + return retval; +} + +static int get_cache_info(struct arm_dpm *dpm, int cl, int ct, uint32_t *cache_reg) +{ + int retval = ERROR_OK; + + /* select cache level */ + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP(SYSTEM_CSSELR, 0), + (cl << 1) | (ct == 1 ? 1 : 0)); + if (retval != ERROR_OK) + goto done; + + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_CCSIDR, 0), + cache_reg); + done: + return retval; +} + +static struct armv8_cachesize decode_cache_reg(uint32_t cache_reg) +{ + struct armv8_cachesize size; + int i = 0; + + size.linelen = 16 << (cache_reg & 0x7); + size.associativity = ((cache_reg >> 3) & 0x3ff) + 1; + size.nsets = ((cache_reg >> 13) & 0x7fff) + 1; + size.cachesize = size.linelen * size.associativity * size.nsets / 1024; + + /* compute info for set way operation on cache */ + size.index_shift = (cache_reg & 0x7) + 4; + size.index = (cache_reg >> 13) & 0x7fff; + size.way = ((cache_reg >> 3) & 0x3ff); + + while (((size.way << i) & 0x80000000) == 0) + i++; + size.way_shift = i; + + return size; +} + +int armv8_identify_cache(struct armv8_common *armv8) +{ + /* read cache descriptor */ + int retval = ERROR_FAIL; + struct arm_dpm *dpm = armv8->arm.dpm; + uint32_t csselr, clidr, ctr; + uint32_t cache_reg; + int cl, ctype; + struct armv8_cache_common *cache = &(armv8->armv8_mmu.armv8_cache); + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + /* retrieve CTR */ + retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_CTR, 0), &ctr); + if (retval != ERROR_OK) + goto done; + + cache->iminline = 4UL << (ctr & 0xf); + cache->dminline = 4UL << ((ctr & 0xf0000) >> 16); + LOG_DEBUG("ctr %" PRIx32 " ctr.iminline %" PRId32 " ctr.dminline %" PRId32, + ctr, cache->iminline, cache->dminline); + + /* retrieve CLIDR */ + retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_CLIDR, 0), &clidr); + if (retval != ERROR_OK) + goto done; + + cache->loc = (clidr & 0x7000000) >> 24; + LOG_DEBUG("Number of cache levels to PoC %" PRId32, cache->loc); + + /* retrieve selected cache for later restore + * MRC p15, 2,, c0, c0, 0; Read CSSELR */ + retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_CSSELR, 0), &csselr); + if (retval != ERROR_OK) + goto done; + + /* retrieve all available inner caches */ + for (cl = 0; cl < cache->loc; clidr >>= 3, cl++) { + + /* isolate cache type at current level */ + ctype = clidr & 7; + + /* skip reserved values */ + if (ctype > CACHE_LEVEL_HAS_UNIFIED_CACHE) + continue; + + /* separate d or unified d/i cache at this level ? */ + if (ctype & (CACHE_LEVEL_HAS_UNIFIED_CACHE | CACHE_LEVEL_HAS_D_CACHE)) { + /* retrieve d-cache info */ + retval = get_cache_info(dpm, cl, 0, &cache_reg); + if (retval != ERROR_OK) + goto done; + cache->arch[cl].d_u_size = decode_cache_reg(cache_reg); + + LOG_DEBUG("data/unified cache index %d << %d, way %d << %d", + cache->arch[cl].d_u_size.index, + cache->arch[cl].d_u_size.index_shift, + cache->arch[cl].d_u_size.way, + cache->arch[cl].d_u_size.way_shift); + + LOG_DEBUG("cacheline %d bytes %d KBytes asso %d ways", + cache->arch[cl].d_u_size.linelen, + cache->arch[cl].d_u_size.cachesize, + cache->arch[cl].d_u_size.associativity); + } + + /* separate i-cache at this level ? */ + if (ctype & CACHE_LEVEL_HAS_I_CACHE) { + /* retrieve i-cache info */ + retval = get_cache_info(dpm, cl, 1, &cache_reg); + if (retval != ERROR_OK) + goto done; + cache->arch[cl].i_size = decode_cache_reg(cache_reg); + + LOG_DEBUG("instruction cache index %d << %d, way %d << %d", + cache->arch[cl].i_size.index, + cache->arch[cl].i_size.index_shift, + cache->arch[cl].i_size.way, + cache->arch[cl].i_size.way_shift); + + LOG_DEBUG("cacheline %d bytes %d KBytes asso %d ways", + cache->arch[cl].i_size.linelen, + cache->arch[cl].i_size.cachesize, + cache->arch[cl].i_size.associativity); + } + + cache->arch[cl].ctype = ctype; + } + + /* restore selected cache */ + dpm->instr_write_data_r0(dpm, ARMV8_MSR_GP(SYSTEM_CSSELR, 0), csselr); + if (retval != ERROR_OK) + goto done; + + armv8->armv8_mmu.armv8_cache.info = 1; + + /* if no l2 cache initialize l1 data cache flush function function */ + if (armv8->armv8_mmu.armv8_cache.flush_all_data_cache == NULL) { + armv8->armv8_mmu.armv8_cache.display_cache_info = + armv8_handle_inner_cache_info_command; + armv8->armv8_mmu.armv8_cache.flush_all_data_cache = + armv8_flush_all_data; + } + +done: + dpm->finish(dpm); + return retval; + +} diff --git a/src/target/armv8_opcodes.h b/src/target/armv8_opcodes.h index 9f5ebf8d..51dc15a5 100644 --- a/src/target/armv8_opcodes.h +++ b/src/target/armv8_opcodes.h @@ -77,6 +77,7 @@ #define SYSTEM_CLIDR 0b1100100000000001 #define SYSTEM_CSSELR 0b1101000000000000 #define SYSTEM_CTYPE 0b1101100000000001 +#define SYSTEM_CTR 0b1101100000000001 #define SYSTEM_DCCISW 0b0100001111110010 #define SYSTEM_DCCSW 0b0100001111010010 -- 2.39.5