IA32 Paging Scheme Introduction to the Pentium’s support for “virtual” memory A quick review • • • • • We’ve learned how to create ‘/proc’ files We wrote a simple device-driver: ‘dram.c’ We displayed a task’s page-directory We looked at Linux’s ‘mem_map[]’ array Now we want to understand the ‘kmap()’ function, used by modules to get a virtual address for any physical page-frame ‘Traditional’ Linux 0x38000000 (896MB) 0x00000000 HIGH MEMORY NORMAL MEMORY Kernel space 1G User space 3G Physical addresses Most of the kernel’s 1GB address-space is directly mapped to physical RAM at all times But mappings to the ‘high memory’ page-frames are, by definition, only temporarily available and are not mapped according to a predictable rule Virtual addresses How ‘mappings’ work • There are two aspects to consider: – the Pentium’s address-translation mechanism – the policies Linux applies to CPU capabilities • Example of this distinction: – The ‘page-directory’ array is a Pentium object – The ‘mem_map’ array is a Linux data-object Control Register 4 This register consists of bits that enable various architectural extensions to the standard features of the Pentium processor, including two that affect virtual-to-physical memory mapping. 31 5 4 0 P P A S E E Legend: PSE = Page-Size Extensions (1=enabled, 0=disabled) PAE = Page-Address Extensions (1=enabled, 0=disabled) Recall that we saw our classroom workstations had CR4 = 000006D0 Two-Level Translation Scheme PAGE DIRECTORY CR3 PAGE TABLES PAGE FRAMES Control Register 3 31 12 Page-directory base-address 4 3 P P C W D T The ‘page-directory base-address’ field holds the upper 20 address-bits of a physical page-frame that contains the current task’s page-directory entries; the lower 12 address-bits of any page-frame are zeros, of course, so can be used by the processor for other purposes (i.e., PCD [bit 4] and PWT [bit 3]: PWT = Page Write-Through (1=yes, 0 = no) PCD = Page Cache-Disable (1 = yes, 0 = no) Your ‘/proc/cr3’ pseudo-file • Recall that you created a kernel module (named ‘cr3.c’) which allows applications to obtain the current value in register CR3 • This CR3 value gives the physical address for the current task’s page-directory, if the ‘traditional’ 3G/1G user-kernel mapping is employed (but not with the 4G/4G “patch”) • Using ‘fileview’ you saw a page-directory! Format of a Page-Directory entry 31 PAGE-TABLE BASE ADDRESS 12 11 10 9 8 7 6 5 4 3 2 1 0 P P P AVAIL G 0 A C W U W P S D T LEGEND P = Present (1=yes, 0=no) W = Writable (1 = yes, 0 = no) U = User (1 = yes, 0 = no) A = Accessed (1 = yes, 0 = no) G = Global (1 = yes, 0 = no) PS = Page-Size (0=4KB, 1 = 4MB) PWT = Page Write-Through (1=yes, 0 = no) PCD = Page Cache-Disable (1 = yes, 0 = no) Format of a Page-Table entry 31 PAGE-FRAME BASE ADDRESS 12 11 10 9 8 7 6 5 4 P AVAIL G 0 D A C D LEGEND P = Present (1=yes, 0=no) W = Writable (1 = yes, 0 = no) U = User (1 = yes, 0 = no) A = Accessed (1 = yes, 0 = no) D = Dirty (1 = yes, 0 = no) G = Global (1 = yes, 0 = no) PWT = Page Write-Through (1=yes, 0 = no) PCD = Page Cache-Disable (1 = yes, 0 = no) 3 2 1 0 P W U W P T kernel mappings • The ‘kmap()’ function is used by modules to obtain the virtual address for a physical page-frame: void * kmap( struct page * page ); • On systems with 1GB of installed memory, the majority of physical page-frames are permanently mapped to kernel addresses, but page-frames in ‘high’ memory can only be ‘temporarily’ mapped into kernel space Normal page-mapping • For a virtual address in kernel space that is below the high-memory start-address, the corresponding physical address can be gotten by a simple subtraction: phys_addr = virt_addr – PAGE_OFFSET • Recall: PAGE_OFFSET = 0xC0000000 Mapping ‘high’ memory • For addresses in kernel space in the range from 0xF8000000 to 0xFFFFFFFF there might be no current mapping to ram • So the action of the ‘kmap()’ function must be more complex in these cases (i.e., it’s necessary to create a temporary mapping if it happens one does not already exist) A limited number of kmaps • In kernel 2.6 there is only one page-table that is reserved for ‘kmap()’ to use when temporary mappings into high-memory need to be created • This is called the ‘kmap_page_table’ • Its page-table entries are forever changing as kernel code calls the functions ‘kmap()’ and ‘kunmap()’ PKMAP_BASE • We can watch the ‘kmap_page_table’ as it undergoes these dynamic changes – if we know where to find it in physical memory • We can do a ‘page-table walk’ to locate it • There are 1024 virtual page-frames used for temporary ‘kmap()’ addresses, starting with the virtual address PKMAP_BASE In-class exercise #1 • Use the ‘init_mm.c’ module to locate the page-directory belonging to the ‘init’ task • Use ‘fileview’ to see these directory entries • Determine the value of PKMAP_BASE • Which directory-entry contains the address of the ‘pkmap_page_table’? (It’s the entry that ‘maps’ virtual-address PKMAP_BASE to a page-frame in physical memory) In-class exercise #2 • Use the result from your ‘page-table walk’ to assign the correct value to ‘zone_base’ in our ‘kmapsnow.cpp’ demo-program • Run the ‘kmapsnow’ in one window while you execute some other commands from inside a different window, to view changes in the set of currently active kmaps • Log in remotely from an adjacent station