U-Boot を Raspberry Pi 3 に導入して、ビルドした mainline Linux kernel を起動してみました。
Raspberry Pi は 既存の bootloader が提供されているので、SDカードの FATパーティションに kernel image を置けば起動するのですが、ビルドした kernel を直接投入するには network 経由で起動したくなるものです。
clone & build
U-Boot を clone してビルドします。
$ git clone git://git.denx.de/u-boot.git $ cd u-boot $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- CONFIG_EFI=y rpi_3_defconfig $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- $ cd -
Linux kernel を clone してビルドします。
$ git clone git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git $ cd linux $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- defconfig $ make ARCH=arm64 CROSS_COMPILE=aarch64-linux-gnu- Image dtbs $ cd -
tftp サーバを用意します。手順は省略しますが、ここではサーバディレクトリを /tftpboot とします。kernel image と devicetree を tftp サーバへコピーします。
$ cp linux/arch/arm64/boot/Image /tftpboot/ $ cp linux/arch/arm64/boot/dts/broadcom/bcm2837-rpi-3-b.dtb /tftpboot/
ここでは Linaro が提供する rootfs image を取得して tftp サーバへコピーします。取得する image は initramfs の uboot で読める形式で、armv8 のものを選択します。
$ wget http://releases.linaro.org/openembedded/images/minimal-initramfs-armv8/latest/linaro-image-minimal-initramfs-genericarmv8-20170127-888.rootfs.cpio.gz.u-boot $ cp linaro-image-minimal-initramfs-genericarmv8-20170127-888.rootfs.cpio.gz.u-boot /tftpboot/rootfs.cpio.gz.u-boot
SD カードを host PC に接続し、パーティションを作成して FAT でフォーマットしマウントします。フォーマットまでは Windows で用意してもよいです。ここでは SD カードは /dev/sdX で認識されたものとしますが、dmesg などで確認して間違えないように注意してください。
※ パーティション分割やフォーマットについての詳細は他の解説にお任せします。情報は Web で探すと出てくると思います...。
$ sudo fdisk /dev/sdX ... (パーティションを作成) ... $ sudo mkfs.vfat -v -c -F 32 /dev/sdX1 $ sudo mount -t vfat /dev/sdX1 /mnt
github で提供されている firmware を clone して SD カードにコピーします。
$ git clone git://github.com/raspberrypi/firmware $ cp -a firmware/boot/* /mnt/
u-boot image をSDカードにコピーし、boot 設定ファイルを作成します。
- arm_control=0x200 を指定すると arm64 モードで起動するようになります。
- enable_uart=1 で GPIO 端子上の Serial を有効にします。Linux では ttyS0 として見えます。
- kernel=u-boot.bin は起動する image のファイル名を指定します。default は(arm64モードの場合) kernel8.img です。
詳しくは RPiconfig にいろいろ解説があります。
$ cp u-boot.bin /mnt/ $ cat > config.txt <<EOF arm_control=0x200 enable_uart=1 kernel=u-boot.bin EOF
マウントを解除して SDカードを PC から外し、Raspberry Pi 3 本体に挿入します。
$ sync $ sudo umount /mnt
console は Serial を使うため、GPIO 端子から 接続する必要があります。今回は手持ちの FTDI chip 搭載の TTL-232r-3v3 を使用しました。Raspberry Pi 初代でも使っていた USB-Serial 変換ケーブルです。直接接続できないので、GPIO 端子を 40pin リボンケーブル(余っていた IDE ケーブル!) を介しています。
※ Raspberry Pi 3 の接続端子の詳細は他の解説にお任せします。情報は Web で探すと出てくると思います...。
また、Ethernet ケーブルで host PC との接続も行っておきます。当たり前ですが、ストレートケーブルは直結できないのでローカル LAN などに接続することになりますので、ローカル LAN の IP アドレス情報は知っておく必要があります。
電源を入れると serial に U-boot のログが出ます。一旦キーを押して止めます。
U-Boot 2017.07-00001-g13e3ef2 (Aug 13 2017 - 23:46:40 +0900) DRAM: 944 MiB RPI 3 Model B (0xa32082) MMC: sdhci@7e300000: 0 reading uboot.env In: serial Out: vidconsole Err: vidconsole Net: No ethernet found. starting USB... USB0: Core Release: 2.80a scanning bus 0 for devices... 3 USB Device(s) found scanning usb for storage devices... 0 Storage Device(s) found Hit any key to stop autoboot: 0 U-Boot>
ネットワークの設定を行います。ipaddr に target(Raspberry Pi 3) の IP アドレス、serverip に tftp サーバを立ち上げた host PC の IP アドレスを指定します。以下は手元で行った例ですので、自分の環境に合わせて設定します。
U-Boot> setenv ipaddr 192.168.1.200 # target(RPi3) の IP アドレス U-Boot> setenv serverip 192.168.1.135 # tftp サーバの IP アドレス U-Boot> setenv bootargs root=/dev/ram0 rw console=ttyS1,115200
tftp で kernel image、devicetree、rootfs image をメモリへ転送し、kernel を起動します。
U-Boot> tftp 0x80000 Image U-Boot> tftp 0x08000000 bcm2837-rpi-3-b.dtb U-Boot> tftp 0x08008000 rootfs.cpio.gz.u-boot U-Boot> booti 0x80000 0x08008000 0x08000000
以下のように起動が確認できました。
Starting kernel ... [ 0.000000] Booting Linux on physical CPU 0x0 [ 0.000000] Linux version 4.13.0-rc4 (kunih@ubuntu) (gcc version 6.3.1 20170404 (Linaro GCC 6.3-2017.05)) #1 SMP PREEMPT Fri Aug 11 11:06:59 JST 2017 [ 0.000000] Boot CPU: AArch64 Processor [410fd034] [ 0.000000] Machine model: Raspberry Pi 3 Model B ... [ 2.229403] Freeing unused kernel memory: 1088K linaro-test [rc=0]#
Raspberry Pi の Ethernet Host は USB で接続されているようですが、現時点での kernel では USB(dwc2) の DMA に問題がありエラーで認識しませんでした。contribute が少ないためか device の mainline への対応はまだまだのようです。
コメント