This shows you the differences between two versions of the page.
so2:laboratoare:lab11 [2014/05/04 22:51] daniel.baluta |
so2:laboratoare:lab11 [2017/05/07 19:19] (current) octavian.purdila update lxr links to use 4.9 |
||
---|---|---|---|
Line 18: | Line 18: | ||
===== Materiale ajutătoare ===== | ===== Materiale ajutătoare ===== | ||
- | *[[http://elf.cs.pub.ro/so2/res/laboratoare/lab12-slides.pdf|Slide-uri de suport pentru laborator]] | + | *[[http://elf.cs.pub.ro/so2/res/laboratoare/lab11-slides.pdf|Slide-uri de suport pentru laborator]] |
*[[http://elf.cs.pub.ro/so2/res/extra/so2_reference.pdf|SO2 Reference Card]] | *[[http://elf.cs.pub.ro/so2/res/extra/so2_reference.pdf|SO2 Reference Card]] | ||
Line 25: | Line 25: | ||
În kernel-ul Linux există posibilitatea mapării unui spaţiu de adresă kernel într-un spaţiu de adresă utilizator. În acest fel se elimină overhead-ul datorat copierii informaţiei din user-space în kernel-space (şi invers). Acest lucru poate fi realizat prin intermediul unui device driver şi a interfeţei dispozitiv (''/dev'') a acestuia în user-space. | În kernel-ul Linux există posibilitatea mapării unui spaţiu de adresă kernel într-un spaţiu de adresă utilizator. În acest fel se elimină overhead-ul datorat copierii informaţiei din user-space în kernel-space (şi invers). Acest lucru poate fi realizat prin intermediul unui device driver şi a interfeţei dispozitiv (''/dev'') a acestuia în user-space. | ||
- | Această facilitate poate fi folosită prin completarea operaţiei [[http://lxr.linux.no/linux+v3.13/include/linux/fs.h#L1532|mmap]] din structura [[http://lxr.linux.no/linux+v3.13/include/linux/fs.h#L1521|struct file_operations]] asociată dispozitivului şi utilizând apelul ''mmap'' din user-space. | + | Această facilitate poate fi folosită prin completarea operaţiei [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/fs.h#L1708|mmap]] din structura [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/fs.h#L1696|struct file_operations]] asociată dispozitivului şi utilizând apelul ''mmap'' din user-space. |
==== Structuri de lucru cu memoria ==== | ==== Structuri de lucru cu memoria ==== | ||
Line 31: | Line 31: | ||
Înainte de a discuta despre mecanismul de memory-mapping peste un dispozitiv, vom prezenta câteva din structurile de bază legate de subsistemul de management al memoriei în kernel-ul Linux. | Înainte de a discuta despre mecanismul de memory-mapping peste un dispozitiv, vom prezenta câteva din structurile de bază legate de subsistemul de management al memoriei în kernel-ul Linux. | ||
- | Cateva din structurile importante sunt: [[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L44|struct page]], [[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L241|struct vm_area_struct]] şi [[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L344|struct mm_struct]]. | + | Cateva din structurile importante sunt: [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L45|struct page]], [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L300|struct vm_area_struct]] şi [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L396|struct mm_struct]]. |
==== Structura ''page'' ==== | ==== Structura ''page'' ==== | ||
- | Structura [[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L44|struct page]] este utilizată pentru a încorpora informaţii despre toate paginile fizice din sistem. Kernel-ul deţine o structură ''struct page'' pentru toate paginile din sistem. | + | Structura [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L45|struct page]] este utilizată pentru a încorpora informaţii despre toate paginile fizice din sistem. Kernel-ul deţine o structură ''struct page'' pentru toate paginile din sistem. |
- | + | ||
- | Printre câmpurile importante ale acestei structuri amintim: | + | |
- | *[[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L117|_count]], contorul de utilizare al paginii; când acesta devine 0 pagina este adăugată la lista de pagini libere; | + | |
- | *[[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L180|virtual]], adresa virtuală în spaţiul kernel asociată acestei pagini fizice; paginile din ''ZONE_DMA'' sau ''ZONE_NORMAL'' sunt tot timpul mapate; paginile din ''ZONE_HIHGMEM'' nu sunt tot timpul mapate; Aceste constante se găsesc în [[http://lxr.linux.no/linux+v3.13/include/linux/mmzone.h#L261|enum zone_type]] | + | |
- | *[[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L46|flags]], un set de flag-uri care descriu atributele paginii. | + | |
Există numeroase funcţii care interacţionează cu această structură: | Există numeroase funcţii care interacţionează cu această structură: | ||
- | *[[http://lxr.linux.no/linux+v3.13/arch/x86/include/asm/page.h#L63|virt_to_page]] întoarce pagina asociată unei adrese virtuale; | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/page.h#L68|virt_to_page]] întoarce pagina asociată unei adrese virtuale; |
- | *[[http://lxr.linux.no/linux+v3.13/include/asm-generic/memory_model.h#L73|pfn_to_page]] întoarce pagina asociată pentru un număr de pagină (''page frame number''); | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/asm-generic/memory_model.h#L81|pfn_to_page]] întoarce pagina asociată pentru un număr de pagină (''page frame number''); |
- | *[[http://lxr.linux.no/linux+v3.13/mm/highmem.c#L348|page_address]] întoarce adresa virtuală a paginii transmise ca parametru. | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm.h#L1013|page_address]] întoarce adresa virtuală a paginii transmise ca parametru. |
==== Structura ''vm_area_struct'' ==== | ==== Structura ''vm_area_struct'' ==== | ||
- | Structura [[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L246|struct vm_area_struct]] deţine informaţii despre o zonă de memorie virtuală contiguă. Zonele de memorie ale unui proces pot fi vizualizate inspectând ''procfs'': | + | Structura [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L300|struct vm_area_struct]] deţine informaţii despre o zonă de memorie virtuală contiguă. Zonele de memorie ale unui proces pot fi vizualizate inspectând ''procfs'': |
<code bash> | <code bash> | ||
Line 69: | Line 64: | ||
O structură ''vm_area_struct'' este creată la fiecare apel ''mmap'' din user-space. Un driver care are suport pentru operaţia de ''mmap'' trebuie să completeze şi să iniţializeze structura ''vm_area_struct'' asociată. Cele mai importante câmpuri ale acestei structuri sunt: | O structură ''vm_area_struct'' este creată la fiecare apel ''mmap'' din user-space. Un driver care are suport pentru operaţia de ''mmap'' trebuie să completeze şi să iniţializeze structura ''vm_area_struct'' asociată. Cele mai importante câmpuri ale acestei structuri sunt: | ||
- | *[[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L249|vm_start]], [[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L250|vm_end]], reprezintă începutul, respectiv, sfârşitul zonei de memorie (aceste câmpuri apar şi in ''/proc/*/maps''); | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L303|vm_start]], [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L304|vm_end]], reprezintă începutul, respectiv, sfârşitul zonei de memorie (aceste câmpuri apar şi in ''/proc/*/maps''); |
- | *[[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L301|vm_file]], pointer-ul la structura de fişier asociată (dacă există); | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L351|vm_file]], pointer-ul la structura de fişier asociată (dacă există); |
- | *[[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L299|vm_pgoff]], offset-ul zonei în cadrul fişierului; | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L349|vm_pgoff]], offset-ul zonei în cadrul fişierului; |
- | *[[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L270|vm_flags]], un set de indicatori; | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L324|vm_flags]], un set de indicatori; |
- | *[[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L296|vm_ops]], un set de funcţii de lucru asupra acestei zone. | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L346|vm_ops]], un set de funcţii de lucru asupra acestei zone. |
- | *[[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L254|vm_next, vm_prev]], ''vm_area''-urile aferente unui proces sunt înlănțuite printr-o listă | + | *[[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L308|vm_next]], [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L308|vm_prev]], ''vm_area''-urile aferente unui proces sunt înlănțuite printr-o listă |
==== Structura ''mm_struct'' ==== | ==== Structura ''mm_struct'' ==== | ||
- | Structura [[http://lxr.linux.no/linux+v3.13/include/linux/mm_types.h#L344|struct mm_struct]] înglobează toate zonele de memorie asociate unui proces; folosind câmpul ''mm'' al structurii [[http://lxr.linux.no/linux+v3.13/include/linux/sched.h#L1042|task_struct]] se poate obţine structura ''mm_struct'' asociată procesului curent. | + | Structura [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L396|struct mm_struct]] înglobează toate zonele de memorie asociate unui proces; folosind câmpul ''mm'' al structurii [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/sched.h#L1475|task_struct]] se poate obţine structura ''mm_struct'' asociată procesului curent. |
==== Maparea memoriei ==== | ==== Maparea memoriei ==== | ||
Line 84: | Line 79: | ||
Maparea memoriei (''memory mapping'') este una dintre cele mai interesante caracteristici ale unui sistem Unix. Din punct de vedere al unui driver, facilitatea de ''memory-mapping'' permite accesul direct al memoriei unui dispozitiv din user-space. | Maparea memoriei (''memory mapping'') este una dintre cele mai interesante caracteristici ale unui sistem Unix. Din punct de vedere al unui driver, facilitatea de ''memory-mapping'' permite accesul direct al memoriei unui dispozitiv din user-space. | ||
- | Pentru a asocia unui driver o operaţie ''mmap'', trebuie utilizat câmpul [[http://lxr.linux.no/linux+v3.13/include/linux/fs.h#L1532|mmap]] din structura [[http://lxr.linux.no/linux+v3.13/include/linux/fs.h#L1521|struct file_operations]] asociată dispozitivului. Metoda astfel asociată este utilizată în cazul unui apel ''mmap'' din user-space. | + | Pentru a asocia unui driver o operaţie ''mmap'', trebuie utilizat câmpul [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/fs.h#L1708|mmap]] din structura [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/fs.h#L1696|struct file_operations]] asociată dispozitivului. Metoda astfel asociată este utilizată în cazul unui apel ''mmap'' din user-space. |
==== User-space ==== | ==== User-space ==== | ||
Line 103: | Line 98: | ||
</code> | </code> | ||
- | Câmpul ''filp'' reprezintă pointer-ul la structura [[http://lxr.linux.no/#linux+v2.6.35/include/linux/fs.h#L914| struct file]] creată o dată cu deschiderea dispozitivului din user-space. Câmpul ''vma'' este utilizat pentru a indica spaţiul de adresă virtual folosit pentru maparea memoriei dispozitivului. Un driver va putea aloca memorie (folosind ''kmalloc'' sau ''vmalloc''), urmând ca un set de procese să poată mapa în spaţiul propriu de adresă adresa alocată în driver. | + | Câmpul ''filp'' reprezintă pointer-ul la structura [[http://lxr.free-electrons.com/source/include/linux/fs.h#L866|struct file]] creată o dată cu deschiderea dispozitivului din user-space. Câmpul ''vma'' este utilizat pentru a indica spaţiul de adresă virtual folosit pentru maparea memoriei dispozitivului. Un driver va putea aloca memorie (folosind ''kmalloc'' sau ''vmalloc''), urmând ca un set de procese să poată mapa în spaţiul propriu de adresă adresa alocată în driver. |
===== ''remap_pfn_range'' ===== | ===== ''remap_pfn_range'' ===== | ||
- | Pentru maparea unui spaţiu de memorie fizică în spaţiul virtual utilizator, reprezentat de structura ''struct vm_area_struct'', se folosește apelul [[http://lxr.linux.no/linux+v3.13/mm/memory.c#L2329 | remap_pfn_range]]. Acesta va mapa un spaţiu de adresă fizic contiguu în spaţiul virtual reprezentat de ''struct vm_area_struct'': | + | Pentru maparea unui spaţiu de memorie fizică în spaţiul virtual utilizator, reprezentat de structura ''struct vm_area_struct'', se folosește apelul [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm.h#L2193|remap_pfn_range]]. Acesta va mapa un spaţiu de adresă fizic contiguu în spaţiul virtual reprezentat de ''struct vm_area_struct'': |
<code C> | <code C> | ||
int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, | int remap_pfn_range(struct vm_area_struct *vma, unsigned long addr, | ||
Line 116: | Line 111: | ||
*''vma'', spaţiul de memorie virtuală în cadrul căruia se face maparea; | *''vma'', spaţiul de memorie virtuală în cadrul căruia se face maparea; | ||
*''addr'', spaţiul virtual de adresă de unde se începe remaparea; se vor construi tabele de pagini pentru spaţiul virtual de adresă cuprins intre ''addr'' şi ''addr + size''; | *''addr'', spaţiul virtual de adresă de unde se începe remaparea; se vor construi tabele de pagini pentru spaţiul virtual de adresă cuprins intre ''addr'' şi ''addr + size''; | ||
- | *''pfn'', numărul paginii fizice (''page frame number'') în care se mapează adresa virtuală; de obicei acesta se obţine prin shifting-ul adresei fizice [[http://lxr.linux.no/linux+v3.13/include/asm-generic/page.h#L15| PAGE_SHIFT]] biţi la dreapta | + | *''pfn'', numărul paginii fizice (''page frame number'') în care se mapează adresa virtuală; de obicei acesta se obţine prin shifting-ul adresei fizice [[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/page_types.h#L8|PAGE_SHIFT]] biţi la dreapta |
*''size'', dimensiunea (în octeţi) a spaţiului de memorie care va fi remapat; | *''size'', dimensiunea (în octeţi) a spaţiului de memorie care va fi remapat; | ||
*''prot'', caracteristicile de protecţie pentru noul spaţiu de adresă. | *''prot'', caracteristicile de protecţie pentru noul spaţiu de adresă. | ||
Line 136: | Line 131: | ||
În exemplul de mai sus se realizează o mapare a zonei fizice începând de la numărul de pagină ''phys_pgoff'' în întreg spaţiul virtual de adresă reprezentat de ''vma''. | În exemplul de mai sus se realizează o mapare a zonei fizice începând de la numărul de pagină ''phys_pgoff'' în întreg spaţiul virtual de adresă reprezentat de ''vma''. | ||
- | Două funcţii care sunt utile sunt cele de translatare a unei adrese virtuale din spaţiul kernel în adrese fizice. Acestea sunt [[http://lxr.linux.no/linux+v3.13/arch/x86/include/asm/io.h#L111| virt_to_phys]] pentru adrese alocate folosind ''kmalloc'' şi [[http://lxr.linux.no/linux+v3.13/mm/vmalloc.c#L259| vmalloc_to_pfn]] pentru adrese alocate folosind ''vmalloc''. | + | Două funcţii care sunt utile sunt cele de translatare a unei adrese virtuale din spaţiul kernel în adrese fizice. Acestea sunt [[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/io.h#L118| virt_to_phys]] pentru adrese alocate folosind ''kmalloc'' şi [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm.h#L473|vmalloc_to_pfn]] pentru adrese alocate folosind ''vmalloc''. |
Astfel, numărul de pagină ''phys_pgoff'' din exemplul de mai sus se va obţine în cazul unei adrese ''kmalloc_area'' alocate folosind ''kmalloc'' astfel: | Astfel, numărul de pagină ''phys_pgoff'' din exemplul de mai sus se va obţine în cazul unei adrese ''kmalloc_area'' alocate folosind ''kmalloc'' astfel: | ||
Line 155: | Line 150: | ||
===== ''SetPageReserved''/''ClearPageReserved'' ===== | ===== ''SetPageReserved''/''ClearPageReserved'' ===== | ||
- | Înainte de a fi utilizată, unei pagini îi va trebui activat bitul [[http://lxr.linux.no/linux+v3.13/include/linux/page-flags.h#L85|PG_reserved]]. Acest bit înseamnă că pagina nu poate fi evacuată pe disk (''swap''). Activarea se realizează cu ajutorul macroului [[http://lxr.linux.no/linux+v3.13/include/linux/page-flags.h#L182|SetPageReserved]]. Macrodefiniţia primeşte ca parametru un pointer către structura de pagină, ''struct page'', care se obţine din adresa virtuală din kernel cu ajutorul funcţiei ''virt_to_page'', pentru adrese alocate folosind ''kmalloc'': | + | Înainte de a fi utilizată, unei pagini îi va trebui activat bitul [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/page-flags.h#L85|PG_reserved]]. Acest bit înseamnă că pagina nu poate fi evacuată pe disk (''swap''). Activarea se realizează cu ajutorul macroului [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/page-flags.h#L194|SetPageReserved]]. Macrodefiniţia primeşte ca parametru un pointer către structura de pagină, ''struct page'', care se obţine din adresa virtuală din kernel cu ajutorul funcţiei ''virt_to_page'', pentru adrese alocate folosind ''kmalloc'': |
<code C> | <code C> | ||
#define NPAGES 16 | #define NPAGES 16 | ||
Line 166: | Line 161: | ||
} | } | ||
</code> | </code> | ||
- | şi cu ajutorul funcţiei [[http://lxr.linux.no/linux+v3.13/mm/vmalloc.c#L225]] pentru adrese alocate folosind ''vmalloc'': | + | şi cu ajutorul funcţiei [[http://elixir.free-electrons.com/linux/v4.9/source/mm/vmalloc.c#L235|vmalloc_to_page]] pentru adrese alocate folosind ''vmalloc'': |
<code C> | <code C> | ||
#define NPAGES 16 | #define NPAGES 16 | ||
Line 178: | Line 173: | ||
</code> | </code> | ||
- | Înainte de eliberarea paginii (''kfree''/''vfree''), bitul de pagină rezervată trebuie dezactivat cu ajutorul macroului [[http://lxr.linux.no/linux+v3.13/include/linux/page-flags.h#L185|ClearPageReserved]]. Acesta primeşte ca parametru acelaşi pointer către o structura de pagină care a fost dat la ''SetPageReserved''. | + | Înainte de eliberarea paginii (''kfree''/''vfree''), bitul de pagină rezervată trebuie dezactivat cu ajutorul macroului [[http://lxr.free-electrons.com/source/include/linux/page-flags.h?v=4.9#L185|ClearPageReserved]]. Acesta primeşte ca parametru acelaşi pointer către o structura de pagină care a fost dat la ''SetPageReserved''. |
Line 193: | Line 188: | ||
- [[http://www.ecst.csuchico.edu/~beej/guide/ipc/mmap.html|Memory Mapped Files]] | - [[http://www.ecst.csuchico.edu/~beej/guide/ipc/mmap.html|Memory Mapped Files]] | ||
- [[http://en.wikipedia.org/wiki/Mmap|mmap]] | - [[http://en.wikipedia.org/wiki/Mmap|mmap]] | ||
- |