Warning
This page is located in archive. Go to the latest version of this course pages.

NOVA – Systémová volání a správa paměti

Na tomto cvičení se seznámíte s jádrem miniaturního OS NOVA a implementujete do něj systémové volání brk. NOVA je mikrohypervizor původně vyvíjený na TU Dresden, později ve firmě Intel a nyní převážně projektem GENODE. Na cvičeních však nebudete pracovat s kompletní verzí jádra NOVA, ale se zjednodušenou verzí pro výuku, která má pouze 2 tisíce řádek kódu.

Domácí příprava

Pro toto cvičení budete potřebovat následující:

  • aspoň trochu rozumět kódu v C++ a inline assembleru (viz 8. cvičení)
  • vědět, co to jsou systémová volání a proč/k čemu se používají (viz přednášky)
  • popis instrukce sysenter
  • vědět, co dělá systémové volání brk
  • rozumět rozdílu mezi uživatelským prostorem a prostorem jádra (viz přednášky)
  • vědět, jak CPU překládá virtuální adresy na fyzické (i386 používá dvoustupňové mapování 10-10-12)
  • viz přednášky, APO, https://www.youtube.com/watch?v=KNUJhZCQZ9c, případně další
  • stáhnout, rozbalit a ideálně i vyzkoušet (make run) operační systém NOVA
    • na vlastním pc budete potřeboval balíčky:
      libc6-dev-i386, qemu-system-i386
  • přečíst hlavní Makefile
  • přečíst funkci Ec::syscall_handler
  • přečíst funkci Ptab::insert_mapping (byla na přednáškách)
  • podívat se na třídu Kalloc

Zadání úlohy

Implementujte systémové volání brk s prototypem:

void *brk(void *address)

Toto systémové volání nastaví konec adresního prostoru procesu (tzv. program break) na danou adresu (parametr address). Tím se zvětší nebo zmenší množství alokované paměti, které může program využívat ke svému běhu. Program break je první adresa za koncem namapovaného virtuálního adresního prostoru.

Vaše řešení by mělo splňovat následující požadavky:

  • Po úspěšném návratu ze systémového volání je program break nastaven na hodnotu address. To znamená, že uživatelský program může používat paměť od adresy 0x1000 do address-1. Přístup na stránky začínající na adrese vyšší či rovné address nebude aplikaci dovolen.
  • Program break nesmí jít nastavit na nižší hodnotu, než je jeho hodnota při spuštění programu. Tím by se program připravil o část svého kódu, dat nebo zásobníku.
  • Program break nesmí jít nastavit na vyšší hodnotu než 0xC0000000. Tím by aplikace mohla přepsat jádro.
  • Při úspěšném dokončení je vrácena původní hodnota program break před vykonáním systémového volání. Při chybě je vrácena hodnota 0.
  • Pokud je address NULL (0), nejedná se o chybu a hodnota program break se nemění.
  • Při žádném volání brk nesmí dojít k “pádu” systému.
  • ABI systémového volání bude následující. Vstup: AL=3, ESI=address. Výstup: EAX=návratová hodnota.
  • Nově alokovaná paměť bude inicializována na nulu.
  • Při snižování hodnoty program break bude nepřístupná paměť dealokována, aby mohla být opět alokována později.
  • Při chybě alokace paměti v průběhu systémového volání nebude adresní prostor uživatelské aplikace změněn a částečně alokovaná paměť bude dealokována.
  • Při kompilaci nevypisuje kompilátor žádná varování.

Odevzdává se archiv se souborem ec_syscall.cc obsahující vaši implementaci, ideálně vytvořený pomocí

make hw10

Nápověda

  • Operační systém NOVA s testovací aplikací user/hello.c můžete nabootovat buď na fyzickém počítači pomocí zavaděče podporujícího multiboot (např. GRUB 2), ale pravděpodobně bude efektivnější ho pouštět jako virtuální stroj například v emulátoru Qemu. Pro to stačí spustit
    make run
  • Při vývoji operačního systému nelze používat debugger tak, jak jste zvyklí při vývoji aplikací. Ladit váš kód můžete buď přidáváním příkazů printf() na potřebná místa v kódu. Pokud vám to nestačí můžete použít parametr -gdb emulátoru Qemu, ale to je trochu komplikovanější.
  • Při zvětšování program break musíte alokovat paměť v jádře a namapovat ji do adresního prostoru uživatelské aplikace modifikováním stránkovacích tabulek. Inspirací vám může být funkce Ec::root_invoke(), která připravuje paměť pro spouštěný program. Funkce čte hlavičky z binárky aplikace, které si můžete zobrazit příkazem readelf –program-headers hello.
  • Při snižování program break naopak musíte mapování zrušit a paměť dealokovat.
  • Při startu uživatelského programu (např. hello) je jeho paměťová mapa následující (trochu zjednodušeno):
    • 0x00001000 – 0x00001fff – zásobník (4 kB), počáteční hodnota registru ESP je 0x2000.
    • 0x00002000 — 0xXXXXX000-1 — data programu (viz .data ve výstupu příkazu readelf –sections hello)
    • 0xXXXXX000 – 0xYYYYY000-1 — kód programu (viz .text ve výstupu příkazu readelf –sections hello)
    • 0xYYYYY000 — program break
  • Ke kódu jádra NOVA není žádná dokumentace, ale části, které budete potřebovat, jsou tak jednoduché, že byste měli být schopni jim porozumět na základě čtení kódu (a komentářů). Pokud však i přes veškerou vaší snahu něčemu nerozumíte, ptejte se na fóru.
courses/b4b35osy/cviceni/cviceni10_brk.txt · Last modified: 2017/12/06 09:50 by sojkam1