Exercise: VM-exit handling

Stash your changes from exercise 1 and do git pull before proceeding. You may also do a clean git clone.

In this exercise, you’ll extend lvisor to trap on more interesting cases.

Logging context switches

Recall that the %cr3 register holds the physical address of a page table. An OS kernel needs to change %cr3 during context switches to switch page tables. Your job is to print out a message when a %cr3 change happens.

Exercise

Skim Chapter 24: Virtual Machine Control Structures of the Intel SDM. Focus on 24.6: VM-Execution Control Fields and find out what you need to intercept writes to %cr3.

Exercise

Recall the steps you need in the booting exercise in order to add a VM-exit handler. Modify lvisor to intercept writes to %cr3, add a corresponding VM-exit handler, and print the %cr3 value in the handler.

As for lv6, you should see something like the following in the output:

...
[    0.407275] cr3: 101000
...
[    0.468820] cr3: 116000
...

Question

Run xv6 inside your lvisor. What are the first three %cr3 values printed out? Can you guess what page tables they point to? You may consult the source code of xv6 (see tests/xv6-src/).

Hypercalls

In an OS, user space may trap into the kernel upon exceptions or interrupts; it can also choose to enter the kernel through system calls. Similarly, in a hypervisor, a guest can choose to enter the hypervisor, through hypercalls. In particular, you need the vmcall instruction on VMX. You may find a detailed description of vmcall in 30.3: VMX Instructions of the Intel SDM.

Exercise

Replace the two syscall instructions in tests/lv6/user.S with vmcall. You should see an unhandled VM-exit. Look up the exit reason, and add a corresponding VM-exit handler for hypercalls. In the VM-exit handler, implement the two system calls for lv6 (feel free to copy some code from tests/lv6/syscall.c) and make sure you see the same output as before.

Think carefully what registers hold the system call number and arguments in your VM-exit handler.

Question

What do you think hypercalls are useful for? Briefly describe one possible application.

Challenge: emulating system calls

It is slightly annoying that we have to duplicate the same implementations for hypercalls and system calls in lvisor/lv6. Instead of duplicating the two system calls of lv6 in lvisor, try to instead emulate the syscall instruction, so that your lvisor will jump back to lv6 and execute system calls there.

You may find a detailed description of the syscall instruction from Intel SDM, Vol 2.

Challenge: intercepting system calls

Using vmcall is easier to trap into lvisor but requires code change. Can you extend lvisor to work on the original lv6 code (i.e., using syscall in user.S)? You need to configure lvisor to intercept syscall instructions, which requires some work. Feel free to search for online resources.

What to submit

This completes the exercise. In answers.txt, write up your answers to the questions, along with a git-diff of your changes. Upload the file through Canvas.