130 likes | 300 Views
Linux ‘Demand-Paging’. Using ‘nopage()’ with ‘mmap()’. Recall ‘mysis.c’ device-driver. Demonstrated the ‘mmap()’ driver-method Used ‘remap_page_range()’ function Mapped video frame-buffer to user space Set up all page-table entries in advance Driver was tested using ‘mmwhere.cpp’
E N D
Linux ‘Demand-Paging’ Using ‘nopage()’ with ‘mmap()’
Recall ‘mysis.c’ device-driver • Demonstrated the ‘mmap()’ driver-method • Used ‘remap_page_range()’ function • Mapped video frame-buffer to user space • Set up all page-table entries in advance • Driver was tested using ‘mmwhere.cpp’ • NOTE: A flaw was spotted by Qing Huang • A revised version now posted on website
Deferring page-table setups • An alternative ‘mmap()’ driver-method • Don’t set up all page-tables in advance • Many entries might never be needed • Waste of cpu time to build unused entries • Our frame-buffer may span 128 MB • Each page-directory entry controls 4 MB • So there may be 32 (=128/4) page-tables! • Our screen display needs less than 8 MB
Linux ‘nopage()’ mechanism • Avoids using ‘remap_page_range()’ • Requires a ‘vm_operations_struct’ object • This object contains ‘callback’ functions • The main one is named ‘nopage()’ • We can implement a ‘nopage()’ method • It will get called by the ‘page_fault’ handler • It can set up a needed page-table entry
Prototype for ‘nopage()’ struct page * my_vma_nopage( struct vm_area_struct *vma, unsigned long address, int write_access );
Less to do for ‘mmap()’ • In device-driver’s ‘mmap()’ method: • Does not call ‘remap_page_range()’ • Installs ‘callback’ functions instead: vma->vm_ops = &my_vm_ops;
Demo: ‘mynopage.c’ • A working example is on course website • It can be tested using ‘mmwhere.cpp’ • Changes are ‘transparent to application • But offer improved efficiency inside kernel • Less memory consumed by page-tables • Less processor time used for table setups
An idea for further efficiency • Bypass ‘mmap()’ mechanism altogether • Use Pentium’s ‘Page-Size Extensions’ • Use page-directory entries for 4MB frames • Avoids allocating/initializing page-tables • Avoids creating/inserting ‘vm_area_struct’ • Mapping done by driver’s ‘open()’ method • Unmapping is done by ‘release()’ method
Page-Directory is modified • Where is task’s page-directory located? long *pgdir = current->mm->pgd; • Which directory-entries do we modify? • What page attributes should we assign? • Demo maps frame-buffer to 0x10000000 • Why? It seems kernel won’t contend this
Loop to setup directory entries long physaddr = fb_base; long virtaddr = 0x10000000; long entry_index = (virtaddr >> 22); long entry_count = (fb_size >> 22); for (i = 0; i < entry_count; i++) { pgdir[ entry_index ] = physaddr | 0x87; physaddr += (1<<22); ++entry_index; }
‘mmtest.cpp’ • Simple application to test ‘mymmfb.c’ • It opens the device file ‘/dev/vram’ • It uses ‘lseek()’ to get frame-buffer’s size • Then it directly writes to the frame-buffer • It uses the agreed-upon virtual-address: long *vram = (long)0x10000000;
Is this a ‘safe’ approach? • Can we create a confliting application? • We could read the Linux source-code • Or we could perform some experiments! • Try using ‘malloc()’ to allocate regions • See if any regions overlay our frame-buffer • But how would we know if they did?