一. bootz启动Linux
uboot 启动Linux内核使用bootz命令。当然还有其它的启动命令,例如,bootm命令等等。
本文只分析 bootz命令启动 Linux内核的过程中涉及的几个重要函数。具体分析 bootz_start 函数执行过程。
本文继上一篇文章,地址如下:
bootz启动 Linux内核过程中涉及的 do_bootz 函数_凌肖战的博客-CSDN博客
二. bootz 启动 Linux 内核涉及函数
上一篇文章简单分析,可以知道:
bootz 命令的执行函数为 do_bootz函数。而 do_bootz函数主要调用如下函数:
bootz_start 函数,bootm_disable_interrupts 函数,设置 images.os.os ,do_bootm_states 函数。
1. bootz_start 函数
bootz_srart
函数也定义在文件
cmd/bootm.c
中,函数内容如下:
static int bootz_start(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[], bootm_headers_t *images)
{
int ret;
ulong zi_start, zi_end;
ret = do_bootm_states(cmdtp, flag, argc, argv, BOOTM_STATE_START,
images, 1);
/* Setup Linux kernel zImage entry point */
if (!argc) {
images->ep = load_addr;
debug("* kernel: default image load address = 0x%08lx\n",
load_addr);
} else {
images->ep = simple_strtoul(argv[0], NULL, 16);
debug("* kernel: cmdline image address = 0x%08lx\n",
images->ep);
}
ret = bootz_setup(images->ep, &zi_start, &zi_end);
if (ret != 0)
return 1;
lmb_reserve(&images->lmb, images->ep, zi_end - zi_start);
/*
* Handle the BOOTM_STATE_FINDOTHER state ourselves as we do not
* have a header that provide this informaiton.
*/
if (bootm_find_images(flag, argc, argv))
return 1;
#ifdef CONFIG_SECURE_BOOT
extern uint32_t authenticate_image(
uint32_t ddr_start, uint32_t image_size);
if (authenticate_image(images->ep, zi_end - zi_start) == 0) {
printf("Authenticate zImage Fail, Please check\n");
return 1;
}
#endif
return 0;
}
第
7 行,调用
do_bootm_states
函数,执行 BOOTM_STATE_START
阶段。 这里执行部分的代码如下:
int do_bootm_states(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[],
int states, bootm_headers_t *images, int boot_progress)
{
boot_os_fn *boot_fn;
ulong iflag = 0;
int ret = 0, need_boot_fn;
images->state |= states;
/*
* Work through the states and see how far we get. We stop on
* any error.
*/
if (states & BOOTM_STATE_START)
ret = bootm_start(cmdtp, flag, argc, argv);
..........
return ret;
}
处理
BOOTM_STATE_START
阶段,
bootz_start
会执行这一段代码,这里调用函数
bootm_start
函数,此函数定义在文件
common/bootm.c
中,函数内容如下:
static int bootm_start(cmd_tbl_t *cmdtp, int flag, int argc,
char * const argv[])
{
memset((void *)&images, 0, sizeof(images));
images.verify = getenv_yesno("verify");
boot_start_lmb(&images);
bootstage_mark_name(BOOTSTAGE_ID_BOOTM_START, "bootm_start");
images.state = BOOTM_STATE_START;
return 0;
}
可以看出,bootm_start 函数对images全局变量清零,设置image的状态等。
第
12
行,设置
images
的
ep
成员变量,也就是系统镜像的入口点。
使用
bootz
命令启动
系统时,就会设置系统在
DRAM
中的存储位置,这个存储位置就是系统镜像的入口点,因
此,
images->ep=0X80800000
。
第
21
行,调用
bootz_setup
函数,此函数会判断当前的系统镜像文件是否为
Linux
的镜
像文件,并且会打印出镜像相关信息,
bootz_setup
函数稍后会讲解。
第 31
行,调用函数
bootm_find_images
查找
ramdisk
和设备树
(dtb)
文件,但是我们没有
用到
ramdisk
,因此,此函数在这里仅仅用于查找设备树
(dtb)
文件。
来看一下
bootz_setup
函数,此函数定义在文件
arch/arm/lib/bootm.c
中,函数内容如下:
#define LINUX_ARM_ZIMAGE_MAGIC 0x016f2818
int bootz_setup(ulong image, ulong *start, ulong *end)
{
struct zimage_header *zi;
zi = (struct zimage_header *)map_sysmem(image, 0);
if (zi->zi_magic != LINUX_ARM_ZIMAGE_MAGIC) {
puts("Bad Linux ARM zImage magic!\n");
return 1;
}
*start = zi->zi_start;
*end = zi->zi_end;
printf("Kernel image @ %#08lx [ %#08lx - %#08lx ]\n", image, *start,
*end);
return 0;
}
第
1
行,宏
LINUX_ARM_ZIMAGE_MAGIC
就是
ARM Linux
系统魔术数。
zimage_header 的zi_magic为 zImage 的幻数,魔术数。应该为0x016f2818。前面有9个32位的数据,那么9*4=36,0~35,第36个字节的数据开始就是zimage的幻数。可以通过查看 编译好的 zImage文件,确认第36个字节数据是否为 这个魔术值。
第 7
行,从传递进来的参数
image(
也就是系统镜像首地址
)
中获取
zimage
头。
zImage
头
结构体为
zimage_header
。
第
8~11
行,判断
image
是否为
ARM
的
Linux
系统镜像,如果不是的话就直接返回,并且打印出 “
Bad Linux ARM zImage magic!
”。
第
13-14
行初始化函数
bootz_setup
的参数
start
和
end
。
第
16
行,打印启动信息,如果
Linux
系统镜像正常的话。会打印如下Log信息:
Kernel image @ 0x80800000 [ 0x000000 - 0x552f80 ]
接下来看一下
bootm_find_images
函数,此函数定义在文件 common/bootm.c
中,函数内容如下:
int bootm_find_images(int flag, int argc, char * const argv[])
{
int ret;
/* find ramdisk */
ret = boot_get_ramdisk(argc, argv, &images, IH_INITRD_ARCH,
&images.rd_start, &images.rd_end);
if (ret) {
puts("Ramdisk image is corrupt or invalid\n");
return 1;
}
#if defined(CONFIG_OF_LIBFDT)
/* find flattened device tree */
ret = boot_get_fdt(flag, argc, argv, IH_ARCH_DEFAULT, &images,
&images.ft_addr, &images.ft_len);
if (ret) {
puts("Could not find a valid device tree\n");
return 1;
}
set_working_fdt_addr((ulong)images.ft_addr);
#endif
......
return 0;
}
第
6~11
行是跟查找
ramdisk
,但是我们没有用到
ramdisk
,因此这部分代码不用管。
第
15~20
行是查找设备树
(dtb)
文件,找到以后就将设备树的起始地址和长度分别写到
images
的
ft_addr
和
ft_len
成员变量中。
我们使用
bootz
启动
Linux
的时候已经指明了设备树在
DRAM
中的存储地址,因此
images.ft_addr=0X83000000
,长度根据具体的设备树文件而定,比
如,我现在使用的设备树文件长度为
0X8C81
,因此
images.ft_len=0X8C81
。
第 21行,设置设备树的起始地址。
bootz_start
函数就讲解到这里,
bootz_start 函数
主要用于初始化
images
的相关成员变量。