/* 
   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 SISECI

24 �ubat 2004