uboot引导内核 Load Address Entry Point

前言

本次实验环境
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;  //将 uImage 下载到 0x60003000
bootm 0x60003000;  // 从 0x60003000 开始解析 zImage 的要求,并按照要求行事. 注意: 此时不是从 0x60003000 启动.

  • uboot 根据 两条需求 怎么侍奉 内核

uboot 一般通过 这两条 command line 来达到目的
tftp 0x60003000 uImage; bootm 0x60003000;

tftp A_addr uImage; bootm B_addr ; //A_addr 必须和 B_addr 一样, 且具体是什么 由 soc 的内存映射决定,值并不是唯一的

tftp 0x60003000 uImage 只是将 uImage 下载到一个 临时地址.下一句才是 安排住宿 和 控制交接的  流程
bootm 0x60003000 ;
1.
uImage(uImage头+ zImage) 已经在 0x60003000,0x60003000(uImage头的位置,存储zImage 要求 1. 住宿地址 2.控制地址) 解析 住宿地址 和 控制地址.
2.
如果 0x60003040(0x60003000+0x40) 已经是 zImage 想要的 住宿地址(0x60003040 == Load Address),就不用 重新安排住宿. // 0x40 是 uImage 头 的长度
如果 0x60003040 不是 zImage 想要的 住宿地址(0x60003040 != Load Address),就将 zImage 搬到 zImage要求的地址(Load Address).
3.
目前 zImage 已经到了想要的住宿环境 ,uboot 就将 控制权(pc)转移到 Entry Point.

  • 内核怎么提出自己的 两条需求

下面注意关注 LOADADDR

//arch/arm/boot/Makefile
ifneq ($(LOADADDR),)           // 可通过     make LOADADDR=0x60004000 uImage    指定      LOADADDR
  UIMAGE_LOADADDR=$(LOADADDR)                                                       
else                                                                                
  ifeq ($(CONFIG_ZBOOT_ROM),y)                                                      
    UIMAGE_LOADADDR=$(CONFIG_ZBOOT_ROM_TEXT)                                        
  else                                                                              
    UIMAGE_LOADADDR=$(ZRELADDR)                                                     
  endif                                                                             
endif

------------------------------手动分隔

下面注意关注 UIMAGE_LOADADDR

//arch/arm/boot/Makefile
$(obj)/uImage:  $(obj)/zImage FORCE                                                 
    @$(check_for_multiple_loadaddr)                                                 
    $(call if_changed,uimage)        // Documentation/kbuild/makefiles.txt  
    @$(kecho) '  Image $@ is ready'
    

------------------------------手动分隔

下面注意关注 cmd_uimage 中 的 UIMAGE_LOADADDR 和 UIMAGE_ENTRYADDR

// scripts/Makefile.lib
# 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 是什么

  • 测试1
// 内核信息
Load Address: 60004000
Entry Point:  60004000

//uboot command
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 // 加载内核,此时打印 Loading Kernel Image ... // 有可能搬移内核 ,to:60004000,from:60003040

		do_bootm_linux
			boot_prep_linux
		boot_selected_os
			do_bootm_linux
				boot_jump_linux(images, flag);
					announce_and_cleanup // 打印 Starting kernel ...  // 往后 uboot 不再打印
					kernel_entry(0, machid, r2); // uboot 最后一个语句

  • 测试2
//内核信息
Load Address: 60004000
Entry Point:  60004000

//uboot command line
tftp 0x60004000 bootm 0x60004000

也进行了搬移
to:60004000,from:60004040

  • 测试3

// 内核信息
Load Address: 60004040
Entry Point:  60004040

// uboot command line
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
// scripts/Kbuild.include

# 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

// uboot command line
tftp 0x60004000 bootm 0x60004000


Wrong Image Format for bootm command
ERROR: can't get kernel image!  


------------------------------手动分隔

uboot 怎么引导zImage
    可以修改uboot 来直接引导 zImage,跳过 对 uImage头的解析

你可能感兴趣的:(uboot,kernel-boot)