关于uBoot和Linux内核中几个地址参数及uboot加载启动内核过程的理解
uboot一般使用mkimage工具先制作一个启动映象文件来引导识别内核的,uboot源代码的tools/目录下有mkimage工具,这个工具可以用来制作不压缩或者压缩的多种可启动映象文件。mkimage在制作映象文件的时候,是在原来的可执行映象文件的前面加上一个0x40字节的头,记录参数所指定的信息,这样uboot才能识别这个映象是针对哪个CPU体系结构的,哪个OS的,哪种类型,加载内存中的哪个位置, 入口点在内存的那个位置以及映象名是什么
vim arch/arm/Makefile
31 # defines filename extension depending memory management type.
32 ifeq ($(CONFIG_MMU),)
33 MMUEXT := -nommu
34 endif
121 #Default value
122 head-y := arch/arm/kernel/head$(MMUEXT).o arch/arm/kernel/init_task .o
123 textofs-y := 0x00008000
124 textofs-$(CONFIG_ARCH_CLPS711X) := 0x00028000
125 # We don't want the htc bootloader to corrupt kernel during resume
126 textofs-$(CONFIG_PM_H1940) := 0x00108000
127 # SA1111 DMA bug: we don't want the kernel to live in precious DMA-able memo ry
128 ifeq ($(CONFIG_ARCH_SA1100),y)
129 textofs-$(CONFIG_SA1111) := 0x00208000
130 endif
222 # The byte offset of the kernel image in RAM from the start of RAM.
223 TEXT_OFFSET := $(textofs-y)
241 export TEXT_OFFSET GZFLAGS MMUEXT
./scripts/mkuboot.sh
#!/bin/bash
#
# Build U-Boot image when `mkimage' tool is available.
#
MKIMAGE=$(type -path "${CROSS_COMPILE}mkimage")
if [ -z "${MKIMAGE}" ]; then
MKIMAGE=$(type -path mkimage)
if [ -z "${MKIMAGE}" ]; then
# Doesn't exist
echo '"mkimage" command not found - U-Boot images will not be built' >&2
exit 1;
fi
fi
# Call "mkimage" to create U-Boot image
${MKIMAGE} "$@"
./arch/arm/mach-s3c2410/Makefile.boot
1 ifeq ($(CONFIG_PM_H1940),y)
2 zreladdr-y := 0x30108000
3 params_phys-y := 0x30100100
4 else
5 zreladdr-y := 0x30008000
6 params_phys-y := 0x30000100
7 endif
vim arch/arm/boot/Makefile
14 MKIMAGE := $(srctree)/scripts/mkuboot.sh
16 ifneq ($(MACHINE),)
17 include $(srctree)/$(MACHINE)/Makefile.boot //即arch/arm/mach-s3c2410/Makefile.boot
18 endif
20 # Note: the following conditions must always be true:
21 # ZRELADDR == virt_to_phys(PAGE_OFFSET + TEXT_OFFSET)
22 # PARAMS_PHYS must be within 4MB of ZRELADDR
23 # INITRD_PHYS must be in RAM
24 ZRELADDR := $(zreladdr-y) //内核加载地址ZRELADDR
25 PARAMS_PHYS := $(params_phys-y)
26 INITRD_PHYS := $(initrd_phys-y)
27
28 export ZRELADDR INITRD_PHYS PARAMS_PHYS
29
30 targets := Image zImage xipImage bootpImage uImage
62 quiet_cmd_uimage = UIMAGE $@
63 cmd_uimage = $(CONFIG_SHELL) $(MKIMAGE) -A arm -O linux -T kernel \
64 -C none -a $(LOADADDR) -e $(STARTADDR) \
65 -n 'Linux-$(KERNELRELEASE)' -d $< $@
66
67 ifeq ($(CONFIG_ZBOOT_ROM),y)
68 $(obj)/uImage: LOADADDR=$(CONFIG_ZBOOT_ROM_TEXT)
69 else
70 $(obj)/uImage: LOADADDR=$(ZRELADDR)
71 endif
72
73 $(obj)/uImage: STARTADDR=$(LOADADDR)
cmd_uimage展开相当于:
mkimage -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008000 -n 'Linux-3.0" -d zImage uImage
-A:CPU类型
-O:操作系统
-T:用于指定image类型,比如Kernel
-C:采用的压缩方式
-a:内核加载地址
-e:内核入口地址
-d 无头信息的image文件名
Boot options --->
[ ] Flattened Device Tree support
(0x0) Compressed ROM boot loader base address
(0x0) Compressed ROM boot loader BSS address
430:CONFIG_ZBOOT_ROM_TEXT=0x0
431:CONFIG_ZBOOT_ROM_BSS=0x0
arch/arm/boot/compressed/Makefile
ifeq ($(CONFIG_ZBOOT_ROM),y)
ZTEXTADDR := $(CONFIG_ZBOOT_ROM_TEXT) //自解压程序地址ZTEXTADDR
ZBSSADDR := $(CONFIG_ZBOOT_ROM_BSS)
else
ZTEXTADDR := 0
ZBSSADDR := ALIGN(8)
endif
默认值ZTEXTADDR= 0x00000000表示不使用。(只能通过uBoot的gunzip解压加载)
include/configs/st2410.h -n
127:#define CFG_LOAD_ADDR 0x33000000 /* default load address*///uImage存放地址
uBoot的do_bootm(cmd_tbl_t *cmdtp, int flag, int argc, char *argv[]);
函数将检验存放到0x33000000地址处的经过mkimage格式化的uImage数据的头部
typedef struct image_header {
uint32_t ih_magic; /* Image Header Magic Number */
uint32_t ih_hcrc; /* Image Header CRC Checksum */
uint32_t ih_time; /* Image Creation Timestamp */
uint32_t ih_size; /* Image Data Size */
uint32_t ih_load; /* Data Load Address */
uint32_t ih_ep; /* Entry Point Address */
uint32_t ih_dcrc; /* Image Data CRC Checksum */
uint8_t ih_os; /* Operating System */
uint8_t ih_arch; /* CPU architecture */
uint8_t ih_type; /* Image Type */
uint8_t ih_comp; /* Compression Type */
uint8_t ih_name[IH_NMLEN]; /* Image Name */
} image_header_t;
(ih_ep值为0x30008000,ih_load值为0x30008000)
如果头部各个域值和crc合法,那么do_bootm将调用如下gunzip解压函数对
0x33000000 +sizeof(image_header_t)地址处的压缩内核进行解压:
gunzip((void*)ntohl(hdr->ih_load),unc_len,(uchar *)data,(int*)&len);
1.hdr->ih_load 为输出数据地址0x30008000
2.unc_len 为gunzip解压输出数据上限值-8M,do_bootm函数前有定义#define CFG_BOOTM_LEN 0x800000,uint unc_len = CFG_BOOTM_LEN;
3.data 为输入数据地址data=0x33000000 +sizeof(image_header_t);
4.Len 为输入数据长度len = ntohl(hdr->ih_size );
解压完成后将会存储解压后数据的实际大小
压缩的Linux内核文件uImage,经由gunzip解压函数后,通过
do_bootm_linux (cmdtp, flag, argc, argv,addr, len_ptr, verify);
函数向Linux内核传递内核运行所需的3个参数,在bootm执行的流程中,可以看到会调用do_bootm_linux()在执行Linux内核,内核的起始地址如下:
void (*theKernel)(int zero, int arch, uint params);
image_header_t *hdr = &header;
theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);
header是uImage的头部,通过头部,得到内核映像起始的执行地址hdr->ih_ep为0x30008000,标识为theKernel。从中也可以看到,内核接受三个参数,第一个为0,第二个为系统的ID号,第三个是传入内核的参数。
在do_bootm_linux()的最后,会跳到内核去执行:
theKernel (0, bd->bi_arch_number, bd->bi_boot_params);
这样完成了Linux系统启动所需要3个参数的传递,至此uBoot的工作已经结束,Linux将在0x30008000地址处正式运行。