Linux系统移植:bootz 启动 Linux 内核

举报
JeckXu666 发表于 2022/02/14 22:51:51 2022/02/14
【摘要】 文章目录 Linux系统移植:bootz 启动 Linux 内核一、images 的全局变量二、do_bootz 函数三、bootz_start 函数四、do_bootm_states 函数五、b...

Linux系统移植:bootz 启动 Linux 内核

一、images 的全局变量

启动 Linux 内核的时候会用到一个重要的全局变量

bootm_headers_t images;

  
 
  • 1

bootm_headers_t 是个 boot 头结构体,在文件 include/image.h 中的定义,代码不粘贴了,具体到 uboot 源码中查看

其中 os 成员变量是 image_info_t 类型的,为系统镜像信息。

20220213151844

结构体 image_info_t 是系统镜像信息结构体,具体如下:

20220213153619

下面的 11 个宏定义表示 U-BOOT 的不同阶段

20220213152105

images 会在 bootz 命令的执行中频繁使用到,非常重要

二、do_bootz 函数

使用 bootz 命令后执行函数为 do_bootz,在文件 cmd/bootm.c 中有定义:

int do_bootz(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
{
	int ret;
	/* Consume 'bootz' */
	argc--; argv++;

	if (bootz_start(cmdtp, flag, argc, argv, &images))
		return 1;
	/*
	 * We are doing the BOOTM_STATE_LOADOS state ourselves, so must
	 * disable interrupts ourselves
	 */
	bootm_disable_interrupts();

	images.os.os = IH_OS_LINUX;
	ret = do_bootm_states(cmdtp, flag, argc, argv,
			      BOOTM_STATE_OS_PREP | BOOTM_STATE_OS_FAKE_GO |
			      BOOTM_STATE_OS_GO,
			      &images, 1);
	return ret;
}

  
 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

该函数首先传入参数调用了 bootz_start 函数,然后调用函数 bootm_disable_interrupts 关闭中断,最后设置 images.os.os 为 IH_OS_LINUX,也就是设置系统镜像为 Linux,表示要启动的是 Linux 系统

之后调用函数 do_bootm_states 来执行不同的 BOOT 阶段,这里要执行的 BOOT 阶段有:

  • BOOTM_STATE_OS_PREP
  • BOOTM_STATE_OS_FAKE_GO
  • BOOTM_STATE_OS_GO

三、bootz_start 函数

bootz_srart 函数定义在文件 cmd/bootm.c 中

20220213195210

代码主要的执行目标如下:

  • 代码先调用函数 do_bootm_states,执行 BOOTM_STATE_START 阶段

  • 设置 images 的 ep 成员变量(系统镜像的入口点)使用 bootz 命令启动系统的时候就会设置系统在 DRAM 中的存储位置,这个存储位置就是系统镜像的入口点,因此 images->ep=0X80800000

  • 调用 bootz_setup 函数,判断当前的系统镜像文件是否为 Linux 的镜像文件,打印出镜像相关信息

  • 调用函数 bootm_find_images 查找 ramdisk 和设备树(dtb)文件

四、do_bootm_states 函数

do_bootz 最后调用的就是函数 do_bootm_states,函数定义在文件common/bootm.c 中

20220213204237

函数 do_bootm_states 根据不同的 BOOT 状态执行不同的代码段,先判断 BOOT 的状态

states & BOOTM_STATE_XXX

  
 
  • 1

然后根据 BOOT 的状态执行不同的代码

五、bootm_os_get_boot_func 函数

do_bootm_states 会调用 bootm_os_get_boot_func 来查找对应系统的启动函数,函数定义在文件 common/bootm_os.c 中

20220213212556

代码中的 boot_os 是个数组,这个数组里面存放着不同的系统对应的启动函数,boot_os 也定义在文件 common/bootm_os.c 中

20220213212706

启动 linux 函数就是 do_bootm_linux

六、do_bootm_linux 函数

do_bootm_linux 就是最终启动 Linux 内核的函数,函数定义在文件 arch/arm/lib/bootm.c

20220213213513

只有在参数 flag 等于 BOOTM_STATE_OS_GO 或者 BOOTM_STATE_OS_FAKE_GO 的时候执行 boot_jump_linux 函数,boot_selected_os 函数在调用 do_bootm_linux 的时候会将 flag 设置为 BOOTM_STATE_OS_GO

然后执行函数 boot_jump_linux,函数定义在文件 arch/arm/lib/bootm.c 中

该代码就是判断芯片的 machid ,Linux 内核会在自己的机器 ID 列表里面查找是否存在与 uboot 传递进来的 machid 匹配的项目,如果存在就说明 Linux 内核支持这个机器,那么 Linux 就会启动,同时代码判断是否启动设备树,其中最核心的一个函数就是 kernel_entry 函数,此函数用于进入 Linux 内核,函数有三个参数:zero,arch,params,第一个参数 zero 为 0;第二个参数为机器 ID;第三个参数 ATAGS 或者设备树(DTB)首地址

注意 kernel_entry 并不是 uboot 定义的,而是 Linux 内核定义的,Linux 内核镜像文件的第一行代码就是函数 kernel_entry,而 images->ep 保存着 Linux内核镜像的起始地址,起始地址保存的正是 Linux 内核第一行代码

在获取 kernel_entry 并执行 kernel_entry 前,uboot 先调用 cleanup_before_linux 函数做一些清理工作,然后使用汇编传参数给 kernel_entry 进入 Linux 内核

do_bootz 函数具体流程可以简化如下

20220213220954

到此 uboot 启动 Linux 结束

文章来源: blog.csdn.net,作者:JeckXu666,版权归原作者所有,如需转载,请联系作者。

原文链接:blog.csdn.net/qq_45396672/article/details/122915919

【版权声明】本文为华为云社区用户转载文章,如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。