41
Оперативни системи 1 Вeжбе Lista predmeta: i [email protected]

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

  • Upload
    benard

  • View
    39

  • Download
    1

Embed Size (px)

DESCRIPTION

Оперативни системи 1. В e жбе Lista predmeta: i [email protected]. Увод у архитектуру 8086. 16-битни микропроцесор. Адресибилна јединица бајт. Регистри: сегментни општенем e нски индексни базни регистар BP и показивач на стек SP. Сегментни регистри. CS – код сегмент , - PowerPoint PPT Presentation

Citation preview

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

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

Вeжбе

Lista predmeta: [email protected]

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

Увод у архитектуру 8086

• 16-битни микропроцесор.• Адресибилна јединица бајт.• Регистри:

– сегментни– општенемeнски– индексни– базни регистар BP и показивач на стек SP.

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

Сегментни регистри• CS – код сегмент,• SS – стек сегмент,• DS – сегмент података и• ES – екстра сегмент за податке• Користе се за формирање адресе:

– адреса је 20-битна– састоји се од:

• сегмента – SEG (16 бита) • и офсета (померај) – OFF (16 бита)

– физичка адреса је 20 бита и рачуна се: 0х10 * SEG + OFF

– сегмент је увeк један од 4 сегментна регистра• ВАЖНЕ НАПОМЕНЕ:

– ови сегменти немају никакве везе са виртуелним адресирањем које се налази код модерних процесора

– примeтити да се неке физичке адресе могу добити комбинацијом више различитих парова сегмената и офсета.

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

Општенам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

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

Индексни и базни регистри

• Индексни:– SI i DI,– Сваки по 16 бита,– Користе се при индексном адресирању (приступ

елементима низа).– Примeр: mov AX, niz[SI]

• Базни регистар за приступ стеку:– BP– 16 бита.– Користи се за приступ стеку (приступ стварним

аргументима и локалним промeнљивим процедуре).

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

Стек

• Постоје две поделе (4 врсте) стекова:– да ли расте ка вишим адресама или ка

нижим?– да ли показивач на стек показује на заузету

локацију на врху стека или на прву слободну локацију изнад врха стека?

• Стек процесора 8086:– расте ка нижим адресама– SP указује на заузету локацију на врху

стека

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

Стек позива потпрограма

• Са BP

Zašto BP?Zar nije dovoljan

SP?

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

Стек позива потпрограма

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 pozivu potprograma:

Napomena: Parametri se stavljaju na stek u obrnutom redosledu od onog navedenog pri deklaraciji f-je.

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

Како се потпрограму прослеђују параметри?

• Потпрограм на C-у:

int fun(int a){

return a;

}

• Исти потпрограм на асемблеру:

fun proc

push BP

mov BP, SP

mov AX, [BP+6]

pop BP

ret

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

Како се потпрограму прослеђују параметри?

fun procpush BPmov BP, SPmov AX, [BP+6]pop BPret...push 1234hcall funadd SP, 2

Напомена: Претпоставља се huge mem. model

Стек:xxxx+7 12 виши бајт на вишој

адреси+6 34 нижи бајт на нижој адреси+5 retCSh h – high byte+4 retCSl l – low byte+3 retPCh+2 retPCl+1 oldBPh+0 oldBPl

SP

BPАХ = 0х1234

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

Задатак 1.• Написати програм на програмском језику C који ће помоћу једне

функције бесконачно исписивати неки текст. Решење може да буде некоректно у смислу да ће оперативни систем у коначном времену пријавити грешку у извршавању програма и прекинути његово извршавање. Није дозвољено коришћење петљи.

#include<stdio.h>void a(){ printf("...\n"); a();}

void main(){ a();}

Шта је проблем?

Стек: (у једном реду једна реч – 2B)xx

retCSend_mainretPCend_mainoldBP_main

retCSend_aretPCend_aoldBP_a1

retCSend_aretPCend_aoldBP_a2

...

SP

BP

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

Задатак 2.

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

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

Решење#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_OFFSETBP_mainAX_old

i:printf_OFFSET

return_OFFSETBP_mainAX_old

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

Задатак 3.

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

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

Решење – варијанта 1unsigned 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

xx

PC_main_}

BP_main

...

f //adresa funkcije f

0

...

...

SP BP

PC

0

На почетку сваке

функције:push BP

mov BP, SP

На почетку сваке

функције:push BP

mov BP, SPНа крају сваке

функције:pop BP

ret

FP_OFF(f) dohvata offset adrese f-je f

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

Решење – варијанта 1unsigned 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

xx

PC_main_}

BP_main

...

f //adresa funkcije f

0

...

...

SP BP

PC

0

PC_f_}

Извршава се код функције

На крају сваке функције:

pop BPret

На почетку сваке

функције:push BP

mov BP, SP

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

Решење – варијанта 2unsigned int temp;

void _dispatch1(){ asm { pop temp

push fpush temp

}}

void f(){//kod funkcije//...}

void main(){ dispatch1();}

xx

PC_main_}

BP_main

BP_main

SPtemp:

BP_main

f //adresa funkcije f

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

Задатак 4.

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

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

Решење• 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

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

Решење• Потребно извршити следећи код:

running->sp = SP; // cuvanje SPгдe је:– sp поље PCB структуре– SP регистар

• На језику С у општем случају није могуће приступити жељеном регистру.

• Зато се умећу сегменти асемблерског кода.• Асемблерски еквивалент горе наведеној наредби је (под

претпоставком PCB структуре дате на следећем слајду):asm{

mov BX, running // BX = runningmov [BX], SP // [BX] = SP - indirektno registarsko adresiranje

}-примeтити да се BX користи за адресирање, па се на почетку његов

садржај мора привремено сачувати (нпр на стеку)

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

Решење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 bxpush cxpush dxmov bx, running //upisuje adresu mem. lok.

mov [bx], sp //cuva sp } running=p[nextThread]; asm {

mov bx, runningmov sp, [bx] // restauira sp

pop dx // restauira registre pop cx pop bx pop ax

}}

При уласку у функцију dispatch() на стек ће се

ставити повратна адреса. То је адреса прве

инструкције после позива dispatch() и уједно и адреса

од које треба наставити прекинуту нит.

Чувају се и 4 регистра (тако је речено у поставци

задатка). У општем случају, неопходно је сачувати све регистре осим CS:PC (већ

сачувано при уласку у функцију) , BP (већ сачуван

првом инструкцијом функције f()) i SS:SP (биће

сачувани у PCB).

Чува се показивач на стек.Инструкције:

mov bx, runningmov [bx], sp

су еквивалентне са C кодом:running->sp = SP //SP je registar

Рестаурација стека нове нити:

SP = running->sp;Рестаурација остатка контекста:-прво регистри DX, CX, BX i AX-рестаурација BP са pop BP-рестаурација PC са ret

running је показивач на PCB структуру нити која се тренутно

извршава. Да би се умeсто нити, која се

извршавала до позива _dispatch() наставила нова нит, неопходно је поставити да running показује на

PCB те нове нити. У овом задатку је претпостављено

да се нова нит одрeђује уписом одговарајуће вредности у

nextThread.

По уласку у функцију, наилази се на прве две инструкције сваке

функције:push BP

mov BP, SPКао резултат прве инструкције на

стеку је сачувана вредност BP регистра која је коришћена у прекинутој нити и која ће се

користити опет по повратку у ту нит.

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

Решење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);

}

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

Решење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;}

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

Задатак 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 ...};

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

Решење• Потребно извршити следећи код:

running->ax = AX;гдe је:– ах поље PCB структуре– АХ регистар

• На језику С у општем случају није могуће приступити жељеном регистру.

• Зато се умећу сегменти асемблерског кода.• Асемблерски еквивалент горе наведеној наредби је (под

претпоставком PCB структуре дате на претходном слајду):asm{

mov BX, running // BX = runningmov BX[6], AX // [BX+6] = AX - indirektno reg. adr. sa pomerajem

}-примeтити да се BX користи за адресирање, па се на почетку његов

садржај мора привремено сачувати (нпр на стеку)

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

Решењеvoid _dispatch(){ asm {

push bxmov bx, runningmov bx[6], axpop WORD PTR [bx+8] //bxmov bx[10], cxmov bx[12], dxpop WORD PTR[bx+4] //bppop WORD PTR[bx] //pc

mov bx[2], sp //cuva sp }

running=p[nextThread]; asm {

mov bx, runningmov sp, bx[2]

push WORD PTR[bx] //pcpush WORD PTR[bx+4] //bpmov ax, [bx+6]push WORD PTR [bx+8] //bxmov 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

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

Решење

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;

}

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

Задатак 6.

• Изменити корутину из задатка 4. тако да се избор нове нити помоћу метода класе Scheduler:– void Scheduler::put(PCB *);

Додаје нит у листу кандидата за извршавање

– PCB* Scheduler::get();

Дохвата следећу нит из листе спремних процеса

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

Решењеvoid _dispatch(){ asm { // cuva registre na steku

push ax //sta bi se desilo da ne cuvamo AX?push bxpush cxpush dxmov bx, running

mov [bx], sp //cuva sp } Scheduler::put(running); running = Scheduler::get(); asm {

mov bx, runningmov sp, [bx] // restauira sp

pop dx // restauira registre pop cx pop bx pop ax

}}

Чување контекстадо сада извршаване

нити

Рестаурација контекстанити која се наставља

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

Задатак 7.

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

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

Решење

void dispatch () {if (setjmp(running->context)==0) {

Scheduler::put(running);running = Scheduler::get();longjmp(running->context,1);

} else {return;

}}

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

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

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

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

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

Задатак 8.

• Имплементирати функције setjmp и longjmp тако да раде на начин описан у претходном задатку:

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

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

Решењеstruct cnt_buf{ // pomeraj

unsigned sp; // +0unsigned ax; // +2unsigned bx; // +4unsigned cx; // +6unsigned dx; // +8unsigned pc; // +10unsigned bp; // +12

};

struct PCB{ cnt_buf* context; unsigned* stack;};

unsigned _setjmp(cnt_buf *b, unsigned i) {asm { push bxmov bx, [bp+4] //bx = b; mov bx[2], axpop WORD PTR [bx+4] //bxmov bx[6], cxmov bx[8], dxmov ax, bp[0]mov bx[12], ax //BP nitimov ax, bp[2]mov bx[10], ax //PC nitimov [bx], sp //running->sp = SP//skida se sa steka i, b, PC, BPadd WORD PTR[bx], 8 }return 0;

}

Sadržaj steka(u odnosu na BP):

+6 i+4 b+2 PC+0 BP-2 BX

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

Решењеunsigned _longjmp(cnt_buf *b, unsigned i){ asm {

mov bx, [bp+4] //BX = b;mov ax, [bp+6] //AX = i;mov sp, [bx] //restauriramo stekpush axpush bxpush WORD PTR bx[10] //pcpush WORD PTR bx[12] //bpmov bp, sp// restauriramo AX, BX …mov ax, bx[2]push WORD PTR bx[4] //bxmov cx, bx[6]mov dx, bx[8]pop bx}return i;

}

Чест случај је да компајлери генеришу такав код да вредност враћају у

неком од регистара. За 8086 углавном важи да се вредност враћа у регистру

АХ. Зато се ова линија преводи у:

mov ax, [bp+6]pop BPret

Sadržaj Restauriranog Steka (potreban za povratak na setjmp):ibPCBP

Sadržaj steka(u odnosu na BP):

+6 i+4 b+2 PC+0 BP

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

Решење

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);}

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

Задатак 9.

• Написати корутину dispatch() коришћењем функције:

void yield(unsigned* oldSP, unsigned* newSP); Прва половина функције чува контекст на

текућем стеку и потом памти тренутну врeдност регистра SP у локацији на коју показује oldSP.

Друга половина прво у регистар SP уписује садржај локације на коју показује newSP и потом са стека рестаурира контекст.

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

Решење

struct PCB{ unsigned SP;

};

void dispatch(){unsigned *oldSP = &running->SP;Scheduler::put(running);running = Scheduler::get();yield(oldSP, &running->SP);

}

Проблем: Потребно је познавати

имплементацију yield() f-je да би се креирао почетни

контекст.

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

Задатак 10.

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

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

Решењеvoid _dispatch(){lock() asm { // cuva registre na steku

push ax //sta bi se desilo da ne cuvamo AX?push bxpush cxpush dxmov bx, running

mov [bx], sp //cuva sp } Scheduler::put(running); running = Scheduler::get(); asm {

mov bx, runningmov sp, [bx] // restauira sp

pop dx // restauira registre pop cx pop bx pop ax

}unlock()}

Чување контекстадо сада извршаване

нити

Рестаурација контекстанити која се наставља

На почетку се забрањује

преузимање процесора.

На крају се поново дозвољава

преузимање процесора.