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

11. 10. 2001
Doba čtení: 11 minut

Sdílet

Opět malé výročí. Dneska jsme se dopracovali až k dvacátému dílu, což už je myslím slušné. A co nás čeká dnes? Nejprve ještě několik slov k adresáři "drivers", který jsem minule nedopatřením dost odbyl, pak budeme pokračovat adresářem "bus", a aby toho po malém zpoždění nebylo málo, profrčíme ještě i "fs".

Opět pro představu o tom, co nás čeká a co už máme za sebou, uvedu výpis adresářů, které lze nalézt na mém počítači v /proc. Otečkované jsou ty adresáře, které už jsme prošli.:

.acpi/     ide/    sys/
 bus/      irq/    sysvipc/
.driver/   net/    tty/
 fs/       nv/
driver

Minule jsem tvrdil, že ovladače, které používají tento adresář, jsou jen tři. Jak se ukázalo, není to pravda. Existuje několik cest, jak provést registraci souboru (podadresáře) v adresáři /proc (resp. /proc/drivers). Abych alespoň částečně osvětlil, jak se mi tohle nedopatření stalo, popíšeme si stručně jednotlivé způsoby.

Pro informační soubory určené pouze pro čtení je možno použít funkci create_proc_re­ad_entry(). Dále existuje obecná funkce pro vytvoření souboru create_proc_en­try(). Aby to nebylo tak jednoduché, v jádrech řady 2.0 a 2.2 se používala funkce s obdobným významem jménem proc_register() (respektive proc_register_dy­namic() v řadě 2.0). Pro odstranění jsou potom určeny funkce remove_proc_en­try() a proc_unregister(). Pro speciální soubory lze ještě využít zjednodušené varianty předchozích, a to proc_symlink(), proc_mknod(), proc_mkdir().

Všechny tyto funkce operují nad strukturou proc_dir_entry, která obsahuje všechny potřebné informace o libovolném prvku v adresáři /proc. Funkce se liší tím, že některé pouze vytvoří tuto strukturu a je na vás, ji vyplnit (proc_create_en­try()), jiné si potřebné informace vezmou jako parametry a vše vyřeší za programátora proc_create_re­ad_entry(). A dalším je třeba předat odkaz na už vytvořenou a vyplněnou strukturu a ony ji pouze zaregistrují v souborovém systému /proc (funkce pro jádra <2.4.x).

U ovladačů pro některý z předdefinovaných adresářů se předpokládá tento postup:

my_proc_entry = create_proc_entry("muj_skvelej_ovladac",
                                   S_IFDIR|my_perm, proc_root_driver);

Tohle volání vytvoří adresář s názvem „muj_skvelej_o­vladac“ a s právy dle proměnné my_perm, umístěný v adresáři proc_root_driver. Že se vytvoří adresář, udává příznak S_IFDIR. Důležité je právě použití exportované proměnné pro adresář /proc/driver, tedy proc_root_driver. Stejně tak existuje například proměnná proc_root_bus nebo proc_root_net.

Protože jsem předpokládal (uznávám dosti naivně), že se takto budou chovat všechny ovladače, prováděl jsem jejich vyhledání právě grepem na proc_root_driver. Výsledek jste viděli minule. Když se ozvaly hlasy (tímto děkuji jejich majitelům za upozornění), že něco chybí, podíval jsem se hlouběji, jak to dělají například ovladače pro RTC, inzerovaný v diskusi. A co jsem zjistil?

create_proc_read_entry ("driver/rtc", 0, 0, rtc_read_proc, NULL);

U ostatních ovladačů je použita právě druhá zmíněná metoda. Při použití této funkce se zadá přímo název souboru a funkce, která vygeneruje data při požadavku na čtení patřičného souboru. Asi je jasné, že můj grep neměl šanci. Poněkud pozoruhodné je použití složitější cesty (přes několik adresářů. Tato funkce bere jako svůj kořenový adresář to, co je zadáno jako poslední parametr. Pokud je to NULL, je kořenem /proc. V názvu je možno jako v tomto případě zadat relativní cestu k souboru a funkce sama vytvoří chybějící adresáře (se standardními právy a nastaveními).

Po tomto malém průzkumu se tedy podívejme, které další ovladače nyní nalezneme pomocí grepu nad „driver/“:

char/rtc.c                  RTC - Real Time Clock
char/h8.c                   Hitachi H8/337 microcontroller
char/nvram.c                NVRAM (neboli CMOS)

sound/via82cxxx_audio.c     AC97 sound codec
sound/emu10k1/main.c        Creative EMU10K1 sound card
sound/ite8172               ITE IT8172G sound card
sound/nec_vrc5477.c         AC97 codec NEC Vcr5477 na čipech MIPS

usb/uhci.c                  Universal Host Controller Interface pro USB

net/pcmcia/ray_cs.c         Raylink Wireless LAN

media/radio/radio-typhoon.c Typhoon Radio Card

Osobně můžu sloužit pouze RTC a CMOS pamětí. Ostatní HW nemám k dispozici. Protože u RTC a CMOSky nenacházím nic extrémně zajímavého, uvedu jen výpisy pro orientaci, a pokud budete mít někdo zájem o detaily, ozvěte se.

rtc_time        : 18:46:15
rtc_date        : 2001-10-03
rtc_epoch       : 1900
alarm           : **:00:00
DST_enable      : no
BCD             : yes
24hr            : yes
square_wave     : no
alarm_IRQ       : no
update_IRQ      : no
periodic_IRQ    : no
periodic_freq   : 1024
batt_status     : okay
Checksum status: valid
# floppies     : 1
Floppy 0 type  : 3.5'' 1.44M
Floppy 1 type  : none
HD 0 type      : 2f
HD 1 type      : none
HD type 48 data: 0/0/75 C/H/S, precomp 0, lz 47616
HD type 49 data: 45679/234/148 C/H/S, precomp 2439, lz 3030
DOS base memory: 640 kB
Extended memory: 65472 kB (configured), 65472 kB (tested)
Gfx adapter    : EGA, VGA, ... (with BIOS)
FPU            : installed

První je výpis souboru /proc/driver/rtc a potom následuje soubor /proc/driver/nvram­.Jenom mne trochu zaráží, že CMOSka hlásí pouze 64MB RAM když osazeno je 256MB. Když budu mít čas, tak se na to mrknu, ale nevím, ovladač NVRAM prostě přečte obsah CMOS paměti a zobrazí ho, takže nečekejte zázraky. Teď u sebe nemám popis obsahu CMOS paměti, ale pokud někdo víte, jak jsou tam informace uloženy, zde je kousek kódu, který vypisuje info o paměti:

 PRINT_PROC( "DOS base memory: %d kB\n", nvram[7] | (nvram[8] << 8) );
 PRINT_PROC( "Extended memory: %d kB (configured), %d kB (tested)\n",
             nvram[9] | (nvram[10] << 8),
             nvram[34] | (nvram[35] << 8) );

Pole nvram[] obsahuje „raw“ obsah paměti CMOS. Jedná se o bajty 14 až 128. Jeho velikost je tedy 128–14. A prvek nvram[0] odkazuje na bajt 14 v paměti CMOS. Pro více informací je možno nahlédnout do souborů: drivers/char/nvram­.c, include/linux/nvram­.h a include/asm/mc146818rt­c.h.

bus

Dostáváme se k informacím o sběrnicích a jejich obsazení periferiemi. Tady vás asi nepotěší, že na mém počítači už není jediná ISA sběrnice (alespoň klasická se slotem). Na druhou stranu deska Abit VP6, jejímž jsem šťastným vlastníkem, obsahuje čidla pro měření teplot a napětí. Ta jsou připojena přes sběrnici i2c a v konkrétním případě je pro připojení zřejmě použita interní ISA. Obsah adresáře /proc/bus je tedy následující:

i2c  i2c-0  i2c-1  pci/

Sběrnice i2c je representována stejnojmenným souborem, i2c-[01] jsou u mne prázdné. Z prvního souboru je možné zjistit právě napojení měřících čidel, v tomto případě přes ISA sběrnici. Další je připojení informačních čipů v pamětech typu DIMM:

i2c-0  dummy  ISA main adapter                ISA bus algorithm
i2c-1  smbus  SMBus VT82C686 adapter at 5000  Non-I2C SMBus adapter

Tento výpis byl proveden při zavedení těchto modulů: i2c-core, i2c-proc, i2c-isa, i2c-viapro, eeprom a via866a. Funkční moduly jsou poslední dva, eeprom pro čtení informací z paměťových modulů DIMM a via686a pro informace ze senzorů tepla a napětí. Jedno malé, leč důležité upozornění! Moduly pro čidla nejsou obsaženy v jádře (i když i zde je možno nalézt podporu sběrnice i2c), ale najdete je na adrese www.lm-sensors.nu. Jedná se o dva samostatné balíčky lm_sensors a i2c (u mne obojí verze 2.6.0).

Nebudu zabředávat do informací o připojení senzorů a sběrnicích jako i2c nebo SMBus. Hlavně proto, že o nich nic moc nevím. Užitečné informace o senzorech a paměti najdeme někde jinde (/proc/sys/de­v/sensors/ a tam si také řekneme, co znamenají.

Teď už raději přejděme na sběrnici PCI, o té Vám toho můžu říci přece jenom něco víc. V adresáři /proc/bus/pci jsou informace o konfiguračním prostoru jednotlivých karet pro tuto sběrnici. Všechny informace jsou zde uvedeny dvakrát, jednou v souboru pci/devices a podruhé v jednotlivých adresářích. Tyto informace využívá například utilita lspci, kterou je vhodné použít namísto civění do nul a jedniček. Ale i to civění může být občas zajímavé. Tak nejprve soubor devices:

0000    11060691   0     d8000008   00000000   00000000
0008    11068598   0     00000000   00000000   00000000
0039    11060571   0     00000000   00000000   00000000
003a    11063038   13    00000000   00000000   00000000
003b    11063038   13    00000000   00000000   00000000
003c    11063057   5     00000000   00000000   00000000
0050    10ec8139   11    0000cc01   de000000   00000000
0058    125d1969   11    0000d001   0000d401   0000d801
0100    10de0110   10    dc000000   d0000008   00000000

Údaje zde můžeme rozdělit po sloupcích. První sloupec udává jednoznačnou adresu zařízení dle sběrnice, jeho první dvě cifry udávají číslo sběrnice. Jak je vidět, všechny řádky kromě posledního zde mají „00“ a jsou tedy připojeny na společnou sběrnici PCI. Poslední řádek je zařízení připojené na sběrnici „01“. Jak zjistíme později, je sběrnice číslo 0 skutečná PCI a sběrnice číslo 1 je AGP sběrnice. AGP je totiž odvozena od PCI, a tak jsou informace o nich zobrazovány společně.

Druhý sloupec jednoznačně identifikuje zařízení, která se v dané sběrnici nachází. První čtyři cifry udávají identifikaci výrobce, zbývající čtyři identifikaci výrobku. Pro převod na textové popisky je potom možno použít několik zdrojů. Jedním z nich je soubor /usr/share/pci­.ids, další možností je patřičný soubor v jádře: drivers/pci/pci­.ids. Ten bude pravděpodobně novější (zvlášť pokud používáte vlastní novější jádro :).

Třetí sloupec udává IRQ, které dané zařízení používá. Je-li umožněno sdílení přerušovacích linek, mohou mít dvě různá zařízení stejné IRQ (viz IRQ 11).

Další sloupce obsahují bázové adresy a velikosti paměťových oblastí pro daný adaptér. Například pro grafickou kartu je jednou oblastí její lokální grafická paměť mapovaná do adresového prostoru procesoru (poslední řádek). Nejprve je uvedeno sedm bázových adres, z nichž ne všechny musí být využity, následuje sedm velikostí oblastí s příslušnou bázovou adresou. Například u posledního řádku najdeme v prvním sloupci adresu DC000000 (MMIO registry) a v druhém adresu D0000000 (framebuffer). Potom ve sloupcích 8 a 9 jsou vidět velikosti těchto oblastí 01000000 (16MB) respektive 08000000 (128MB). Stejné informace dostaneme jednak pomocí utility lspci, a nebo pro XFree86 >4.0 také ze souboru XFree86.0.log pomocí grepu:

sioux@sirion /var/log $grep -E "Linear|MMIO" XFree86.0.log
(--) NVIDIA(0): Linear framebuffer at 0xD0000000
(--) NVIDIA(0): MMIO registers at 0xDC000000

Zvídavé jistě napadne, proč je ve výpisu adresa D0000008. To vypadá jako nějaký blud. Ovšem pokud si uvědomíme, že velikost oblasti a její bázová adresa budou zřejmě zarovnány na nějakou jednotku větší než bajt (třeba stránka – 4/8 KB), zbývá nám posledních pár bitů adresy k jinému využití. Konkrétně jsou zde uvedeny příznaky pro danou oblast. Jednotlivé příznaky udávají typ oblasti – zda se jedná o 32bitovou, nebo 64bitovou adresu, případně zda je paměť tzv. prefetchable – kešovatelná. V této situaci se poslední případ rozlišuje podle toho, zda čtení v dané oblasti má, nebo nemá vedlejší účinky. Čtení framebufferu nám prostě zobrazí jeho hodnotu, ale čtení konfiguračních registrů může měnit jejich nastavení, a proto je nutné ho číst znovu z paměti a ne z cache.

Teď se přeneseme do jednotlivých adresářů. Nejprve jejich název. Ten kóduje identifikaci konkrétního zařízení na sběrnici – jeho umístění. Nejdříve adresář s číslem sběrnice – o tom jsme už mluvili. V nich se nacházejí podadresáře pro jednotlivá zařízení s dalšími podivnými názvy. Je na čase shrnout adresování PCI zařízení. Každé PCI zařízení v systému je jednoznačně adresováno pomocí 16bitového čísla skládajícího se ze tří částí. Prvních osm bitů udává číslo sběrnice, z toho dostaneme až 256 možných sběrnic v jednom počítači. Následuje pět bitů pro zařízení (32 zařízení) a tři bity pro tzv. funkci. Tohle schéma počítá s multifunkčními zařízeními jako například zvuková karta, na níž je napojena ještě CD-ROMka. V takovém případě bude mít tento komplet přiděleno jedno číslo zařízení, ale lišit se budou čísla funkcí (zvukovka funkce 0, CD-ROM funkce 1). Dalším dobrým příkladem jsou prostředky základní desky (řádky 3–6 ve výpisu souboru drivers). Zde je vše jedno zařízení a jednotlivé funkce jsou ISA bridge, IDE cntrl, USB, USB, ACPI.

Tohle identifikační číslo se používá buď jako jedno 16bitové číslo – jako v prvním sloupci v souboru devices, nebo jako dvě 8bitová čísla oddělující sběrnici a zařízení, nebo jako trojice bus, dev, fun. Tato trojice se často zapisuje jako

bus:dev.fun

No a to nám už vysvětluje způsob pojmenování souborů v /proc/bus/pci­/[bus_id]/. Obsahem těchto souborů je kopie tzv. konfiguračního prostoru PCI zařízení. Jeho velikost je vždy 256 bajtů, z toho obsah prvních 64 bajtů je dán standardem, je vždy přítomen a obsahuje nejdůležitější informace o zařízení. Pro popis jednotlivých položek doporučuji například kapitolu 15. z knihy Linux Device Drivers, kterou lze on-line najít na internetu u nakladatelství O'Reilly, případně její PDF verzi tamtéž.

Jak jsem již řekl, informace uvedené v adresáři /proc/bus/pci/ lze jednoduše získat pomocí utility lspci (často /sbin/lspci). Ta má spoustu voleb, jak informace zobrazit, a bývá příjemnější než přímý výstup konfiguračního prostoru.

fs

Opět se jedná o podobný adresář jako /pro/driversc. Po menším hledání (obdobným způsobem) jsem našel dva souborové systémy, které jej využívají. Prvním z nich je NFS. Když spustíte NFS démona, objeví se zde adresář /proc/fs/nfs, který obsahuje soubor exports. Ten obsahově odpovídá stejnojmennému souboru v adresáři /etc, rozdíl je v tom, že zde nalezneme navíc číslo verze (je nastavena napevno v fs/nfsd/expor­t.c) a standardní příznaky, které nemusí být v souboru s definicí exportů uvedeny (async, wdelay), a také IP adresu klientského počítače. Je doufám jasné, že tento soubor zobrazuje aktuální informace, a tak je možné ho použít v případě potíží, když je potřeba vědět, jak je export nastaven ve skutečnosti.

# Version 1.1
# Path Client(Flags) # IPs
/home   se710(rw,no_root_squash,async,wdelay) # 192.0.0.2

Druhým kandidátem na využití je souborový system CODA. Ten si v adresáři /proc/fs/coda vytváří tyto soubory: vfs_stats, upcall_stats, permission_stats, cache_inv_stats. Bohužel CODu neprovozuji, a tak vám nemohu poskytnout ani výpis, ani podrobnosti o obsahu jednotlivých souborů. Pokud máte s CODou někdo nějaké zkušenosti, určitě se o ně rádi podělíte s námi ostatními :)

Autor článku