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/+/7874

-- gerrit

commit 237268e2b7ab3406575f09b441ccbfee5f1d4d28
Author: Walter Ji <walter...@oss.cipunited.com>
Date:   Mon Aug 28 16:24:17 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.
    Checkpatch-ignore: CAMELCASE
    
    Change-Id: Ib019e05cc66aeced99026f6e95a85f728e5a2058
    Signed-off-by: Walter Ji <walter...@oss.cipunited.com>

diff --git a/src/target/mips32.c b/src/target/mips32.c
index ad7071683c..689626d2c0 100644
--- a/src/target/mips32.c
+++ b/src/target/mips32.c
@@ -234,6 +234,18 @@ static uint32_t  ftlb_sets[16] = {1, 2, 4, 8,      16, 32, 
64, 128,        256, 0, 0, 0,   0,
 #define L2             5
 
 
+static const struct {
+       unsigned int option;
+       const char *arg;
+} invalidate_cmd[5] = {
+       { ALL, "all", },
+       { INST, "inst", },
+       { DATA, "data", },
+       { ALLNOWB, "allnowb", },
+       { DATANOWB, "datanowb", },
+};
+
+
 static int mips32_get_core_reg(struct reg *reg)
 {
        int retval;
@@ -1768,6 +1780,449 @@ exit:
        pracc_queue_free(&ctx);
        return ctx.retval;
 }
+
+
+
+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_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) {
+                               // Writes back when invalidating data cache
+                               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_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 {
+                       // Get number of TLB entries from config1
+                       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;
+}
+
 COMMAND_HANDLER(mips32_handle_cpuinfo_command)
 {
        int retval;
@@ -1842,6 +2297,28 @@ COMMAND_HANDLER(mips32_handle_cpuinfo_command)
        info.vzase = (config3 & (1 << 23)) ? 1 : 0;                     /* VZ */
        LOG_USER("VZ Module: %d", info.vzase);
 
+       /* Check if Virtualization supported */
+       /* TODO List */
+       if (info.vzase) {
+               /* Core supports Virtualization - now get Guest Info */
+               uint32_t width;
+               uint32_t guestCtl0;
+
+               retval = mips32_cp0_read(ejtag_info, &guestCtl0, 12, 6);
+               if (retval  != ERROR_OK)
+                       return retval;
+
+               info.guest_ctl1_present = (guestCtl0 >> 22) & 0x1;
+
+               retval = mips32_determine_guestid_width(ejtag_info, &width);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               info.vz_guest_id_width = width;
+
+               LOG_USER("guest ID width: %d", info.vz_guest_id_width);
+       }
+
 
        /* MIPS SIMD Architecture (MSA) */
        info.msa = (config3 & 0x10000000) ? 1 : 0;
@@ -2591,6 +3068,27 @@ static const struct command_registration 
mips32_exec_command_handlers[] = {
                .help = "read ejtag registers",
                .usage = "",
        },
+       {
+               .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 = "dump_tlb",
+               .handler = mips32_handle_dump_tlb_command,
+               .mode = COMMAND_ANY,
+               .help = "dump_tlb",
+               .usage = "[entry]",
+       },
+       {
+               .name = "guest_id",
+               .handler = mips32_handle_guest_id,
+               .mode = COMMAND_ANY,
+               .help = "Display the current guest ID.",
+               .usage = "",
+       },
        COMMAND_REGISTRATION_DONE
 };
 

-- 

Reply via email to