Blog'a dön

Sıfırdan İşletim Sistemi Geliştirme

Sıfırdan işletim sistemi inşa etmek, yazılım mühendisliğindeki en zorlu ama ödüllendirici deneyimlerden biridir. Sizi bilgisayarların en düşük seviyede gerçekten nasıl çalıştığını anlamaya zorlar.

Neden Bir İşletim Sistemi İnşa Etmeli?

prometheus-os üzerinde çalışmaya başladığımda, amacım bir sonraki Linux’u yaratmak değildi. Her geliştiricinin doğal kabul ettiği temel kavramları anlamaktı:

  • CPU talimatları nasıl çalıştırır?
  • Bellek ayırdığınızda ne olur?
  • Kesintiler (interrupt) nasıl çalışır?
  • Çoklu görevi (multitasking) mümkün kılan nedir?

Bu sorular beni assembly dili, donanım spesifikasyonları ve sistem programlamanın tavşan deliğine götürdü ve yazılım hakkında düşünme şeklimi temelden değiştirdi.

Önyükleme Süreci

Her şey bootloader ile başlar. Bir bilgisayarı açtığınızda, BIOS/UEFI diskinizin ilk sektörünü belleğe yükler ve ona atlar. Bu 512 baytlık bootloader giriş noktanızdır:

; bootloader.asm - Birinci aşama bootloader
[BITS 16]
[ORG 0x7C00]

start:
    ; Segment register'larını ayarla
    xor ax, ax
    mov ds, ax
    mov es, ax
    mov ss, ax
    mov sp, 0x7C00

    ; Diskten kernel'ı yükle
    mov ah, 0x02        ; BIOS sektör okuma fonksiyonu
    mov al, 10          ; Okunacak sektör sayısı
    mov ch, 0           ; Silindir 0
    mov cl, 2           ; Sektör 2'den başla
    mov dh, 0           ; Kafa 0
    mov bx, 0x1000      ; Yükleme adresi
    int 0x13            ; BIOS kesmesi

    ; Kernel'a atla
    jmp 0x1000

times 510-($-$$) db 0
dw 0xAA55               ; Önyükleme imzası

Bu küçük kod parçası tüm kernel’ınızı belleğe yüklemekten sorumludur.

Bellek Yönetimi

Herhangi bir işletim sisteminin en kritik bileşenlerinden biri bellek yönetimidir. Hangi bellek sayfalarının kullanımda olduğunu takip etmeniz ve işlemlere ayırma/serbest bırakma hizmetleri sağlamanız gerekir.

class PhysicalMemoryManager {
private:
    uint32_t* bitmap;
    uint32_t totalPages;
    uint32_t usedPages;

public:
    void* allocatePage() {
        for (uint32_t i = 0; i < totalPages; i++) {
            if (!testBit(i)) {
                setBit(i);
                usedPages++;
                return (void*)(i * PAGE_SIZE);
            }
        }
        return nullptr; // Bellek dolu
    }

    void freePage(void* address) {
        uint32_t page = (uint32_t)address / PAGE_SIZE;
        clearBit(page);
        usedPages--;
    }
};

Bitmap yaklaşımı eğitim amaçları için basit ama etkilidir. Prodüksiyon sistemleri buddy allocation gibi daha sofistike algoritmalar kullanır.

Kesinti İşleme

Kesintiler, CPU’nun harici olaylara (klavye girişi, zamanlayıcı tikleri) ve dahili istisnalara (sıfıra bölme, sayfa hatası) nasıl yanıt verdiğidir. Interrupt Descriptor Table (IDT) kurmak çok önemlidir:

struct IDTEntry {
    uint16_t offsetLow;
    uint16_t selector;
    uint8_t  zero;
    uint8_t  typeAttr;
    uint16_t offsetHigh;
} __attribute__((packed));

void setupIDT() {
    // İstisna işleyicilerini ayarla (0-31)
    setIDTEntry(0, (uint32_t)divisionByZeroHandler, 0x08, 0x8E);
    setIDTEntry(14, (uint32_t)pageFaultHandler, 0x08, 0x8E);

    // IRQ işleyicilerini ayarla (32-47)
    setIDTEntry(32, (uint32_t)timerHandler, 0x08, 0x8E);
    setIDTEntry(33, (uint32_t)keyboardHandler, 0x08, 0x8E);

    // IDT'yi yükle
    loadIDT(&idtDescriptor);
}

Öğrenilen Dersler

prometheus-os inşa etmek bana paha biçilmez dersler öğretti:

  1. Her soyutlamanın bir maliyeti var: Yüksek seviye diller karmaşıklığı gizler, ama o karmaşıklık hala var. Bunu anlamak sizi daha iyi bir programcı yapar.

  2. Donanım affetmez: Uygulama geliştirmesinin aksine, işletim sistemi geliştirmesinin güvenlik ağı yok. Tek bir hata tüm sistemi dondurabilir.

  3. Dokümantasyon şart: Intel kılavuzları, OSDev wiki ve diğer kaynaklar can simidinizdır. Bunları baştan sona okuyun.

  4. Basit başlayın: Ekrana metin yazdırmayla başlayın. Sonra klavye girişi ekleyin. Sonra bellek yönetimi. Artımlı olarak inşa edin.

Başlamak İçin Kaynaklar

Bu yolculuğa çıkmak istiyorsanız:

  • OSDev Wiki: İşletim sistemi geliştirme için kesin kaynak
  • Intel Yazılım Geliştirici Kılavuzları: x86 mimarisi için şart
  • “Operating Systems: Three Easy Pieces”: Mükemmel teorik temel
  • QEMU: Gerçek donanımı sürekli yeniden başlatmadan test için

Sonuç

Bir işletim sistemi inşa etmek sizi web uygulamaları yazarken daha hızlı yapmayacak. Ancak üzerine inşa ettiğimiz soyutlama katmanları için derin bir takdir kazandıracak. Kodunuz ile CPU arasında ne olduğunu anladığınızda, daha düşünceli, daha etkili bir mühendis olursunuz.

Bir dahaki sefere uygulamanızda bellek ayırdığınızda veya bir kesinti işlediğinizde, yüzeyin altında tam olarak ne olduğunu bileceksiniz.