前言
本次实验环境
linux-4.0.tar.xz
u-boot-2017.05.tar.bz2
问题描述
在系统移植的第一步,一般是 直接 找个 相似的 config ,然后配置一下,然后编译一下.直接tftp 然后bootm
如果 没有看到 Uncompressing Linux... done, booting the kernel
一般是因为 地址 的问题
这里面涉及到 四个地址
tftp 地址 / bootm 地址 / Load Address / Entry Point
总结
从实验来看
可见,内核(zImage,uImage去掉uImage头就是zImage)最终在内核的地址 还是内核做主.
Load Address 表示 内核镜像(zImage)想要 住宿 的 内存地址
Entry Point 表示 当 内核镜像已经 住宿 到内存中去, uboot 要 将控制权 转移到 Entry Point ,也就是 uboot 的 最后一句 kernel_entry(0, machid, r2); 这个函数的 地址 就是 Entry Point. 这个 Entry Point 就是 解压代码的第一条指令.
---
Load Address 是 zImage 的住宿地址
Entry Point 是 zImage 的控制地址,(从这个地址接收控制权)
可以看出来 uboot 就像 奴仆 一样 侍奉 kernel
tftp 0x60003000 uImage;
bootm 0x60003000;
uboot 一般通过 这两条 command line 来达到目的
tftp 0x60003000 uImage; bootm 0x60003000;
tftp A_addr uImage; bootm B_addr ;
tftp 0x60003000 uImage 只是将 uImage 下载到一个 临时地址.下一句才是 安排住宿 和 控制交接的 流程
bootm 0x60003000 ;
1.
uImage(uImage头+ zImage) 已经在 0x60003000, 从 0x60003000(uImage头的位置,存储zImage 要求 1. 住宿地址 2.控制地址) 解析 住宿地址 和 控制地址.
2.
如果 0x60003040(0x60003000+0x40) 已经是 zImage 想要的 住宿地址(0x60003040 == Load Address),就不用 重新安排住宿.
如果 0x60003040 不是 zImage 想要的 住宿地址(0x60003040 != Load Address),就将 zImage 搬到 zImage要求的地址(Load Address).
3.
目前 zImage 已经到了想要的住宿环境 ,uboot 就将 控制权(pc)转移到 Entry Point.
下面注意关注 LOADADDR
ifneq ($(LOADADDR),)
UIMAGE_LOADADDR=$(LOADADDR)
else
ifeq ($(CONFIG_ZBOOT_ROM),y)
UIMAGE_LOADADDR=$(CONFIG_ZBOOT_ROM_TEXT)
else
UIMAGE_LOADADDR=$(ZRELADDR)
endif
endif
------------------------------手动分隔
下面注意关注 UIMAGE_LOADADDR
$(obj)/uImage: $(obj)/zImage FORCE
@$(check_for_multiple_loadaddr)
$(call if_changed,uimage)
@$(kecho) ' Image $@ is ready'
------------------------------手动分隔
下面注意关注 cmd_uimage 中 的 UIMAGE_LOADADDR 和 UIMAGE_ENTRYADDR
# U-Boot mkimage
# ---------------------------------------------------------------------------
MKIMAGE := $(srctree)/scripts/mkuboot.sh
# SRCARCH just happens to match slightly more than ARCH (on sparc), so reduces
# the number of overrides in arch makefiles
UIMAGE_ARCH ?= $(SRCARCH)
UIMAGE_COMPRESSION ?= $(if $(2),$(2),none)
UIMAGE_OPTS-y ?=
UIMAGE_TYPE ?= kernel
UIMAGE_LOADADDR ?= arch_must_set_this
UIMAGE_ENTRYADDR ?= $(UIMAGE_LOADADDR)
UIMAGE_NAME ?= 'Linux-$(KERNELRELEASE)'
UIMAGE_IN ?= $<
UIMAGE_OUT ?= $@
quiet_cmd_uimage = UIMAGE $(UIMAGE_OUT)
cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A $(UIMAGE_ARCH) -O linux \
-C $(UIMAGE_COMPRESSION) $(UIMAGE_OPTS-y) \
-T $(UIMAGE_TYPE) \
-a $(UIMAGE_LOADADDR) -e $(UIMAGE_ENTRYADDR) \
-n $(UIMAGE_NAME) -d $(UIMAGE_IN) $(UIMAGE_OUT)
------------------------------手动分隔
cmd_uimage 最后的体现是
$cat arch/arm/boot/.uImage.cmd
cmd_arch/arm/boot/uImage := /bin/bash ./scripts/mkuboot.sh -A arm -O linux -C none -T kernel -a 0x60004000 -e 0x60004000 -n 'Linux-4.0.0' -d arch/arm/boot/zImage arch/arm/boot/uImage
实验流程
$ export ARCH=arm CROSS_COMPILE=arm-linux-gnueabi-;make vexpress_defconfig;make LOADADDR=0x60004000 uImage -j8
...
LD vmlinux
SORTEX vmlinux
SYSMAP System.map
OBJCOPY arch/arm/boot/Image
Kernel: arch/arm/boot/Image is ready
LDS arch/arm/boot/compressed/vmlinux.lds
AS arch/arm/boot/compressed/head.o
GZIP arch/arm/boot/compressed/piggy.gzip
CC arch/arm/boot/compressed/misc.o
CC arch/arm/boot/compressed/decompress.o
CC arch/arm/boot/compressed/string.o
SHIPPED arch/arm/boot/compressed/hyp-stub.S
SHIPPED arch/arm/boot/compressed/lib1funcs.S
SHIPPED arch/arm/boot/compressed/ashldi3.S
SHIPPED arch/arm/boot/compressed/bswapsdi2.S
AS arch/arm/boot/compressed/hyp-stub.o
AS arch/arm/boot/compressed/lib1funcs.o
AS arch/arm/boot/compressed/ashldi3.o
AS arch/arm/boot/compressed/bswapsdi2.o
AS arch/arm/boot/compressed/piggy.gzip.o
LD arch/arm/boot/compressed/vmlinux
OBJCOPY arch/arm/boot/zImage
Kernel: arch/arm/boot/zImage is ready
UIMAGE arch/arm/boot/uImage
Image Name: Linux-4.0.0+
Created: Tue Oct 9 18:14:46 2018
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 6317536 Bytes = 6169.47 kB = 6.02 MB
Load Address: 60004000
Entry Point: 60004000
Image arch/arm/boot/uImage is ready
可以看到,
1/
首先生成了 vmlinux ,然后vmlinux 被 OBJCOPY 成了 Image
2/
一些解压代码 和 压缩过后的 Image 链接成了 zImage
3/
通过 UIMAGE 将 zImage 做成了 uImage
4/
打印了 uImage的信息
----
此时的关注点在
1/
UIMAGE 是什么
2/
uImage 打印信息中 的 Load Address 和 Entry Point 是什么
Load Address: 60004000
Entry Point: 60004000
tftp 0x60003000 uImage; bootm 0x60003000
正常启动.
## Booting kernel from Legacy Image at 60003000 ...
Image Name: Linux-4.0.0
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 3409856 Bytes = 3.3 MiB
Load Address: 60004000
Entry Point: 60004000
Verifying Checksum ... OK
## Flattened Device Tree blob at 60500000
Booting using the fdt blob at 0x60500000
Loading Kernel Image ... OK
Loading Device Tree to 7fed4000, end 7feda6df ... OK
Starting kernel ...
kernel_entry addr : 60004000
Booting Linux on physical CPU 0x0
Initializing cgroup subsys cpuset
Linux version 4.0.0 (pop@ubuntu) (gcc version 5.4.0 20160609 (Ubuntu/Linaro 5.4.0-6ubuntu1~16.04.9) ) #2 SMP Mon Oct 8 00:43:35 PDT 2018
------------
追踪uboot 代码流程发现
Starting kernel ... 之前,有搬移内核,并从60004000 启动
从 from:60003040 搬移 到 to:60004000
---------------
bootm 流程
do_bootm
do_bootm_states
bootm_load_os
bootm_decomp_image
do_bootm_linux
boot_prep_linux
boot_selected_os
do_bootm_linux
boot_jump_linux(images, flag);
announce_and_cleanup
kernel_entry(0, machid, r2);
Load Address: 60004000
Entry Point: 60004000
tftp 0x60004000 bootm 0x60004000
也进行了搬移
to:60004000,from:60004040
Load Address: 60004040
Entry Point: 60004040
tftp 0x60004000 bootm 0x60004000
不搬移,且打印 XIP Kernel Image ...
---
Load Address: 60004040 Entry Point: 60004040 这样子的内核 是 我们 手动做出来的,当然也可以 通过 make 生成.
/bin/bash ./scripts/mkuboot.sh -A arm -O linux -C none -T kernel -a 0x60004040 -e 0x60004040 -n 'Linux-4.0.0' -d arch/arm/boot/zImage arch/arm/boot/uImage
Image Name: Linux-4.0.0
Created: Tue Oct 9 20:07:23 2018
Image Type: ARM Linux Kernel Image (uncompressed)
Data Size: 3409856 Bytes = 3329.94 kB = 3.25 MB
Load Address: 60004040
Entry Point: 60004040
其他
if_changed_rule
# Usage: $(call if_changed_rule,foo)
# Will check if $(cmd_foo) or any of the prerequisites changed,
# and if so will execute $(rule_foo).
if_changed_rule = $(if $(strip $(any-prereq) $(arg-check) ), \
@set -e; \
$(rule_$(1)))
uboot 引导 zImage
uboot可以引导 zImage? 不可以
------------------------------手动分隔
测试
Load Address: 60004040
Entry Point: 60004040
tftp 0x60004000 bootm 0x60004000
Wrong Image Format for bootm command
ERROR: can't get kernel image!
------------------------------手动分隔
uboot 怎么引导zImage
可以修改uboot 来直接引导 zImage,跳过 对 uImage头的解析