Browse Source

mprv test now breaks like it's supposed to.

pull/39/head
Tim Newsome 10 years ago
parent
commit
c7643c32e0
  1. 9
      riscv/mmu.cc
  2. 52
      tests/gdbserver.py
  3. 38
      tests/mprv.S
  4. 90
      tests/standalone.lds
  5. 20
      tests/testlib.py

9
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;
}
}

52
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()

38
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

90
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 = .;
}

20
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)

Loading…
Cancel
Save