home 
news 
thread sync 
sync problems 
project intro 
assignment 1 
assignment 2 
assignment 3 
resources 
examples 
rules 
submit howto 
   
 

Apeluri de sistem si spatii de adrese

Apeluri de sistem

In acesta parte a proiectului veti completa sistemul Nachos astfel incat sa fie capabil sa ruleze programe in mod utilizator. Deocamdata, nu ne intereseaza multiprogramarea si vom avea un singur program utilizator la un moment dat in memorie.

Atunci cind ruleaza, un program utilizator foloseste un spatiu propriu de memorie, diferit de cel al nucleului. De asemenea el trebuie sa se execute intr-un mod al procesorului care sa nu-i permita accesul la anumite instructiuni si functii.

Apelul unei functii din sistemul de operare nu se poate face, prin urmare, in mod obisnuit, deoarece aceste functii (apelurile de sistem) nu sunt adresabile din spatiul de adrese al procesului. Mai mult, chiar daca ar fi adresabile (exista situatii in care sunt), un simplu apel de functie nu este suficient, codul sistemului de operare trebuie sa se execute in modul supervizor (sau modul nucleu) al procesorului. De aceea, apelurile de sistem se efectueaza prin mecanisme similare intreruperilor hardware. Astfel, procesorul MIPS pe care il emuleaza Nachos are o instructiune syscall, care declanseaza o exceptie la nivelul procesorului. Exceptiile si intreruperile sunt tratate de obicei uniform de procesoare, ele determinand saltul la o adresa prestabilita. In cazul unui syscall, aceasta adresa corespunde unei rutine de tratare care va determina tipul apelului de sistem dorit si va executa functia corespunzatoare.

Pe langa apelul in sine, mai exista si problema schimbului de informatii. In cazul apelurilor de functii, parametri acestora sunt transmisi prin stiva, la fel si rezultatul functiei. In cazul apelurilor de sistem, de obicei parametri si rezultatul sunt transmisi prin registri. Exista situatii in care dorim sa transferam cantitati mai mari de date; intr-un apel sistem write , rutina corespunzatoare din nucleu trebuie sa poata citi datele utilizatorului si sa le trimita la un anumit dispozitiv. Aceste date nu pot fi transmise, in mod evident, prin registri. De obicei se transmite adresa zonei de date (printr-un pointer). Problema este ca adresa respectiva nu are sens in spatiul de adrese al nucleului. Exista chiar situatii (memorie virtuala, de exemplu) cand, numeric vorbind, spatiile de adrese se suprapun. Prin urmare este necesar un mecanism prin care nucleul sa poata citi si scrie in spatiul de adrese al procesului utilizatorului. Acest mecanism este dependent de platforma si de sistemul de operare.

Programe utilizator in Nachos

Nachos ruleaza programele utilizator in cate un fir de executie al nucleului. Fiecare astfel de fir de executie ruleaza masina virtuala care emuleaza procesorul MIPS. Programele astfel rulate se vor compila si asambla pentru acest procesor, codul fiind interpretat, instructiune cu instructiune, de metoda Machine::OneInstruction. Atunci cand o instructiune cauzeaza o exceptie (un syscall, o eroare de adresare, etc.), emulatorul da controlul unei rutine de tratare din nucleu (ExceptionHandler()), prin invocarea metodei Machine::RaiseException().

Transmiterea parametrilor catre apelurile sistem se face de obicei (si in cazul Nachos) prin registrii procesorului. In particular pe arhitectura simulata (MIPS R3000), si apelurile normale de functii C folosesc registri. De aceea, in rutinele corespunzatoare apelurilor sistem din test/start.s nu veti gasi cod care sa incarce parametrii functiilor in registri, acest cod este generat de compilator.

Cateva exemple de programe se gasesc in directorul "test". Compilarea acestora (vezi test/Makefile) se face cu un cross-compiler. Pentru a adauga propriile programe, creati-le tot in directorul "test" si modificati fisierul test/Makefile. Observati ca trebuie apelat utilitarul coff2noff, pentru a transforma fisierul executabil rezultat in formatul inteles de Nachos. De asemenea, observati ca in faza de editare de legaturi se include un program test/start.s, care contine functii (in limbaj de asamblare) pentru apelurile sistem. Acest program trebuie sa fie primul in linia de comanda, fata de celelalte fisiere obiect, pentru a fi pus la inceputul executabilului.

Intrare/Iesire in programele utilizator

Din pacate, nu avem la dispozitie o biblioteca standard pentru programele utilizator. Acestea sunt scrise in C, dar nu pot apela functii precum printf(), scanf(), strcpy(), etc. Toate operatiile de intrare/iesire trebuie efectuate prin intermediul apelurilor de sistem.

Pentru a citi si tipari date la consola, un proces Nachos va trebui sa aiba deschise automat doua fisiere (cu identificatorii ConsoleInput si ConsoleOutput, vezi userprog/syscall.h) corespunzatoare intrarii si iesirii standard, astfel incat Read() si Write() sa poata sa le foloseasca fara ca procesul sa fie nevoit sa le deschida in prealabil. Operatiile de citire, respectiv scriere, la aceste "fisiere" vor trebui efectuate cu ajutorul dispozitivului Nachos Console (vezi machine/console.*).

Pentru fisiere folositi clasele FileSystem si OpenFile. Nachos vine cu o implementare "stub" pentru sistemul de fisiere, care foloseste sistemul de fisiere real din sistemul de operare in care rulati Nachos.

"Driver" pentru dispozitivul temporizator (ceas)

Pe linga alte dispozitive, un sistem de calcul are in general si un circuit ce genereaza intreruperi la intervale regulate de timp -- un ceas. In Nachos, codul ce simuleaza acest dispozitiv se regaseste in clasa Timer. Veti scrie un driver pentru acest dispozitiv, care va permite proceselor utilizator sa ceara sa fie oprite pentru un interval de timp specificat (multiplu al unui interval de baza). Mijloacele de interactiune cu driver-ul cit si acest interval de vaza sint la latitudinea fiecarei echipe.

Mersul lucrarii

  1. Studiati mecanismul prin care sunt implementate exceptiile in Nachos. Examinati fisierele machine/machine.cc, machine/mipssim.cc, userprog/exception.cc
  2. Cititi prototipurile apelurilor sistem in userprog/syscall.h .
  3. Studiati fisierul userprog/progtest.cc si test/start.s .
  4. Explicati executia programului test/halt, pas cu pas.
  5. Implementati apelul sistem Exit.
  6. Studiati fisierele filesys/filesys.h si filesys/openfile.h. Observati ca exista o implementare "stub", folosind fisierele din sistemul de operare gazda (UNIX/Linux), pentru lucrul cu fisiere.
  7. Implementati apelurile de sistem pentru lucrul cu fisiere: Create(), Open(), Read(), Write(), Close(). Folositi pentru aceasta metodele claselor FileSystem si OpenFile.
  8. Implementati driver-ul pentru consola si ceas.

Documentatie

Pe langa codul in sine, cititi urmatoarele:
  • "A Roadmap Through Nachos", capitolul 4
  • "A Roadmap Through Nachos", sectiunea 6.3
  • "A Roadmap Through Nachos", sectiunea 2.5
  • ../doc/userprog.ps

Observatii

  • Lucrati in subdirectorul "userprog".
  • Atunci cind se produce o exceptie, registrul PC nu este incrementat, deoarece s-ar putea sa trebuiasca sa se re-execute instructiunea curenta (de exemplu, in cazul utilizarii memoriei virtuale, atunci cand o pagina nu se gaseste in memorie; aceasta pagina este adusa, dupa care instructiunea este executata din nou). Din acest motiv, atunci cand tratati o exceptie, va trebui sa aveti grija sa setati in PC valoarea corespunzatoare. Pentru syscall, PC va trebui avansat corespunzator.
  • Masina virtuala Nachos foloseste, in diverse scopuri, cativa registri in plus fata de cei "vizibili" ai procesorului MIPS. Doi dintre acestia sunt registers[PrevPCReg] si registers[NextPCReg]. Pe langa actualizarea lui registers[PCReg], trebuie actualizati si acestia.
  • Este util sa studiati fisierele din subdirectorul "machine", pentru a intelege cum functioneaza emulatorul.
  • Trebuie sa implementati o metoda prin care sa accesati, din functiile nucleului Nachos (apeluri de sistem si altele), spatiul de adrese al masinii emulate.
  • Scrieti macar un program de test, care sa foloseasca toate apelurile de sistem pe care le-ati implementat.
  • Folositi un debugger (gdb sau interfata grafica pentru acesta, ddd).

Alte observatii

Veti avea de implementat functii corespunzatoare apelurilor sistem de mai jos:
  • Exit()
  • Open()
  • Close()
  • Read()
  • Write()
  • Create()
Pentru a face acest lucru, va trebui sa va scrieti si un numar de alte functii si structuri de date, cum ar fi: comunicarea intre spatiul de adrese al nucleului si cel al proceselor utilizator, generarea si gestionarea identificatorilor de fisiere (OpenFileId), etc.

Pentru acesta parte a proiectului un singur program utilizator va fi rulat la un moment dat in memorie. Cu toate acestea, in partea a 3-a vom avea mai multe procese. De aceea, scrieti functiile voastre astfel incat sa poata fi folosite fara probleme in mai multe fire de executie simultan (ca exemplu, mai multe procese vor putea apela simultan Open). Pentru aceasta va fi nevoie sa folositi mecanisme de sincronizare.

Este foarte important sa faceti toate verificarile necesare astfel incat, daca utilizatorul transmite parametri eronati apelurilor sistem, nucleul Nachos sa nu fie compromis.