IO 

po polsku


Nastêpna strona
Poprzednia strona
Spis tre¶ci

2. U¿ywanie rejestrów wej¶cia/wyj¶cia w programach napisanych w C

2.1 Metoda zwyk³a


Procedury dostêpu do portów (rejestrów) we/wy umieszczone s± w
/usr/include/asm/io.h (lub w linux/include/asm-i386/io.h w ¼ród³ach j±dra)
Procedury te wystêpuj± w formie makr do wstawienia a wiêc wystarczy ¿e zrobisz #include <asm/io.h>;
nie potrzebujesz ju¿ ¿adnych dodatkowych bibliotek.
Z powodu ograniczeñ w gcc (obecna wersja 2.7.2.3 i poni¿ej) oraz egcs
(wszystkie wersje) programy wykorzystuj±ce te procedury musz± byæ kompilowane
z w³±czon± optymalizacj± (gcc -O1 lub wiêcej) lub mo¿esz te¿
zrobiæ #define extern bez parametru (puste) zanim w³±czysz <asm/io.h>.
Do odpluskwiania (debugging) mo¿esz u¿yæ gcc -g -O (przynajmniej w nowoczesnych
wersjach gcc), chocia¿ optymalizacja mo¿e spowodowaæ, i¿ debugger bêdzie
zachowywa³ siê trochê dziwnie. Je¶li to sprawia Ci k³opot, procedury korzystaj±ce
z rejestrów we/wy wstaw do osobnego pliku i tylko ten plik poddaj optymalizacji
podczas kompilacji.
Zanim dostaniesz siê do jakiegokolwiek portu we/wy, musisz nadaæ swemu
programowi uprawnienia do tego. Robi siê to wywo³uj±c funkcjê ioperm()
(zdeklarowan± w unistd.h i zdefiniowan± w j±drze) gdzie¶ w okolicach pocz±tku
programu (przed jakimkolwiek dostêpem do portów) Sk³adnia tego polecenia
to ioperm(sk±d,ile,w³acz) gdzie sk±d jest pierwszym portem do którego
chcesz mieæ dostêp a ile liczb± kolejnych portów do których chcesz mieæ dostêp.
Dla przyk³adu ioperm(0x300, 5, 1) da ci dostêp do portów od 0x300 do 0x304
(w sumie piêc portów). Ostatni argument to warto¶c logiczna mówi±ca
o tym czy program otrzyma dostêp do portów (1 - prawda) b±d¼ nie (0 - fa³sz).
Mo¿esz wywo³ywaæ ioperm() wiele razy aby w³±czyæ wiele nieci±g³ych obszarów
rejestrów. Zajrzyj do ioperm(2) w podrêczniku systemowym man po szczegó³y
odno¶nie sk³adni.
Wywo³anie ioperm() wymaga aby twój program mia³ uprawnienia root'a:
wobec czego albo musisz uruchamiaæ go jako root albo daæ mu suid root'a.
Po wywo³aniu ioperm() mo¿esz ju¿ zrezygnowaæ z uprawnieñ root'a.
Nie wymaga siê aby¶ w sposób jawny wy³±cza³ uprzywilejowany dostêp
do portów (czyli ioperm(....,0)) na koñcu programu; robi siê to automatycznie
wraz z zakoñczeniem procesu.
Funkcja setuid() w wypadku u¿ytkownika bez przywilejów root'a nie odbiera
dostêpu do portów przydzielonego przez ioperm() ale funkcja fork() ju¿
tak. (proces potomny nie dostaje dostêpu ale proces-rodzic go zachowuje)
ioperm() mo¿e jedynie umo¿liwiæ dostêp do portów od 0x000 do 0x3FF. Je¶li
chcesz u¿ywaæ innych portów (wy¿szych) musisz u¿yæ funkcji iopl() (która
daje ci dostêp do wszystkich portów od razu) U¿yj argumentu 3 (czyli iopl(3))
aby daæ swemu programowi dostêp do wszystkich portów (b±d¼ ostro¿ny
- dostêp do niew³a¶ciwych portów mo¿e wywo³aæ najró¿niejsze usterki komputera).
Musisz mieæ uprawnienia root'a aby wywo³aæ iopl(). Po szczególy
zajrzyj do podrêcznika systemowego man: iopl(2)
Teraz w³a¶ciwy dostêp do portów.. Aby odczytaæ bajt (8 bitów) z
portu, wywo³aj funkcjê inb(port), zwraca ona odczytan± warto¶æ.
Aby zapisaæ bajt do portu wywo³aj outb(warto¶æ,port) (zwróæ uwagê na kolejno¶æ argumentów)
Aby odczytaæ s³owo (16 bitów) z portów x i x+1 (jeden bajt z ka¿dego ³±czone
w s³owo za pomoc± asemblerowej instrukcji inw) wywo³aj inw(x) Aby zapisaæ
s³owo do tych dwóch portów u¿yj outw(warto¶æ,x) Je¶li nie jeste¶ pewien
której instrukcji u¿yæ (operuj±cej bajtem czy s³owem) prawdopodobnie bêdziesz
chcia³ u¿yæ inb() i outb() - wiêkszo¶æ urz±dzeñ zaprojektowana jest z
bajtowo-zorientowanym dostêpem do portów.
Zauwa¿, ¿e wykonanie ka¿dej instrukcji operuj±cej na portach zajmuje co najmniej mikrosekundê.
Makra inb_p(),outb_p(),inw_p() i outw_p() dzia³aj± identycznie z tymi
powy¿ej ale dodatkowo wykonuj± opó¼nienie (oko³o 1 mikrosekundy) po dostêpie
do portu. Mo¿esz spowodowaæ ¿e opó¼nienie bêdzie warto¶ci ok 4 mikrosekund
je¶li zrobisz #define REALLY_SLOW_IO zanim w³±czysz <asm/io.h>
Makra te zwykle (chyba ¿e zrobisz #define SLOW_IO_BY_JUMPING, które jest raczej
mniej dok³adne) u¿ywaj± zapisu do portu 0x80 zby uzyskaæ opó¼nienie, wobec
czego musisz najpierw daæ dostêp do portu 0x80 za pomoc± ioperm(). Zapisy
do portu 0x80 nie powinny mieæ wp³ywu na ¿adn± czêsæ systemu. Je¶li chcesz
poznaæ bardziej wszechstronne metody dostêpu do portów czytaj dalej.
W stosunkowo nowych dystrybucjach podrêcznika systemowego man znajduj±
siê strony ioperm(2), iopl(2) oraz powy¿szych makr.

2.2 Metoda alternatywna: /dev/port


Innym sposobem dostêpu do rejestrów I/O jest otworzenie urz±dzenia
/dev/port do zapisu lub/i odczytu za pomoc± funkcji open()
(/dev/port to urz±dzenie znakowe, numer g³ówny 1, poboczny 4)
(Funkcje f*() z biblioteki stdio maj± wewnêtrzne buforowanie wiêc ich unikaj)
Nastêpnie wywo³aj lseek() do odpowiedniego bajtu w tym pliku
(pozycja 0 = port 0x00 pozycja 1 = port 0x01 itd) i czytaj (read())
lub zapisuj (write()) bajt lub s³owo.
Oczywi¶cie aby to zadzia³a³o twój program musi mieæ mo¿liwo¶c czytania i zapisywania do /dev/port.
Metoda ta jest prawdopodobnie wolniejsza od metody normalnej pokazanej powy¿ej
ale nie potrzebuje ani optymalizacji programu ani wywo³ywania ioperm().
Nie potrzebuje te¿ uprawnieñ root'a je¶li nadasz zwyk³ym u¿ytkownikom lub jakiej¶
grupie prawa dostêpu do /dev/port - jest to jednak nieporz±dane z punktu widzenia
bezpieczeñstwa systemu, jako ¿e mo¿liwe jest wtedy uszkodzenie systemu,
a mo¿e nawet zdobycie przywilejów root'a przez bezpo¶redni dostêp
za pomoc± /dev/port do dysków, kart sieciowych itp.


Nastêpna strona
Poprzednia strona
Spis tre¶ci
  • zanotowane.pl
  • doc.pisz.pl
  • pdf.pisz.pl
  • pajaa1981.pev.pl