sayfa başı

6 Mart 2015 Cuma

Adım Adım Linux Driver Yazıyoruz -1-

Adım Adım Linux Driver Yazıyoruz
Giriş
Bu yazımda Linux driver eklemeyi ele alacağım. Kullanacağımız başlık dosyalarından(header file) yazacağımız koda, teorik bilgilerden uygulamalı anlatıma hatta konsol komutları ve çıktılarına kadar değinip anlaşılması ve öğrenilmesi kolay bir içerik oluşturmaya çalışacağım. Bu sayede daha öncesinde örümcek ağı gibi gelen konular ve sorular gittikçe açılacak. Hatta yazının sonunda bunlar o kadar da zor değilmiş diyeceksiniz ki bu da zor olduğu halde bilinen(becerilen) iş kolay iştir cümlesini size hatırlatacak.


   Her ne kadar basit bir anlatım oluşturmayı amaçlasam da bu dokümanda bulunanları tam olarak anlamak için işin bir kısmı da sizin üzerinizde. Size yüklediğim görev yazılan her kodu satır satır bakarak yazmak, ismi geçen başlık dosyasını bulup bahsi geçen fonksiyonlara göz atmak, koşulan konsol komutlarını koşmak ve buradaki çıktılar ile karşılaştırmak olacak. Her zaman söylendiği gibi “Yazılım” nasıl öğrenileceğini kendi içinde saklar. “YAZ ılım”. Bu yüzden yazın yazın yazın tekrar tekrar yazın.
Kernel Nedir?
Eğer bir sözlüğe bakarsanız kernel kelimesinin anlamının çekirdek, öz olduğunu görürsünüz. Fakat  Kernel bizim bildiğimiz gibi bir işletim sisteminin tüm çekirdeğidir. Kernel sistem yöneticisidir. Tüm sistem kaynaklarını yönetir. Sistem kaynakları nelerdir diyecek olursanız eğer: CPU, memory, input/output, network...

   Kernel' dan neden bu kadar az bahsettim derseniz ilk olarak uzun uzun yazıp konu dışına çıkmamak için bu özet bilgi ile yetindim diyebilirim. İkinci olarak ilerde anlatılacak konuların, özellikle yazılacak kodların bu katmana ait olduğunu belirtmek isterim. Burada aklınızda bir soru oluşmasını bekliyorum. “Başka katmanlar da mı var?” sorusu ya da en azından şu kelimenin aklınıza gelmesini umut ediyorum. User space(kullanıcı katmanı). Fark ettiyseniz iki katmanımız oluştu, kernel ve user space. User space çok yakın olduğumuz alan hatta sürekli kullandığımız alan. Hani şu printf ile “Hello World” uygulamasını koşup çıktısını konsolda gördüğümüz katman.
Kernel' dan bu kadar az bahsetmemin sebebinin anlaşıldığını umarak ana konunun derinliklerine doğru giriş yapıyorum.

Kernel C (Pure C)
  Kernel modül yazmadan önce Kernel katmanında kullanacağımız Kernel C tanımamız gerekir. Bu sayede yazılan kodları daha kolay ve hızlı kavrayabiliriz. Kernel C dedim, bu sizi yanıltmasın. Hemen telaş edip "Kernel modüle yazmak için yeni bir dil mi öğreneceğim?" sorusunu aklınıza getirmeyin. Kernel C normal kullandığımız C dilidir. Sadece Kernel seviyesinde GNU uzantıları ile kullanılır. Biraz daha açıklayıp sizi rahatlatmak için şöyle söyleyeyim: Kernel C, kullanıcı katmanında kullandığımız kütüphaneleri içermez. Yani C dilini elimizde glibc kütüphaneleri olmadan kullanacağız. (glibc için busiteye ve bu siteye gözatabilirsiniz. glibc bahsetmişken şu sayfaya da göz atın derim.) Peki elimizde o çok sevdiğimiz başlık dosyaları olmadan(stdio.h, stdlib.h, string.h) nasıl kod yazacağız derseniz eğer imdadımıza Kernel seviyesine ait başlık dosyaları yetişir. <kernel_source>/kernel/lib. Ufak bir örnek #include <linux/module.h> İşte Kernel C ile kullandığımız C arasındaki fark bu, başlık dosyaları.
   
    Kernel seviyesinde çalışırken bile en sevdiğimiz dil C kullanmamız işin en güzel yanlarından. Fakat burada nesne dayalı programlama mantığı kullanılmıştır. Biraz C++ bilenler için şu iki kelime constructor ve destructor tanıdık gelecektir. C++ bilmeyenler bu durumu dert etmesine gerek yok. Çünkü bu işleri yine basit bir fonksiyonla yapacağız. Bu kadar yazıdan sonra basit bir modül kodu örneğine bakalım.

Şekil 1 Basit Bir Kernel Modul Kodu

   Gördüğünüz gibi modül constructor ve destructor fonksiyonlarını içerir. mymodule_init modülün constructor fonksiyonu, mymodule_exit modülün destructor fonksiyonudur. C++ bilenler constructor fonksiyonunun obje yaratılırken çağrıldığını bilirler. Fakat burada constructor (kurucu fonksiyon) fonksiyonu -mymodule_init- modül dinamik olarak Kernel yüklenirken çağrılır. Peki destructor fonksiyonu -mymodule_exit- ne zaman  ne zaman çağrılır. Tabi ki de modül Kernel' dan çıkartılırken yani modül sistemden geri alınırken.

Kernel' ın Mesaj Kayıtcısı printk()

   Basit Bir Kernel Modul Kodunda kullanılan constructor ve destructor fonksiyonlarının dışında biraz bu basit modülde ismi geçen printk() fonksiyonundan bahsedelim.  printk(), çok yakından bildiğimiz printf() in Kernel seviyesinde çalışan eşdeğeridir. Tabi kullanımı ve görevi printf()' den biraz farklıdır.

   printk, printf gibi çıktılarını standart output basmaz. Peki printk nereye yazar? Kullanıcı katmanında(user space) çalışan syslog daemon bu mesajları toplar ve son işlem olarak çeşitli cihazlara yönlendirir. Yani kısaca bazı mesajları konsol komutuna yolladığı gibi bazılarını da sadece dosya da saklar. Tüm printk çıktılarını
default olarak /var/log/messages dosyasına basılır. Ayrıca ayarlanarak bazı printk mesajları seri port üzerinden
 konsola(/dev/ttyS0) basılabilir. Örneğin KERN_ERR mesajları konsolda gözlenebilir.



NOT 1: /var/log/messages dosyası normal kullanıcılar için okunabilir biri dosya değildir. Fakat $dmesg komutu ile bu verilere ulaşabilirsiniz

NOT 2: kernel seviyesinde çağrılan tüm printk mesajlarını konsol ekranına basmak için şu komutu koşmanız yeterli:    $dmesg  

NOT 3:dmesg kullanıma yönelik pratik bilgi: $dmesg koştuktan
sonra ekranda bir sürü kernel seviyesinden gelen mesaj göreceksiniz. Bunların içinde kaybolmamak için bir anahtar kelime ile arama yapabilirsiniz. $dmesg | grep my_key_word















printk teknik özelliğinin yanında birazda kullanım biçiminden bahsedelim. Basit Bir Kernel Modul Kodunda kullanımına tekrar bakalım. printk(KERN_INFO "BYE BYE My Module"); İlk göze çarpan KERN_INFO makrosu oluyor. Aslında bu makro sabit bir stringden başka bir şey değil. KERN_INFO kullanımından sonra virgül kullanılmadığına dikkat ediniz. (Arada bir şey kullanılmamış.) Bu durum bize C nin kurallarından biri olan string birleştirmeyi hatırlatması gerekir. 
printf("first text" " second text\n");   [çıktısı: first text second text] 
kodu her ne kadar geçerli ise prink çağrımı da o kadar geçerli ve aynı. Bu açıklamadan sonra printk gizemi gittikçe azalıyor olması lazım. Artık printk ya da bizim printf gibi bir yakınlık duymamız lazım.

Printk sadece KERN_INFO makrosu kullanılmaz. #include<linux/kernel.h> başlık dosyasında printk mesaj durumunu anlatan sekiz adet makro bulunmaktadır.



Yazının devamı olan Adım Adım Linux Driver Yazıyoruz -2- de bu uyku getirici teorik bilgilerden biraz daha uzaklaşıp daha fazla kod göreceğiz. Hatta ilk modülümüzü derleyeceğiz ve cihaza yükleyip çalıştıracağız. Böyle zevkli işler olacak pek yakında. Yazının devamında görüşmek üzere.

Faydalanacağını düşündüğünüz kişilere iletin, eksik ya da yanlış olduğunu düşündüğünüz yerleri belirtin.

Şimdi Yazmaya Devam ....

Hiç yorum yok:

Yorum Gönder

Son Ütücü