JÁDRO VERSUS ASEMBLER

Jádro plní dvì základní funkce: implementuje mechanismus doruèování zpráv a rídí plánování procesu.Mimo to obsahuje nejnizší úroven obsluzných rutin prerušení a zajištuje prevod hardwarového prerušení na zaslání zprávy príslušnému tasku. Mechanismus predávání zpráv bylo náplní prednášek. Doposud jsme se v souvislosti s predáváním zpráv odkazovali na primitiva SEND, RECEIVE a SENDREC.Jejich skutecná implementace je realizována pomocí maker(viz makra.h), jez jsou vyuzívána ostatními vrstvami systému, vcetne systémových knihoven. Makro se rozvine na vyvolání softwarového prerušení 31h, které je nasmerováno nadále popisovanou rutinu jádra s_call,jediný vstupní bod do jádra. Parametry volání se predávají v registrech. Jde zejména o informaci o typu primitiva (SEND/RECEIVE/SENDREC,TRAP,DIE_TRAP), identifikace procesu, kterému se má zpráva predat, resp. od kterého se má zpráva prevzít a pointer na buffer se zprávou (near pointer, v rámci adresového prostoru práve bezícího procesu).Nevyuzitá prerušení jsou nasmerovány na obsluznou rutinu expected_int(),volá se save(), provede se výpis chybového hlášení prostrednictvím BIOSu, a restart().

Kernel sestává ze tøí zdrojových souboru: PROC.C,MPX88.C a KLIB.C poslední dva jsou napsány mou malickostí v céckovské konvenci , s vyuzitím direktivy ASM.

Kernel obhospodaøuje následující promìnné:

int cur_proc - index práve bezícího procesu v tabulce proc[]
struct struct_proc *proc_ptr; /* &proc[cur_proc]) */
- pointer na prvek proc[] patrící práve bezícího procesu v tabulce
struct struct_proc *bill_ptr;
- pointer na (uzivatelský) proces, kterému se bude úctovat tik hodin
struct struct_proc *rdy_head[NQ];
- pointer na pole zacátku front behuschopných procesu
struct struct_proc *rdy_tail[NQ];
- pointer na pole koncu front behuschopných procesu

unsigned busy_map;

- bitmapa: každý bit odpovídá jednomu tasku. Jednicka na príslušném bitu indikuje, ze se obsluzná rutina prerušení svázaného s daným taskem pokoušela predat tasku zprávu,ale task byl zaneprázdnen. Proto se musí funkce interrupt() pri dalším prerušení pokusitzprávu dorucit znovu. Zpráva je mezitím ulozena na odpovídající pozici pole task_mess[NR_TASKS].Pole pro ulození zpráv o prerušení, které dosud nemohly být doruceny príslušným taskum z duvodu jejich zaneprázdnenosti.

proc_ptr int_message - buffer pro zprávu, která se vytvárí v dobe prerušení a odesílá se príslušnému tasku
int sig_procs - pocet procesu, jimz má být dorucen signál


MPX88.C


Nejnizší úroven pøepínání procesù a obsluhy prerušení. Obsahuje zejména tyto rutiny:

s_call ()

tty_int () ... interrupt, vstupní bod pøerušení od klavesnice volá k_save(), keyboard(), k_restart ().

hdd_int () ... interrupt - vstupní bod pøerušení od disku, volá k_save(), nachysta message, vola k_interrupt(), k_restart().

floppy_int () ... interrupt ,vstupni bod preruseni od FDD vola k_save(), nachysta message, vola k_interrupt(), k_restart().

clock_int () ... interrupt, vstupni bod pøeruseni od hodin, volá k_save(), nahysta message, vola k_interrupt(), k_restart().

k_save ()

k_restart ()

expected_int() - pri vstupu oèekáváme DS=DS jádra.Implementace TRAP ,vypise zpravu,oproti DIE_TRAP se necykli,požívá se k hlášení že nìjaký proces volá neobsazené pøerušení.

unexpected_int() - implementace DIE_TRAP se cykli,požívá se k hlášení že nìjaký proces volá neobsazené pøerušení.Volá k_save(),vypis_msg_bios(),k_restart().

vypis_msg_bios() - je ve skutecnosti vypis_msg_bios(offset_textu (v ramci DS), delka_textu, error_kod) Je-li error kod=0, nevypise se error kod .Jedna se o jednoduchou funkci,která nabere parametry se zásobníku,tudíž pøed každým voláním je nutno nachystat a vypíše hlášeni pomocí služby biosu 10h.

Obsluha pøerušení 31h

Voláno z nejnizších vrstev obsluhy prerušení (MPX88.C), pokusí se urèenému tasku zaslat
zprávu a tím dosáhnout jeho naplánování. Zpráva se zde ovšem nezasílá bezným primitivem SEND,
které muze zpusobit zablokování odesílatele do doby, kdy bude adresát schopen prevzít zprávu,
ale zvláštní funkcí mini_send(), která indikuje úspech odeslání jako návratový kód. Jako odesílatel
zprávy se namísto pozice odesílatele v proc[] uvádí zvl. kód HARDWARE. V prípade, ze se predání
zprávy nepodarilo (task byl zaneprázdnen), nastav príslušný bit v busy_map a zprávu uschovej
do task_mess. Navíc, pokud šlo o zprávu pro clock task, zvyš hodnotu promenné lost_ticks,
aby pozdeji bylo mozné opozdené prerušení zkompenzovat. Pokud se zpráva odeslala, zruš príslušný
bit v busy_map, byl-li nastaven.At jiz se zaslání zprávy podarilo nebo ne, projde se ve smycce busy_map a vzdy se pokusíme odeslat zprávu tem taskum, kterým mela a doposud nemohla být dorucena. V prípade úspešného dorucení
se samozrejme nuluje príslušný bit busy_map.Protoze v mini_send() mohlo dojít k naplánování tasku s vyšší prioritou, nez má práve bezící proces, zkoumáme, zda práve bezící proces je uzivatelským (nebo dokonce idle). Pokud tomu tak je a ve fronte
ceká nejaký task schopný behu (rdy_head[TASK_Q]!=NULL), provede se preplánování voláním funkce pick_proc().
Ta muze zmenit hodnotu cur_proc a po návratu z interrupt() rutina restart provede prechod k jinému procesu,
nez bezel doposud.

k_save a k_restart

Slouží k uložení a obnovení registru do/z tabulky procesu a to do/z pozice,na kterou ukazuje cur_proc. Jelikoz se mezi voláním save a restart muze hodnota cur_proc zmenit (pokud byla zavolán plánovac), lze takto provádet prepínání mezi procesy. Plánovac zajistí pouze nastavení cur_proc, samotné uschování puvodních obsahu registru a jejich nové naplnení provedou save a restart. Rutina save navíc nastavuje zásobník na zásobník kernelu (k_stack[]). Pokud v okamziku, kdy je vyvoláno restart, není zádný proces schopen behu (cur_proc=IDLE), provede se odskok na zvláštní smycku, ve které se povolí prerušení a instrukcí wait se ceká na další prerušení, které zpusobí, ze se nekterý task stane schopným behu.restart koncí iret => znovupovolení prerušení, na stacku musí být nové CS:IP:FLAGS.

k_save () - uschová registry do proc[cur_proc],nastaví DS na DS jádra abychom byli schopni vidìt strukturu proc.Zachovává AX, BX a DX (kvuli makrum SEND/RECEIVE/TRAP)

k_restart () - obnoví registry z proc[cur_proc] a obnovi beh procesu/tasku cur_proc. Je-li cur_proc==IDLE : skoc na idle (WAIT, skok zpet na WAIT)


s_call

Obsluha SW prerušení pro predávání zpráv. V ní se uschovají registry (save), z predaných hodnot (caller=cur_proc, destination, typ pozadavku:

SEND,RECEIVE,TRAP,DIE_TRAP trap od send/receive message (hlavní a jediný vstupní bod SW do jadra), volá k_save(), nachysta parametry a zavola sys_call() a k_restart().

Nìkterá hlášení systému

char dtrap_txt[26] = "System halted: DIE_TRAP #:";

char trap_txt[8] = "TRAP #: ";

char unexpected_int_txt[14] = "Unexpected int";

SEND/RECEIVE/SENDREC, ptr na buffer se zprávou)se zformulují parametry (vytvorí se zásobník obsahující tyto parametry) pro C-funkci sys_call() a tato funkce se zavolá. Ve funkci muze mj. dojít k preplánování, coz se projeví zmenou hodnoty promenné cur_proc. Po návratu se volá restart, která nastaví registry podle práve provádeného procesu (prommenná cur_proc).

Souèástí tìla funkce je test, zda
odesílatel a príjemce zprávy lezí ve stejné, popr. prilehlé vrstve (jinak se komunikace neumožní).
V prípade zasílání zprávy uzivatelským procesem (resp. jeho knihovanami) se umozní pouze volání primitiva
SEND_REC. Pro zaslání zprávy se zavolá funkce mini_send(caller,dest,mess_ptr), pro prevzetí
pak mini_rec(caller,src,mess_ptr).


Nevyužitá pøerušení jsou nasmìrovány na tuto obslužnou rutinu. Volá se k_save(), provede se výpis
chybového hlášení prostøednictvím BIOSu, k_restart().


KLIB88.C


Implementuje skupinu pomocných nízkoúrovnových funkcí, které mohou být volány tasky
(pripomenme, ze jádro je s tasky slinkováno). Jde napr. o funkce podporující kopírování bloku
(lineární) pameti, povolování prerušení, vstup/výstup z portu atd., viz pseudokód.
Jelikoz techto rutin vyuzívají tasky, je nezbytné zdokumentovat jejich rozhraní a funkci
a poskytnout odpovídající C-headery, které umožní volání rutin z C-kódu stejne jako by se volaly
C-funkce. Parametry funkcí se tedy pøedávají pøes zásobník ve volací konvenci podporované jazykem C
Vyšší úroven obsluhy prerušení (prevod na zprávy), mechanismus dorucování zpráv, plánovac naleznete v PROC.C od mého kolegy p.Harabiše.

k_phys_copy (dword src, dword dest, word count)

Kopie dat odkudkoli kamkoli v ramci cele pameti .adresy jsou 32-bitove linearni.Pøedpokládá se že bloky dat se nepøekrývají a cílová èi zdrojová adresa spolu s délkou bloku nepøesáhne 20Bit (1MB) k vuli 8086.Délka bloku nesmí být vìtší než (65 535-15) Byte.Lineární adresy se pøepoèítají na Seg:Off a kopírování se dìje pomocí funkce MOVSB.

k_cp_mess (src,src_addr,dest_addr)

Kopie message od odesilatele k prijemci a nastavení ve zprávì sendera

k_port_out (port, value) - zápis hodnoty na port

k_port_in (port) - ètení hodnoty z portu

Nìkolik funkcí které blokují masku IF ve stav.reg.procesoru

k_lock () - zákaz pøerusení, uschová pùvodni hodnotu (povoleno/zakázáno) do globální promìnné:

unsigned int IF = 1;

k_restore () - obnoveni predchoziho stavu interrupts (z glob. promenne)

k_unlock () - povolení pøerusení

{ asm sti asm mov IF, 1 //1 - preruseni povoleno }

k_vid_copy (?) - zápis dat do video RAM (s èekánim na retrace (?) )

/* NEZKONTROLOVANO !!! */

Parametry budou:

-segment a offset, na nìmž jsou data

-linearni offset v ramci obrazovky (videosegmentu-B800h)

-délka kopírované oblasti - žádne výøezy !!!




DODATEK:Rutiny plánovaèe

pick_proc()

Hlavní rutina plánovace. Nastavuje cur_proc (a proc_ptr) na proces s nejvyšší prioritou, který
má dále bezet. Pokud zádný proces není schopen behu, nastaví se cur_proc=IDLE a proc_ptr na jinak
nevyuzitý slot tabulky procesu, aby bylo kam uschovat registry pri dalším prerušení. Promenná bill_ptr
se stále udrzuje ukazující na proces, kterému má být úctován následující tik hodin.

ready()

Pripojí proces, který byl prohlášen za schopný behu, na konec príslušné fronty

unready()

odstraní proces, který nadále není schopen behu z príslušné fronty procesu schopných behu

sched()

rutina vyvolávána periodicky clock taskem pri vypršení casového kvanta. Jestlize je ve fronte
pripravených uzivatelských procesu více nez jeden proces, tento proces se z cela fronty presune
na její konec. Tím se dostává ke slovu další uzivatelský proces. Následne se volá pick_proc()
pro naplánování procesu s nejvyšší prioritou.


Autorem výše vlozených pseudokódu ,které mely poslouzit jako zadání je, cvicící p.Ing.Grygárek

Autorem imlpementace asembleru KERNELU a tudíz i této stránky jsem já Pavel Hruzík sk.L93558

V Ostrave 19.1.1198