背景
上一讲我们完成了 编译 QEMU 以及简单地做了仿真。这一讲在 启动uboot 的基础上进行,以加强对于 运行地址,加载地址等理解。
有关资料: uboot 与 代码重定位
有这样的约定,uboot正常运行的模式称为自主模式;倒计时被中断以后的交互模式称为下载模式。
在Uboot中加载内核与设备树一般通过网络(tftp)、读存储介质(sd卡usb等)以及仿真器等方式。
uboot通过tftp加载uImage
为了通过 tftp 加载有关的文件到指定的内存地址,需要先完成下面2个步骤。
在主机搭建tftp服务器
在Linux使用tftp一般以搭建tftp服务器,Windows可以使用软件完成(例如tftpd32)。
参考文章:《ubuntu 下tftp的安装、配置、使用》
QEMU网络功能配置
为了 让 QEMU 能够与主机 建立网络连接,我们采用桥接的网络连接与Host通信(需要主机内核tun/tap模块支持)
参考文章:《QEMU 配置网络》
很可惜我的Ubuntu有问题。折腾了好久网络都没有通,但根据以往的开发经验,教程是可行的。
这里需要用到 uboot的命令,添加/改动uboot变量有2种方法,一种是在运行的时候通过setenv, saveenv
等命令完成的;另外一种就是把有关的命令固化在程序中。
我相信大家对于uboot下载模式下的命令非常熟悉,下面我们简单介绍在代码中固化配置的方法。
1)修改uboot代码并编译
在include/configs/vexpress_common.h
中加入相应的宏定义(相当于步骤4)
// 根据自己的实际情况修改对应的地址
#define CONFIG_IPADDR 192.168.31.240
#define CONFIG_NETMASK 255.255.255.0
#define CONFIG_SERVERIP 192.168.31.241
/* 指定启动文件为uImage */
#define CONFIG_BOOTFILE "uImage"
/* 指定启动命令 */
#define CONFIG_BOOTCOMMAND "tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb; setenv bootargs'root=/dev/mmcblk0 console=ttyAMA0'; bootm 0x60003000 - 0x60500000"
关于设备树,可以参考文章: 《设备树DTS 学习: uboot 传递 dtb 给 内核》
实际上,CONFIG_BOOTCOMMAND的值会在uboot启动以后自动执行,相当于在下载模式输入下面的指令
tftp 0x60003000 uImage tftp 0x60500000 vexpress-v2p-ca9.dtb setenv bootargs'root=/dev/mmcblk0 console=ttyAMA0' bootm 0x60003000 - 0x60500000
重新编译uboot
#!/bin/sh
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-
# make clean && make vexpress_ca9x4_defconfig # 不需要改配置
make -j4
仿真(节选)
$ qemu-system-arm -M vexpress-a9 -m 256 -kernel u-boot -nographic
U-Boot 2018.01 (Feb 23 2020 - 10:43:34 +0800)
DRAM: 256 MiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC: MMC: 0
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: smc911x-0
Hit any key to stop autoboot: 0
=> print
...
arch=arm
bootcmd=tftp 0x60003000 uImage;tftp 0x60500000 vexpress-v2p-ca9.dtb; setenv bootargs'root=/dev/mmcblk0 console=ttyAMA0'; bootm 0x60003000 - 0x60500000
...
bootfile=uImage
...
ipaddr=192.168.31.240
...
netmask=255.255.255.0
...
serverip=192.168.31.241
2)指定编译 kernel 与 dtb
LOADADDR(运行地址) 和uboot的启动加载位置一致
export ARCH=arm
export CROSS_COMPILE=arm-linux-gnueabi-
make dtbs -j4
make uImage LOADADDR=0x60003000 -j4
3)进行仿真(把uImage 与 dtb 放到tftp目录下)
sudo qemu-system-arm -M vexpress-a9 -m 256 -kernel u-boot -nographic -net nic,macaddr=00:16:3e:00:00:01 -net tap -sd a9rootfs.ext3
成功的话,会有以下的结果(节选):
TFTP from server 192.168.31.241; our IP address is 192.168.31.240
Filename 'uImage'.
Load address: 0x60003000
Loading: #########################
#########################
####
8.3 MB/s
done
Filename 'vexpress-v2p-ca9.dtb'.
Load address: 0x60500000
Loading: ##
10.3 MB/s
done
starting kernel...
补充一点,既然网络是通的,那么就可以通过uboot 引导nfs,只要修改bootargs的一些参数即可,不在这里赘述,有兴趣的读者可以参考:《配置uboot指定nfs挂载根文件系统》
uboot通过sd卡加载uImage
uboot通过sd卡加载内核 的步骤和以前差不多。
制作SD卡镜像
1)生成一个空的SD卡镜像
dd if=/dev/zero of=uboot.disk bs=1M count=256
# 注意自己控制 count 大小
2)创建GPT分区,
创建两个分区(一个用来存放kernel和设备树,另一个存放根文件系统)
sgdisk -n 0:0:+10M -c 0:kernel uboot.disk
sgdisk -n 0:0:0 -c 0:rootfs uboot.disk
查看分区:
$ sgdisk -p uboot.disk
Disk uboot.disk: 524288 sectors, 256.0 MiB
Logical sector size: 512 bytes
Disk identifier (GUID): 87B3B250-BA97-4089-A0F1-E7807FE061B6
Partition table holds up to 128 entries
First usable sector is 34, last usable sector is 524254
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 22527 10.0 MiB 8300 kernel
2 22528 524254 245.0 MiB 8300 rootfs
3)寻找一个空闲的loop设备 并 将SD卡镜像映射到loop设备上
LOOPDEV=`losetup -f`
sudo losetup $LOOPDEV uboot.disk
sudo partprobe $LOOPDEV
此时会看到/dev/loop0p1 和/dev/loop0p2 两个节点
$ ls /dev/loop*
/dev/loop0 /dev/loop1 /dev/loop4 /dev/loop7
/dev/loop0p1 /dev/loop2 /dev/loop5 /dev/loop-control
/dev/loop0p2 /dev/loop3 /dev/loop6
4)格式化
sudo mkfs.ext4 /dev/loop0p1
sudo mkfs.ext4 /dev/loop0p2
5)挂载
mkdir p1 p2
sudo mount -t ext4 /dev/loop0p1 p1
sudo mount -t ext4 /dev/loop0p2 p2
6)拷贝文件
# 将 zImage 和 dtb 拷贝到 p1
# schips @ ubuntu in ~/arm/sc/linux-4.14.14 [17:55:39]
$ sudo cp arch/arm/boot/zImage p1
$ sudo cp arch/arm/boot/dts/vexpress-v2p-ca9.dtb p1
# 将 文件系统中的文件拷贝到 p2
## 因为在上一讲我已经做好了一个 ext3的镜像,所以我直接使用了
# schips @ ubuntu in ~/arm/sc/linux-4.14.14 [17:59:24] C:1
$ sudo mount -t ext3 ../busybox-1.27.0/a9rootfs.ext3 _tmp -o loop
$ sudo cp _tmp/* p2 -arf
7)取消挂载
sudo umount p1 p2
sudo losetup -d /dev/loop0
启动uboot
使用下面的命令运行uboot
qemu-system-arm -M vexpress-a9 -m 1024M -smp 1 -nographic -kernel u-boot -sd ./uboot.disk
在倒计时结束之前打断它,不要让其进入自主模式
U-Boot 2018.01 (Feb 23 2020 - 18:07:26 +0800)
DRAM: 1 GiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC: MMC: 0
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: smc911x-0
Hit any key to stop autoboot: 0
=>
查看 SD卡的情况,可以用下面的命令查看(默认SD卡就是出于可用状态):
先mmc dev 0
再mmc info
=> mmc dev 0
switch to partitions #0, OK
mmc0 is current device
=> mmc info
Device: MMC
Manufacturer ID: aa
OEM: 5859
Name: QEMU!
Tran Speed: 25000000
Rd Block Len: 512
SD version 2.0
High Capacity: No
Capacity: 256 MiB
Bus Width: 1-bit
Erase Group Size: 512 Bytes
使用part list mmc 0
查看分区内容:
=> part list mmc 0
Partition Map for MMC device 0 -- Partition Type: EFI
Part Start LBA End LBA Name
Attributes
Type GUID
Partition GUID
1 0x00000800 0x000057ff "kernel"
attrs: 0x0000000000000000
type: 0fc63daf-8483-4772-8e79-3d69d8477de4
guid: d3485081-83ea-4027-a379-2f3172877833
2 0x00005800 0x0007ffde "rootfs"
attrs: 0x0000000000000000
type: 0fc63daf-8483-4772-8e79-3d69d8477de4
guid: d058e69e-02aa-4543-9f1a-4bd3809fb275
查看SD卡2个分区里面的东西:
分区1: ls mmc 0:1
或者 ext4ls mmc 0:1
分区2: ls mmc 0:2
或者 ext4ls mmc 0:2
=> ls mmc 0:1
<DIR> 1024 .
<DIR> 1024 ..
<DIR> 12288 lost+found
3961960 zImage
14692 vexpress-v2p-ca9.dtb
=> ext4ls mmc 0:1
<DIR> 1024 .
<DIR> 1024 ..
<DIR> 12288 lost+found
3961960 zImage
14692 vexpress-v2p-ca9.dtb
=> ext4ls mmc 0:2
<DIR> 1024 .
<DIR> 1024 ..
<DIR> 12288 lost+found
12288 app
<DIR> 3072 bin
<DIR> 1024 dev
<DIR> 1024 etc
<DIR> 4096 lib
<SYM> 11 linuxrc
<DIR> 1024 mnt
<DIR> 1024 proc
<DIR> 1024 root
<DIR> 3072 sbin
<DIR> 1024 sys
<DIR> 1024 tmp
<DIR> 1024 usr
<DIR> 1024 var
加载kernel、设备树
加载sd卡分区中指定的文件(内核)到指定的内存: load mmc 0:1 0x60008000 zImage
或者ext4load mmc 0:1 0x60008000 zImage
=> load mmc 0:1 0x60008000 zImage
3961960 bytes read in 11446 ms (337.9 KiB/s)
加载sd卡分区中指定的文件(设备树)到指定的内存:load mmc 0:1 0x61000000 vexpress-v2p-ca9.dtb
或者 ext4load mmc 0:1 0x61000000 vexpress-v2p-ca9.dtb
=> load mmc 0:1 0x61000000 vexpress-v2p-ca9.dtb
14692 bytes read in 35 ms (409.2 KiB/s)
设置bootargs
setenv bootargs 'root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait earlycon console=tty0 console=ttyAMA0 init=/linuxrc ignore_loglevel'
引导内核
=> bootz 0x60008000 - 0x61000000
关于 uboot 启动命令可以参考:《Uboot 命令行 介绍》
固化启动命令
如果没有问题的话,那么可以在uboot的代码中将上面的命令固化进程序中
在include/configs/vexpress_common.h
中修改CONFIG_BOOTCOMMAND
改成
#define CONFIG_BOOTCOMMAND "load mmc 0:1 0x60008000 zImage ;load mmc 0:1 0x61000000 vexpress-v2p-ca9.dtb; setenv bootargs "root=/dev/mmcblk0p2 earlycon console=ttyAMA0"; bootz 0x60008000 - 0x61000000"
再重新编译即可。
启动结果
完整的启动结果如下:
$ qemu-system-arm -M vexpress-a9 -m 1024M -smp 1 -nographic -kernel u-boot -sd uboot.disk
WARNING: Image format was not specified for 'uboot.disk' 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.
U-Boot 2018.01 (Feb 23 2020 - 18:07:26 +0800)
DRAM: 1 GiB
WARNING: Caches not enabled
Flash: 128 MiB
MMC: MMC: 0
*** Warning - bad CRC, using default environment
In: serial
Out: serial
Err: serial
Net: smc911x-0
Hit any key to stop autoboot: 0
=> load mmc 0:1 0x60008000 zImage
3961960 bytes read in 11530 ms (335 KiB/s)
=> load mmc 0:1 0x61000000 vexpress-v2p-ca9.dtb
14692 bytes read in 38 ms (377 KiB/s)
=> setenv bootargs 'root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait earlycon console=tty0 console=ttyAMA0 init=/linuxrc ignore_loglevel'
=> bootz 0x60008000 - 0x61000000
Kernel image @ 0x60008000 [ 0x000000 - 0x3c7468 ]
## Flattened Device Tree blob at 61000000
Booting using the fdt blob at 0x61000000
Loading Device Tree to 7fef1000, end 7fef7963 ... OK
Starting kernel ...
Booting Linux on physical CPU 0x0
Linux version 4.14.14 (schips@ubuntu) (gcc version 7.4.1 20181213 [linaro-7.4-2019.02 revision 56ec6f6b99cc167ff0c2f8e1a2eed33b1edc85d4] (Linaro GCC 7.4-2019.02)) #1 SMP Sat Feb 22 21:14:14 CST 2020
CPU: ARMv7 Processor [410fc090] revision 0 (ARMv7), cr=10c5387d
CPU: PIPT / VIPT nonaliasing data cache, VIPT nonaliasing instruction cache
OF: fdt: Machine model: V2P-CA9
Malformed early option 'earlycon'
debug: ignoring loglevel setting.
Memory policy: Data cache writeback
On node 0 totalpages: 262144
free_area_init_node: node 0, pgdat 80a5f080, node_mem_map bf7fb000
Normal zone: 2048 pages used for memmap
Normal zone: 0 pages reserved
Normal zone: 262144 pages, LIFO batch:31
CPU: All CPU(s) started in SVC mode.
random: fast init done
percpu: Embedded 16 pages/cpu @bf7ae000 s36428 r8192 d20916 u65536
pcpu-alloc: s36428 r8192 d20916 u65536 alloc=16*4096
pcpu-alloc: [0] 0 [0] 1 [0] 2 [0] 3
Built 1 zonelists, mobility grouping on. Total pages: 260096
Kernel command line: root=/dev/mmcblk0p2 rw rootfstype=ext4 rootwait earlycon console=tty0 console=ttyAMA0 init=/linuxrc ignore_loglevel
log_buf_len individual max cpu contribution: 4096 bytes
log_buf_len total cpu_extra contributions: 12288 bytes
log_buf_len min size: 16384 bytes
log_buf_len: 32768 bytes
early log buf free: 14720(89%)
PID hash table entries: 4096 (order: 2, 16384 bytes)
Dentry cache hash table entries: 131072 (order: 7, 524288 bytes)
Inode-cache hash table entries: 65536 (order: 6, 262144 bytes)
Memory: 1029388K/1048576K available (6144K kernel code, 402K rwdata, 1364K rodata, 1024K init, 169K bss, 19188K reserved, 0K cma-reserved)
Virtual kernel memory layout:
vector : 0xffff0000 - 0xffff1000 ( 4 kB)
fixmap : 0xffc00000 - 0xfff00000 (3072 kB)
vmalloc : 0xc0800000 - 0xff800000 (1008 MB)
lowmem : 0x80000000 - 0xc0000000 (1024 MB)
modules : 0x7f000000 - 0x80000000 ( 16 MB)
.text : 0x80008000 - 0x80700000 (7136 kB)
.init : 0x80900000 - 0x80a00000 (1024 kB)
.data : 0x80a00000 - 0x80a649b8 ( 403 kB)
.bss : 0x80a6bd30 - 0x80a964b4 ( 170 kB)
SLUB: HWalign=64, Order=0-3, MinObjects=0, CPUs=4, Nodes=1
Hierarchical RCU implementation.
RCU event tracing is enabled.
RCU restricting CPUs from NR_CPUS=8 to nr_cpu_ids=4.
RCU: Adjusting geometry for rcu_fanout_leaf=16, nr_cpu_ids=4
NR_IRQS: 16, nr_irqs: 16, preallocated irqs: 16
GIC CPU mask not found - kernel will fail to boot.
GIC CPU mask not found - kernel will fail to boot.
smp_twd: clock not found -2
sched_clock: 32 bits at 24MHz, resolution 41ns, wraps every 89478484971ns
clocksource: arm,sp804: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 1911260446275 ns
Failed to initialize '/smb@4000000/motherboard/iofpga@7,00000000/timer@12000': -22
Console: colour dummy device 80x30
console [tty0] enabled
Calibrating local timer... 90.87MHz.
Calibrating delay loop... 560.33 BogoMIPS (lpj=2801664)
pid_max: default: 32768 minimum: 301
Mount-cache hash table entries: 2048 (order: 1, 8192 bytes)
Mountpoint-cache hash table entries: 2048 (order: 1, 8192 bytes)
CPU: Testing write buffer coherency: ok
CPU0: thread -1, cpu 0, socket 0, mpidr 80000000
Setting up static identity map for 0x60100000 - 0x60100060
Hierarchical SRCU implementation.
smp: Bringing up secondary CPUs ...
smp: Brought up 1 node, 1 CPU
SMP: Total of 1 processors activated (560.33 BogoMIPS).
CPU: All CPU(s) started in SVC mode.
devtmpfs: initialized
VFP support v0.3: implementor 41 architecture 3 part 30 variant 9 rev 0
clocksource: jiffies: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 19112604462750000 ns
futex hash table entries: 1024 (order: 4, 65536 bytes)
NET: Registered protocol family 16
DMA: preallocated 256 KiB pool for atomic coherent allocations
cpuidle: using governor ladder
hw-breakpoint: debug architecture 0x4 unsupported.
Serial: AMBA PL011 UART driver
OF: amba_device_add() failed (-19) for /memory-controller@100e0000
OF: amba_device_add() failed (-19) for /memory-controller@100e1000
OF: amba_device_add() failed (-19) for /watchdog@100e5000
10009000.uart: ttyAMA0 at MMIO 0x10009000 (irq = 35, base_baud = 0) is a PL011 rev1
console [ttyAMA0] enabled
1000a000.uart: ttyAMA1 at MMIO 0x1000a000 (irq = 36, base_baud = 0) is a PL011 rev1
1000b000.uart: ttyAMA2 at MMIO 0x1000b000 (irq = 37, base_baud = 0) is a PL011 rev1
1000c000.uart: ttyAMA3 at MMIO 0x1000c000 (irq = 38, base_baud = 0) is a PL011 rev1
OF: amba_device_add() failed (-19) for /smb@4000000/motherboard/iofpga@7,00000000/wdt@f000
SCSI subsystem initialized
libata version 3.00 loaded.
usbcore: registered new interface driver usbfs
usbcore: registered new interface driver hub
usbcore: registered new device driver usb
Advanced Linux Sound Architecture Driver Initialized.
clocksource: Switched to clocksource arm,sp804
NET: Registered protocol family 2
TCP established hash table entries: 8192 (order: 3, 32768 bytes)
TCP bind hash table entries: 8192 (order: 4, 65536 bytes)
TCP: Hash tables configured (established 8192 bind 8192)
UDP hash table entries: 512 (order: 2, 16384 bytes)
UDP-Lite hash table entries: 512 (order: 2, 16384 bytes)
NET: Registered protocol family 1
RPC: Registered named UNIX socket transport module.
RPC: Registered udp transport module.
RPC: Registered tcp transport module.
RPC: Registered tcp NFSv4.1 backchannel transport module.
hw perfevents: enabled with armv7_cortex_a9 PMU driver, 1 counters available
workingset: timestamp_bits=30 max_order=18 bucket_order=0
squashfs: version 4.0 (2009/01/31) Phillip Lougher
jffs2: version 2.2. (NAND) © 2001-2006 Red Hat, Inc.
9p: Installing v9fs 9p2000 file system support
io scheduler noop registered (default)
io scheduler mq-deadline registered
io scheduler kyber registered
clcd-pl11x 10020000.clcd: PL111 designer 41 rev2 at 0x10020000
clcd-pl11x 10020000.clcd: /clcd@10020000 hardware, 1024x768@59 display
Console: switching to colour frame buffer device 128x48
clcd-pl11x 1001f000.clcd: PL111 designer 41 rev2 at 0x1001f000
clcd-pl11x 1001f000.clcd: /smb@4000000/motherboard/iofpga@7,00000000/clcd@1f000 hardware, 640x480@59 display
40000000.flash: Found 2 x16 devices at 0x0 in 32-bit bank. Manufacturer ID 0x000000 Chip ID 0x000000
Intel/Sharp Extended Query Table at 0x0031
Using buffer write method
erase region 0: offset=0x0,size=0x40000,blocks=256
40000000.flash: Found 2 x16 devices at 0x0 in 32-bit bank. Manufacturer ID 0x000000 Chip ID 0x000000
Intel/Sharp Extended Query Table at 0x0031
Using buffer write method
erase region 0: offset=0x0,size=0x40000,blocks=256
Concatenating MTD devices:
(0): "40000000.flash"
(1): "40000000.flash"
into device "40000000.flash"
libphy: Fixed MDIO Bus: probed
libphy: smsc911x-mdio: probed
smsc911x 4e000000.ethernet eth0: MAC Address: 52:54:00:12:34:56
isp1760 4f000000.usb: bus 32, oc: digital
isp1760 4f000000.usb: NXP ISP1760 USB Host Controller
isp1760 4f000000.usb: new USB bus registered, assigned bus number 1
isp1760 4f000000.usb: Scratch test failed.
isp1760 4f000000.usb: can't setup: -19
isp1760 4f000000.usb: USB bus 1 deregistered
usbcore: registered new interface driver usb-storage
rtc-pl031 10017000.rtc: rtc core: registered pl031 as rtc0
IR NEC protocol handler initialized
IR RC5(x/sz) protocol handler initialized
IR RC6 protocol handler initialized
IR JVC protocol handler initialized
IR Sony protocol handler initialized
IR SANYO protocol handler initialized
IR Sharp protocol handler initialized
IR MCE Keyboard/mouse protocol handler initialized
IR XMP protocol handler initialized
mmci-pl18x 10005000.mmci: Got CD GPIO
mmci-pl18x 10005000.mmci: Got WP GPIO
mmci-pl18x 10005000.mmci: mmc0: PL181 manf 41 rev0 at 0x10005000 irq 31,32 (pio)
input: AT Raw Set 2 keyboard as /devices/platform/smb@4000000/smb@4000000:motherboard/smb@4000000:motherboard:iofpga@7,00000000/10006000.kmi/serio0/input/input0
mmc0: new SD card at address 4567
ledtrig-cpu: registered to indicate activity on CPUs
usbcore: registered new interface driver usbhid
usbhid: USB HID core driver
mmcblk0: mmc0:4567 QEMU! 256 MiB
aaci-pl041 10004000.aaci: ARM AC'97 Interface PL041 rev0 at 0x10004000, irq 30
aaci-pl041 10004000.aaci: FIFO 512 entries
oprofile: using arm/armv7-ca9
NET: Registered protocol family 17
9pnet: Installing 9P2000 support
Registering SWP/SWPB emulation handler
mmcblk0: p1 p2
rtc-pl031 10017000.rtc: setting system clock to 2020-02-23 10:36:55 UTC (1582454215)
ALSA device list:
#0: ARM AC'97 Interface PL041 rev0 at 0x10004000, irq 30
input: ImExPS/2 Generic Explorer Mouse as /devices/platform/smb@4000000/smb@4000000:motherboard/smb@4000000:motherboard:iofpga@7,00000000/10007000.kmi/serio1/input/input2
EXT4-fs (mmcblk0p2): Filesystem with huge files cannot be mounted RDWR without CONFIG_LBDAF
EXT4-fs (mmcblk0p2): mounted filesystem with ordered data mode. Opts: (null)
VFS: Mounted root (ext4 filesystem) readonly on device 179:2.
Freeing unused kernel memory: 1024K
random: crng init done
Processing /etc/profile... Done
/ # ls
app etc lost+found root tmp
bin lib mnt sbin usr
dev linuxrc proc sys var
总结
通过上文,我们了解了如何在QEMU中启动uboot,并通过不同的方式来引导内核。也了解了整个嵌入式系统的完整启动流程。