Kodime ovladace zariadeni v C 1.

22.11.2001 18:26 | blackhole

Myslim, ze vsetci dobre vieme co to je ovladac zariadenia, modul, alebo ako chcete.
Ovladac sluzi pre vytvorenie jednotneho pristupu pre zariadenia rozneho typu. Moze sa jednat o ovladac znakoveho zariadenia, cd-rom, scsi, ide, ram disku. Ovladac moze zabezpecovat “prepojenie” medzi aplikaciou a suborovym systemom atd.. Hned v uvode by som rad upozornil, ze pisat ovladac nemusi byt narocnejsie, ale jednoznacne by sme mali byt rozvaznejsi ako pri pisani aplikacie (prepacte mi to slovo :)) Pri pisani ovladacu by sme mali poznat niektore kniznice, ktore sa pri rieseni “standardnych” problemov nevyuzivaju a podobne budeme riesit odlisne problemy ako pri pisani programu (aplikacie). Musime si uvedomit, ze pisanim modulu dotvarame cast jadra a ze aplikacie su daleko viac chranene voci chybam ako moduly jadra. Zle napisany (ci uz umyselne alebo nie) modul moze fatalne ohrozit stabilitu a funkcnost celeho systemu. Pri vytvarani vlastnych modulov mame vyhodu, ak mame k dispozicii zdrojovy kod jadra a mozeme pouzivat jeho casti v nasom module. Takze sme si vysvetlili co je to ovladac a ze si ho musime vazit a byt k nemu velmi dobry. Teraz by sa patrilo nieco povedat o zariadeniach. Zariadenie moze byt prakticky akakolvek cast pocitaca. Moze to byt interne alebo externe (ked chcete periferne) zariadenie. Zariadenie nemusi byt len fyzicke zariadenie, ale moze to byt napr. Specialny subor v /dev napr. random,… Toto zariadenie nie je pripojene na ziadny hardware, ale jedna sa o zariadenie, ktore exportuje nejaku funkciu aplikaciam. Dalo by sa tiez oznacit ako softwarove zariadenie (software device). Tu sa opat vraciame k ovladacu, je to vlastne kod, ktory ovlada dane zariadenie a exportuje (ako som uz spomenul pri /dev/random) pouzitelne funkcie pre aplikacie. Pri exportovani tychto funkcii hra jadro rolu len prostrednika, ktory umozni modulu komunikovat s danym zariadenim. Takze jadro nemusi ani tusit s cim komunikuje o to sa stara modul. Potom nie je ziadny problem pridat opdporu pre novy file system, nove zariadenie, nepotrebujeme prepisat jadro, len pripojime modul, ktory vie s danym zariadenim komunikovat. Zariadenia by sme mohli rozdelit na dve skupiny – znakove a blokove. Znakove zariadenia funguju na principe sekvencneho zapisu a citania dat, takze zapisujeme/citame bajt po bajte a prisup nie je zabespeceny ziadnou vyrovnavacou pamatou. Blokove zariadenia alebo zariadenia s nahodnym prisupom mozeme citat (zapisovat na ne) pomocou blokov dat, takze mozeme citat len po nasobkoch. Pristup k tymto zariadeniam je zabespeceny vyrovnavacou pamatou. Unix povoluje citanie len celych blokov, ale Linux umoznuje aj citanie casti bloku. K vacsine ovladacov v linuxe sa pristupuje cez suborovy system. Zariadenia su ulozene v adresari /dev. Ak v Linuxe zadate ls –l /dev tak v type suboru moze byt b alebo c (c=character device(znakove zariadenie), b=block device(blokove zariadenie)) nebudem podrobne rozoberat strukturu adresara /dev ak by bol zaujem mozem to v buducnosti doplnit. Este by sme si pred napisanim prveho modulu (ten tak straaaasne znamy hello world(kernel :-)) mohli povedat par pravidiel, ktorych by sme sa mali drzat. Najdolezitejsie je uvedomit si to, co som uz naznacil, ze modul bezi v rezime jadra a nie v uzivatelskom rezime, takze moze prakticky vsetko. Procesy beziace na linuxe maju iste “privilegia” ktore su pomenovane ring (0,1,2,3) kde ring 0 je rezim jadra a ring 3 je uzivatelsky rezim. Dolezite je pre nas to ze modul, ktory bezi v rezime ring 0 ma na rozdiel od procesov v rezime ring 3 pravo pristupovat priamu k zariadeniu. Predpokladam ze vieme co znamena multi-tasking, ktory samozrejme funguje aj pri jadre, aby nam mohlo bezat viac procesov sucasne (teda aspon na vonok to tak vyzera). Dolezite je, ze procesor prepina medzi procesmi (teda aj rezimamy vykonavania procesu (v linuxe len medzi ring 0 a ring 3)) a najdolezitejsie na tomto prepinani pre nas je ze pocas prepnutia z jedneho rezimu do druheho procesor neuchovava hodnotu registru FP, takze sa neodporuca pouzivat v moduloch cisla s “plavajucou” desatinnou ciarkou. Dalej treba davat pozor na dlhe cakania pocas vykonavania, aby modul zbytocne neblokoval system a samozrejme ako v kazdom programe si zachovat co najvacsi prehlad v kode a snazme sa do modulu nezahrnat veci, ktore sa daju riesit na vyssej urovni. Este by som rad spomenul, ze ladit jadro je problematickejsie ako ladit aplikaciu, ale tym sa v tomto clanku zaoberat nebudem. Takze tu mame zdrojovy kod nasho modulu:

/*
file:        prvy.c
author(:-)):    nieaky ze -=[Zyx]=-
desc:        moj prvy modul :)
*/

#include <linux/module.h>

// len kontrola (okopcena z nejakej knihy :-) pre spravne
// verzie funkcii API...?>
#if defined(CONFIG_MODVERSIONS)
#define MODVERSIONS
#include <linux/modversions.h>
#endif

#include <linux/kernel.h>

// nebude ziadne main, ale bude init_module ;)
int init_module(void)
{
        // ladiaca sprava, vsetky spravy zacinaju KERN_ najdete ich v kernel.h
        printk(KERN_DEBUG \"Zdravim moj krasny kernel !!! :-)\\n\\n\");
        return 0;
}

// vykona sa pri unloadnuti :-) modulu
void cleanup_module(void)
{
        // ladiaca sprava
        printk(KERN_DEBUG \"Caf, kernel, bolo mi u teba dobre :(\\n\\n\");
}

no, tak sme uspesne napisali modul, teraz ho skompilujeme:

[root@tux root]# gcc -D__KERNEL__ -DMODULE -DMODVERSIONS -I/usr/src/linux-2.4/include -Wall -O2 -o prvy.o -c prvy.c

gcc – tie parametre sa mi nechcu vysvetlovat najdete to niekde va manualovy strankach (mozno v helpe) a verte mi, ze su vsetky potrebne ;) problem by ste mohli mat s –I definuje to cestu k zdrojakom kernelu, takze ked vam to nepojde tak to upravte podla toho, kde tie zdrojaky mate. Tak a teraz staci uz len

[root@tux root]# insmod prvy.o
[root@tux root]# lsmod
Module Size Used by
prvy 384 0 (unused

…..

a mame ho loadnuty ladiace spravy zobrazite prokazom dmesg (pripadne si tam dajte na druhej konzole |tail –f a mozete sledovat, ako sa loadol a unloadol) Modul unloadneme prikazom

[root@tux root]# rmmod prvy

Modul (s kompilovanim) som testoval na RedHat 7.2ke.
Pokusil som sa priblizit problematiku modulov v linuxe, mam v plane tuto temu doplnit s nejakym komplexnejsim riesenim (len musim prehrabat nejaku literaturu, lebo nemam potuchy aky modul by som urobil, aby sa dal vyuzit a aby sluzil ako pekny priklad, asi nieco “ukradnem” z nejakej knihy) Ak by tu boli nejake nejasnosti/nepresnosti (urcite som na nieco zabudol) tak kritiku len uvitam. Su este veci, ktore viem ze nie som v suvislosti s touto temou nespomenul, ale to sa pokusim dotiahnut nabuduce.-=[Zyx]=-