From 7351b31ffa1c72e16d2d8da3021c9ff5edbbf821 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Thu, 26 Mar 2020 09:09:34 -0700 Subject: Improve address translation tests (#261) * 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 https://github.com/riscv/riscv-openocd/pull/459 merges that will work. --- debug/gdbserver.py | 41 +++++++++++++++++++++++++++-------------- debug/programs/translate.c | 20 ++++++++++++++++---- debug/testlib.py | 11 +++++++++++ env | 2 +- 4 files changed, 55 insertions(+), 19 deletions(-) diff --git a/debug/gdbserver.py b/debug/gdbserver.py index 8800137..da671d3 100755 --- a/debug/gdbserver.py +++ b/debug/gdbserver.py @@ -1229,15 +1229,7 @@ class PrivTest(GdbSingleHartTest): 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) @@ -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") @@ -1315,11 +1318,19 @@ class TranslateTest(GdbTest): 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() @@ -1328,6 +1339,7 @@ class Sv39Test(TranslateTest): return self.hart.xlen > 32 def test(self): + self.check_satp(SATP_MODE_SV39) self.gdb.p("vms=&sv39") self.test_translation() @@ -1336,6 +1348,7 @@ class Sv48Test(TranslateTest): return self.hart.xlen > 32 def test(self): + self.check_satp(SATP_MODE_SV48) self.gdb.p("vms=&sv48") self.test_translation() diff --git a/debug/programs/translate.c b/debug/programs/translate.c index ebeb92d..c0424bf 100644 --- a/debug/programs/translate.c +++ b/debug/programs/translate.c @@ -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 = { @@ -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 = { @@ -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 = { @@ -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; @@ -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; diff --git a/debug/testlib.py b/debug/testlib.py index 3d714df..36f1f17 100644 --- a/debug/testlib.py +++ b/debug/testlib.py @@ -1076,6 +1076,17 @@ class GdbTest(BaseTest): 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) diff --git a/env b/env index 500b89f..68cad7b 160000 --- a/env +++ b/env @@ -1 +1 @@ -Subproject commit 500b89fb41ae857f5a1a0d6df382812cfce0b82e +Subproject commit 68cad7baf3ed0a4553fffd14726d24519ee1296a -- cgit v1.1