/* Bu belgenin telif haklar� Necati Ersen ���EC�'ye aittir. K�k: http://acikkod.org �lk bask�: 2004-02-24 Son de�i�iklik: 2004-02-24 Bu d�k�man A��kkod.ORG Belge Yaz�m ve Da��t�m Lisans� ile da��t�lmaktad�r. */
Linux Kernel Mod�lleri ve Sistem �a�r�lar� Linux'te ayg�t s�r�c�leri, iki �ekilde kullan�labilir. Birincisi, direk olarak �ekirde�e g�m�l� olarak �al��mas�d�r(static loading). Bu durumda �ekirdek ba�lad�ktan sonra bu modulu de �al��t�racakt�r. �kincisi ise �ekirde�in i�inde olmay�p, sonradan y�klenecek �ekilde kullan�l�r(dynamic loading). Bu i�lem ise, �ekirdek sistemde �al���rken yap�l�r. Dinamik yuklenen bir modulun i�indeki, bir fonksiyon, m�d�l y�klenmeden �nce �al��t�r�lmak istenirse hata verecektir. Mod�l y�klendikten sonra bu fonksiyon rahatl�kla kullan�labilecektir. Linux, a��l�rken tipik olarak baz� modulleri kendisi y�kler. Sistem a��ld�ktan sonra y�klenen modulleri (statik yada dinamik) /proc/modules dosyas�ndan g�rebiliriz. Mod�ller genel olarak ayg�t s�r�c�s� olarak kullan�l�rlar. Bununla birlikte mod�ller herhangi bir fonksiyonu da ger�ekle�tirebilir. Mod�l Organizasyonu Bir mod�l y�klenirken, �ekirdek adres aral���nda (kernel space) s�per kullan�c� modunda �al��t�r�l�r. Y�klenen mod�l, kernel adres aral���ndaki veri yap�lar�ndan okuyabilir ya da yazabilir. Genel olarak kernel taraf�ndan, kullan�c�lara sunulan (export) fonksiyonlar ve hangi fonksiyonlar�n hangi mod�l taraf�ndan kullan�ld���n� /proc/ksyms dosyas�na bakarak g�rebiliriz. �ekirdek taraf�ndan export edilmi� fonksiyonlar, mod�l taraf�ndan direk olarak kullanabilir. Bir mod�l, ba�ka bir mod�l taraf�ndan export edilmi� fonksiyon ve de�i�kenleri kullanabilir yada kendisi, fonksiyon ve de�i�ken export edebilir. Mod�l yaz�l�rken dikkat edilmesi gereken noktalardan birisi de, export edilmi� de�i�kenlerin de�erini de�i�tirmektir. ��nk�, bu de�erler sistemin kararl�l���n� etkileyebilir. Bu y�zden ne yazd���m�zdan emin olmadan bu de�i�kenlerin de�eri de�i�tirilmemeli, sadece okunmal�d�r. Kernel konfig�rasyonunu hat�rlayal�m. SCSI deste�i k�sm�na g�z atal�m. E�er derleyece�imiz �ekirdekte SCSI deste�i olmayacaksa SCSI support se�ili olmamal�d�r. < > SCSI support SCSI deste�ini mod�l olarak sa�lamak i�in a�a��daki �ekilde kullan�r�z. <M> SCSI support --- SCSI support type (disk, tape, CD-ROM) <M> SCSI disk support (NEW) SCSI deste�i �ekirde�in i�inde g�m�l� olmas� i�in ise bu �ekilde kullan�r�z. <*> SCSI support --- SCSI support type (disk, tape, CD-ROM) <*> SCSI disk support (NEW) Modullerin Yap�s� Dinamik olarak y�klenecek �ekirdek mod�llerinin en az iki fonksiyon i�ermelidir. Bu fonksiyonlar mod�l y�klenirken ve bellekten at�l�rken kullan�lan init_module() ve cleanup_module() fonksiyonlar�d�r. #define __KERNEL__ #define MODULE #define LINUX #include <linux/kernel.h> #include <linux/module.h> #include ... ... int init_module (void) { ... } void cleanup_module (void) { ... } ... Genel olarak bir �ekirdek mod�l�n�n yap�s� bu �ekildedir. Bu �ekilde sadece iki fonksiyonu olan �ekirdek mod�l� kullanmak m�mk�nd�r. init_module() ve cleanup_module() fonksiyonlar�na, modulun ilk y�klendi�i zaman ve bellekten at�ld��� zaman yapmas� gereken i�ler yaz�l�r. �rne�in bir ayg�t�n register edilmesi ve unregister edilmesi bu fonksiyonlarla yap�lmal�d�r. init_module() fonksiyonu, mod�l y�klenirken �al��t�r�l�r. /sbin/insmod komutu ile bir mod�l� y�klemek istedi�imiz zaman, sistem taraf�ndan mod�l�n i�erisinde bulunan init_module fonksiyonunu �al��t�r�r. Bir mod�l sisteme y�klendi�i zaman, �ekirde�in yeni eklenen fonksiyonlar� kullanabilmesi i�in bu fonksiyonlar�n register edilmesi gerekir. E�er mod�l statik olarak y�klenmi�se, �ekirdek boot i�lemi s�ras�nda bu fonksiyonlar� register eder. Ama dinamik olarak y�klenen bir mod�l i�in bu i�i init_module() fonksiyonu yapar. Bellekten at�lan mod�ller i�inde unregister olay�, ayn� �ekilde ge�erlidir. Bu i�lemi ise, cleanup_module() fonksiyonu yapar. Kullan�c� taraf�ndan, mod�l i�inde bulunan bir fonksiyon kullan�lmak istendi�i zaman bir sistem �a�r�s� yap�l�r, ve �ekirdek, program� kullan�lmak istenen fonksiyona y�nlendirir. Bir mod�l derlendikten sonra �al��t�r�labilir bir kod haline gelir. Mod�l y�klenirken; 1. Ilk olarak bir �ekirdek fonksiyonu olan create_module() fonksiyonu �al���r ve y�klenecek olan mod�l� �ekirdek adres aral���na y�kler. 2. Bu i�lemden sonra mod�l�n kulland��� daha �nceden export edilmi� �ekirdek sembolleri aran�r. Bu y�zden export edilmi� bir sembol kullanan mod�l, bu sembol� export eden mod�lden sonra y�klenmek zorundad�r. Bu i�lemi bir �ekirdek fonksiyonu olan get_kernel_syms() yapar. 3. create_module() fonksiyonu, mod�l i�in bellek aral��� ay�r�r. 4. init_module() sistem �a�r�s� ile mod�l y�klenir. Burada daha sonradan y�klenecek mod�ller taraf�ndan kullan�lacak olan semboller export edilir. 5. Son olarak insmod, init_module() fonksiyonunu �a��r�r. cleanup_module() fonksiyonu ise, modul bellekten at�l�rken �al��t�r�l�r. /sbin/rmmod komutu, daha �nceden y�klenmi� bir mod�l� bellekten atmak i�in kullan�l�r ve sistem cleanup_module() fonksiyonunu �al��t�r�r. Basit bir mod�l� inceleyelim. #define __KERNEL__ #define MODULE #define LINUX #include <linux/module.h> #include <linux/version.h> #include <linux/fs.h> int init_module (void) { printk (KERN_EMERG "Module y�kleniyor.!\n"); return 0; } void cleanup_module (void) { printk (KERN_EMERG "Module bellekten at�l�yor.\n"); } #define __KERNEL__ Program�n normal bir program olmad���n�, kernel ile ilgili oldu�unu g�sterir. #define MODULE Program�n bir kernel mod�l� oldu�unu g�sterir. #define LINUX Linux i�in oldu�unu g�sterir. #include <linux/module.h> Modul ile ilgili tan�mlamalar�n bulundu�u header dosyas�d�r. #include <linux/version.h> Kernel'in versiyon bilgisini gosterir. #include <linux/fs.h> Veri yap�lar� gibi �nemli tan�mlamalar� i�erir. Yukar�daki modulu bir obje olarak derlememiz gerekmektedir. Derleyiciye, yazd���m�z kodun normal bir program olmad���n�, -Wall opsiyonu ile loader � ge�mesini ve -c opsiyonu ile de linker � �a��rmamas� gerekti�ini belirmemiz gerekir. siseci:~/kernel# gcc -Wall -c ornek.c siseci:~/kernel# ls -l ornek.o -rw------- 1 root root 1192 Jan 1 02:36 ornek.o siseci:~/kernel# insmod ornek Module y�kleniyor.! siseci:~/kernel# lsmod Module Size Used by ornek 196 0 (unused) .... siseci:~/kernel# rmmod ornek Module bellekten at�l�yor. MODULE tan�malamas�, bir deste�in mod�l olarak m� yoksa �ekirde�in i�inde g�m�l� olarak m� derlenece�ini belirtmek i�in kullan�l�r. S�r�c�leri inceledi�imiz de; #ifdef MODULE int init_module(void) #else int i2c_tuner_init(void) #endif �eklinde bir #ifdef blo�u ile, mod�l olarak derlenmesi durumunda ve �ekirde�e g�m�l� olacak �ekilde derlendi�inde hangi fonksiyonun kullan�ld���n�, nas�l anlad���n� g�r�r�z. MODULE olarak derlenecekse, gcc'nin -D parametresi ile belirtilmeli ve ya define ile belirtilmelidir. siseci:~/kernel# gcc -Wall -c -D__KERNEL__ -DMODULE -DLINUX ornek.c Yukar�daki �rnekte #define ile belirtilmi� tan�malamalar� kald�r�p, bu �ekilde de derleyebiliriz. Ilk bak��ta, C bilen birisi i�in iki nokta dikkati �eker. Birincisi main fonksiyonun olmamas�, ikincisi ise printf yerine printk kullan�lmas�d�r. printk ile printf arasindaki tek fark, printk da loglevel i belirmemizdir. #define KERN_EMERG "<0>" #define KERN_ALERT "<1>" #define KERN_CRIT "<2>" #define KERN_ERR "<3>" #define KERN_WARNING "<4>" #define KERN_NOTICE "<5>" #define KERN_INFO "<6>" #define KERN_DEBUG "<7>" Bu konu ile ilgili ayr�nt�l� bilgiyi syslog(2) man page inde bulabilirsiniz. Sistem �a�r�lar� ��letim sistemlerinin temelinde, sistemde yap�lacak t�m i�lemleri yapan fonksiyonlar vard�r. Linux'te bu fonksiyonlar sistem �a�r�s� denir. Kullan�c�n�n yapt��� i�lemler �ekirde�e iletilir ve �ekirdek ilgili sistem �a�r�s� �al��t�r�r. �zet olarak, kullan�c� taraf�ndan yap�lan i�lemlerin, �ekirdek taraf�ndan yap�lan k�sm�d�r diyebiliriz. Dosya a�mak, kapatmak, okumak, yazmak gibi bir �ok sistem �a�r�s� vard�r. SYS_open, SYS_close dosya a�arken (veya olu�tururken) / dosyay� kapat�rken, SYS_read ve SYS_write ise okuma / yazma yaparken kullan�lan sistem �a�r�lar�d�r. Sistem �a�r�lar� /usr/include/sys/syscall.h dosyas�nda belirtilmi�tir. #define SYS_read 3 #define SYS_write 4 #define SYS_open 5 #define SYS_close 6 int sys_open (const char *filename, int mode); int sys_close (unsigned int fd); int sys_read (unsigned int fd, char *buf, unsigned int count); int sys_write (unsigned int fd, char *buf, unsigned int count); Linux, IA32 mimarisinde sistem cagrilarini karsilamak icin iki metod kullanir: 1. lcall7/lcall27 gates 2. INT 0x80 software interrupt. Asil Linux uygulamalari INT 0x80'i kullanirken, diger bazi UNIX ler de lcall7 mekanizmasini kullanir. Sistem �a�r�s� numaras�n� ve parametreleri register'lara yazar ve 0x80 nolu interrupt'� �a��r�r. Sistem cagrisi istegini, cagri anindaki CPU register'larinin durumu belirler. EAX register'inin alacagi deger, hangi sistem cagirisinin calistirilacagini tespit eder. Diger register'lar, EAX'in aldigi deger gore parametrik deger tasirlar. Bu k�sm�n detaylar� i�in /usr/include/asm/unistd.h dosyas�na g�z atabilirsiniz. Sistem �a�r�lar�n�n nas�l �a�r�ld���n�, sistem ca�r�lar�n�n parametrelerinin nas�l i�lendi�ini g�rebilirisiniz. Bizlerde, kendi yapt���m�z mod�llerde sistem �a�r�lar�n� kullanabiliriz. Linux'te strace komutu ile, �al��t�r�lan programlar�n kullan��� sistem �a�r�lar�n� g�rebilirsiniz. 1.c -------------------- void main() { printf("Deneme\n"); } Derleyip, strace ile inceleyelim. siseci:~/kernel# make 1 siseci:~/kernel# strace ./1 execve("./1", ["./1"], [/* 32 vars */]) = 0 ... ... write(1, "Deneme\n", 7) = 7 .... execve ile yeni bir process ba�lat�l�yor. write ile 1 ile g�sterilen dosyaya 7 bayt uzunlu�unde "deneme\n" yaz�l�yor. ssize_t write(int fd, const void *buf, size_t count); write fonksiyonun 3 parametresinden birincisi hangi dosyaya yazaca��m�z� g�steriyor. Burada 1 olarak g�sterilen dosya standart output (stdout) u g�sterir. Linux'e baglandigimiz terminal de bir ayg�tt�r. A�a��daki �rnekte, tty1 i kullan�d���m�z g�r�lmektedir. siseci:~# ls -al /proc/self/fd/ total 0 lrwx------ 1 root root 64 Jan 1 03:05 0 -> /dev/tty1 lrwx------ 1 root root 64 Jan 1 03:05 1 -> /dev/tty1 lrwx------ 1 root root 64 Jan 1 03:05 2 -> /dev/tty1 0: stdin 1: stdout 2: stderr dir. Sistem Cagrilarinin modullerde kullanilmasi Mod�llerimizde sistem �a�r�lar�n� a�a��daki �ekilde kullanabilirsiniz. A�a��daki �rne�i inceleyelim. #define MODULE #define __KERNEL__ #define LINUX #include <linux/module.h> #include <linux/version.h> #include <linux/fs.h> #include <sys/syscall.h> extern void* sys_call_table[]; asmlinkage int (*getuid_syscall)(); int init_module (void) { getuid_syscall = sys_call_table[SYS_getuid]; printk(KERN_EMERG "%d\n", getuid_syscall()); return 0; } void cleanup_module (void) { printk (KERN_EMERG "Module bellekten at�l�yor.\n"); } siseci:~/kernel# insmod 1.o 0 siseci:~/kernel# rmmod 1 Module bellekten at�l�yor. Bu �rnekte, getuid sistem �a�r�s� kullan�l�yor. Pointer yap�s�nda bir fonksiyon tan�mlay�p, sys_call_table dan getuid() fonksiyonun adresini alip, tan�mlad���m�z fonksiyona atay�p kullanmam�z gerekiyor. Bu �ekilde di�er sistem �a�r�lar�n� da kullanabilirsiniz. Ilerleyen yazilarimizda, ornek bir aygit s�r�c�s�n�n nas�l �al��t���n� inceleyece�iz. Necati Ersen SISECI24 �ubat 2004