Navigation Menu

Skip to content

Commit

Permalink
Improve address translation tests (#261)
Browse files Browse the repository at this point in the history
* Improve address translation tests.

Check that the mode we're testing is supported by hardware before
running the test.
Test with high address bits set, which catches a bug in OpenOCD.

* Turn off PMP for address translation test.

Otherwise it doesn't pass on HiFive Unleashed.

* Run TranslateTest on random hart.

Once riscv-collab/riscv-openocd#459 merges that will work.
  • Loading branch information
timsifive committed Mar 26, 2020
1 parent 094985d commit 7351b31
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 19 deletions.
41 changes: 27 additions & 14 deletions debug/gdbserver.py
Expand Up @@ -1229,15 +1229,7 @@ def setup(self):
self.supported.add(2)
self.supported.add(3)

# Disable physical memory protection by allowing U mode access to all
# memory.
try:
self.gdb.p("$pmpcfg0=0xf") # TOR, R, W, X
self.gdb.p("$pmpaddr0=0x%x" %
((self.hart.ram + self.hart.ram_size) >> 2))
except testlib.CouldNotFetch:
# PMP registers are optional
pass
self.disable_pmp()

# Ensure Virtual Memory is disabled if applicable (SATP register is not
# reset)
Expand Down Expand Up @@ -1294,16 +1286,27 @@ class TranslateTest(GdbTest):
compile_args = ("programs/translate.c", )

def setup(self):
# TODO: If we use a random hart, then we get into trouble because
# gdb_read_memory_packet() ignores which hart is currently selected, so
# we end up reading satp from hart 0 when the address translation might
# be set up on hart 1 only.
self.gdb.select_hart(self.target.harts[0])
self.disable_pmp()

self.gdb.load()
self.gdb.b("main")
output = self.gdb.c()
assertRegex(output, r"\bmain\b")

def check_satp(self, mode):
if self.hart.xlen == 32:
satp = mode << 31
else:
satp = mode << 60
try:
self.gdb.p("$satp=0x%x" % satp)
except testlib.CouldNotFetch:
raise TestNotApplicable
readback = self.gdb.p("$satp")
self.gdb.p("$satp=0")
if readback != satp:
raise TestNotApplicable

def test_translation(self):
self.gdb.b("error")
self.gdb.b("handle_trap")
Expand All @@ -1315,11 +1318,19 @@ def test_translation(self):
assertEqual(0xdeadbeef, self.gdb.p("virtual[0]"))
assertEqual(0x55667788, self.gdb.p("virtual[1]"))

SATP_MODE_OFF = 0
SATP_MODE_SV32 = 1
SATP_MODE_SV39 = 8
SATP_MODE_SV48 = 9
SATP_MODE_SV57 = 10
SATP_MODE_SV64 = 11

class Sv32Test(TranslateTest):
def early_applicable(self):
return self.hart.xlen == 32

def test(self):
self.check_satp(SATP_MODE_SV32)
self.gdb.p("vms=&sv32")
self.test_translation()

Expand All @@ -1328,6 +1339,7 @@ def early_applicable(self):
return self.hart.xlen > 32

def test(self):
self.check_satp(SATP_MODE_SV39)
self.gdb.p("vms=&sv39")
self.test_translation()

Expand All @@ -1336,6 +1348,7 @@ def early_applicable(self):
return self.hart.xlen > 32

def test(self):
self.check_satp(SATP_MODE_SV48)
self.gdb.p("vms=&sv48")
self.test_translation()

Expand Down
20 changes: 16 additions & 4 deletions debug/programs/translate.c
Expand Up @@ -23,6 +23,7 @@ typedef struct {
unsigned ppn_offset_bits[5];
unsigned entry_width_bytes;
unsigned vpn_width_bits;
unsigned vaddr_bits;
} virtual_memory_system_t;

static virtual_memory_system_t sv32 = {
Expand All @@ -31,7 +32,8 @@ static virtual_memory_system_t sv32 = {
.ppn_width_bits = {12, 10, 10},
.ppn_offset_bits = {0, 12, 22},
.entry_width_bytes = 4,
.vpn_width_bits = 10
.vpn_width_bits = 10,
.vaddr_bits = 32
};

static virtual_memory_system_t sv39 = {
Expand All @@ -40,7 +42,8 @@ static virtual_memory_system_t sv39 = {
.ppn_width_bits = {12, 9, 9, 26},
.ppn_offset_bits = {0, 12, 21, 30},
.entry_width_bytes = 8,
.vpn_width_bits = 9
.vpn_width_bits = 9,
.vaddr_bits = 39
};

static virtual_memory_system_t sv48 = {
Expand All @@ -49,7 +52,8 @@ static virtual_memory_system_t sv48 = {
.ppn_width_bits = {12, 9, 9, 9, 26},
.ppn_offset_bits = {0, 12, 21, 30, 39},
.entry_width_bytes = 8,
.vpn_width_bits = 9
.vpn_width_bits = 9,
.vaddr_bits = 48
};

static virtual_memory_system_t *vms;
Expand Down Expand Up @@ -152,12 +156,20 @@ int main()
void *master_table = get_page();
setup_page_table(master_table, vms->levels-1, 0);
uint32_t *physical = get_page();
uint32_t *virtual = (uint32_t *) (((reg_t) physical) ^ ((reg_t) 0x40000000));
//uint32_t *virtual = (uint32_t *) (((reg_t) physical) ^ ((reg_t) 0x40000000));
uint32_t *virtual = (uint32_t *) (((reg_t) physical) ^ (((reg_t) 0xf) << (vms->vaddr_bits - 4)));
// Virtual addresses must be sign-extended.
if (vms->vaddr_bits < sizeof(virtual) * 8 && (reg_t) virtual & ((reg_t) 1<<(vms->vaddr_bits-1)))
virtual = (uint32_t *) (
(reg_t) virtual | ~(((reg_t) 1 << vms->vaddr_bits) - 1));
add_entry(master_table, 0, (reg_t) virtual, (reg_t) physical);

unsigned long satp = set_field(0, SATP_MODE, vms->mode);
satp = set_field(satp, SATP_PPN, ((unsigned long) master_table) >> 12);
write_csr(satp, satp);
satp = read_csr(satp);
if (get_field(satp, SATP_MODE) != vms->mode)
error();

reg_t mstatus = read_csr(mstatus);
mstatus |= MSTATUS_MPRV;
Expand Down
11 changes: 11 additions & 0 deletions debug/testlib.py
Expand Up @@ -1076,6 +1076,17 @@ def parkOtherHarts(self):

self.gdb.select_hart(self.hart)

def disable_pmp(self):
# Disable physical memory protection by allowing U mode access to all
# memory.
try:
self.gdb.p("$pmpcfg0=0xf") # TOR, R, W, X
self.gdb.p("$pmpaddr0=0x%x" %
((self.hart.ram + self.hart.ram_size) >> 2))
except CouldNotFetch:
# PMP registers are optional
pass

class GdbSingleHartTest(GdbTest):
def classSetup(self):
GdbTest.classSetup(self)
Expand Down
2 changes: 1 addition & 1 deletion env
Submodule env updated 5 files
+13 −1,244 encoding.h
+4 −57 p/riscv_test.h
+0 −37 v/entry.S
+0 −4 v/riscv_test.h
+27 −54 v/vm.c

0 comments on commit 7351b31

Please sign in to comment.