From c7643c32e07e4b5d82bdb98b91998f9c12f24434 Mon Sep 17 00:00:00 2001 From: Tim Newsome Date: Sat, 7 May 2016 11:15:59 -0700 Subject: [PATCH] mprv test now breaks like it's supposed to. --- riscv/mmu.cc | 9 +++++ tests/gdbserver.py | 52 +++++++++++++++++-------- tests/mprv.S | 38 +++++++++++++++++++ tests/standalone.lds | 90 ++++++++++++++++++++++++++++++++++++++++++++ tests/testlib.py | 20 +++++++--- 5 files changed, 187 insertions(+), 22 deletions(-) create mode 100644 tests/mprv.S create mode 100644 tests/standalone.lds diff --git a/riscv/mmu.cc b/riscv/mmu.cc index 9b623ae..b88cade 100644 --- a/riscv/mmu.cc +++ b/riscv/mmu.cc @@ -117,6 +117,7 @@ void mmu_t::refill_tlb(reg_t vaddr, reg_t paddr, access_type type) reg_t mmu_t::walk(reg_t addr, access_type type, bool supervisor, bool pum) { + fprintf(stderr, "walk 0x%lx\n", addr); int levels, ptidxbits, ptesize; switch (get_field(proc->get_state()->mstatus, MSTATUS_VM)) { @@ -130,6 +131,7 @@ reg_t mmu_t::walk(reg_t addr, access_type type, bool supervisor, bool pum) int va_bits = PGSHIFT + levels * ptidxbits; reg_t mask = (reg_t(1) << (proc->xlen - (va_bits-1))) - 1; reg_t masked_msbs = (addr >> (va_bits-1)) & mask; + fprintf(stderr, "walk masked_msbs=0x%lx, mask=0x%lx\n", masked_msbs, mask); if (masked_msbs != 0 && masked_msbs != mask) return -1; @@ -140,6 +142,7 @@ reg_t mmu_t::walk(reg_t addr, access_type type, bool supervisor, bool pum) // check that physical address of PTE is legal reg_t pte_addr = base + idx * ptesize; + fprintf(stderr, "pte_addr=0x%lx\n", pte_addr); if (!sim->addr_is_mem(pte_addr)) break; @@ -147,11 +150,16 @@ reg_t mmu_t::walk(reg_t addr, access_type type, bool supervisor, bool pum) reg_t pte = ptesize == 4 ? *(uint32_t*)ppte : *(uint64_t*)ppte; reg_t ppn = pte >> PTE_PPN_SHIFT; + fprintf(stderr, "pte=0x%lx\n", pte); + if (PTE_TABLE(pte)) { // next level of page table base = ppn << PGSHIFT; } else if (pum && PTE_CHECK_PERM(pte, 0, type == STORE, type == FETCH)) { + fprintf(stderr, "pum fail\n"); break; } else if (!PTE_CHECK_PERM(pte, supervisor, type == STORE, type == FETCH)) { + fprintf(stderr, "perm(0x%lx, %d, %d, %d)\n", + pte, supervisor, type==STORE, type==FETCH); break; } else { // set referenced and possibly dirty bits. @@ -159,6 +167,7 @@ reg_t mmu_t::walk(reg_t addr, access_type type, bool supervisor, bool pum) // for superpage mappings, make a fake leaf PTE for the TLB's benefit. reg_t vpn = addr >> PGSHIFT; reg_t value = (ppn | (vpn & ((reg_t(1) << ptshift) - 1))) << PGSHIFT; + fprintf(stderr, " -> 0x%lx\n", value); return value; } } diff --git a/tests/gdbserver.py b/tests/gdbserver.py index 0f9ee1d..6ca9af6 100755 --- a/tests/gdbserver.py +++ b/tests/gdbserver.py @@ -25,6 +25,18 @@ class InstantHaltTest(unittest.TestCase): self.gdb.command("stepi") self.assertNotEqual(0x1000, self.gdb.p("$pc")) + def test_change_pc(self): + """Change the PC right as we come out of reset.""" + # 0x13 is nop + self.gdb.command("p *((int*) 0x80000000)=0x13") + self.gdb.command("p *((int*) 0x80000004)=0x13") + self.gdb.command("p *((int*) 0x80000008)=0x13") + self.gdb.command("p $pc=0x80000000") + self.gdb.command("stepi") + self.assertEqual(0x80000004, self.gdb.p("$pc")) + self.gdb.command("stepi") + self.assertEqual(0x80000008, self.gdb.p("$pc")) + class DebugTest(unittest.TestCase): def setUp(self): self.binary = testlib.compile("debug.c") @@ -156,22 +168,30 @@ class RegsTest(unittest.TestCase): self.assertEqual(9, self.gdb.p("$x1")) self.assertEqual(9, self.gdb.p("$csr1")) -#class MprvTest(unittest.TestCase): -# def setUp(self): -# self.binary = testlib.compile("mprv.S") -# self.spike, self.port = testlib.spike(self.binary, halted=False) -# self.gdb = testlib.Gdb() -# self.gdb.command("file %s" % self.binary) -# self.gdb.command("target extended-remote localhost:%d" % self.port) -# -# def tearDown(self): -# self.spike.kill() -# self.spike.wait() -# -# def test_mprv(self): -# """Test that the debugger can access memory when MPRV is set.""" -# output = self.gdb.command("p/x data"); -# self.assertIn("0xbead", output) +class MprvTest(unittest.TestCase): + def setUp(self): + self.binary = testlib.compile("mprv.S", "-T", "standalone.lds", + "-nostartfiles") + self.spike, self.port = testlib.spike(None, halted=True) + self.gdb = testlib.Gdb() + self.gdb.command("file %s" % self.binary) + self.gdb.command("target extended-remote localhost:%d" % self.port) + self.gdb.command("load") + + def tearDown(self): + self.spike.kill() + self.spike.wait() + + def test_mprv(self): + """Test that the debugger can access memory when MPRV is set.""" + self.gdb.c(wait=False) + self.gdb.interrupt() + output = self.gdb.command("p/x *(int*)(((char*)&data)-0x80000000)") + self.assertIn("0xbead", output) if __name__ == '__main__': + # TROUBLESHOOTING TIPS + # If a particular test fails, run just that one test, eg.: + # ./tests/gdbserver.py MprvTest.test_mprv + # Then inspect gdb.log and spike.log to see what happened in more detail. unittest.main() diff --git a/tests/mprv.S b/tests/mprv.S new file mode 100644 index 0000000..114918a --- /dev/null +++ b/tests/mprv.S @@ -0,0 +1,38 @@ +#include "../riscv/encoding.h" +#define PGSHIFT 12 + + .global main + + .section .text +main: + # Set up a page table entry that maps 0x0... to 0x8... + la t0, page_table + srli t0, t0, PGSHIFT + csrw CSR_SPTBR, t0 + + # update mstatus + csrr t1, CSR_MSTATUS + li t0, (MSTATUS_MPRV | (VM_SV39 << 24)) + #li t0, ((VM_SV39 << 24)) + or t1, t0, t1 + csrw CSR_MSTATUS, t1 + + la t0, (loop - 0x80000000) + csrw CSR_MEPC, t0 + + # Exit supervisor mode, entering user mode at loop. + mret + +loop: + la t0, data + lw t1, 0(t0) + j loop + + .section .data +data: + .word 0xbead + + .balign 0x1000 +page_table: + .word ((0x80000000 >> 2) | PTE_V | PTE_TYPE_URWX_SRWX) + .word 0 diff --git a/tests/standalone.lds b/tests/standalone.lds new file mode 100644 index 0000000..6705cfd --- /dev/null +++ b/tests/standalone.lds @@ -0,0 +1,90 @@ +OUTPUT_ARCH( "riscv" ) + +ENTRY( main ) + +SECTIONS +{ + + /*--------------------------------------------------------------------*/ + /* Code and read-only segment */ + /*--------------------------------------------------------------------*/ + + /* Begining of code and text segment */ + . = 0x80000000; + _ftext = .; + PROVIDE( eprol = . ); + + .text : + { + *(.text.init) + } + + /* text: Program code section */ + .text : + { + *(.text) + *(.text.*) + *(.gnu.linkonce.t.*) + } + + /* rodata: Read-only data */ + .rodata : + { + *(.rdata) + *(.rodata) + *(.rodata.*) + *(.gnu.linkonce.r.*) + } + + /* End of code and read-only segment */ + PROVIDE( etext = . ); + _etext = .; + + /*--------------------------------------------------------------------*/ + /* Initialized data segment */ + /*--------------------------------------------------------------------*/ + + /* Start of initialized data segment */ + . = ALIGN(16); + _fdata = .; + + /* data: Writable data */ + .data : + { + *(.data) + *(.data.*) + *(.srodata*) + *(.gnu.linkonce.d.*) + *(.comment) + } + + /* End of initialized data segment */ + . = ALIGN(4); + PROVIDE( edata = . ); + _edata = .; + + /*--------------------------------------------------------------------*/ + /* Uninitialized data segment */ + /*--------------------------------------------------------------------*/ + + /* Start of uninitialized data segment */ + . = .; + _fbss = .; + + /* sbss: Uninitialized writeable small data section */ + . = .; + + /* bss: Uninitialized writeable data section */ + . = .; + _bss_start = .; + .bss : + { + *(.bss) + *(.bss.*) + *(.sbss*) + *(.gnu.linkonce.b.*) + *(COMMON) + } + + _end = .; +} diff --git a/tests/testlib.py b/tests/testlib.py index 6233901..3b439b1 100644 --- a/tests/testlib.py +++ b/tests/testlib.py @@ -13,14 +13,20 @@ def find_file(path): fullpath = os.path.join(directory, path) if os.path.exists(fullpath): return fullpath - raise ValueError("Couldn't find %r." % path) + return None -def compile(src): +def compile(*args): """Compile a single .c file into a binary.""" - src = find_file(src) - dst = os.path.splitext(src)[0] + dst = os.path.splitext(args[0])[0] cc = os.path.expandvars("$RISCV/bin/riscv64-unknown-elf-gcc") - cmd = "%s -g -o %s %s" % (cc, dst, src) + cmd = [cc, "-g", "-O", "-o", dst] + for arg in args: + found = find_file(arg) + if found: + cmd.append(found) + else: + cmd.append(arg) + cmd = " ".join(cmd) result = os.system(cmd) assert result == 0, "%r failed" % cmd return dst @@ -46,7 +52,9 @@ def spike(binary, halted=False, with_gdb=True, timeout=None): if with_gdb: port = unused_port() cmd += ['--gdb-port', str(port)] - cmd += ['pk', binary] + cmd.append('pk') + if binary: + cmd.append(binary) logfile = open("spike.log", "w") process = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=logfile, stderr=logfile) -- 2.30.2