みつきんのメモ

組み込みエンジニアです。Interface誌で「Yocto Projectではじめる 組み込みLinux開発入門」連載中

秋月の「アレ」をYoctoProjectで遊ぶ(Linux起動まで)

はじめに

秋月の「アレ」をYoctoProjectで遊ぶ(u-boot起動まで)の続き。

u-boot起動まで行くがLinuxカーネルが起動しない。

Linuxカーネルのレシピ

コケる原因

野生のプロがすでに原因を突き止めてた。

パッチの作成

せっかくマシン定義も分離したので、カーネルのデバイスツリーも分離してしまう。

次の内容で/tmp/0001-dts-Add-devicetree-for-am3352-aki.patchを作成する。

From 23531bab2524a625f00d3aba6a3f3f14700a7a30 Mon Sep 17 00:00:00 2001
From: Yusuke Mitsuki <mickey.happygolucky@gmail.com>
Date: Thu, 23 Mar 2023 02:47:07 +0900
Subject: [PATCH] dts: Add devicetree for am3352-aki

Signed-off-by: Yusuke Mitsuki <mickey.happygolucky@gmail.com>
---
 arch/arm/boot/dts/Makefile       | 3 ++-
 arch/arm/boot/dts/am3352-aki.dts | 7 +++++++
 2 files changed, 9 insertions(+), 1 deletion(-)
 create mode 100644 arch/arm/boot/dts/am3352-aki.dts

diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 27ca1ca6e827..03c0454077a1 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -872,7 +872,8 @@ dtb-$(CONFIG_SOC_AM33XX) += \
    am335x-sbc-t335.dtb \
    am335x-sl50.dtb \
    am335x-wega-rdk.dtb \
-  am335x-osd3358-sm-red.dtb
+   am335x-osd3358-sm-red.dtb \
+   am3352-aki.dtb
 dtb-$(CONFIG_ARCH_OMAP4) += \
    omap4-droid-bionic-xt875.dtb \
    omap4-droid4-xt894.dtb \
diff --git a/arch/arm/boot/dts/am3352-aki.dts b/arch/arm/boot/dts/am3352-aki.dts
new file mode 100644
index 000000000000..47b7ff75b8cf
--- /dev/null
+++ b/arch/arm/boot/dts/am3352-aki.dts
@@ -0,0 +1,7 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#include "am335x-boneblack.dts"
+
+&pruss_tm {
+   status = "disabled";
+};
-- 
2.34.1

このパッチでは次のことを行っている。

  1. am3352-aki.dtsを作成
  2. am3352-aki.dtsをカーネルのビルド対象に組み込む
  3. pruss_tmノードを無効化する

カーネルレシピ

次のコマンドを実行してカーネルのレシピを作成する。

$ recipetool appendsrcfile ./meta-am3352-aki virtual/kernel /tmp/0001-dts-Add-devicetree-for-am3352-aki.patch

起動確認

local.confの修正

追加したam3352-aki.dtbがイメージに含まれるようにlocal.confに次の行を追加する。

KERNEL_DEVICETREE:am3352-aki = "am3352-aki.dtb"

extlinux.confの修正

この状態でcore-image-minimalを作成しSDカードにイメージを書き込む。しかしそのままでは起動しない。 u-bootが今回新たに作成したam3352-aki.dtbを使用するようになっていないためである。

am3352-aki.dtbを使用するためには、SDカードをLinuxマシンに接続し、ブートパーティションに存在するextlinux.confを書き換える必要がある。

エディタでextlinux.confを開く。

$ vim /media/${USER}/boot/extlinux/extlinux.conf

次のように修正する。

+++ extlinux.conf  2023-03-25 11:43:40.000000000 +0900
@@ -1,5 +1,5 @@
 default Yocto
 label Yocto
    kernel /zImage
-   fdtdir /
+   fdt /am3352-aki.dtb
 append root=PARTUUID=b8ee76af-02 rootwait console=ttyS0,115200

ログイン画面まで進んだ。

Poky (Yocto Project Reference Distro) 4.0.8 am3352-aki /dev/ttyS0

am3352-aki login: root
root@am3352-aki:~#

マシン定義の修正

このままでは、作成したイメージを毎回手作業で修正しなければLinuxが起動できない。

そこで、マシン定義を修正し、extlinux.confでam3352-aki.dtbを参照されるようにする。

meta-am3352-aki/conf/machine/am3352-aki.confに次の内容を追加する。

KERNEL_DEVICETREE:am3352-aki ?= "am3352-aki.dtb"

UBOOT_EXTLINUX:am3352-aki ?= "1"
UBOOT_EXTLINUX_FDT:am3352-aki ?= "../am3352-aki.dtb"
UBOOT_EXTLINUX_ROOT:am3352-aki  ?= "root=PARTUUID=${uuid}"
UBOOT_EXTLINUX_BOOT_FILES:am3352-aki  ?= " \
    extlinux.conf;extlinux/extlinux.conf \
    ${KERNEL_IMAGETYPE} \
    ${KERNEL_DEVICETREE} \
"
IMAGE_BOOT_FILES:am3352-aki ?= "${SPL_BINARY} u-boot.${UBOOT_SUFFIX} ${UBOOT_EXTLINUX_BOOT_FILES}"

これでbitbake一発でLinuxまで起動できるイメージを作成することができるようになる。

まとめ

Linuxが起動できるようになったのでここで区切る。

  • カーネル本体への修正は今の所不要
  • バイスツリーをam3352-aki向けに分離
  • 野生のプロすごい
  • extlinux.confはbitbakeから作成・修正が可能
  • ルートFS含めて一発でビルドできる環境が整った

秋月の「アレ」をYoctoProjectで遊ぶ(u-boot起動まで)

はじめに

すべては「ふが」のアイコンでおなじみの某氏からのこんなメッセージから始まった。

本稿の「アレ」とは秋月電子で売っている「無線モジュール付きSoc基板+白色プラスチックケース」という商品のことだ。この時点では購入もしておらず、手を出す気もなかった。しかし煽られた衝動的に購入ボタンをポチッとしてしまった。

※ 2023/3/25時点ですでに通販での取り扱いはなくなっているようだ。

BeagleBone用のイメージを作成

YoctoProjectでBeagleBone向けのイメージを作成する。 使用するブランチはkirkstone。

Pokyの取得

作業ディレクトリの作成し、pokyを取得する。

$ mkdir -p ~/yocto/aki-soc
$ cd ~/yocto/aki-soc
$ git clone git://git.yoctoproject.org/poky.git -b kirkstone

BeagleBoneはPokyのリファレンスボードに入っているため、追加のレイヤは(この時点では)ない。

環境変数の設定

$ source poky/oe-init-build-env

local.conf

MACHINEにbeaglebone-yoctoを設定する。

MACHINE ?= "beaglebone-yocto"
DL_DIR = "${TOPDIR}/../downloads"

ビルド

まず、最低限ブートに必要な機能だけあればよいのでcore-image-minimalを作成する。

$ bitbake core-image-minimal

初回起動(失敗)

SDカードブート

SDカードにイメージを書き込んでブートしてみる。

虚無が見えた。

UARTブート

インターネッツで調べたところ、SDカードを差し込まずに電源を投入するとCCCCCCCCCが出続けるらしい。

これはUART越しにu-bootを送り込んで起動するモードになっていることを示すらしい。

WindowsであればTeraTermで書き込めるらしい。LinuxではFirsts steps with AM335xの方法がわかりやすい。

しかし虚無が見える。

u-bootの修正

このあたりの情報からOSD335Xをカスタム基板でU-bootを動かすまで(メモ)に行き着いて、RobertCNelsonさんのBootloader-Builderを見つけた。

Bootloader-BuilderはAM335x向けのu-bootをビルドするためのツールで、いくつかのパッチを適用している。 Bootloader-Builderで作成したMLOとu-bootを先程作成したcore-image-minimalを書き込んだSDカードのものと差し替えて見るとu-bootまで起動することがわかった。

U-Boot SPL 2021.10-00003-g92b221314b (Mar 23 2023 - 00:00:07 +0900)
Trying to boot from MMC1


U-Boot 2021.10-00003-g92b221314b (Mar 23 2023 - 00:00:07 +0900)

CPU  : AM335X-GP rev 2.1
Model: TI AM335x BeagleBone Black
DRAM:  512 MiB

このツールで適用しているパッチの中から1つずつ試していき、このパッチが有効であるところまではわかった。

meta-am3352-akiの作成

動くu-bootの作成方法がわかったので、この基板向けのレイヤを作成する。名前は適当に「meta-am3352-aki」とする。

$ bitbake-layers create-layer meta-am3352-aki
$ rm -rf ./meta-am3352-aki/recipes-example
$ bitbake-layers add-layer ./meta-am3352-aki

マシン定義

まずはマシン定義を作成する。

$ mkdir ./meta-am3352-aki/conf/machine

meta-am3352-aki/conf/machine/am3352-aki.confを下記の内容で作成する。

MACHINEOVERRIDES =. "beaglebone-yocto:"
require conf/machine/beaglebone-yocto.conf

とりあえずこれでbeaglebone-yoctoのマシンと同等の内容でam3352-akiというマシンが定義される。

u-bootのレシピ

このパッチをYoctoProjectが提供するu-bootに適用する。そのままでは当たらないので手パッチする。

From 389cc4d07be03ef77614d7b8c8fdb7f8e8aeae9b Mon Sep 17 00:00:00 2001
From: Robert Nelson <robertcnelson@gmail.com>
Date: Thu, 21 Oct 2021 16:06:34 -0500
Subject: [PATCH] NFM-Production-eeprom-assume-device-is-BeagleBone-Bl

Signed-off-by: Robert Nelson <robertcnelson@gmail.com>
Signed-off-by: Yusuke Mitsuki <mickey.happygolucky@gmail.com>
---
 board/ti/am335x/board.c        |  4 ++--
 board/ti/am335x/board.h        |  9 +++++++--
 board/ti/am335x/mux.c          |  6 ++++--
 board/ti/common/board_detect.c | 12 ++++++++++++
 configs/am335x_evm_defconfig   |  2 +-
 include/configs/am335x_evm.h   |  8 ++++++++
 6 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/board/ti/am335x/board.c b/board/ti/am335x/board.c
index e8555de9c9..348ca65761 100644
--- a/board/ti/am335x/board.c
+++ b/board/ti/am335x/board.c
@@ -272,7 +272,7 @@ const struct dpll_params *get_dpll_ddr_params(void)
 
    if (board_is_evm_sk())
        return &dpll_ddr3_303MHz[ind];
-  else if (board_is_pb() || board_is_bone_lt() || board_is_icev2())
+   else if (board_is_pb() || board_is_bone_lt() || board_is_icev2() || board_is_blank_bone_lt())
        return &dpll_ddr3_400MHz[ind];
    else if (board_is_evm_15_or_later())
        return &dpll_ddr3_303MHz[ind];
@@ -548,7 +548,7 @@ void sdram_init(void)
    if (board_is_evm_sk())
        config_ddr(303, &ioregs_evmsk, &ddr3_data,
               &ddr3_cmd_ctrl_data, &ddr3_emif_reg_data, 0);
-  else if (board_is_pb() || board_is_bone_lt())
+   else if (board_is_pb() || board_is_bone_lt() || board_is_blank_bone_lt())
        config_ddr(400, &ioregs_bonelt,
               &ddr3_beagleblack_data,
               &ddr3_beagleblack_cmd_ctrl_data,
diff --git a/board/ti/am335x/board.h b/board/ti/am335x/board.h
index c2962111c1..0932bf8bfc 100644
--- a/board/ti/am335x/board.h
+++ b/board/ti/am335x/board.h
@@ -48,10 +48,15 @@ static inline int board_is_bben(void)
    return board_is_bone_lt() && !strncmp(board_ti_get_rev(), "SE", 2);
 }
 
+static inline int board_is_blank_bone_lt(void)
+{
+   return board_ti_is("A335BLNK");
+}
+
 static inline int board_is_beaglebonex(void)
 {
-  return board_is_pb() || board_is_bone() || board_is_bone_lt() ||
-         board_is_bbg1() || board_is_bben();
+   return board_is_pb() || board_is_bone() || board_is_bone_lt() || 
+          board_is_bbg1() || board_is_bben() || board_is_blank_bone_lt();
 }
 
 static inline int board_is_evm_sk(void)
diff --git a/board/ti/am335x/mux.c b/board/ti/am335x/mux.c
index fed737fa09..9a6cba3733 100644
--- a/board/ti/am335x/mux.c
+++ b/board/ti/am335x/mux.c
@@ -427,7 +427,9 @@ void enable_board_pin_mux(void)
        configure_module_pin_mux(rmii1_pin_mux);
        configure_module_pin_mux(spi0_pin_mux);
    } else {
-      /* Unknown board. We might still be able to boot. */
-      puts("Bad EEPROM or unknown board, cannot configure pinmux.");
+       puts("Unknown board: assuming BeagleBone Black.");
+       configure_module_pin_mux(mii1_pin_mux);
+       configure_module_pin_mux(mmc0_pin_mux);
+       configure_module_pin_mux(mmc1_pin_mux);
    }
 }
diff --git a/board/ti/common/board_detect.c b/board/ti/common/board_detect.c
index de92eb0981..6008f848c0 100644
--- a/board/ti/common/board_detect.c
+++ b/board/ti/common/board_detect.c
@@ -288,6 +288,17 @@ int __maybe_unused ti_i2c_eeprom_am_get(int bus_addr, int dev_addr)
 
    rc = ti_i2c_eeprom_get(bus_addr, dev_addr, TI_EEPROM_HEADER_MAGIC,
                   sizeof(am_ep), (uint8_t *)&am_ep);
+   if (rc < 0) {
+       ep->header = TI_EEPROM_HEADER_MAGIC;
+
+       strlcpy(ep->name, "A335BLNK", TI_EEPROM_HDR_NAME_LEN + 1);
+       ti_eeprom_string_cleanup(ep->name);
+
+       strlcpy(ep->version, "EMMC", TI_EEPROM_HDR_REV_LEN + 1);
+       ti_eeprom_string_cleanup(ep->version);
+
+       goto already_read;
+   }
    if (rc)
        return rc;
 
@@ -310,6 +321,7 @@ int __maybe_unused ti_i2c_eeprom_am_get(int bus_addr, int dev_addr)
    memcpy(ep->mac_addr, am_ep.mac_addr,
           TI_EEPROM_HDR_NO_OF_MAC_ADDR * TI_EEPROM_HDR_ETH_ALEN);
 
+already_read:
    return 0;
 }
 
diff --git a/configs/am335x_evm_defconfig b/configs/am335x_evm_defconfig
index 4dc5d0fe34..075e50d066 100644
--- a/configs/am335x_evm_defconfig
+++ b/configs/am335x_evm_defconfig
@@ -9,7 +9,7 @@ CONFIG_DISTRO_DEFAULTS=y
 CONFIG_SPL_LOAD_FIT=y
 # CONFIG_USE_SPL_FIT_GENERATOR is not set
 CONFIG_OF_BOARD_SETUP=y
-CONFIG_BOOTCOMMAND="run findfdt; run init_console; run finduuid; run distro_bootcmd"
+CONFIG_BOOTCOMMAND="run eeprom_program; run findfdt; run init_console; run finduuid; run distro_bootcmd"
 CONFIG_LOGLEVEL=3
 CONFIG_SYS_CONSOLE_INFO_QUIET=y
 CONFIG_ARCH_MISC_INIT=y
diff --git a/include/configs/am335x_evm.h b/include/configs/am335x_evm.h
index 7fb1b3a3e3..66c614c5b3 100644
--- a/include/configs/am335x_evm.h
+++ b/include/configs/am335x_evm.h
@@ -126,6 +126,14 @@
            "setenv fdtfile am335x-bone.dtb; fi; " \
        "if test $board_name = A335BNLT; then " \
            "setenv fdtfile am335x-boneblack.dtb; fi; " \
+       "if test $board_name = A335BLNK; then " \
+           "if test -e mmc 0:1 /boot/.eeprom.txt; then " \
+               "load mmc 0:1 ${loadaddr} /boot/.eeprom.txt;" \
+               "env import -t ${loadaddr} ${filesize};" \
+               "echo Loaded environment from /boot/.eeprom.txt;" \
+               "run eeprom_program; " \
+           "fi;" \
+           "setenv fdtfile am335x-bonegreen.dtb; fi; " \
        "if test $board_name = A335PBGL; then " \
            "setenv fdtfile am335x-pocketbeagle.dtb; fi; " \
        "if test $board_name = BBBW; then " \
-- 
2.34.1

この内容で/tmp/0001-NFM-Production-eeprom-assume-device-is-BeagleBone-Bl.patchを作成して、次のコマンドを実行する。

$ recipetool appendsrcfile ./meta-am3352-aki virtual/bootloader /tmp/0001-NFM-Production-eeprom-assume-device-is-BeagleBone-Bl.patch

これでu-bootのレシピが作成される。

この状態でcore-image-minimalを作成し、u-bootが起動することを確認する。

U-Boot SPL 2022.01 (Jan 10 2022 - 18:46:34 +0000)
Trying to boot from MMC1


U-Boot 2022.01 (Jan 10 2022 - 18:46:34 +0000)

CPU  : AM335X-GP rev 2.1
Model: TI AM335x EVM
DRAM:  512 MiB
WDT:   Started wdt@44e35000 with servicing (60s timeout)
NAND:  0 MiB
MMC:   OMAP SD/MMC: 0
Loading Environment from FAT... Unable to read "uboot.env" from mmc0:1... <ethaC
Net:   eth2: ethernet@4a100000, eth3: usb_ether
Hit any key to stop autoboot:  0 
=> 

この時点でカーネルは起動しない。

まとめ

長くなったので一旦区切る。ここまでのまとめ。

  • ふがさんに煽られたので気絶してポチった
  • BeagleBone向けのイメージで起動すると思ったが起動しなかった
  • RobertCNelsonさん最高!
  • meta-am3352-akiを作った
  • u-bootまでは起動した

YoctoProject kirkstone + RPi4Bでdm-verity環境を試す

はじめに

YoctoProject dm-verity環境を試すでYoctoProjectを使用してqemu環境でdm-verityを試した。

今回は実機で使用する際にどの様なことが必要か考えてみる。

ターゲットはラズベリーパイ4 モデルB

使用するブランチはkirkstone

環境構築

作業環境

作業ディレクトリは~/yocto/rpi-kirkstone-securityとする。

$ mkdir -p ~/yocto/rpi-kirkstone-security
$ cd ~/yocto/rpi-kirkstone-security

pokyの取得

下記コマンドを実行してpokyおよびビルド環境を取得する。

$ git clone -b kirkstone git://git.yoctoproject.org/poky.git

環境変数の設定

bitbakeを実行可能にするため環境変数を設定する。

$ source poky/oe-init-build-env

meta-raspberrypiの取得

meta-raspberrypiを取得する。

$ bitbake-layers layerindex-fetch meta-raspberrypi

meta-securityの取得

meta-securityと依存するレイヤを取得する。

$ bitbake-layers layerindex-fetch meta-security meta-oe meta-python meta-networking meta-perl

wksを作成

マイクロSDにveirty用のルートFSを書き込むためにwksファイルを作成する。 wksを格納するための作業用レイヤを作成する。

$ bitbake-layers create-layer meta-work
$ mkdir meta-work/wic
$ rm -rf meta-work/wic/recipes-example
$ mv ./meta-work ../poky
$ bitbake-layers add-layer ../poky/meta-work

meta-work/wic/sdimage-raspberrypi-dm.wks.inを下記の内容で作成する。

part /boot --source bootimg-partition --ondisk mmcblk0 --fstype=vfat --label boot --active --align 4096 --size 20
part / --source rawcopy --ondisk mmcblk0 --sourceparams="file=${IMGDEPLOYDIR}/${DM_VERITY_IMAGE}-${MACHINE}.${DM_VERITY_IMAGE_TYPE}.verity" --fstype=ext4

wksファイルの拡張子をwks.inとすることにより、bitbake内で使用できる変数を記述することができる。 変数を含んだwks.inから、変数が解決されたwksが作成され、wicツールに渡されるような流れとなる。

local.confを編集

conf/local.confに下記の部分を追加

MACHINE = "raspberrypi4-64"
DL_DIR = "${TOPDIR}/../downloads"

# enable uart
ENABLE_UART = "1"

# systemd
DISTRO_FEATURES:append = " systemd pam"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""

# dm-verity
DM_VERITY_IMAGE = "core-image-base"
DM_VERITY_IMAGE_TYPE = "ext4"
IMAGE_CLASSES += "dm-verity-img"

INITRAMFS_IMAGE = "dm-verity-image-initramfs"
INITRAMFS_IMAGE_BUNDLE = "1"

# use the kernel that bundled initramfs
IMAGE_BOOT_FILES = " \
  ${BOOTFILES_DIR_NAME}/* \
  ${@make_dtb_boot_files(d)} \
  ${KERNEL_IMAGETYPE}-${INITRAMFS_LINK_NAME}.bin;${SDIMG_KERNELIMAGE} \
"

# enable kernel features for dm-verity
KERNEL_FEATURES:append = " features/device-mapper/dm-verity.scc"

WKS_FILE = "sdimage-raspberrypi-dm.wks.in"

dm-verity用イメージ作成の設定

dm-veirty用のイメージを作成するための設定は下記の部分となる。

# dm-verity
DM_VERITY_IMAGE = "core-image-base"
DM_VERITY_IMAGE_TYPE = "ext4"
IMAGE_CLASSES += "dm-verity-img"

dm-verity検証用initramfs作成の設定

起動時にdm-verityを使用してルートFSのデバイスを検証するための initramfsを作成するための設定は下記の部分となる。

INITRAMFS_IMAGE = "dm-verity-image-initramfs"
INITRAMFS_IMAGE_BUNDLE = "1"

ここでは、initramfsはカーネルにバンドルするようにしている。

initramfsをバンドルしたカーネルを使う設定は下記の部分となる。

# use the kernel that bundled initramfs
IMAGE_BOOT_FILES = " \
    ${BOOTFILES_DIR_NAME}/* \
    ${@make_dtb_boot_files(d)} \
    ${KERNEL_IMAGETYPE}-${INITRAMFS_LINK_NAME}.bin;${SDIMG_KERNELIMAGE} \
"

カーネルのdm-verity関連の機能を有効化

dm-veirty関連のドライバをカーネルに組み込むために下記の行を追加している。

# enable kernel features for dm-verity
KERNEL_FEATURES:append = " features/device-mapper/dm-verity.scc"

veirty用のwksを使用

今回作成したwksを使用するように下記を設定している。

WKS_FILE = "sdimage-raspberrypi-dm.wks.in"

ビルド

core-image-baseをビルドする。

$ bitbake core-image-base

動作確認

作成されたイメージを書き込んだマイクロSDでラズベリーパイ4を起動する。

root@raspberrypi4-64:~# mount | grep '/ '
/dev/mapper/rootfs on / type ext4 (ro,relatime)
root@raspberrypi4-64:~#

dm-verity関連のログ

筆者環境では下記のようなログが出力されているが、システムが起動できているのでひとまず気にしないことにしている。

[    5.070957] random: veritysetup: uninitialized urandom read (2 bytes read)
[    5.078808] device-mapper: verity: sha256 using implementation "sha256-generic"
[    5.179765] device-mapper: verity: 179:2: data block 2048 is corrupted
[    5.187192] device-mapper: verity: 179:2: data block 2048 is corrupted
[    5.193909] Buffer I/O error on dev dm-0, logical block 512, async page read
Verity device detected corruption after activation.

注意点

dm-verity用のルートFSを書き込んだマイクロSDは、書き込み後PCなどでマウントしてしまうと、 ハッシュが変わってしまうため、起動しなくなるので注意すること。

まとめ

YoctoProjectで作成したdm-verityの環境を実機で動かしてみた。 エラーっぽいメッセージも見られたが、一応は動作しているようだ。

性質上、ルートFSはリードオンリーでマウントされるため、 実用するには、overlayfsなどを使用して書き込み可能な領域を重ねるか、 書き込み可能領域をどこかにマウントするなど対応が必要となる。

YoctoProject dm-verity環境を試す

はじめに

最近はセキュリティ的な需要で、YoctoProjectを使用した環境でもルートFSをdm-veirtyで検証したいという要望を聞くようになった。

meta-securityを使用することで、dm-verityを使用したルートFSの検証を実装することができる。 恐らく、もっとも簡単に実行可能な環境を作成するにはmeta-securityのkasディレクトリに格納されている「kas-security-dm.yml」を使用することである。

kasについて

kasについてはYocto meta-raspberrypi環境の作成にkasを使ってみるで解説している。

ビルド環境の構築

今回はkasを使用するので、明示的に取得する環境はmeta-securityのみとなる。

作業ディレクト

作業ディレクトリは~/yocto/kas-securityとする。

$ mkdir -p ~/yocto/kas-security
$ cd ~/yocto/kas-security

meta-securityの取得

$ git clone git://git.yoctoproject.org/meta-security

ビルド用のベース環境を構築

kasを使用してビルド用のベースとなる環境を構築する。

$ kas checkout ./meta-security/kas/kas-security-dm.yml

kasの実行

kasを使用してビルドを実行する。コマンドはビルドディレクトリではなく~/yocto/kas-securityで実行する。

$ kas build ./meta-security/kas/kas-security-dm.yml

動作確認

普通にqemuを実行

普通に実行してみる。

$ source ./poky/oe-init-build-env
$ runqemu nographic

下記のように「Device /dev/vda is not a valid VERITY device.」となり、ルートFSのデバイスとなる/dev/vdaが正しいVERITYデバイスではないというエラーになる。

...(snip)...
realpath: /dev/disk/by-partuuid//dev/vda: No such file or directory
Device /dev/vda is not a valid VERITY device.
[    4.375051] /dev/mapper/rootfs: Can't open blockdev
mount: /rootfs: special device /dev/mapper/rootfs does not exist.
...(snip)...

正しいverityデバイスを指定

$ source ./poky/oe-init-build-env #設定済みであれば不要
$ runqemu nographic ./tmp/deploy/images/qemux86-64/core-image-minimal-qemux86-64.ext4.verity

実行結果

...(snip)...
Poky (Yocto Project Reference Distro) 4.1+snapshot-fb1853c66ce901d03a45f6dbef549b66bb94279d qemux86-64 /dev/ttyS0

qemux86-64 login: root
root@qemux86-64:~# mount | grep 'on / '
/dev/mapper/rootfs on / type ext4 (ro,relatime)

ログイン可能となっており、/dev/mapper/rootfs/としてマウントされている。

meta-securityが提供するdm-verityの機能

必要パッケージのレシピなどを除いて、meta-securityでは次のdm-veirtyの機能を提供している。

  • dm-verity-img.bbclass
  • dm-verity-image-initramfs.bb

dm-verity-img.bbclass

このクラスでは主に下記のことを行う。

  1. DM_VERITY_IMAGEで指定されたcore-image-minimalなどのイメージに対応するハッシュデータの作成
  2. ハッシュデータをイメージの末尾に結合した.verityファイルの作成
  3. ハッシュデータを検証するためのルートハッシュを含むenvファイルの作成

このクラスはconfファイルなどで、IMAGE_CLASSES += "dm-verity-img"された場合に自動的にinheritされるため、直接inheritしない。

普通にrunqemuした際に、ルートFSが「Device /dev/vda is not a valid VERITY device.」とエラーになったのは、 1と2の作用によるものとなっている。

このクラスの機能は、dm-verityによる検証に必要なデータを作成するためのもので、検証する機能は含まれていない。

3で作成されるenvファイルにはルートハッシュなどが含まれている。このファイルが自由に参照されてしまうと dm-verityでの検証は意味をなさなくなってしまうため、このファイル自体に署名などを行いセキュリティチェックを行うか、 安全なストレージに格納される必要がある。

dm-verity-image-initramfs.bb

このレシピでは、dm-verity-img.bbclassで作成されたenvファイルをinitramfsイメージに取り込み、 ルートFSのマウント時にinitramfs上で検証するという機能を提供する。

実際に検証を行うのは、initramfs-module-dmverityで提供される80-dmverityとなっている。 検証用スクリプトを入れるだけであれば、core-image-minimal-initramfsにinitramfs-module-dmverityすれば行けそうであるが、 envファイルをinitramfsに取り込む処理は別途実装する必要が出てくるので、dm-verity-image-initramfsを使用するほうが無難そう。

また、80-dmverityはルートファイルシステムをリードオンリーでマウントするため、書き込み領域が必要であれば、 overlayfsなどを使用して別途実装する必要がある。

このinitramfsではenvファイルに対して署名検証などは行っていないため、実践的な環境で使うためにはenvファイルへの署名検証のプロセスを追加するか、このinitramfs自体を何らかの形で署名検証しセキュアにする必要がある。

まとめ

YoctoProjectでルートFSをdm-verityする方法としてmeta-securityを紹介した。 qemu環境とはなるが、簡単に実行可能な環境を作成する方法としてkas-security-dm.ymlを使用するというものがある。 実践的な環境でこれらの機能を使用するためには、dm-verity-img.bbclassは問題なく使用可能であると思うが、 envファイルの管理上の問題からdm-verity-image-initramfs.bbはそのまま使用する場合は、initramfsを他の何らかの仕組みでセキュアに保つ必要がありそうだ。 また、ルートFSがリードオンリーになるため、書き込み領域が必要な場合は別途実装が必要となる。

YoctoProject ラズパイ4でdocker

はじめに

筆者がDEBIXでぐずぐずやっている間にTLに下記のようなものが流れてきた。

このお方は必要であれば放っておいても自力でどうにかされるのだが、いいお題なので試してみる。

meta-virtualization

xenやらlxcやら仮想化の機能を詰め込んだレイヤがmeta-virtualizationである。もちろんこの中にdocker-ceも含まれている。 これは基本的にBSP層は関係ないので持ってきたら動かせるはず。

ただし、カーネルの機能には依存しているので、プラットフォームによってはコンフィグなどは調整する必要があるかもしれない。

とりあえず、今回はラズベリーパイ4を使用してdockerを動かしてみる。 YoctoProjectのブランチはkirkstoneを使用する。

環境構築

作業環境

$ mkdir -p ~/yocto/rpi-kirkstone
$ cd ~/yocto/rpi-kirkstone

pokyの取得

$ git clone git://git.yoctoproject.org/poky.git -b kirkstone 

環境変数の設定

$ source poky/oe-init-build-env

meta-raspberrypiの取得

$ bitbake-layers layerindex-fetch meta-raspberrypi

meta-virtualization

dockerを使用するためにmeta-virtualizationを取得しビルド対象に含める。依存する他のレイヤも一緒に引っ張ってくる。

$ bitbake-layers layerindex-fetch meta-virtualization meta-python meta-networking meta-filesystems meta-oe

local.confを編集

MACHINE = "raspberrypi4-64"
DL_DIR = "${TOPDIR}/../downloads"

# systemd
DISTRO_FEATURES:append = " systemd pam"
VIRTUAL-RUNTIME_init_manager = "systemd"
DISTRO_FEATURES_BACKFILL_CONSIDERED = "sysvinit"
VIRTUAL-RUNTIME_initscripts = ""

# enable uart
ENABLE_UART = "1"

# docker
IMAGE_INSTALL:append = " packagegroup-docker"

ビルド

$ bitbake core-image-base

動作確認

ターゲットはLANか無線LANでインターネットにアクセスできるようにしておく。

シリアルコンソールで実行するとカーネルログもうじゃうじゃ出るが、「Hello from Docker! This message shows that your installation appears to be working correctly.」もきちんと出力されている。

root@raspberrypi4-64:~# docker run hello-world
[30139.948961] docker0: port 1(veth1cf1ac9) entered blocking state
[30139.955135] docker0: port 1(veth1cf1ac9) entered disabled state
[30139.962038] device veth1cf1ac9 entered promiscuous mode
[30139.967491] audit: type=1700 audit(1677102815.507:54): dev=veth1cf1ac9 prom=256 old_prom=0 auid=4294967295 uid=0 gid=0 ses=4294967295
[30139.979792] audit: type=1300 audit(1677102815.507:54): arch=c00000b7 syscall=206 success=yes exit=40 a0=f a1=4000e7d0e0 a2=28 a3=0 items=0 ppid=1 pid=366 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsu)
[30140.010097] audit: type=1327 audit(1677102815.507:54): proctitle=2F7573722F62696E2F646F636B657264002D480066643A2F2F
[30140.896771] eth0: renamed from veth8fd4f92
[30140.935651] IPv6: ADDRCONF(NETDEV_CHANGE): veth1cf1ac9: link becomes ready
[30140.942952] docker0: port 1(veth1cf1ac9) entered blocking state
[30140.949006] docker0: port 1(veth1cf1ac9) entered forwarding state

Hello from Docker!
This message shows that your installation appears to be working correctly.

To generate this message, Docker took the following steps:
 1. The Docker client contacted the Docker daemon.
 2. The Docker daemon pulled the "hello-world" image from the Docker Hub.
    (arm64v8)
 3. The Docker daemon created a new container from that image which runs the
    executable that produces the output you are currently reading.
 4. The Docker daemon streamed that output to the Docker client, which sent it
    to your terminal.

To try something more ambitious, you can run an Ubuntu container with:
 $ docker run -it ubuntu bash

Share images, automate workflows, and more with a free Docker ID:
 https://hub.docker.com/

For more examples and ideas, visit:
 https://docs.docker.com/get-started/

[30141.280346] docker0: port 1(veth1cf1ac9) entered disabled state
[30141.286936] veth8fd4f92: renamed from eth0
[30141.367995] docker0: port 1(veth1cf1ac9) entered disabled state
[30141.378777] device veth1cf1ac9 left promiscuous mode
[30141.383899] docker0: port 1(veth1cf1ac9) entered disabled state
[30141.383960] audit: type=1700 audit(1677102816.923:55): dev=veth1cf1ac9 prom=0 old_prom=256 auid=4294967295 uid=0 gid=0 ses=4294967295
[30141.426246] audit: type=1300 audit(1677102816.923:55): arch=c00000b7 syscall=206 success=yes exit=32 a0=f a1=40003c5020 a2=20 a3=0 items=0 ppid=1 pid=366 auid=4294967295 uid=0 gid=0 euid=0 suid=0 fsu)
[30141.453833] audit: type=1327 audit(1677102816.923:55): proctitle=2F7573722F62696E2F646F636B657264002D480066643A2F2F
root@raspberrypi4-64:~#

まとめ

YoctoProject環境でもdockerは動く。

YoctoProject DEBIX Model Aのカーネルを5.15に対応する

はじめに

DEBIX Model AをYoctoProjectで使いやすくするためにmeta-debixを作成した。

u-bootとカーネルは、DebixのGitHubリポジトリで公開されているものを使用していた。 それでは下記のような問題がある。

  • カーネルやu-bootのバージョンがあげられない
  • YoctoProjectのバージョンをあげたときにGPUドライバなどが使用できなくなる

imx-yocto-bspのカーネルとu-bootをDEBIX Model Aに対応するために、meta-debixにimx8mp-debix-aというマシンを定義する。 imx8mp-debix-aのポーティングは、DebixのGitHubリポジトリの修正をもとに筆者が独自に行う。

使用するYoctoProjectバージョン、マシンとカーネル、u-bootのバージョンの関係を以下に示す。

マシン カーネル u-boot YPバージョン
debix-a 5.10 2021.04 hardknott, kirkstone
imx8mp-debix-a 5.15 2022.04 kirkstone

DEBIX Model Aのモデルによって搭載されているペリフェラルに差異があるが、最低限オプションボードなどなしで、動かないと問題がありそうなペリフェラルだけに対応する。

現状で考えられるのは下記のペリフェラル

今回購入したのがeMMCなしのバージョンであることもあり、下記のペリフェラルはとりあえず対応しない。

特に無線関連は技適の問題もある。

対応状況

なにもパッチをあてない状態でどの程度動作するかを確認する。

ペリフェラル 動作 対応範囲
SDカード OK -
UART OK -
LPDDR4 NG u-boot
LAN(EQOS) NG u-boot
USB3.0 NG カーネル
HDMI OK

幸いなことにSDカードとUARTはリファレンスボードから変更が無い構成であるため、 比較的作業を開始しやすい。 このあたりが変更されている場合、回路図やデータシートなどが必要になってしまう。

LPDDR4に関してはタイミング設定のパラメータなどは基本的にツールで出力されたものをそのまま取り込むようにするはずなので、 DEBIXのリポジトリのものをそのまま取り込む。

LANとUSB3.0は必ずしも対応しなくてもよいが、無いといろいろ不便なので対応しておきたい。

作業手順

  • マシン定義の追加
  • u-bootのレシピ作成
  • カーネルのレシピ作成

今回はソースコードリポジトリはimx-yocto-bspのままでDEBIX Model Aに対応するため、 まずはhardknottで使用しているバージョンのリポジトリを比較し差分を調査してみる。

マシン定義の追加

すでにDEBIX Model A用に定義したdebix-aとは区別できるようにマシン定義を追加する。 imx-yocto-bspのカーネル、u-bootをベースにすることがわかりやすいように、imx8mp-debix-aとする。

u-bootのレシピ作成

u-bootでのリファレンスボードからの変更は下記のようになっている。

  1. LPDDR4
  2. LAN(EQOS)

LPDDR4

前述の通り、LPDDR4に関してはタイミング設定のパラメータなどは基本的にツールで出力されたものをそのまま取り込むようにするはずなので、 DEBIXのリポジトリのものをそのまま取り込むしか無い。

ただし使用するクロックの定義が足りていなかったので追加している。 これらの変更は両方ともdebixのリポジトリのものを参考にしている。

また、メモリのサイズも異なっているのでそれを調整するための修正も行っている。

LAN(EQOS)

MDIOで接続されるPHYのアドレスが変更されているのでそれに伴う修正を行う。 リセット信号の制御ピンが変更されているので、こちらも対応する。

また、u-bootのドライバがリセットピンの制御を簡略化したようでphy-reset-gpiosのプロパティが効かなくなっているので、 対応する必要がある。 debixのリポジトリでは、ドライバに直接修正を行いリセットピンが常にアクティブになるようになっている。

これらのことを踏まえて、リセットピンであるGPIO4_IO18に対してgpio-hogの機能を使用して、信号を出し続けるように設定変更する。

diff --git a/arch/arm/dts/imx8mp-evk.dts b/arch/arm/dts/imx8mp-evk.dts
index 61e8a70196..b2938d3075 100644
--- a/arch/arm/dts/imx8mp-evk.dts
+++ b/arch/arm/dts/imx8mp-evk.dts
@@ -130,10 +130,12 @@
        #address-cells = <1>;
        #size-cells = <0>;
 
-      ethphy0: ethernet-phy@1 {
+       ethphy0: ethernet-phy@0 {
            compatible = "ethernet-phy-ieee802.3-c22";
-          reg = <1>;
-          eee-broken-1000t;
+           reg = <0>;
+           at803x,led-act-blind-workaround;
+           at803x,eee-disabled;
+           at803x,vddio-1p8v;
        };
    };
 };
@@ -151,20 +153,33 @@
    phy-mode = "rgmii-id";
    phy-handle = <&ethphy1>;
    fsl,magic-packet;
-  status = "okay";
+   status = "disabled";
 
    mdio {
        #address-cells = <1>;
        #size-cells = <0>;
 
-      ethphy1: ethernet-phy@1 {
+       ethphy1: ethernet-phy@0 {
            compatible = "ethernet-phy-ieee802.3-c22";
-          reg = <1>;
-          eee-broken-1000t;
+           reg = <0>;
+           at803x,led-act-blind-workaround;
+           at803x,eee-disabled;
+           at803x,vddio-1p8v;
        };
    };
 };
 
+&gpio4 {
+   eqos-reset-hog {
+       gpio-hog;
+       gpios = <18 GPIO_ACTIVE_HIGH>;
+       output-high;
+       line-name = "eqos-reset";
+       pinctrl-names = "default";
+       pinctrl-0 = <&pinctrl_reg_eqos>;
+   };
+};
+
 &flexspi {
    pinctrl-names = "default";
    pinctrl-0 = <&pinctrl_flexspi0>;
@@ -505,7 +520,12 @@
            MX8MP_IOMUXC_ENET_TD3__ENET_QOS_RGMII_TD3       0x1f
            MX8MP_IOMUXC_ENET_TX_CTL__ENET_QOS_RGMII_TX_CTL 0x1f
            MX8MP_IOMUXC_ENET_TXC__CCM_ENET_QOS_CLOCK_GENERATE_TX_CLK   0x1f
-          MX8MP_IOMUXC_SAI2_RXC__GPIO4_IO22       0x19
+       >;
+   };
+
+   pinctrl_reg_eqos: eqosreggrp {
+       fsl,pins = <
+           MX8MP_IOMUXC_SAI1_TXD6__GPIO4_IO18  0x19
        >;
    };
 
@@ -525,7 +545,14 @@
            MX8MP_IOMUXC_SAI1_TXD3__ENET1_RGMII_TD3     0x1f
            MX8MP_IOMUXC_SAI1_TXD4__ENET1_RGMII_TX_CTL  0x1f
            MX8MP_IOMUXC_SAI1_TXD5__ENET1_RGMII_TXC     0x1f
-          MX8MP_IOMUXC_SAI1_RXD0__GPIO4_IO02      0x19
+           MX8MP_IOMUXC_SAI1_RXD1__ENET1_1588_EVENT1_OUT   0x1f
+           MX8MP_IOMUXC_SAI1_RXD0__ENET1_1588_EVENT1_IN    0x1f
+       >;
+   };
+
+   pinctrl_reg_fec: fecreggrp {
+       fsl,pins = <
+           MX8MP_IOMUXC_SAI1_TXD7__GPIO4_IO19  0x19
        >;
    };

カーネルのレシピ作成

カーネルでのリファレンスボードからの変更はいくつもあるようだが、現時点で対応するのはUSB3.0ハブのみとする。

USB3.0ハブ

USB3.0もdebixのリポジトリでは、リセットピンと、電源ピンをアクティブに固定するような修正が入っている。 いろいろ試した結果、電源ピンだけアクティブに固定すればUSB3.0が動作しているようなので、こちらもgpio-hogで対応する。

バイスツリーのファイルをimx8mp-debix-a.dtsとして新たに作成し、こちらを使用する。

+diff --git a/arch/arm64/boot/dts/freescale/Makefile b/arch/arm64/boot/dts/freescale/Makefile
+index 9a7319c6b4e3..3a6f6b9ae138 100644
+--- a/arch/arm64/boot/dts/freescale/Makefile
++++ b/arch/arm64/boot/dts/freescale/Makefile
+@@ -115,6 +115,7 @@ dtb-$(CONFIG_ARCH_MXC) += imx8mp-evk.dtb imx8mp-evk-rm67191.dtb imx8mp-evk-it626
+             imx8mp-evk-hifiberry-dac2.dtb \
+             imx8mp-evk-usdhc1-m2.dtb imx8mp-evk-rm67199.dtb \
+             imx8mp-evk-dpdk.dtb imx8mp-evk-8mic-swpdm.dtb imx8mp-evk-rpmsg-lpv.dtb imx8mp-evk-revA3-8mic-revE.dtb
++dtb-$(CONFIG_ARCH_MXC) += imx8mp-debix-a.dtb
+ dtb-$(CONFIG_ARCH_MXC) += imx8mp-phyboard-pollux-rdk.dtb
+ dtb-$(CONFIG_ARCH_MXC) += imx8mq-evk.dtb imx8mq-evk-rpmsg.dtb imx8mp-ab2.dtb
+ dtb-$(CONFIG_ARCH_MXC) += imx8mp-ddr4-evk.dtb
+diff --git a/arch/arm64/boot/dts/freescale/imx8mp-debix-a.dts b/arch/arm64/boot/dts/freescale/imx8mp-debix-a.dts
+new file mode 100644
+index 000000000000..e26e9209a4c8
+--- /dev/null
++++ b/arch/arm64/boot/dts/freescale/imx8mp-debix-a.dts
+@@ -0,0 +1,40 @@
++// SPDX-License-Identifier: (GPL-2.0+ OR MIT)
++/*
++ * Copyright 2019 NXP
++ * Copyright 2023 Yusuke Mitsuki <mickey.happygolucky@gmail.com>
++ */
++
++/dts-v1/;
++
++#include "imx8mp-evk.dts"
++
++/ {
++  model = "DEBIX Model A board";
++
++  memory@40000000 {
++      device_type = "memory";
++      reg = <0x0 0x40000000 0 0x80000000>;
++  };
++};
++
++&usb_dwc3_1 {
++  dr_mode = "host";
++  status = "okay";
++};
++
++&gpio4 {
++  eqos-reset-hog {
++      gpio-hog;
++      gpios = <26 GPIO_ACTIVE_HIGH>;
++      output-high;
++      line-name = "dwc3-vbus";
++      pinctrl-names = "default";
++      pinctrl-0 = <&pinctrl_usb1_vbus>;
++  };
++};
++
++&pinctrl_usb1_vbus {
++  fsl,pins = <
++      MX8MP_IOMUXC_SAI2_TXD0__GPIO4_IO26  0x19
++  >;
++};
+-- 
+2.25.1

ビルド・動作確認

imx-yocto-bspの5.15ベースのカーネルを使用するようにしたので、GPUドライバも使用可能となっている。 kirkstoneで5.10ベースのカーネルを使用する際の制限はなくなっているため、waylandなども使用できるようになっている。

一方でMIPIカメラなどのドライバは未対応となっているため、別途実装が必要になる可能性がある。

imx-image-full

imx-image-fullを作成する。

$ bitbake imx-image-full

westonとQt6ベースのデモアプリが動作している。

まとめ

DebixのGitHubリポジトリとimx-yocto-bspのソースコードを比較してみると、 Debix対応のために直接ソースコードを修正しているが、修正内容を精査するとデバイスツリーとコンフィグの修正だけで対応できるものが多いことがわかった。 今回の対応は基本的に電源やリセットの信号線をアクティブにする修正しか行っていない。

この様な対応でDEBIX Model Aで、5.15ベースのカーネルでもが使用できることがわかった。 GPU関連の機能も問題なく使用できているようだ。

本稿で記載した修正内容は抜粋であるため、ビルド可能なレイヤはGitHubのmeta-debixに格納してある。

DEBIX Model Aは比較的安価なi.MX8M Plus搭載のボードであるため、 5.15カーネルで動作できるようになったことで、活用の幅が広がれば良いなと思っている。

YoctoProject meta-debixをkirkstoneに対応する

はじめに

YoctoProject DEBIX Model Aを動かすで作成したmeta-debixはhardknottのみに対応しているがkirkstoneなどでも使用したい。

カーネルとu-bootはdebix提供のものに固定してkirkstoneに対応する。

そのためには下記のようなことを行う。

  • u-boot,kernelのレシピを分離
  • PREFERRED_PROVIDERを分離したレシピに向ける
  • PREFERRED_VERSIONを分離したレシピのものに設定

環境構築

作業ディレクト

$ mkdir -p ~/yocto/debix-kirkstone
$ cd ~/yocto/debix-kirkstone

ダウンロード

repoツールで環境をダウンロードする。

$ repo init -u https://github.com/nxp-imx/imx-manifest -b imx-linux-kirkstone -m imx-5.15.71-2.2.0.xml
$ repo sync

初期セットアップ

imx-yocto-bsp特有の初期セットアップ

$ DISTRO=fsl-imx-wayland MACHINE=imx8mp-lpddr4-evk source imx-setup-release.sh -b build

EULAが表示されるので最後まで読んでyを入力する。

2回目以降

別の端末を開いて、すでに作成されてビルドディレクトリを使用する場合は下記を実行する。

$ source setup-environment build

これらはimx-yocto-bspの独特なお作法となる。

レイヤの作成

レイヤは前回作成したものをベースに作業する。

$ cp -ra ~/yocto/debix-hardknott/sources/meta-debix ~/yocto/debix-kirkstone/sources 

LAYERSERIES_COMPATの変更

kirkstoneでビルド可能なようにconf/layer.confLAYERSERIES_COMPATの値を変更する。

-LAYERSERIES_COMPAT_meta-debix = "hardknott"
+LAYERSERIES_COMPAT_meta-debix = "kirkstone"

u-boot

レシピの作成

u-boot-imx_2021.04.bbappendu-boot-debix_2021.04.bbにリネームする。

$ pushd ../sources/meta-debix/recipes-bsp/u-boot
$ mv u-boot-imx_2021.04.bbappend u-boot-debix_2021.04.bb
$ popd

下記の内容に変更する。

# Copyright (C) 2013-2016 Freescale Semiconductor
# Copyright 2018 (C) O.S. Systems Software LTDA.
# Copyright 2017-2021 NXP
# Copyright 2023 Yusuke Mitsuki <mickey.happygolucky@gmail.com>

require recipes-bsp/u-boot/u-boot.inc

DESCRIPTION = "i.MX U-Boot suppporting DEBIX Model A board."

LICENSE = "GPLv2+"
LIC_FILES_CHKSUM = "file://Licenses/gpl-2.0.txt;md5=b234ee4d69f5fce4486a80fdaf4a4263"

PROVIDES = "virtual/bootloader u-boot"

UBOOT_SRC ?= "git://github.com/debix-tech/uboot.git;protocol=https"
SRCBRANCH = "lf_v2021.04"
SRC_URI = "${UBOOT_SRC};branch=${SRCBRANCH}"
SRCREV = "1a87b972fac74699482e2dce2023b66358d8c4f5"

LOCALVERSION = "-${SRCBRANCH}"

DEPENDS += "flex-native bison-native bc-native dtc-native"

S = "${WORKDIR}/git"
B = "${WORKDIR}/build"

inherit fsl-u-boot-localversion

BOOT_TOOLS = "imx-boot-tools"


do_deploy:append:debix-a() {
    # Deploy u-boot-nodtb.bin and fsl-imx8m*-XX.dtb for mkimage to generate boot binary
    if [ -n "${UBOOT_CONFIG}" ]
    then
        for config in ${UBOOT_MACHINE}; do
            i=$(expr $i + 1);
            for type in ${UBOOT_CONFIG}; do
                j=$(expr $j + 1);
                if [ $j -eq $i ]
                then
                    install -d ${DEPLOYDIR}/${BOOT_TOOLS}
                    install -m 0777 ${B}/${config}/arch/arm/dts/${UBOOT_DTB_NAME}  ${DEPLOYDIR}/${BOOT_TOOLS}
                    install -m 0777 ${B}/${config}/u-boot-nodtb.bin  ${DEPLOYDIR}/${BOOT_TOOLS}/u-boot-nodtb.bin-${MACHINE}-${type}
                fi
            done
            unset  j
        done
        unset  i
    fi
}

UBOOT_TAGGED_BINARY ?= "u-boot-tagged.${UBOOT_SUFFIX}"

deploy_tag() {
    # Append a tag to the bootloader image used in the SD card image
    cp ${UBOOT_BINARY} ${UBOOT_TAGGED_BINARY}
    ln -sf ${UBOOT_TAGGED_BINARY} ${UBOOT_BINARY}
    stat -L -cUUUBURNXXOEUZX7+A-XY5601QQWWZ%sEND ${UBOOT_BINARY} >> ${UBOOT_BINARY}
}

do_deploy:append:debix-a() {
    deploy_tag
}

PACKAGE_ARCH = "${MACHINE_ARCH}"
COMPATIBLE_MACHINE = "debix-a"

UBOOT_NAME:debix-a = "u-boot-${MACHINE}.bin-${UBOOT_CONFIG}"

meta-imx/meta-bsp/recipes-bsp/u-boot/u-boot-imx_2021.04.bbをベースに下記の修正を行っている。

  1. u-boot-imx-common_${PV}.incの内容を直接取り込む
  2. UBOOT_SRC、SRCREVをdebixに向ける
  3. オーバーライドのシンタックスを新書式に対応
  4. mx8mなどのオーバーライドをdebix-aに変更

マシン定義の修正

conf/machine/debix-a.confにu-boot定義のオーバーライドを追加する。

IMX_DEFAULT_BOOTLOADER:debix-a = "u-boot-debix"
PREFERRED_PROVIDER_virtual/bootloader:debix-a = "u-boot-debix"

=演算子で値を束縛していても、オーバーライドすれば書き換え可能。 local.confなどでは書き換えさせたくないが、マシンごとに値を切り替えたい場合などは有効。

カーネル

レシピの作成

linux-imx_5.10.bbappendlinux-debix_5.10.bbにリネームする。

$ pushd ../sources/meta-debix/recipes-kernel/linux
$ linux-imx_5.10.bbappend linux-debix_5.10.bb
$ mv linux-imx linux-debix
$ popd

下記の内容に変更する。

# Copyright (C) 2013-2016 Freescale Semiconductor
# Copyright 2017-2022 NXP
# Copyright 2023 Yusuke Mitsuki <mickey.happygolucky@gmail.com>
# Released under the MIT license (see COPYING.MIT for the terms)
#
# SPDX-License-Identifier: MIT
#

SUMMARY = "Linux Kernel provided and supported by NXP"
DESCRIPTION = "Linux Kernel provided and supported by NXP with focus on \
i.MX Family Reference Boards. It includes support for many IPs such as GPU, VPU and IPU."

require recipes-kernel/linux/linux-imx.inc

LICENSE = "GPL-2.0-only"
LIC_FILES_CHKSUM = "file://COPYING;md5=6bc538ed5bd9a7fc9398086aedcd7e46"

DEPENDS += "lzop-native bc-native"

SRCBRANCH = "debix"
LOCALVERSION = "-lts-next"
KERNEL_SRC ?= "git://github.com/debix-tech/linux;protocol=https;branch=${SRCBRANCH}"
KBRANCH = "${SRCBRANCH}"
SRC_URI = "${KERNEL_SRC} \
  file://0001-linux-imx-fix-tar-option.patch"

SRCREV = "f924d76e63c153f58206425d31f88c5771caeb80"

# PV is defined in the base in linux-imx.inc file and uses the LINUX_VERSION definition
# required by kernel-yocto.bbclass.
#
# LINUX_VERSION define should match to the kernel version referenced by SRC_URI and
# should be updated once patchlevel is merged.
LINUX_VERSION = "5.10.72"

KERNEL_CONFIG_COMMAND = "oe_runmake_call -C ${S} CC="${KERNEL_CC}" O=${B} olddefconfig"

DEFAULT_PREFERENCE = "1"

DO_CONFIG_V7_COPY = "no"
DO_CONFIG_V7_COPY:debix-a = "no"

# Add setting for LF Mainline build
IMX_KERNEL_CONFIG_AARCH32 = "imx_v7_defconfig"
IMX_KERNEL_CONFIG_AARCH64 = "imx_v8_defconfig"
KBUILD_DEFCONFIG ?= ""
KBUILD_DEFCONFIG:debix-a= "${IMX_KERNEL_CONFIG_AARCH64}"

# Use a verbatim copy of the defconfig from the linux-imx repo.
# IMPORTANT: This task effectively disables kernel config fragments
# since the config fragments applied in do_kernel_configme are replaced.
addtask copy_defconfig after do_kernel_configme before do_kernel_localversion
do_copy_defconfig () {
    install -d ${B}
    if [ ${DO_CONFIG_V7_COPY} = "yes" ]; then
        # copy latest IMX_KERNEL_CONFIG_AARCH32 to use for mx6, mx6ul and mx7
        mkdir -p ${B}
        cp ${S}/arch/arm/configs/${IMX_KERNEL_CONFIG_AARCH32} ${B}/.config
    else
        # copy latest IMX_KERNEL_CONFIG_AARCH64 to use for mx8
        mkdir -p ${B}
        cp ${S}/arch/arm64/configs/${IMX_KERNEL_CONFIG_AARCH64} ${B}/.config
    fi
}

DELTA_KERNEL_DEFCONFIG ?= ""
#DELTA_KERNEL_DEFCONFIG:mx8-nxp-bsp = "imx.config"

do_merge_delta_config[dirs] = "${B}"
do_merge_delta_config[depends] += " \
    flex-native:do_populate_sysroot \
    bison-native:do_populate_sysroot \
"
do_merge_delta_config() {
    for deltacfg in ${DELTA_KERNEL_DEFCONFIG}; do
        if [ -f ${S}/arch/${ARCH}/configs/${deltacfg} ]; then
            ${KERNEL_CONFIG_COMMAND}
            oe_runmake_call -C ${S} CC="${KERNEL_CC}" O=${B} ${deltacfg}
        elif [ -f "${WORKDIR}/${deltacfg}" ]; then
            ${S}/scripts/kconfig/merge_config.sh -m .config ${WORKDIR}/${deltacfg}
        elif [ -f "${deltacfg}" ]; then
            ${S}/scripts/kconfig/merge_config.sh -m .config ${deltacfg}
        fi
    done
    cp .config ${WORKDIR}/defconfig
}
addtask merge_delta_config before do_kernel_localversion after do_copy_defconfig

do_kernel_configcheck[noexec] = "1"

KERNEL_VERSION_SANITY_SKIP="1"
COMPATIBLE_MACHINE = "debix-a"

meta-imx/meta-bsp/recipes-kernel/linux/linux-imx_5.15.bbをベースに下記の修正を行っている。

  1. KERNEL_SRCなどの変数をdebixに向ける
  2. mx8などのオーバーライドをdebix-aに変更

マシン定義の修正

conf/machine/debix-a.confにカーネル定義のオーバーライドを追加し、KERNEL_DEVICETREEの値を変更する。

diff --git a/conf/machine/debix-a.conf b/conf/machine/debix-a.conf
index b603365..6029e14 100644
--- a/conf/machine/debix-a.conf
+++ b/conf/machine/debix-a.conf
@@ -4,6 +4,8 @@ require conf/machine/imx8mp-lpddr4-evk.conf
 IMX_DEFAULT_BOOTLOADER:debix-a = "u-boot-debix"
 PREFERRED_PROVIDER_virtual/bootloader:debix-a = "u-boot-debix"
 
+PREFERRED_PROVIDER_virtual/kernel:debix-a = "linux-debix"
+
 KERNEL_DEVICETREE:remove:debix-a = " \
        freescale/imx8mp-evk-dsp.dtb \
        freescale/imx8mp-evk-ecspi-slave.dtb \
@@ -35,4 +37,11 @@ KERNEL_DEVICETREE:remove:debix-a = " \
        freescale/imx8mp-evk-sof-wm8960.dtb \
        freescale/imx8mp-evk-spdif-lb.dtb \
        freescale/imx8mp-evk-usdhc1-m2.dtb \
+       freescale/imx8mp-evk-dpdk.dtb \
+       freescale/imx8mp-evk-dual-os08a20.dtb \
+       freescale/imx8mp-evk-os08a20.dtb \
+       freescale/imx8mp-evk-os08a20-ov5640.dtb \
+       freescale/imx8mp-evk-revA3-8mic-revE.dtb \
+       freescale/imx8mp-evk-rpmsg-lpv.dtb \
+       freescale/imx8mp-evk-8mic-swpdm.dtb \
 "

ビルド

local.confの修正

local.confに下記を追加する。

MACHINE ?= "debix-a"
IMAGE_ISNTALL:append = " linux-debix-modules"

bitbake

core-image-minimalをビルドする。

$ bitbake core-image-minimal

動作確認

NXP i.MX Release Distro 5.15-kirkstone debix-a ttymxc1

debix-a login: root
Last login: Thu Apr 28 17:43:14 UTC 2022 on ttymxc1
root@debix-a:~# uname -a
Linux debix-a 5.10.72+g158599ad1 #1 SMP PREEMPT Tue Jan 10 10:28:10 UTC 2023 aarch64 GNU/Linux
root@debix-a:~# cat /etc/os-release
ID=fsl-imx-wayland
NAME="NXP i.MX Release Distro"
VERSION="5.15-kirkstone (kirkstone)"
VERSION_ID=5.15-kirkstone
PRETTY_NAME="NXP i.MX Release Distro 5.15-kirkstone (kirkstone)"
DISTRO_CODENAME="kirkstone"
root@debix-a:~#

OSのバージョンはkirkstoneで、カーネルバージョンは5.10.72+g158599ad1となっている。

まとめ

meta-debixを修正して、kirkstoneに対応した。

カーネルとu-bootはそれぞれパッケージ名を変更し、 imx-yocto-bspで提供しているカーネルやu-bootとは分離している。

バージョンを固定することでカーネルなどが古いままになってしまうため、ドライバがバイナリ提供されているGPUなどの一部機能はそのままでは使用できない。

ただ、このような移植は、YoctoProject非対応のカーネルやu-bootを対応するケースなどのちょうどよいトレーニングになると思う。