当前位置:网站首页>bootz 启动 kernel
bootz 启动 kernel
2022-08-06 17:30:00 【Li-Yongjun】
活动地址:CSDN21天学习挑战赛
思考
uboot 启动 kernel,这是一个众所周知的事实。但是,你有没有思考过,这两个独立的镜像实体,是如何做到 A 启动 B 的呢?如果是同一份代码中的 func_a() 调用 func_b(),还好理解,因为是在同一份程序中(或者说是同一份指令中),func_a 是知道 func_b() 的地址的,直接跳转过去就行了(设置 PC 指针指向 func_b 的地址)。
但是 uboot 和 kernel 不在同一份指令中,这是两个独立的程序,那么是怎样实现 程序 A “调用” 程序 B 的呢?
bootz
在 uboot 命令行下,可以使用 bootz 命令启动 kernel,我们就以此为切入点,探究 uboot 启动 kernel 的底层原理。
表象
使用如下命令,就能完成 uboot 启动 kernel。
tftp 80800000 zImage
tftp 83000000 imx6ull-14x14-evk.dtb
bootz 80800000 - 83000000
这里简单介绍下命令作用。
前两条是通过 tftp 命令,分别将 kernel 镜像 zImage 和设备树二进制文件下载到内存的 0x80800000 和 0x83000000 位置。
第三条是使用 bootz 命令启动 kernel。
bootz
接下来,就分析下 bootz 启动 kernel 的原理。
通过 uboot 命令行,向 bootz 传递了三个参数 “80800000”、“-”、“83000000”,它们分别是 “kernel 镜像在内存中的首地址”、“无效参数”、“设备树文件首地址”,
bootz 命令对应的执行函数为 do_bootz(),在该函数中,首先设置 kernel 首地址和设备树首地址(其实这就是 uboot 能够启动 kernel 的原因:有了地址就能跳转过去运行)。
images->ep = simple_strtoul(argv[0], NULL, 16);
变量 ep 用来存储 kernel 镜像在内存中的首地址,该参数由 argv[0] 赋值,argv[0] 就是刚刚在命令行传递给 bootz 的第一个参数 80800000,
images.ft_addr = argv[2];
变量 ft_addr 用来存储设备树在内存中的首地址,该参数由 argv[2] 赋值,为 83000000。
kernel_entry()
do_bootz() 最终会调用 kernel_entry(),kernel_entry 并不是在 uboot 中定义的函数,它是一个地址转换来的,如下:
kernel_entry = (void (*)(void *fdt_addr, void *res0, void *res1,
void *res2))images->ep;
而 image->ep 就是 kernel 在内存中的首地址,这不就联系上了嘛。
uboot 将设备树传递给 kernel
刚才分析出 images.ft_addr 存放设备树在内存中的首地址,那又是如何将这个地址传递给 kernel 呢?这里不像函数传参,当成实参就传递过去了。
一来 uboot 和 kernel 不是同一份程序,不共用同一个堆栈;二来 kernel 一开始的代码是汇编代码,C 函数也没办法直接将自己的实参传递给汇编函数。
那要怎么才能实现 uboot 中的一个变量传递给 kernel 呢?答案是使用寄存器。
uboot 生命周期的最后一个函数调用如下
r2 = (unsigned long)images->ft_addr;
kernel_entry(0, machid, r2);
使用 r2 寄存器存储设备树文件的首地址。
kernel 接收设备树
再来看 kernel 是怎么接收这个地址的呢?
kernel 的入口函数是 head.S 中的 stext
ENTRY(stext)
...
ldr r13, =__mmap_switched @ address to jump to after
__mmap_switched:
...
str r2, [r6] @ Save atags pointer
cmp r7, #0
strne r0, [r7] @ Save control register values
b start_kernel
ENDPROC(__mmap_switched)
__mmap_switched_data:
.long __data_loc @ r4
.long _sdata @ r5
.long __bss_start @ r6
.long _end @ r7
.long processor_id @ r4
.long __machine_arch_type @ r5
.long __atags_pointer @ r6
...
总体流程是:
stext 调用 __mmap_switched,在 __mmap_switched 中将 r2 的值赋给全局变量 __atags_pointer,然后调用 start_kernel()。
start_kernel() 调用 setup_arch(),在该函数中解析设备树,如下:
mdesc = setup_machine_fdt(__atags_pointer);
总结
uboot 启动 kernel:
uboot 拿到 kernel 在内存中的首地址,就能跳转到该地址运行。
uboot 将设备树传递给 kernel:
通过 r2 寄存器。
边栏推荐
- Will win7 upgrade win10 data loss?
- 华泰证券开户怎么样?安不安全
- Windows 7 input method is missing how to adjust out Windows 7 input method icon is missing
- #yyds dry goods inventory # WWW service
- Talking about the Jmeter performance test process
- How to format computer to restore factory settings in win7
- win7资源管理器反复停止工作 win7资源管理器已停止工作不断重复
- php ini设置session过期时间
- Linux 安装配置 mysql
- 2022.8.5-----leetcode.623
猜你喜欢
随机推荐
下一个十年,什么样的测试最吃香?
使用接口地址池为直连网段分配地址
From VLAN to IPVLAN: Talking about virtual network devices and their cloud-native applications
#yyds dry goods inventory # WWW service
selenium中的Chrome.Option类
FP6601AP5 CPC-16L Type-A HVDCP控制器与插入/输出自动检测
win7资源管理器反复停止工作 win7资源管理器已停止工作不断重复
win7打印机共享设置(详细图文步骤)
bonjour是什么软件 bonjour可以卸载吗
QWT下载、安装、配置教程
百度搜索排名:三板斧,有哪些?
word2vec原理
怎么解除谷歌浏览器的防火墙 如何关闭防火墙对chrome浏览器的拦截
笔记本win11怎么退回win10(适用联想、华为、小米、戴尔)
win7升级win10数据会丢失吗 win7升级win10怎么备份数据
12 异常处理器
02 【常用类型(上)】
win7缺失dll文件一键修复 msvcr120.dll丢失怎样修复win7
Fast charging charger Multi-port fast charging protocol chip
Principle of USB Communication









