← Engineering Notes

Engineering Note

Embedded Linux Nedir? Masaüstü Linux ile Temel Farklar ve Mimari Bileşenler

Bir STM32 projesinde çalışma zamanı tamamen sizin elinizdedir: while(1) döngüsü, elle yazılmış bir görev zamanlayıcı ya da FreeRTOS ve USART’ın register haritası. Kart enerji aldığı ilk milisaniyede ne yapıyorsa, onu siz yazmışsınızdır. Gömülü Linux’lu bir SoC kartına geçtiğinizde bu netlik kaybolur: açılışın ilk 500 milisaniyesinde birbirine kontrol devreden beş ayrı yazılım katmanı vardır ve her biri farklı bir kaynaktan, farklı bir derleyiciyle üretilmiştir.

Bu yazının amacı o zinciri zihninizde kurmak: Gömülü Linux’un ne olduğunu (ve ne olmadığını), masaüstü dünyasından hangi varsayımların çöpe gittiğini ve sistemin dört mimari ayağının birbirine nasıl kenetlendiğini netleştirmek.

1. Gömülü Linux Gerçekte Nedir? (Ve Ne Değildir?)

1.1 Dağıtım Değil, Yazılım Yığını

Gömülü Linux, Ubuntu/Fedora/Debian gibi hazır bir dağıtım (distro) değildir. Dağıtımlar binlerce paketi, değişken donanımı ve çalışma zamanında paket kurulumunu yönetecek şekilde tasarlanmış genel amaçlı sistemlerdir. Gömülü tarafta tersini yaparsınız: hedef donanım sabit ve spesifiktir. Kernel yapılandırmasından C kütüphanesine, bootloader’dan init scriptlerine kadar her bileşeni o tek kart için kaynak koddan derlersiniz.

Çıktı, megabaytlarla ölçülen tek parça bir imajdır: sürümü, içeriği, boyutu ve güvenlik yaması stratejisi tamamen sizin kontrolünüzdedir. Bu yığını derleyen fabrika otomasyonları Buildroot veya Yocto, hedef kartın donanımına göre toolchain’i çalıştırır ve çıktı olarak tek bir imaj üretir:

u-boot.bin → bootloader

Image / zImage → Linux çekirdeği

board.dtb → donanım tanım blob'u (Device Tree)

rootfs.ext4 / rootfs.ubifs → kök dosya sistemi

1.2 Neden Tam Olarak Linux?

Kernel seçenekleri bitmiyor: Zephyr, FreeRTOS + TCP/IP yaması, RT-Thread… Bir ürünün Linux’a yönelmesinin somut teknik gerekçeleri şunlar:

  • Sürücü ekosistemi: Mainline kernel’de binlerce hazır sürücü var. SoC üreticileri (NXP, TI, ST, Qualcomm, Rockchip) BSP’lerini ana hatta taşımak için ciddi kaynak harcıyor. Yeni bir Ethernet PHY, Wi-Fi çipi veya USB denetleyicisini entegre etmek bare-metal’de aylar süren bir işken, Linux’ta çoğu zaman “kernel config’i açtım, çalışıyor” ile biter.
  • Ağ protokolü zenginliği: Olgun TCP/IP yığını, VLAN, netfilter (firewall), IPSec/WireGuard, Zeroconf… Router’lar, endüstriyel gateway’ler ve IoT hub’larının çekirdek gereksinimi budur; yeniden yazılmaz.
  • Çoklu işlem + bellek koruması: MMU sayesinde her uygulama kendi izole adres uzayında çalışır. Bir süreç çöktüğünde sistem ayakta kalır. 7/24 çalışan kiosk, HVAC denetleyicisi veya tıbbi cihaz için bu fark kritiktir.
  • Lisans ve maliyet: Kernel GPLv2, telif ücreti yok. Kullanıcı uygulamaları (kernel modülü olmadığı sürece) kapalı kaynak olabilir.
  • Yetenek havuzu: POSIX API’sini bilen her sistem programcısı üründe görev alabilir; platforma özel API öğrenme maliyeti yoktur.

Bu gerekçeler yüzünden otomotiv (IVI, domain controller), savunma sanayii, telekom ekipmanları, endüstriyel gateway’ler, akıllı sayaçlar ve digital signage ürünlerinde aynı yığın koşar. Donanım tarafında da tablo netleşiyor: NXP i.MX, TI Sitara, STM32MP1, Rockchip ve Allwindger SoC’leri bu ekosistemin standart parçalarıdır.

⚠️ Önemli Not — Android nerede? Android de Linux kernel çalıştırır; ancak Bionic libc, kendi init’i ve framework’üyle bambaşka bir yığındır. “Gömülü Linux” denince anılan derleme-zamanı yığın (Yocto/Buildroot) ile AOSP dünyası ayrı uzmanlık alanlarıdır. Kernel ortak, kullanıcı alanı apayrıdır.

2. Masaüstü Linux vs Gömülü Linux: Mimari Farklar

Aynı kernel isminden bahsediyoruz, ama sistem iki dünyada bambaşka yerlerden besleniyor:

KriterMasaüstü Linux (x86_64)Gömülü Linux (ARM / RISC-V)
Donanım keşfiACPI tabloları + PCI/USB çalışma zamanı enumerasyonu (Plug & Play)Device Tree (.dts → .dtb): donanım derleme zamanında statik tanımlanır
Başlatma zinciriReset vector → UEFI (SPI flash) → GRUB → KernelBoot ROM → SPL (SRAM) → Das U-Boot (DDR) → Kernel
Paket yönetimiapt / dnf / pacman: depodan çalışma zamanı kurulumuBuildroot/Yocto ile tüm imaj tek seferde kaynak koddan derlenir; çoğu cihazda paket yöneticisi yoktur
DepolamaSATA/NVMe SSD, yüzlerce GB, blok cihazeMMC, Raw NAND (MTD/UBI), SPI-NOR, SD; 8–64 MB yaygın
Dosya sistemleriext4, XFS, Btrfs (okunur-yazılır)SquashFS (salt-okunur + sıkıştırılmış rootfs), UBIFS/JFFS2, ext4 (veri bölümü)
RAM / boyut4–64 GB RAM, TB’larca disk32–512 MB RAM; tüm sistem çoğu zaman < 100 MB
C kütüphanesiGlibcMusl veya uClibc-ng
Kullanıcı alanısystemd + GNU CoreutilsBusyBox (init + ~300 applet, tek binary) + minimal init scriptleri
Güncelleme stratejisiPaket bazlı, sürekli güncellemeA/B imaj geçişi (RAUC, Mender, SWUpdate), atomik OTA

2.1 Donanım Keşfi: ACPI + PCI vs Device Tree

Masaüstü x86 dünyasında donanım dinamik keşfedilir: UEFI, ACPI tablolarını (DSDT/SSDT) kernel’e sunar; PCI/PCIe veri yolları açılışta enumerate edilir. Kernel çalışma zamanında “şu adreste şu cihaz varmış” diye öğrenir, milyonlarca donanım kombinasyonunu desteklemenin tek yolu budur.

Gömülü SoC’de bu model geçersizdir. Çevre birimler PCIe kart gibi takılıp sökülmez; çip tasarımı sırasında fiziksel adreslere bağlanmış IP bloklarıdır. UART’ın hangi adreste olduğu, hangi kesme hattına bağlı olduğu ve hangi pinlere muxlandığı üretim aşamasında silikona yazılmıştır. Kernel’in “keşfedeceği” bir veri yolu yoktur, bu sabit bilgi bir veri dosyasına yazılır: “Device Tree.”

Kaynağı .dts olan bu dosya, dtc (Device Tree Compiler) ile .dtb binary’sine derlenir ve açılış sırasında kernel’e fiziksel adres olarak verilir. Kernel her düğümdeki compatible string’ini, derlenmiş sürücü tablolarıyla eşleştirir ve eşleşen sürücüyü probe eder.

Bu ayrımın getirisi büyüktür: tek kernel binary + farklı DTB = aynı çekirdek onlarca kartı destekler. Donanım tanımı ile sürücü kodunun ayrıştırılması, gömülü Linux’un en önemli tasarım fikridir. Board’a özel eklemeler overlay (.dtbo) dosyalarıyla yapılır; U-Boot da devretmeden önce DTB’nin /chosen ve /memory düğümlerine boot argümanları ve RAM boyutu gibi bilgileri işleyebilir.

2.2 Depolama: Blok Cihaz Dünyasından MTD’ye

Masaüstünde her disk bir blok cihazdır (/dev/nvme0n1); üzerine ext4 koyarsınız ve biter. Gömülü tarafta depolama medyası, dosya sistemi seçimini doğrudan belirler:

  • eMMC: İçinde NAND flash + bir FTL (flash translation layer) barındıran yönetimli çip. Wear-leveling ve ECC’yi kendi denetleyicisi halleder; sisteme /dev/mmcblkX blok cihazı olarak görünür. ext4 rahatça kullanılır.
  • Raw NAND: Yönetim yoktur. Kötü blok (bad block) yönetimi, ECC hesabı ve wear-leveling’i yazılım yapmak zorundadır. Bunun için Linux’ta MTD alt sistemi + üstünde UBI katmanı ve UBIFS dosya sistemi kullanılır. /dev/mtdX cihazları blok değil, erase-block tabanlı karakter cihazlarıdır.
  • SPI-NOR: 4–64 MB’lık küçük, güvenilir medya. Bootloader ve DTB gibi kritik küçük imajların evi; MTD üzerinden erişilir.
  • SquashFS: Sıkıştırılmış ve salt-okunur. Rootfs’i değiştirilemez kılmak, rastgele yazma bozulmasına ve yarım kalmış güncellemeye karşı doğal bir savunmadır. Üretim desenleri (A/B bölüm + atomik geçiş: RAUC, Mender, SWUpdate) bu yapı üzerine kuruludur.

2.3 Kullanıcı Alanı: Glibc + systemd vs Musl + BusyBox

Masaüstü kullanıcı alanı, GB’larca diskle çalışmayı varsayar: glibc, systemd ve GNU Coreutils birlikte onlarca-yüzlerce MB tutar. Gömülü yığında üç değişim olur:

  • C kütüphanesi: Glibc yerine musl (MIT lisanslı, ~1 MB altı, statik derlemeye çok uygun) veya uClibc-ng kullanılır.
  • Kullanıcı araçları: Tüm temel Unix araçları: ls, cp, mount, ifconfig, sh, hatta init.. tek bir binary’de birleşir: BusyBox. ~300 applet, binary’ye symlink’lerle kişilik kazandırılır: /bin/ls → busybox.
  • init: BusyBox init, /etc/inittab dosyasını okuyup sistem kurar.

3. Gömülü Linux’un Dört Mimari Ayağı

Sistemin tamamı dört parçadan oluşur. Her birinin görevi, tipik temsilcisi ve hedef donanımdaki izi:

AyağGöreviTipik temsilciHedefteki izi
1. ToolchainHost’ta target için kod üretiraarch64-linux-gnu- (GCC/LLVM) + binutils + C kütüphanesiDoğrudan yok; diğer üçünü o üretir
2. BootloaderDonanımı uyandırır, kernel’i yüklerDas U-Boot (+SPL)SPI-NOR/eMMC’nin ilk bölümlerinde (~100 KB SPL + ~500 KB U-Boot)
3. KernelSüreç, bellek, sürücü, ağ yönetimiMainline Linux + kart DTSBoot bölümünde Image/zImage + .dtb
4. Rootfs/ dizini + tüm kullanıcı alanıBusyBox + musl (+ sizin uygulamanız)eMMC/SD’nin veri bölümünde (2–100 MB)

3.1 Toolchain: Hedef Makinede Çalışmayan Derleyici

Sorun basit: Host’unuz x86_64, hedefiniz ARM64 — farklı komut setleri. Derleyici, kendi çalıştıramadığı kodu üretmek zorundadır. Buna çapraz derleme (cross-compilation) denir ve tüm yığının temelidir.

Toolchain üç bileşenden oluşur:

  • binutils: as (assembler), ld (linker), objcopy, readelf, strip — düşük seviyeli ikili üretim araçları.
  • Derleyici: GCC veya Clang front-end’leri.
  • C kütüphanesi: Syscall’ları POSIX API’sine saran katman — printf → write, malloc → mmap/brk. Glibc (tam donanımlı, büyük) veya musl (minimal, statik-dostu) seçilir.

İsimlendirme konvansiyonu (triplet) her şeyi anlatır: aarch64-linux-gnu = aarch64 mimarisi + Linux ABI + glibc. arm-linux-gnueabihf içindeki hf, hard-float ABI’sidir (fonksiyon parametreleri FPU register’larıyla geçilir). Toolchain’in --sysroot‘u, hedefin başlık dosyalarını (headers) ve kütüphanelerini barındırır.

3.2 Bootloader: Das U-Boot

U-Boot’un iş tanımı dört maddedir:

  1. Donanımı uyandırmak: Saat ağacı, PMIC ve DDR denetleyicisi dahil minimum donanımı çalışır hale getirmek.
  2. İmajı yüklemek: Kernel (Image/zImage) ve DTB’yi bir kaynaktan (eMMC, SPI-NOR, SD, USB, TFTP) RAM’e çekmek.
  3. Argümanları işlemek: bootargs (kernel komut satırı) bilgisini DTB’nin /chosen düğümüne yazmak.
  4. Devretmek: Kontrolü kernel’e bırakmak — bir daha geri dönmemek üzere.

3.3 Linux Kernel

Kernel’in sorumluluk dört ana başlıktır:

  • Süreç yönetimi: Zamanlayıcı (scheduler), syscall arayüzü, sinyaller, PID yönetimi.
  • Bellek yönetimi: Page table’lar, fiziksel sayfa tahsisi (SLUB), demand paging, OOM politikası. Gömülüde swap yoktur — bellek biterse OOM killer devreye girer; bu yüzden bellek bütçesi tasarımın bir parçasıdır, tesadüf değil.
  • Sürücüler + Device Tree: DTB’deki düğümlerle compatible eşleşmesi sonucu sürücüler probe edilir; GPIO, I2C, SPI, Ethernet MAC gibi platform cihazları bu sayede hayata geçer.
  • VFS + ağ yığını: root= ile gelen dosya sisteminin mount’u, soket arayüzü, netfilter.

İmaj formatları da pratik bilgi: ARM32’de kendi sıkıştırmasını açan zImage; ARM64’te düz Image; üretimde sık sık kernel + DTB + ramdisk’i tek, imzalanmış pakette birleştiren FIT image (secure boot zincirinin parçası).

3.4 Root Filesystem (Rootfs)

Kernel açılışın sonunda root= parametresindeki dosya sistemini / olarak mount eder ve ilk kullanıcı alanı sürecini başlatır: /sbin/init (PID 1). Bu dosya yoksa kernel anında panic verir: “No working init found.” PID 1, tüm proseslerin atasıdır; yetimleri toplar, açılış scriptlerini çalıştırır ve kapanışı yönetir.

Rootfs’i kim derler? İki ana fabrika:

BuildrootYocto / OpenEmbedded
Modelmake menuconfig → kaynak indirir → toolchain + kernel + rootfs’i tek seferde derlerBitBake + recipe’ler; katman (layer) mimarisi
ÇıktızImage + rootfs.ext4 + u-boot.bin + dtbİmaj + RPM/IPK paket beslemesi + SDK
Öğrenme eğrisiDüşük, hızlı ilk sonuçDik, ciddi yatırımla geri döner
Uygun olduğuTek ürün, sade cihazlar, hızlı prototipÇok ürünlü portföy, uzun yaşam döngüsü, lisans/sertifikasyon yükümlülükleri

3.5 Handoff

Dört ayağın birbirine kenetlendiği üç kritik arayüz vardır — sistem tam olarak bu sözleşmeler üzerinde durur:

  1. Toolchain → (U-Boot, Kernel, Rootfs): Tek ABI, tek C kütüphanesi. Yığın homojen derlenmezse çalışmaz.
  2. U-Boot → Kernel: Register sözleşmesi (x0 = DTB fiziksel adresi, ARM64) + bootargs‘ın /chosen düğümüne işlenmesi.
  3. Kernel → Rootfs: root= parametresiyle mount, ardından /sbin/init‘in PID 1 olarak çalıştırılması.

Bir sonraki bölümde bu devir teslimlerin zamansal sırasını göreceğiz.

4. Donanımın Açılış Akışı: Power-On’dan Kullanıcı Uygulamasına

                     Güç Uygulaması / Reset
                                │
                                ▼
  ┌─────────────────────────────────────────────────────┐
  │  1. BOOT ROM            [SoC mask ROM — değiştirilemez]
  │     • Boot mod pinleri / eFuse okunur               │
  │     • Geçerli imaj SD / eMMC / SPI-NOR / USB        │
  │       kaynaklarından aranır                         │
  │     • İlk stage yazılımı → Internal SRAM'e yüklenir │
  └──────────────────────────┬──────────────────────────┘
                             │  kontrol devri
                             ▼
  ┌─────────────────────────────────────────────────────┐
  │  2. SPL / TF-A          [Internal SRAM, ~128–512 KB]
  │     • Saat (clock) ve PMIC yapılandırması           │
  │     • DDR denetleyicisi init + training             │
  │     • Ana Bootloader'ı (U-Boot) DDR'ye yükler       │
  └──────────────────────────┬──────────────────────────┘
                             ▼
  ┌─────────────────────────────────────────────────────┐
  │  3. U-Boot (proper)     [DDR RAM]                   │
  │     • Ortam değişkenleri (env), storage/net sürücü- │
  │       leri, komut kabuğu                            │
  │     • Kernel Image + DTB'yi belleğe yükler          │
  │     • booti/bootz: kontrolü kernel'e devreder       │
  │       (ARM64: x0 = DTB fiziksel adresi)             │
  └──────────────────────────┬──────────────────────────┘
                             ▼
  ┌─────────────────────────────────────────────────────┐
  │  4. LINUX KERNEL        [DDR RAM]                   │
  │     • MMU açılır, page table'lar kurulur            │
  │     • Device Tree ayrıştırılır, sürücüler probe     │
  │     • root= ile Rootfs mount edilir                 │
  │     • /sbin/init (PID 1) çalıştırılır               │
  └──────────────────────────┬──────────────────────────┘
                             ▼
  ┌─────────────────────────────────────────────────────┐
  │  5. ROOTFS / init       [eMMC / SD / NFS]           │
  │     • inittab → init scriptleri / systemd           │
  │     • Servisler, ağ, mount'lar                      │
  └──────────────────────────┬──────────────────────────┘
                             ▼
                    Kullanıcı Uygulaması

Neden Üç Aşamalı Bootloader?

Bu merdivenin var olma sebebi, gömülü sistemlerin klasik tavuk-yumurta problemidir:

  • Reset anında kullanıma hazır tek bellek, SoC’nin iç SRAM’idir — ancak boyutu 128–512 KB ile sınırlıdır.
  • DDR RAM büyüktür, ama denetleyicisi (saat, zamanlama parametreleri, training) yazılım tarafından önce yapılandırılmalıdır. Kod henüz DDR’de yokken, DDR init eden kodun nerede çalışacağı sorusunun cevabı: SRAM’de, yani küçük bir ilk aşama — SPL.
  • Boot ROM yalnızca sınırlı boyutta imajı SRAM’e yükleyebilir; bu yüzden zincir kırılma noktalarında küçük adımlarla büyür.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir