Quite frankly, virtual memory as we have presented it earlier in this chapter is not easy to use. Operating systems, compilers and other programs need to "chunkify" memory in order to assign different protections, names and other properties to it. If virtual memory is just one huge chunk, this "chunkification" must be done by the program and is very hard to get right.
All modern computers break their virtual memory space into chunks called segments. Each segment represents one conceptual piece of memory. For example, a compiler assigns the heap to one segment, the run-time stack to another, the code to yet another and so forth. Each segment can have its own protection scheme so that the code can be readable, but not writable, while the stack and heap are both readable and writeable. Some segments may be write-only, such as a mailbox into which a program could write a message, but not read existing messages.
The way segments are merged with virtual memory is to treat each segment as its own little paged virtual memory, complete with its own page table. Segments are identified by number, starting with 0. Pages within segments are identified by number, too, but the concatenation of segment number + page number is unique.
A new table, the segment table, must exist in order to tell the computer where the page tables are to be found. Fig. 12.10.1 illustrates this:
There is one Segment Table Base Register (STBR) for the entire machine. It points to the segment table (which may be in ordinary RAM or some special high-speed RAM or register set.) To get to the right page table, the segment number is taken out of the virtual address. In Fig. 12.10.1, this is the top 9 bits of the virtual address. This number is added to the address in STBR to give the address of the right pointer in the segment table. This pointer points to the page table for that segment.
The various page tables may be in main memory, or in special high-speed RAM, or in special registers. However, a page table is much larger than the segment table, and there are many page tables. If 9 bits are devoted to the segment number, then there may be up to 29 segments, or 512 of them! If there are 11 bits in the page number, there may be 211, or 2048, pages for each segment. A given program may not need more than a few segments, however, so not that much memory may be needed for these tables. However, they may consume vast quantities of memory in the worst case.
Once the correct page table is found, the page table entry is consulted and the usual mechanism of examining the present/absent bit, the dirty bit and other data is invoked. If the page is not in RAM, a page fault occurs. If the page table is full, a victim must be found.
Speed is obviously sacrificed by having a two-layer virtual memory such as this. Some chips even have more than 2 levels! But the principle of locality saves the day, along with a translation lookaside buffer to remember the most recently translated addresses. See section 12.7 for details. In a segmented paged virtual memory, such as the one in Fig. 12.10.1, the combination of segment number/page number is used as the search key, with the actual frame number of RAM being the result. Then the offset within the page is tacked onto the end.
In Fig. 12.10.2, the TLB is inserted, showing how it speeds up this complex virtual memory system by bypassing the multi-step translation process if the virtual address has been translated recently.
The MMU is shown in gray. It comprises the entire virtual address translation system, except that page tables are often so large that they must be stored in RAM itself. This is why they are surrounded in yellow. However, some older systems cache the page tables in special high speed memory or registers.