Paging Activity

Introduction

In this activity, we will explore some of the early stages of implementing paging in xv6. Unfortunately, paging is dictated by the architecture (RISC-V) in this case, so we cannot really change how it is structured, but nothing is stopping us from playing around with it.

Getting the Source Code

For this acitivity, we will need to mess around with the code for the xv6 kernel. So before you start this activity, please make sure that all of your code for the next lab is pushed to your own private repo, otherwise, we might risk mixing things up and losing your progress.

Backing up your lab code

If you have made a private xv6 repo, first commit and push all of your changes to your repo. You can do so using:

[xv6-riscv-public] $ git commit -am "progress on xv6 lab"
[xv6-riscv-public] $ git push

If you have not made a private xv6 repo, we strongly recommend you do so! For now, in order to not loose your progress, clone the xv6 repository again in a different location, something like:

[~] $ mkdir activities
[~] $ cd activities
[~/activities] $ git clone https://github.com/rhit-csse332/xv6-riscv-public.git

Getting on the right branch

Once you have everything saved, checkout the paging branch from the xv6 repository as follows:

[xv6-riscv-public] $ git fetch
[xv6-riscv-public] $ git checkout paging
[xv6-riscv-public] $ git pull

The Activity

What we would like to do in this activity is to examine the mappings from virtual addresses to physical addresses in xv6. Normally, a process cannot access its phyical address (think about why?) but we will expose those in this activity so we could learn more.

The goal of this activity is to implement a system call that, given a virtual address, returns the address of the physical frame of memory that corresponds to the page that the address belongs to. The system call we are implementing is called getmaping and it has the following signature:

int getmaping(uint64 va, uint64 pa_addr);

where va is the virtual address we are looking up, and pa_addr is a pointer to a pointer where we would like to store the physical frame address.

❓ Why do we have to do this level of indirection to write a value back to the user?

To use it, the system, you could do something like:

// the physical address we map to
uint64 pa;

// allocate some virtual address
char *p = malloc(4);

// make the system call, pa will contain the physical frame address
getmaping((uint64)p, (uint64)&pa);

To help you out, we have provided you with a userspace program that makes several calls to the getmaping system call and prints out some valid and invalid mappings. You can find the source code for the program under user/map.c, you can run from the xv6 shell using

[xv6 shell] $ map 1024
############### CHILD (4) ###############
 Virtual Address                  Physical Address
------------------               -------------------
0x0000000000013C00               0x0000000000000000

Checking for invalid address 0x0000000000014C00 -->  0x0000000000000000
############### CHILD (4) ###############

############### PARENT (3) ###############
 Virtual Address                  Physical Address
------------------               -------------------
0x0000000000013C00               0x0000000000000000

Checking for invalid address 0x0000000000014C00 -->  0x0000000000000000
############### PARENT (3) ###############

Currently, all addresses will show up as zeros, since we have not implemented the system call completely. Your job in this activity is to implement the system call.

Implementing getmaping

Systems calls are called from userspace, but they cause a trap into the kernel so that the kernel can execute some service on behalf of the user process. We have set everything up for you to add the getmaping system call. Your job is to implement the functionality of translating the virtual address into a physical address.

In kernel/sysproc.c, at the end of the file, you will find a function called sys_getmaping(void). This is the function that the kernel executes when the user calls the getmaping system call.

Your job now is to add your code to line 104 so that you can translate the virtual address va into its corresponding physical frame address pa.

Hint 1: To get a reference to the process that issues the system call, you can use the myproc() call. It returns struct proc * pointer that represents the PCB of the process that issued the system call.

Hint 2: You will find the functions defined in kernel/vm.c very helpful for this activity.