Koray ÜSTÜNDAĞ

KORAY ÜSTÜNDAĞ

C ile Sıfırdan 32-Bit Kernel Yazma

Merhaba, Bu yazıda C Programlama dilinde sıfırdan 32-Bit(x86) kernel yazacağız. Bir işletim sisteminin çekirdeğini yazmak zor bir işlemdir. Çünkü tüm sürücüleri ve donanımları siz yöneteceksiniz. Bu kerneli linux işletim sisteminde derleyeceğiz. Windows kullanıcıları WSL2 kullanabilirler. Fakat ben bu yazıda sanki yeni bir makina kurulmuş gibi davranacağım. Yani tüm programları ve kütüphaneleri birlikte kuracağız. Şimdi yavaştan geliştirme ortamımızı hazırlamaya başlayabiliriz. Ben işletim sistemi olarak Ubuntu kullanacağım. Sizde tavsiye ederim, ama zorunda değilsiniz. Şimdi başlayalım.

İhtiyacımız Olanlar:

  • Linux İşletim Sistemi (Tercihen Ubuntu) yada WSL2
  • GCC
  • i686-elf-tools
  • Make
  • Bison
  • Flex
  • GMP
  • MPC
  • MPFR
  • Textinfo
  • unzip

Şimdi Ubuntu’yu sıfırdan kurduğunuzu varsayıyorum ve geliştirme araçlarını kurmaya başlayabiliriz.

Aşağıdaki araçları tek tek kuralım:

				
					sudo apt install build-essential
sudo apt install bison
sudo apt install flex
sudo apt install libgmp3-dev
sudo apt install libmpc-dev
sudo apt install libmpfr-dev
sudo apt install texinfo
sudo apt install xorriso
sudo apt install unzip
				
			

Kurulumlar bittikten sonra doğrulama yapalım:

				
					gcc --version
g++ --version

# Eğer GCC ve G++ bulunamadı hatası verirse manuel kurulum yapacaksınız:
sudo apt install gcc
sudo apt install g++
				
			

Şimdi ise i686-elf-tools kurulumu yapacağız. Hali hazırda i686-elf-tools binary dosyaları yok. Elinizde iki seçenek var. Ya sıfırdan kendiniz derleyeceksiniz yada benim derlediğim i686-elf-tools binary lerini kullanacaksınız. Seçim size kalmış. Şunu söylemek istiyorum. Derleme işlemi baya uzun sürüyor bilginize. Kendiniz derlemek isterseniz internette bu konuyu araştırabilirsiniz. Benim derlediğim i686-elf-tools setini indirmek için >> Buraya << tıklayarak indirebilirsiniz. Yada wget ile çekebilirsiniz.

Surasıyla aşağıdaki komutları çalıştıralım.

				
					mkdir $HOME/elf-tools
cd $HOME/elf-tools
wget https://www.korayustundag.com/static_files/i686-elf-tools-linux.zip
unzip i686-elf-tools-linux.zip
				
			

Şimdi ise elf tool setini PATH‘e ekleyelim.

				
					export PATH="$HOME/elf-tools/bin:$PATH"
				
			

Şimdi ise versiyon kontrolü yapalım:

				
					cd $HOME
i686-elf-as --version
				
			

Versiyon bilgisini veriyorsa herşey hazır demektir. Artık kodlamaya geçebiliriz.

Bootloader

Şimdi ben tüm kodları konsol üzerinden nano ile yazacağım. Siz isterseniz VSCode, Vim veya KDevelop gibi araçlar kullanarak yazabilirsiniz. Şimdi Klasörlerimizi oluşturalım.

				
					mkdir -p $HOME/dev/src
cd $HOME/dev/src
				
			

Şimdi bootloader dosyamızı oluşturalım ve yazmaya başlayalım. Dosyanın adını “boot.s” yapıyoruz ve içine ağaıdaki kodları yazıyoruz:

				
					.set ALIGN,    1<<0
.set MEMINFO,  1<<1
.set FLAGS,    ALIGN | MEMINFO
.set MAGIC,    0x1BADB002
.set CHECKSUM, -(MAGIC + FLAGS)

.section .multiboot
.align 4
.long MAGIC
.long FLAGS
.long CHECKSUM
.section .bss
.align 16
stack_bottom:
.skip 16384
stack_top:
.section .text
.global _start
.type _start, @function
_start:
	mov $stack_top, %esp
	call kernel_main
	cli
1:	hlt
	jmp 1b
.size _start, . - _start


				
			

Şimdi ise boot dosyamızı derleyelim.

				
					i686-elf-as boot.s -o boot.o
				
			

Kernel

Şimdi ise kernel yazmaya başlayabiliriz. “kernel.c” dosyamızı oluşturalım ve yazmaya başlayalım.

				
					#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>

/* Derleyicinin yanlış işletim sistemini hedeflediğinizi düşünüp düşünmediğini kontrol edin. */
#if defined(__linux__)
#error "Bir çapraz derleyici(cross-compiler) kullanmıyorsunuz."
#endif

/* Bu kernel yalnızca 32-bit ix86 hedefleri için çalışacaktır. */
#if !defined(__i386__)
#error "Bu çekirdeğin bir ix86-elf derleyicisi ile derlenmesi gerekiyor."
#endif

/* Donanım metin modu renk sabitleri. */
enum vga_color {
	VGA_COLOR_BLACK = 0,
	VGA_COLOR_BLUE = 1,
	VGA_COLOR_GREEN = 2,
	VGA_COLOR_CYAN = 3,
	VGA_COLOR_RED = 4,
	VGA_COLOR_MAGENTA = 5,
	VGA_COLOR_BROWN = 6,
	VGA_COLOR_LIGHT_GREY = 7,
	VGA_COLOR_DARK_GREY = 8,
	VGA_COLOR_LIGHT_BLUE = 9,
	VGA_COLOR_LIGHT_GREEN = 10,
	VGA_COLOR_LIGHT_CYAN = 11,
	VGA_COLOR_LIGHT_RED = 12,
	VGA_COLOR_LIGHT_MAGENTA = 13,
	VGA_COLOR_LIGHT_BROWN = 14,
	VGA_COLOR_WHITE = 15,
};

static inline uint8_t vga_entry_color(enum vga_color fg, enum vga_color bg)
{
	return fg | bg << 4;
}

static inline uint16_t vga_entry(unsigned char uc, uint8_t color)
{
	return (uint16_t) uc | (uint16_t) color << 8;
}

size_t strlen(const char* str)
{
	size_t len = 0;
	while (str[len])
		len++;
	return len;
}

static const size_t VGA_WIDTH = 80;
static const size_t VGA_HEIGHT = 25;

size_t terminal_row;
size_t terminal_column;
uint8_t terminal_color;
uint16_t* terminal_buffer;

void terminal_initialize(void)
{
	terminal_row = 0;
	terminal_column = 0;
	terminal_color = vga_entry_color(VGA_COLOR_LIGHT_GREY, VGA_COLOR_BLACK);
	terminal_buffer = (uint16_t*) 0xB8000;
	for (size_t y = 0; y < VGA_HEIGHT; y++) {
		for (size_t x = 0; x < VGA_WIDTH; x++) {
			const size_t index = y * VGA_WIDTH + x;
			terminal_buffer[index] = vga_entry(' ', terminal_color);
		}
	}
}

void terminal_setcolor(uint8_t color)
{
	terminal_color = color;
}

void terminal_putentryat(char c, uint8_t color, size_t x, size_t y)
{
	const size_t index = y * VGA_WIDTH + x;
	terminal_buffer[index] = vga_entry(c, color);
}

void terminal_putchar(char c)
{
	/* Yeni satırı kontol et */
    if (c == '\n') {
        terminal_column = 0;
        if (++terminal_row == VGA_HEIGHT)
            terminal_row = 0;
    } else {
        terminal_putentryat(c, terminal_color, terminal_column, terminal_row);
        if (++terminal_column == VGA_WIDTH) {
            terminal_column = 0;
            if (++terminal_row == VGA_HEIGHT)
                terminal_row = 0;
        }
    }
}

void terminal_write(const char* data, size_t size)
{
	for (size_t i = 0; i < size; i++)
		terminal_putchar(data[i]);
}

void terminal_writestring(const char* data)
{
	terminal_write(data, strlen(data));
}

void kernel_main(void)
{
	/* Terminal arayüzünü başlat */
	terminal_initialize();

	terminal_writestring("KoraX Kernel'e Hos Geldiniz.\n");
	terminal_writestring("Sistem Hazir!");
}

				
			

Şimdi ise Kerneli derleyelim.

				
					i686-elf-gcc -c kernel.c -o kernel.o -std=gnu99 -ffreestanding -O2 -Wall -Wextra
				
			

Linker

Şimdi ise boot ile kerneli birbirine bağlamamız lazım. Bunun için linker yazmamız gerekiyor. “linker.ld” dosyamızı oluşturuyoruz.

				
					ENTRY(_start)
SECTIONS
{
	. = 1M;

	.text BLOCK(4K) : ALIGN(4K)
	{
		*(.multiboot)
		*(.text)
	}
	
	.rodata BLOCK(4K) : ALIGN(4K)
	{
		*(.rodata)
	}
	
	.data BLOCK(4K) : ALIGN(4K)
	{
		*(.data)
	}
	
	.bss BLOCK(4K) : ALIGN(4K)
	{
		*(COMMON)
		*(.bss)
	}
}
				
			

Şimdi ise kerneli ve boot dosyasını linkleyelim.

				
					i686-elf-gcc -T linker.ld -o kernel.bin -ffreestanding -O2 -nostdlib boot.o kernel.o -lgcc
				
			

Tebrikler. Kernel dosyamız(kernel.bin) hazır. Şimdi isterseniz qemu ile direkt çalıştırabilir veya iso dosyası hazırlayabilirsiniz. İsterseniz iso dosyamızı hazırlayalım.

İlk önce grub.cfg dosyamızı oluşturalım.

				
					menuentry "myos" {
	multiboot /boot/kernel.bin
}
				
			

Ardınan iso dosyası için gerekli klasörleri oluşturup, son olarak iso dosyamızı oluşturalım.

				
					mkdir -p isodir/boot/grub
cp kernel.bin isodir/boot/kernel.bin
cp grub.cfg isodir/boot/grub/grub.cfg
grub-mkrescue -o myos.iso isodir
				
			

Artık iso dosyamız(myos.iso) hazır. Tek yapmamız gereken qemu ile çalıştırmak.

				
					qemu-system-i386 -cdrom myos.iso
# Veya #
qemu-system-i386 -kernel kernel.bin
				
			

Hayırlı uğurlu olsun. Yerli ve milli 😂 kernelimiz hazır. Gerisi sizin programlama bilginize kalmış.

Umarım yardımcı olmuşumdur.

Kolay gelsin.

Şimdi Paylaş

Facebook
Twitter
LinkedIn

4 Responses

  1. Ya bu yazıyı yazmışsın. Eline sağlık. Fakat ben bu lanet wsl2 de ya da windows 10 üzerindeki hiç bir programda kernel ve c dosyalarını derleyemedim. olmuyor sürekli hata. hataları araştırdığımda ise sonuç sıfır. ya hata sana uymuyor ya da çözümü yok. Şu yazıyı böyle üstün körü geçeceğine adam akıllı bir yazı serisi yayınlasan olmaz mıydı? Wsl üstünde işlemleri nasıl yapacağız neler yükleyeceğiz. Adım adım video olur resimli olur. Tek tek anlatsan çok güzel olurdu. En başında daha hata alıyorum. Günlerdir yazı okumaktan video izlemekten bıktım. Sorun sürekli hata ve sorun. Ana hatlarıyla başlıkla yazıp geçmişsin. Milyonlar işletim sistemi yazmak istemiyor sonuçta. Kaynak çok az ve yabancı anlaşılmıyor. Hiç birisinde ayrıntı yok. Linuxta derleyin gcc ile diyor. Ama nasıl yapılacak o yok. Windows zaten yok. nasm var bilmem ne var. eee yapımı yok. Yardımcı olmak istersen. Yorum altına iletişim için mailini bırak oradan ulaşayım.

    1. Dostum, Haklısın. Çok az kaynak var. Zaten benim yaptığım sadece bir örnek. Alıp üstüne koyup ilerleyebilirsin. Kernel yazmak zaten zor bir iştir. Çok ileri düzeyde C ve Assembly bilmen gerekiyor. İngilizcenin iyi olması gerekiyor(en azından okuduğunu anlama). Çünkü compiler sana hatanın sebebini zaten söylüyor. Ek olarak Windows altında sistem yazmak zaten zordur. Çünkü sistem compiler’ı yok. Yazanlarda internal kullanıyorlar. Dışarıya paylaşmıyor. Bu yüzden açık kaynak derleyicilere ihtiyacın var. Açık kaynak denilince Linux. Bu derleyiciler linux ortamında yazılıp derleniyor. Bu yüzden windows üzerinde hata alman normal. Sana tavsiyem; önce C öğren ardından Assembly öğrenmen. Daha sonra Compiler nasıl çalışır bunu öğrenmen. Amazon’da compiler kitapları bulabilirsin. Fakat ingilizce. Uzun lafın kısası C/Assembly uzmanı olman gerekiyor. Sonuçta kendi kernelin için kendi “stdio.h” kütüphaneni yazman gerekecek.

  2. Başlığı görünce inanamadım. Gerçektende Türkçe bir kaynak bulmak beni sevindirdi.
    Öncelikle söylemem gerekiyor, gerçekten çok zor bir iş başarmışsın. Söylediklerini adım adım uyguladım. Sonunda ekrana SudeOS yazan bir kernele sahip oldum. Bir şeyi merak ediyorum. Bu kerneli nasıl geliştirebilirim?

    1. Merhaba,
      İlk önce yapman gereken, kendi işini kolaylaştırmak. Mesela kendi “stdio.h” kütüphaneni yazmayla başlayabilirsin.
      Kendi işini ne kadar kolaylaştırırsan o kadar rahat edersin. Daha sonrasında ACPI apisi yazarak devam edebilirsin.

Bir cevap yazın

E-posta hesabınız yayımlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir