Cyclone® V SoC に載せるLinuxの構築手順

# 1. はじめに
FPGA設計者やハードウェア設計者がSoC FPGAを使うときに困るのは、Linuxの構築だと思います。開発キット等に付属しているSDイメージを使用すれば事足りるかもしれませんが、カーネルのバージョンが古かったり、必要なドライバが入ってなかったりと、必ずしも満足のいくものにはなっていないことも多いと思います。本記事では、ハードウェア環境としてCyclone V SoCが実装されているKEIm-CVSoCを題材に、Linuxをイチから構築する手順を記載します。

# 2. 開発環境
+ Linuxビルド環境：Ubuntu 20.04 LTS (Vertualbox 6.1のゲストOS)
+ ツールチェーン：gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf
+ SoC開発環境：Intel® SoC EDS Standard Edition Version 20.1 for Linux
+ ハードウェア：KEIm-CVSoC 開発キット Rev.B (Cyclone V SoC搭載）
 
# 3. 全体の作成フロー
1. [ビルド環境のセットアップ](#4-ビルド環境のセットアップ)
1. [U-Bootのビルド](#5-u-bootのビルド)
1. [Linuxカーネルのビルド](#6-linuxカーネルのビルド)
1. [ルートファイルシステムの構築](#7-ルートファイルシステムの構築)
1. [SDカードイメージの作成](#8-sdカードイメージの作成)
1. [実機でのセットアップ](#9-実機でのセットアップ)

# 4. ビルド環境のセットアップ
LinuxカーネルやU-Bootのクロスコンパイルに必要なGNU ARM Embeded ツールチェーン、ビルドに必要な各種パッケージをインストールします。

## 4.1. ツールチェーンのセットアップ
ARM Developerサイトよりツールチェーンをダウンロードし、圧縮ファイルを解凍します。

```console:
$ cd ~/Downloads
$ wget https://developer.arm.com/-/media/Files/downloads/gnu-a/10.2-2020.11/binrel/gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf.tar.xz
$ tar xf gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf.tar.xz

$ export PATH=~/Downloads/gcc-arm-10.2-2020.11-x86_64-arm-none-linux-gnueabihf/bin:$PATH
$ export ARCH=arm
$ export CROSS_COMPILE=arm-none-linux-gnueabihf-
```
下3行は環境変数の設定ですが、ターミナルを閉じた際は消えるので、再入力を忘れないようにしてください。

## 4.2 パッケージのインストール
ビルドに必要な各種パッケージをインストールします。
```console:
$ sudo apt install gawk wget git diffstat unzip texinfo gcc-multilib build-essential chrpath socat cpio python-is-python2 python3 python3-pip python3-pexpect xz-utils debianutils iputils-ping python3-git python3-jinja2 libegl1-mesa libsdl1.2-dev pylint gawk flex bison openssl libssl-dev libncurses-dev
```
足りないパッケージがあるとmake時にエラーがでますが、エラーメッセージに従って必要なパッケージをインストールしてmakeしなおせばOKです。

## 4.3 ワークディレクトの作成
SDイメージ作成用にワークディレクトを作成します。
```console:
$ mkdir ~/sdmake_keim
$ cd ~/sdmake_keim
$ export TOP_DIR=`pwd`
```

# 5. U-Bootのビルド
U-BootはLinuxを起動するために必要なブートローダです。Linuxカーネルイメージ（zImage）をメモリへ展開するのはもちろん、Cyclone V SoCのコンフィグレーションデータ（.rbf）をFPGAへ展開する作業も担っています。

## 5.1 HPS設定用ファイルを生成
U-Bootをビルドする際に、FPGAデザインのHPS設定情報が必要になります。以降の手順でFPGAデザインのhandoffファイルからHPS設定ファイルを生成しますが、ここではFPGAデザインの作成方法は割愛し、KEIm-CVSoCのリファレンスデザインをホームページからダウンロードする形で進めます。

```console:
$ cd $TOP_DIR
$ mkdir fpga && cd fpga #ワークディレクトリの作成

$ wget https://kd-group.co.jp/download-data/keim-cvsoc/bsp/keim-cvsoc-b_devkit_ghrd_q21.zip
$ unzip keim-cvsoc-b_devkit_ghrd_q21.zip #FPGAプロジェクトをダウンロードして解凍
$ cd keim-cvsoc-b_devkit_ghrd_q21
$ export FPGA_TOP=`pwd`

$ rm -rf software #古いデータが残っている場合は削除しておく
$ mkdir -p software/bootloader
$ ~/intelFPGA/20.1/embedded/embedded_command_shell.sh #パスはSoCESのインストールパス
$ bsp-create-settings --type spl --bsp-dir software/bootloader --preloader-settings-dir "hps_isw_handoff/soc_system_hps_0" --settings software/bootloader/settings.bsp
```

上記を実行すると、software/bootloader/generatedにFPGAのハンドオフファイルからHPSの設定を反映したソースが生成されます。

## 5.2 U-Bootのソースコードの取得

```console:
$ cd software/bootloader
$ git clone https://github.com/altera-opensource/u-boot-socfpga
$ cd u-boot-socfpga
$ export UBOOT_TOP=`pwd`
$ git checkout -b test-bootloader -t origin/socfpga_v2021.07 #v2021.07のブランチを使用

$ #U-BootソースにHPS設定を組み込む
$ ./arch/arm/mach-socfpga/qts-filter.sh cyclone5 ../../../ ../ ./board/altera/cyclone5-socdk/qts/

$ #U-Bootの設定
$ make socfpga_cyclone5_defconfig
$ cp .config .config.old #今の設定をバックアップ
$ sed -i "s/WATCHDOG_TIMEOUT_MSECS=10000/WATCHDOG_TIMEOUT_MSECS=60000/" .config　#ウォッチドッグのタイムアウトの時間10sから60sに延ばしておく

```
必要に応じて、menuconfig等を使用してU-Bootの設定を変更しておきます。

## 5.3 ボード固有ファイルの編集
Development Kitのソースファイルをベースに編集します。

```console:
$ cd $UBOOT_TOP/include/configs
$ cp socfpga_cyclone5_socdk.h socfpga_cyclone5_socdk.h.org #バックアップ
$ sed -i "s/0x40000000/0x8000000/" socfpga_cyclone5_socdk.h
$ sed -i "s/1GiB on SoCDK/2GiB/" socfpga_cyclone5_socdk.h
```
## 5.4 デバイスツリーソースの編集
U-Bootのデバイスツリーソースを作成しますが、独自にファイル名を設定して作成すると、U-Bootのソースツリーを色々と変更する必要がありそうで面倒なので、最初から用意されているsocfpga_cyclone5_socdk.dtsを修正する形で進めます。

```console:
$ cd $UBOOT_TOP/arch/arm/dts
$ cp socfpga_cyclone5_socdk.dts socfpga_cyclone5_socdk.dts.org #バックアップ
$ gedit socfpga_cyclone5_socdk.dts
```

以下、変更するノードのみを記載しています。

```c:socfpga_cyclone5_socdk.dts
//model = "Altera SOCFPGA Cyclone V SoC Development Kit";
model = "KEIm-CVSoC Development Kit"; //起動メッセージで表示されるので修正

memory {
        name = "memory";
        device_type = "memory";
		//reg = <0x0 0x40000000>; /* 1GB */
        reg = <0x0 0x80000000>; /* 2GB */ //メモリの容量の修正
};

leds {
        compatible = "gpio-leds";
        hps0 {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
            label = "hps_led0";
			//gpios = <&portb 15 1>;
            gpios = <&porta 0 0>; //ポートの修正
        }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​;

    /* hps1からhps3までの不要な定義の削除
		hps1 {
			label = "hps_led1";
			gpios = <&portb 14 1>;
		};

		hps2 {
			label = "hps_led2";
			gpios = <&portb 13 1>;
		};

		hps3 {
			label = "hps_led3";
			gpios = <&portb 12 1>;
		};
    */
}

&gmac1 {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
    status = "okay";
    phy-mode = "rgmii";

	//rxd0-skew-ps = <0>;
	//rxd1-skew-ps = <0>;
	//rxd2-skew-ps = <0>;
	//rxd3-skew-ps = <0>;
	//txen-skew-ps = <0>;
	//txc-skew-ps = <1560>;
    txc-skew-ps = <2000>; //PHYのスキュー調整
	//rxdv-skew-ps = <0>;
	//rxc-skew-ps = <1200>;
    rxc-skew-ps = <2000>; //PHYのスキュー調整
}​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​;

&qspi {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
    status = "okay";
    
    //flash0: n25q00@0 {
    flash0: n25q512a@0 {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ //デバイスの修正
        #address-cells = <1>;
        #size-cells = <1>;
        //compatible = "n25q00";
        compatible = "n25q512a";​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​ //デバイスの修正
        reg = <0>;    /* chip select */
        spi-max-frequency = <100000000>;
    
        m25p,fast-read;
        cdns,page-size = <256>;
        cdns,block-size = <16>;
        cdns,read-delay = <4>;
        cdns,tshsl-ns = <50>;
        cdns,tsd2d-ns = <50>;
        cdns,tchsh-ns = <4>;
        cdns,tslch-ns = <4>;
    
        partition@qspi-boot {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
            /* 8MB for raw data. */
            label = "Flash 0 Raw Data";
            reg = <0x0 0x800000>;
        }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​;

        partition@qspi-rootfs {​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​
            /* 120MB for jffs2 data. */
            label = "Flash 0 jffs2 Filesystem";
            //reg = <0x800000 0x7800000>;
            reg = <0x800000 0x3800000>; //メモリ範囲の修正
        }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​;
    }​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​;
}​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​;


```

## 5.6 ビルド

```
$ cd $UBOOT_TOP
$ make
```

## 5.7 U-Boot関連生成ファイル
U-Bootビルドでの生成物は下記のとおりです。この内太字のものを後述のSDイメージ作成の時に使用します。


| No. | ファイル名 | パス | 説明 |
|:-:|:--|:--|:--|
| 1  |  u-boot-spl | $UBOOT_TOP/spl/  | SPLのelfファイル（今回は使いません）  |
| 2  |  u-boot | $UBOOT_TOP/  | U-BOOTのelfファイル（今回は使いません）  |
| 3  | **u-boot-with-spl.sfp**  | $UBOOT_TOP/  | SPLとU-BOOTを合わせたバイナリイメージ  |
| 4  | **socfpga_cyclone5_socdk.dtb**  | $UBOOT_TOP/  | U-BOOTのデバイスツリーブロブ  |

# 6. Linuxカーネルのビルド

## 6.1 Linuxカーネルのソースコードの取得
カーネルのソースコードはGitHubからU-Bootと同じようにAltera Opensourceからダウンロードし、socfpga-5.10.60-ltsのブランチを使用します。

```console:
$ cd $TOP_DIR
$ mkdir kernel && cd kernel #ワークディレクトリの作成

$ git clone https://github.com/altera-opensource/linux-socfpga linux-5.10.60
$ cd linux-5.10.60
$ export KERNEL_TOP=`pwd`
$ git checkout -b test-kernel -t origin/socfpga-5.10.60-lts
```

## 6.2 カーネルのビルド
カーネルのビルドに際して、カーネルの設定が必要です。これは、Cyclone V SoCを含むシステムに搭載されているペリフェラルに対応したドライバを組み込んだり、カーネルそのものの設定をする作業になります。今回は、前の項でダウンロードしたKEIm-CVSoCのリファレンスデザインに含まれているdefconfigを使用します。

```console:
$ cd $KERNEL_TOP
$ cp $FPGA_TOP/linux/5.10.60/keim-cvsoc_desktop_defconfig ./arch/arm/configs/.
$ make keim-cvsoc_desktop_defconfig
$ #必要に応じてmenuconfig等で設定を追加修正
$ make zImage dtbs modules
```
ビルドするとカーネルイメージzImageが./arch/arm/boot/の下に生成されます。

## 6.2 デバイスツリーブロブの作成

デバイスツリーはSoCFPGAシステム及びSoCFPGAシステムに接続されるペリフェラルのレジスタ設定を行うしくみです。決められたフォーマットに沿って記述したテキストファイルであるデバイスツリーソース（.dts）をカーネルが読み込める形式であるデバイスツリーブロブ（.dtb）に変換して使用します。
デバイスツリーはシステムに対応したものを作成をする必要がありますが、今回はKEIm-CVSoCのリファレンスデザインに含まれているデバイスツリーソースを使用する形で進めます。

```console:
$ cd $KERNEL_TOP
$ cp $FPGA_TOP/linux/5.10.60/socfpga_cyclone5_keim-cvsoc-b_vfw.dts ./arch/arm/boot/dts/.
$ sed -i '/socfpga_cyclone5_socdk/i \\tsocfpga_cyclone5_keim-cvsoc-b_vfw.dtb \\' ./arch/arm/boot/dts/Makefile
$ make dtbs
```

./arch/arm/boot/dts/socfpga_cyclone5_keim-cvsoc-b_vfw.dtb

## 6.2 カーネルモジュールの作成

```console:
$ cd $KERNEL_TOP
$ make modules_install INSTALL_MOD_PATH=modules_install
$ rm -rf modules_install/lib/modules/*/source
```
上記ではsourceディレクトリを削除して、buildディレクトリは残しています。

## 6.3 カーネル関連生成ファイル
本項の生成ファイルでSDイメージ生成時に使用するものは下記のとおりです。

| No. | ファイル名 | パス | 説明 |
|:-:|:--|:--|:--|
| 1  | **zImage** | $KERNEL_TOP/arch/arm/boot/ | Linuxカーネル  |
| 2  | **socfpga_cyclone5_keim-cvsoc-b_vfw.dtb** | $KERNEL_TOP/arch/arm/boot/dts/  | デバイスツリーブロブ  |
| 3  | **module_install/**  | $KERNEL_TOP/modules_install  | カーネルモジュールファイル  |

# 7. ルートファイルシステム（rootfs）の構築
Ubuntuルートファイルシステムを作成し、作成したルートファイルシステムに対し、最低限の設定を実施します。

## 7.1 Ubuntuルートファイルシステムの作成

ルートファイルシステムの生成にはmmdebstrapツールを使用します。下記の通り必要なツールのインストールを行います。

```console:
$ sudo apt install mmdebstrap
$ sudo apt install qemu-user-static binfmt-support
```

ワークディレクトリを作成し、mmdebstrapでubuntu-focal-armhf-standardディレクトリにUbuntu 20.04 LTS（Focal Fossa）ルートファイルシステムを作成します。
```console:
$ cd $TOP_DIR
$ mkdir rootfs && cd rootfs #ワークディレクトリの作成
$ mmdebstrap --components="main restricted universe multiverse" --architectures=armhf focal ubuntu-focal-armhf-standard http://ports.ubuntu.com/ubuntu-ports
```
ディレクトリやファイルの所有者やグループが100000なってしまうので、chownでユーザー及びグループを共にrootに設定します。

```console:
$ sudo chown -R root:root ubuntu-focal-armhf-standard
```
```console:
$ cd $TOP_DIR/rootfs/ubuntu-focal-armhf-standard
$ export ROOTFS_TOP=`pwd`
$ sudo chroot .
```
chrootコマンドでルートディレクトリを変更したので、ここから以降しばらくubuntu-focal-armhf-standardをルートディレクトリとした作業になります。

## 7.2 rootのパスワード設定
実機での作業で、しばらくrootユーザーで作業をするのでパスワードを設定します。ただ、実際の運用を視野に入れると安易なパスワード設定は良くないので、adduserでrootユーザー以外の一般ユーザーを追加して、実機でも一般ユーザーをメインに使用したほうが良いかもしれません。

```console:
# chmod 4755 /usr/bin/sudo #sudoのパーミッション変更

# passwd root #rootのパスワード設定
New password: root
Retype new password: root
passwd: password update sucessfully
```
## 7.3 ネットワークの設定
実機でのセットアップの際に、インターネットに接続してツールのダウンロード等を頻繁に行うので、ネットワークの設定をしておきます。

```console:
# vi /etc/netplan/99-custom.yaml
```

```c:99-custom.yaml
network:
  version: 2
  ethernets:
    eth0:
      dhcp4: true
      optional: true
```

## 7.4 ツールのインストール
この項は、必要に応じてインストールをしていただくという項目になりますが、最低限SSHとパーティション拡張はあった方が安心だと思います。

```console:
# apt update
# apt upgrade
# apt install -y openssh-server #SSHサーバー
# apt install -y parted #パーティション拡張ツール
# exit #chrootを抜ける
```
exitでubuntu-focal-armhf-standardのからクロスコンパイル環境へルートを戻して作業します。

## 7.5 カーネルモジュールのコピー
```console:
$ sudo rm -rf lib/modules
$ sudo cp -Lpr $KERNEL_TOP/modules_install/lib/* lib/.
```

## 7.6 ルートファイルシステム（rootfs）関連生成ファイル
本項の生成ファイルでSDイメージ生成時に使用するものは下記のとおりです。

| No. | ファイル名 | パス | 説明 |
|:-:|:--|:--|:--|
| 1  | **ubuntu-focal-armhf-standard/**  | $ROOTFS_TOP  | Ubuntuルートファイルシステム  |


# 8. SDカードイメージの作成
これまで作成してきた生成物（FPGA関連データ、U-Boot関連データ、カーネル関連データ、rootfs関連データ）をSDに書き込めるようにイメージデータとして統合します。

## 8.1 スクリプトのダウンロード
SDイメージの作成にはスクリプトを使用します。下記コマンドによりスクリプトファイルをダウンロードします。

```console:
$ cd $TOP_DIR
$ wget https://releases.rocketboards.org/release/2020.05/gsrd/tools/make_sdimage_p3.py
$ sudo apt install u-boot-tools #mkimageコマンド実行のため
```

## 8.2 イメージに必要なファイルの準備

```console:
$ cd $TOP_DIR
$ cp $FPGA_TOP/software/bootloader/u-boot-socfpga/u-boot-with-spl.sfp . #U-Boot

$ mkdir sdfs && cd sdfs #ワークディレクトリの作成
$ cp $FPGA_TOP/keim-cvsoc-b_devkit_ghrd_q21.zip . #FPGAプロジェクト（必要に応じて）
$ cp $FPGA_TOP/output_files/soc_system.rbf . #FPGAコンフィグレーションデータ
$ cp $FPGA_TOP/software/bootloader/u-boot-socfpga/arch/arm/dts/socfpga_cyclone5_socdk.dtbsocfpga_cyclone5_keim-cvsoc-b.dtb #U-Bootデバイスツリー
$ cp -r $FPGA_TOP/linux . #MISCファイル（ドライバやアプリケーション等）
$ cp $KERNEL_TOP/arch/arm/boot/zImage . #Linuxカーネルイメージ
$ cp $KERNEL_TOP/arch/arm/boot/dts/socfpga_cyclone5_keim-cvsoc-b_vfw.dtb socfpga_cyclone5_keim-cvsoc-b.dtb #Linuxデバイスツリー
```

## 8.2 U-Bootスクリプトの作成
U-Bootが起動後に実行するスクリプトファイルです。テキストで作成しておいて、mkimageコマンドで（.scr）にコンバートします。

```console:
$ cd $TOP_DIR/sdfs
$ touch u-boot.txt
```
u-boot.txtをエディタで下記の様に編集します。

```c:u-boot.txt
fatload mmc 0:1 $fdt_addr_r soc_system.rbf;
fpga load 0 $fileaddr $filesize;
bridge enable;
mw.l 0xFF220140 0x1 1;
mw.l 0xFF220140 0x0 1;
```
1,2行目でFPGAのコンフィグレーションファイルをSDRAMに読み込み、FPGAにロードします。
3行目はSoC FPGA間のバスブリッジのイネーブルで、4行目、5行目はPCIe Hard IPのリセットとリセット解除です。

作成したu-boot.txtを下記コマンドを使用してu-boot.scrに変換します。
```console:
$ mkimage  -A arm -O linux -T script -C none -a 0 -e 0 -n "My script" -d u-boot.txt u-boot.scr

0 "My script" -d u-boot.txt u-boot.scr
Image Name:   
Created:      Tue Nov  8 16:38:05 2022
Image Type:   ARM Linux Script (uncompressed)
Data Size:    146 Bytes = 0.14 KiB = 0.00 MiB
Load Address: 00000000
Entry Point:  00000000
Contents:
   Image 0: 139 Bytes = 0.14 KiB = 0.00 MiB
```


## 8.3 extlinux.conf（Linux起動設定ファイル）の作成
こちらは、Linuxカーネルが起動時に読み込む設定ファイルになります。

```console:
$ cd $TOP_DIR/sdfs
$ mkdir extlinux && cd extlinux
$ touch extlinux.conf
```

extlinux.confをエディタで下記の様に編集します。

```c:extlinux.conf
LABEL Linux Default
    KERNEL ../zImage
    FDT ../socfpga_cyclone5_keim-cvsoc-b.dtb
    APPEND root=/dev/mmcblk0p2 rw rootwait earlyprintk console=ttyS0,115200n8 uio_pdrv_genirq.of_id=generic-uio
```
extlinux.confは特に変換等は必要ないので、この状態で完成です。

## 8.4 イメージの作成
ここまでの作業を通して、ワークディレクトリ以下が下記のような構成になっていると思います。
```text:
$TOP_DIR
    make_sdimage_p3.py  #SDイメージ作成スクリプト
    u-boot-with-spl.sfp #U-Boot
    /fpga               #FPGAデータ & U-Bootビルド用ディレクトリ
    /kernel             #Linuxカーネルビルド用ディレクトリ
    /sdfs               #SD FAT領域書き込みデータ用ディレクトリ
        socfpga_cyclone5_keim-cvsoc-b.dtb #Linuxデバイスツリー
        socfpga_cyclone5_socdk.dtb        #U-Bootデバイスツリー
        zImage                            #Linuxカーネルイメージ
        soc_system.rbf                    #FPGAコンフィグデータ
        u-boot.txt                        #U-Bootスクリプト(テキスト)
        u-boot.scr                        #U-Bootスクリプト(SCRファイル）
        /extlinux/extlinux.conf           #Linux起動設定ファイル 
        /linux                            #MISCファイル
    /rootfs/ubuntu-focal-armhf-standard/  #ルートファイルシステム    
```
この状態で、下記のコマンドを入力すると、keim-vfw-focal-5.10.60.imgが生成されます。

```console:
$ cd $TOP_DIR
$ sudo python3 ./make_sdimage_p3.py -f \
-P u-boot-with-spl.sfp,num=3,format=raw,size=10M,type=A2 \
-P sdfs/*,num=1,format=fat32,size=100M \
-P $ROOTFS_TOP/*,num=2,format=ext3,size=7800M \
-s 8000M \
-n keim-vfw-focal-5.10.60.img
```


## 8.5 make_sdimage_keim-cvsoc-b_vfw_focal_5.10.60.sh
ほとんどの部分はスクリプト化できるので、本項のU-Bootスクリプト作成、extlinux.confの作成、SDイメージの作成をスクリプト化したものをリファレンスデザイン（$FPGA_TOP/linux）に入れています。

```console:
$ cd $TOP_DIR
$ cp $FPGA_TOP/linux/make_sdimage_keim-cvsoc-b_vfw_focal_5.10.60.sh .
$ sudo chmod +x make_sdimage_keim-cvsoc-b_vfw_focal_5.10.60.sh
$ ./make_sdimage_keim-cvsoc-b_vfw_focal_5.10.60.sh
```

# 9. 実機でのセットアップ
作成したSDイメージをSDカードに書き込んで、実機（KEIm-CVSoC 開発キット）を起動し、最低限のセットアップをします。

## 9.1 SDイメージの書き込み

下記URLを参考に、SDカードにイメージデータを書き込みます。

[SoC FPGA ブート用 SD カードイメージの作り方](https://malt.zendesk.com/hc/ja/articles/900006257823-SoC-FPGA-%E3%83%96%E3%83%BC%E3%83%88%E7%94%A8-SD-%E3%82%AB%E3%83%BC%E3%83%89%E3%82%A4%E3%83%A1%E3%83%BC%E3%82%B8%E3%81%AE%E4%BD%9C%E3%82%8A%E6%96%B9)

※：Win32 Disk Imagerを使用する場合、既に書き込み済みのSDカードに書き込みしようとするとエラーが発生することがあります。SDカードにFAT以外のパーティションがあるのが問題なので、Windowsのディスク管理ツールやdiskpartコマンド等を使用してFAT以外のパーティションの削除すれば、Win32 Disk Imagerで書き込みできるようになります。


## 9.2 実機立ち上げ
イメージを書き込んだSDカードを、KEIm-CVSoC 開発キットのSDカードスロットに挿入し、電源を投入するとLinuxが立ち上りるのがターミナルソフトで確認できると思います。ログインネーム、パスワードともに"root"でログインできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/721171/7dbce130-39d1-1615-7fa2-bec34047b38a.png)

以降は実機のLinuxで必要なセッティングをしていく流れになりますが、本稿長くなりすぎたのでここまでとして、別の記事で以降の手順を記載したいと思います。
+ タイムゾーンやキーボードの設定
+ ユーザーの追加
+ ディスク容量の拡張
+ デスクトップ環境の構築
+ ドライバの組み込み 


# 10. 参考URL

+ [Building Bootloader for Cyclone V and Arria 10](https://www.rocketboards.org/foswiki/Documentation/BuildingBootloaderCycloneVAndArria10#Building_Linux_Kernel)

+ [SoC EDS v19.1 std / v19.3 pro から変更された新しいブートローダー生成フローの動作確認](https://malt.zendesk.com/hc/ja/articles/900005300046-SoC-EDS-v19-1-std-v19-3-pro-%E3%81%8B%E3%82%89%E5%A4%89%E6%9B%B4%E3%81%95%E3%82%8C%E3%81%9F%E6%96%B0%E3%81%97%E3%81%84%E3%83%96%E3%83%BC%E3%83%88%E3%83%AD%E3%83%BC%E3%83%80%E3%83%BC%E7%94%9F%E6%88%90%E3%83%95%E3%83%AD%E3%83%BC%E3%81%AE%E5%8B%95%E4%BD%9C%E7%A2%BA%E8%AA%8D-Cyclone-V-SoC-Arria-V-SoC-%E7%B7%A8-)