[WIP] Raspberry Pi 1でベアメタルコードを実行させる

手持ちのRaspberry Piは1とZero。このため、SoCはBCM2835となる。

やりたいこと

  • 「12ステップで学ぶ組み込みOS自作入門」はH8で組み込みOSを自作していく内容であるが、これをRaspberry Piで実現したい。
  • 見たところ、ベアメタルプログラムの起動とシリアル通信までできればやりたいことは達成できそうである。

ベアメタルでC言語コードを実行させるまで

以下のサイトの、C言語のベアメタルコードを実行させるところまで行ってみる。ただし、RPi3のため読み替えが必要だった。

https://qiita.com/fireflower0/items/47ed5bf9af5bf156a649

以下のコードは参考にさせていただいています。

スタートアップコードのboot.Sは、以下のように32bit ARM向けに書き換えを行った。元のコードはマルチコアのRPi3用でいらないコアの停止処理などが入っていたが、RPi1はシングルコアのためそのあたりを削除。また、.bss領域の初期化も「組み込みOS自作入門」ではC言語コードのほうで行っていたので、それもスタートアップコードから削除した。そうしたら次の通りかなり短いものになった。

    .section ".text.boot"
    .global _start

_start:
    ldr r0, =_start
    mov sp, r0

_main:
    bl  main

また、Makefileは32bit ARM向けのコンパイラ指定に書き換えた。

TARGET     = kernel
TARGET_ELF = kernel.elf
TARGET_IMG = kernel.img

PREFIX  = arm-none-eabi-
GCC     = $(PREFIX)gcc
LD      = $(PREFIX)ld
OBJCOPY = $(PREFIX)objcopy

SRCS = $(wildcard *.c)
OBJS = $(SRCS:.c=.o)
CFLAGS  = -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles
LDFLAGS = -nostdlib -nostartfiles

%.o: %.S
	$(GCC) $(CFLAGS) -c $< -o $@

%.o: %.c
	$(GCC) $(CFLAGS) -c $< -o $@

$(TARGET_IMG): boot.o $(OBJS)
	$(LD) $(LDFLAGS) boot.o $(OBJS) -T linker.ld -o $(TARGET_ELF)
	$(OBJCOPY) -O binary $(TARGET_ELF) $(TARGET_IMG)

clean:
	rm $(TARGET_ELF) $(TARGET_IMG) *.o

その他、リンカスクリプトは上記サイトのものをそのまま利用させていただきます。

SECTIONS
{
    . = 0x80000;

    /* .text : プログラムコードが入る領域 */
    .text : {
        KEEP(*(.text.boot))
        *(.text .text.* .gnu.linkonce.t*)
    }

    /* .rodata : 変更されない文字列とか定数などが入る領域 */
    .rodata : {
        *(.rodata .rodata.* .gnu.linkonce.r*)
    }

    PROVIDE(_data = .);

    /* .data : 初期値を持った変数などを置く領域 */
    .data : {
        *(.data .data.* .gnu.linkonce.d*)
    }

    /* .bss : 初期値を持たない変数などを置く領域 */
    .bss (NOLOAD) : {
        . = ALIGN(16);
        __bss_start = .;
        *(.bss .bss.*)
        *(COMMON)
        __bss_end = .;
    }

    _end = .;

    /* 入力セクション破棄 */
    /DISCARD/ : {
        *(.comment)
        *(.gnu*)
        *(.note*)
        *(.eh_frame*)
    }
}

/* .bssのサイズ */
__bss_size = (__bss_end - __bss_start) >> 3;

参考情報

公式マニュアル

周辺回路マニュアルは以下。