关于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地址处正式运行。 |