Published on

uboot从sd卡启动kernel

Authors

qemu启动uboot

qemu-system-arm -M vexpress-a9 -m 512M -kernel u-boot -nographic -no-reboot

下面是uboot加载的日志

pulseaudio: set_sink_input_volume() failed
pulseaudio: Reason: Invalid argument
pulseaudio: set_sink_input_mute() failed
pulseaudio: Reason: Invalid argument


U-Boot 2024.07 (Sep 02 2024 - 17:26:56 +0800)

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

In:    uart@9000
Out:   uart@9000
Err:   uart@9000
Net:   eth0: ethernet@3,02000000
Hit any key to stop autoboot:  0 
MMC Device 1 not found
no mmc device at slot 1
Card did not respond to voltage select! : -110
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 (3 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] source target count
Wrong Image Type for bootm command
ERROR -91: can't get kernel image!

从log看到,uboot通过tftp网络读取kernel镜像,但是找不到。uboot可以从sd卡读取,制作一SD卡,将kernel,rootfs,dtb文件放到sd卡, 在uboot中将sd卡文件载入到DDR,从DDR启动内核。

创建sd卡

创建sd卡文件

dd if=/dev/zero of=./sd_scard bs=1M count=512

给sd卡分区

sudo fdisk /home/victor/work/sd_card

# 键入  o n w
# n的时候有几个参数,全部default即可

Welcome to fdisk (util-linux 2.38.1).                                                                                                     
Changes will remain in memory only, until you decide to write them.                                                                       
Be careful before using the write command.

Device does not contain a recognized partition table.
Created a new DOS disklabel with disk identifier 0xb0076014.

Command (m for help): o
Created a new DOS disklabel with disk identifier 0x34a29c34.

Command (m for help): n
Partition type
   p   primary (0 primary, 0 extended, 4 free)
   e   extended (container for logical partitions)
Select (default p): p
Partition number (1-4, default 1): 1
First sector (2048-1048575, default 2048): 
Last sector, +/-sectors or +/-size{K,M,G,T,P} (2048-1048575, default 1048575): 

Created a new partition 1 of type 'Linux' and of size 511 MiB.

Command (m for help): w
The partition table has been altered.
Syncing disks.

创建vfat文件系统

sudo mkfs.vfat sd_scard
file sd_scard
sd_scard: DOS/MBR boot sector, code offset 0x58+2, OEM-ID "mkfs.fat", sectors/cluster 8, Media descriptor 0xf8, sectors/track 63, heads 255, sectors 1048576 (volumes > 32 MB), FAT (32 bit), sectors/FAT 1024, serial number 0xe3792218, unlabeled

制作uramdisk.img

下载最新的busybox

wget https://busybox.net/downloads/busybox-1.36.1.tar.bz2
tar -xf busybox-1.36.1.tar.bz2
cd busybox-1.36.1
make defconfig #加载默认配置
make CROSS_COMPILE=arm-linux-gnueabi- #编译
make install CROSS_COMPILE=arm-linux-gnueabi- #安装

编译的bin文件生成在_install/路径下

  • 创建根目录
mkdir -p rootfs/{dev,etc/init.d,lib}
  • 拷贝bin文件到rootfs
cp -rf _install/* rootfs/
  • 拷贝库文件到lib目录下
cp -P /usr/arm-linux-gnueabi/lib/* rootfs/lib/
  • 创建proc和sys目录
mkdir rootfs/proc
mkdir rootfs/sys
mkdir rootfs/config
mkdir rootfs/debug

之所以要创建这两个目录,因为后面需要挂载procfs和sysfs两个文件系统。当然,这两个目录也可以在启动脚本中创建。

  • 修改为root
sudo chown -R root:root rootfs/
  • 创建4个tty终端设备
sudo mknod rootfs/dev/tty1 c 4 1
sudo mknod rootfs/dev/tty2 c 4 2
sudo mknod rootfs/dev/tty3 c 4 3
sudo mknod rootfs/dev/tty4 c 4 4
  • 制作根文件系统
dd if=/dev/zero of=a9rootfs.ext4 bs=1M count=32
  • 格式化成ext4格式
mkfs.ext4 a9rootfs.ext4
```git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux.git


- ext4格式uboot无法引导,重新制作`initramfs`格式镜像
initrd 是一种较早的机制,使用 cpio 归档文件格式,作为临时根文件系统挂载。  
initramfs 是 initrd 的现代替代方案,直接在内存中以文件系统形式存在,提供更高的灵活性和功能。  
现代 Linux 系统通常使用 initramfs,因为它提供了更好的性能和更简化的操作方式。   

```sh
cd rootfs/
find . |cpio -ov -H newc |gzip > ../ramdisk.img

newc 表示initramfs格式

制作的ramdisk.img uboot是无法识别的,需转换成uImage,uImage就是在头部加上64字节的信息,才能通过bootz去启动。

mkimage -A arm -O linux -C none -T ramdisk -a 0x00000000 -e 0x00000000 -n "Jcob's Root Filesystem" -d ramdisk.img uramdisk.img

Image Name:   Jcob's Root Filesystem
Created:      Wed Sep  4 17:48:25 2024
Image Type:   ARM Linux RAMDisk Image (uncompressed)
Data Size:    6284950 Bytes = 6137.65 KiB = 5.99 MiB
Load Address: 00000000
Entry Point:  00000000

mkimage如果交叉编译工具链没有带,在编译好的u-boot/tools下有。

复制到sd卡

将sd卡挂载到 card/

mkdir card
sudo mount -tvfat sd_scard card/

拷贝uboot的image到sd卡

cp busybox-1.36.1/uramdisk.img card/

编译kernel

git clone https://mirrors.tuna.tsinghua.edu.cn/git/linux.git
# 全部拉取太慢,拉取指定的版本
git clone -b v6.9 --single-branch   https://mirrors.tuna.tsinghua.edu.cn/git/linux.git

编译个最新的内核试试

配置

make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm vexpress_defconfig
make CROSS_COMPILE=arm-linux-gnueabi- ARCH=arm -j4 # 或指定 make zImage dtbs
...
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready

看到zImage is ready,编译完成了。

复制内核文件到sd卡

sudo cp linux/arch/arm/boot/zImage card/
sudo cp linux/arch/arm/boot/dts/arm/vexpress-v2p-ca9.dtb card/
sudo umount card/

修改uboot配置

修改启动命令

vim configs/vexpress_ca9x4_defconfig

## CONFIG_BOOTCOMMAND="run distro_bootcmd; run bootflash"
CONFIG_BOOTCOMMAND="run bootsd"

改为bootsd

添加zImage和uramdisk配置

vim include/configs/vexpress_common.h
~/code/embeded/u-boot-2024.07/include/configs$ diff  vexpress_common.h vexpress_common.h_bak
151,159d150
<               "kernel_name=zImage\0" \
<               "ramdisk_name=uramdisk.img\0" \
<               "dtb_name=vexpress-v2p-ca9.dtb\0" \
<               "kernel_jcob_addr=0x60000000\0" \
<               "ramdisk_jcob_addr=0x70000000\0" \
<               "dtb_jcob_addr=0x61000000\0" \
<               "load_kernel=fatload mmc 0:0 ${kernel_jcob_addr} ${kernel_name}\0 " \
<               "load_ramdisk=fatload mmc 0:0 ${ramdisk_jcob_addr} ${ramdisk_name}\0 "\
<               "load_dtb=fatload mmc 0:0 ${dtb_jcob_addr} ${dtb_name}\0 " \
165c156
<               "root=/dev/mmcblk0 rw\0" \
---
>               "root=/dev/sda1 rw\0" \
171d161
<               "sdargs=setenv bootargs rdinit=/sbin/init root=${root} console=${console}\0" \
175,179d164
<               "bootsd=run sdargs; "\
<                       "run load_kernel; "\
<                       "run load_ramdisk; "\
<                       "run load_dtb; " \
<                       "bootz ${kernel_jcob_addr} ${ramdisk_jcob_addr} ${dtb_jcob_addr}\0"\

重新编译uboot

启动

qemu-system-arm -M vexpress-a9 -m 1024M -kernel u-boot-2024.07/u-boot -dtb linux/arch/arm/boot/dts/arm/vexpress-v2p-ca9.dtb -sd sd_scard  -nographic -no-reboot

报VFS错误,找不到根文件系统。提示“root=”,这里可以看到需要设定root启动设备,之前uboot启动参数漏了root=${root},加上。

先从qemu直接启动kernel

生成一个init程序

#include <stdio.h>

 void main() 
 {
     printf("Hello World!\n");

     while(1);
 }

因为init程序不能退出,所以加while

静态编译 arm-linux-gnueabi-gcc -static test.c -o test

echo test | cpio -o --format=newc > rootfs

生成一个简单的文件系统,启动kernel

qemu-system-arm -M vexpress-a9 -m 1024M -kernel linux/arch/arm/boot/zImage -dtb linux/arch/arm/boot/dts/arm/vexpress-v2p-ca9.dtb -initrd rootfs  -nographic -append "root=/dev/ram rdinit=/test console=ttyAMA0"

启动kernel,可以看到hello owrld就成功了,这样可以先排除kernel和设备树的问题。

启动成功

最新6.9内核,完成。

Reference

Kernel boot parameters