Submit: Turn in your
entire xinu-hw7
directory
source files using the
turnin command on morbius.mscsnet.mu.edu or
one of the other
Systems Lab machines. Please run "make clean" in the
compile/ subdirectory just before submission to reduce
unnecessary space consumption.
Work should be completed in pairs. Be certain to include both names in the comment block at the top of all source code files, with a TA-BOT:MAILTO comment line including any addresses that should automatically receive results. It would be courteous to confirm with your partner when submitting the assignment.
First, make a copy of your Project 6 directory:
cp -R xinu-hw6 xinu-hw7
Then, untar the new project files on top of it:
tar xvzf ~brylow/os/Projects/xinu-hw7.tgz
Be certain to make clean before compiling for the first time.
In this assignment, you will be implementing a function that given a virtual address, walks the pagetable and returns the address of the page table entry (PTE). It will create any pages along the way. Since we're dealing with paging and memory protection, there are multiple files that will need to be changed to account for the user processes' virtual address space.
Paging can be implemented by the following steps:
dispatch
to use the swap area instead of frame. Have it return the value of the satp
registercreate
to create the stack by using a physical page. Call vm_userinit
to create the user page table. Make sure to set the stack pointer correctly. ctxsw
to take in the new process' satp value. In ctxsw
, after we set the sepc
register, we can update the satp
register (see other areas for example). pgTraverseAndCreate
to walk the page table for a virtual address and return the page table entry's address. initialize.c
to enable paging. New test cases are in system/testcases.c, which should demonstrate memory protection and paging. You will need to create others to fully test your implementation.
This assignment involves a lot of work. There are 5 different files must be changed to support paging. Even starting the assignment a few days before the deadline isn't enough time to make all the necessary changes. We're giving you two weeks (excluding break) for a reason. You'll need the full two weeks of class to fully complete this assignment.
The CPU on the Sipeed Nezha implements the RISC-V Sv39 paging, meaning there are 39 bits used to map from a virtual address to a physical address. In Sv39, all pages are 4096 bytes long. The Sv39 paging uses a 3-level hierarchical page table to map from virtual addresses to physical addresses. In the image of a virtual address above, VPN stands for virtual page number. The first 9-bits (VPN[2]) are used as the index into the first page table, the middle 9 bits (VPN[1]) are used as the index into the second page table, and the right most 9 bits (VPN[0]) are used as the index into the last page table. The last page table contains a page table entry with the physical address of the actual page in memory as well as any protection bits (see below). The page offset is used to find which byte in the page is being referenced.
In every page table, there are page table entries. In RISC-V pages are 4096 bytes. Each PTE is 8 bytes long, meaning 4096/8 = 512 (2^9) page table entries on one page.
These entries can either point to another page table (called a link PTE) or point to the physical page (called a leaf PTE). The format for the RISC-V page table entries is shown above.
Bits 0-7 are protection bits. These bit meanings are described in include/safemem.h
. Bits 10-53 hold the physical page address. In this class, we will not be using
bits 8-9 or bits 54-63.
satp
Register
The satp
register contains the physical address of the root page table divided by the page size (4096 bytes) called the PPN (physical page number). The MMU must know where the root page
table resides so it can start translation. The satp
register also holds the Address Space Identifier (ASID). The TLB uses the ASID to determine if a new page table was swapped in. If the ASID changes,
the TLB won't used the cached changes for the old ASID. The mode bits are used to tell the MMU to use Sv39 paging. In Embedded Xinu, we give you a helper function to do the bit shifting for creating a
value to go into the satp
register. MAKE_SATP(pid, physical_root_page_address)
is defined in includes/safemem.h
. Given a process ID (used as the ASID) and the
physical address of the root page, MAKE_SATP
does all the bit shifting to create the valid value to place in the satp
register. You will use MAKE_SATP
in dispatch
and
when calling ctxsw
In previous assignments, dispatch()
took in the frame (or the stack pointer) as a parameter.
Now that user processes have a virtualized view of memory, the stack pointer isn't an actual
physical address, rather it's a virtual address. The kernel can't use the user's virtual address since it's
local to that user process' page table. Instead of saving registers onto the stack,
like we did in previous assignments, every user process has a page in memory called the swap area.
To make it easier for saving the registers, the swap area is at a fixed virtual address for every process. When interrupt
is called,
the OS will save all the registers into this swap area, switch to the kernel page table, and execute dispatch
.
When returning from interrupt
, the user process' page table is loaded in and the registers are restored from
the swap area. Every PCB has a swaparea
that can be used as an array just like we've used frame previously.
You will need to remove frame as a parameter in dispatch.c
and replace it with the swaparea
. dispatch
should
return the value being loaded into the satp
register.
Now that paging is enabled, we no longer need to rely on the broken getstk
to create a user process' stack.
Instead, you'll have to get a physical page in create
to use that as the stack. You'll have to pass that
page into vm_userinit
along with the PID. vm_userinit
will return the pagetable which should be
set on the PPCB. The stack pointer address in the regs
will have to be updated accordingly to take into account the virtual address,
the accounting information, and any arguments pushed onto the stack. Finally, within the process' swap area, the PREG_KERNSATP
and PREG_KERNSP
need to be set so the kernel can restore the kernel's stack and pagetable during an interrupt/exception.
The functions in map.c
take care of translating between physical and virtual addresses. Given a root page table, a physical page and
a virtual address, mapPage
places that physical page at the virtual address for the root page table. This is used in vm_userinit.c
to map the stack you setup in create.c
to the
PROCSTACKADDR
virtual address. The mapAddress
function is used to map a range of physical addresses to virtual addresses for a given root page table. Both mapPage
and mapAddress
rely on a helped function pgTraverseAndCreate
. The main TODO for this assignment is in pgTraverseAndCreate
. pgTraverseAndCreate
walks the page table, for a given virtual address and returns the address of the PTE. See the TODO in pgTraverseAndCreate
for more information.
system/start.S
, system/criticalerr.S
, and include/riscv.h
into the previous assignment.[Revised 2023 Mar 09 12:49 DWB]