はじめに
Kria KV 260 Vision AI Starter Kit (以下 KV260) の System On Module(以下 SOM) 上には QSPI に接続されたフラッシュメモリがあります。『KV260 が Linux をブートするまでのシーケンス』 で説明したように、KV160 のプライマリーブートデバイスは、この QSPI 上のフラッシュメモリです。この記事では、このフラッシュメモリを Linux から読む方法について説明します。
QSPI のデバイスツリー
KV260 の QSPI 関連のデバイスツリーは次のようになっています。
spi@ff0f0000 {
u-boot,dm-pre-reloc;
compatible = "xlnx,zynqmp-qspi-1.0";
status = "okay";
clock-names = "ref_clk" "pclk";
interrupts = <0x00 0x0f 0x04>;
interrupt-parent = <0x04>;
num-cs = <0x01>;
reg = <0x00 0xff0f0000 0x00 0x1000 0x00 0xc0000000 0x00 0x8000000>;
#address-cells = <0x01>;
#size-cells = <0x00>;
#stream-id-cells = <0x01>;
iommus = <0x0d 0x873>;
power-domains = <0x0c 0x2d>;
clocks = <0x03 0x35 0x03 0x1f>;
is-dual = <0x00>;
spi-rx-bus-width = <0x04>;
spi-tx-bus-width = <0x04>;
phandle = <0x6d>;
flash@0 {
compatible = "mt25qu512a" "jedec,spi-nor";
#address-cells = <0x01>;
#size-cells = <0x01>;
reg = <0x00>;
spi-tx-bus-width = <0x01>;
spi-rx-bus-width = <0x04>;
spi-max-frequency = <0x2625a00>;
partition@0 {
label = "Image Selector";
reg = <0x00 0x80000>;
read-only;
lock;
};
partition@80000 {
label = "Image Selector Golden";
reg = <0x80000 0x80000>;
read-only;
lock;
};
partition@100000 {
label = "Persistent Register";
reg = <0x100000 0x20000>;
};
partition@120000 {
label = "Persistent Register Backup";
reg = <0x120000 0x20000>;
};
partition@140000 {
label = "Open_1";
reg = <0x140000 0xc0000>;
};
partition@200000 {
label = "Image A (FSBL, PMU, ATF, U-Boot)";
reg = <0x200000 0xd00000>;
};
partition@f00000 {
label = "ImgSel Image A Catch";
reg = <0xf00000 0x80000>;
read-only;
lock;
};
partition@f80000 {
label = "Image B (FSBL, PMU, ATF, U-Boot)";
reg = <0xf80000 0xd00000>;
};
partition@1c80000 {
label = "ImgSel Image B Catch";
reg = <0x1c80000 0x80000>;
read-only;
lock;
};
partition@1d00000 {
label = "Open_2";
reg = <0x1d00000 0x100000>;
};
partition@1e00000 {
label = "Recovery Image";
reg = <0x1e00000 0x200000>;
read-only;
lock;
};
partition@2000000 {
label = "Recovery Image Backup";
reg = <0x2000000 0x200000>;
read-only;
lock;
};
partition@2200000 {
label = "U-Boot storage variables";
reg = <0x2200000 0x20000>;
};
partition@2220000 {
label = "U-Boot storage variables backup";
reg = <0x2220000 0x20000>;
};
partition@2240000 {
label = "SHA256";
reg = <0x2240000 0x10000>;
read-only;
lock;
};
partition@2250000 {
label = "User";
reg = <0x2250000 0x1db0000>;
};
};
};
QSPI を直接制御するデバイスドライバは Xilinx が提供する drivers/spi/spi-zynqmp-gqspi.c です。ただし、このデバイスドライバを直接使ってフラッシュメモリにアクセスするわけではありません。その上に Memory Technology Device (以下 MTD) があって、この MTD デバイスドライバを使ってユーザーアプリケーションから QSPI に接続されているフラッシュメモリを読み書きします。
なお、このデバイスツリーにフラッシュメモリの各パーティション情報(名前、開始位置、サイズ、属性) が定義されています。
フラッシュメモリのパーティションとデバイス名
前述のデバイスツリーを使って KV260 をブートすると、各々のパーティションが次のようなデバイスとして見えるようになります。
デバイス名 | 開始位置 | サイズ | 説明 |
---|---|---|---|
/dev/mtd0 | 0x0000_00000 | 0x0080_0000 | Image Selector |
/dev/mtd1 | 0x0008_00000 | 0x0080_0000 | Image Selector Golden |
/dev/mtd2 | 0x0010_00000 | 0x0002_0000 | Persistent Register |
/dev/mtd3 | 0x0012_00000 | 0x0002_0000 | Persistent Register Backup |
/dev/mtd4 | 0x0014_00000 | 0x000C_0000 | Open_1 |
/dev/mtd5 | 0x0020_00000 | 0x00D0_0000 | Image A (FSBL, PMU, ATF, U-Boot) |
/dev/mtd6 | 0x00F0_00000 | 0x0008_0000 | IMGSel Image A Cache |
/dev/mtd7 | 0x00F8_00000 | 0x00D0_0000 | Image B (FSBL, PMU, ATF, U-Boot) |
/dev/mtd8 | 0x01C8_00000 | 0x0008_0000 | IMGSel Image B Cache |
/dev/mtd9 | 0x01D0_00000 | 0x0010_0000 | Open_2 |
/dev/mtd10 | 0x01E0_00000 | 0x0020_0000 | Recovery Image |
/dev/mtd11 | 0x0200_00000 | 0x0020_0000 | Recovery Image Backup |
/dev/mtd12 | 0x0220_00000 | 0x0002_0000 | U-Boot Storage variables |
/dev/mtd13 | 0x0222_00000 | 0x0002_0000 | U-Boot Storage variables Backup |
/dev/mtd14 | 0x0224_00000 | 0x0001_0000 | SHA256 |
/dev/mtd15 | 0x0225_00000 | 0x01DB_0000 | User |
QSPI のフラッシュメモリには Image A と Image B と呼ばれる二つの BOOT.BIN が格納されています。例えば、次のようにして Image A の BOOT.BIN をファイルに書き出すことができます。
shell$ sudo dd if=/dev/mtd7 of=boot_a.bin bs=1024
13312+0 records in
13312+0 records out
13631488 bytes (14 MB, 13 MiB) copied, 2.9342 s, 4.6 MB/s
おそらく書き込みも出来ますが、うかつに BOOT.BIN を書き換えるとブートしなくなる可能性があるので注意が必要です。BOOT.BIN を変更するには次節で説明するアプリケーションを使った方が良いでしょう。
BOOT.BIN の更新
BOOT.BIN が二つ格納されているのは、例えば、新しい BOOT.BIN をフラッシュメモリ の Image B に書き込んだとして、万が一ブートに失敗した時には Image A に書き込まれているブートすることが確認されている BOOT.BIN を起動するようにするためだろうと思われます。
どちらの Image を利用してブートするかを制御するのは Persistent Register に格納されている情報を使うようです。このような BOOT.BIN の更新を行うためのアプリケーションが Xilinx から提供されています。
また、上記のアプリケーションを実行するためのラッパープログラムも Xilinx から提供されています。
BOOT.BIN の確認
BOOT.BIN にどのような情報が格納されているかは bootgen コマンドで確認することができます。
fpga@debian-fpga:~$ sudo bootgen -read /dev/mtd5
****** Xilinx Bootgen v2019.2
**** Build date : Jan 16 2020-08:00:00
** Copyright 1986-2019 Xilinx, Inc. All Rights Reserved.
--------------------------------------------------------------------------------
BOOT HEADER
--------------------------------------------------------------------------------
boot_vectors (0x00) : 0x1400000014000000140000001400000014000000140000001400000014000000
width_detection (0x20) : 0xaa995566
image_id (0x24) : 0x584c4e58
encryption_keystore (0x28) : 0x00000000
header_version (0x2c) : 0xfffc0000
fsbl_sourceoffset (0x30) : 0x00002800
fsbl_length (0x34) : 0x0001fae0
fsbl_load_address (0x38) : 0x0001fae0
fsbl_exec_address (0x3C) : 0x0001b200
fsbl_total_length (0x40) : 0x0001b200
qspi_config-word (0x44) : 0x00000800
checksum (0x48) : 0xfd16d281
iht_offset (0x98) : 0x000008c0
pht_offset (0x9c) : 0x00001100
--------------------------------------------------------------------------------
IMAGE HEADER TABLE
--------------------------------------------------------------------------------
version (0x00) : 0x01020000 total_images (0x04) : 0x00000004
pht_offset (0x08) : 0x00001100 ih_offset (0x0c) : 0x00000900
hdr_ac_offset (0x10) : 0x00000000
--------------------------------------------------------------------------------
IMAGE HEADER (zynqmp_fsbl.elf)
--------------------------------------------------------------------------------
next_ih(W) (0x00) : 0x00000250
next_pht(W) (0x04) : 0x00000440
total_partitions (0x08) : 0x00000000
total_partitions (0x0c) : 0x00000001
name (0x10) : zynqmp_fsbl.elf
--------------------------------------------------------------------------------
IMAGE HEADER (bl31.elf)
--------------------------------------------------------------------------------
next_ih(W) (0x00) : 0x00000260
next_pht(W) (0x04) : 0x00000450
total_partitions (0x08) : 0x00000000
total_partitions (0x0c) : 0x00000001
name (0x10) : bl31.elf
--------------------------------------------------------------------------------
IMAGE HEADER (u-boot.dtb)
--------------------------------------------------------------------------------
next_ih(W) (0x00) : 0x00000270
next_pht(W) (0x04) : 0x00000460
total_partitions (0x08) : 0x00000000
total_partitions (0x0c) : 0x00000001
name (0x10) : u-boot.dtb
--------------------------------------------------------------------------------
IMAGE HEADER (u-boot.elf)
--------------------------------------------------------------------------------
next_ih(W) (0x00) : 0x00000000
next_pht(W) (0x04) : 0x00000470
total_partitions (0x08) : 0x00000000
total_partitions (0x0c) : 0x00000001
name (0x10) : u-boot.elf
--------------------------------------------------------------------------------
PARTITION HEADER TABLE (zynqmp_fsbl.elf.0)
--------------------------------------------------------------------------------
encrypted_length (0x00) : 0x0000eb38 unencrypted_length (0x04) : 0x0000eb38
total_length (0x08) : 0x0000eb38 load_addr (0x0c) : 0x00000450
exec_addr (0x10) : 0xfffc0000 partition_offset (0x14) : 0x00000000
attributes (0x18) : 0xfffc0000 section_count (0x1C) : 0x00000000
checksum_offset (0x20) : 0x00000a00 iht_offset (0x24) : 0x00000116
ac_offset (0x28) : 0x00000001 checksum (0x3c) : 0x00052cb0
attribute list -
trustzone [non-secure] el [el-0]
exec_state [aarch-64] dest_device [none]
encryption [no] core [none]
--------------------------------------------------------------------------------
PARTITION HEADER TABLE (bl31.elf.0)
--------------------------------------------------------------------------------
encrypted_length (0x00) : 0x000031ec unencrypted_length (0x04) : 0x000031ec
total_length (0x08) : 0x000031ec load_addr (0x0c) : 0x00000460
exec_addr (0x10) : 0xfffea000 partition_offset (0x14) : 0x00000000
attributes (0x18) : 0xfffea000 section_count (0x1C) : 0x00000000
checksum_offset (0x20) : 0x0000f540 iht_offset (0x24) : 0x00000117
ac_offset (0x28) : 0x00000001 checksum (0x3c) : 0x00012d32
attribute list -
trustzone [non-secure] el [el-0]
exec_state [aarch-64] dest_device [PL]
encryption [yes] core [a53-1]
--------------------------------------------------------------------------------
PARTITION HEADER TABLE (u-boot.dtb.0)
--------------------------------------------------------------------------------
encrypted_length (0x00) : 0x000021e0 unencrypted_length (0x04) : 0x000021e0
total_length (0x08) : 0x000021e0 load_addr (0x0c) : 0x00000470
exec_addr (0x10) : 0x00000000 partition_offset (0x14) : 0x00000000
attributes (0x18) : 0x00100000 section_count (0x1C) : 0x00000000
checksum_offset (0x20) : 0x00012730 iht_offset (0x24) : 0x00000116
ac_offset (0x28) : 0x00000001 checksum (0x3c) : 0xffee6b46
attribute list -
trustzone [non-secure] el [el-0]
exec_state [aarch-64] dest_device [none]
encryption [no] core [none]
--------------------------------------------------------------------------------
PARTITION HEADER TABLE (u-boot.elf.0)
--------------------------------------------------------------------------------
encrypted_length (0x00) : 0x0004174e unencrypted_length (0x04) : 0x0004174e
total_length (0x08) : 0x0004174e load_addr (0x0c) : 0x00000000
exec_addr (0x10) : 0x10080000 partition_offset (0x14) : 0x00000000
attributes (0x18) : 0x10080000 section_count (0x1C) : 0x00000000
checksum_offset (0x20) : 0x00014910 iht_offset (0x24) : 0x00000114
ac_offset (0x28) : 0x00000001 checksum (0x3c) : 0xdfe26d7d
attribute list -
trustzone [non-secure] el [el-0]
exec_state [aarch-64] dest_device [none]
encryption [no] core [none]
--------------------------------------------------------------------------------
AUTHENTICATION CERTIFICATE (zynqmp_fsbl.elf.0)
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
AUTHENTICATION CERTIFICATE (bl31.elf.0)
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
AUTHENTICATION CERTIFICATE (u-boot.dtb.0)
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
AUTHENTICATION CERTIFICATE (u-boot.elf.0)
--------------------------------------------------------------------------------
--------------------------------------------------------------------------------
余談1
bootgen は KV260 上の Debian や Ubuntu で動かすことができます。詳細は次の記事を参照してください。
余談2
bootgen の -read コマンドは bootgen のヘルプコマンドで説明されません(何故?)。