mirror of
https://github.com/openhwgroup/cvw
synced 2025-01-24 21:44:29 +00:00
added support for sv48 and some docs on how to use these files
This commit is contained in:
parent
a84dd6dfc5
commit
1b2822e078
@ -5,9 +5,54 @@
|
||||
# Jessica Torrey <jtorrey@hmc.edu> 01 March 2021
|
||||
# Thomas Fleming <tfleming@hmc.edu> 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 <Variant name, ex: RV64I> --program <path to elf file> --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)
|
||||
|
Loading…
Reference in New Issue
Block a user