CS560 Lab #7

  • Jim Plank, Rich Wolski
  • URL: http://www.cs.utk.edu/~plank/plank/classes/cs560/560/labs/lab7/lab.html
  • Directory: /blugreen/homes/plank/cs560/labs/lab7
  • Makefile: /blugreen/homes/plank/cs560/labs/lab7/Makefile

    Lab 7 -- Virtual Memory

    Below we describe the JOS interface to virtual memory. Your job is get virtual memory and demand paging working in JOS. When you are done, everything should work as in lab 6, however you can have an arbitrary number of processes in memory, and the processes should use the memory they need, rather than a stock 135K.

    Compiling Information

    Use the Makefile in the lab7 directory to link your code with: Also, in order to get JOS to run, you have to create your disk (this is used in lab 8, but you have to make it here). To do this, execute the file /home/cs560/bin/sparc-sun-solaris2.9/makedisk. This will create an 8 megabyte "disk" file somewhere that you will have sole access to. Once you make some adjustments to your code involving User_Base and User_Limit you will see the following when you fire up JOS:
    JOS booting...  done.
    Probing disk...  done.
    
    Probing console...  done.
    
    Once you have created a disk, you should not run makedisk again. If you get any JOS errors about the disk send the TA's the errors right away so that they can track the problem down.

    Lab Description

    Virtual Memory

    The main_memory array will still exist as the user-accessible memory. However, the User_base and User_limit registers go away. They are replaced by page tables. Each process should have a page table, defined as follows:
            typedef struct {
                    PTE           **table;
                    int             tableSize;
            }               PageTable;
    
    
    
    
            typedef struct {
                    int             physicalFrame;
                    bool            valid;
                    bool            dirty;
                    bool            use;
            }               PTE;
    

    These are defined for you in simulator.h and the simulator understands them, so you are not free to change them.

    Pages are PageSize bytes (defined in simulator.h). I would recommend having processes allocate page tables with enough entries for user processes to be 8 megabytes in size.

    Run_user_code has been changed so that it takes a set of registers and a page table:

       run_user_code(int registers[], PageTable *pageTable);
    
    Whenever a memory location is accessed in the user's program, the page table is consulted to find what the physical address of that memory location is. If the valid field is set, then the address is at the page denoted by physicalFrame. Note that this is a page number. In other words, if physicalFrame is i, then the page begins at main_memory+i*PageSize.

    If the valid field is not set, then JOS will get control in exceptionHandler(), with the which argument set to PageFaultException, and with the faulting address in register BadVAddrReg (see simulator.h). If the page is not legal (see lazy sbrk() and stack allocation below), this means you should terminate the program (seg fault).

    If you run out of memory, you must suspend the process asking for memory until another process frees some or dies. This requires a little care in your implementation. Can this deadlock the OS? Yes! Can you detect it? Yes!! Should you deal with this and fix it? Yes!!!!!!! How? By selecting a victim process and killing it. Here's how you should select a victim -- memory is allocated in the following places, so here is how you should deal with victims:

    Other changes

    The following procedures have been added or modified to work with page tables:

    With paged virtual memory you must be aware that logically contiguous data may not be contiguous in physical memory. For example, a buffer on your stack might span separate, non-contiguous physical pages. You will need to deal with this issue in system calls such as read(), write(), pipe(), and execve() -- anything that copies data into or out of process memory other than through a register. Ioctl(), and fstat() are also included in this group but we have the following functions that will correctly write data to memory using a page table.

    As with the load function, these functions expect that the pages referenced are valid. Results are undefined if a referenced page is not valid.

    Lazy sbrk() and stack allocation

    You should implement sbrk() in a lazy fashion: sbrk() should simply mark somewhere (in the page table will be a good place) that the page is ok, but set the valid bit to zero. Then grab a page frame for the pages when they page fault.

    Treat the stack in this manner too -- i.e. only allocate as many frames as you need, and let the stack grow by page faulting. You may assume that any page fault within 10K bytes of the current top of the stack is a legal memory reference in the stack.

    This means that the following page faults should turn into segmentation violations:


    No ``WHAT_DR_PLANK_DID'' file

    You're on your own to design the solution to this lab. Even your Aunt Heloise wants you to ride your own two-wheeler without training wheels on this one. She does have a couple of suggestions.
    1. Start with the argtest program and not with jsh right away. Think about what you are going to do to write the argv[] and argc values out to the stack of the program. Shouldn't the pages be valid? How many will you need?
    2. Now do real paging. Only allocate however many pages the process needs. Make fork(), execve and sbrk() work correctly. Test again. When a process touches a page, you will catch a page fault through the exception handler. Handle the exception.