はじめに
MPFS-DISCO-KIT(Microchip PolarFire SoC FPGA Discovery Kit) で動作する Ubuntu 22.04 を構築する方法をいくつかの記事に分けて説明します。
- イントロ編
- HSS(Hart Software Services)編
- U-Boot 標準編 (この記事)
- U-Boot bootmenu 改造編
- Linux Kernel linux4microchip+fpga-2024.09 編
- Linux Kernel mpfs-fpga-first 編
- Ubuntu 22.04 Root File System 編
- SD-Card 作成編
- SD-Card 起動編
上記の記事で構築した MPFS-DISCO-KIT 向け Ubuntu 22.04 Root File System、Linux Kernel、Boot Loader は次の URL にて公開しています。なお、これらはオフシャルなものではなく、筆者の魔改造がはいっています。ご使用の際はこの点にご留意してください。
- https://github.com/ikwzm/MPFS-FPGA-Ubuntu22.04
- https://github.com/ikwzm/MPFS-FPGA-Linux-Kernel-6.6
- https://github.com/ikwzm/MPFS-DISCO-KIT-U-Boot
この記事では、Microchip Technology 社が提供する U-Boot (u-boot-mchp) のビルドについて解説します。
なお、この記事で紹介した U-boot のビルド済みのファイル(uboot.imd、uboot.env、boot.scr) は以下の URL にあります。ビルドが面倒な方はどうぞ。
ダウンロード
u-boot-mchp
Microchip Technology 社が提供する U-Boot は、以下の URL にあります。
この記事では、linux4microchip+fpga-2024.09 というタグのついたものを使用するので、ダウンロードしておきます。
shell$ git clone --depth 1 --branch linux4microchip+fpga-2024.09 https://github.com/linux4microchip/u-boot-mchp.git u-boot-mchp-fpga-2024.09
meta-polarfire-soc-yocto-bsp
上記のリポジトリの他に、meta-polarfire-soc-yocto-bsp からビルドの際に必要なファイルをダウンロードしておきます。必要なファイルの詳細な説明は後述します。
必要なのは、recipes-bsp/u-boot/files/mpfs-disco-kit/ の中身です。./files あたりにコピーしておきます。
shell$ git clone --depth 1 --branch v2024.09 https://github.com/polarfire-soc/meta-polarfire-soc-yocto-bsp.git meta-polarfire-soc-yocto-bsp-v2024.09
shell$ cp -r meta-polarfire-soc-yocto-bsp-v2024.09/meta-polarfire-soc-bsp/recipes-bsp/u-boot/files/mpfs-disco-kit/ ./files
hart-software-services
最終的に HSS からブートするためには、HSS(Hart Software Services)編 で紹介した HSS Payload Generator が必要です。HSS Payload Generator は以下の URL にあります。必要に応じてダウンロードしておきます。
shell$ git clone --depth 1 --branch v2024.09 https://github.com/polarfire-soc/hart-software-services.git hart-software-services-v2024.09
ファイルの説明
今回は u-boot-mchp を単純に make するだけではなく、meta-polarfire-soc-yocto-bsp から幾つかファイルを追加してカスタマイズしています。ここではこれらのファイルの説明をします。
mpfs-disco-kit.cfg
u-boot-mchp についてくる microchip_mpfs_discokit_defconfig(MPFS-DISCO-KIT 用の def_config)に加えて、あらたに変更&追加するコンフィギュレーションです。
CONFIG_MPFS_PRIORITISE_QSPI_BOOT=n
CONFIG_ENV_IS_NOWHERE=n
CONFIG_ENV_IS_IN_FAT=y
CONFIG_ENV_FAT_INTERFACE="mmc"
CONFIG_ENV_FAT_DEVICE_AND_PART="0:1"
CONFIG_ENV_FAT_FILE="uboot.env"
主に u-boot が最初に設定する環境変数に関する変更点が記述されています。
u-boot は起動後に環境変数を設定するのですが、環境変数を外部ファイルから読むことを指定しています。
ここでは、アクセスするファイルシステムを FAT に、デバイスを mmc に、ドライブを 0 に、パーティションを 1 に、ファイル名を uboot.env にしています。
uEnv.txt
前述した uboot.env のソースコードです。uEnv.txt を mkenvimage というツールを使って uboot.env に変換します。
uEnv.txt (長いので折りたたみ)
arch=riscv
baudrate=115200
board=mpfs_discokit
board_name=mpfs_discokit
boot_a_script=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${script}; source ${scriptaddr}
boot_efi_binary=load ${devtype} ${devnum}:${distro_bootpart} ${kernel_addr_r} efi/boot/bootriscv64.efi; if fdt addr -q ${fdt_addr_r}; then bootefi ${kernel_addr_r} ${fdt_addr_r};else bootefi ${kernel_addr_r} ${fdtcontroladdr};fi
boot_efi_bootmgr=if fdt addr -q ${fdt_addr_r}; then bootefi bootmgr ${fdt_addr_r};else bootefi bootmgr;fi
boot_extlinux=sysboot ${devtype} ${devnum}:${distro_bootpart} any ${scriptaddr} ${prefix}${boot_syslinux_conf}
boot_prefixes=/ /boot/
boot_script_dhcp=boot.scr.uimg
boot_scripts=boot.scr.uimg boot.scr
boot_syslinux_conf=extlinux/extlinux.conf
boot_targets= mmc0 dhcp
bootcmd=run distro_bootcmd
bootcmd_dhcp=devtype=dhcp; if dhcp ${scriptaddr} ${boot_script_dhcp}; then source ${scriptaddr}; fi;setenv efi_fdtfile ${fdtfile}; setenv efi_old_vci ${bootp_vci};setenv efi_old_arch ${bootp_arch};setenv bootp_vci PXEClient:Arch:00027:UNDI:003000;setenv bootp_arch 0x1b;if dhcp ${kernel_addr_r}; then tftpboot ${fdt_addr_r} dtb/${efi_fdtfile};if fdt addr -q ${fdt_addr_r}; then bootefi ${kernel_addr_r} ${fdt_addr_r}; else bootefi ${kernel_addr_r} ${fdtcontroladdr};fi;fi;setenv bootp_vci ${efi_old_vci};setenv bootp_arch ${efi_old_arch};setenv efi_fdtfile;setenv efi_old_arch;setenv efi_old_vci;
bootcmd_mmc0=devnum=0; run mmc_boot
bootdelay=2
bootm_size=0x10000000
cpu=mpfs
design_overlays=if test -n ${no_of_overlays}; then setenv inc 1; setenv idx 0; fdt resize ${dtbo_size}; while test $idx -ne ${no_of_overlays}; do setenv dtbo_name dtbo_image${idx}; setenv fdt_cmd "fdt apply $"$dtbo_name; run fdt_cmd; setexpr idx $inc + $idx; done; fi;
distro_bootcmd=for target in ${boot_targets}; do run bootcmd_${target}; done
efi_dtb_prefixes=/ /dtb/ /dtb/current/
fdt_addr_r=0x8a000000
fdtoverlay_addr_r=0x8a080000
kernel_addr_r=0x80200000
load_efi_dtb=load ${devtype} ${devnum}:${distro_bootpart} ${fdt_addr_r} ${prefix}${efi_fdtfile}
loadaddr=0x80200000
mmc_boot=if mmc dev ${devnum}; then devtype=mmc; run scan_dev_for_boot_part; fi
mtdparts=mtdparts=spi-nand0:2m(payload),128k(env),119m(rootfs)
ramdisk_addr_r=0x8aa00000
scan_dev_for_boot=echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; for prefix in ${boot_prefixes}; do run scan_dev_for_extlinux; run scan_dev_for_scripts; done;run scan_dev_for_efi;
scan_dev_for_boot_part=part list ${devtype} ${devnum} -bootable devplist; env exists devplist || setenv devplist 1; for distro_bootpart in ${devplist}; do if fstype ${devtype} ${devnum}:${distro_bootpart} bootfstype; then part uuid ${devtype} ${devnum}:${distro_bootpart} distro_bootpart_uuid ; run scan_dev_for_boot; fi; done; setenv devplist
scan_dev_for_efi=setenv efi_fdtfile ${fdtfile}; for prefix in ${efi_dtb_prefixes}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${efi_fdtfile}; then run load_efi_dtb; fi;done;run boot_efi_bootmgr;if test -e ${devtype} ${devnum}:${distro_bootpart} efi/boot/bootriscv64.efi; then echo Found EFI removable media binary efi/boot/bootriscv64.efi; run boot_efi_binary; echo EFI LOAD FAILED: continuing...; fi; setenv efi_fdtfile
scan_dev_for_extlinux=if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${boot_syslinux_conf}; then echo Found ${prefix}${boot_syslinux_conf}; run boot_extlinux; echo EXTLINUX FAILED: continuing...; fi
scan_dev_for_scripts=for script in ${boot_scripts}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${script}; then echo Found U-Boot script ${prefix}${script}; run boot_a_script; echo SCRIPT FAILED: continuing...; fi; done
scriptaddr=0x8e000000
vendor=microchip
uEnv.txt では主にブートシーケンスの記述が含まれています。実はこのブートシーケンスは KV260 とほぼ同じです。詳しいブートシーケンスについては以下の記事を参照してください。
最終的に boot_a_script コマンドによりブートデバイスにある boot.scr の実行を試みます。
boot.cmd
前述した boot.scr のソースコードです。boot.cmd を mkimage というツールを使って boot.scr に変換します。
setenv fdt_high 0xffffffffffffffff
setenv initrd_high 0xffffffffffffffff
load mmc 0:${distro_bootpart} ${scriptaddr} fitImage
bootm start ${scriptaddr};
bootm loados ${scriptaddr};
# Try to load a ramdisk if available inside fitImage
bootm ramdisk;
bootm prep;
fdt set /soc/ethernet@20110000 mac-address ${discokit_mac_addr0};
run design_overlays;
bootm go;
ブートデバイスにある fitImage というファイルをロードしています。fitImage は u-boot で使用される FIT(Flattend Image Tree) というフォーマットのファイルです。このスクリプトでは、ロードした Device Tree になにやら ethernet の MAC Address を上書きしているようです。
uboot.yaml
u-boot.bin を hss-payload-generator を使って uboot.img(HSS からブートできるイメージファイル)に変換する際に使用する設定ファイルです。
#
# HSS Payload Generator
#
# First, we can optionally set a name for our image, otherwise one will be created dynamically
set-name: 'PolarFire-SoC-HSS::U-Boot'
#
# Next, we'll define the entry point addresses for each hart, as follows:
#
hart-entry-points: {u54_1: '0x80200000', u54_2: '0x80200000', u54_3: '0x80200000', u54_4: '0x80200000'}
#
# Finally, we'll define some payloads (source ELF files) that will be placed at certain regions in memory
# The payload section is defined with the keyword payloads, and then a number of individual
# payload descriptors.
#
# Each payload has a name (path to its ELF file), an owner-hart, and optionally 1-3 secondary-harts.
#
# Additionally, it has a privilege mode in which it will start execution.
# * Valid privilege modes are PRV_M, PRV_S and PRV_U.
#
#
# In the following example:
# * test/baremetal is assumed to be a bare metal application that runs in u54_3,
# and expects to start in PRV_M
# * test/u-boot is the Das U-Boot bootloader, and it runs on U54_1, U54_2 and U54_4.
# It expects to start in PRV_S.
#
# Case only matters for the ELF path names, not the keywords.
#
payloads:
u-boot.bin: {exec-addr: '0x80200000', owner-hart: u54_1, secondary-hart: u54_2, secondary-hart: u54_3, secondary-hart: u54_4, priv-mode: prv_s}
名前やブートするファイル名や各々の CPU が実行する際のエントリーポイントが記述されています。
ビルド
ディレクトリ構造とファイル
- files/
- boot.cmd
- mpfs-disco-kit.cfg
- uEnv.txt
- uboot.yaml
- u-boot-mchp-fpga-2024.09/
- hart-software-services-v2024.09/
- tools/
- hss-payload-generator/
- tools/
- uboot.img (ビルドした成果物)
- uboot.env (ビルドした成果物)
- boot.scr (ビルドした成果物)
環境設定
shell$ cd u-boot-mchp-fpga-2024.09
shell$ export CROSS_COMPILE=riscv64-unknown-linux-gnu-
uboot.img のビルド
hss-payload-generator のビルド
あらかじめ hss-payload-generator をビルドしておきます。
shell$ make -C ../hart-software-services-v2024.09/tools/hss-payload-generator/
microchip_mpfs_discokit_defconfig のコンフィギュレーション
まずは u-boot-mchp にある microchip_mpfs_discokit_defconfig でコンフィギュレーションします。同時に scripts にある各種ツールもビルドされます。
shell$ make microchip_mpfs_discokit_defconfig
HOSTCC scripts/basic/fixdep
HOSTCC scripts/kconfig/conf.o
YACC scripts/kconfig/zconf.tab.c
LEX scripts/kconfig/zconf.lex.c
HOSTCC scripts/kconfig/zconf.tab.o
HOSTLD scripts/kconfig/conf
#
# configuration written to .config
#
files/mpfs-disco-kit.cfg のマージ
recipes-bsp/u-boot/files/mpfs-disco-kit/mpfs-disco-kit.cfg を .config にマージします。
shell$ ./scripts/kconfig/merge_config.sh .config ../files/mpfs-disco-kit.cfg
Using .config as base
Merging ../files/mpfs-disco-kit.cfg
Value of CONFIG_MPFS_PRIORITISE_QSPI_BOOT is redefined by fragment ../files/mpfs-disco-kit.cfg:
Previous value: CONFIG_MPFS_PRIORITISE_QSPI_BOOT=y
New value: CONFIG_MPFS_PRIORITISE_QSPI_BOOT=n
Value of CONFIG_ENV_IS_NOWHERE is redefined by fragment ../files/mpfs-disco-kit.cfg:
Previous value: CONFIG_ENV_IS_NOWHERE=y
New value: CONFIG_ENV_IS_NOWHERE=n
Value of CONFIG_ENV_IS_IN_FAT is redefined by fragment ../files/mpfs-disco-kit.cfg:
Previous value: # CONFIG_ENV_IS_IN_FAT is not set
New value: CONFIG_ENV_IS_IN_FAT=y
scripts/kconfig/conf --alldefconfig Kconfig
#
# configuration written to .config
#
Value requested for CONFIG_MPFS_PRIORITISE_QSPI_BOOT not in final .config
Requested value: CONFIG_MPFS_PRIORITISE_QSPI_BOOT=n
Actual value: # CONFIG_MPFS_PRIORITISE_QSPI_BOOT is not set
Value requested for CONFIG_ENV_IS_NOWHERE not in final .config
Requested value: CONFIG_ENV_IS_NOWHERE=n
Actual value: # CONFIG_ENV_IS_NOWHERE is not set
u-boot.bin のビルド
shell$ make
:
(中略)
:
LD u-boot
OBJCOPY u-boot.srec
OBJCOPY u-boot-nodtb.bin
DTC arch/riscv/dts/microchip-mpfs-disco-kit.dtb
SHIPPED dts/dt.dtb
CAT u-boot-dtb.bin
COPY u-boot.bin
SYM u-boot.sym
COPY u-boot.dtb
OFCHK .config
uboot.img に変換
u-boot.bin を hss-payload-generator を使って uboot.img(HSS からブートできるイメージファイル)に変換します。
shell$ ../hart-software-services-v2024.09/tools/hss-payload-generator/hss-payload-generator -c ../files/uboot.yaml -v ../uboot.img
uboot.env
files/uEnv.txt (uboot.env のソースコード)を uboot.env(u-boot が直接扱う環境変数ファイル) に変換します。
その際、u-boot をビルドした際に設定した CONFIG_ENV_SIZE が必要です。
shell$ grep CONFIG_ENV_SIZE .config
CONFIG_ENV_SIZE=0x2000
shell$ export CONFIG_ENV_SIZE=0x2000
shell$ tools/mkenvimage -s $CONFIG_ENV_SIZE ../files/uEnv.txt -o ../uboot.env
boot.scr
files/boot.cmd(boot.scr のソースコード) を boot.scr(u-boot が直接扱うスクリプトファイル) に変換します。
shell$ tools/mkimage -c none -A riscv -T script -d ../files/boot.cmd ../boot.scr
Image Name:
Created: Fri Nov 22 15:18:44 2024
Image Type: RISC-V Linux Script (gzip compressed)
Data Size: 368 Bytes = 0.36 KiB = 0.00 MiB
Load Address: 00000000
Entry Point: 00000000
Contents:
Image 0: 360 Bytes = 0.35 KiB = 0.00 MiB