Project #7: Virtual Memory and Paging

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.

Enough pages to make a book

Preparation

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.

Paging

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:

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.

RISC-V Paging

Overview

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.

Page table entry (PTE)

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

Changes

dispatch.c and the swap area

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.

create.c and getstk.c

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.

map.c

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.

Notes


[back]

[Revised 2023 Mar 09 12:49 DWB]