Class 14 CS 439 28 Feburary 2013 On the board ------------ 1. Last time 2. [last time] paging in general 3. paging on the x86 --[last time] page tables --[last time] TLB --JOS memory map 4. page faults --------------------------------------------------------------------------- 1. Last time --paging! --clarify offset versus page number --------------------------------------------------------------------------- potentially useful reference: 4KB = 2^{12} = 0x00001000 = 0x00000fff + 1 4MB = 2^{22} = 0x00400000 = 0x003fffff + 1 256 MB = 2^{28} = 0x10000000 = 0x0fffffff + 1 4GB = 2^{32} =0x100000000 = 0xffffffff (+1) = ~0x00000000 (0xef400000 >> 22) = 0x3bd = 957 (0xef800000 >> 22) = 0x3be = 958 (0xefc00000 >> 22) = 0x3bf = 959 (0xf0000000 >> 22) = 0x3c0 = 960 --------------------------------------------------------------------------- B. TLB, continued --questions: --does TLB miss imply page fault? [what's a page fault?] --does the existence of a page fault imply that there was a TLB miss? C. memory in JOS --segments only used to switch privilege level into and out of kernel --paging structures the address space --paging limits process memory access to its own address space --see handout for JOS virtual memory map --why are kernel and current process both mapped into address space? --convenient for kernel --why is all of physical memory mapped at the top? that must mean that there are physical memory pages that are mapped in multiple places.... --need to be able to get access to physical memory when setting up page tables: *kernel* has to be able to use physical addresses from time to time --what the heck is UVPT? ...... --remember how we wanted a contiguous set of entries? --wouldn't it be awesome if the 4MB worth of page table appeared inside the virtual address space, at address, say, 0xef400000 (which we call UVPT)? --to do that, we sneakily insert a pointer in the pgdir back to the pgdir itself, like this: 1023 | | ..... ........ 960 | | 959 | <...> | 958 | <...> | 957 | self.. U | .... 0 | ........ not present| --result: the page tables *themselves* show up in the program's virtual address space --in more detail, the virtual address space looks like this: [0xef400000,0xef800000) --> looks like one contiguous page table, visible to users. read only to user ; r/w to kernel. more specifically: the picture of [UVPT,UVPT+4MB) in virtual space is: UVPT+4MB __________________ PGTABLE 1023 __________________ . . . __________________ PGTABLE 2 __________________ PGTABLE 1 ___________________ PGTABLE 0 UVPT ___________________ --QUESTION: * where does the pgdir itself live in the virtual address space? --0xef400000 ? --0xef400000 + 4KB ? --0xef400000 + 4KB * 957 ? --in JOS, user processes can see their own page tables, but we will set the R/W bit to 0 so that they cannot modify them --something it is probably worth internalizing: one of the things that a second-level page table is doing is to take as many as 1024 disparate physical pages, perhaps scattered throughout RAM, and then glue them together in a logical way, making them appear as a contiguous 4MB region in virtual space (just as the entire page structure glues disparate physical pages into a 4GB "region"). if the second-level page table that is chosen for this gluing is the page directory itself, then the disparate physical pages that all appear as a contiguous 4MB region wind up being the page tables themselves --with the above as background, here is further detail on the JOS implementation trick: this works because the page directory has the same structure as a page table and because the CPU just "follows arrows", namely: (1) From the relevant entry in the pgdir [which entry, recall, covers 4MB worth of VA space] to the physical page number where the relevant page table lives (2) From the physical page number where the relevant page table lives, more specifically the relevant entry in the relevant page table (which is relevant to 4KB of address space), to the physical page number that is the target of the mapping. now, if you "trick" the CPU into following the first arrow back to the pgdir itself, and the program references an address 0xef400000+x, where x < 4MB, then the logic goes like this (compare the exact words below to the exact words of the numbered items above): (1) From the relevant entry in the pgdir [which entry, recall, is covering the 4MB worth of VA space from [0xef40000,0xef800000)] to the physical page number where the page directory lives (2) From the physical page number where the page directory lives, more specifically the relevant entry in the page directory (which now is relevant to only 4KB of address space), to the physical page number that is the target of the <0xef40000+x,PA> mapping. that physical page holds a second-level page table! result: the second-level page table appears at 0xef40000+x 3. Continuing with paging and JOS memory map --two classes ago: virtual memory on the x86 is implemented first via a segment translation and second by a paging translation --above we discussed: --how the processor actually maps from virtual page to physical page when a process does a load or store, which in turn determined: --what data structures the operating system must set up for the processor --here are some points to reinforce the ideas: --KEY IDEA IN VIRTUAL MEMORY: **OS inserts appropriate entries in the page directory and page table, and then the program, or the OS itself, can reference the address** --the above is a powerful thing. it amounts to the ability to manufacture (and remove) opaque handles on the fly, just by inserting and removing entries in the mapping. --the program itself can make such requests implicitly (as it page faults) or explicitly (via mmap, which can be told to fail if it can't create a particular entry in virtual space). --the OS can certainly proactively set up the virtual address space for the program --example #1 of the KEY IDEA: if OS wants a program to be able to use address 0x0040 2000 to refer to physical address 0x0a37 0000 but in a read-only way, the OS, conceptually speaking, creates an entry <0x00402000, 0x0a370000> That mapping is implemented like this: PGDIR ............ <20 bits> <12 bits> ............ | a370 | W=0 | [entry 2] | | | [entry 1] .....[entry 1] ----> |________|_________| [entry 0] ........ --example #2 of the KEY IDEA: recall that JOS itself maps physical memory at the top of the virtual address space (ask yourself how this works) --see handout: everything above KERNBASE --conclude: any physical memory that is in use is actually mapped in multiple places --why does the kernel do this? because the kernel needs to be able to get access to physical memory when setting up page tables: *kernel* has to be able to use physical addresses from time to time. common use: setting up page directories and page tables --example #3 of the KEY IDEA: UVPT. this is a virtual address where the entire page structure appears to the OS and user-level processes --see handout: UVPT --see notes from last time about how this is implemented --if you truly understand how and why this implementation trick works -- and what it's accomplishing -- then you understand the important pieces of virtual memory. 4A. Page faults: mechanics --what happens if the address isn't in the page table or there is a protection violation? [page fault!] --NOTE: TLB MISS != PAGE FAULT --not all TLB misses generate page faults, and not all page faults began with TLB misses (on a store instruction, when might an appropriate entry be in the TLB but there is a still a page fault? what about on a load instruction?) --what happens on the x86? [see handout] --kernel constructs a trap frame and transfers execution to an interrupt or trap handler ss esp [former value of stack pointer] eflags [former value of eflags] cs %esp--> eip [instruction that caused the trap] [error code] %eip is now executing code to handle the trap [how did processor know what to load into %eip?] error code: [ ................................ U/S | W/R | P] unused U/S: user mode fault / supervisor mode fault R/W: access was read / access was write P: not-present page / protection violation on a page fault, %cr2 holds the faulting linear address idea is that when page fault happens, the kernel sets up the process's page entries properly, or kills the process