Hobi Kernel: Giriş ve Ekrana Yazdırma

Bir süredir boş vakitlerimi değerlendirmek için kernel üzerine okuduğum makaleleri gerçeklemeye sonunda fırsat buldum ve bu sırada elde ettiğim birikimleri bu makale dizisinde paylaşacağım. Bu ilk yazıda ekrana karakter ve karakter dizisi yazdıran bir kernel elde edeceğiz. Daha sonraki yazılarda port okuma, porta yazma, interrupt, IDT, klavye sürücüsü, bellek yönetimi ve dinamik allokasyon(malloc) gibi konulara değinmeye çalışacağım.

Gereksinimler

  • Nasm
  • gcc
  • ld(Linux linker)
  • qemu-system-i386

Bu 32 bit kerneli Linux ortamında gerçekliyorum.

Kernel Entry Point Oluşturma

Proje klasörümüzün içinde entry_point.asm, kernel.c ve link.ld isminde üç dosya oluşturalım.

ASM dosyasını aşama aşama takip edelim.

İlk olarak NASM için 32 bit seçiyoruz. Sonrasında bir section oluşturuyoruz. Genelde kullanılan üç çeşit section ve amaçları aşağıdaki gibidir:

  • text: Kodun kendisi için
  • data: Deklare edilmiş ve tanımlanmış değişkenler için
  • bss: Deklare edilmiş ve tanımlanmamış değişkenler için

Sonrasındaki 5 satır bootloader sistemin kernelimizi yüklemesi için gerekli. Bunun ardında global anahtar kelimesini(keyword) kodda start ile isimlendirdiğimiz kısmı dışarıdan kullanılabilir hale getirmesi(expose) için kullanıyoruz. Bu sayede kernelimizin nerden başladığını belirtmiş olduk.

Start içinde ilk olarak interrupt sistemini devre dışı bırakıyoruz(Interrupt sistemine ilerde değineceğiz). Sonrasında da bss kısmında deklare ettiğimiz stack_space adresini esp(Extended Stack Pointer) “register”ının içine atıyoruz. Stack veri yapısı fonksiyon çağrılarının yapılabilmesine olanak sağlayan sistem olduğu için burada oluşturulması gerekiyor. Sonrasında ilk fonksiyon çağrımız olan kmain(kernel main) fonksiyonunu çağırıyoruz. Sistem kernel main fonksiyonundan döndüğünde hlt(Halt) komutu ile bilgisayarı kapatıyoruz. Böylece kodun text bölümü bitmiş oluyor.

bss kısmında ise sadece yukarıda kullanacağımız stack yapısı için resb(reserve byte) kullanarak 8 kilobaytlık bir alan ayırdık. Burada stack ve fonksiyon çağrısı kısmı için yazının sonunda opsiyonel bir açıklama kısmı yazdım. Daha ayrıntılı bilgilendirme için oraya başvurabilirsiniz.

C dosyası ASM kısmına nazaran daha basit. Burada x86 sistemleri için video belleğin giriş adresine işaret eden bir pointer oluşturarak o bellek alanını kodun içinde dolduruyoruz.

Bu iki dosyayı ve ileride oluşturacağımız dosyaları linux linker(ld) ile bağlamak için aşağıdaki dosyayı oluşturmamız gerekiyor.

Bunları tek bir komutla halletmek için bir shell script yazalım:

Çıktı

Stack Yapısı, ESP ve Fonksiyon Çağrıları(Opsiyonel)

Stack(yığın) yapısını üst üste koyulmuş eşyalar gibi düşünebilirsiniz alttakilere erişmek için önce üsttekileri çıkarmanız lazım. ESP x86 tabanlı mimarilerde bu stack yapısının en üstüne işaret eder. Bellekteki stack yapısının adresinin sistem başlangıcında ESP içine yazılması gerekmektedir. Fonksiyon çağrıları yapılırken Stack yapısının kullanılmasının sebebi girişte bahsettiğimiz karakteristiğinden dolayıdır. Fonksiyon çağrısı yapıldığında yığına eleman eklenir. Return işlemi gerçekleşince yığından eleman çekilir. Böylece fonksiyon bir fonksiyondan döndüğümüzde önceki fonksiyonda kaldığımız yerden devam edebiliriz.

Bir sonraki yazıda görüşmek üzere.