ОС2/Пројекат 2022

Извор: SI Wiki
Пређи на навигацију Пређи на претрагу

Пројекат 2022. године је први пројекат из Оперативних система 1 и 2 у ком се користи xv6 оперативни систем на RISC-V архитектури. У овом водичу се налазе корисни савети при изради пројекта.

Додавање интерфејса распоређивача

Интерфејс дефинисан поставком за распоређивач је исти онај из школског језгра:

struct proc *get(); // Дохватање спремног процеса из реда чекања
void put(struct proc *); // Убацивање спремног процеса у ред чекања

xv6 у себи садржи Round-robin распоређивач директно имплементиран у функцији scheduler(). Неопходно је заменити овај алгоритам са траженим интерфејсом. Места од значаја су она где процес мења стање.

  1. get() у scheduler() након укључивања прекида - прелаз из RUNNABLE у RUNNING.
  2. put() у yield() - кад процес предаје контекст неком другом процесу.
  3. put() у userinit() - кад се креира први кориснички процес.
  4. put() у fork() - кад се форкује нов процес.
  5. put() у wakeup() - прелаз из SLEEPING у RUNNABLE.
  6. put() у kill() - кад процес треба да се заврши треба да га пробудимо.

Имплементирање преотимања по временском квантуму

Концепт временског квантума (timeslice) из овог пројекта је исти као онај из школског језгра на ОС1. xv6 мења контекст (преотима) процесе на сваки тајмерски прекид. Ово се може лако променити да подржава преотимање након истека квантума или непостојање преотимања (nonpreemptive scheduling). Места од значаја:

  1. Позив yield() у usertrap() се треба догодити само ако је истекао квантум, или никад ако нема преотимања. Овде би се одузимала тренутна вредност све док квантум не истекне.
  2. Исто и за kerneltrap(), који је само случај тајмерског прекида у кернел режиму.
  3. Праћење временског квантума неког процеса се може имплементирати на разне начине, али најчешћи је памтити га у struct proc, где би онда требало постављати његову вредност у userinit() и fork().

Додавање новог системског позива

  1. Дефинишете потпис системског позива са корисничке стране у user.h
  2. Додати његов назив из претходног фајла у Perl скрипту usys.pl за генерисање кода за позив (не мењати usys.S јер је то аутоматски генерисан assembly фајл - брише се при сваком превођењу).
  3. Дефинисати број системског позива (22 је следећи у низу) у syscall.h
  4. Имплементирати системски позив у фајлу sysproc.c. Потпис мора бити uint64 sys_poziv(void)
    • Дохватање целобројних аргумената, показивача и стрингова је омогућено уз помоћне функције argint(), argaddr() и argstr() респективно у фајлу syscall.c.
    • Први аргумент помоћних функција је индекс аргумента у потпису функције са корисничке стране, а сама вредност се прослеђује преко показивача који је други аргумент.
    • Повратна вредност 0 из помоћних функција означава успех.
    • argraw(int n) директно враћа вредности регистара a0-a5 који се номинално користе за пренос аргумената при позиву процедуре.
  5. Додати назив функције из прошле тачке у низ показивача функције syscalls у syscall.c. Индекс функције у низу мора да се слаже из индекса у syscall.h.

Окружење

Makefile

Дебаговање корисничких програма

Да би дебаговали корисничке програме, морате у конфигурацији за дебаговање у окружењу променити бинарни фајл који ће gdb-multiarch да дебагује (подразумевано сам кернел).

  • Мени RunEdit ConfigurationsRemote DebugDebug (или ваш назив конфигурације) → Symbol file промените на бинарни фајл корисничког програма (налазе се у директоријуму /user/ и сви почињу са доњом цртом).
  • Поставите breakpoint, покрените ОС са qemu-gdb и у њему покрените изабрани програм.

Промена учестаности тајмерског прекида

У сврху тестирања на одбрани је понекад тражено да се повећа учестаност прекида ради прецизнијих мерења перформанси (помоћу системског позива uptime()) и видљивијег ефекта распоређивања. Интервал тајмера се може променити у фајлу start.c у функцији timerinit().

Тумачење scause и sepc

Прескочене су резервисане вредности.

scause вредност Значење Потенцијални проблем
0 Адреса у PC није поравната Кернел је променио контекст у невалидан процес (вероватно је распоређивач вратио невалидан процес).
1 Грешка у приступу инструкцији
2 Илегална инструкција Уколико користите floating-point типове, они нису подржани на овој имплементацији RISC-V.
3 Breakpoint Не би требало да се појави као разлог за панику.
4 Адреса са које се чита није поравната Лош показивач.
5 Грешка у приступу при читању
6
  • Адреса у коју се пише није поравната
  • Атомична инструкција приступа адреси која није поравната
7 Грешка у приступу при писању/атомичној инструкцији.
8 ecall из корисничког режима Не би требало да се појави као разлог за панику.
9 ecall из супервизорског (кернел) режима Не би требало да се дешава уопште у xv6.
c Странична грешка при учитавању инструкције Кернел је променио контекст у невалидан процес (вероватно је распоређивач вратио невалидан процес).
d Странична грешка при читању
  • Кернел је променио контекст у невалидан процес (вероватно је распоређивач вратио невалидан процес).
  • Лош показивач.
f Странична грешка при писању/атомичној инструкцији
  • Кернел је променио контекст у невалидан процес (вероватно је распоређивач вратио невалидан процес).
  • Лош показивач.

Вредност sepc регистра означава вредност PC у тренутку кад је настала грешка. Може се тачно пронаћи место у коду претраживњем ове адресе у фајлу kernel.asm који садржи и C код кернела и генерисани RISC-V асембли са тачном адресом инструкција.