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 your labs 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:
$ git commit -am "saving progress"
$ git push
Getting on the right branch
First, switch to the main
branch to get everything back in order, to do so,
use (recall, if your main branch’s name is master
, use master
)
$ git checkout main
Next, fetch the changes from our end using
$ git fetch upstream
Then, make sure that the branch paging_act
shows up
$ git branch -a
clab_solution
heapmm_solution
* main
remotes/origin/clab_solution
remotes/origin/heapmm_solution
remotes/origin/main
remotes/upstream/clab
remotes/upstream/heapmm
remotes/upstream/main
remotes/upstream/paging_act
Then, get the paging_act
branch as follows:
$ git checkout -b paging_act_sol upstream/paging_act
branch 'paging_act_sol' set up to track 'upstream/paging_act'.
Switched to a new branch 'paging_act_sol'
Finally, push the empty stub to your own repo using:
$ git push --set-upstream origin paging_act_sol
Enumerating objects: 99, done.
Counting objects: 100% (99/99), done.
Delta compression using up to 56 threads
Compressing objects: 100% (80/80), done.
Writing objects: 100% (88/88), 3.15 MiB | 11.39 MiB/s, done.
Total 88 (delta 15), reused 19 (delta 2), pack-reused 0
remote: Resolving deltas: 100% (15/15), completed with 11 local objects.
remote:
remote: Create a pull request for 'paging_act_sol' on GitHub by visiting:
remote: https://github.com/user/csse332-labs-user/pull/new/paging_act_sol
remote:
To github.com:user/csse332-labs-noureddi.git
* [new branch] paging_act_sol -> paging_act_sol
branch 'paging_act_sol' set up to track 'origin/paging_act_sol'.
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.
Hint 3: Read the comments for those functions!
This page was last edited by Mohammad Noureddine on Mon Dec 11 2023. If you notice any typos or inaccuracies, please open a GitHub issue on this repository.