Bare Metal Programming-1

Nedir?

Bare Metal, işletim sisteminin ve kullandığınız programlama dilinin bir çok katmanına bağımlı olmayan, donanım ile direkt olarak iletişime geçen bir yazılım tekniğidir.

Resimde de görüldüğü üzere Bare Metal bölümünde HWLibs (Hardware Libraries) katmanı bulunmaktadır. Bu katman, gömülü sistemlerde o donanıma tam erişimi sağlayan kütüphanedir.

HWLibs için örnek verecek olursak;

https://www.arduino.cc/en/Reference/LiquidCrystal

Linkte bulunan LiquidCrystal (LCD) kütüphanesi, Arduino kartlarında LCD'leri instance aracılığıyla kontrol edebilmemizi sağlayan bir HWLib katmanıdır ve direkt olarak Arduino tarafından geliştiricilere sunulmuştur.


Proje

Hızlıca basit bir Rust projesi oluşturalım.

cargo new embedded --bin

CLI komutundan sonra standart Rust proje yapısı oluşturulacaktır.

no_std İşaretçisi

Yazının başında da bahsettiğimiz gibi herhangi bir katmana bağımlı olmayacağını söylemiştik. thread, heap memory, stdout vb. özellikleri kullanabilmemiz için OS katmanına ihtiyacımız var (Bu katmana erişmemizi sağlayan ise std kütüphanesidir). Bu mini projemizde direkt olarak donanım ile etkileşime gireceğimizden ve OS katmanı desteklenmeyeceğinden dolayı Rust'a, Standart Kütüphanesini (std) devre dışı bırakmasını söyleyeceğiz.

// main.rs

#![no_std]

Bu şekilde compile etmeye çalıştığımızda ise;

> cargo build
error: `#[panic_handler]` function required, but not found
error: language item required, but not found: `eh_personality`


eh_personality ve Panic Handler

eh_personality, compiler'a özel fonksiyon ve tipleri tanımlamak için kullanılan terimdir.

std kütüphanesini devre dışı bırakmanız durumunda compiler'a ait error handler da kullanılamaz olacaktır. Panic Handler, Rust compiler tarafından zorunlu tutulmasından dolayı bu handler'ı kendimiz tanımlayacağız.

// in main.rs

use core::panic::PanicInfo;

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}


Panic Info struct'ı, bize hangi file'da ve o file'ın hangi satırında panic olduğu bilgisini getirecektir.


Tekrar compile etmek istediğimzde;

> cargo build
error: requires `start` lang_item


Yine std kütüphanesi içerisinde eh_personality tarafından tanımlanmış olan standart program giriş noktası olmadığından, build aşaması tekrardan başarısız olacaktır.

#![no_std]
#![no_main]

use core::panic::PanicInfo;

#[no_mangle]
pub extern "C" fn _start() -> ! {
    loop {}
}

#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
    loop {}
}


Rust compiler'a, standart giriş noktasını (#![no_main]) ve ismini (#[no_mangle]) kullanmayacağımızı belirttiğimiz işaretçileri kullandık.

Ek olarak; tanımladığımız giriş noktasını ' extern "C" ' ile işaretlememiz gerekmektedir. Bunun sebebi, Rust çağırma kuralı yerine C çağırma kuralını uygulamak istememiz.


Tekrardan compile etmek istediğimizde bir çok Linker hatası ile karşılaşacağız. Bunun sebebi ise Linux, Windows ve macOS arasındaki executable (çalıştırabilir) dosya sistemi farkındandır.  Şuanki build aşamamız default olarak C runtime'ının projemize bağlı olduğunu söylemektedir. Linker'a, C runtime'ın bağımlılığının olmadığını executable dosyasına söylemesini isteyeceğiz.

rustc --version --verbose


Komutunu çalıştırdığımızda bize şuna benzer bir çıktı verecektir;

rustc 1.54.0-nightly (eab201df7 2021-06-09)
binary: rustc
commit-hash: eab201df7028ebb6812c0b1a01702ac6ecfcceed
commit-date: 2021-06-09
host: x86_64-pc-windows-msvc
release: 1.54.0-nightly
LLVM version: 12.0.1

host bölümünde gördüğünüz değer ise 3 kısıma ayrılmaktadır. x86_64 CPU mimarisi, pc bulunduğunuz platform ve windows ise işletim sistemi.

Bu üç tanımlamayı destekleyen ARM altyapılı build targetimizi rustup ile kuralım.

rustup target add thumbv7em-none-eabihf


ve cargo build komutuna target ile eklediğimiz altyapıyı gösterelim.

cargo build --target thumbv7em-none-eabihf


Mutlu son.

Buraya kadar çok basit bir Bare Metal altyapısı oluşturmuş olduk. Sonraki aşamalarımız bulunduğumuz platformdaki donanımlara erişmek olacak.