aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTim Newsome <tim@sifive.com>2020-03-05 11:33:51 -0800
committerGitHub <noreply@github.com>2020-03-05 11:33:51 -0800
commit1ae21b387482f09dacebb9f4a267df85868657d9 (patch)
tree859e945aa686d3cbc009b55f5707557c28dcae6a
parent1449af5bdb99052c2f3bf92747f8438544cd8f3f (diff)
downloadriscv-openocd-1ae21b387482f09dacebb9f4a267df85868657d9.zip
riscv-openocd-1ae21b387482f09dacebb9f4a267df85868657d9.tar.gz
riscv-openocd-1ae21b387482f09dacebb9f4a267df85868657d9.tar.bz2
Fix address translation when high bits are set. (#453)
Fixes #452. Also check that the high bits match the MSB of the virtual address. Change-Id: Ib1d3d04db9ad9327ef71ea3736d5cf5d3b65b9c4
-rw-r--r--src/target/riscv/riscv.c27
-rw-r--r--src/target/riscv/riscv.h2
2 files changed, 23 insertions, 6 deletions
diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c
index ae04897..929746f 100644
--- a/src/target/riscv/riscv.c
+++ b/src/target/riscv/riscv.c
@@ -276,6 +276,8 @@ static enum {
} resume_order;
virt2phys_info_t sv32 = {
+ .name = "Sv32",
+ .va_bits = 32,
.level = 2,
.pte_shift = 2,
.vpn_shift = {12, 22},
@@ -287,6 +289,8 @@ virt2phys_info_t sv32 = {
};
virt2phys_info_t sv39 = {
+ .name = "Sv39",
+ .va_bits = 39,
.level = 3,
.pte_shift = 3,
.vpn_shift = {12, 21, 30},
@@ -298,6 +302,8 @@ virt2phys_info_t sv39 = {
};
virt2phys_info_t sv48 = {
+ .name = "Sv48",
+ .va_bits = 48,
.level = 4,
.pte_shift = 3,
.vpn_shift = {12, 21, 30, 39},
@@ -1412,18 +1418,16 @@ static int riscv_address_translate(struct target *target,
if (result != ERROR_OK)
return result;
- mode = get_field(satp_value, RISCV_SATP_MODE(riscv_xlen(target)));
+ unsigned xlen = riscv_xlen(target);
+ mode = get_field(satp_value, RISCV_SATP_MODE(xlen));
switch (mode) {
case SATP_MODE_SV32:
- LOG_DEBUG("Translation mode: SV32");
info = &sv32;
break;
case SATP_MODE_SV39:
- LOG_DEBUG("Translation mode: SV39");
info = &sv39;
break;
case SATP_MODE_SV48:
- LOG_DEBUG("Translation mode: SV48");
info = &sv48;
break;
case SATP_MODE_OFF:
@@ -1435,8 +1439,18 @@ static int riscv_address_translate(struct target *target,
" (satp: 0x%" PRIx64")", satp_value);
return ERROR_FAIL;
}
+ LOG_DEBUG("virtual=0x%" TARGET_PRIxADDR "; mode=%s", virtual, info->name);
+
+ /* verify bits xlen-1:va_bits-1 are all equal */
+ target_addr_t mask = ((target_addr_t) 1 << (xlen - (info->va_bits-1))) - 1;
+ target_addr_t masked_msbs = (virtual >> (info->va_bits-1)) & mask;
+ if (masked_msbs != 0 && masked_msbs != mask) {
+ LOG_ERROR("Virtual address 0x%" TARGET_PRIxADDR " is not sign-extended "
+ "for %s mode.", virtual, info->name);
+ return ERROR_FAIL;
+ }
- ppn_value = get_field(satp_value, RISCV_SATP_PPN(riscv_xlen(target)));
+ ppn_value = get_field(satp_value, RISCV_SATP_PPN(xlen));
table_address = ppn_value << RISCV_PGSHIFT;
i = info->level - 1;
while (i >= 0) {
@@ -1477,7 +1491,8 @@ static int riscv_address_translate(struct target *target,
return ERROR_FAIL;
}
- *physical = virtual;
+ /* Make sure to clear out the high bits that may be set. */
+ *physical = virtual & (((target_addr_t) 1 << info->va_bits) - 1);
while (i < info->level) {
ppn_value = pte >> info->pte_ppn_shift[i];
diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h
index 928e460..7233579 100644
--- a/src/target/riscv/riscv.h
+++ b/src/target/riscv/riscv.h
@@ -176,7 +176,9 @@ typedef struct {
} riscv_bscan_tunneled_scan_context_t;
typedef struct {
+ const char *name;
int level;
+ unsigned va_bits;
unsigned pte_shift;
unsigned vpn_shift[PG_MAX_LEVEL];
unsigned vpn_mask[PG_MAX_LEVEL];