mips32: add micromips breakpoints support

Breakpoint setting based on length (kind) only.
Added 16bit aligned 32bit software breakpoints
support and same filtering before setting
breakpoint.
Set the required isa bit in hardware breakpoints.
Drop the isa bit in software breakpoints.

Change-Id: I7020f27be16015194b76f385d9b8e5af496d0dfc
Signed-off-by: Salvador Arroyo <sarroyofdez@yahoo.es>
Reviewed-on: http://openocd.zylin.com/4124
Tested-by: jenkins
Reviewed-by: Freddie Chopin <freddie.chopin@gmail.com>
gitignore-build
Salvador Arroyo 2017-05-08 09:44:50 +02:00 committed by Freddie Chopin
parent 4831ce4433
commit b702b16dc2
1 changed files with 106 additions and 47 deletions

View File

@ -631,6 +631,11 @@ static int mips_m4k_set_breakpoint(struct target *target,
comparator_list[bp_num].used = 1;
comparator_list[bp_num].bp_value = breakpoint->address;
if (breakpoint->length != 4) /* make sure isa bit set */
comparator_list[bp_num].bp_value |= 1;
else /* make sure isa bit cleared */
comparator_list[bp_num].bp_value &= ~1;
/* EJTAG 2.0 uses 30bit IBA. First 2 bits are reserved.
* Warning: there is no IB ASID registers in 2.0.
* Do not set it! :) */
@ -648,41 +653,77 @@ static int mips_m4k_set_breakpoint(struct target *target,
bp_num, comparator_list[bp_num].bp_value);
} else if (breakpoint->type == BKPT_SOFT) {
LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id);
if (breakpoint->length == 4) {
uint32_t isa_req = breakpoint->length & 1; /* micro mips request bit */
uint32_t bplength = breakpoint->length & ~1; /* drop micro mips request bit for length */
uint32_t bpaddr = breakpoint->address & ~1; /* drop isa bit from address, if set */
if (bplength == 4) {
uint32_t verify = 0xffffffff;
uint32_t sdbbp32_instr = MIPS32_SDBBP(isa_req);
if (ejtag_info->endianness && isa_req)
sdbbp32_instr = SWAP16(sdbbp32_instr);
retval = target_read_memory(target, breakpoint->address, breakpoint->length, 1,
breakpoint->orig_instr);
if (retval != ERROR_OK)
return retval;
retval = target_write_u32(target, breakpoint->address, MIPS32_SDBBP(ejtag_info->isa));
if ((breakpoint->address & 3) == 0) { /* word alligned */
retval = target_read_memory(target, bpaddr, bplength, 1, breakpoint->orig_instr);
if (retval != ERROR_OK)
return retval;
retval = target_read_u32(target, breakpoint->address, &verify);
retval = target_write_u32(target, bpaddr, sdbbp32_instr);
if (retval != ERROR_OK)
return retval;
if (verify != MIPS32_SDBBP(ejtag_info->isa)) {
LOG_ERROR("Unable to set 32-bit breakpoint at address " TARGET_ADDR_FMT
retval = target_read_u32(target, bpaddr, &verify);
if (retval != ERROR_OK)
return retval;
if (verify != sdbbp32_instr)
verify = 0;
} else { /* 16 bit aligned */
retval = target_read_memory(target, bpaddr, 2, 2, breakpoint->orig_instr);
if (retval != ERROR_OK)
return retval;
uint8_t sdbbp_buf[4];
target_buffer_set_u32(target, sdbbp_buf, sdbbp32_instr);
retval = target_write_memory(target, bpaddr, 2, 2, sdbbp_buf);
if (retval != ERROR_OK)
return retval;
retval = target_read_memory(target, bpaddr, 2, 2, sdbbp_buf);
if (retval != ERROR_OK)
return retval;
if (target_buffer_get_u32(target, sdbbp_buf) != sdbbp32_instr)
verify = 0;
}
if (verify == 0) {
LOG_ERROR("Unable to set 32bit breakpoint at address %08" PRIx64
" - check that memory is read/writable", breakpoint->address);
return ERROR_OK;
}
} else {
uint16_t verify = 0xffff;
retval = target_read_memory(target, breakpoint->address, breakpoint->length, 1,
breakpoint->orig_instr);
if (retval != ERROR_OK)
return retval;
retval = target_write_u16(target, breakpoint->address, MIPS16_SDBBP(ejtag_info->isa));
retval = target_read_memory(target, bpaddr, bplength, 1, breakpoint->orig_instr);
if (retval != ERROR_OK)
return retval;
retval = target_read_u16(target, breakpoint->address, &verify);
retval = target_write_u16(target, bpaddr, MIPS16_SDBBP(isa_req));
if (retval != ERROR_OK)
return retval;
if (verify != MIPS16_SDBBP(ejtag_info->isa)) {
LOG_ERROR("Unable to set 16-bit breakpoint at address " TARGET_ADDR_FMT
retval = target_read_u16(target, bpaddr, &verify);
if (retval != ERROR_OK)
return retval;
if (verify != MIPS16_SDBBP(isa_req)) {
LOG_ERROR("Unable to set 16bit breakpoint at address %08" PRIx64
" - check that memory is read/writable", breakpoint->address);
return ERROR_OK;
}
@ -725,39 +766,50 @@ static int mips_m4k_unset_breakpoint(struct target *target,
} else {
/* restore original instruction (kept in target endianness) */
uint32_t isa_req = breakpoint->length & 1;
uint32_t bplength = breakpoint->length & ~1;
uint8_t current_instr[4];
LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id);
if (breakpoint->length == 4) {
uint32_t current_instr;
if (bplength == 4) {
uint32_t sdbbp32_instr = MIPS32_SDBBP(isa_req);
if (ejtag_info->endianness && isa_req)
sdbbp32_instr = SWAP16(sdbbp32_instr);
if ((breakpoint->address & 3) == 0) { /* 32bit aligned */
/* check that user program has not modified breakpoint instruction */
retval = target_read_memory(target, breakpoint->address, 4, 1,
(uint8_t *)&current_instr);
retval = target_read_memory(target, breakpoint->address, 4, 1, current_instr);
if (retval != ERROR_OK)
return retval;
/**
* target_read_memory() gets us data in _target_ endianess.
* If we want to use this data on the host for comparisons with some macros
* we must first transform it to _host_ endianess using target_buffer_get_u32().
* we must first transform it to _host_ endianess using target_buffer_get_u16().
*/
current_instr = target_buffer_get_u32(target, (uint8_t *)&current_instr);
if (current_instr == MIPS32_SDBBP(ejtag_info->isa)) {
if (sdbbp32_instr == target_buffer_get_u32(target, current_instr)) {
retval = target_write_memory(target, breakpoint->address, 4, 1,
breakpoint->orig_instr);
if (retval != ERROR_OK)
return retval;
}
} else {
uint16_t current_instr;
/* check that user program has not modified breakpoint instruction */
retval = target_read_memory(target, breakpoint->address, 2, 1,
(uint8_t *)&current_instr);
} else { /* 16bit alligned */
retval = target_read_memory(target, breakpoint->address, 2, 2, current_instr);
if (retval != ERROR_OK)
return retval;
current_instr = target_buffer_get_u16(target, (uint8_t *)&current_instr);
if (current_instr == MIPS16_SDBBP(ejtag_info->isa)) {
if (sdbbp32_instr == target_buffer_get_u32(target, current_instr)) {
retval = target_write_memory(target, breakpoint->address, 2, 2,
breakpoint->orig_instr);
if (retval != ERROR_OK)
return retval;
}
}
} else {
/* check that user program has not modified breakpoint instruction */
retval = target_read_memory(target, breakpoint->address, 2, 1, current_instr);
if (retval != ERROR_OK)
return retval;
if (target_buffer_get_u16(target, current_instr) == MIPS16_SDBBP(isa_req)) {
retval = target_write_memory(target, breakpoint->address, 2, 1,
breakpoint->orig_instr);
if (retval != ERROR_OK)
@ -765,6 +817,7 @@ static int mips_m4k_unset_breakpoint(struct target *target,
}
}
}
breakpoint->set = 0;
return ERROR_OK;
@ -774,6 +827,12 @@ static int mips_m4k_add_breakpoint(struct target *target, struct breakpoint *bre
{
struct mips32_common *mips32 = target_to_mips32(target);
if ((breakpoint->length > 5 || breakpoint->length < 2) || /* out of range */
(breakpoint->length == 4 && (breakpoint->address & 2)) || /* mips32 unaligned */
(mips32->isa_imp == MIPS32_ONLY && breakpoint->length != 4) || /* misp32 specific */
((mips32->isa_imp & 1) != (breakpoint->length & 1))) /* isa not implemented */
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
if (breakpoint->type == BKPT_HARD) {
if (mips32->num_inst_bpoints_avail < 1) {
LOG_INFO("no hardware breakpoint available");