Hlavní navigace

Co před námi tají /proc (8)

9. 8. 2001
Doba čtení: 6 minut

Sdílet

Tentokrát se díky velkému vytížení při psaní dílu o přerušeních vracím k několika informacím, které jsem opomněl zmínit. Tímto děkuji nejmenovanému laskavému čtenáři za připomenutí. Pokračování popisu souborů (dnes to měl být ksyms) odložíme na příště, neboť tohle téma mi připadá taky poměrně zajímavé.

Řekneme si něco podrobností o systému přerušení na architektuře Intel x86 a jeho obsluze v systému Linux. Základní otázka zvídavého čtenáře byla, kde jsou přerušení, jejichž čísla v patřičném výpisu souboru interrupts chybí. Odpověď je na jednu stranu velmi jednoduchá: Při tisku se prochází pole všech možných přerušení a tisknou se ty, u nichž je platný (nenulový) ukazatel na strukturu action, která obsahuje informace o obsluze přerušení. Patřičná funkce se jmenuje get_irq_list a nalézá se v souboru arch/xxx/kernel/ir­q.c. Položka action pro nás zatím bude pro zjednodušení představovat pouze akci vykonanou po přijetí příslušného přerušení. Pokud není co vykonat, nikdo asi přerušení neobsluhuje a tudíž nemá cenu něco vypisovat (stejně není co).

Pokud někomu tohle vysvětlení stačí, nechť laskavě přeskočí pár následujících odstavců (až na ten poslední :). Pro ty ostatní pro lepší orientaci zopakuji původní výpis z pátého dílu o souboru interrupts:

        CPU0
  0:     460943    IO-APIC-edge  timer
  1:      21161    IO-APIC-edge  keyboard
  2:          0          XT-PIC  cascade
  9:     460757   IO-APIC-level  nvidia
 10:          0   IO-APIC-level  ESS Solo1, eth0
 12:      83236    IO-APIC-edge  PS/2 Mouse
 14:       9901    IO-APIC-edge  ide0
 15:          5    IO-APIC-edge  ide1
NMI:          0

Na první pohled by tohle základní vysvětlení možná mohlo vypadat použitelně, jenže existuje několik ALE. S tím, co jsme si právě řekli, si vystačíme například při vysvětlování, proč chybí přerušení číslo 7, o kterém (například z bios setupu) vím, že obsluhuje paralelní port. Podporu paralelního portu nemám zakompilovanou napevno do jádra, protože paralelní port používám výjimečně. Proto je tohle přerušení skutečně volné. Pokud budu potřebovat třeba propojit dva počítače pomocí PLIP a zavedu modul pro paralelní port například takto:

modprobe parport_pc

s následujícím obsahem /etc/modules.conf

...
#Paralell port module options
alias parport_lowlevel parport_pc
options parport_pc io=0x378 irq=7
...

Tak dostanu do syslogu hlášení:

Aug  2 16:19:24 sirion kernel: 0x378: FIFO is 16 bytes
...  0x378: writeIntrThreshold is 8
...  0x378: readIntrThreshold is 8
...  parport0: PC-style at 0x378 (0x778), irq 7, using FIFO
               [PCSPP,TRISTATE,COMPAT,ECP]

Během inicializace modulu se provede mimo jiné žádost o přidělení potřebného přerušení, přesněji IRQ. Pokud provedu nyní výpis obsahu souboru /proc/interrupts, přibude nový řádek (označený šipkou):

   2:          0          XT-PIC  cascade
-> 7:          2    IO-APIC-edge  parport0
   9:     539350   IO-APIC-level  nvidia

Pokud moduly odstraním (příkazem rmmod), řádek opět zmizí. Stejná situace bude u ovladačů pro USB rozhraní, které nejsou také momentálně nahrány. Ty ovšem využívají IRQ 12 spolu s PS/2 myší a tak řádek nepřibude, jen se doplní druhý ovladač pro IRQ 12.

Dále se budeme zabývat sériovými porty. Dle BIOSu (Setupu) mají přiřazeny IRQ 3 a 4. Ovladač sériového portu mám opět jako modul, takže ho zavedu pomocí příkazu modprobe:

modprobe serial

A patřičný výpis ze syslogu:

Aug  2 17:27:38 sirion kernel: Serial driver version 5.05a (2001-03-20)
                               with MANY_PORTS SHARE_IRQ SERIAL_PCI enabled
Aug  2 17:27:38 sirion kernel: ttyS00 at 0x03f8 (irq = 4) is a 16550A
Aug  2 17:27:38 sirion kernel: ttyS01 at 0x02f8 (irq = 3) is a 16550A

Nyní by se dalo čekat, že bude situace stejná jako u paralelního portu. Kupodivu se však soubor interrupts vůbec nezmění. Po delším pátrání jsem přišel na to, že vlastní přerušení se alokují až v okamžiku otevření souborů /dev/ttyS[0|1]. Pokud tedy zadáme třeba jen cat /dev/ttyS0 & cat /dev/ttyS1, objeví se kýžené řádky:

   2:          0          XT-PIC  cascade
-> 3:          1    IO-APIC-edge
-> 4:          1    IO-APIC-edge
   7:          2    IO-APIC-edge  parport0
   9:     253542   IO-APIC-level  nvidia

K malému úžasu ovšem není přítomen název ovladače (poslední sloupec výpisu) a to i přes to, že funkce pro požadavek IRQ se zdá být volána správně (s hodnotou příslušného parametru „serial“). Přiznám se, že mi není úplně jasné, proč tomu tak je. Předává se (a uchovává se) sice jen hodnota ukazatele na řetězec, ale adresový prostor jádra by měl být jednotný. Možná je to proto, že je ovladač přeložen jako modul.

Jakmile soubory ttySx uzavřeme, uvolní se i příslušné IRQ. Stejně to funguje i u ovladače floppy mechaniky. Stačí dát mount /mnt/floppy máme další řádek:

   4:          1    IO-APIC-edge
-> 6:          4    IO-APIC-edge  floppy
   7:          2    IO-APIC-edge  parport0

Doufám, že jste získali představu jak to funguje, a tak zbytek jen shrnu. Chybí nám už jen IRQ číslo 5, 8, 11 a 13. Teď už to není složité. IRQ 5 patří ovladači APIC – tedy řadiči přerušení. IRQ 8 je Real Time Clock a jeho absence je opět způsobena chybějícím kódem v jádře nebo modulem. Řádek uvedu v koncovém výpisu. IRQ 11 je přiřazeno pro RAID řadič HPT370, ten je ovšem v současné době nevyužit. Podle literatury patří IRQ 13 jednotce FPU, tohle řešení komunikace s procesorem se (předpokládám) používalo v době samostatného koprocesoru. Dnes je tedy buď nedostupné (rezervované), nebo volné k libovolnému využití.

Na závěr této konkrétní ukázky tedy celý výpis ještě jednou:

           CPU0
  0:     842363    IO-APIC-edge  timer
  1:      37642    IO-APIC-edge  keyboard
  2:          0          XT-PIC  cascade
  3:          1    IO-APIC-edge
  4:          1    IO-APIC-edge
  6:          6    IO-APIC-edge  floppy
  7:          2    IO-APIC-edge  parport0
  8:          0    IO-APIC-edge  rtc
  9:     486873   IO-APIC-level  nvidia
 10:          0   IO-APIC-level  ESS Solo1, eth0
 12:      50836    IO-APIC-edge  PS/2 Mouse
 14:      19831    IO-APIC-edge  ide0
 15:          5    IO-APIC-edge  ide1
NMI:          0
ERR:          0

Teď bych ještě rád zúročil všechnu námahu vynaloženou při hledání přesné implementace obsluh přerušení v Linuxu na architektuře Intel x86 a přidám ještě odstaveček o konstrukci IDT.

Procesory Intel x86 v chráněném režimu uchovávají informace o obsluze přerušení v segmentu, jehož obsahem je IDT – Interupt Descriptor Table. To je tabulka vstupních bodů přerušení. Pokud se vyskytne libovolné přerušení, vezme se jako index do této tabulky a provede se obsluha dle obsahu položky v tabulce. Tabulka může být v (nejen v chráněném režimu) umístěna kdekoliv v paměti počítače (tedy nejen prvních 1024 bajtů) a odkazuje na ni registr IDTR. Ten je ovládán privilegovanými instrukcemi LIDT, SIDT Load IDT, Store IDT. Prvky tabulky jsou deskriptory – struktura určená pro popis dalších segmentů v paměti v tomto případě segmentů s kódem obsluhy přerušení. Existuje několik variant obsahu deskriptoru pro obsluhu přerušení, ale tím se zde nebudu zabývat. Velikost této tabulky může být až 256 popisovačů (deskriptorů). Připomenu, že existují čtyři druhy přerušení: externí – maskovatelné a nemaskovatelné a interní – výjimky a softwarové přerušení. Ty jsou naskládány do této tabulky takto:

CS24_early

Tabulka č. 163
Index IDL využití
0×00-x01F

systémové,rezer­vované přerušení. 0×00 – 0×13
jsou výjimky procesoru, 0×02 je nemaskovatelné přerušení

0×20–0×2F

hardwarová přerušení – IRQ. Mapování je nastaveno ve funkci
init_8259A() v souboru arch/xxx/kernel/i8259­.c. Master obvod
mapuje přerušení IRQ 0–7 do vektoru na pozici 0×20–0×27, slave obvod
pak IRQ 8–15 do pozic 0×28–0×2F. Jedná se o maskovatelná přerušení.

0×30–0×EF

Přerušení pro potřeby ovladačů. Taktéž maskovatelná. Přerušení 0×80 má
speciální význam, používá se k provádění systémového volání. To nejde
provést pouhým voláním funkce, protože jádro musí běžet v režimu
maximální priority (na Intelu Privilege Level – Úroveň oprávnění
0). Volání systému tedy probíhá tak, že se na zásobník vloží
požadované parametry volání a nakonec index do tabulky všech
systémových volání. Potom se provede zmiňované přerušení, jehož
obsluha vybere (částečně) obsah zásobníku a zavolá skutečnou funkci
jádra.

0×F0–0×FF

Konec tabulky je vyhrazen systémovým přerušením převážně pro SMP
architektury. Z toho 0×F0 – 0×FA jsou volné pro budoucí využití.
Význam vektorů 0×FB až 0×FF lze nalézt v souboru
include/asm-i386/hw_irq.h. Přerušení jsou využity například k
invalidaci TLB nebo pro APIC.

Softwarová přerušení jsou vyvolávána instrukcí INT jejímž parametrem je index do tabulky. Tímto způsobem lze tedy vyvolat libovolné z uvedených přerušení. Vyvolání instrukcí INT lze ovšem maskovat. Maximální počet uvažovaných přerušení (např. při výpisu souboru interrupts) je definován jako NR_IRQS a jeho hodnota je v současnosti 224 (16 IRQ + 208 APIC přerušení – adresový prostor 0×20–0×FF).

Příště už budeme pokračovat normálně souborem ksyms.

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

Autor článku