【OK210试用体验】bootloader启动linux内核 - 在线问答 - 电子技术论坛 - 最好最受欢迎电子论坛!

【OK210试用体验】bootloader启动linux内核

刘天 ( 楼主 ) 2016-1-10 15:57:45  只看该作者 倒序浏览
bootloader启动linux内核
象棋小子    1048272975
不同的CPU具有不同的启动方式,其系统外设等均具有较大的差异。CPU上电启动后,并不具有相应的内核启动环境,需要bootloader先初始化CPU及相应系统外设,加载内核,使之具备内核启动的必要条件。bootloader一般应有下载固化以及加载启动这两个功能,笔者此处就s3c2416基于yaffs文件系统的linux下载固化以及加载启动作一个简单的介绍。
1. 基于linuxbootloader
bootloader的实现流程前面章节有详细的介绍,此处不再细述。bootloader为了能启动linux,往往需要跟内核彼此协调约定,才能联合工作。linux系统为了精简以及便于维护,分成了内核空间以及用户空间。Linux内核由内存管理、进程管理、设备驱动程序、网络管理等组成,它是操作系统的核心,具有很多最基本的功能,决定了系统的性能和稳定性。用户空间的文件系统用来提供管理系统的各种配置,提供相应的应用程序、服务、数据交换等。文件系统作为一种载体,它是用来实现用户与操作系统内核的交互。因此,一个可启动的linux系统必须包含linux内核以及一个根文件系统。
bootloader应该具有把自身、linux内核、根文件系统下载固化进相应的非易失存性储器中,以便目标机能脱离宿主机,单独加载启动运行。bootloader可以通过多种通讯方式,如u***、网络、sd卡、u盘等,把宿主机上开发好的内核、根文件系统等下载进目标机的内存,再固化进相应的存储器中。目标机单独运行时,bootloader首先自启动,然后从固化存储器中加载linux内核到内存,如果根文件系统在ram disk里,bootloader还需加载根文件系统到内存,否则,根文件系统由linux内核根据约定进行挂载。最后,bootloader跳转到内核,把CPU控制器全权交付内核处理。
2. 下载固化
此处假设已经做好了bootloader、linux内核、基于yaffs的根文件系统,把宿主机里的这些镜像文件拷贝到sd卡,bootloader从sd卡读取这些镜像文件到内存,然后再烧录固化进nand flash里,实现从sd卡自更新nand flash里面的bootloader、内核、文件系统。bootloader采用fatfs来支持sd卡的fat32文件系统的访问。
2.1. bootloader固化
bootloader从/image/bootloader.bin读取文件到内存,然后调用nand写函数把代码下载固化进nand flash。对于s3c2416,此时的bootloader在nand flash最开始的位置,如果是nand boot,启动后CPU不通过任何校验直接把nand flash最前面的8k加载进内部ram(stepping stone),如果是irom nand启动,则CPU需要通过ecc校验成功后才会把nand flash里面的8k代码加载进stepping stone。此处bootloader采用ecc检验烧写方式用于同时支持nand boot以及irom nand启动,同时,bootloader从nand flash加载自身时需采用一致的读取方式。
2.2. linux内核固化
bootloader从/image/kernel.bin读取文件到内存,linux内核由bootloader安装以及加载,因此linux内核的储存位置本身与内核无关,由bootloader决定。bootloader可以决定把内核储存进如spi flash、sd卡等存储器,如果储存进nand flash,只需注意linux内核储存位置不与bootloader、根文件系统位置冲突即可。bootloader加载内核时需从安装内核的位置读取即可。
2.3. 根文件系统固化
bootloader从/image/rootfs.bin读取文件到内存,如果根文件系统为initrd,则根文件系统储存位置也与内核无关,由bootloader决定存储及加载。如果根文件系统为initramfs,并且跟linux内核链接在一起,那么bootloader无需再处理根文件系统了,因为linux内核包含了根文件系统,固化加载内核也同时处理了根文件系统。
如果根文件系统在nand flash、sd/mmc卡等存储设备中,首先linux内核必须支持相应的设备驱动以及文件系统。此处以nandflash为例说明,bootloader应该与linux内核协调约定nand flash的分区位置,因为此时根文件系统由linux内核挂载,与bootloader无关。bootloader把根文件系统下载固化进相应的分区位置,然后在启动内核时告之内核所在的分区。除此之外,nand flash还有oob区,对于yaffs文件系统,oob区用来存储yaffs的tag数据,坏块标记,ecc校验数据,这需要宿主机制作yaffs镜像工具mkyaffs2image、bootloader、linux内核协调约定,确保bootloader与linux内核有一致的nand layout,即bootloader的坏块标记位置、yaffs的tag数据位置应该与linux内核完全一致,如果linux内核采用了相应的nand ecc,那么bootloader在下载固化根文件系统时也应采用相同的nandecc方式进行填充oob区。任何一点bootloader与linux内核的不一致,将造成linux内核无法挂载根文件系统,引起内核panic。

                              
2-1 linux内核源码中的nand分区信息


2-2 linux内核启动时的nand分区打印信息3. 加载启动3.1. bootloader硬件初始化
上电启动后,bootloader首先初始化必要的硬件,如内存控制器,整个系统时钟等,包括linux内核默认不初始化直接使用的部分,如外部总线时序、u***时钟等。
3.2. bootloader加载内核
bootloader从内核安装位置加载内核到内存,这个内存位置并没有需要特别注意的地方,一般默认是内存基址+0x8000处,linux内核会自行重定位到执行地址执行。如果采用initrd根文件系统,也由bootloader加载根文件系统到内存。
3.3. linux启动参数
bootloader可以给linux内核传递启动参数以控制其行为。linux内核启动参数位置并没有需要特别注意的地方,一般默认是内存基址+0x100处,bootloader通过标记列表的形式来传递启动参数。
标记列表以标记ATAG_CORE开始
params->hdr.tag =ATAG_CORE;
params->hdr.size =tag_size (tag_core);
params->u.core.flags =0;
params->u.core.pagesize= 0;
params->u.core.rootdev= 0;
params = tag_next(params);
设置内存标记ATAG_MEM,标记内存的位置及大小
params->hdr.tag =ATAG_MEM;
params->hdr.size =tag_size (tag_mem32);
params->u.mem.start =DRAM_BASE;
params->u.mem.size =DRAM_SIZE; // 64M
params = tag_next(params);
设置命令行标记ATAG_CMDLINE,这是一个字符串,用来控制内核的行为。如"noinitrd root=/dev/mtdblock3 rootfstype=yaffs2init=/linuxrc console=ttySAC0",表示根文件系统在MTD3分区上,文件系统为yaffs2,系统启动后执行的第一个程序为linuxrc,控制台为ttySAC0。
params->hdr.tag =ATAG_CMDLINE;            
params->hdr.size =(sizeof(struct tag_header)+strlen(NandBootCmd)+1+4) >> 2;
strcpy(params->u.cmdline.cmdline,NandBootCmd);
params = tag_next(params);
标记列表以标记ATAG_NONE结束
params->hdr.tag =ATAG_NONE;
params->hdr.size = 0;
3.4. 内核启动环境
在交出CPU控制权之前,bootloader需要把CPU恢复成初始的环境,CPU必须禁止IRQ以及FIQ中断,处于特权模式,关闭MMU,使无效并且写回DCache数据到主存,禁止DCache,推荐ICache打开。
IRQ_Disable();
CP15_DisableDCache();
CP15_DisableICache();
CP15_CleanDCache();
CP15_DrainWriteBuffer();
CP15_InvalidateDCache();
CP15_InvalidateICache();
CP15_DisableMMU();
CP15_InvalidateTLB();
CP15_EnableICache();
3.5. 跳转到内核
bootloader跳转到内核时,将传递三个参数给内核,对于ARM为R0、R1、R2这三个寄存器。第一个参数R0必须为0,第二个参数R1为机器码,必须与linux内核一致才能启动,第三个参数为先前设置的内核启动参数地址位置。跳转到内核后,bootloader完全退出,由linux内核全权处理。
Kernel(0, MACH_TYPE,(uint32_t)params);

图3-1 linux内核启动
4. 附录
附录为arm交叉编译工具链下基于newlib的s3c2416 linux启动 bootloader工程,附带了newlib库,sd卡windows下烧录工具,工程直接make即可。
mdk下s3c2416 linux启动bootloader工程。

3个回复

HelloWii 发表于 2016-1-11 11:45:12
学习一下,,,,
回复

举报 使用道具

刘德义 发表于 2016-5-2 09:32:51
楼主很强,学习啦。赞…
回复

举报 使用道具

成都魏星 发表于 2016-5-30 11:38:42
现在很多内核分区信息是写到参数表里的,u-boot和kernel启动去读这个参数信息,而不需要每次调整都去重新编译u-boot和kernel。现在主流的rootfs都是使用压缩比例比较高的sques.fs,为什么飞凌的资料没有提供呢?
您需要登录后才可以回帖 登录 | 注册

本版积分规则


关闭

站长推荐上一条 /6 下一条

小黑屋|手机版|Archiver|电子发烧友 ( 湘ICP备2023018690号 )

GMT+8, 2024-11-25 00:13 , Processed in 0.603749 second(s), Total 67, Slave 47 queries .

Powered by 电子发烧友网

© 2015 bbs.elecfans.com

微信扫描
快速回复 返回顶部 返回列表