PB173 - Ovladače jádra - Linux IX. Jiri Slabý ITI, Fakulta Informatiky 29. 11. 2012 J. Slabý (ITI) PB173/06 29. 11. 2012 1 / 12 Paměť jinak I. LDD3 kap. 15 (zastaralá) • I. (dnes): Mapování paměti jádra (mmap) a II. (příště): Přímý přístup do paměti (DMA) J. Slabý (ITI) PB173/06 29.11.2012 2/ 12 Mapování paměti jádra Předání dat do/z procesu • Známe: read, write, ioctl, .. . • U všeho nutné kopírování dat • copy_{f rom, to}_user apod. Mapování paměti • Namapování stránek do procesu • Proces používá kus stejné paměti jako jádro • Syscall: mmap 29. 11. 2012 3/ 12 mmap • V userspace volání mmap • void *mmap(void *addr, size.t len, int prot, int flags, int fd, off.t off) • V jádře jeden Člen V struct f ile_operations • int mmap(struct file *filp, struct vm_area_struct *vma) • Parametry JSOU V struct vm_area_struct J. Slaby (ITI) PB173/06 29. 11. 2012 4/ 12 Úkol Alokace pomocí mmap (uživatelský prostor) O Anonymní paměť • void *mmap(void *addr, size.t len, int prot, int flags, int fd, off-t off) • len .. . 20M • prot . . . PROT_READ a PROT_WRITE • flags . . . MAP .PRIVÁTE a MAP_ANONYMOUS • fd . . . -1 O Mapování /dev/zero • flags . . . MAP .PRIVÁTE • f d ... deskriptor otevřeného /dev/zero J. Slabý (ITI) PB173/06 29. 11. 2012 5/ 12 Parametry mmap Prototyp (znovu): void *mmap(void *addr, size_t len, int prot, int flags, int fd, off.t off) • JSOU V jádře uloženy V struct vm_area_struct struct vm.area.struct { unsigned long vm.start; /* addr or random when addr is NULL */ unsigned long vm.end; /* vm.end = vm.start + len */ unsigned long vm.pgoff; /* vm.pgoff = of f/PAGE.SIZE */ unsigned long vm.flags ; /* vm.flags = encoded(flags | prot) */ pgprot.t vm.page.prot; /* only for remap.* functions */ const struct vm.operations.struct *vm_ops; /* later ... */ void *vm_private.data ; } Je třeba namapovat stránky mezi vm_start a vm_end. Ale také ověřit privilegia (čtení, zápis, spuštění). J. Slabý (ITI) PB173/06 29. 11. 2012 6/ 12 Základní mmap funkce API • linux/mm.h, struct vm_area_struct • __get_f ree_page/pages =4> remap_pfn.range • vmalloc_user =4> remap.vmalloc.range int my.init (void) { mem = ..get.free.pages (GFP.KERNEL, 2); /* mem = vmalloc.user(PAGE.SIZE) ; */ } int my_mmap( struct file *filp , struct vm.area.struct *vma) { if ((vma->vm.flags & (VM.WRITE | VM.READ)) != VM.READ) return -EINVAL; return remap.pfn.range (vma, vma->vm.start , virt.to.phys (mem) » PAGE.SHIFT, 4 * PAGE.SIZE, vma->vm_page.prot) ; /* return remap.vmalloc.range (vma, mem, 0); */ } J. Slaby (ITI) PB173/06 29. 11. 2012 7/ 12 Úkol Přemapování prostorů O Alokovat 2stránku (vmalloc) a 2stránku (page alokátory) O Zapsat na všechny 4 stránky libovolný ale různý řetězec 0 Přemapovat stránky v mmap • První dvojice RO, druhá R/W • 0 < pgof f <2=> jedno mapování • 2 < pgof f druhé mapování 0 Z userspace 2 x mmap s off 0 a 2*4096 • Již hotovo v pb173/09 API znovu • linux/mm.h, struct vm_area_struct • int mmap(struct file *filp, struct vm_area_struct *vma) • __get_f ree_page* =4> remap_pfn.range • vmalloc_user =4> remap_vmalloc_range J. Slabý (ITI) PB173/06 29.11.2012 8/ 12 mmap po stránkách Přemapování roztroušených stránek • Přes remap_pf n_range obtížně • Při výpadcích stránek se mapují tyto stránky jednotlivě • Každý ovladač má „page fault handier" • Stará jádra: nopage • Nová jádra: fault • V mmap/nopage/f ault je třeba zkontrolovat rozsahy a velikosti • Před tím to dělaly remap_*_range funkce • vma->vm_ops • Struktura ukazující na háčky (včetně nopage/f ault) • vma->vm_private_data • Pro naše potřeby • K předání informací z mmap do vm_ops J. Slabý (ITI) PB173/06 29. 11. 2012 9/ 12 mmap po stránkách (ponovu) Nové API struct vm.operations.struct { void (*open) (struct vm.area-Struct *vma) ; void (* close )( struct vm.area.struct *vma) ; int (* fau It)(struct vm.area.struct *vma, struct vm.fault *vmf) ; } int my.fault (struct vm.area.struct *vma, struct vm.fault *vmf) { /* my.data == vma->vm_private.data ; */ unsigned long offset = vmf->pgoff « PAGE.SHIFT; struct page *page; page = my.find.page ( offset) ; if (Ipage) return VM.FAULT.SIGBUS; get.page(page) ; vmf->page = page; return 0; } int my_mmap( struct file *filp , struct vm.area.struct *vma) { /* don't forget to check ranges */ vma->vm_ops = &my_vm_ops; vma->vm.private-data = my.data; return 0; } J. Slaby (ITI) PB173/06 29. 11. 2012 10/ 12 mmap po stránkách (postaru) Stare API struct vm.operations.struct { struct page (*nopage) (struct vm.area.struct *vma, unsigned long address , int *type) } struct page *my.nopage( struct vm.area.struct *vma, unsigned long address, int *type) { /* my.data = vma->vm_private.data ; */ unsigned long offset = vma->pgoff « PAGE.SHIFT; struct page *page; offset += address - vma->vm_start; page = my.find.page ( offset) ; if (!page) return NOPAGE.SIGBUS; get.page(page) ; if (type) *type = VM_FAULT_MINOR; return page; } J. Slaby (ITI) PB173/06 29. 11. 2012 11 / 12 Úkol Mapování roztroušených stránek (domácí) O Předchozí příklad rozšiřte O Místo alokací 2stránek alokovat 4 samostatné stránky O Přemapovat stránky v mmap • Změna remap_pf n.range na vma->vm_ops->nopage O Userspace program stejný (funkčnost navenek stejná) Potřebné podkroky • Definice int fault(struct vm_area_struct *vma, struct vrrufault *vmf); • Popr. Staré struct page *nopage (struct vm_area_struct *vma, unsigned long address, int *type) • Kontrola rozsahů v mmap (end-start < 2*page_size apod.) a Definice vm_ops a přiřazení do vma->vm_ops J. Slabý (ITI) PB173/06 29. 11. 2012 12/ 12