MPFS-DISCO-KIT 向け Ubuntu 22.04 の構築(U-Boot bootmenu 改造編)


## はじめに

MPFS-DISCO-KIT(Microchip PolarFire SoC FPGA Discovery Kit) で動作する Ubuntu 22.04 を構築する方法をいくつかの記事に分けて説明します。

 * [イントロ編](https://qiita.com/ikwzm/items/1866dc3bb5292fd1f6e1)
 * [HSS(Hart Software Services)編](https://qiita.com/ikwzm/items/3d6d0a645dd60aba90d2)
 * [U-Boot 標準編](https://qiita.com/ikwzm/items/8b6e78e1c5599d9d375d)
 * __U-Boot bootmenu 改造編 (この記事)__
 * [Linux Kernel linux4microchip+fpga-2024.09 編](https://qiita.com/ikwzm/items/0ca6aea057a3696bd5f0)
 * [Linux Kernel mpfs-fpga-first 編](https://qiita.com/ikwzm/items/d7405466ed7391d4dd73)
 * [Ubuntu 22.04 Root File System 編](https://qiita.com/ikwzm/items/a3d1d5a1a9640b400872)
 * [SD-Card 作成編](https://qiita.com/ikwzm/items/19af3dd7a34ea5364683)
 * [SD-Card 起動編](https://qiita.com/ikwzm/items/42a1aa7b355734a813f8)

上記の記事で構築した 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


筆者は Linux Kernel をいろいろと取り替えたり boot 時の引数を変更したりするため、よく uEnv.txt を書き換えます。その際、書き間違えたり、元に戻すのを間違えたりしてブートに失敗することがありました。これをもう少しなんとかならないかと思っていたところ、u-boot にはもともと bootmenu という機能があり、bootmenu を使えばブート時にメニューから実行するコマンドを選べることを知りました。残念ながら bootmenu 機能は u-boot をビルドする際にオフになっており通常は使えなくなっています。この記事では、 Microchip Technology 社が提供する U-Boot (u-boot-mchp) に対して、bootmenu を使えるようにビルドする方法と、実際に bootmenu を使ってメニューを表示させる方法を示します。

なお、この記事で紹介した U-boot のビルド済みのファイル(uboot.imd、uboot.env、boot.scr) は以下の URL にあります。ビルドが面倒な方はどうぞ。

 * https://github.com/ikwzm/MPFS-DISCO-KIT-U-Boot/tree/v2024.09-1

## U-Boot のブート処理の説明

U-Boot は次のフローチャートで示す順番でブート処理を行います。

![Fig.1 U-Boot のブート処理のフローチャート](https://qiita-image-store.s3.amazonaws.com/0/24981/9fbb6c2e-8670-0410-fe7a-5f5182b9eeb5.jpeg "Fig.1 U-Boot のブート処理のフローチャート")

Fig.1 U-Boot のブート処理のフローチャート

bootmenu は上記フローチャートの bootdelay_process の部分で実行されます。具体的には bootmenu(%d)_ 変数 ( (%d) には0〜9の数字が入る) が定義されていると、その変数の値に基づいてメニュー画面を表示し、選択されたメニューで定義されているコマンドを実行します。

なお、bootdelay_process で bootmenu を表示させるためには、bootdelay_process が開始される __前__ に bootmenu 変数が定義されていなければなりません。
さらに、bootmenu 変数を簡単に編集できるようにテキストファイルで保存しておくことが望ましい。
そこで、bootdelay_process 実行前に preboot を実行し、preboot でテキストファイルで記述されている環境変数を読み込むようにします。

## ダウンロード

### MPFS-DISCO-KIT-U-Boot/files

u-boot を改造するためのファイルは以下の URL にあります。

 * https://github.com/ikwzm/MPFS-DISCO-KIT-U-Boot/tree/v2024.09-1/files/

### u-boot-mchp 

Microchip Technology 社が提供する U-Boot は、以下の URL にあります。

 * https://github.com/linux4microchip/u-boot-mchp.git

この記事では、linux4microchip+fpga-2024.09 というタグのついたものを使用するので、ダウンロードしておきます。

```console
shell$ git clone --depth 1 --branch linux4microchip+fpga-2024.09 https://github.com/linux4microchip/u-boot-mchp.git u-boot-mchp-fpga-2024.09-1
```

### hart-software-services

最終的に HSS からブートするためには、[HSS(Hart Software Services)編](https://qiita.com/ikwzm/items/3d6d0a645dd60aba90d2) で紹介した HSS Payload Generator が必要です。HSS Payload Generator は以下の URL にあります。必要に応じてダウンロードしておきます。

 * https://github.com/polarfire-soc/hart-software-services/tools/hss-payload-generator/

```console
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 から幾つかファイルを追加してカスタマイズしています。さらに、bootmenu を使うためにさらに手をいれています。ここではこれらのファイルの説明をします。

```config:files/mpfs-disco-kit.cfg
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"
CONFIG_USE_PREBOOT=y
CONFIG_CMD_BOOTMENU=y
CONFIG_AUTOBOOT_MENU_SHOW=y
```

u-boot は起動後に環境変数を設定するのですが、環境変数を外部ファイルから読むことを指定しています。
ここでは、アクセスするファイルシステムを FAT に、デバイスを mmc に、ドライブを 0 に、パーティションを 1 に、ファイル名を uboot.env にしています。

bootdelay_process の前に preboot 変数が定義されている場合は preboot 変数で定義されたコマンドが実行されるように、CONFIG_USE_PREBOOT=y を追加しています。

bootdelay_process の際に bootmenu を表示させるために CONFIG_AUTOBOOT_MENU_SHOW=y を追加しています。

CLI でも bootmenu コマンドを実行できるようにするために CONFIG_CMD_BOOTMENU=y を追加しています。

### uboot-env.txt

前述した uboot.env のソースコードです。uboot-env.txt を mkenvimage というツールを使って uboot.env に変換します。

<details><summary>uboot.env (長いので折りたたみ)</summary>

```:files/uboot.env
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=if test -n ${uenvcmd}; then echo Running uenvcmd...; run uenvcmd; fi; 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
bootmenu_0=Boot Default=boot
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)
preboot=run uenv_text_scan_from_mmc0
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
uenv_text=uEnv.txt
uenv_text_load_from_dev=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${uenv_text}
uenv_text_scan_from_dev=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 run uenv_text_scan_from_dev_part; fi; done; setenv devplist
uenv_text_scan_from_dev_part=echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; for prefix in ${boot_prefixes}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${uenv_text}; then if run uenv_text_load_from_dev; then env import -t ${scriptaddr} $filesize; fi; fi; done
uenv_text_scan_from_mmc=if mmc dev ${devnum}; then devtype=mmc; run uenv_text_scan_from_dev; fi
uenv_text_scan_from_mmc0=devnum=0; run uenv_text_scan_from_mmc
vendor=microchip
```

</details>


bootmenu を表示するために新に追加した部分は次のとおりです。

```:files/uboot.env
bootcmd=if test -n ${uenvcmd}; then echo Running uenvcmd...; run uenvcmd; fi; run distro_bootcmd
preboot=run uenv_text_scan_from_mmc0
uenv_text=uEnv.txt
uenv_text_load_from_dev=load ${devtype} ${devnum}:${distro_bootpart} ${scriptaddr} ${prefix}${uenv_text}
uenv_text_scan_from_dev=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 run uenv_text_scan_from_dev_part; fi; done; setenv devplist
uenv_text_scan_from_dev_part=echo Scanning ${devtype} ${devnum}:${distro_bootpart}...; for prefix in ${boot_prefixes}; do if test -e ${devtype} ${devnum}:${distro_bootpart} ${prefix}${uenv_text}; then if run uenv_text_load_from_dev; then env import -t ${scriptaddr} $filesize; fi; fi; done
uenv_text_scan_from_mmc=if mmc dev ${devnum}; then devtype=mmc; run uenv_text_scan_from_dev; fi
uenv_text_scan_from_mmc0=devnum=0; run uenv_text_scan_from_mmc
```

かいつまんで説明すると次のとおりです。

preboot 変数には uenv_text_scan_from_mmc0 を実行するように定義しています。preboot 変数を定義しておくことにより、bootdelay_process の前に preboot 変数の内容を実行します。

uenv_text 変数には読み込むファイル名(uEnv.txt)を定義しています。

uenv_text_scan_from_mmc0 変数は、デバイス mmc のドライブ 0 のパーティションを検索して uenv_text 変数に指定されたファイルの内容を環境変数として import を試みる処理を定義しています。

bootcmd 変数には、uenvcmd 変数が定義されていた場合は uenvcmd 変数の内容を実行する処理を追加しています。uenvcmd 変数が定義されていない場合、または uenvcmd が失敗した場合は、従来通りに distro_bootcmd を実行します。distro_bootcmd は、最終的に boot_a_script コマンドによりブートデバイスにある boot.scr の実行を試みます。distro_bootcmd の詳細は以下の記事を参照してください。

 * [『KV260 が Linux をブートするまでのシーケンス (U-Boot編)』 @Qiita](https://qiita.com/ikwzm/items/c261fe7c0d68c326db3d)

### boot.cmd

前述した boot.scr のソースコードです。boot.cmd を mkimage というツールを使って boot.scr に変換します。

```:boot.cmd
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;
```

### uboot.yaml

u-boot.bin を hss-payload-generator を使って uboot.img(HSS からブートできるイメージファイル)に変換する際に使用する設定ファイルです。

```yaml:uboot.yaml
#
# 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
   + uboot-env.txt
   + uboot.yaml
 * u-boot-mchp-fpga-2024.09-1/
 * hart-software-services-v2024.09/
   + tools/
     - hss-payload-generator/
 * __uboot.img (ビルドした成果物)__
 * __uboot.env (ビルドした成果物)__
 * __boot.scr  (ビルドした成果物)__
  
### 環境設定

```console
shell$ cd u-boot-mchp-fpga-2024.09-1
shell$ export CROSS_COMPILE=riscv64-unknown-linux-gnu-
```

### uboot.img のビルド

#### hss-payload-generator のビルド

あらかじめ hss-payload-generator をビルドしておきます。

```console
shell$ make -C ../hart-software-services-v2024.09/tools/hss-payload-generator/ 
```

#### microchip_mpfs_discokit_defconfig のコンフィギュレーション

まずは u-boot-mchp にある microchip_mpfs_discokit_defconfig でコンフィギュレーションします。同時に scripts にある各種ツールもビルドされます。

```console
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 にマージします。

```console
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

Value of CONFIG_USE_PREBOOT is redefined by fragment ../files/mpfs-disco-kit.cfg:
Previous value: # CONFIG_USE_PREBOOT is not set
New value: CONFIG_USE_PREBOOT=y

Value of CONFIG_CMD_BOOTMENU is redefined by fragment ../files/mpfs-disco-kit.cfg:
Previous value: # CONFIG_CMD_BOOTMENU is not set
New value: CONFIG_CMD_BOOTMENU=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 のビルド

```console
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 からブートできるイメージファイル)に変換します。

```console
shell$ ../hart-software-services-v2024.09/tools/hss-payload-generator/hss-payload-generator -c ../files/uboot.yaml -v ../uboot.img
Hart Software Service formatted boot image generator v0.99.37
Copyright (c) 2021-2022 Microchip FPGA Embedded Systems Solutions.

Parsing set-name
Parsing hart entry points
Parsing payload >>u-boot.bin<<
>>u-boot.bin<< is not an ELF object
Set-name is >>PolarFire-SoC-HSS::U-Boot<<
Output filename is >>../uboot.img<<
Outputting Payload Header
Outputting Code/Data Chunks
Outputting ZI Chunks
Outputting Binary Data
Outputting Payload Header
```

### uboot.env

files/uboot-env.txt (uboot.env のソースコード)を uboot.env(u-boot が直接扱う環境変数ファイル) に変換します。
その際、u-boot をビルドした際に設定した CONFIG_ENV_SIZE が必要です。

```console
shell$ grep CONFIG_ENV_SIZE .config
CONFIG_ENV_SIZE=0x2000
shell$ export CONFIG_ENV_SIZE=0x2000
shell$ tools/mkenvimage -s $CONFIG_ENV_SIZE ../files/uboot-env.txt -o ../uboot.env
```

### boot.scr

files/boot.cmd(boot.scr のソースコード) を boot.scr(u-boot が直接扱うスクリプトファイル) に変換します。

```console
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
```

## uEnv.txt の参考例

以下に uEnv.txt の参考例を示します。

```text:uEnv.txt
########################################################################
# Linux Kernel Files
#  * linux_kernel_image : Linux Kernel Image File Name
#  * linux_fdt_image    : Linux Device Tree Blob File Name
########################################################################
linux_kernel_image=vmlinux-6.6.51-mpfs-fpga-first
linux_fdt_image=devicetree-6.6.51-mpfs-fpga-first-mpfs-disco-kit.dtb

########################################################################
# Linux Boot Argments
#  * linux_boot_args_console : ex) console=tty1
#                                  console=ttyPS0,115200
#  * linux_boot_args_rootfs  : ex) root=/dev/mmcblk0p2 rw rootwait
#  * linux_boot_args_systemd : ex) systemd.unit=graphical.target
#                                  systemd.unit=multi-user.target
#  * linux_boot_args_cpuidle : ex) cpuidle.off=1
#  * linux_boot_args_cma     : ex) cma=256M
#  * linux_boot_args_uio     : ex) uio=uio_pdrv_genirq.of_id=generic-uio
#  * linux_boot_args_other   :
########################################################################
linux_boot_args_console=
linux_boot_args_rootfs=root=/dev/mmcblk0p3 rw rootwait
linux_boot_args_systemd=
linux_boot_args_cpuidle=
linux_boot_args_cma=
linux_boot_args_uio=uio_pdrv_genirq.of_id=generic-uio
linux_boot_args_other=

########################################################################
# uenvcmd : During sdboot, if uenvcmd is set, uenvcmd will be executed.
########################################################################
linux_img_load_cmd=load mmc 0:1 ${kernel_addr_r} ${linux_kernel_image}
linux_fdt_load_cmd=load mmc 0:1 ${fdt_addr_r}    ${linux_fdt_image}
linux_fdt_update_cmd=fdt addr ${fdt_addr_r} ; fdt set /soc/ethernet@20110000 local-mac-address ${discokit_mac_addr0}
linux_load_cmd=env run linux_img_load_cmd && env run linux_fdt_load_cmd && env run linux_fdt_update_cmd
linux_boot_cmd=booti ${kernel_addr_r} - ${fdt_addr_r}
linux_args_cmd=if env exists linux_boot_args; then; setenv bootargs ${linux_boot_args}; else; setenv bootargs ${linux_boot_args_console} ${linux_boot_args_rootfs} ${linux_boot_args_systemd} ${linux_boot_args_cpuidle} ${linux_boot_args_cma} ${linux_boot_args_uio} ${linux_boot_args_other}; fi
uenvcmd=env run linux_args_cmd && env run linux_load_cmd && env run linux_boot_cmd

########################################################################
# Boot Menu
########################################################################
bootmenu_0=Boot Default=boot
bootmenu_1=Boot linux-6.6.51-mpfs-fpga-first=env set linux_kernel_image vmlinux-6.6.51-mpfs-fpga-first && env set linux_fdt_image devicetree-6.6.51-mpfs-fpga-first-mpfs-disco-kit.dtb && boot
bootdelay=5
```

この例では、

 * linux_kernel_image 変数に Linux Kernel Image のファイル名を定義
 * linux_fdt_image に Device Tree Blob のファイル名を定義
 * uenvcmd 変数に上記のファイルをロードして bootargs 変数を設定して booti コマンドを実行するように定義
 * bootdelay 変数に bootmenu 表示時のタイムアウトの秒数を指定

しています。

## 参考

 * https://github.com/linux4microchip/u-boot-mchp
 * https://github.com/polarfire-soc/meta-polarfire-soc-yocto-bsp
 * https://github.com/polarfire-soc/hart-software-services
 * [『ZYBO用U-Bootでブート時にメニューを表示させる』 @Qiita](https://qiita.com/ikwzm/items/c7932ebd1a7b40919241)
 * [『KV260 が Linux をブートするまでのシーケンス (U-Boot編)』 @Qiita](https://qiita.com/ikwzm/items/c261fe7c0d68c326db3d)