Hlavní navigace

Píšeme operační systém: přerušení

20. 2. 2006
Doba čtení: 5 minut

Sdílet

Minule jsme si vytvořili funkční boot disketu. Dnes si v našem seriálu o vnitřnostech operačního systému rozebereme jednu z vlastností procesoru, kterou je obsluha přerušení.

Přerušení

Přerušení (interrupt) je schopnost procesoru přerušit právě vykonávaný program a začít vykonávat jiný program (obsluhu přerušení). Přerušení se začalo implementovat do procesorů z důvodu obsluhy periferii – přesněji V/V zařízení. Procesor je mnohem rychlejší než ostatní hardware, a tak kdyby se zabýval pouze obsluhou periferie, byl by v danou chvíli nevyužit a většinu svého procesorového času by strávil ve smyčce čekáním na daný hardware. V dnešní době se přerušení využívá mnohem víc při přepínání procesů. Takový jeden pohyb myší vyvolá přerušení hardwarové, které obslouží daný driver, ten následně pošle informaci jádru, to pošle informaci o změně na ploše a aktivní aplikaci, která například reaguje zvýrazněním odkazu. Vždy musí dojít k přerušení, neboť se měnil program, který vykonával danou činnost. V minulé díle jsme si na příkladu ukázali volání služeb BIOSu pomocí přerušení (instrukce INT).

Přerušení v architektuře x86 se vyvolá dvěma základními způsoby: Software-generated (softwarově), a to pří dekódování instrukce INT n (zmíněné volání BIOSu). A External-hardware generated (hardwarově), tedy vyvolané vnějším okolím. To se dále rozděluje na NMI (Non Maskable Interrupt) nemaskovatelné a na INTR (INTerrupt Request). Vše shrnuto v tabulce:

  • Software-generated (softwarové)
  • External-hardware generated (hardwarové)
    • NMI (Non Maskable Interrupt)
    • INTR (INTerrupt Request)

Software generated

Softwarová přerušení vznikají v jediném případě, a to když procesor narazí na instrukci INT n, kde n je vektor přerušení v rozsahu 0–255, tedy INT 0h – INT 0ffh. Vyžívá se k volání služeb operačního systému. Tento typ přerušení nelze maskovat.

External-hardware generated

Když jsem v minulém odstavci definoval toto přerušení jako vyvolané mimo procesor, nebyla to úplně pravda, protože do hardwarového přerušení se řadí tzv. Internal HW, která vznikají při vnitřní chybě kódu, např. dělení nulou, špatná instrukce. Externě vyvolané přerušení nastává při žádosti ze vstupu (vnější hardware) nebo chybě matematického koprocesoru.

INTerrupt Request

Je typ signálu přerušení, které lze tzv. maskovat, a to znamená, že pokud je bit IF (Interrupt Enable Flag) v příznakovém registru nastaven na 0, přerušení generované signálem INTR se neprovede.

Non Maskable Interrupt

Je-li typ signálu přerušení, které naopak nelze maskovat, tehdy se nezávisle na bitu IF se po přijetí signálu MNI přerušení provede.

Obsluha přerušení

Co se tedy stane, když procesor obdrží žádost o přerušení? Nejprve zkontroluje, jestli se daný signál bude maskovat a pokud ne, přeruší právě vykonávaný program a začne vykonávat program obsluhy přerušení, to v následujícím pořadí:

1. Na zásobník se uloží příznakový registr Flags
2. Příznaky IF a TF se vynulují
3. Na zásobník se uloží registr CS

4. Registr CS se naplní hodnotou obsluhy přerušení
5. Na zásobník se uloží registr IP
6. Registr IP se naplní hodnotou obsluhy přerušení

Interrupt Vector Table

Aby procesor věděl, jaké hodnoty má uložit do registrů CS,IP a hlavně, aby mohl rozlišovat různé druhy přerušení, existuje IVT ( tabulka vektorů přerušení ). Je to tabulka ukazatelů na příslušné obsluhy, obsahuje tedy hodnoty CS a IP volaných programů. IVT je uložená na fyzickém začátku paměti, tedy na adrese 0000h:0000h, jak jsme již zmínili obsahuje 256 položek ( řádků ) a každá má délku 4B. Celá tabulka má délku 1KB až po adresu 0000h:0400h. První dva byte řádku obsahují offset daného přerušení a druhé dva byte segment.

Rozložení v paměti
Adresa: tabulka: přerušení:
0000h:0000h offset:segment INT 0
0000h:0004h offset:segment INT 1
0000h:0008h offset:segment INT 2
0000h:03FCh offset:segment INT 0FFh

Návrat z obsluhy přerušení provádí instrukce IRET ( Interrupt RETurn ). Tato instrukce načte z zásobníku „staré” IP,CS a Flags a tím předá kontrolu zpět do volajícího programu. V následujícím pořadí:
1. Ze zásobníku se načte IP
2. Ze zásobníku se načte CS
3. Ze zásobníku se načte Flags

Vyhrazená přerušení

Procesor 8086 má 5 rezervovaných přerušení:
INT 0h nastává při dělení nulou, a to instrukcemi DIV a IDIV.
INT 1h nastane po provedení instrukce, když je bit TF ( Trap Flag ) v příznakovém registru nastaven. Jde o tzv. krokovací režim.
INT 2h nastává při přijetí vnějšího NMI.
INT 3h se generuje, když procesor narazí na jedno-slabikovou ( 1B ) instrukci INT 3 se strojovým kódem 0CCh. Používá se k ladění programů.
INT 4h pokud je OF ( Overflow Flag ) nastaven a procesor narazí na instrukci INT0, provede se následující přerušení.
Všechny tyto přerušení můžeme také generovat softwarově uvnitř programu.

root_podpora

V dnešní ukázce si ukážeme, jak nastavit naši vlastní obsluhu přerušení, obsluhující přerušení INT 0  – dělení nulou. Princip při nastavování rutiny všech 256-přerušení je stejný, jde pouze o změnu IVT tabulky. Jako v minulém díle pracujeme v reálném režimu, a k ukázce nám bude stačit boot sector. Funkčnost obsluhy jednoduše vyzkoušíte změnou z dělení nulou na jinou hodnotu.

; preruseni.asm

org 0x7c00  ;nastaveni segmentu

jmp main

;promene

boot_zpr db 'Start ...',13,10,0
chyba_zpr db 'Deleno nulou',13,10,0
int_zpr db 'Nastaveno preruseni.',13,10,0
konec_zpr db 'Konec programu.',13,10,0
bootdev db 0

zprava:   ;funkce na vypis na obrazovku
lodsb
or al,al
jz short zprava_konec
mov ah,0eh
mov bx,0007h
int 10h
jmp zprava
zprava_konec:
ret

main:
cli
mov ax,9000h
mov ss,ax
mov sp,0xffff     ;nastaveni zasobniku
sti

mov [bootdev],dl  ;dl = zarizeni ze ktereho je bootovano

mov ax,0
mov ds,ax
mov si,boot_zpr   ;vypis boot zpravy
call zprava

mov word [ds:0h*4],obsluha ;nastaveni obsluhy preruseni
mov word [ds:0h*4+2],0
jmp umela_chyba

obsluha:                       ;nastane pri deleni 0
mov si,chyba_zpr
call zprava
iret

umela_chyba:
mov si,int_zpr
call zprava
mov bx,0   ; deleni nulou
div bx
mov si,konec_zpr
call zprava

smycka:
jmp smycka      ;restart

times 510-($-$$) db 90h   ;sector musi byt dlouhy 512B

dw 0xaa55         ;oznaceni boot sectoru 

Kód přeložíme a nahrajeme na disketu:

nasm -o preruseni.bin -f bin preruseni.asm
dd if=preruseni.bin of=/dev/fd0 bs=512 

Byl pro vás článek přínosný?

Autor článku