cortex-a8 uboot系列:第十一章 uboot源码分析 uboot如何启动内核1

发布者:JoyfulSpirit5最新更新时间:2021-02-23 来源: eefocus关键字:cortex-a8  启动内核 手机看文章 扫描二维码
随时随地手机看文章

一、Uboot和内核到底是什么(从系统启动角度看)

1.Uboot

Uboot的本质是一个复杂的裸机程序。


2.内核

操作系统内核本身也是一个裸机程序,和uboot、其他裸机程序并没有什么本质区别。

但是和其他裸机程序的区别:操作系统运行起来后在软件上分为内核层和应用层,分层后两层的权限不同,内核访问和设备操作的管理上更加精细(内核可以随意访问各种硬件,而应用程序只能被限制的访问硬件和内存地址)。


Uboot的镜像是u-boot.bin,linux系统镜像是zImage,这两个文件都是两个裸机程序bin文件镜像。


二、SD卡中的分区

一个完整的软件+硬件的嵌入式系统,未上电时,bootloader、kernel、rootfs等必须的软件都以镜像的形式(.bin的形式),存储在启动介质中(x210是iNand/SD卡)。运行时,都是在DDR内存中运行,与存储介质无关。这两个状态都是稳定状态。


还有一个状态是动态过程,从静止态到运行态的过程,也就是启动过程。


动态启动过程就是从启动介质(以下以SD卡为例)逐步搬移到DDR内存,并且运行启动代码进行相关的硬件初始化和软件结构的建立,最终达到运行时稳定状态。


静止时u-boot.bin,zImage,rootfs都在SD卡中,他们不能随意存放在SD卡的任意位置,因此需要对SD卡进行一个分区,然后将各种镜像各自存在各自的分区中,这样在启动过程中就知道去什么位置查找uboot、内核等。(uboot和kernel中的分区表必须一致,同时和SD卡的实际使用的分区要一致)。


三、运行时必须要先加载到DDR中链接地址处

Uboot在第一阶段中进行重定位时将第二阶段(整个uboot镜像)加载到DDR的0xc3e00000地址处,这个地址就是uboot的链接地址。


内核也有类似要求,uboot启动内核时要将内存从SD卡读取放到DDR中(其实就是重定位的过程),不能随意放置,必须放在内核的链接地址处,否则不能启动内核。如使用的内核链接地址是0x30008000,那么uboot拷贝kernel代码时,就要将kernel拷贝到地址0x30008000的DDR中去。


四、内核启动需要必要的启动参数

Uboot是无条件启动的,从零开始启动。


内核是不能开机自动完全从零开始启动的,内核启动要别人帮忙。Uboot要帮助内核实现重定位(从SD卡到DDR),以及给内核提供必要的启动参数。如dram的起始地址以及大小,所用串口以及波特率,根文件系统位置等等。


uboot启动kernel时,会调用kernel的入口函数,此时要给kernel传递三个参数。这三个参数是固定的:

r0: 固定为0

r1: 机器码

r2: 启动参数在ddr中的位置


五、启动内核

uboot要启动内核,分为两个步骤:第一步是将内核镜像从启动介质中加载到DDR中,第二步是去DDR中启动内核镜像。(内核代码没有考虑重定位,因为内核知道会有一个bootloader将内核代码加载到DDR链接地址处,所以内核直接从链接地址处运行)


1.加载内核到DDR

静态内核镜像放在哪里?

有两种情况:

第一种:SD卡/iNand/Nand/Norflash等:raw分区

常规启动时各种镜像都在SD卡中,因此uboot只需要从SD卡的kernel分区读取内核镜像到DDR即可。


读取要使用uboot的命令来读取(x210的iNand版本是movi命令,x210的Nand版本就是Nand命令)

clip_image002

如读取kernel到内存0x30008000。

movi read kernel 0x30008000

这里的kernel指的是uboot中的kernel分区(就是uboot中规定的SD卡中的一个区域范围,这个区域范围被设计来存放kernel镜像,就是所谓的kernel分区)

 

第二种:tftp、nfs等网络下载方式从远端服务器获取镜像

uboot还支持远程启动,也就是内核镜像不烧录到开发板的SD卡中,而是放在主机的服务器中,然后需要启动时uboot通过网络从服务器中下载镜像到开发板的DDR中。


首先在主机上搭建tftp服务器,然后将要下载的文件拷贝到tftp设置的传输目录中。

clip_image004

开发板的uboot中,使用tftp命令将远程的文件通过网络下载下来。

clip_image005

tftp命令格式

tftp     DDR地址  远程下载的文件名

 

不管哪种方式,最终结果要的是内核镜像到DDR中特定地址即可,不管内核镜像是怎么到DDR中的。以上2种方式各有优劣。产品出厂时会设置为从SD卡中启动;tftp下载远程启动这种方式一般用来开发。

 

镜像要放在DDR的什么地址

内核一定要放在链接地址处。链接地址要去内核源代码的链接脚本或者makefile中去查找。X210中是0x30008000。


2.执行内核

uboot将kernel拷贝到DDR中kernel的链接地址处后,直接调用kernel的入口函数,即可启动内核。


uboot使用命令bootm来启动内核。


六、zImage和uImage的区别联系

1.bootm命令对应do_bootm函数(common/cmd_bootm.c)

clip_image007

CONFIG_SECURE_BOOT宏表示安全启动,对程序做了更安全的校验,对于一般应用,这个是不需要的。


CONFIG_ZIMAGE_BOOT宏很重要,这个宏控制条件编译支持zImage格式的内核启动的一段代码。


2.vmlinuz和zImage和uImage

uboot经过编译直接生成的elf格式的可执行程序是u-boot,这个程序是可执行,类似于windows下的exe格式,在linux下可直接执行。但是这种格式不能用来烧录下载。用来烧录下载的是u-boot.bin。这个是由u-boot使用arm-linux-objcopy工具来进行转化(主要是去掉无用的信息)。这个u-boot.bin就叫镜像(image),镜像就是用来烧录到启动介质中让CPU去取指执行的。


Linux内核经过编译后也会生成一个elf格式的可执行程序,叫vmlinux或vmlinuz,这个是原始的未经任何处理加工的原版内核elf文件。嵌入式系统部署时烧录的一般不是这个vmlinux/vmlinuz,而是要用objcopy工具去制作成烧录镜像格式(就是u-boot.bin这种,但是内核没有.bin后缀),制作出来的镜像文件就叫Image(这个镜像就比elf格式的文件要小很多)。


原则上Image就可以直接烧录到启动介质中,但是实际上linux的开发者认为Image的大小还是太大,所以对Image进行了压缩,并且在Image压缩后的文件的前端附加了一部分解压缩代码。构成了压缩格式的镜像就叫zImage。

clip_image009

Uboot为了启动linux内核,还发明了一种内核格式叫uImage,uImage是由zImag加工得到的,uboot中有一个工具,可以将zImage转换成uImage。注意:uImage不关linux内核的事,linux内核只管生成zImage即可,然后uboot中的mkimage工具再去由zImage转换成uImage来给uboot启动。这个转换过程其实就是在zImage的前面加上64字节的uImage的头信息即可。


原则上uboot启动时应该给他uImage格式的内核镜像,但是实际上uboot中也可以支持zImage启动,是否支持就看x210_sd.h中是否定义了CONFIG_ZIMAGE_BOOT这个宏。


这也就是,有些uboot支持zImage启动,有些则不支持。但是所有的uboot肯定都支持uImage启动。


对于mkimage工具,在uboot下的tools目录下,由clip_image011

上面这一段代码就是提供uboot的zImage启动。当判断镜像是zImage,对其进行校验,校验完后,直接跳转到after_header_check符号处,后面的其他镜像就不校验了。


LINUX_ZIMAGE_MAGIC是一个定义的魔数,这个数等于0x016f2818,表示这个镜像是一个zImage。也就是zImage格式的镜像中在头部的一个固定位置存放了这个数作为格式标记,如果有一个image,去这个位置读取4个字节的数据,判断是否为0x016f2818,是的话,说明是zImage,否则不是。


命令bootm 地址(0x30008000),所以do_bootm的argc=2,argv[0]=bootm,argv[1]=0x30008000。但是有argc小于2的情况,这个时候启动地址就是默认的地址,追寻,这个地址就是内存的基地址0x30000000。所以对于bootm命令,可以不带参数执行。不带参数,就默认为启动地址为0x30000000。


从镜像的37字节开始的4个字节数据读取出来,判断是否为0x016f2818,从而可以判断出这个镜像是不是zImage。

 

clip_image013

clip_image015

clip_image017

编译kernel时,


直接make, 生成zImage


make uImage, 生成uImage, 但是会用到mkimage工具,而这个工具在linux源码中是没有的,因此会直接报错。

clip_image019

需要将uboot的tools目录中的mkimage拷贝至$PATH的目录下,就可以了。

clip_image021

此时在make uImage,就会在arch/arm/boot目录下生成uImage文件了。

clip_image023

将该文件通过tftp下载带开发板的DDR,然后使用bootm命令运行。

clip_image025

黄色部分就是uboot解析uImage打印的信息。

关键字:cortex-a8  启动内核 引用地址:cortex-a8 uboot系列:第十一章 uboot源码分析 uboot如何启动内核1

上一篇:cortex-a8 uboot系列:第十二章 uboot源码分析 uboot如何启动内核2
下一篇:cortex-a8 uboot系列:第十章 uboot启动总结

推荐阅读最新更新时间:2024-11-12 13:09

快速入门了解ARM Cortex-A8内核和应用
随着手机和平板等移动市场的持续火爆,ARM低功耗高效率内核技术越来越受重视,国内各大企业相继卷入移动平台,华为、联想、小米、魅族、阿里巴巴等,都已经和ARM有了深度的合作。 图1 据ARM中国代理商米尔科技统计,2009年,ARM在纳斯达克股票均价6.04美元,2013年,ARM纳斯达克股票均价已经升到了44.54美元,四年之间涨了将近八倍。 而作为ARM的一个关键转型产品,Cortex-A8备受瞩目,因其可在Android、Linux和WinCE系统之间切换,所以在手机、平板、工控三大领域得到了大量的应用。 接下来就Cortex-A8的发展过程做一个简要叙述,看看这个关键的过渡技术有怎
[嵌入式]
快速入门了解ARM <font color='red'>Cortex-A8</font><font color='red'>内核</font>和应用
1_5.3.3_内核配置裁剪及启动流程_内核启动流程分析之Makefile_P
分析Makefile,主要是: 找到第1个文件,从这个文件入手分析启动流程; 链接脚本,分析文件分布情况。 涉及的文件分类如下: kbuild Makefile 首先来看子目录下面的Makefile,也就是kbuild Makefile,每个子目录下面都会有一个Makefile,它们的主要功能是设置该目录的文件的编译选项。 选取一个子目录下的Makefile来研究一下。 其中大部分的内容是设置文件的编译选项。 假设有两个文件a.c和b.c,如果需要单独的将它们编译进内核,可以使用如下语句: obj-y += a.o b.o 那么,如果要将这两个文件编成一个模块呢? 在内核的Document/kbui
[单片机]
1_5.3.3_<font color='red'>内核</font>配置裁剪及<font color='red'>启动</font>流程_<font color='red'>内核</font><font color='red'>启动</font>流程分析之Makefile_P
cortex-a8 uboot系列:第十二章 uboot源码分析 uboot如何启动内核2
一、zImage启动细节 do_bootm函数在after_header_check符号前,都是在进行镜像的头部信息校验。校验时就要根据不同的种类的image类型进行不同的校验。而不同的镜像的开头都是有自己的头信息。 所以do_bootm函数的核心就是去分辨传进来的image到底是什么类型,然后按照这种类型的头信息格式去校验。校验通过则进入下一步,准备启动内核,如果检验失败,则认为镜像有问题,不启动内核。 上一节分析过zImage启动,当判断不是从zImage启动时,会检查其他类镜像。如uImage镜像。 Uboot支持多种镜像启动,uboot中定义3种镜像方式。但是只有两种是有效的。 IMAGE_FORMAT_
[单片机]
<font color='red'>cortex-a8</font> <font color='red'>uboot</font><font color='red'>系列</font>:第十二章 <font color='red'>uboot</font>源码分析 <font color='red'>uboot</font>如何<font color='red'>启动</font><font color='red'>内核</font>2
Linux移植之内核启动过程start_kernel函数简析
在Linux移植之内核启动过程引导阶段分析中从arch/arm/kernel/head.S开始分析,最后分析到课start_kernel这个C函数,下面就简单分析下这个函数,因为涉及到Linux的内容较多,这里只是简单介绍下内核启动流程。先看一下内核启动的流程框图,截图来自《嵌入式Linux应用开发完全手册》。内核引导阶段已经分析过,接下来分析一下内核启动的第二阶段。 1、start_kernel函数全局概览 2、start_kernel函数调用层次 1、start_kernel函数全局概览,对start_kernel作一下粗略注释。 打开initMain.c ,下面主要分析处理UBOOT传入的参数,其中r1是传入的第一个参
[单片机]
Linux移植之<font color='red'>内核</font><font color='red'>启动</font>过程start_kernel函数简析
自己写一个最简单的bootloader_jz2440
写在前面: 我的博客已迁移至自建服务器:博客传送门,CSDN博客暂时停止,如有机器学习方面的兴趣,欢迎来看一看。 此外目前我在gitHub上准备一些李航的《统计学习方法》的实现算法,目标将书内算法全部手打实现,欢迎参观并打星。GitHib传送门 正文 boot是为了启动内核,本质上也就是一个裸板程序,就是为了引导内核的启动。所以打算自己写一个boot,功能只有引导内核启动。 首先是汇编的代码段,是为了关闭看门狗,设置时钟以及代码的重定位,这些都是在main函数之前执行的。之前学习单片机的时候,我们只看到main函数,实际上是main之前的执行步骤都被包起来了。 整个汇编文件的开头要写上 .text @这是为了表
[单片机]
1_5.3.1_内核配置裁剪及启动流程_内核启动流程分析之编译
使用linux-2.6.22.6版本,补丁为官方提供的2440补丁。 解压缩:tar -jxvf linux-2.6.22.6.tar.bz2 打补丁:patch -p? 补丁文件 配置 编译 其中,配置主要有三种方法: make menuconfig,自己手动配置(太复杂); 使用默认配置,在上面修改; 使用厂家提供的配置; 使用默认配置的话,默认配置是什么呢?在arch/arm/configs目录下,找到相似的配置文件xxx_defconfig,然后执行make xxx_defconfig(结果保存在.config),执行make menuconfig(从.config中读取)配置。 使用厂家提供的配置文件时,
[单片机]
1_5.3.1_<font color='red'>内核</font>配置裁剪及<font color='red'>启动</font>流程_<font color='red'>内核</font><font color='red'>启动</font>流程分析之编译
小广播
设计资源 培训 开发板 精华推荐

最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

换一换 更多 相关热搜器件

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved