Rustでcoreboot payload

この記事は自作OS Advent Calendar の19日目の記事として書かれた. ここでは,corebootのpayloadをRustを使って作ってみる. corebootファームウェアなのでOSとは異なるが,そこはご愛嬌ということで.

corebootについて

corebootとは既存のプロプライエタリBIOSを置き換えるBIOSと そのプロジェクトのことである. corebootは大きくcoreboot本体とPayloadの2つがあり, Payloadには様々なソフトウェアを載せることができる. 今回はPayloadをRustで作ってみようということである. ここでは,Libpayloadと呼ばれるPayload向けのライブラリの関数を Rustから呼び出してみる.

Rustでのベアメタルプログラミング

Rustでのベアメタルプログラミングについてはκeenさんの記事 が詳しい.ほとんどここを参考にした.

ホストの環境はx86_64であるとする. 最初にcargo new --bin cb-ffiとかやって新規のCargoプロジェクトを作成する.

次に以下のような内容でmain.rsを書く.

#![feature(lang_items, asm)]
#![crate_type = "staticlib"]
#![no_std]

#[link(name = "libpayload", kind = "static")]
extern {
    fn putchar(c: u32);
}

#[no_mangle]
pub extern fn main() {
    loop{
        unsafe { putchar(65) };
    }   
}

#[lang = "eh_personality"]
extern fn eh_personality() {}

#[lang = "panic_fmt"]
extern fn panic_fmt() {}

ほとんど上記の記事と同じであるが,

#[link(name = "libpayload", kind = "static")]
extern {
    fn putchar(c: u32);
}

でlibpayloadのputcharの参照を定義しており,

#[no_mangle]
pub extern fn main() {
    loop{
        unsafe { putchar(65) };
    }   
}

上記のputcharを呼び出していることがわかる.

次に

rustc --target i686-unknown-linux-gnu --emit=obj main.rs

とかやってmain.oを作成する.

最後に,あらかじめ作成しておいたlibpayload.aとリンクする. ここでは,Libpayloadのlpgccを用いる.Libpayloadについては ここを参照のこと.

~/src/coreboot/payloads/libpayload/bin/lpgcc main.o libpayload.a

できたa.outcorebootのPayloadに指定すればできあがり.

以上,ファームウェアといいつつも, ただのベアメタルプログラミングであることがわかる. しかも一切アセンブリに触れずにできていることからも簡単であると言える. なお,以上の内容をリポジトリにまとめた.

参考文献