Vývoj operačného systému/Bootloader po prvé - BIOS
V tejto kapitole si ukážeme, ako sa pracuje so softvérovými prerušenia BIOSu. Budeme sa sústrediť na vstup a výstup.
Každé prerušenie si zo sebou berie aj stav registrov (nerátajúc EIP - pozícia kódu a ESP-miesto uloženia stavu) a vracia ho nezmenený (mimo registrov vracajúcich hodnotu, napríklad stlačenú klávesu ), čo znamená že registre sú jedným zo spôsobov, ako sa dajú prerušeniu poslať dáta. Zvyčajne sa číslo funkcie ktorú chceme cez prerušenie zavolať ukladá do registra EAX alebo len do jeho časti (AX, AL|AH). V prípadne základných BIOSových rutín sa používa register AH.
Znakový výstup
[upraviť]Prerušenie na zobrazenie výstupu má číslo 16 (teda 0x10 hexadecimálne). Po zavolaní prerušenia sa hodnota (farba alebo znak) určená na vypísanie a pozícia na obrazovke upravia do formátu, ktorý akceptuje grafická karta. Následne sa zabezpečí vypísanie, zafarbenie a posunutie kurzoru. O udržiavanie obrazu na obrazovke sa už nestará prerušenie, ale grafická karta. Je nutné podotknúť že BIOSové prerušenia sa spolu s postupom grafických kariet veľmi nevyvíjali (BIOS dnes podporuje len z hľadiska kvality zastaralý štandard VGA, prípadne lepší štandard VBE, no nie je to žiadna sláva). Z toho hľadiska netreba od reálneho módu veľa očakávať. Nižšie je uvedený zoznam funkcií na základnú prácu s grafikou pomocou prerušenia 16.
Funkcie prerušenia 0x10
[upraviť]Číslo (hodnota registra AH) | Názov | Vstup | Výstup | Popis |
---|---|---|---|---|
00 | Set video mode - nastav mód zobrazovania grafického výstupu | AL=požadovaný video mód (pozri tabuľku nižšie) | AL=stav módu (0x20 mód > 7, 0x30 módy 0-5 a 7, 0x3F mód 6)
alebo AL=bajt módu radiča CRT monitoru |
Nastaví konkrétny mód vyobrazovania dát na obrazovku. |
02 | Set cursor position - nastav pozíciu kurzora | BH = číslo stránky, DH = riadok, DL = stĺpec | Nastaví pozíciu kurzora v textovom móde na obrazovke | |
03 | Get cursor position and shape - zober pozíciu a tvar kurzora | BH = číslo stránky | DH = riadok, DL = stĺpec, AX=0 | Vyberie aktuálnu pozíciu kurzora na konkrétnej strane |
05 | Select active display page- vyber stránku na zobrazenie | AL = číslo stránky | Vyberie konkrétnu stranu vyobrazovania | |
08 | Read character and attribute at cursor position - načítaj znak a atribút na pozícii kurzoru. | BH = číslo stránky | AH = farba, AL = znak | Načíta znak a atribút(farba) z pozície kurzoru na konkrétnej stránke |
09 | Write character and attribute at cursor position - zapíš znak a atribút na aktuálnu pozíciu kurzoru. | AL = znak, BH = číslo strany, BL = atribút (farba), CX = počet, koľkokrát sa má znak vypísať | Vypíše (prepíše) znak a atribút na aktuálnu pozíciu kurzoru. Funkcia opačná k funkcii 08. | |
10 | Write character only at cursor position - vypíš len znak na pozíciu kurzoru | AL = znak, BH = číslo strany, CX = počet, koľkokrát sa má znak vypísať | Vypíše (prepíše) znak na aktuálnu pozíciu kurzoru | |
11 |
Set background/border color - nastav farbu pozadia (alebo orámovania) Set palette - nastav paletu |
BH=0 (pre farbu pozadia), BL = farba pozadia/orámovania (orámovanie je dostupné len v textových módoch) alebo BH=1 (pre nastavenie palety), BL=identifikačné číslo palety (palette ID) |
Nastaví farbu pozadia alebo paletu farieb na základe hodnoty registra BH. | |
14 | Teletype output | AL = znak, BH = číslo stránky, BL = farba (atribút) | Vypíše znak na aktuálnu pozíciu kurzoru a posunie kurzor dopredu. | |
15 | Get current video mode - načítaj aktuálny grafiký mód (mód vyobrazovania) | AL = mód | Funkcia opačná k funkcii 00. |
Poznámka: "znaky" vypisované BIOSom sa držia ASCII tabuľky. Existujú nezmapované oblasti ASCII tabuľky, ktoré si prispôsobujú už jednotlivé firmy. Ak budete hľadať smajlíka, skúste čísla hneď na začiatku tabuľky ;)
Zobrazovacie módy BIOSu
[upraviť]Zobrazovacie (grafické) módy BIOSu (pre štandard VGA - dnes často podporovaný z dôvodov spätnej kompatibility). Rozlíšenie módu určuje v prípade pixelového módu šírku a výšku v bodoch, v prípade textového módu šírku a výšku v znakoch. (Samotný znak môže zaberať rôzny blok pixelov, v módoch VGA štandardne 9x16 alebo 8x8- mód 03.)
Poznámka: Dáta v tabuľke sú v desiatkovej sústave. Nula pred číslicami bola dodaná len pre zarovnanie. Nepoužívajte nulu pred číslami v programe - niektoré kompilátory by si mohli myslieť, že používate osmičkovú sústavu.
Číslo módu (vo fun.00 a 15=AL) | Typ módu | Rozlíšenie (podľa typu) | Počet farieb |
---|---|---|---|
00 | textový | 40x25 | 16 odtieňov šedej |
01 | textový | 40x25 | 16 |
02 | textový | 80x25 | 16 odtieňov šedej |
03 | textový | 80x25 | 16 |
04 | pixelový | 320x200 | 4 |
05 | pixelový | 320x200 | 4 odtiene šedej |
07 | textový | 80x25 | 2 |
13 | pixelový | 320x200 | 16 |
14 | pixelový | 640x200 | 16 |
15 | pixelový | 640x350 | 2 |
16 | pixelový | 640x350 | 16 |
17 | pixelový | 640x480 | 2 |
18 | pixelový | 640x480 | 16 |
19 | pixelový | 320x200 | 256
Poznámka: Mód s 256-timi farbami nepoužíva klasický spôsob vypočítavania farby z čísla. Namiesto toho používa číslo ako index v palete, ktorú si udržuje v pamäti grafická karta. |
Poznámka: Mód s dvoma farbami (biela a čierna) sa niekedy zvykne označovať aj ako monochrómny (monochrome).
Príklady použítia funkcií
[upraviť]Funkcie 00 a 15
[upraviť]Nižšie uvedený kód overí, či je aktuálny mód 0 alebo 1 (rozlíšenie 40x25 znakov). Ak je to pravda, nastaví mód na 2 alebo 3 (v závislosti od pôvodného módu, proste pripočíta 2 a tým zachová farby).
BITS 16
mov ah, 15 ; funkcia 15: načítaj aktuálny mód do AL
int 0x10 ; zavolaj prerušenie
test al, 11111110 ;cez sito prepusti všetky bity okrem prvého
jnz .KONIEC ;nie je čo nastavovať
;ak je číslo módu 0 alebo 1, tak...
or al, 2 ; mód 0 prestav na mód 2, mód 1 na mód 3 (zachovanie farieb)
mov ah, 00 ; funkcia 00: nastav mód z registra AL
int 0x10 ; nastav!
.KONIEC:
Funkcie 02 a 03
[upraviť]Tento kód simuluje (v reálnom použití to nie je potrebné) funkciu klávesy backspace, nie je však funkčný bez iných súčastí. Užívateľ môže posúvať kurzor dozadu (znak sa však nevymaže a tak ich môže prepisovať). Ak sú pozície x a y nulové, nachádzame sa v ľavom hornom okraji obrazovky a nemáme už miesto, kam by sme sa mohli posunúť. Poznámka: tento kód vychádza z toho, že šírka obrazovky je 80 stĺpcov (znakov). Pre funkčnosť by musel byť nastavený mód zodpovedajúci tejto požiadavky.
BITS 16
... ; naplnenie registru AL
xor bh, bh ; ďalej v kóde chceme ukazovať na text na stránke 0
cmp al, '\b' ; rovná sa stisnutiu klávesy backspace?
jnz .pokracuj ; tak nič...
cmp dh, 0 ; sme v riadku 0?
jnz .pracuj ; ak nie, všetko v poriadku
cmp dl, 0 ; sme aj v stĺpci 0? - sme v pravom hornom kraji obrazovky
jz .pokracuj ; ak áno, tak nič nevymazuj - nie je čo
mov ah, 03 ; funkcia 03: zisti aktuálnu pozíciu kurzoru
int 0x10 ; zavolaj prerušenie
dec dl ; x = x - 1
jnz .nastav ; x!=0 ? ak sa nerovná, nastav kurzor
mov dl, 79 ; x = pravý okraj obrazovky
dec dh ; y = y - 1 = o riadok vyššie
.nastav:
mov ah, 02 ; funkcia 02: nastav pozíciu kurzoru
int 0x10 ; zavolaj prerušenie
.pokracuj:
Funkcia 05
[upraviť]Nasledujúci kód je niekedy dobré umiestniť na začiatok rozsiahlejších vypisovacích funkcií pre prípad, že by sa stránka na ktorú sa text vypisoval v inej časti programu zmenila. Tento kód nastaví stránku 0 ako aktívnu (bude sa zobrazovať na obrazovke).
BITS 16
mov ah, 5
xor al, al
int 0x10 ; zavolaj prerušenie
Funkcie 08 a 09
[upraviť]Tento program má za úlohu skontrolovať všetky znaky na obrazovke, či sú znakom '$'. Ak ním sú, vymení ich za znak '€'.
xor bh, bh ;stránka 0
xor dh, dh
xor dl, dl ;x=y=0: ľavý horný roh obrazovky
mov cx, 1 ;znak chceme vypísať len raz
.cyklus:
cmp dl, 80 ;sme za posledným stĺpcom?
jnz .over_riadok ;ak nie, skontroluj riadok
xor dl, dl ;ak áno, posuň kurzor na začiatok...
inc dh ;... nového riadka
.over_riadok:
cmp dh, 25 ;sme za posledným riadkom?
jz .KONIEC ;už sme spracovali všetko, čo sa dalo
mov ah, 02 ;nastav kurzor
int 0x10 ;ideš!
mov ah, 08 ;funkcia 08: načítaj znak a farbu na pozícii kurzoru
int 0x10 ;čítaj!
cmp al, '$' ;je to dolár?
jnz .dalej ;ak nie, pokračuj na ďalší stĺpec
mov al, '€' ;nastav znak na '€'
mov bl, ah ;zachovaj prečítanú farbu
mov ah, 09 ;funkcia 09: zapíš znak a farbu na pozíciu kurzoru
int 0x10 ;zapíš!
.dalej:
inc dl ;posuň kurzor na ďalší stĺpec (znak v riadku)
jmp .cyklus
.KONIEC:
Funkcia 10
[upraviť]Následný kód je poupravená verzia kódu pre funkcie 02 a 03. Tento kód v reakcii na znak '\b' (backspace) zároveň pred posunutím kurzoru dozadu znak vymaže (nahradí medzerou, znak 0 je ten spomínaný smajlík :) )
BITS 16
... ; naplnenie registru AL
xor bh, bh ; ďalej v kóde chceme ukazovať na text na stránke 0
xor cx, cx
cmp al, '\b' ; rovná sa stisnutiu klávesy backspace?
jnz .pokracuj ; tak nič...
cmp dh, 0 ; sme v riadku 0?
jnz .pracuj ; ak nie, všetko v poriadku
cmp dl, 0 ; sme aj v stĺpci 0? - sme v pravom hornom kraji obrazovky
jz .pokracuj ; ak áno, tak nič nevymazuj - nie je čo
mov ah, 03 ; funkcia 03: zisti aktuálnu pozíciu kurzoru
int 0x10 ; zavolaj prerušenie
mov ah, 09
mov al, ' ' ; medzera, alebo hexadecimálne 0x20
int 0x10 ; zapíš
dec dl ; x = x - 1
jnz .nastav ; x!=0 ? ak sa nerovná, nastav kurzor
mov dl, 79 ; x = pravý okraj obrazovky
dec dh ; y = y - 1 = o riadok vyššie
.nastav:
mov ah, 02 ; funkcia 02: nastav pozíciu kurzoru
int 0x10 ; zavolaj prerušenie
.pokracuj:
Funkcia 14
[upraviť]Tento kód vypíše reťazec ukončený nulou (null-terminated string, štandard pre reťazce jazyka C - nie je potrebné držať informáciu o dĺžke).
BITS 16
mov si, retazec
call vypis
....
vypis:
mov al, byte [ds:si]
test al, al
jz .koniec
mov ah, 14
int 0x10
inc si
jmp vypis
.koniec:
ret
...
retazec: db "Vitajte v realnom mode!", 0x0D, 0x0A, 0
Poznámka: Vyššia polovica ASCII tabuľky je často neštandardná. Diakritika nemusí byť podporovaná.
Podrobné zdroje
[upraviť]- Video Graphics Array na slovenskej Wikipédii
- Video Graphics Array na anglickej Wikipédii
- základná teória a programovanie grafiky na BrokenThorn.com
- Projekt FreeVGA so záberom na dokumentáciu VGA grafiky
- Kapitola knihy "The Art of Assembly Language Programming" (online) týkajúca sa prerušenia 0x10
- Špecifikácie štandardov VBE 2.0 a VBE 3.0
- Ďalšie zdroje pre VGA, popis VGA hardvéru, signály a časovanie, fonty VGA a VGA kurzor v textovom móde na OSDev.org
Znakový vstup
[upraviť]Otázka vstupu bývala v minulosti dosť spletitá. Existovalo viacero druhov klávesníc, ktoré sa odlišovali nielen zo softvérového hľadiska, ale aj z hľadiska hardvérového (rôzne druhy klávesníc mali rôzne konektory). Pred príchodom portu USB sa značne rozšírili pripojenia PS/2 (Personal System/2 od spoločnosti IBM). Počítače PS/2 mali podobné, no mechanicky a farebne rozdielne pripojenia pre myš (zelená) a klávesnicu (fialová). Ak ste zapojili myš do portu na klávesnicu alebo naopak, zariadenie nefungovalo. Pretože sa nejednalo o zariadenie pripojiteľné za behu (pluggable, hot-pugging), bolo treba konektory správne zapojiť a počítač reštartovať. Tieto zariadenia boli navrhnuté s dvoma radičmi. Prvý sa nachádzal na klávesnici a nazýval sa keyboard encoder. Druhý sa nachádzal na základnej doske a nazýval sa keyboard controller. Kým prvé zariadenie lokalizovalo stlačenú klávesu a informovalo ďalej, druhé zariadenie sa zaoberalo správou toho prvého. Keyboard controller po nejakom čase zrástol so základnou doskou (ako jej obvod).
Klávesnice PS/2 sa ujali a po príchode konektorov USB sa hneď nové návrhy nevymýšľali. V nových počítačoch (BIOS) sa preto nachádzalo premostenie, ktoré toto prepojenie umožňovalo. Z celkových funkcií klávesníc PS/2 sa vynechali len niektoré (napríklad scroll lock), inak si s klávesnicou PS/2 bez problémov vystačíte.
Prerušenie 0x16
[upraviť]Klávesnica posiela dva signály: press (stlačenie) a release (uvoľnenie). Každá klávesa (okrem zopár výnimiek) má svoj kód klávesy (scan code) pre obidve situácie. Existuje niekoľko súborov kódov kláves, a je na BIOSe na ktorom z nich sa s klávesnicou "dohodne". BIOS si pri načítavaní znakov z klávesnice dopredu udržiava informácie vo vlastnom bufferi (zozname stlačených kláves). Zavolaním špecifickej funkcie prerušenia sa pracuje s týmto bufferom, prípadne sa čaká na ďalší vstup.
Číslo funkcie (AH) | Popis | Vstup | Výstup |
---|---|---|---|
00 | Načíta stlačenú klávesu. Ak je zoznam stlačených kláves prázdny, na stlačenie si počká. | AL=znak podľa ASCII tabuľky,
AH=kód stlačenej klávesy (press scan code), špecifický identifikátor klávesy na klávesnici (ASCII tabuľka nemusí mať všetky klávesy zmapované, niektoré znaky sa nedajú vyobraziť. Jedná sa o dáta priamo z klávesnice.). | |
01 | Skontroluje, či boli stlačené nejaké klávesy od posledného čítania. | ZF=1 ak nebola stlačená žiadna klávesa, inak 0.
V prípade stlačenia AL=znak podľa ASCII tabuľky, AH=kód klávesy (scan code) | |
02 | Načíta stav špeciálnych kláves (SHIFT, ALT, CTRL, INSERT...) | AL=stav špeciálnych kláves (pozri tabuľku nižšie) | |
03 | Nastaví takzv. autorepeat, teda čas a interval, v ktorom sa má opakovať signál stlačenia klávesy ak je klávesa držaná dole po dlhší čas | AL=05,
BH[1]=hodnota n predstavujúca zlomok sekúnd, ktorý sa má počkať kým sa začne opakovanie signálu stlačenia. Platí, že dĺžka vyčkávania je s kde . BL[1]=hodnota , na základe ktorej sa dá vypočítať počet opakovaní stlačenia vykonaných za sekundu. Hodnoty sú skôr tabuľkové, no približne platia aj tieto dva vzorce:
|
|
05 | Pridaj stlačenú klávesu na koniec zoznamu (prečíta sa ako posledná) | CL=znak podľa ASCII tabuľky, CH=kód klávesy
Poznámka: BIOS neoveruje, či je hodnota CH správna. Hodnota sa uloží a keď na ňu príde rad, vyberie sa bez akejkoľvek práce s hodnotou. Na chybné dáta tak môže prísť až program spracúvajúci vstup zachytený BIOSom. |
|
18 | Načíta rozšírený stav špeciálnych kláves (pravý ALT, ľavý ALT, pravé CTRL, INSERT...) | AX=rozšírený stav špeciálnych kláves (pozri tabuľku nižšie) |
Stav špeciálnych kláves
[upraviť]Bit | Stav špeciálnych kláves (funkcia 02) | Rozšírený stav špeciálnych kláves (funkcia 18) | |
---|---|---|---|
AH | 0 | Ľavá klávesa CTRL (stlačená) | |
1 | Ľavý ALT (stlačený) | ||
2 | Pravá klávesa CTRL (stlačená) | ||
3 | Pravá klávesa ALT (stlačená) | ||
4 | Klávesa Scoll Lock (práve stláčaná) | ||
5 | Klávesa Num Lock (práve stláčaná) | ||
6 | Klávesa Caps Lock (práve stláčaná) | ||
7 | Klávesa SysRq (stlačená) - dnes aj nedodávaná (alebo dodávaná vo forme PrtScr, Fn+PrtScr) | ||
AL | 0 | Pravý SHIFT (stlačený) | |
1 | Ľavý SHIFT (stlačený) | ||
2 | Ľavá alebo pravá klávesa CTRL (stlačená) | ||
3 | Ľavá alebo pravá (na niektorých strojoch len ľavá) klávesa ALT (stlačená) | ||
4 | Klávesa Scoll Lock (aktivovaná) | ||
5 | Klávesa Num Lock (aktivovaná) | ||
6 | Klávesa Caps Lock (aktivovaná) | ||
7 | Klávesa Insert Lock (aktivovaná) |
Príklady použitia funkcií
[upraviť]Funkcia 00
[upraviť]Nasledujúci kód načíta vstup z klávesnice a priamo ho vypíše na obrazovku (na aktuálnu pozíciu kurzoru).
BITS 16
start:
xor ah, ah
int 0x16
mov ah, 0Eh
int 0x10
jmp start
Funkcie 02 a 18
[upraviť]Tento kód je uzavretý v nekonečnej slučke do času, keď bude stlačený pravý a ľavý alt. V prípade stlačenia obidvoch kláves sa vypíše správa "Dovidenia!" a vykonávanie sa zastaví.
BITS 16
start:
.cyklus:
mov ah, 02 ;funkcia 02: načítaj stav špeciálnych kláves
int 0x16 ;načítaj!
and al, 10
cmp al, 10 ;sú bity 3 (2^3) a 1 (2^1) nastavené (klávesy pravý a ľavý alt stlačené)?
jne .cyklus ;ak nie, normálne pokračuj
mov ax, 0x7C0
mov ds, ax
mov si, dovidenia
call retazec
cli ;zakáž prerušenia
hlt ;zastav vykonávanie
retazec:
xor bh, bh
mov ah, 0x0E
.cyklus:
mov al, byte [ds:si]
test al, al
jz .koniec
int 0x10
inc si
jmp .cyklus
.koniec:
ret
dovidenia: db 0x0D, 0x0A, "Dovidenia!", 0
Funkcia 03
[upraviť]Kód nižšie nastaví dobu vyčkávania pred opakovaním stlačenia (BH) na jednu sekundu a frekvenciu opakovania približne na 7.5Hz.
BITS 16
start:
mov ah, 03 ;funkcia 03: nastavenie 'typematic delay' a 'typematic rate'
mov al, 05 ;nastavenie hodnôt
mov bh, 3 ;3+1/4 = 1s
mov bl, 0x10 ;približne 7.5 Hz
int 0x16 ;prerušenie 0x16: rutiny práce s klávesnicou
cli ;zakáž prerušenia
hlt ;zastav vykonávanie
Funkcia 05
[upraviť]Funkcia 05 má skôr využitie ako bočná systémová podpora, keď je nutné poslať vykonávajúcemu sa programu vstup zo systému napríklad kvôli nejakej udalosti. Systém pridávania je jednoduchý, no netreba zabúdať, že klávesa sa umiestni až na koniec zoznamu načítaných znakov (nebude prijatá prednostne).
BITS 16
mov ah, 05 ;funkcia 05: pridanie znaku na koniec zachyteného vstupu
xor ch, ch ;kód klávesy=0
mov cl, 65 ;znak podľa ASCII tabuľky=65='A'
int 0x16 ;prerušenie 0x16: rutiny práce s klávesnicou
Podrobné zdroje
[upraviť]- PS/2 pripojenie na slovenskej Wikipédii
- PS/2 pripojenie na anglickej Wikipédii
- Programovanie PS/2 klávesnice a myši na OSDev.org
- Programovanie (podrobne) klávesnice na BrokenThorn.com
- INT 0x13, funkcia 3 podrobne
- Prerušenie 0x16 v "Ralf's Brown Interrupt List"
- Kapitola knihy "The Art of Assembly Language Programming" (online) zaoberajúca sa vstupom a výstupom z klávesnice (pomocou prerušení)