行情
HOME
行情
正文内容
uboot nand 启动 海思Hi35xx uboot启动分析总结
发布时间 : 2024-11-24
作者 : 小编
访问数量 : 23
扫码分享至微信

海思Hi35xx uboot启动分析总结

liwen01 2019.12.09

前言

在嵌入式linux设备中,uboot的最终目的就是启动kernel。对于uboot而言,没有人把它引导起来,所以uboot首先需要把自己加载起来,然后再去引导kernel的启动,这也就可以大致的分为Uboot启动的第一阶段和第二阶段。

(一)start.S第一阶段启动总结

在海思hi3251a官方的《Hi3521A_PINOUT_CN》手册上有上电锁存管脚BOOTROM_SEL,这个是引脚用来定义是从BOOTROM启动还是从spi flash启动 。

(1)BOOTROM启动

当启动模式为从 BOOTROM 启动时,海思的BOOTROM的程序会去初始化串口,然后与海思的HiBurn工具建立通信

如果能建立通信,则启动HiBurn升级uboot程序流程,如果不能与HiBurn建立连接,等待一段时间之后它就转去从外部的spi flash启动

(2)HiBurn 烧入原理

HiBurn烧入的基本原理是,HiBurn工具与BOOTROM程序建立连接之后,先下载uboot程序的开始4KB数据到海思芯片的内部RAM

然后通过下载的那一小部分uboot代码去初始化外部的DDR,如果DDR初始化成功,HiBurn再将剩下的uboot程序下载到外部的DDR中去

最后是在DDR中启动uboot,如果要进行烧入操作,是通过DDR中的Uboot程序,发送uboot命令将DDR中的uboot程序烧入到外部的flash中去,这样就实现了uboot程序的升级。

(3)spi flash启动

海思的hi3521a芯片支持从 SPI NOR Flash 和 SPI NAND Flash 直接启动,它的启动也就是我们start.s中的大部分实现。主要做的工作有:

初始化CPU相关功能(关缓存,关MMU,设置SVC模式等)将异常中断向量表重定向到内部RAM将uboot代码重定向到外部DDR中设置栈空间清空BSS段最后调用C语言接口去执行C语言代码实现第二阶段的启动。第一阶段在执行之后,在DDR中的映射空间的数据分布如下:

(二)start_armboot第二阶段启动总结

在uboot的启动的第二阶段,主要做的是:

初始化变量和结构体重定向环境变量初始化堆管理器初始化环境变量进入命令处理循环

在命令处理循环中,默认Uboot是超时等待用户命令输入

如果有检测到命令的输入,则执行相应的命令,如果超时没有命令输入,uboot默认执行的bootm命令进行kernel启动引导。

这里涉及到两个比较总要的点:环境变量的重定向和uboot命令处理。

(1)环境变量重定向

在uboot第二阶段的时候,uboot会去检测flash中环境变量的地址中环境变量是否有效,如果有效,则使用flash中的环境变量值来初始化uboot运行中的环境变量,如果flash中的环境变量无效,则使用默认的环境变量来初始化运行中的uboot。

在uboot的用户命令操作过程中,如果有对环境变量进行修改,都是修改的内存中的那一份环境变量,如果要将修改的环境变量保存到flash中去,则需要运行命令saveenvuboot在flash的分布如下:

uboot.bin烧入到flash的0地址位置,boot.bin里面的数据就是按我们连接脚本中的数据那样分布。在0x80000(512KB)开始的位置就是环境变量的在flash的位置,其大小为256KB。

(2)uboot命令处理

在启动的最后阶段,就是执行uboot的bootm命令,主要就是uboot将kernel程序从flash中复制到内存去,然后就是检验kernel镜像文件的有效性,设置uboot传递给kernel的参数,设置kernel启动的环境(比如关缓存,关中断,CPU处于SVC模式等)

最后就是通过一个函数指针指向kernel的启动地址,调用该函数实现uboot到kernel的运行。

在这个过程中,启动参数和机器码同时传递给kernel,关于参数传递,实际在这里是通过寄存器间参数的地址传递给了kernel。

(3)参数传递

C语言进行函数调用的时候,常常会传递给被调用的函数一些参数,对于这些C语言级别的参数,被编译器翻译成汇编语言的时候,就要找个地方存放一下,并且让被调用的函数能够访问,否则就没发实现传递参数了。对于找个地方放一下,分两种情况。

一种情况是,本身传递的参数就很少,就可以通过寄存器传送参数。因为在前面的保存现场的动作中,已经保存好了对应的寄存器的值,那么此时,这些寄存器就是空闲的,可以供我们使用的了,那就可以放参数,而参数少的情况下,就足够存放参数了,比如参数有2个,那么就用r0和r1存放即可。另外一种情况是,如果参数太多,寄存器不够用,那么就得把多余的参数堆栈中了。即,可以用堆栈来传递所有的或寄存器放不下的那些多余的参数。

--------------End--------------

如需获取更多内容

请关注公众号 liwen01

uboot启动内核是什么,认识 uboot 和 内核 之间不可不说的关系

uboot启动内核是什么,认识 uboot和内核之间不可不说的关系

uboot镜像为 uboot.bin,Linux镜像为 zImage

嵌入式设备中的分区表是自己定义的,uboot和内核中的分区表应一致

内核运行前必须加载到 ddr中指定的地址处

uboot需要提供内核必要的参数

内核启动的方式

uboot启动内核有两种方式,一种是等待倒计时结束后直接启动内核,一种是在 uboot命令行中使用 boot命令启动内核

其代码分别如下

其中 parse_string_outer的作用是解析 boot参数并执行

/*------------------倒计时----------------------*/

s = getenv ("bootcmd");

if (bootdelay >= 0 && s && !abortboot (bootdelay)) {

...

parse_string_outer(s, FLAG_PARSE_SEMICOLON |

FLAG_EXIT_FROM_LOOP);

...

}

/*------------------命令行----------------------*/

int do_bootd (cmd_tbl_t *cmdtp, int flag, int argc, char *argv[])

{

...

if (parse_string_outer (getenv ("bootcmd"),

FLAG_PARSE_SEMICOLON | FLAG_EXIT_FROM_LOOP) != 0)

rcode = 1;

...

}

U_BOOT_CMD(

boot, 1, 1, do_bootd,

"boot - boot default, i.e., run 'bootcmd'\n",

NULL

);

/*-----------------相关宏定义----------------------*/

#ifdef CONFIG_BOOTARGS

"bootargs=" CONFIG_BOOTARGS "\0"

#endif

#ifdef CONFIG_BOOTCOMMAND

"bootcmd=" CONFIG_BOOTCOMMAND "\0"

#endif

#define CONFIG_BOOTARGS "console=ttySAC2,115200 root=/dev/mmcblk0p2 rw init=/linuxrc rootfstype=ext3"

#define CONFIG_BOOTCOMMAND "movi read kernel 30008000; movi read rootfs 30B00000 300000; bootm 30008000 30B00000"

加载内核到DDR中

uboot启动内核的步骤

·内核镜像从启动介质中加载到DDR中

·去DDR中启动内核镜像

本文使用的开发板 x210将镜像存放在 SD卡中,要加载到 ddr中需要使用到 movi指令

movi提供了对 iNand/SD卡的操作,movi read用来读取 iNand/SD卡中的内容到DDR中;movi write用来将DDR中的内容写入到 iNand/SD卡中

上面的代码中 bootcmd中的命令就是用来加载 kernel rootfs到 ddr

除了从 SD卡加载,还可以通过 tftp nfs等网络下载方式加载镜像

通过movi read kernel 30008000可以知道,内核加载到了 0x30008000的位置

内核的镜像生成

Linux直接编译得到 elf文件,叫 vmlinux或 vmlinuz。这种文件会比较大,为了烧录方便,会使用 objcopy工具制作成镜像文件,叫 Image(从78M精简成了7.5M)

早期使用的软盘比较小,Image对与软盘来说还是太大了,放不下。Linux对 Image做进一步的压缩,并在压缩文件前端附加了一部分解压缩代码,形成 zImage

uboot可以使用 mkimage工具,在 zImage前面加上64字节的uImage的头信息,形成 uImage

加载启动内核

内核的加载启动是通过 do_bootm完成的

前面介绍过,镜像文件分为两个部分,头部以及真正的内核

所以 do_bootm会先对镜像进行头部信息的校验,然后再进行内核的启动

头部信息的结构体如下

typedef struct image_header {

uint32_t ih_magic; /* Image Header Magic Number */

uint32_t ih_hcrc; /* Image Header CRC Checksum */

uint32_t ih_time; /* Image Creation Timestamp */

uint32_t ih_size; /* Image Data Size */

uint32_t ih_load; /* Data Load Address */

uint32_t ih_ep; /* Entry Point Address */

uint32_t ih_dcrc; /* Image Data CRC Checksum */

uint8_t ih_os; /* Operating System */

uint8_t ih_arch; /* CPU architecture */

uint8_t ih_type; /* Image Type */

uint8_t ih_comp; /* Compression Type */

uint8_t ih_name[IH_NMLEN]; /* Image Name */

} image_header_t;

在 do_bootm中就是通过 ih_os判断镜像的类型,然后使用相应的方法启动内核

这里的镜像是 Linux镜像,所以使用的是 do_bootm_linux, do_bootm_linux的参数大部分是通过 do_bootm传递的

启动的参数bootm 30008000,告诉 uboot去 30008000这个地址去找镜像文件

内核启动

镜像的程序入口叫做 entrypoint,在 do_bootm_linux中使用 ep保存,镜像的程序入口在头信息的 ih_ep中,可以通过读取头信息得到

得到 ep后,通过theKernel = (void (*)(int, int, uint))ep;将 ep格式化后传递给 theKernel,这样 theKernel函数就指向了内存中加载的OS镜像的真正入口地址

前面也提到了,每个开发板在 uboot中都有唯一的机器码,这个编码用来验证开发板与 uboot是否匹配,这个机器码还会传到内核中再次验证。这个机器码获取的第一顺序备选是环境变量machid,第二顺序备选是gd->bd->bi_arch_num(x210_sd.h中的 #define MACH_TYPE 2456)

接下来就是传参的过程。先看看 Linux的 Documentation/arm/Booting中对 CPU寄存器设置的描述

- CPU register settings

r0 = 0,

r1 = machine type number discovered in (3) above.

r2 = physical address of tagged list in system RAM, or

physical address of device tree block (dtb) in system RAM

通过读取 r0 r1 r2这三个寄存器的值来设置 CPU,r0固定为0,r1为前面提到的机器码,r2为存放启动参数 tag结构体的首地址

所以在 do_bootm_linux通过theKernel (0, machid, bd->bi_boot_params);完成传参的过程

传参是通过 struct tag这个结构体完成的,获取参数就是获取一个个 tag的过程。这些 tag也有着规定的格式,do_bootm_linux中通过 setup_start_tag和 setup_end_tag函数设置 tag的开始和结束,这个函数的作用就是设置当前 tag的类型为 ATAG_CORE和 ATAG_NONE,用作 tag起始终止位置的判别

需要注意的是,传参是一个很重要的过程,内核启动不成功与传参错误有很大关系

uboot启动4步骤总结

第一步:将内核搬移到DDR中

第二步:校验内核格式、CRC等

第三步:准备传参

第四步:跳转执行内核

相关问答

uboot启动 详细讲解?

uboot是遵循GPL条款的开放源码项目。uboot的作用是系统引导。uboot从FADSROM、8xxROM、PPCBOOT逐步发展演化而来。其源码目录、编译形式与Linux内核很相似,...

如何让U-boot实现 Nand /Nor双 启动 ?

非常简单,mini2440从Nor启动后,CPU运行在0x00000000地址,这片地址实际对应NorFlash,因为NorFlash是一个Ramlike器件,所以读取数据方法更内存一样,在Uboot...

ubootmlospl是什么东西?

当选择从nandflash启动时,spl为第一阶段,copy前4K到iram,然后完成初始化ddr后,重定位,跳转到ddr,copy剩余uboot到ddr,开始启动第二阶段。当选择从nandfl...

板子 启动 怎么进 uboot ?

你需要制作一个USB启动盘,注意一般大于512M的U盘不能支持启动,开机从硬盘列表里选择从USB启动,最好的制作工具是HPDriveKeyBootUtility,到HP的网上去下...

uboot 是什么,在linux中干嘛用的?

以初始化硬件设备、建立内存空间的映射表,从...u-boot是一种普遍用于嵌入式系统中的Bootloader,Bootloader是在操作系统运行之前执行的一小段程序,通过它,我...

uboot 由哪四个部分组成?

1.U-Boot由四个部分组成。2.首先是启动阶段的SPL(SecondaryProgramLoader),它是一个小型的引导程序,负责初始化硬件和加载U-Boot。其次是U-Boot的主体...

uboot 是怎样从 nand 加载linux?

一般是开发过程中是先把uboot载到nor中,然后通过nor中的uboot再把uboot跟linux内核,根文件系统下到nandflash,它的最终位置应该是在nandflash。至于nor跟nan...

acer bios设置u盘开启-ZOL问答

在宏基笔记本上使用一键U盘启动的方法如下:1.首先,将U盘制作成可用于深度启动的U盘,并将其连接到宏基笔记本电脑。然后重新启动电脑,在开机...

emmc芯片拷贝方法?

一、目的:嵌入式开发板,通过emmc上的内核文件加载启动linux操作系统,以及存放其他程序文件。需要将所需文件先写入emmc中。二、总体步骤是:uboot启动后,进...

usb大容量存储设备为什么无法识别? - 懂得

1。如果USB设备插入本机无法使用,但插入其他电脑就可使用,说明usb大容量存储设备无法识别是因为本机电压不足,而USB设备性能是完好的。2。USB设备属...

 酷狗游戏  三星b9388 
王经理: 180-0000-0000(微信同号)
10086@qq.com
北京海淀区西三旗街道国际大厦08A座
©2024  上海羊羽卓进出口贸易有限公司  版权所有.All Rights Reserved.  |  程序由Z-BlogPHP强力驱动
网站首页
电话咨询
微信号

QQ

在线咨询真诚为您提供专业解答服务

热线

188-0000-0000
专属服务热线

微信

二维码扫一扫微信交流
顶部