QEMUでu-bootを利用し、仮想SDカードからLinuxを起動する

〇事前準備

 1.必要なソフトウェアのインストール

  ①クロスコンパイル環境の構築

sudo apt install gcc-arm-linux-gnueabi

  ②QEMUのインストール

sudo apt install qemu-system-arm

    2.必要なライブラリのインストール  

        ①opensslのライブラリをインストールする(u-bootをコンパイルする時の必要なライブラリ)

sudo apt-get install libssl-dev

  ②カーネルコンパイルする時の必要なライブラリをインストールする

sudo apt-get install flex
sudo apt-get install bison -y

flexとbisonをインストールしないと、コンパイルパラメータを設定する時、「flex:not found」のエラーメッセージが出て来る。

sudo apt-get install u-boot-tools

※u-boot-toolsをインストールしないと、uImageをコンパイルする時、「"mkimage" command not found - uboot image will not be built」のエラーメッセージが出て来る。

  ③menuconfigを実施する必要なcursesライブラリをインストールする

sudo opt-get install libncurses5-dev

〇Bootloaderの構築

    1.u-bootをダウンロードする

        https://ftp.denx.de/pub/u-boot/u-boot-2023.10.tar.bz2

    2.u-bootを解凍する

zhou@zhou-Vostro-3480:~/ker-arm$ tar -xf u-boot-2023.10.tar.bz2
zhou@zhou-Vostro-3480:~/ker-arm$

    3.下記の様に、u-boot-2023.10フォルダのMakefileにCROSS_COMPILEとARCHを指定する

zhou@zhou-Vostro-3480:~/ker-arm$ cd u-boot-2023.10/
zhou@zhou-Vostro-3480:~/ker-arm/u-boot-2023.10$ vim Makefile
# SPDX-License-Identifier: GPL-2.0+

VERSION = 2023
PATCHLEVEL = 10
SUBLEVEL =
EXTRAVERSION =
NAME =
CROSS_COMPILE = arm-linux-gnueabi-
ARCH = arm

# *DOCUMENTATION*

 4.u-bootをコンパイルする

        ①コンパイルパラメータの設定

zhou@zhou-Vostro-3480:~/ker-arm/u-boot-2023.10$ make vexpress_ca9x4_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
#
zhou@zhou-Vostro-3480:~/ker-arm/u-boot-2023.10$

        ②コンパイル

zhou@zhou-Vostro-3480:~/ker-arm/u-boot-2023.10$ make -j8
・・・
  AR      lib/built-in.o
  LD      u-boot
  OBJCOPY u-boot.srec
  OBJCOPY u-boot-nodtb.bin
  SYM     u-boot.sym
  COPY    u-boot.bin
===================== WARNING ======================
CONFIG_OF_EMBED is enabled. This option should only
be used for debugging purposes. Please use
CONFIG_OF_SEPARATE for boards in mainline.
See doc/develop/devicetree/control.rst for more info.
====================================================
===================== WARNING ======================
This board does not use CONFIG_DM_SERIAL (Driver Model
for Serial drivers). Please update the board to use
CONFIG_DM_SERIAL before the v2023.04 release. Failure to
update by the deadline may result in board removal.
See doc/develop/driver-model/migration.rst for more info.
====================================================
  OFCHK   .config
zhou@zhou-Vostro-3480:~/ker-arm/u-boot-2023.10$

QEMUにu-boot.binを使用できない為、u-bootを利用し、SDカードからカーネルDTBとルートファイルシステムを読み込む

 5.ボードの情報を確認する

zhou@zhou-Vostro-3480:~/ker-arm/u-boot-2023.10$ qemu-system-arm -M vexpress-a9 -m 512M -nographic -kernel u-boot
pulseaudio: set_sink_input_volume() failed
pulseaudio: Reason: Invalid argument
pulseaudio: set_sink_input_mute() failed
pulseaudio: Reason: Invalid argument
・・・
DRAM:  512 MiB
WARNING: Caches not enabled
Core:  18 devices, 10 uclasses, devicetree: embed
Flash: 64 MiB
MMC:   mmci@5000: 0
Loading Environment from Flash... *** Warning - bad CRC, using default environment
・・・
Usage:
cp [.b, .w, .l, .q] source target count
Wrong Image Format for bootm command
ERROR: can't get kernel image!
=> bdinfo
boot_params = 0x60002000
DRAM bank   = 0x00000000
-> start    = 0x60000000
-> size     = 0x20000000
・・・
Early malloc usage: 370 / 400
=>

※上記より、ボードのメモリ開始アドレスは0x60000000など情報が分かれるが、それはuImageを構築する時の必要なパラメータである。

カーネルDTBの構築

 1.カーネルをダウンロードする

wget https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/snapshat/linux-5.15.141.tar.gz

 2.カーネルを解凍する

zhou@zhou-Vostro-3480:~/ker-arm$ tar -xf linux-5.15.141.tar.gz
zhou@zhou-Vostro-3480:~/ker-arm$

 3.コンパイルパラメータを設定する

zhou@zhou-Vostro-3480:~/ker-arm$ cd linux-5.15.141
zhou@zhou-Vostro-3480:~/ker-arm/linux-5.15.141$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- vexpress_defconfig
  HOSTCC  scripts/basic/fixdep
  HOSTCC  scripts/kconfig/conf.o
  HOSTCC  scripts/kconfig/confdata.o
  HOSTCC  scripts/kconfig/expr.o
  LEX     scripts/kconfig/lexer.lex.c
  YACC    scripts/kconfig/parser.tab.[ch]
  HOSTCC  scripts/kconfig/lexer.lex.o
  HOSTCC  scripts/kconfig/menu.o
  HOSTCC  scripts/kconfig/parser.tab.o
  HOSTCC  scripts/kconfig/preprocess.o
  HOSTCC  scripts/kconfig/symbol.o
  HOSTCC  scripts/kconfig/util.o
  HOSTLD  scripts/kconfig/conf
#
# configuration written to .config
#
zhou@zhou-Vostro-3480:~/ker-arm/linux-5.15.141$

 3.コンパイルする

zhou@zhou-Vostro-3480:~/ker-arm/linux-5.15.141$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- LOADADDR=0x60008000 uImage -j8
・・・
  Kernel: arch/arm/boot/Image is ready
  Kernel: arch/arm/boot/zImage is ready
  UIMAGE  arch/arm/boot/uImage
Image Name:   Linux-5.15.141
Created:      Wed Jan 10 23:03:41 2024
Image Type:   ARM Linux Kernel Image (uncompressed)
Data Size:    5023752 Bytes = 4906.01 KiB = 4.79 MiB
Load Address: 60008000
Entry Point:  60008000
  Kernel: arch/arm/boot/uImage is ready
zhou@zhou-Vostro-3480:~/ker-arm/linux-5.15.141$

※u-bootの情報より、メモリ開始アドレスは0x60000000であることが分かるが、カーネルを実行する時、ページング用のページテーブル情報の保存も必要だったので、ロードアドレスに0x8000のオフセットを設定する(具体的なオフセットのサイズはトプフォルダのMakefileに記載されている)  

 4.ディバイスツリーをコンパイルする

zhou@zhou-Vostro-3480:~/ker-arm/linux-5.15.141$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- dtbs
  DTC     arch/arm/boot/dts/vexpress-v2p-ca5s.dtb
  DTC     arch/arm/boot/dts/vexpress-v2p-ca9.dtb
  DTC     arch/arm/boot/dts/vexpress-v2p-ca15-tc1.dtb
  DTC     arch/arm/boot/dts/vexpress-v2p-ca15_a7.dtb
zhou@zhou-Vostro-3480:~/ker-arm/linux-5.15.141$

〇ルートファイルシステムの構築:

  1.Busyboxのダウンロード

wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2

  2.Busyboxの解凍

zhou@zhou-Vostro-3480:~/ker-arm$ tar -xf busybox-1.36.1.tar.bz2
zhou@zhou-Vostro-3480:~/ker-arm$

  3.Busyboxコンパイルパラメーの設定

zhou@zhou-Vostro-3480:~/ker-arm$ cd busybox-1.36.1
zhou@zhou-Vostro-3480:~/ker-arm/busybox-1.36.1$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- menuconfig

  メニュー画面にてSetting->Buildoptions->Build static binaryの先頭に*を付与する(どこでも使えるように)。設定が完了したら、続いてコンパイルを実施する

  4.Busyboxコンパイル

zhou@zhou-Vostro-3480:~/ker-arm/busybox-1.36.1$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- -j8
  SPLIT   include/autoconf.h -> include/config/*
・・・
zhou@zhou-Vostro-3480:~/ker-arm/busybox-1.36.1$

  5.ルートファイルを作成する

zhou@zhou-Vostro-3480:~/ker-arm/busybox-1.36.1$ make ARCH=arm CROSS_COMPILE=arm-linux-gnueabi- install
  ./_install//bin/arch -> busybox
  ./_install//bin/ash -> busybox
・・・
  --------------------------------------------------
You will probably need to make your busybox binary
setuid root to ensure all configured applets will
work properly.
--------------------------------------------------

zhou@zhou-Vostro-3480:~/ker-arm/busybox-1.36.1$ ls
applets                      examples                networking
applets_sh                   findutils               NOFORK_NOEXEC.lst
arch                         include                 NOFORK_NOEXEC.sh
archival                     init                    printutils
AUTHORS                      _install                procps
busybox                      INSTALL                 qemu_multiarch_testing
busybox_ldscript.README.txt  klibc-utils             README
busybox.links                libbb                   runit
busybox_unstripped           libpwdgrp               scripts
busybox_unstripped.map       LICENSE                 selinux
busybox_unstripped.out       loginutils              shell
Config.in                    mailutils               size_single_applets.sh
configs                      Makefile                sysklogd
console-tools                Makefile.custom         testsuite
coreutils                    Makefile.flags          TODO
debianutils                  Makefile.help           TODO_unicode
docs                         make_single_applets.sh  util-linux
e2fsprogs                    miscutils
editors                      modutils
zhou@zhou-Vostro-3480:~/ker-arm/busybox-1.36.1$

※上記コマンドを実行すると、_installフォルダーを作成され、中身に必要なルートファイルが保存される。

〇仮想SDカードの作成:

説明:uImageのサイズは10Mが足りるが、FSは32Mもできる為、64Mの仮想SDカードが有余です。仮想SDカードをパーティション分割し、パート1は16Mで、uImageとディバイスツリーを格納し、パート2は48Mで、ルートファイルシステムを格納する。

  1.仮想SDカードを作成する

zhou@zhou-Vostro-3480:~/ker-arm/qemu$ dd if=/dev/zero of=sdImage bs=1M count=64
记录了64+0 的读入
记录了64+0 的写出
67108864字节(67 MB,64 MiB)已复制,0.0512024 s,1.3 GB/s
zhou@zhou-Vostro-3480:~/ker-arm/qemu

  2.使用可能のループバックデバイスを確認する

zhou@zhou-Vostro-3480:~/ker-arm/qemu$ losetup -f
/dev/loop16
zhou@zhou-Vostro-3480:~/ker-arm/qemu

  3.仮想SDカードをループバックデバイスに関連付ける

zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo losetup /dev/loop16 sdImage 
[sudo] zhou 的密码: 
zhou@zhou-Vostro-3480:~/ker-arm/qemu

  4.仮想SDカードのパーティションを変更し、新たなパーティションを作成する

zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo sgdisk -n 0:0:+16M -c 0:ker sdImage 
Creating new GPT entries in memory.
Setting name!
partNum is 0
Warning: The kernel is still using the old partition table.
The new table will be used at the next reboot or after you
run partprobe(8) or kpartx(8)
The operation has completed successfully.
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo sgdisk -n 0:0:0 -c 0:rootfs sdImage 
Setting name!
partNum is 1
Warning: The kernel is still using the old partition table.
The new table will be used at the next reboot or after you
run partprobe(8) or kpartx(8)
The operation has completed successfully.
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo sgdisk -p sdImage 
Disk sdImage: 131072 sectors, 64.0 MiB
Sector size (logical): 512 bytes
Disk identifier (GUID): B7DE305C-4510-4353-BB6F-A5C5FDB21D88
Partition table holds up to 128 entries
Main partition table begins at sector 2 and ends at sector 33
First usable sector is 34, last usable sector is 131038
Partitions will be aligned on 2048-sector boundaries
Total free space is 2014 sectors (1007.0 KiB)

Number  Start (sector)    End (sector)  Size       Code  Name
   1            2048           34815   16.0 MiB    8300  ker
   2           34816          131038   47.0 MiB    8300  rootfs
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ 

  5.ディスクパーティション情報を再読み込む

zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo partprobe /dev/loop16
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ ls /dev | grep loop16
loop16
loop16p1
loop16p2
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ 

  6.SDカードの各パーティションファイルシステムを作成する

zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo mkfs.ext4 /dev/loop16p1
mke2fs 1.46.5 (30-Dec-2021)
丢弃设备块: 完成                            
创建含有 4096 个块(每块 4k)和 4096 个 inode 的文件系统

正在分配组表: 完成                            
正在写入 inode表: 完成                            
创建日志(1024 个块): 完成
写入超级块和文件系统账户统计信息: 已完成

zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo mkfs.ext4 /dev/loop16p2
mke2fs 1.46.5 (30-Dec-2021)
丢弃设备块: 完成                            
创建含有 12027 个块(每块 4k)和 12032 个 inode 的文件系统

正在分配组表: 完成                            
正在写入 inode表: 完成                            
创建日志(1024 个块): 完成
写入超级块和文件系统账户统计信息: 已完成

zhou@zhou-Vostro-3480:~/ker-arm/qemu$ 

  7.SDカードをマウントし、作成したカーネル、デバイスツリー、ルートファイルシステムをSDカードにロードする

zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo mount -t ext4 /dev/loop16p1 tmp
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo cp ../linux-5.15.141/arch/arm/boot/uImage tmp/
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo cp ../linux-5.15.141/arch/arm/boot/dts/*.dtb tmp/              
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo umount /dev/loop16p1
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo mount -t ext4 /dev/loop16p2 tmp
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo cp -r ../busybox-1.36.1/_install/* /tmp
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ 
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo cp -rf ../busybox-1.36.1/_install/* tmp/
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ ls tmp/
bin  linuxrc  lost+found  sbin  usr
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo umount /dev/loop16p2
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ sudo losetup -d /dev/loop16
zhou@zhou-Vostro-3480:~/ker-arm/qemu$ 

Linuxの起動テスト:

  1.U-BOOTを起動する

zhou@zhou-Vostro-3480:~/ker-arm/qemu$ qemu-system-arm -M vexpress-a9 -m 512M -nographic -kernel ../u-boot-2023.10/u-boot -sd sdImage
WARNING: Image format was not specified for 'sdImage' and probing guessed raw.
         Automatically detecting the format is dangerous for raw images, write operations on block 0 will be restricted.
         Specify the 'raw' format explicitly to remove the restrictions.
pulseaudio: set_sink_input_volume() failed
pulseaudio: Reason: Invalid argument
pulseaudio: set_sink_input_mute() failed
pulseaudio: Reason: Invalid argument


U-Boot 2023.10 (Jan 08 2024 - 00:05:18 +0900)

DRAM:  512 MiB
WARNING: Caches not enabled
Core:  18 devices, 10 uclasses, devicetree: embed
Flash: 64 MiB
MMC:   mmci@5000: 0
Loading Environment from Flash... *** Warning - bad CRC, using default environment

In:    serial
Out:   serial
Err:   serial
Net:   eth0: ethernet@3,02000000
Hit any key to stop autoboot:  0 
MMC Device 1 not found
no mmc device at slot 1
switch to partitions #0, OK
mmc0 is current device
Scanning mmc 0:1...
14081 bytes read in 13 ms (1 MiB/s)
No EFI system partition
No EFI system partition
Failed to persist EFI variables
BootOrder not defined
EFI boot manager: Cannot load any image
smc911x: detected LAN9118 controller
smc911x: phy initialized
smc911x: MAC 52:54:00:12:34:56
BOOTP broadcast 1
DHCP client bound to address 10.0.2.15 (1 ms)
*** Warning: no boot file name; using '0A00020F.img'
Using ethernet@3,02000000 device
TFTP from server 10.0.2.2; our IP address is 10.0.2.15
Filename '0A00020F.img'.
Load address: 0x60100000
Loading: *
TFTP error: 'Access violation' (2)
Not retrying...
smc911x: MAC 52:54:00:12:34:56
missing environment variable: pxefile_addr_r
smc911x: detected LAN9118 controller
smc911x: phy initialized
smc911x: MAC 52:54:00:12:34:56
BOOTP broadcast 1
DHCP client bound to address 10.0.2.15 (0 ms)
Using ethernet@3,02000000 device
TFTP from server 10.0.2.2; our IP address is 10.0.2.15
Filename 'boot.scr.uimg'.
Load address: 0x60100000
Loading: *
TFTP error: 'Access violation' (2)
Not retrying...
smc911x: MAC 52:54:00:12:34:56
smc911x: detected LAN9118 controller
smc911x: phy initialized
smc911x: MAC 52:54:00:12:34:56
BOOTP broadcast 1
DHCP client bound to address 10.0.2.15 (1 ms)
Using ethernet@3,02000000 device
TFTP from server 10.0.2.2; our IP address is 10.0.2.15
Filename 'boot.scr.uimg'.
Load address: 0x60100000
Loading: *
TFTP error: 'Access violation' (2)
Not retrying...
smc911x: MAC 52:54:00:12:34:56
cp - memory copy

Usage:
cp [.b, .w, .l, .q] source target count
Wrong Image Format for bootm command
ERROR: can't get kernel image!
=> 

  2.カーネルと.dtbファイルをロードする

=> load mmc 0:1 0x60008000 uImage
5023816 bytes read in 810 ms (5.9 MiB/s)
=> load mmc 0:1 0x60800000 vexpress-v2p-ca9.dtb
14081 bytes read in 11 ms (1.2 MiB/s)
=> 

  3.起動パラメータを設定する

=> setenv bootargs 'root=/dev/mmcblk0p2 rw rootfstype=ext4 console=ttyAMA0'
=> 

  4.カーネルを起動する

 

Linuxの起動を完璧にする: