This shows you the differences between two versions of the page.
so2:laboratoare:lab11:exercitii [2016/05/08 18:59] sorin.baltateanu [Laborator 11: Exerciții] |
so2:laboratoare:lab11:exercitii [2019/05/08 09:53] (current) constantin.ghioc [2. [3p] Mapare de memorie virtual contiguă în user space] |
||
---|---|---|---|
Line 1: | Line 1: | ||
====== Laborator 11: Exerciții ====== | ====== Laborator 11: Exerciții ====== | ||
- | Pentru desfășurarea laboratorului pornim de la [[http://elf.cs.pub.ro/so2/res/laboratoare/lab11-tasks.zip|arhiva de sarcini a laboratorului]]. Descărcăm și decomprimăm arhiva în directorul ''so2/'' din directorul home al utilizatorului ''student'' de pe sistemul de bază (stația ''mjolnir''):<code bash> | + | |
- | student@mjolnir:~$ cd so2/ | + | ===== Pregătirea laboratorului ===== |
- | student@mjolnir:~/so2$ wget http://elf.cs.pub.ro/so2/res/laboratoare/lab11-tasks.zip | + | |
- | student@mjolnir:~/so2$ unzip lab11-tasks.zip | + | Pentru rezolvarea laboratorului, vom lucra în același director din care pornim mașina virtuală (''~/so2/linux/tools/labs''). |
- | student@mjolnir:~/so2$ tree lab11-tasks | + | |
+ | Pașii de rezolvare sunt următorii: | ||
+ | * pregătirea scheletului de laborator | ||
+ | * compilarea modulelor de Kernel | ||
+ | * copierea modulelor pe mașina virtuală | ||
+ | * pornirea mașinii virtuale și testarea modulelor | ||
+ | |||
+ | ==== Pregătirea scheletului de laborator ==== | ||
+ | |||
+ | Pentru rezolvarea laboratorului trebuie sa activam suportul de netfilter din kernel. In meniul deschis cu ''make menuconfig'' | ||
+ | activati optiunea ''Networking support/Networking options/Network packet filtering framework (Netfilter)''. | ||
+ | |||
+ | Scheletul de laborator este generat din sursele din directorul ''tools/labs/templates''. Putem genera scheletele pentru toate laboratoarele folosind următoarea comanda: | ||
+ | |||
+ | <code bash> | ||
+ | tools/labs $ make skels | ||
</code> | </code> | ||
- | În cadrul directorului ''lab11-tasks/'' se găsesc resursele necesare pentru dezvoltarea exercițiilor de mai jos: fișiere schelet de cod sursă, fișiere Makefile și Kbuild, scripturi și programe de test. | ||
- | Vom dezvolta exercițiile pe sistemul de bază (stația ''mjolnir'') și apoi le vom testa pe [[:so2:resurse:masini-virtuale|mașina virtuală QEMU]]. După editarea și compilarea unui modul de kernel îl vom copia în directorul dedicat pentru mașina virtuală QEMU folosind o comandă de forma<code bash> | + | Pentru a genera scheletul pentru un singur laborator, vom folosi variabila de mediu ''LABS'': |
- | student@mjolnir:~/so2$ cp /path/to/module.ko ~/so2/qemu-vm/fsimg/root/modules/ | + | |
- | </code> unde ''/path/to/module.ko'' este calea către fișierul obiect aferent modulului de kernel. Apoi vom porni, din directorul ''~/so2/qemu-vm/'' mașina virtuală QEMU folosind comanda<code bash> | + | <code bash> |
- | student@mjolnir:~/so2/qemu-vm$ make | + | tools/labs $ make clean |
+ | tools/labs $ LABS=<lab name> make skels | ||
</code> | </code> | ||
- | După pornirea mașinii virtuale QEMU vom putea folosi comenzi în fereastra QEMU pentru a încărca și descărca modulul de kernel:<code> | + | <note important> |
- | # insmod modules/module-name.ko | + | Numele laboratorului curent este ''memory_mapping''. |
- | # rmmod module/module-name | + | </note> |
- | </code> unde ''module-name'' este numele modulului de kernel. | + | |
+ | Similar, putem genera și scheletul pentru un singur exercițiu, atribuind valoarea ''<lab_name>/<task_name>'' variabilei ''LABS''. | ||
<note> | <note> | ||
- | Pentru dezvoltarea laboratorului, este recomandat să folosim trei terminale sau, mai bine, trei tab-uri de terminal. Pentru a deschide un nou tab de terminal folosim combinația de taste ''Ctrl+Alt+t''. Cele trei tab-uri de terminal îndeplinesc următoarele roluri: | + | Scheletul este generat în directorul ''tools/labs/skels''. |
- | - În primul tab de terminal dezvoltăm modulul de kernel: editare, compilare, copiere în directorul dedicat pentru mașina virtaulă QEMU. Lucrăm în directorul aferent rezultat în urma decomprimării arhivei de sarcini a laboratorului. | + | </note> |
- | - În al doilea tab de terminal pornim mașina virtuală QEMU și apoi testăm modulul de kernel: încărcare/descărcare modul, rulare teste. Lucrăm în directorul aferent mașinii virtuale: ''~/so2/qemu-vm/''. | + | |
- | - În al treilea tab de terminal pornim un server UDP care să primească [[:so2:laboratoare:lab02#netconsole|mesajele de netconsole]]. Nu contează în ce director ne aflăm. Folosim comanda<code bash> | + | ==== Compilarea modulelor ==== |
- | student@mjolnir:~$ netcat -lup 6666 | + | |
+ | Comanda ''make build'' compilează toate modulele din directorul ''skels''. | ||
+ | |||
+ | <code bash> | ||
+ | student@eg106:~/so2/linux/tools/labs$ make build | ||
+ | echo "# autogenerated, do not edit " > skels/Kbuild | ||
+ | echo "ccflags-y += -Wno-unused-function -Wno-unused-label -Wno-unused-variable " >> skels/Kbuild | ||
+ | for i in ./memory_mapping/vmmap ./memory_mapping/kmmap; do echo "obj-m += $i/" >> skels/Kbuild; done | ||
+ | ... | ||
</code> | </code> | ||
+ | |||
+ | ==== Copierea modulelor pe mașina virtuală ==== | ||
+ | |||
+ | Putem copia modulele generate pe mașina virtuală folosind target-ul ''copy'' al comenzii make, atunci când mașina virtuală este oprită. | ||
+ | |||
+ | <code bash> | ||
+ | student@eg106:~/so2/linux/tools/labs$ make copy | ||
+ | student@eg106:~/so2/linux/tools/labs$ make boot | ||
+ | </code> | ||
+ | |||
+ | Alternativ, putem copia fișierele prin ''scp'', pentru e evita repornirea mașinii virtuale. Pentru detalii despre folosirea interacțiunea prin rețea cu mașina virtuală citiți [[https://ocw.cs.pub.ro/courses/so2/resurse/masini-virtuale#interactiunea_cu_masina_virtuala|Interacțiunea cu mașina virtuală]]. | ||
+ | |||
+ | ==== Testarea modulelor ==== | ||
+ | |||
+ | Modulele generate sunt copiate pe mașina virtuală în directorul ''/home/root/skels/<lab_name>''. | ||
+ | |||
+ | <code bash> | ||
+ | root@qemux86:~/skels/memory_mapping# ls | ||
+ | kmmap test vmmap | ||
+ | root@qemux86:~/skels/memory_mapping# ls vmmap/ | ||
+ | vmmap.ko | ||
+ | </code> | ||
+ | |||
+ | După pornirea mașinii virtuale QEMU vom putea folosi comenzi în fereastra QEMU (sau în ''minicom'') pentru a încărca și descărca modulul de kernel:<code> | ||
+ | root@qemux86:~# insmod skels/<lab_name>/<task_name>/<module_name>.ko | ||
+ | root@qemux86:~# rmmod skels/<lab_name>/<task_name>/<module_name>.ko | ||
+ | </code> | ||
+ | |||
+ | <note> | ||
+ | Pentru dezvoltarea laboratorului, este recomandat să folosim trei terminale sau, mai bine, trei tab-uri de terminal. Pentru a deschide un nou tab de terminal folosim combinația de taste ''Ctrl+Shift+t''. Cele trei tab-uri de terminal îndeplinesc următoarele roluri: | ||
+ | - În primul tab de terminal dezvoltăm modulul de kernel: editare, compilare, copiere în directorul dedicat pentru mașina virtuală QEMU. Lucrăm în directorul aferent rezultat în urma decomprimării arhivei de sarcini a laboratorului. | ||
+ | - În al doilea tab de terminal pornim mașina virtuală QEMU și apoi testăm modulul de kernel: încărcare/descărcare modul, rulare teste. Lucrăm în directorul aferent mașinii virtuale: ''~/so2/linux/tools/labs''. | ||
+ | - În al treilea tab de terminal accesăm directorul ''~/so2/linux/'' cu sursele nucleului unde putem folosi [[:so2:laboratoare:lab01#cscope|Vim și cscope]] pentru parcurgerea codului sursă.<code> | ||
+ | student@eg106-pc:~$ netcat -lup 6666 | ||
+ | </code> | ||
+ | |||
</note> | </note> | ||
- | - (**3 puncte**) Mapare de memorie fizic contiguă în user space | + | ===== Exerciții ===== |
- | * Utilizați scheletul de modul de kernel din directorul ''lin/kmmap/'' pentru a crea o mapare a memoriei driver-ului în user-space. | + | |
+ | <note important> | ||
+ | Înainte de începerea rezolvării laboratorului, rulați comanda ''%%git pull --rebase%%'' in directorul ''~/so2/linux'', pentru a obține ultima versiune a scheletului de laborator. | ||
+ | </note> | ||
+ | |||
+ | ==== 1. [3p] Mapare de memorie fizic contiguă în user space ==== | ||
+ | * Utilizați scheletul de modul de kernel din directorul ''kmmap/'' pentru a crea o mapare a memoriei driver-ului în user-space. | ||
* Memoria driver-ului este alocată folosind ''kmalloc''. | * Memoria driver-ului este alocată folosind ''kmalloc''. | ||
* Completați zonele marcate cu ''TODO 1''. | * Completați zonele marcate cu ''TODO 1''. | ||
* Parcurgeți secțiunea [[:so2:laboratoare:lab11#Kernel-space|Maparea memoriei. Kernel-space]]. | * Parcurgeți secțiunea [[:so2:laboratoare:lab11#Kernel-space|Maparea memoriei. Kernel-space]]. | ||
- | * Alocați, în funcția de inițializare a modulului, o zonă de memorie de ''NPAGES+1'' pagini folosind ''kmalloc''. | + | * Alocați, în funcția de inițializare a modulului, o zonă de memorie de ''NPAGES+2'' pagini folosind ''kmalloc''. |
- | * O pagină în kernel are dimensiunea [[http://lxr.linux.no/linux+*/arch/x86/include/asm/page_types.h#L8|PAGE_SIZE]]. | + | * O pagină în kernel are dimensiunea [[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/page_types.h#L9|PAGE_SIZE]]. |
* Zona alocată din spațiul kernel este indicată de ''kmalloc_area''. | * Zona alocată din spațiul kernel este indicată de ''kmalloc_area''. | ||
- | * Dimensiunea ''NPAGES+1'' este necesară pentru aliniere. | + | * Dimensiunea ''NPAGES+2'' este necesară pentru aliniere. |
* Adresa ''kmalloc_ptr'' (variabilă globală) obținută în urma apelului ''kmalloc'' trebuie aliniată la adresa unei pagini. | * Adresa ''kmalloc_ptr'' (variabilă globală) obținută în urma apelului ''kmalloc'' trebuie aliniată la adresa unei pagini. | ||
* Pentru aceasta, va trebui să alocați o pagină în plus față de numărul de pagini necesare și să folosiți formula:<code> | * Pentru aceasta, va trebui să alocați o pagină în plus față de numărul de pagini necesare și să folosiți formula:<code> | ||
Line 43: | Line 109: | ||
</code> | </code> | ||
* Activați/dezactivați bitul ''PG_reserved'' al fiecărei pagini cu ajutorul funcțiilor ''SetPageReserved'' (în funcția de inițializare a modulului), respectiv ''ClearPageReserved'' (în funcția de ieșire a modulului). | * Activați/dezactivați bitul ''PG_reserved'' al fiecărei pagini cu ajutorul funcțiilor ''SetPageReserved'' (în funcția de inițializare a modulului), respectiv ''ClearPageReserved'' (în funcția de ieșire a modulului). | ||
- | * Folosiți [[http://lxr.free-electrons.com/source/tools/virtio/linux/virtio.h?v=3.7#L32|virt_to_page]] pentru a traduce paginile virtuale în pagini fizice folosite de funcțiile ''SetPageReserved'' și ''ClearPageReserved''. | + | * Folosiți [[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/page.h#L68|virt_to_page]] pentru a traduce paginile virtuale în pagini fizice folosite de funcțiile ''SetPageReserved'' și ''ClearPageReserved''. |
* Pentru verificare (folosind testul indicat mai jos) completați primii 4 octeți din fiecare pagină alocată cu valorile, respectiv, ''0xaa'',''0xbb'',''0xcc'',''0xdd''. | * Pentru verificare (folosind testul indicat mai jos) completați primii 4 octeți din fiecare pagină alocată cu valorile, respectiv, ''0xaa'',''0xbb'',''0xcc'',''0xdd''. | ||
* Implementați funcția ''mmap'' pentru driver. | * Implementați funcția ''mmap'' pentru driver. | ||
- | * Pentru mapare folosiți funcția [[http://lxr.free-electrons.com/source/mm/memory.c?v=3.7#L2282|remap_pfn_range]]. | + | * Pentru mapare folosiți funcția [[http://elixir.free-electrons.com/linux/v4.9/source/mm/memory.c#L1760|remap_pfn_range]]. |
- | * Al treilea argument primit de [[http://lxr.free-electrons.com/source/mm/memory.c?v=3.7#L2282|remap_pfn_range]] este un număr de pagină fizică (''pfn'' -- //page frame number//). | + | * Al treilea argument primit de [[http://elixir.free-electrons.com/linux/v4.9/source/mm/memory.c#L1760|remap_pfn_range]] este un număr de pagină fizică (''pfn'' -- //page frame number//). |
- | * Pentru conversia din adresă kernel virtuală (adică ''kmalloc_area'') în adresă fizică utilizați [[http://lxr.free-electrons.com/source/arch/x86/include/asm/io.h?v=3.7#L98|virt_to_phys]]. | + | * Pentru conversia din adresă kernel virtuală (adică ''kmalloc_area'') în adresă fizică utilizați [[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/io.h#L118|virt_to_phys]]. |
- | * Shiftați rezultatul cu ''PAGE_SHIFT'' biți pentru a obține ''pfn''. | + | * Shiftați rezultatul cu [[http://elixir.free-electrons.com/linux/v4.9/source/arch/x86/include/asm/page_types.h#L8|PAGE_SHIFT]] biți pentru a obține ''pfn''. |
* Încărcați modulul în kernel. | * Încărcați modulul în kernel. | ||
- | * Pentru testare utilizați testul din directorul ''lin/test''. | + | * Pentru testare utilizați testul din directorul ''test/''. |
- | * Compilați testul folosind comanda ''make''. | + | |
* Rulați testul folosind comanda ''./mmap-test''. | * Rulați testul folosind comanda ''./mmap-test''. | ||
* Dacă totul merge bine testul va afișa mesaje ''matched''. | * Dacă totul merge bine testul va afișa mesaje ''matched''. | ||
* Descărcați modulul din kernel. | * Descărcați modulul din kernel. | ||
- | - (**3 puncte**) Mapare de memorie virtual contiguă în user space | + | |
- | * Utilizați scheletul de modul de kernel din directorul ''lin/vmmap/'' pentru a crea o mapare a memoriei driver-ului în user-space. | + | ==== 2. [3p] Mapare de memorie fizic discontiguă în user space ==== |
+ | * Utilizați scheletul de modul de kernel din directorul ''vmmap/'' pentru a crea o mapare a memoriei driver-ului în user-space. | ||
* Memoria driver-ului este alocată folosind ''vmalloc''. | * Memoria driver-ului este alocată folosind ''vmalloc''. | ||
- | * Completați zonele marcate cu ''TODO 2''. | + | * Completați zonele marcate cu ''TODO 1''. |
* Parcurgeți secțiunea [[:so2:laboratoare:lab11#Kernel-space|Maparea memoriei. Kernel-space]] din laborator. | * Parcurgeți secțiunea [[:so2:laboratoare:lab11#Kernel-space|Maparea memoriei. Kernel-space]] din laborator. | ||
* Alocați o zonă de memorie de ''NPAGES'' pagini în funcția de inițializare a modulului folosind ''vmalloc''. | * Alocați o zonă de memorie de ''NPAGES'' pagini în funcția de inițializare a modulului folosind ''vmalloc''. | ||
Line 65: | Line 131: | ||
* Alocarea cu ''vmalloc'' întoarce adrese aliniate la dimensiunea paginii; nu este nevoie de operații suplimentare. | * Alocarea cu ''vmalloc'' întoarce adrese aliniate la dimensiunea paginii; nu este nevoie de operații suplimentare. | ||
* Activați/dezactivați bitul ''PG_reserved'' al fiecărei pagini cu ajutorul funcțiilor ''SetPageReserved'' (în funcția de inițializare a modulului), respectiv ''ClearPageReserved'' (în funcția de ieșire a modulului); | * Activați/dezactivați bitul ''PG_reserved'' al fiecărei pagini cu ajutorul funcțiilor ''SetPageReserved'' (în funcția de inițializare a modulului), respectiv ''ClearPageReserved'' (în funcția de ieșire a modulului); | ||
- | * Folosiți [[http://lxr.free-electrons.com/source/mm/vmalloc.c?v=3.7#L202|vmalloc_to_page]] pentru a traduce paginile virtuale în pagini fizice folosite de funcțiile ''SetPageReserved'' și ''ClearPageReserved''. | + | * Folosiți [[http://elixir.free-electrons.com/linux/v4.9/source/mm/vmalloc.c#L235|vmalloc_to_page]] pentru a traduce paginile virtuale în pagini fizice folosite de funcțiile ''SetPageReserved'' și ''ClearPageReserved''. |
* Pentru verificare folosind testul, completați primii 4 octeți din fiecare pagină alocată cu următoarele valori: ''0xaa'',''0xbb'',''0xcc'',''0xdd''. | * Pentru verificare folosind testul, completați primii 4 octeți din fiecare pagină alocată cu următoarele valori: ''0xaa'',''0xbb'',''0xcc'',''0xdd''. | ||
* Implementați funcția ''mmap'' pentru driver. | * Implementați funcția ''mmap'' pentru driver. | ||
- | * Pentru conversia din adresă kernel virtuală în adresă fizică utilizați [[http://lxr.free-electrons.com/source/mm/vmalloc.c?v=3.7#L236|vmalloc_to_pfn]]. | + | * Pentru conversia din adresă kernel virtuală în adresă fizică utilizați [[http://elixir.free-electrons.com/linux/v4.9/source/mm/vmalloc.c#L269|vmalloc_to_pfn]]. |
- | * [[http://lxr.free-electrons.com/source/mm/vmalloc.c?v=3.7#L236|vmalloc_to_pfn]] întoarce un index de pagină (//page frame number//), astfel că **nu** este nevoie de shift la dreapta. | + | * [[http://elixir.free-electrons.com/linux/v4.9/source/mm/vmalloc.c#L269|vmalloc_to_pfn]] întoarce un index de pagină (//page frame number//), astfel că **nu** este nevoie de shift la dreapta. |
* Paginile alocate cu ''vmalloc'' nu sunt fizic contigue. | * Paginile alocate cu ''vmalloc'' nu sunt fizic contigue. | ||
- | * Apelați [[http://lxr.free-electrons.com/source/mm/memory.c?v=3.7#L2282|remap_pfn_range]] pentru **fiecare** pagină virtuală. | + | * Apelați [[http://elixir.free-electrons.com/linux/v4.9/source/mm/memory.c#L1760|remap_pfn_range]] pentru **fiecare** pagină virtuală. |
* Adică veți avea nevoie de un ciclu for și veți incrementa adresa virtuală kernel (''vmalloc_area'') cu câte o pagină și veți obține pentru fiecare adresă virtuală astfel obținută ''pfn''-ul. | * Adică veți avea nevoie de un ciclu for și veți incrementa adresa virtuală kernel (''vmalloc_area'') cu câte o pagină și veți obține pentru fiecare adresă virtuală astfel obținută ''pfn''-ul. | ||
* Folosiți ''vmalloc_area_ptr'' pentru parcurgerea spațiului virtual din kernel space. | * Folosiți ''vmalloc_area_ptr'' pentru parcurgerea spațiului virtual din kernel space. | ||
* Nu modificați variabila globală ''vmalloc_area''. | * Nu modificați variabila globală ''vmalloc_area''. | ||
- | * Argumentul pentru [[http://lxr.free-electrons.com/source/mm/vmalloc.c?v=3.7#L236|vmalloc_to_pfn]] este o adresă virtuală din kernel space. | + | * Argumentul pentru [[http://elixir.free-electrons.com/linux/v4.9/source/mm/vmalloc.c#L269|vmalloc_to_pfn]] este o adresă virtuală din kernel space. |
- | * Al doilea argument pentru [[http://lxr.free-electrons.com/source/mm/memory.c?v=3.7#L2282|remap_pfn_range]] este o adresă virtuală din cadrul unui VMA. | + | * Al doilea argument pentru [[http://elixir.free-electrons.com/linux/v4.9/source/mm/memory.c#L1760|remap_pfn_range]] este o adresă virtuală din cadrul unui VMA. |
- | * Al treilea argument pentru [[http://lxr.free-electrons.com/source/mm/memory.c?v=3.7#L2282|remap_pfn_range]] este pfn-ul paginii virtuale din kernel-space care se dorește remapată. | + | * Al treilea argument pentru [[http://elixir.free-electrons.com/linux/v4.9/source/mm/memory.c#L1760|remap_pfn_range]] este pfn-ul paginii virtuale din kernel-space care se dorește remapată. |
* Încărcați modulul în kernel. | * Încărcați modulul în kernel. | ||
- | * Pentru testare utilizați testul din directorul ''lin/test''. | + | * Pentru testare utilizați testul din directorul ''test/''. |
- | * Compilați testul folosind comanda ''make''. | + | |
* Rulați testul folosind comanda ''./mmap-test''. | * Rulați testul folosind comanda ''./mmap-test''. | ||
* Dacă totul merge bine testul va afișa mesaje ''matched''. | * Dacă totul merge bine testul va afișa mesaje ''matched''. | ||
* Descărcați modulul din kernel. | * Descărcați modulul din kernel. | ||
- | - (**2 puncte**) Operații de read/write în memoria mapată | + | |
+ | |||
+ | ==== 3. [2p] Operații de read/write în memoria mapată ==== | ||
* Modificați **unul dintre** modulele anterioare astfel încât să permiteți operații read/write pe dispozitiv. | * Modificați **unul dintre** modulele anterioare astfel încât să permiteți operații read/write pe dispozitiv. | ||
* E vorba de un exercițiu didactic ca să vedem că același spațiu poate fi folosit și cu apel-ul ''mmap'' și cu apeluri de tipul ''read'' și ''write''. | * E vorba de un exercițiu didactic ca să vedem că același spațiu poate fi folosit și cu apel-ul ''mmap'' și cu apeluri de tipul ''read'' și ''write''. | ||
* Operațiile de citire și scriere vor acționa chiar asupra zonei de memorie alocate. | * Operațiile de citire și scriere vor acționa chiar asupra zonei de memorie alocate. | ||
- | * Completați zonele marcate cu ''TODO 3''. | + | * Completați zonele marcate cu ''TODO 2''. |
* Revedeți [[so2:laboratoare:lab04 | Laboratorul 4]] | * Revedeți [[so2:laboratoare:lab04 | Laboratorul 4]] | ||
* **Ignorați** parametrul ''offset'' trimis operației de read/write. | * **Ignorați** parametrul ''offset'' trimis operației de read/write. | ||
- | * Pentru testare utilizați testul din directorul ''lin/test''. | + | * Pentru testare utilizați testul din directorul ''test/''. |
- | * Definiți macroul ''TASK_3'' în ''mmap_test.c'' | + | * Rulați testul folosind comanda ''./mmap-test 3''. |
- | - (**3 puncte**) Afișare memorie mapată în ''procfs'' | + | |
+ | |||
+ | ==== 4. [3p] Afișare memorie mapată în ''procfs'' ==== | ||
* Folosind **unul dintre** modulele anterioare, creați un fișier ''procfs'' în care să afișați totalul memoriei mapate de procesul apelant. | * Folosind **unul dintre** modulele anterioare, creați un fișier ''procfs'' în care să afișați totalul memoriei mapate de procesul apelant. | ||
- | * Completați zonele marcate cu ''TODO 4''. | + | * Completați zonele marcate cu ''TODO 3''. |
- | * Creați o intrare nouă în ''procfs'' (''PROC_ENTRY_NAME'', definit în ''mmap-test.h'') care va afișa totalul memoriei mapate de procesul care a apelat read-ul pe acel fișier. Folosiți apelul [[http://lxr.free-electrons.com/source/include/linux/proc_fs.h?v=3.13#L30|proc_create]]. | + | * Creați o intrare nouă în ''procfs'' (''PROC_ENTRY_NAME'', definit în ''mmap-test.h'') care va afișa totalul memoriei mapate de procesul care a apelat read-ul pe acel fișier. Folosiți apelul [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/proc_fs.h#L30|proc_create]]. |
* Pentru parametrul ''mode'' folosiți ''0'', iar pentru parametrul ''parent'' folosiți ''NULL''. | * Pentru parametrul ''mode'' folosiți ''0'', iar pentru parametrul ''parent'' folosiți ''NULL''. | ||
* Operațiile sunt descrise în structura ''my_proc_file_ops''. | * Operațiile sunt descrise în structura ''my_proc_file_ops''. | ||
- | * În funcția de ieșire a modulului ștergeți intrarea ''PROC_ENTRY_NAME'' folosind [[http://lxr.free-electrons.com/source/fs/proc/generic.c?v=3.13#L484|remove_proc_entry]]. | + | * În funcția de ieșire a modulului ștergeți intrarea ''PROC_ENTRY_NAME'' folosind [[http://elixir.free-electrons.com/linux/v4.9/source/fs/proc/generic.c#L548|remove_proc_entry]]. |
- | * O utilizare (complexă) și descriere a interfeței [[http://lxr.free-electrons.com/source/include/linux/seq_file.h?v=3.7#L18|seq_file]] se găsește aici [[http://tldp.org/LDP/lkmpg/2.6/html/x861.html | acest exemplu]]. | + | * O utilizare (complexă) și descriere a interfeței [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/seq_file.h#L15|seq_file]] se găsește aici [[http://tldp.org/LDP/lkmpg/2.6/html/x861.html | acest exemplu]]. |
- | * Pentru acest exercițiu este suficientă doar o simplă utilizare a interfeței, descrisă [[http://lwn.net/Articles/22355/ | aici]]. Căutați **extra-simple**. Atenție, funcția ''create_proc_entry'' nu mai este disponibilă în versiunea 3.13 a kernelului. Va trebui să folosiţi funcţia [[http://lxr.free-electrons.com/source/include/linux/proc_fs.h?v=3.13#L30|proc_create]], care primeşte ca parametru suplimentar un pointer către operaţiile de tip fişier ce vor fi folosite pentru intrarea procfs. | + | * Pentru acest exercițiu este suficientă doar o simplă utilizare a interfeței, descrisă [[http://lwn.net/Articles/22355/ | aici]]. Căutați **extra-simple**. |
* În funcția de afișare ''my_seq_show'' va trebui să: | * În funcția de afișare ''my_seq_show'' va trebui să: | ||
- | * Obțineți structura [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.7#L311|mm_struct]] a procesului curent folosind funcția [[http://lxr.linux.no/#linux+v3.9.2/kernel/fork.c#L661|get_task_mm]]. | + | * Obțineți structura [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L396|mm_struct]] a procesului curent folosind funcția [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/sched.h#L2912|get_task_mm]]. |
* Procesul curent este indicat de variabila ''current'' de tip ''struct task_struct *''. | * Procesul curent este indicat de variabila ''current'' de tip ''struct task_struct *''. | ||
- | * Iterați prin toată lista de structuri [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.7#L220|vm_area_struct]] asociată procesului. | + | * Iterați prin toată lista de structuri [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L300|vm_area_struct]] asociată procesului. |
* Folosiți variabila ''vma_iterator''. | * Folosiți variabila ''vma_iterator''. | ||
* Porniți de la ''%%mm->mmap%%''. | * Porniți de la ''%%mm->mmap%%''. | ||
- | * Folosiți câmpul ''vm_next'' al [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.7#L220|structurii vm_area_struct]] pentru a parcurge lista de zone de memorie (vma-uri -- //virtual memory areas//). | + | * Folosiți câmpul ''vm_next'' al [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L300|vm_area_struct]] pentru a parcurge lista de zone de memorie (vma-uri -- //virtual memory areas//). |
* Opriți-vă când ajungeți la ''NULL''. | * Opriți-vă când ajungeți la ''NULL''. | ||
* Vă bazați pe ''vm_start'' și ''vm_end'' pentru fiecare structură pentru a deduce dimensiunea totală. | * Vă bazați pe ''vm_start'' și ''vm_end'' pentru fiecare structură pentru a deduce dimensiunea totală. | ||
* Afișați, folosind ''%%printk("%lx %lx\n, ... )%%'', ''vm_start'' și ''vm_end'' pentru fiecare structură ''vm_area_struct''. | * Afișați, folosind ''%%printk("%lx %lx\n, ... )%%'', ''vm_start'' și ''vm_end'' pentru fiecare structură ''vm_area_struct''. | ||
- | * Pentru a "elibera" structura [[http://lxr.free-electrons.com/source/include/linux/mm_types.h?v=3.7#L311|mm_struct]], decrementați reference counter-ul structurii folosind [[http://lxr.linux.no/#linux+v3.9.2/kernel/fork.c#L606|mmput]]. | + | * Pentru a "elibera" structura [[http://elixir.free-electrons.com/linux/v4.9/source/include/linux/mm_types.h#L396|mm_struct]], decrementați reference counter-ul structurii folosind [[http://elixir.free-electrons.com/linux/v4.9/source/kernel/fork.c#L877|mmput]]. |
- | * Folosiți [[http://lxr.linux.no/#linux+v2.6.38/include/linux/seq_file.h#L86|seq_printf]] pentru a scrie în fișier. | + | * Folosiți [[http://elixir.free-electrons.com/linux/v4.9/source/fs/seq_file.c#L413|seq_printf]] pentru a scrie în fișier. |
* Afișați **doar** domensiunea totală, fără alt mesaj/șir de caractere. **Nu** afișați nici măcar newline (''\n''). | * Afișați **doar** domensiunea totală, fără alt mesaj/șir de caractere. **Nu** afișați nici măcar newline (''\n''). | ||
- | * În funcția ''my_seq_open'' înregistrați funcția de afișare (''my_seq_show'') folosind apelul [[http://lxr.free-electrons.com/source/fs/seq_file.c?v=3.7#L581|single_open]]. | + | * În funcția ''my_seq_open'' înregistrați funcția de afișare (''my_seq_show'') folosind apelul [[http://elixir.free-electrons.com/linux/v4.9/source/fs/seq_file.c#L566|single_open]]. |
* Ca al treilea argument pentru ''single_open'' puteți folosi ''NULL''. | * Ca al treilea argument pentru ''single_open'' puteți folosi ''NULL''. | ||
- | * Pentru testare utilizați testul din directorul ''lin/test''. | + | * Pentru testare utilizați testul din directorul ''test/''. |
- | * Definiți ''TASK_4'' în ''mmap_test.c''. | + | * Rulați testul folosind comanda ''./mmap-test 4''. |
- | * Rulați testul. | + | |
* Testul așteaptă un timp (are o instrucțiune ''sleep'' internă). | * Testul așteaptă un timp (are o instrucțiune ''sleep'' internă). | ||
* Cât timp testul așteaptă, folosiți în altă consolă comanda ''pmap'' pentru a vedea mapările testului și a le compara cu cele obținute. | * Cât timp testul așteaptă, folosiți în altă consolă comanda ''pmap'' pentru a vedea mapările testului și a le compara cu cele obținute. | ||
* Puteți folosi comanda în forma<code> | * Puteți folosi comanda în forma<code> | ||
- | pmap $(pidof mmap-test) | + | cat /proc/$(pidof mmap-test)/maps |
</code> | </code> | ||
- | * Pentru a accesa altă consolă în mașina virtuală folosiți combinația de taste ''Alt+F2''. | + | <note> |
+ | * Pentru a accesa altă consolă porniți mașina virtuală în mod grafic și folosiți combinația de taste ''Alt+F2''. | ||
* Pentru a reveni înapoi în prima consolă folosiți combinația de taste ''Alt+F1''. | * Pentru a reveni înapoi în prima consolă folosiți combinația de taste ''Alt+F1''. | ||
+ | </note> | ||
==== Soluții ==== | ==== Soluții ==== | ||
* [[http://elf.cs.pub.ro/so2/res/laboratoare/lab11-sol.zip | Soluții exerciții laborator 11]] | * [[http://elf.cs.pub.ro/so2/res/laboratoare/lab11-sol.zip | Soluții exerciții laborator 11]] | ||
===== Resurse utile ===== | ===== Resurse utile ===== |