3

uboot, Linux镜像文件, 嵌入式Linux

 2 years ago
source link: http://antkillerfarm.github.io/linux/2022/01/01/boot.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

uboot

从uboot到Linux

这里以uboot 2014年11月的主线代码为例分析从uboot到linux的全过程。之所以写这篇文章,是由于网上的资料多数都很陈旧,诸如start_armboot之类的函数在新的代码里根本找不到了。由于uboot支持的CPU以及Board非常的多,所以本文仅以Samsung exynos为例来介绍这个过程。

从上电到uboot启动:

1./arch/arm/cpu/armv7/start.S: reset——uboot的汇编入口

2./arch/arm/lib/crt0.S: _main

3./arch/arm/lib/board.c: board_init_f——初始化第一阶段

4./arch/arm/lib/board.c: board_init_r——初始化第二阶段

5./common/main.c: main_loop——uboot主循环

uboot启动Linux

1.uboot中有个bootd的命令选项,执行该命令会进入/common/cmd_bootm.c: do_bootd

2.common/cli.c: run_command,传入bootcmd命令作为参数。

3.common/cmd_bootm.c: do_bootm

4.arch/arm/lib/bootm.c: do_bootm_linux

5.arch/arm/lib/bootm.c: do_jump_linux——跳转到Linux内核的入口地址

uImage格式是专为uboot开发的格式,主要解决了uboot和linux在嵌入式设备的存储上共存的问题。

uboot命令处理流程

从main_loop到命令处理:

1./common/main.c: main_loop

2./common/cli.c: cli_loop

3./common/cli_simple.c: cli_simple_loop

4./common/cli.c: run_command_repeatable

5./common/cli_simple.c: cli_simple_run_command

6./common/cli_simple.c: cmd_process

7./common/command.c: cmd_call

上面的流程仅是主循环如何调用命令回调函数的过程。下面介绍一下命令是如何声明、存储和查询的。

首先查看链接脚本,uboot使用的链接脚本文件名为u-boot.lds。根据cpu和board的不同,u-boot.lds也有所差异。例如Samsung exynos所用的u-boot.lds在arch\arm\cpu下。

其中有个.u_boot_list段就是用来存储命令数据的。它的表述如下所示:

.u_boot_list : {
		KEEP(*(SORT(.u_boot_list*)));
	}

命令的声明,通常使用U_BOOT_CMD宏。这个宏最终展开为:

_type _u_boot_list_2_##_list##_2_##_name __aligned(4)		\
		__attribute__((unused,				\
		section(".u_boot_list_2_"#_list"_2_"#_name)))

这也就是.u_boot_list*的来历了。

可以使用/common/command.c: find_cmd函数在命令列表中,根据名称查找命令数据。

/common/cmd_nvedit.c: setenv–这个函数用于设置环境变量的值。它的原理是:

1.首先在环境变量数组default_environment中,更改相应内容的值。

2.然后调用saveenv,保存default_environment的值,到具体的硬件中。例如NAND设备的代码在/common/env_nand.c中。

在linux内核层面也可以修改uboot的环境变量。通常的做法步骤如下:

1.uboot代码中有个tools/env文件夹。编译改代码可以得到fw_printenv文件。编译的命令是:

make env

2.将fw_printenv放到linux系统的/usr/sbin路径下,并创建符号链接fw_setenv。此处的符号链接并不是可有可无的,这里有个编程小技巧:如何用同一个可执行文件执行不同的功能呢?

除了最常用的使用参数区分的方法之外,还可以采用如下方法:

int main(int argc, char *argv[])

这是main函数的声明,其中argv是参数数组,而argv[0]是输入的命令本身,因此可以使用这个作为判断依据,来区分不同的用途。这时候符号链接也就派上用场了。

tftpsrv

有些uboot提供了tftpsrv的功能,用于从网口传输文件(主要是烧写用的镜像文件)。

该tftpsrv默认监听的ip地址保存在uboot的ip环境变量中。如果需要的话,可进行必要的修改并重启。

客户端传输镜像文件时,需要采用二进制模式。命令如下:

tftp 10.3.9.161 -m binary -c put <file name>

Linux镜像文件

vmlinux

这是源代码直接生成的镜像文件。以x86平台为例:

arch\x86\kernel\vmlinux.lds.S–这是链接脚本的源代码,经过C语言的宏预处理之后会生成vmlinux.lds,使用这个脚本,链接即可得到vmlinux,其过程与普通应用程序并无太大区别,也就是个elf文件罢了。

image

vmlinux使用objcopy处理之后,生成的不包含符号表的镜像文件。这是linux默认生成的结果。

zImage

zImage = 使用gzip压缩后的image + GZip自解压代码。使用make zImage或者make bzImage创建。两者的区别是zImage只适用于大小在640KB以内的内核镜像。

uImage

uImage = uImage header + zImage。使用uboot提供的mkimage工具创建。

以上的这些镜像文件的关系可参见:

http://www.cnblogs.com/armlinux/archive/2011/11/06/2396786.html

http://www.linuxidc.com/Linux/2011-02/32096.htm

Flash镜像

一般来说,一个完整的linux系统,不仅包括内核,还包括bootloader和若干分区。这些镜像文件散布,不利于批量生产的进行。这时就需要将之打包,并生成一个可直接用于生产烧写的Flash镜像。

可使用mtd-utils库中的ubinize工具生成Flash镜像。

mtd-utils的官网是:

http://www.linux-mtd.infradead.org/

安装方法:

sudo apt install mtd-utils

mtd-utils还可用于烧写分区。例如如下命令:

mtd write xyz.uimage linux

其中xyz.uimage是镜像文件名,linux是分区名称。

http://blog.csdn.net/andy205214/article/details/7390287

利用mkfs.ubifs和ubinize两个工具制作UBI镜像

从代码来查看板子的MTD分区方案,主要是搜索mtd_partition类型的使用定义。比如mini2440板子的分区方案可在mini2440_default_nand_part数组中查到。

MTD(memory technology device):内存技术设备,是linux用于描述ROM,NAND,NOR等内存设备的子系统的抽象。

除了MTD之外,常用的还有SPI Flash方案。

嵌入式Linux

Linaro

Linaro虽然名义上是一家非营利性质的开放源代码软件工程公司。然而,它所提供的ARM工具链,基本上已经是ARM御用级别的了。

https://www.linaro.org/

Yocto

Yocto是一个开源协作项目,它提供了一些模板、工具和方法来支持面向嵌入式产品的自定义Linux系统。

https://www.yoctoproject.org/

它也提供了一套工具链,依附于旗下的子项目:Poky Linux。似乎NXP用的较多。

https://www.ibm.com/developerworks/cn/linux/l-yocto-linux/index.html

使用Yocto Project构建自定义嵌入式Linux发行版

32/64位编译

大致的原则是:

1.使用对应的bit的工具链。

2.链接的库也需要是对应bit的。

32bit float:

-march=armv7-a -mfloat-abi=hard -mfpu=neon

Linux参考资源+

https://mp.weixin.qq.com/s/-U7L8aXoaPXSwZshSpjQ2g

进程间通信

https://mp.weixin.qq.com/s/oKtu3AA9D3y–xMDQ8EARw

携程一次Dubbo连接超时问题的排查

https://mp.weixin.qq.com/s/4o_cSzWeJdLJMObJBhaZlw

计算机系统中的内存

https://www.jianshu.com/p/fad3339e3448

浅析Linux中的零拷贝技术

https://mp.weixin.qq.com/s/Q9BOA88Q6OBaDch1AiS9QA

原来8张图,就可以搞懂零拷贝了

https://mp.weixin.qq.com/s/6R8UcLLjm9gdWud-eNHztw

中断及其初始化

https://mp.weixin.qq.com/s/qwouMWc4CFtqG_jra4xbIg

IDT及中断处理的实现

https://mp.weixin.qq.com/s/pRsXWAv7wgYcN_jlzcA2YA

内存都没了,还能运行程序?

https://mp.weixin.qq.com/s/snQ3T86usv4rXz0MMQvFfQ

如何回答性能优化的问题,才能打动阿里面试官?

https://www.cnblogs.com/zhouyu629/p/3734494.html

一次心惊肉跳的服务器误删文件的恢复过程

https://mp.weixin.qq.com/s/IcEP-JGQbWA7s7yPdIC9vA

80%时间屏蔽了中断,实时性还有救么?

https://mp.weixin.qq.com/s/iKfWSfzauzNjcAvXPNhq0Q

这些算法都不会还学什么操作系统

https://mp.weixin.qq.com/s/gj6Zw8SvOdSZqRx8KP9wWw

20张图揭开内存管理的迷雾,瞬间豁然开朗

https://mp.weixin.qq.com/s/IQYUNzVgSOFUHB9c1SM0Bw

10张图22段代码,万字长文带你搞懂虚拟内存模型和malloc内部原理

https://zhuanlan.zhihu.com/p/370092684

虚拟内存精粹

http://www.ruanyifeng.com/blog/2016/03/systemd-tutorial-commands.html

Systemd入门教程:命令篇

https://mp.weixin.qq.com/s/xOqXM5kFi0CzilDg0EXFKg

Linux内核源码规范解析

https://mp.weixin.qq.com/s/QB-IHiCIWEu3bALm2Dp46Q

操作系统课程知识结构

https://www.zhihu.com/answer/460715569

生产力应用大汇总

https://mp.weixin.qq.com/s/QsgoONKwI7ds8Hnx2Wer6A

Linux从程序到进程

https://mp.weixin.qq.com/s/v9XlJjIQkuVpSudhQIS70A

神秘!申请内存时底层发生了什么?

https://mp.weixin.qq.com/s/V-XT6QuDG522P0bP2e3ULg

咋办,死锁了

https://mp.weixin.qq.com/s/RHAoM8zhFvQl9R8V0ePxNQ

看腾讯这道多线程面试题

https://mp.weixin.qq.com/s/QshDG-nbmBcF1OBZbBFwjg

操作系统与存储:解析Linux内核全新异步IO引擎io_uring设计与实现

https://mp.weixin.qq.com/s/qWXcL90ZAkc7rrhsbuB_Bw

只有170字节,最小的64位Hello World程序这样写成

https://mp.weixin.qq.com/s/5iyWeSeDzuA2cY7YBMhk7w

MMU那些事儿

https://mp.weixin.qq.com/s/0OeeYUgBBVVMtxscvzgJHw

i++是线程安全的吗?

https://mp.weixin.qq.com/s/U0qr1oZYXBBmZnC5vsKYLQ

浅谈linux IO

https://mp.weixin.qq.com/s/3kgwoyYI90XHm1QPqFJAiQ

内存分页不就够了?为什么还要分段?

https://mp.weixin.qq.com/s/VSbzTh3xEbVdB4IgGJzQ3A

25张图,一万字,拆解Linux网络包发送过程

https://mp.weixin.qq.com/s/2dbr4-dxRCJ_SLCQnrt8ag

Linux内核调度器源码分析

https://yanqiyu.info/2021/06/21/huawei-v-qwr/

某不知名网友怒斥华为,究竟发生了什么

https://mp.weixin.qq.com/s/-8L5MFZrgmyatGgYaR1AEA

波兰极客用一张软盘运行Linux系统,用的还是最新内核!

https://mp.weixin.qq.com/s/-hfI4GLkChRJQDqcLcvbGg

嵌入式C编程实现上下文的快速切换(cpost)

https://zhuanlan.zhihu.com/p/400200921

x86 Linux下实现10us误差的高精度延时

https://www.zhihu.com/question/496656138

为什么Windows文件设计成占用无法删除?

https://mp.weixin.qq.com/s/h4LwSRAsDgRqOq3mLt_SCw

浅谈mmap

https://mp.weixin.qq.com/s/djEPqxZSfMp13Uf_h6TSiA

认真分析mmap:是什么 为什么 怎么用

https://mp.weixin.qq.com/s/FMYimnxcAya6bhvdGD5LUw

惊魂48小时,阿里工程师如何紧急定位线上内存泄露?

https://zhuanlan.zhihu.com/p/424240082

编译一个属于自己的最小Linux系统

https://www.zhihu.com/question/66902460

为什么Linux下要把创建进程分为fork()和exec()(一系列函数)两个函数来处理?

https://zhuanlan.zhihu.com/p/464204319

Linux网络子系统中DMA机制的实现


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK