From 1b2822e0782daddc61b21cb5211dacbe17e92229 Mon Sep 17 00:00:00 2001 From: Kip Macsai-Goren Date: Thu, 3 Jun 2021 14:32:12 -0400 Subject: [PATCH] added support for sv48 and some docs on how to use these files --- .../testgen/virtual_memory_util.py | 101 +++++++++++++++--- 1 file changed, 88 insertions(+), 13 deletions(-) diff --git a/wally-pipelined/testgen/virtual_memory_util.py b/wally-pipelined/testgen/virtual_memory_util.py index 27ca742b3..0aafb3a12 100644 --- a/wally-pipelined/testgen/virtual_memory_util.py +++ b/wally-pipelined/testgen/virtual_memory_util.py @@ -5,9 +5,54 @@ # Jessica Torrey 01 March 2021 # Thomas Fleming 01 March 2021 # -# Utility functions for simulating and testing virtual memory on RISC-V. +# Modified kmacsaigoren@hmc.edu 2 June 2021 +# file now reflects actual use to generate assembly code pagetable. +# file now also includes small guide on how it can be used. +# +# Utility for generating the pagetable for any test assembly code where virtual memory is needed. ################################## +###################################################### +""" HOW TO USE THIS FILE + +This is all assuming you are writing code very similar to the WALLY-VIRTUALMEMORY tests and would like your own virtual memory map. +This guide is also stored in the WALLY-VIRTUALMEMORY.S file as well. + +Begin by copying an existing page directory over to your test and running make (it'll be wrong, but we'll fix it in a second). + Make may hang or give you an error because the reference outputs may be wrong, but all we're trying to do is get an elf file. +Simulate the test code on your favorite riscv processor simulator with a debugger that will show you internal state/register values. + I used OVPsimPlus with the command 'riscvOVPsimPlus.exe --variant --program --gdbconsole' +Run through the simulation until it has written to satp and read the bottom 60 bits of it. + Assuming you're a test with the same setup code, this should be the value of the base ppn. + +Near the top of the python file you're reading right now, edit the value of 'INITIAL_PPN' to be the base PPN you just found in hex. + +Now find the mappings at the very bottom of the python file. +Each of these loops is adding a mapping from each virtual page in the loop to a physical page somewhere in RAM. + +add or remove mappings as you see fit. the first loop maps VPNs of 0x80000 to 0x80014 onto PPNs of 0x80000 to 0x80014 + you can map single pages or ranges of pages. you can also map multiple VPNs onto the same PPN. + Make sure NOT to include the final VPN that causes the page fault in your test or your program will hang on the j loop instruction (unless you change the end condition). + +double check that you're using the right architecture/svmode in the 'arch' variable + +then run this python file and paste its output at the bottom of your assembly code. Be sure not to delete the signature fills. + +email kmacsaigoren@hmc.edu if you have any questions and he might be able to remember the answers. + +*** Currently doesn't work: mapping something with nonzeros in the VPN[3] feild onto any physical aderss. + It'll produce a page table, but writing to those virtual adresses will not correspond to the correctly mapped physical adresses. + + additionally, the expected behaviour doesn't really work when we try to map to a ram afress that starts with something larger than 000000008 + This could be ebcause of the 32 bit adress space for physical memory. + + remember that these things are broken with this program that generates page tables for test code. it does not say whether the test or module + itself works or not. +*/ + +""" +###################################################### + ################################## # libraries ################################## @@ -38,13 +83,18 @@ testcase_num = 0 signature_len = 2000 signature = [0xff for _ in range(signature_len)] +# Base PPN, comes after 2 pages of test code and 2 pages of filler signature output space. +# depending on your test however, this value may be different. You can use OVPsimPlus or QEMU with your testcode to find it. +INITIAL_PPN = 0x80005 + + ################################## # classes ################################## class Architecture: - def __init__(self, xlen): + def __init__(self, xlen, svMode): if (xlen == 32): - self.PTESIZE = 4 + self.PTESIZE = 4 # bytes self.PTE_BITS = 32 self.VPN_BITS = 20 @@ -54,15 +104,28 @@ class Architecture: self.LEVELS = 2 elif (xlen == 64): - self.PTESIZE = 8 - self.PTE_BITS = 54 + if (svMode == 39): + self.PTESIZE = 8 + self.PTE_BITS = 54 - self.VPN_BITS = 27 - self.VPN_SEGMENT_BITS = 9 + self.VPN_BITS = 27 + self.VPN_SEGMENT_BITS = 9 - self.PPN_BITS = 44 + self.PPN_BITS = 44 - self.LEVELS = 3 + self.LEVELS = 3 + elif (svMode == 48): + self.PTESIZE = 8 + self.PTE_BITS = 54 + + self.VPN_BITS = 36 + self.VPN_SEGMENT_BITS = 9 + + self.PPN_BITS = 44 + + self.LEVELS = 4 + else: + raise ValueError('Only Sv39 and Sv48 are implemented') else: raise ValueError('Only rv32 and rv64 are allowed.') @@ -179,7 +242,6 @@ def virtual_to_vpn(vaddr, arch): return page_number -INITIAL_PPN = 0x80002 next_free_ppn = INITIAL_PPN def next_ppn(): global next_free_ppn @@ -194,11 +256,12 @@ def print_pages(): ################################## # helper variables ################################## -rv32 = Architecture(32) -rv64 = Architecture(64) +sv32 = Architecture(32, 32) +sv39 = Architecture(64, 39) +sv48 = Architecture(64, 48) if __name__ == "__main__": - arch = rv64 + arch = sv39 pgdir = PageTable("page_directory", next_ppn(), arch) # Directly map the first 20 pages of RAM @@ -206,6 +269,18 @@ if __name__ == "__main__": vaddr = 0x80000000 + (arch.PGSIZE * page) paddr = 0x80000000 + (arch.PGSIZE * page) pgdir.add_mapping(vaddr, paddr, PTE_D | PTE_A | PTE_R | PTE_W | PTE_U | PTE_X | PTE_V) + + # Map Vpn of of the offset below and the 20 pages after it mapped onto the same 20 pages of ram. + # the first two of these are also the location of the output for each test. + for page in range(40): + vaddr = 0x00000000 + (arch.PGSIZE * page) + paddr = 0x80000000 + (arch.PGSIZE * page) + if page >= 20: + pgdir.add_mapping(vaddr, paddr, PTE_D | PTE_A | PTE_R | PTE_W | PTE_U | PTE_X | 0) # gives me an invalid mapping where I can try to store/read to force a page fault. + else: + pgdir.add_mapping(vaddr, paddr, PTE_D | PTE_A | PTE_R | PTE_W | PTE_U | PTE_X | PTE_V) + + """ supervisor_pgdir = PageTable("sdir", next_ppn(), rv64) supervisor_pgdir.add_mapping(0x80000000, 0x80000000, PTE_R | PTE_W | PTE_X)