週末!プログラミング部

ソフトウェア開発ネタを中心に自分でいろいろ調べた内容を自分の勝手な解釈で思うがままに書いくためのブログ。サンプルソースコード、API、プラットフォーム、プログラミング言語、開発環境などを調査、分析して追求いく予定です。

Crosstool-NGを使ってRPiのベアメタル開発環境を構築してみる

前回、格安でRasperry Piを手に入れたのでこれらを使ってベアメタルプログラミングをしてみようと思います。
まずは開発環境の構築から(・`ω´・)b

開発環境の構築にはCrosstool-NGを使います。
Crosstool-NGは、toolchain(コンパイラアセンブラ、リンカなどの開発環境)を自動生成してくれるツールです。ARMやMIPSなどさまざまなアーキテクチャをサポートしています。

今回は、Winodws10上でBoW(Bash on ubuntu on Windows)を動かし、その上で開発環境を構築しました。
BoWのubuntuのバージョンは、18.04 LTSです。
BoWのインストールは以下のサイトがとても参考になります。
Bash on Ubuntu on Windowsをインストールしてみよう!

必要なパッケージをインストールする

まずは必要なパッケージをぶっこみます。

$ sudo apt-get -y install git autoconf gcc bison \
flex texinfo help2man gawk make libtool-bin \
libncurses5-dev g++ python-dev python3.6-dev \
build-essential libssl-dev zlib1g-dev libbz2-dev \
libreadline-dev libsqlite3-dev wget curl llvm \
libncurses5-dev xz-utils tk-dev libxml2-dev \
libxmlsec1-dev libffi-dev liblzma-dev


さて、Crosstool-NGを動かすのにはPythonが必要ですがubuntu 18.04 LTSにはデフォルトでpython2.xが入っているようです。
必要なのはpython3.xなのでバージョンを切り替るためにpyenvを使います。

$ git clone https://github.com/pyenv/pyenv.git ~/.pyenv

$ echo 'export PYENV_ROOT="$HOME/.pyenv"' >> ~/.profile
$ echo 'export PATH="$PYENV_ROOT/bin:$PATH"' >> ~/.profile
$ echo -e 'if command -v pyenv 1>/dev/null 2>&1; then\n  eval "$(pyenv init -)"\nfi' >> ~/.profile

$ source ~/.profile

$ pyenv install --list
$ pyenv install 3.6.3
$ pyenv global 3.6.3
$ pip install --upgrade pip

以下のコマンドでpython3.xになっているか確認しておきます。

$ pyenv versions
  system
* 3.6.3 (set by /home/natsu_no_omoide/.pyenv/version)

Crosstool-NGをインストールする

ここまでできたら、いよいよCrosstool-NGをインストールしていきます。

$ git clone https://github.com/crosstool-ng/crosstool-ng
$ cd crosstool-ng
$ ./bootstrap
$ ./configure --prefix=/opt/cross
$ make -j$(nproc)
$ sudo make install

今回は/opt/crossにインストールしました。 あとはパスを通して完了です。

$ export PATH=$PATH:/opt/cross/bin

toolchainを生成してみる

まずは適当に作業ディレクトリを作ります。

$ mkdir ~/ctng
$ cd ~/ctng

次にtoolchainのテンプレートを更新します。

$ ct-ng update-samples

以下のコマンドでテンプレート一覧が表示されます。

$ ct-ng list-samples
Status  Sample name
[G...]   aarch64-rpi3-linux-gnu
[G..X]   aarch64-unknown-linux-android
[G...]   aarch64-unknown-linux-gnu
[G...]   aarch64-unknown-linux-uclibc
[G...]   alphaev56-unknown-linux-gnu
[G...]   alphaev67-unknown-linux-gnu
[G...]   arc-arc700-linux-uclibc
[G...]   arc-archs-linux-gnu
[G...]   arc-multilib-elf32
[G...]   arc-multilib-linux-gnu
[G...]   arc-multilib-linux-uclibc
[G...]   arm-bare_newlib_cortex_m3_nommu-eabi
~~~~~
~~~~~
[G...]   x86_64-multilib-linux-uclibc
[G..X]   x86_64-w64-mingw32,x86_64-pc-linux-gnu
[G...]   x86_64-ubuntu12.04-linux-gnu
[G...]   x86_64-ubuntu14.04-linux-gnu
[G...]   x86_64-ubuntu16.04-linux-gnu
[G...]   x86_64-unknown-linux-gnu
[G...]   x86_64-unknown-linux-uclibc
[G..X]   x86_64-w64-mingw32
[G..X]   xtensa-fsf-elf
[G...]   xtensa-fsf-linux-uclibc
 L (Local)       : sample was found in current directory
 G (Global)      : sample was installed with crosstool-NG
 X (EXPERIMENTAL): sample may use EXPERIMENTAL features
 B (BROKEN)      : sample is currently broken
 O (OBSOLETE)    : sample needs to be upgraded

テンプレートを選ぶと.configが生成されます。 今回はAarch64を使用してみたかったのでaarch64-rpi3-linux-gnuを選択しました。

$ ct-ng aarch64-rpi3-linux-gnu
  CONF  aarch64-rpi3-linux-gnu
#
# configuration written to .config
#

***********************************************************

Initially reported by: Bryan Hundven
URL:

Comment:
Raspberry PI 3 aarch64

***********************************************************

Now configured for "aarch64-rpi3-linux-gnu"

以下のコマンドで .configを編集できます。

$ ct-ng menuconfig

とりあえず設定は以下のチェックを外してMMUを無効にしておきます。

Target options  ---> Use the MMU

またTarget OSをbaer-metalにしておきます。

Operating System  --->Target OS 

標準Cライブラリとしてnewlibを使用するようにしておきます。

C-library  ---> C library (newlib)

さらにC compilerの項目からsyscallsを使用しない設定にチェックを入れておきます。

C compiler  --->Disable the syscalls supplied with newlib (NEW)

ここまでできたら.configをSaveしてmenuから抜けます。

そして最後に以下のコマンドを実行してtoolchainを生成します。

$ ct-ng build

注意
Core i7-6700Kのマシンを使用しましたがbuildに40分くらいかかりました。。。(;´Д`)
気長にお待ちください。

toolchainを使ってみる

.configのmenuで特に操作していなければtoolchainは$HOME/x-tools/にできているはずなので以下のようにしてパスを通します。

$ export PATH=$PATH:$HOME/x-tools/aarch64-rpi3-elf/bin

さて、ビルド確認ですがRPi3のベアメタルチュートリアルを使います。

$ git clone https://github.com/bztsrc/raspi3-tutorial
$ cd ./raspi3-tutorial/03_uart1

とりあえず、チュートリアル「03_uart1」をビルドしてみます。 ビルドするために今回は強引にMakefile.gccにあるtoolchainのPrefixを「aarch64-rpi3-elf-」に書き換えます。

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

all: clean kernel8.img

start.o: start.S
  aarch64-rpi3-elf-gcc $(CFLAGS) -c start.S -o start.o

%.o: %.c
  aarch64-rpi3-elf-gcc $(CFLAGS) -c $< -o $@

kernel8.img: start.o $(OBJS)
  aarch64-rpi3-elf-ld -nostdlib -nostartfiles start.o $(OBJS) -T link.ld -o kernel8.elf
  aarch64-rpi3-elf-objcopy -O binary kernel8.elf kernel8.img

clean:
  rm kernel8.elf *.o >/dev/null 2>/dev/null || true

run:
  qemu-system-aarch64 -M raspi3 -kernel kernel8.img -serial null -serial stdio

あとは、makeを実行してkernel8.imgができれば成功です!

$make
rm kernel8.elf *.o >/dev/null 2>/dev/null || true
aarch64-rpi3-elf-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c start.S -o start.o
aarch64-rpi3-elf-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c uart.c -o uart.o
aarch64-rpi3-elf-gcc -Wall -O2 -ffreestanding -nostdinc -nostdlib -nostartfiles -c main.c -o main.o
aarch64-rpi3-elf-ld -nostdlib -nostartfiles start.o uart.o main.o -T link.ld -o kernel8.elf
aarch64-rpi3-elf-objcopy -O binary kernel8.elf kernel8.img