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