This is an automated email from Gerrit. "Walter Ji <walter...@oss.cipunited.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/7868
-- gerrit commit ba7baab78ca4f1d2c9ca6464f7eb3a9a07ff66fc Author: Walter Ji <walter...@oss.cipunited.com> Date: Fri Aug 25 18:36:57 2023 +0800 target/mips32: add cache, tlb and guest(vz) related operation Add cache invalidate function and its command. Add dump tlb function and its monitor command. Add virtualisation/guest related function and its command. Fix checkpatch warnings. Change-Id: I3e49343f9d1b49f9383cdbc871420acc990271f9 Signed-off-by: Walter Ji <walter...@oss.cipunited.com> diff --git a/src/target/mips32.c b/src/target/mips32.c index 2fa3ce1e9b..ad697b1e47 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -1259,6 +1259,14 @@ int mips32_read_config_regs(struct target *target) return retval; } + if ((((dcr > 18) & 0x1) == 1) && ((ejtag_info->config[3] & 0x00000008) != 0)) { + mips32->fdc = 1; + mips32->semihosting = 1; + } else { + mips32->fdc = 0; + mips32->semihosting = 0; + } + uint32_t prid; retval = mips32_cp0_read(ejtag_info, &prid, 15, 0); if (retval != ERROR_OK) { @@ -1507,6 +1515,9 @@ COMMAND_HANDLER(mips32_handle_cp0_command) if (strcmp(mips32_cp0_regs[i].name, CMD_ARGV[0]) == 0) { retval = mips32_cp0_read(ejtag_info, &value, mips32_cp0_regs[i].reg, mips32_cp0_regs[i].sel); command_print(CMD, "0x%8.8x", value); + if (retval != ERROR_OK) + LOG_INFO("Encounter an Error while reading cp0 reg %d sel %d", + mips32_cp0_regs[i].reg, mips32_cp0_regs[i].sel); return ERROR_OK; } } else /* Register name not valid for this core */ @@ -1549,11 +1560,17 @@ COMMAND_HANDLER(mips32_handle_cp0_command) mips32->core_cache->reg_list[MIPS32_REGLIST_C0_GUESTCTL1_INDEX].dirty = 1; } - retval = mips32_cp0_write(ejtag_info, value, mips32_cp0_regs[i].reg, mips32_cp0_regs[i].sel); + retval = mips32_cp0_write(ejtag_info, value, + mips32_cp0_regs[i].reg, + mips32_cp0_regs[i].sel); + if (retval != ERROR_OK) + LOG_INFO("Encounter an Error while writing to cp0 reg %d, sel %d", + mips32_cp0_regs[i].reg, mips32_cp0_regs[i].sel); return ERROR_OK; } - } else /* Register name not valid for this core */ - continue; + } + /* Register name not valid for this core */ + continue; } LOG_ERROR("BUG: register '%s' not found", CMD_ARGV[0]); @@ -1616,6 +1633,52 @@ COMMAND_HANDLER(mips32_handle_cp0_command) return ERROR_OK; } +int mips32_pracc_read_tlb_entry(struct mips_ejtag *ejtag_info, uint32_t *data, uint32_t index) +{ + int isa = 0; + + struct pracc_queue_info ctx = { + .max_code = 49, + .ejtag_info = ejtag_info + }; + + pracc_queue_init(&ctx); + if (ctx.retval != ERROR_OK) + goto exit; + + int tlb_read_code[] = { + MIPS32_MFC0(isa, 8, 2, 0), /* Read MIPS32_C0_ENTRYLO0 */ + MIPS32_MFC0(isa, 8, 3, 0), /* Read MIPS32_C0_ENTRYLO1 */ + MIPS32_MFC0(isa, 8, 10, 0), /* Read MIPS32_C0_ENTRYHI */ + MIPS32_MFC0(isa, 8, 5, 0) /* Read MIPS32_C0_PAGEMASK */ + }; + + pracc_add(&ctx, 0, MIPS32_LUI(isa, 15, PRACC_UPPER_BASE_ADDR)); /* $15 = MIP32_PRACC_BASE_ADDR */ + pracc_add(&ctx, 0, MIPS32_LUI(isa, 8, UPPER16(index))); /* Load TLB Index to $8 */ + pracc_add(&ctx, 0, MIPS32_ORI(isa, 8, 8, LOWER16(index))); + + pracc_add(&ctx, 0, MIPS32_MTC0(isa, 8, 0, 0)); /* write MIPS32_C0_Index */ + pracc_add(&ctx, 0, MIPS32_ISA_TLBR()); /* Read TLB entry specified by Index */ + + + for (uint32_t i = 0; i < ARRAY_SIZE(tlb_read_code); i++) { + pracc_add(&ctx, 0, tlb_read_code[i]); + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + (i * 4), + MIPS32_SW(isa, 8, PRACC_OUT_OFFSET + (i * 4), 15)); + } + + pracc_add(&ctx, 0, MIPS32_LUI(isa, 8, UPPER16(ejtag_info->reg8))); /* restore upper 16 of $8 */ + pracc_add(&ctx, 0, MIPS32_ORI(isa, 8, 8, LOWER16(ejtag_info->reg8))); /* restore lower 16 of $8 */ + + pracc_add(&ctx, 0, MIPS32_SYNC(isa)); + pracc_add(&ctx, 0, MIPS32_B(isa, NEG16(ctx.code_count + 1))); /* jump to start */ + pracc_add(&ctx, 0, MIPS32_MTC0(isa, 15, 31, 0)); /* load $15 in DeSave */ + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, data, 1); +exit: + pracc_queue_free(&ctx); + return ctx.retval; +} int mips32_pracc_read_dsp_regs(struct mips_ejtag *ejtag_info, uint32_t *val, uint32_t regs) { @@ -1755,6 +1818,238 @@ exit: pracc_queue_free(&ctx); return ctx.retval; } + +int mips32_pracc_invalidate_cache(struct target *target, struct mips_ejtag *ejtag_info, int cache) +{ + int isa = 0; + + uint32_t inv_inst_cache[] = { + + /* Determine how big the I$ is */ + MIPS32_MFC0(isa, t7, 16, 1), /* MIPS32_C0_Config1 */ + MIPS32_ADDIU(isa, t1, t7, zero), + MIPS32_SRL(isa, t1, t7, MIPS32_CFG1_ISSHIFT), + MIPS32_ANDI(isa, t1, t1, 0x7), + MIPS32_ADDIU(isa, t0, zero, 64), /* li t0, 64 */ + MIPS32_SLLV(isa, t1, t0, t1), /* I$ Sets per way */ + + MIPS32_SRL(isa, t7, t7, MIPS32_CFG1_IASHIFT), + MIPS32_ANDI(isa, t7, t7, 0x7), + MIPS32_ADDIU(isa, t7, t7, 1), + MIPS32_MUL(isa, t1, t1, t7), /* Total number of sets */ + + /* Clear TagLo/TagHi registers */ + MIPS32_MTC0(isa, zero, MIPS32_C0_ITAGLO, 0), /* MIPS32_C0_ITagLo */ + MIPS32_MTC0(isa, zero, MIPS32_C0_ITAGHI, 0), /* MIPS32_C0_ITagHi */ + MIPS32_MFC0(isa, t7, 16, 1), /* Re-read MIPS32_C0_Config1 */ + + /* Isolate I$ Line Size */ + MIPS32_ADDIU(isa, t0, zero, 2), /* li a2, 2 */ + MIPS32_SRL(isa, t7, t7, MIPS32_CFG1_ILSHIFT), + MIPS32_ANDI(isa, t7, t7, 0x7), + + MIPS32_SLLV(isa, t7, t0, t7), /* Now have true I$ line size in bytes */ + MIPS32_LUI(isa, t0, 0x8000), /* Get a KSeg0 address for cacheops */ + + MIPS32_CACHE(isa, Index_Store_Tag_I, 0, t0), + MIPS32_ADDI(isa, t1, t1, NEG16(1)), /* Decrement set counter */ + MIPS32_BNE(isa, t1, zero, NEG16(3)), + MIPS32_ISA_ADD(t0, t0, t7), + }; + + uint32_t inv_data_cache[] = { + + MIPS32_MFC0(isa, t7, 16, 1), /* read MIPS32_C0_Config1 */ + + MIPS32_SRL(isa, t1, t7, MIPS32_CFG1_DSSHIFT), /* extract DS */ + MIPS32_ANDI(isa, t1, t1, 0x7), + MIPS32_ADDIU(isa, t0, zero, 64), /* li t0, 64 */ + MIPS32_SLLV(isa, t1, t0, t1), /* D$ Sets per way */ + + MIPS32_SRL(isa, t7, t7, MIPS32_CFG1_DASHIFT), /* extract DA */ + MIPS32_ANDI(isa, t7, t7, 0x7), + MIPS32_ADDIU(isa, t7, t7, 1), + MIPS32_MUL(isa, t1, t1, t7), /* Total number of sets */ + + /* Clear TagLo/TagHi registers */ + MIPS32_MTC0(isa, zero, MIPS32_C0_TAGLO, 0), /* write MIPS32_C0_TagLo */ + MIPS32_MTC0(isa, zero, MIPS32_C0_TAGHI, 0), /* write MIPS32_C0_TagHi */ + MIPS32_MTC0(isa, zero, MIPS32_C0_TAGLO, 2), /* write MIPS32_C0_DTagLo */ + MIPS32_MTC0(isa, zero, MIPS32_C0_TAGHI, 2), /* write MIPS32_C0_DTagHi */ + + /* Isolate D$ Line Size */ + MIPS32_MFC0(isa, t7, 16, 1), /* Re-read MIPS32_C0_Config1 */ + MIPS32_ADDIU(isa, t0, zero, 2), /* li a2, 2 */ + + MIPS32_SRL(isa, t7, t7, MIPS32_CFG1_DLSHIFT), /* extract DL */ + MIPS32_ANDI(isa, t7, t7, 0x7), + + MIPS32_SLLV(isa, t7, t0, t7), /* Now have true I$ line size in bytes */ + + MIPS32_LUI(isa, t0, 0x8000) /* Get a KSeg0 address for cacheops */ + }; + + uint32_t done[] = { + MIPS32_LUI(isa, t7, UPPER16(MIPS32_PRACC_TEXT)), + MIPS32_ORI(isa, t7, t7, LOWER16(MIPS32_PRACC_TEXT)), + MIPS32_JR(isa, t7), /* jr start */ + MIPS32_MFC0(isa, t7, 31, 0) /* move COP0 DeSave to $15 */ + }; + + struct pracc_queue_info ctx = { + .max_code = 26+20, /* alloc memory for the worst case */ + .ejtag_info = ejtag_info + }; + + uint32_t conf; + uint32_t bpl; + + pracc_queue_init(&ctx); + if (ctx.retval != ERROR_OK) { + LOG_ERROR("pracc_queue_init failed"); + goto exit; + } + + /* Read Config1 Register to retrieve cache info */ + mips32_cp0_read(ejtag_info, &conf, 16, 1); + + switch (cache) { + case INST: + /* Extract cache line size */ + bpl = (conf >> MIPS32_CFG1_ILSHIFT) & 7; /* bit 21:19 */ + + /* Core configured with Instruction cache */ + if (bpl == 0) { + LOG_USER("no instructure cache configured"); + ctx.retval = ERROR_OK; + goto exit; + } + + for (unsigned int i = 0; i < ARRAY_SIZE(inv_inst_cache); i++) + pracc_add(&ctx, 0, inv_inst_cache[i]); + + break; + + case DATA: + case ALLNOWB: + case DATANOWB: + /* Extract cache line size */ + bpl = (conf >> MIPS32_CFG1_DLSHIFT) & 7; /* bit 12:10 */ + + /* Core configured with Instruction cache */ + if (bpl == 0) { + LOG_USER("no data cache configured"); + ctx.retval = ERROR_OK; + goto exit; + } + + /* Write exit code */ + for (unsigned int i = 0; i < ARRAY_SIZE(inv_data_cache); i++) + pracc_add(&ctx, 0, inv_data_cache[i]); + + if (cache == DATA) + pracc_add(&ctx, 0, MIPS32_CACHE(isa, Index_Writeback_Inv_D, 0, t0)); + else { + if ((cache == ALLNOWB) || (cache == DATANOWB)) + pracc_add(&ctx, 0, MIPS32_CACHE(isa, Index_Store_Tag_D, 0, t0)); + } + + /* Decrement set counter */ + pracc_add(&ctx, 0, MIPS32_ADDI(isa, t1, t1, NEG16(1))); + pracc_add(&ctx, 0, MIPS32_BNE(isa, t1, zero, NEG16(3))); + pracc_add(&ctx, 0, MIPS32_ISA_ADD(t0, t0, t7)); + break; + + case L2: + break; + + } + + /* Write exit code */ + for (unsigned int i = 0; i < ARRAY_SIZE(done); i++) + pracc_add(&ctx, 0, done[i]); + + /* Start code execution */ + ctx.code_count = 0; /* Disable pracc access verification due BNZ instruction */ + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, NULL, 1); + if (ctx.retval != ERROR_OK) + LOG_DEBUG("mips32_pracc_queue_exec failed - ctx.retval: %d", ctx.retval); + +exit: + pracc_queue_free(&ctx); + return ctx.retval; +} + +static uint32_t mips32_determine_guestid_width(struct mips_ejtag *ejtag_info, uint32_t *width) +{ + /* if GuestCtl1 is implemented { + * save current GuestCtl1 value + * write GuestCtl1, placing all-ones in the ID field + * read GuestCtl1 + * in read value, count the consecutive number of 1 bits (starting from bit position 0) + * restore GuestCtl1 value + * } else width is 0 + */ + + uint32_t err = ERROR_OK; + uint32_t err2 = ERROR_OK; + uint32_t count = 0; + bool guestCtl1Clobbered = false; + uint32_t guestCtl0 = 0; + uint32_t guestCtl1 = 0; + uint32_t tempReg = 0; + + err = mips32_cp0_read(ejtag_info, &guestCtl0, 12, 6); + if (err != ERROR_OK) + goto CLEANUP; + + if (((guestCtl0 >> 22) & 0x1) != 0) { + err = mips32_cp0_read(ejtag_info, &guestCtl1, 10, 4); + if (err != ERROR_OK) + goto CLEANUP; + + + guestCtl1Clobbered = true; + tempReg = guestCtl1; + do { + tempReg = (((tempReg) & ~0xFF) | 0xFF); + } while (0); + + err = mips32_cp0_write(ejtag_info, tempReg, 10, 4); + if (err != ERROR_OK) + goto CLEANUP; + + err = mips32_cp0_read(ejtag_info, &tempReg, 10, 4); + if (err != ERROR_OK) + goto CLEANUP; + + while (count < 8 && (tempReg & 0x1) != 0) { + count++; + tempReg >>= 1; + } + } + +CLEANUP: + if (guestCtl1Clobbered) { + /* restore */ + err2 = mips32_cp0_write(ejtag_info, guestCtl1, 10, 4); + } + *width = count; + return (err != ERROR_OK ? err : err2); +} + +COMMAND_HANDLER(mips32_handle_guest_id) +{ + uint32_t value; + struct target *target = get_current_target(CMD_CTX); + struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + + mips32_cp0_read(ejtag_info, &value, 10, 4); + command_print(CMD, "guest id: %d", value & 0xff); + return ERROR_OK; +} + COMMAND_HANDLER(mips32_handle_cpuinfo_command) { int retval; @@ -2474,6 +2769,166 @@ COMMAND_HANDLER(mips32_handle_dsp_command) return ERROR_OK; } +COMMAND_HANDLER(mips32_handle_invalidate_cache_command) +{ + int retval = -1; + struct target *target = get_current_target(CMD_CTX); + struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + int i = 0; + + static const char * const cache_msg[] = {"all", "instr", "data", "L23", NULL, NULL, NULL}; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if ((CMD_ARGC >= 2) || (CMD_ARGC == 0)) { + LOG_DEBUG("ERROR_COMMAND_SYNTAX_ERROR"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (CMD_ARGC == 1) { + /* PARSE command options - all/inst/data/allnowb/datanowb */ + for (i = 0; i < 5 ; i++) { + if (strcmp(CMD_ARGV[0], invalidate_cmd[i].arg) == 0) { + switch (invalidate_cmd[i].option) { + case ALL: + LOG_INFO("clearing %s cache", cache_msg[1]); + /* For this case - ignore any errors checks, just in case core has no instruction cache */ + mips32_pracc_invalidate_cache(target, ejtag_info, invalidate_cmd[1].option); + + /* TODO: Add L2 code */ + + LOG_INFO("clearing %s cache", cache_msg[2]); + /* For this case - ignore any errors checks, just in case core has no data cache */ + mips32_pracc_invalidate_cache(target, ejtag_info, invalidate_cmd[2].option); + + break; + + case INST: + LOG_INFO("clearing %s cache", cache_msg[invalidate_cmd[i].option]); + retval = mips32_pracc_invalidate_cache(target, ejtag_info, invalidate_cmd[i].option); + if (retval != ERROR_OK) + return retval; + + break; + + case DATA: + LOG_INFO("clearing %s cache", cache_msg[invalidate_cmd[i].option]); + retval = mips32_pracc_invalidate_cache(target, ejtag_info, invalidate_cmd[i].option); + if (retval != ERROR_OK) + return retval; + + break; + + case ALLNOWB: + LOG_INFO("invalidating %s cache", cache_msg[invalidate_cmd[1].option]); + retval = mips32_pracc_invalidate_cache(target, ejtag_info, invalidate_cmd[1].option); + if (retval != ERROR_OK) + return retval; + + /* TODO: Add L2 code */ + + LOG_INFO("invalidating %s cache - no writeback", cache_msg[2]); + retval = mips32_pracc_invalidate_cache(target, ejtag_info, invalidate_cmd[2].option); + if (retval != ERROR_OK) + return retval; + + break; + + case DATANOWB: + LOG_INFO("invalidating %s cache - no writeback", cache_msg[2]); + retval = mips32_pracc_invalidate_cache(target, ejtag_info, invalidate_cmd[i].option); + if (retval != ERROR_OK) + return retval; + break; + + default: + LOG_ERROR("Invalid command argument '%s' not found", CMD_ARGV[0]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (retval == ERROR_FAIL) + return ERROR_FAIL; + break; + } + if (i >= DATANOWB) { + LOG_ERROR("Invalid command argument '%s' not found", CMD_ARGV[0]); + return ERROR_COMMAND_SYNTAX_ERROR; + } + } + } + return ERROR_OK; +} + +COMMAND_HANDLER(mips32_handle_dump_tlb_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct mips32_common *mips32 = target_to_mips32(target); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; + int retval; + + uint32_t data[4]; + + if (target->state != TARGET_HALTED) { + LOG_WARNING("target not halted"); + return ERROR_TARGET_NOT_HALTED; + } + + if (CMD_ARGC >= 2) { + LOG_DEBUG("ERROR_COMMAND_SYNTAX_ERROR"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + uint32_t config; /* cp0 config - 16, 0 */ + uint32_t config1; /* cp0 config1 - 16, 1 */ + + /* Read Config register */ + retval = mips32_cp0_read(ejtag_info, &config, 16, 0); + if (retval != ERROR_OK) + return retval; + + /* Read Config1 register */ + retval = mips32_cp0_read(ejtag_info, &config1, 16, 1); + if (retval != ERROR_OK) + return retval; + + uint32_t mmu_type; + uint32_t tlb_entries; + + mmu_type = (config >> 7) & 7; + if (mmu_type == 0) { + LOG_USER("mmu_type: %d, No TLB configured", mmu_type); + return ERROR_OK; + } + + if ((CMD_ARGC == 0) || (CMD_ARGC == 1)) { + uint32_t i = 0; + + /* Get number of TLB entries */ + if (CMD_ARGC == 1) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], i); + tlb_entries = (((config1 >> 25) & 0x3f)+1); + if (i >= tlb_entries) { + LOG_USER("Invalid TLB entry specified - Valid entry #'s are 0-%d", tlb_entries-1); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + tlb_entries = i+1; + } else + tlb_entries = (((config1 >> 25) & 0x3f)+1); + + LOG_USER("index\t entrylo0\t entrylo1\t entryhi\t pagemask"); + for (; i < tlb_entries; i++) { + mips32_pracc_read_tlb_entry(ejtag_info, &data[0], i); + command_print(CMD, " %d\t0x%8.8x\t0x%8.8x\t0x%8.8x\t0x%8.8x", i, data[0], data[1], data[2], data[3]); + } + + } + return ERROR_OK; +} extern void ejtag_main_print_imp(struct mips_ejtag *ejtag_info); extern int mips_ejtag_get_impcode(struct mips_ejtag *ejtag_info); @@ -2584,6 +3039,13 @@ static const struct command_registration mips32_exec_command_handlers[] = { "with no arguments, displays all registers and their values", .usage = "[register_name] [value]]", }, + { + .name = "invalidate", + .handler = mips32_handle_invalidate_cache_command, + .mode = COMMAND_EXEC, + .help = "Invalidate either or both the instruction and data caches.", + .usage = "all|inst|data|allnowb|datanowb", + }, { .name = "scan_delay", .handler = mips32_handle_scan_delay_command, @@ -2591,6 +3053,13 @@ static const struct command_registration mips32_exec_command_handlers[] = { .help = "display/set scan delay in nano seconds", .usage = "[value]", }, + { + .name = "dump_tlb", + .handler = mips32_handle_dump_tlb_command, + .mode = COMMAND_ANY, + .help = "dump_tlb", + .usage = "[entry]", + }, { .name = "ejtag_reg", .handler = mips32_handle_ejtag_reg_command, @@ -2598,6 +3067,13 @@ static const struct command_registration mips32_exec_command_handlers[] = { .help = "read ejtag registers", .usage = "", }, + { + .name = "guest_id", + .handler = mips32_handle_guest_id, + .mode = COMMAND_ANY, + .help = "Display the current guest ID.", + .usage = "", + }, COMMAND_REGISTRATION_DONE }; --