[RPi][Linux] boot upstream Linux from U-Boot on Raspberry Pi 3

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 への対応はまだまだのようです。

参考


コメント

タイトルとURLをコピーしました