CS 111 Lecture 14: Virtual Memory

March 4, 2013

by Sidney Chan


Our Next Problem: Unreliable processes with bad memory references

     We've had these problems since the 1950s.

Some possible solutions include:

Why can't we just do runtime checks?

We need help from the hardware to do subscript checking, so the hardware will check the memory references.

Simple approach: 2 extra registers, base and bounds                   
We have a hardware check for each memory access. If you access outside your bounds you trap and the kernel can decide what to do.

Problems with this simple approach:


Suppose you're running a sort program and you want to run two instances at the same time:
                       
To fix the absolute-address pointer, you can:
Suppose the program changes the base or bounds.

Suppose you want processes to share memory.

If you have only 2 processes you can pull this off, but this won't scale to larger numbers.
                        map_domain( [size], [permissions] )
                                                            x (execute)
                                                            rx (read-execute)
                                                            w (we can have this, but it's unusual)
                                                            _ (for kernel use only)
                                                            rwx
                                                            ...

Traditional x86 does r, w, but not x.

Problem: If you have an arbitrary amount of base-bounds pairs, say 4, this will not be enough domains. There are many possible uses for a domain, including: text of a program (r), data of a program (rw), heap (rw), stack (have 1 per thread), I/O buffers, shared memory. We have many uses for a base-bound pair.

Segmentation (segmented memory)



We choose a base-bounds pair from a segment table. Privilege is needed to change the segment table. The segment number is used to identify the segment, along with an offset within the segment. Each entry in the table includes information such as its base, bounds, permissions, and so on.


Problems


Page-based Memory Management: the solution for segmented memory


 

Linear page tables 


With linear page tables, we have a page table that holds multiple page table entries (PTE). In our example, the table holds 2^20 entries of 4 bytes each, meaning that each process has a page table of 4 MiB.


                int pmap (int v)
                {
                        return PAGE_TABLE[v]; // this is stored in priviliged register %cr3
                }


2-level page tables



Here, instead of using the full 20 bits for page numbers, we use the first 10 bits for the first level page table and the next 10 bits for the next level. With two levels, we now have a more complicated pmap function.

                int pmap (int v)
                {
                        int hi = v >> 10;
                        int lo = v & (1 << 10) - 1;
                        pt *p = PAGETABLE[hi];
                        if(!p)
                                return 0;
                        return p[lo] >> 8;
                }


                      

Mechanism for page faulting

When we page fault, we trap and enter the kernel. The kernel inspects the faulting address.

        void pfault(int v, int access, ... )
        {
                if(swapmap(v, current_process) == FAIL) // if bad address, eg. derefence a null pointer or subscript error
                        kill(current_process);
                else // valid address
                {
                        (p, va) = removal_policy();
                        pa = p->pmap(va); // pa: physical address
                        p->pmap(va) = FAULT; // tell that the page doesn't exist anymore
                        write(pa, swapmap(p, va));
                        read(pa, swapmap(currentprocess, v);
                        currentprocess->pmap(v) = pa;
                }
        }

What can we do wrong?

Virtual Memory Tuning

How can we optimize the dirty bit so we don't have to store 2 positions in RAM?