大仰なタイトルにしてしまいましたが、
http://wiki.osdev.org/Raspberry_Pi_Bare_Bones
ここの内容の一部をRustに置き換えてみようというだけの記事です。
qemuを使うので実機がなくても大丈夫です。
開発環境はDebian testing(stretch)です。
準備
qemuインストール
$ sudo aptitude install qemu-system-arm
ツールチェインインストール
Debianにはgcc-arm-none-eabiパッケージが存在しているのでインストールするだけです。
$ sudo aptitude install build-essential gcc-arm-none-eabi
Rustインストール
rustupを使います。
$ curl https://sh.rustup.rs -sSf | sh
$ source $HOME/.cargo/env
ビルドにはnightlyが必要です。
$ rustup default nightly
ターゲットにarm-none-eabiが無いので、替わりにarm-unknown-linux-gnueabiを使用します
$ rustup target add arm-unknown-linux-gnueabi
似たターゲット名にarm-unknown-linux-gnueabihfがありますが、こちらを使うとビルドエラーが出るので注意です。1
まずはRust抜きで
http://wiki.osdev.org/Raspberry_Pi_Bare_Bones
ここの内容通りに進めていくだけです。
いちいちコマンド打たなくて良いようにMakefileを作りましょう。
#!/usr/bin/make
CC = arm-none-eabi-gcc
CFLAGS = -mcpu=arm1176jzf-s -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra
ASM_FLAGS = -mcpu=arm1176jzf-s -fpic -ffreestanding
OBJ = boot.o kernel.o
kernel.elf: ${OBJ}
${CC} -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ}
boot.o: boot.S
${CC} ${ASM_FLAGS} -c $< -o $@
kernel.o: kernel.c
${CC} ${CFLAGS} -c $< -o $@
clean:
rm -f *.o *.elf
.PHONY: clean
ビルドしてqemuで実行してみます。
$ make
$ qemu-system-arm -m 256 -M raspi2 -serial mon:stdio -kernel kernel.elf
Hello, kernel World!
kernel_main()
をRustにしてみる
いよいよRustを使ってみます。
#![feature(lang_items)]
#![crate_type = "staticlib"]
#![no_std]
extern {
fn uart_init();
fn uart_puts(data: &'static str);
}
#[no_mangle]
pub extern fn kernel_main() {
unsafe {uart_init();}
unsafe {uart_puts("Hello, kernel World!\r\n");}
loop{}
}
#[lang = "eh_personality"]
extern fn eh_personality() {}
#[lang = "panic_fmt"]
extern fn panic_fmt() -> ! { loop {} }
#[no_mangle]
pub extern fn __aeabi_unwind_cpp_pr0 () {}
stdlibは使わない(使えない)ため#[no_std]
で無効にします
使用するCの関数はextern
で宣言します
kernel_main()
は外部から呼び出せるようにpub
と#[no_mangle]
を付けます
kernel.cとMakefileを修正します。
@@ -112,19 +112,3 @@ unsigned char uart_getc() {
void uart_puts(const char* str) {
for (size_t i = 0; str[i] != '\0'; i++) uart_putc((unsigned char)str[i]);
}
-
-#if defined(__cplusplus)
-extern "C" /* Use C linkage for kernel_main. */
-#endif
- void
- kernel_main(uint32_t r0, uint32_t r1, uint32_t atags) {
- // Declare as unused
- (void)r0;
- (void)r1;
- (void)atags;
-
- uart_init();
- uart_puts("Hello, kernel World!\r\n");
-
- while (1) uart_putc(uart_getc());
-}
@@ -3,7 +3,7 @@
CC = arm-none-eabi-gcc
CFLAGS = -mcpu=arm1176jzf-s -fpic -ffreestanding -std=gnu99 -O2 -Wall -Wextra
ASM_FLAGS = -mcpu=arm1176jzf-s -fpic -ffreestanding
-OBJ = boot.o kernel.o
+OBJ = boot.o kernel.o main.o
kernel.elf: ${OBJ}
${CC} -T linker.ld -o $@ -ffreestanding -O2 -nostdlib ${OBJ}
@@ -14,6 +14,9 @@ boot.o: boot.S
kernel.o: kernel.c
${CC} ${CFLAGS} -c $< -o $@
+main.o : main.rs
+ rustc --target arm-unknown-linux-gnueabi --emit=obj $<
+
clean:
rm -f *.o *.elf
ビルドして実行してみます。
$ make clean
$ make
$ $ qemu-system-arm -m 256 -M raspi2 -serial mon:stdio -kernel kernel.elf
Hello, kernel World!
無事実行できました。
参考
Raspberry Pi Bare Bones
RustでベアメタルRaspberry PiのLチカ
-
arm-unknown-linux-gnueabihfのhfはhard floatの略で、こちらを使う場合はCコードのコンパイルやリンク時に
-mfloat-abi=hard
等の指定が必要になってくると思われます ↩