1 / 41

Оперативни системи 1

Оперативни системи 1. В e жбе Lista predmeta: i r2os1@lists.etf.rs. Увод у архитектуру 8086. 16-битни микропроцесор. Адресибилна јединица бајт. Регистри: сегментни општенем e нски индексни базни регистар BP и показивач на стек SP. Сегментни регистри. CS – код сегмент ,

benard
Download Presentation

Оперативни системи 1

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Оперативни системи 1 Вeжбе Lista predmeta: ir2os1@lists.etf.rs

  2. Увод у архитектуру 8086 • 16-битни микропроцесор. • Адресибилна јединица бајт. • Регистри: • сегментни • општенемeнски • индексни • базни регистар BP и показивач на стек SP.

  3. Сегментни регистри • CS – код сегмент, • SS – стек сегмент, • DS – сегмент података и • ES – екстра сегмент за податке • Користе се за формирање адресе: • адреса је 20-битна • састоји се од: • сегмента –SEG(16 бита) • и офсета (померај) – OFF (16 бита) • физичка адреса је 20 бита и рачуна се: 0х10 * SEG + OFF • сегмент је увeк један од 4 сегментна регистра • ВАЖНЕ НАПОМЕНЕ: • ови сегменти немају никакве везе са виртуелним адресирањем које се налази код модерних процесора • примeтити да се неке физичке адресе могу добити комбинацијом више различитих парова сегмената и офсета.

  4. Општенамeнски регистри • AX, BX, CX и DX, • Сваки по 16 бита, • Сваки се може посматрати као два 8-битна:AX -> AH (виши бајт) и AL (нижи бајт)BX -> BH (виши бајт) и BL (нижи бајт)CX -> CH (виши бајт) и CL (нижи бајт)DX -> DH (виши бајт) и DL (нижи бајт)Примeр:mov AX, 1234h (исто што и 0х1234 на C-у) AH AL 12h 34h

  5. Индексни и базни регистри • Индексни: • SI i DI, • Сваки по 16 бита, • Користе се при индексном адресирању (приступ елементима низа). • Примeр: mov AX, niz[SI] • Базни регистар за приступ стеку: • BP • 16 бита. • Користи се за приступ стеку (приступ стварним аргументима и локалним промeнљивим процедуре).

  6. Стек • Постоје две поделе (4 врсте) стекова: • да ли расте ка вишим адресама или ка нижим? • да ли показивач на стек показује на заузету локацију на врху стека или на прву слободну локацију изнад врха стека? • Стек процесора 8086: • расте ка нижим адресама • SP указује на заузету локацију на врху стека

  7. Стек позива потпрограма • Са BP Zašto BP? Zar nije dovoljan SP?

  8. Стек позива потпрограма mySub: ; Start of procedure push bp mov bp, sp sub sp, n ; reserve n bytes ; of local storage push reg1 ; save registers push reg2 ; do some processing pop reg2 pop reg1 add sp, n ; just the opposite mov sp, bp pop bp ret ; we are done. Кonvencija pri pozivupotprograma: Napomena: Parametri se stavljaju na stek u obrnutom redosledu od onog navedenog pri deklaraciji f-je.

  9. Потпрограм на C-у: int fun(int a){ return a; } Исти потпрограм на асемблеру: fun proc push BP mov BP, SP mov AX, [BP+6] pop BP ret Како се потпрограму прослеђују параметри?

  10. fun proc push BP mov BP, SP mov AX, [BP+6] pop BP ret ... push 1234h call fun add SP, 2 Напомена: Претпоставља се huge mem. model Стек: xx xx +7 12виши бајт на вишој адреси +6 34 нижи бајт на нижој адреси +5 retCShh – high byte +4 retCSl l – low byte +3 retPCh +2 retPCl +1 oldBPh +0 oldBPl Како се потпрограму прослеђују параметри? BP АХ = 0х1234 SP

  11. Задатак 1. • Написати програм на програмском језику C који ће помоћу једне функције бесконачно исписивати неки текст.Решење може да буде некоректно у смислу да ће оперативни систем у коначном времену пријавити грешку у извршавању програма и прекинути његово извршавање. Није дозвољено коришћење петљи. #include<stdio.h> void a(){ printf("...\n"); a(); } void main(){ a(); } BP Стек: (у једном реду једна реч – 2B)xx retCSend_mainretPCend_mainoldBP_main retCSend_aretPCend_aoldBP_a1 retCSend_aretPCend_aoldBP_a2 ... Шта је проблем? SP

  12. Задатак 2. • Написати програм на програмском језику C који ће бесконачно понављати исписивање неког текста. Није дозвољено користити петље и програм мора бити исправан, тј. да ОС никада не пријави грешку за тај програм.

  13. #include <stdio.h> int i; void a(){ //cuva pov. adr. asm{ push ax mov ax, [bp]+2 mov i,ax pop ax } } void b(){ //menja pov. adr. asm{ push ax mov ax,i mov [bp]+2,ax pop ax } } int main(){ a(); printf("Izmedju a i b.\n"); b(); return 0; } Решење printf_OFFSET BP_main AX_old return_OFFSET BP_main AX_old i: printf_OFFSET

  14. Задатак 3. • Написати програм за процесор 8086 који треба да изврши неки потпрограм, али тако да се нигдe у коду не види позив тог потпрограма.

  15. unsigned int SP_f, SP_main; unsigned int stek_f[1024]; void _dispatch1(){ asm { mov SP_main, sp //cuva sp od main mov sp, SP_f // restauira sp od f } } void _dispatch2(){ asm { mov SP_f, sp //cuva sp od f mov sp, SP_main // restauira sp od main } } void f(){ //kod funkcije //... //kod za izlazak iz funkcije: dispatch2(); } void main(){ stek_f[1023] = FP_OFF(f) SP_f = FP_OFF(stek_f+1022); dispatch1(); } stek_f+1023 stek_f SP_main SP_f На почетку сваке функције: push BP mov BP, SP Решење – варијанта 1 На почетку сваке функције: push BP mov BP, SP На крају сваке функције: pop BP ret SP BP xx PC_main_} BP_main ... f //adresa funkcije f 0 ... ... PC FP_OFF(f) dohvata offset adrese f-je f 0

  16. unsigned int SP_f, SP_main; unsigned int stek_f[1024]; void _dispatch1(){ asm { mov SP_main, sp //cuva sp od main mov sp, SP_f // restauira sp od f } } void _dispatch2(){ asm { mov SP_f, sp //cuva sp od f mov sp, SP_main // restauira sp od main } } void f(){ //kod funkcije //... //kod za izlazak iz funkcije: dispatch2(); } void main(){ stek_f[1023] = FP_OFF(f) SP_f = FP_OFF(stek_f+1022); dispatch1(); } stek_f+1023 stek_f SP_main SP_f Решење – варијанта 1 Извршава се код функције PC На почетку сваке функције: push BP mov BP, SP xx PC_main_} BP_main ... f //adresa funkcije f 0 ... ... SP BP 0 На крају сваке функције: pop BP ret PC_f_}

  17. unsigned int temp; void _dispatch1(){ asm { pop temp push f push temp } } void f(){ //kod funkcije //... } void main(){ dispatch1(); } Решење– варијанта 2 temp: BP_main SP xx PC_main_} BP_main BP_main f //adresa funkcije f

  18. Задатак 4. • За процесор 8086 и код написан на програмском језику C, омогућити да се функције извршавају конкурентно, а да се прелазак са функције на функцију обавља помоћу корутина. Сматрати да се користе само регистри АX, BX, CX и DX. Остале занемарити. Регистре чувати на стеку.

  19. Решење • Korutina – eksplicitno odricanje od procesora jedne nit u korist druge niti. Potrebno je sacuvati kontekst, kako bi kasnije mogao da se restaurira. • Kontekst procesora(processor execution context): sve vrednosti iz procesorskih registara koje je potrebno sačuvati da bi se izvršavanje nastavilo od mesta napuštanja: • Mesto u programu na kome se stalo - PC • Podaci u procesoru – registri opšte namene • Lokalni podaci potprograma i “trag” izvršavanja – sve na steku – SP • Prelazak sa izvršavanja jednog procesa na drugi – promena konteksta(context switch): • sačuvati kontekst koji se napušta • povratiti kontekst na koji se prelazi

  20. Решење • Потребно извршити следећи код: running->sp = SP; // cuvanjeSP гдe је: • sp поље PCB структуре • SP регистар • На језику С у општем случају није могуће приступити жељеном регистру. • Зато се умећу сегменти асемблерског кода. • Асемблерски еквивалент горе наведеној наредби је (под претпоставком PCB структуре дате на следећем слајду): asm{ mov BX, running // BX = running mov [BX], SP // [BX] = SP - indirektno registarsko adresiranje } -примeтити да се BX користи за адресирање, па се на почетку његов садржај мора привремено сачувати (нпр на стеку)

  21. struct PCB{ unsigned sp; unsigned* stack; }; PCB *p[3]; PCB* running; int nextThread; //makro #define dispatch(x) { nextThread = x; \ _dispatch(); } void _dispatch(){ asm { // cuva registre na steku push ax //sta bi se desilo da ne cuvamo AX? push bx push cx push dx mov bx, running //upisuje adresu mem. lok. mov [bx], sp //cuva sp } running=p[nextThread]; asm { mov bx, running mov sp, [bx] // restauira sp pop dx // restauira registre pop cx pop bx pop ax } } Решење При уласку у функцију dispatch() на стек ће се ставити повратна адреса. То је адреса прве инструкције после позива dispatch() и уједно и адреса од које треба наставити прекинуту нит. По уласку у функцију, наилази се на прве две инструкције сваке функције: push BP mov BP, SP Као резултат прве инструкције на стеку је сачувана вредност BP регистра која је коришћена у прекинутој нити и која ће се користити опет по повратку у ту нит. running је показивач на PCB структуру нити која се тренутно извршава. Да би се умeсто нити, која се извршавала до позива _dispatch() наставила нова нит, неопходно је поставити да running показује на PCB те нове нити. У овом задатку је претпостављено да се нова нит одрeђује уписом одговарајуће вредности у nextThread. Чувају се и 4 регистра (тако је речено у поставци задатка). У општем случају, неопходно је сачувати све регистре осим CS:PC (већ сачувано при уласку у функцију) , BP (већ сачуван првом инструкцијом функције f()) i SS:SP (биће сачувани у PCB). Чува се показивач на стек. Инструкције: mov bx, running mov [bx], sp су еквивалентне са C кодом: running->sp = SP //SP je registar Рестаурација стека нове нити: SP = running->sp; Рестаурација остатка контекста: -прво регистри DX, CX, BX i AX -рестаурација BP са pop BP -рестаурација PC са ret

  22. void a(){ for (int i = 0; i < 3; ++i) printf("U a() %d\n",i); asm { mov ax, 7 } dispatch(2); asm { mov i, ax } printf(" u a() ax = %d\n",i); for (i = 0; i < 3; ++i) printf("U a() %d\n",i); dispatch(2); } void b(){ for (int i = 0; i < 3; ++i) { printf("U b() %d\n",i); } asm { mov ax, 2 } dispatch(1); for (i = 0; i < 3; ++i) { printf("U b() %d\n",i); } dispatch(0); } Решење

  23. void createThread(PCB *newPCB, void (*body)()){ unsigned* st = new unsigned[1024]; unsigned newPC = FP_OFF(body); st[1023] = newPC; //upisuje se rec - int //pocetni kontekst (proizvoljne vrednosti) //st[1023-1018]={PC,BP,AX…DX} newPCB->sp = FP_OFF(st+1018); newPCB->stack = st; } void delete_all(){ delete [] p[1]->stack; delete [] p[2]->stack; delete p[0]; delete p[1]; delete p[2]; } int main(){ p[1] = new PCB(); createThread(p[1],a); printf("napravio a\n"); p[2] = new PCB(); createThread(p[2],b); printf("napravio b\n"); p[0] = new PCB(); running = p[0]; dispatch(1); printf("Kraj.\n"); delete_all(); return 0; } Решење

  24. Задатак 5. • Рeшити претходни задатак, али тако да се сви регистри чувају у PCB. struct PCB{ pomeraj u odnosu na poc. adresu strukture unsigned pc; +0 unsigned sp; +2 unsigned bp; +4 unsigned ax; +6 unsigned bx; +8 unsigned cx; +10 unsigned dx; +12 // izrazeno u bajtovima ... };

  25. Решење • Потребно извршити следећи код: running->ax = AX; гдe је: • ах поље PCB структуре • АХ регистар • На језику С у општем случају није могуће приступити жељеном регистру. • Зато се умећу сегменти асемблерског кода. • Асемблерски еквивалент горе наведеној наредби је (под претпоставком PCB структуре дате на претходном слајду): asm{ mov BX, running // BX = running mov BX[6], AX // [BX+6] = AX - indirektno reg. adr. sa pomerajem } -примeтити да се BX користи за адресирање, па се на почетку његов садржај мора привремено сачувати (нпр на стеку)

  26. void _dispatch(){ asm { push bx mov bx, running mov bx[6], ax pop WORD PTR [bx+8] //bx mov bx[10], cx mov bx[12], dx pop WORD PTR[bx+4] //bp pop WORD PTR[bx] //pc mov bx[2], sp //cuva sp } running=p[nextThread]; asm { mov bx, running mov sp, bx[2] push WORD PTR[bx] //pc push WORD PTR[bx+4] //bp mov ax, [bx+6] push WORD PTR [bx+8] //bx mov cx, [bx+10] mov dx, [bx+12] pop bx } } Решење struct PCB{ pomeraj unsigned pc; +0 unsigned sp; +2 unsigned bp; +4 unsigned ax; +6 unsigned bx; +8 unsigned cx; +10 unsigned dx; +12 ... }; Napomena: WORD PTR[bx+...] – oznčava da se pristupa reči a ne jedanom bajtu

  27. void createThread(PCB *newPCB, void (*body)()){ unsigned* st = new unsigned[1024]; newPCB->pc = FP_OFF(body); //stek je sada prazan newPCB->sp = FP_OFF(st+1024); newPCB->bp = FP_OFF(st+1024); newPCB->stack = st; } Решење

  28. Задатак 6. • Изменити корутину из задатка 4. тако да се избор нове нити помоћу метода класе Scheduler: • void Scheduler::put(PCB *); Додаје нит у листу кандидата за извршавање • PCB* Scheduler::get(); Дохвата следећу нит из листе спремних процеса

  29. Решење void _dispatch(){ asm { // cuva registre na steku push ax //sta bi se desilo da ne cuvamo AX? push bx push cx push dx mov bx, running mov [bx], sp //cuva sp } Scheduler::put(running); running= Scheduler::get(); asm { mov bx, running mov sp, [bx] // restauira sp pop dx // restauira registre pop cx pop bx pop ax } } Чување контекста до сада извршаване нити Рестаурација контекста нити која се наставља

  30. Задатак 7. • Написати универзалну корутину dispatch() коришћењем функицја setjmp и longjmp. Функција setjmp прихвата показивач на бафер у којем чува тренутни контекст и враћа 0. Функција longjmp прихвата два параметра. Први параметар је показивач на структуру која садржи раније сачувани контекст (са setjmp) и који сада треба рестаурирати. Други параметар је вредност коју функција треба да врати (размислити где ће бити коришћена враћена вредност?).

  31. Решење void dispatch () { if (setjmp(running->context)==0) { Scheduler::put(running); running = Scheduler::get(); longjmp(running->context,1); } else { return; } }

  32. Напомене • Деофункцијеdispatch() изапозиваsetjmp(), апрепозиваlongjmp (), радиидаљенастекупретходнотекућенити (позивифункцијакласеScheduler). • Текодпозиваlongjmp () прелазисенастекноветекућенити. Овонијеникакавпроблем, јертајдеопредставља "ђубре" настекуизнадграницекојајезапамћенауsetjmp(). Приликомповраткаконтекстапретходненити, извршавањећесенаставитиодзапамћенеграницестека, исподовог "ђубрета".

  33. Напомене • Извршавањенастављасаоногместагдејепозванаsetjmp(), стимдасадаsetjmp()враћаонувредносткојаједостављенапозивуlongjmp()(томорабитивредностразличитаод 0), самимтимвредностАX регистрајеизмењена – проблем код асинхроног преузимања. • Одтренуткачувањаконтекстапомоћуsetjmp(), дотренуткаповраткапомоћуlongjmp(), извршавањеукомејеsetjmp() несмедасевратиизфункцијекојанепосредноокружујепозивsetjmp(), јербисетиместекнарушио, паповратакпомоћуlongjmp() доводидокрахасистема.

  34. Задатак 8. • Имплементирати функције setjmpи longjmp тако да раде на начин описан у претходном задатку: " Функција setjmp прихвата показивач на бафер у којем чува тренутни контекст и враћа 0. Функција longjmp прихвата два параметра. Први параметар је показивач на структуру која садржи раније сачувани контекст (са setjmp) и који сада треба рестаурирати. Други параметар је врeдност коју функција треба да врати."

  35. struct cnt_buf{ // pomeraj unsigned sp; // +0 unsigned ax; // +2 unsigned bx; // +4 unsigned cx; // +6 unsigned dx; // +8 unsigned pc; // +10 unsigned bp; // +12 }; struct PCB{ cnt_buf* context; unsigned* stack; }; unsigned _setjmp(cnt_buf *b, unsigned i){ asm { push bx mov bx, [bp+4] //bx = b; mov bx[2], ax pop WORD PTR [bx+4] //bx mov bx[6], cx mov bx[8], dx mov ax, bp[0] mov bx[12], ax //BP niti mov ax, bp[2] mov bx[10], ax //PC niti mov [bx], sp //running->sp = SP //skida se sa steka i, b, PC, BP add WORD PTR[bx], 8 } return 0; } Решење Sadržaj steka (u odnosu na BP): +6 i +4 b +2 PC +0 BP -2 BX

  36. Решење Sadržaj steka (u odnosu na BP): +6 i +4 b +2 PC +0 BP unsigned _longjmp(cnt_buf *b, unsigned i){ asm { mov bx, [bp+4] //BX = b; mov ax, [bp+6] //AX = i; mov sp, [bx] //restauriramo stek push ax push bx push WORD PTR bx[10] //pc push WORD PTR bx[12] //bp mov bp, sp // restauriramo AX, BX … mov ax, bx[2] push WORD PTR bx[4] //bx mov cx, bx[6] mov dx, bx[8] pop bx } return i; } Чест случај је да компајлери генеришу такав код да вредност враћају у неком од регистара. За 8086 углавном важи да се вредност враћа у регистру АХ. Зато се ова линија преводи у: mov ax, [bp+6] pop BP ret Sadržaj Restauriranog Steka (potreban za povratak na setjmp): i b PC BP

  37. Решење void createThread(PCB *newPCB, void (*body)()){ newPCB->stack = new unsigned[1024]; newPCB->context = new cnt_buf; newPCB->context->pc = FP_OFF(body); newPCB->context->sp = FP_OFF(newPCB->stack+1024); }

  38. Задатак 9. • Написати корутину dispatch() коришћењем функције: voidyield(unsigned* oldSP, unsigned* newSP); Прва половина функције чува контекст на текућем стеку и потом памти тренутну врeдност регистра SP у локацији на коју показује oldSP. Друга половина прво у регистар SP уписује садржај локације на коју показује newSP и потом са стека рестаурира контекст.

  39. Решење Проблем: Потребно је познавати имплементацију yield() f-je да би се креирао почетни контекст. struct PCB{ unsigned SP; }; void dispatch(){ unsigned *oldSP = &running->SP; Scheduler::put(running); running = Scheduler::get(); yield(oldSP, &running->SP); }

  40. Задатак 10. • Прокоментарисати претходне задатке уколико се dispatch() позива из прекидне рутине. Шта је у том случају проблем и како се решава?

  41. Решење На почетку се забрањује преузимање процесора. void _dispatch(){ lock() asm { // cuva registre na steku push ax //sta bi se desilo da ne cuvamo AX? push bx push cx push dx mov bx, running mov [bx], sp //cuva sp } Scheduler::put(running); running= Scheduler::get(); asm { mov bx, running mov sp, [bx] // restauira sp pop dx // restauira registre pop cx pop bx pop ax } unlock() } Чување контекста до сада извршаване нити Рестаурација контекста нити која се наставља На крају се поново дозвољава преузимање процесора.

More Related