diff options
author | Robert Morris <[email protected]> | 2019-08-02 13:18:37 -0400 |
---|---|---|
committer | Robert Morris <[email protected]> | 2019-08-02 13:18:37 -0400 |
commit | 0b5c01d429d9f4927fa5acb46c32c9c2be948e76 (patch) | |
tree | 072ec84434fb12e27e43fd15b07a3c23b919d0c5 /labs | |
parent | 9110f40b7d65e7090b6214fd5db4814693b2e635 (diff) | |
parent | 7510ac70e5e03b26d8ad3355a9e5d30d6bd48507 (diff) | |
download | xv6-labs-0b5c01d429d9f4927fa5acb46c32c9c2be948e76.tar.gz xv6-labs-0b5c01d429d9f4927fa5acb46c32c9c2be948e76.tar.bz2 xv6-labs-0b5c01d429d9f4927fa5acb46c32c9c2be948e76.zip |
Merge branch 'riscv' of g.csail.mit.edu:xv6-dev into riscv
Diffstat (limited to 'labs')
-rw-r--r-- | labs/mmap.html | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/labs/mmap.html b/labs/mmap.html new file mode 100644 index 0000000..6f779c4 --- /dev/null +++ b/labs/mmap.html @@ -0,0 +1,171 @@ +<html> +<head> +<title>Lab: mmap</title> +<link rel="stylesheet" href="homework.css" type="text/css" /> +</head> +<body> + +<h1>Lab: mmap</h1> + +<p>In this lab you will use </tt>mmap</tt> on Linux to demand-page a +very large table and add memory-mapped files to xv6. + +<h2>Using mmap on Linux</h2> + +<p>This assignment will make you more familiar with how to manage virtual memory +in user programs using the Unix system call interface. You can do this +assignment on any operating system that supports the Unix API (a Linux Athena +machine, your laptop with Linux or MacOS, etc.). + +<p>Download the <a href="mmap.c">mmap homework assignment</a> and look +it over. The program maintains a very large table of square root +values in virtual memory. However, the table is too large to fit in +physical RAM. Instead, the square root values should be computed on +demand in response to page faults that occur in the table's address +range. Your job is to implement the demand faulting mechanism using a +signal handler and UNIX memory mapping system calls. To stay within +the physical RAM limit, we suggest using the simple strategy of +unmapping the last page whenever a new page is faulted in. + +<p>To compile <tt>mmap.c</tt>, you need a C compiler, such as gcc. On Athena, +you can type: +<pre> +$ add gnu +</pre> +Once you have gcc, you can compile mmap.c as follows: +<pre> +$ gcc mmap.c -lm -o mmap +</pre> +Which produces a <tt>mmap</tt> file, which you can run: +<pre> +$ ./mmap +page_size is 4096 +Validating square root table contents... +oops got SIGSEGV at 0x7f6bf7fd7f18 +</pre> + +<p>When the process accesses the square root table, the mapping does not exist +and the kernel passes control to the signal handler code in +<tt>handle_sigsegv()</tt>. Modify the code in <tt>handle_sigsegv()</tt> to map +in a page at the faulting address, unmap a previous page to stay within the +physical memory limit, and initialize the new page with the correct square root +values. Use the function <tt>calculate_sqrts()</tt> to compute the values. +The program includes test logic that verifies if the contents of the +square root table are correct. When you have completed your task +successfully, the process will print “All tests passed!”. + +<p>You may find that the man pages for mmap() and munmap() are helpful references. +<pre> +$ man mmap +$ man munmap +</pre> + + +<h2>Implement memory-mapped files in xv6</h2> + +<p>In this assignment you will implement memory-mapped files in xv6. + The test program <tt>mmaptest</tt> tells you what should work. + +<p>Here are some hints about how you might go about this assignment: + + <ul> + <li>Start with adding the two systems calls to the kernel, as you + done for other systems calls (e.g., <tt>sigalarm</tt>), but + don't implement them yet; just return an + error. run <tt>mmaptest</tt> to observe the error. + + <li>Keep track for each process what <tt>mmap</tt> has mapped. + You will need to allocate a <tt>struct vma</tt> to record the + address, length, permissions, etc. for each virtual memory area + (VMA) that maps a file. Since the xv6 kernel doesn't have a + memory allocator in the kernel, you can use the same approach has + for <tt>struct file</tt>: have a global array of <tt>struct + vma</tt>s and have for each process a fixed-sized array of VMAs + (like the file descriptor array). + + <li>Implement <tt>mmap</tt>: allocate a VMA, add it to the process's + table of VMAs, fill in the VMA, and find a hole in the process's + address space where you will map the file. You can assume that no + file will be bigger than 1GB. The VMA will contain a pointer to + a <tt>struct file</tt> for the file being mapped; you will need to + increase the file's reference count so that the structure doesn't + disappear when the file is closed (hint: + see <tt>filedup</tt>). You don't have worry about overlapping + VMAs. Run <tt>mmaptest</tt>: the first <tt>mmap</tt> should + succeed, but the first access to the mmaped- memory will fail, + because you haven't updated the page fault handler. + + <li>Modify the page-fault handler from the lazy-allocation and COW + labs to call a VMA function that handles page faults in VMAs. + This function allocates a page, reads a 4KB from the mmap-ed + file into the page, and maps the page into the address space of + the process. To read the page, you can use <tt>readi</tt>, + which allows you to specify an offset from where to read in the + file (but you will have to lock/unlock the inode passed + to <tt>readi</tt>). Don't forget to set the permissions correctly + on the page. Run <tt>mmaptest</tt>; you should get to the + first <tt>munmap</tt>. + + <li>Implement <tt>munmap</tt>: find the <tt>struct vma</tt> for + the address and unmap the specified pages (hint: + use <tt>uvmunmap</tt>). If <tt>munmap</tt> removes all pages + from a VMA, you will have to free the VMA (don't forget to + decrement the reference count of the VMA's <tt>struct + file</tt>); otherwise, you may have to shrink the VMA. You can + assume that <tt>munmap</tt> will not split a VMA into two VMAs; + that is, we don't unmap a few pages in the middle of a VMA. If + an unmapped page has been modified and the file is + mapped <tt>MAP_SHARED</tt>, you will have to write the page back + to the file. RISC-V has a dirty bit (<tt>D</tt>) in a PTE to + record whether a page has ever been written too; add the + declaration to kernel/riscv.h and use it. Modify <tt>exit</tt> + to call <tt>munmap</tt> for the process's open VMAs. + Run <tt>mmaptest</tt>; you should <tt>mmaptest</tt>, but + probably not <tt>forktest</tt>. + + <li>Modify <tt>fork</tt> to copy VMAs from parent to child. Don't + forget to increment reference count for a VMA's <tt>struct + file</tt>. In the page fault handler of the child, it is OK to + allocate a new page instead of sharing the page with the + parent. The latter would be cooler, but it would require more + implementation work. Run <tt>mmaptest</tt>; make sure you pass + both <tt>mmaptest</tt> and <tt>forktest</tt>. + + </ul> + +<p>Run usertests to make sure you didn't break anything. + +<p>Optional challenges: + <ul> + + <li>If two processes have the same file mmap-ed (as + in <tt>forktest</tt>), share their physical pages. You will need + reference counts on physical pages. + + <li>The solution above allocates a new physical page for each page + read from the mmap-ed file, even though the data is also in kernel + memory in the buffer cache. Modify your implementation to mmap + that memory, instead of allocating a new page. This requires that + file blocks be the same size as pages (set <tt>BSIZE</tt> to + 4096). You will need to pin mmap-ed blocks into the buffer cache. + You will need worry about reference counts. + + <li>Remove redundancy between your implementation for lazy + allocation and your implementation of mmapp-ed files. (Hint: + create an VMA for the lazy allocation area.) + + <li>Modify <tt>exec</tt> to use a VMA for different sections of + the binary so that you get on-demand-paged executables. This will + make starting programs faster, because <tt>exec</tt> will not have + to read any data from the file system. + + <li>Implement on-demand paging: don't keep a process in memory, + but let the kernel move some parts of processes to disk when + physical memory is low. Then, page in the paged-out memory when + the process references it. Port your linux program from the first + assignment to xv6 and run it. + + </ul> + +</body> +</html> |