Assignment 8, Solutions

Part of the homework for 22C:112, Fall 2012
by Douglas W. Jones
THE UNIVERSITY OF IOWA Department of Computer Science

  1. Background: In class, we discussed using "soft page faults" to set the state of a page from "unmarked" to "marked" in support of the clock page-replacement algorithm. (As traditionally stated, clock replacement relies on the MMU hardware to set the "mark bit" on each page frame when the CPU references the page in that frame.)

    The software version uses a second set of access rights bits on each page, called the real access rights, known only to software. The hardware access rights are known to the MMU and may be set more restrictively than the real access rights. For example, when a page is "unmarked" the hardware access rights are set to "no access" in order to cause a soft page fault so that the page can be marked. There is no need for a mark bit in the software version. Instead, if the software access rights don't equal the hardware access rights, the page is unmarked, and if they are equal, the page is marked.

    If the page in some page frame has not been changed since the last time it was copied from disk to RAM, there is no reason to copy it back to disk because the copy there is still correct. Therefore, some MMU hardware has been built with a second bit on each page frame, the clean-dirty bit. When a page is copied from disk to RAM, the page frame is marked as clean. If the CPU writes data to that page, the frame is marked as dirty. There is no need to copy clean pages back to disk. In effect, pages have 3 useful states: unmarked, marked-but-clean and marked-and-dirty.

    For this problem, assume that the access rights have the following 4 values: none, read-only, read-execute, and read-write-execute. Assume that the MMU has no knowledge of clean versus dirty pages or marked versus unmarked pages.

    a) Give a 4 by 4 matrix with the real access rights as labels on rows and the hardware access rights as labels on the columns. For each combination of real and hardware access rights, indicate whether that combination indicates an unmarked page, a marked-but-clean page, or a marked-and-dirty page. Note that some combinations should never occur. Put an X in those matrix entries. (0.5 points)

    Hardware Rights
    None RO RX RWX
    Real
    Rights
    None * X X X M = Marked
    C = Clean
    D = Dirty
    RO UC MC X X
    RX UC X MC X
    RWX UC X MC MD

    The entry marked * in the above table does not participate in this question. If the real access rights are "None" for a page, and the process accesses that page, the process should be killed or it should throw an exception.

    b) Give a 4 by 4 matrix just like the above, but this time, for each entry, if that combination is found on entry to the page fault service routine, is this a real page fault, or is it a soft page fault. For the entries that are soft page faults, indicate the new value that the page-fault service routine should put in the hardware access rights. (0.5 points)
    Hardware Rights
    None RO RX RWX
    Real
    Rights
    None * X X X F = real page fault
    RO F/RO * X X
    RX F/RX X * X
    RWX F/RX X RWX *

    Entries marked * in the above table do not participate in this question. For these entries, any trap forced by the MMU reflects a real access rights violation by the user program.

    The distinction between real page faults and soft page faults when the hardware rights say "None" must rest on data not described here, for example, an extra bit in the page table indicating whether the indicated page is in a page frame in RAM or is on disk.

  2. A problem: Consider the linux mmap(), execve() and open() system calls. Use man 2 mmap for example, to get documentation.

    Assume that the object file itself begins with a header giving:

    And, assume that the linker guarantees that the offsets above are integer multiples of the page size and of the sector size, both of which are powers of two.

    a) Give code appropriate for the body of the execve() system call to open the object file in preparation for loading. (0.2 points)

    fd = open( filename, O_RDEXEC );
    

    Note that something like O_RDEXEC must exist, although user programs can only demand O_RDONLY.

    b) Give code appropriate for the body of the execve() system call, in the context of the code you just gave, that uses mmap() to "load" the code segment by mapping it to the correct part of the object file. (0.4 points)

    read( fd, header, sizeof(struct header) );
    mmap( header.codeva, header.codesize, PROT_READ | PROT_EXEC,
            MAP_FIXED | MAP_SHARED, fd, header.codeoffset );
    

    c) Give code appropriate for the body of the execve() system call, in the context of the code you just gave, that uses mmap() to "load" the static segment by mapping it to the correct part of the object file. This must be different from part b) for two reasons: The access rights needed to the static segment are different, and the sharing relationship between the (different) processes running the same program are different. (0.4 points)

    /* assume header has been read */
    mmap( header.staticva, header.staticsize, PROT_READ | PROT_WRITE,
            MAP_FIXED | MAP_PRIVATE, fd, header.staticoffset );
    

  3. Background: All of the algorithms for implementing malloc() and free() (or their equivalents in other programming languages) depend on the ability to do arbitrary arithmetic on pointers. Consider the following C declarations, which assume that the constant HEAPSIZE has a positive integer value:
            char heap[HEAPSIZE];
            char * free = heap;
    

    A Problem: Write code for malloc(s), where s is the size of the object to be allocate, so that it operates by returning the prior value of free, which it then increments by s bytes. Your code should be fully compatible with the standard malloc() except that there is no support for free(). (1 point)

    void * malloc( int s ) {
            void * new = free;
            char * next = free + s; /* works with free declared as char * */
            if (next < &heap[HEAPSIZE]) { /* there is space */
                    free = next;
                    return new;
            } else { /* there is not enough space */
                    return NULL;
            }
    }