快讯
HOME
快讯
正文内容
uboot nand 分区 uboot启动内核是什么,认识 uboot 和 内核 之间不可不说的关系
发布时间 : 2024-10-10
作者 : 小编
访问数量 : 23
扫码分享至微信

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命令,虽然资料光盘->常见问题目录有U-boot常用命令汇总文档,但从大家的反馈来看,并没有很多人注意到这个文档,所以把它挪到这里。如此全的uboot命令汇总,建议收藏。

注意:不同版本的uboot,它的命令有所不同,这里使用u-boot 1.1.6。

一、nandflash分区信息

OpenJTAG>mtdpart

device nand0 <nandflash0>, # parts = 4

#:name size offset

0: bootloader 0x00040000 0x00000000

1: params 0x00020000 0x00040000

2: kernel 0x00200000 0x00060000

3: root 0x0fba0000 0x00460000

二、设置机器ID

set machid 16a // JZ2440,也可以用setenv machid 16a

set machid 7CF // mini2440

三、设置环境变量

print // 打印环境变量

save // 保存环境变量

setenv bootdelay 5 // 设置bootdelay 为5setenv ipaddr 192.168.1.226 // 设置开发板ip为192.168.1.226setenv serverip 192.168.1.200 // 设置服务器ip为192.168.1.200

setenv gatewayip 192.168.1.1 // 设置网关为 192.168.1.1setenv netmask 255.255.255.0 // 设置子网掩码

// 由于是两条指令,因此需要用单引号引起来

// 读取内核 并启动

setenv bootcmd 'nand read.jffs2 0x30007FC0 kernel ; bootm 0x30007FC0'

// 使用flash中的文件系统启动,默认为yaffs2文件系统,如果是jffs2文件系统,添加 rootfstype=jffs2

// yaffs2

setenv bootargs noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0,115200

// jffs2setenv bootargs noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0,115200 rootfstype=jffs2

// 使用nfs网络文件系统启动,默认为yaffs2文件系统,如果是jffs2文件系统,添加rootfstype=jffs2

举例:

虚拟机ip :192.168.1.2

网关 :192.168.1.1

开发板ip : 192.168.1.3

子网掩码 :255.255.255.0

文件系统目录:/work/nfs_root/xxxx

// yaffs2 ,注意是一行

setenv bootargs noinitrd root=/dev/nfs console=ttySAC0

nfsroot=192.168.1.2:/work/nfs_root/xxxxip=192.168.1.3:192.168.1.2:192.168.1.1:255.255.255.0::eth0:off init=/linuxrc

// jffs2 ,注意是一行

setenv bootargs noinitrd root=/dev/nfs console=ttySAC0

nfsroot=192.168.1.2:/work/nfs_root/xxxxip=192.168.1.3:192.168.1.2:192.168.1.1:255.255.255.0::eth0:off init=/linuxrc rootfstype=jffs2

// 清除某个环境变量

setenv bootargs //以bootargs为例

save

// 清除全部的环境变量

nand erase params

四、tftp烧写

// 通过tftp烧写u-boot.bin到nand Flash步骤:

打开 tftpd32.exe 软件, 将u-boot.bin 拷贝至工作目录

在SecureCRT中依次输入:

tftp 0x30008000 u-boot.bin //将uboot.bin 下载到sdram 0x30008000地址处

nand erase bootloader // 擦除bootloader区域

nand write 0x30008000 bootloader // 烧写到bootloader

// 通过tftp烧写uImage到nand Flash步骤:

打开 tftpd32.exe 软件, 将 uImage 拷贝至工作目录

在SecureCRT中依次输入:

tftp 0x30008000 uImage

nand erase kernel

nand write 0x30008000 kernel

// 烧写YAFFS文件系统至Nand Flash

打开 tftpd32.exe 软件, 将 fs_mini.yaffs2 拷贝至工作目录

在SecureCRT中依次输入:

tftp 0x30008000 fs_mini.yaffs2

nand erase root

nand write.yaffs 0x30008000 root $(filesize) // $(filesieze) 是fs_mini.yaffs2 的大小

// 烧写JFFS文件系统至Nand Flash

//使用 jffs2 文件系统启动时记得修改 bootargs 添加 rootfstype=jffs2

打开 tftpd32.exe 软件,将 fs_mini.jffs2 拷贝至工作目录

在SecureCRT中依次输入:

tftp 0x30008000 fs_mini.jffs2

nand erase root

nand write.jffs2 0x30008000 root $(filesize) // $(filesieze) 是fs_mini.yaffs2 大小

当然,之前的所有下载也可以换成 nfs ,

假设虚拟机 ip 为 192.168.1.123

nfs共享目录(在ubuntu 的 /etc/exports设置)为: /work/nfs_root

那么nfs下载命令如下:

nfs 0x30008000 192.168.1.123:/work/nfs_root/u-boot.bin // nfs下载u-boot.bin

nfs 0x30008000 192.168.1.123:/work/nfs_root/uImage // nfs下载uImage

nfs 0x30008000 192.168.1.123:/work/nfs_root/fs_mini.yaffs2 // nfs下载fs_mini.yaffs2

nfs 0x30008000 192.168.1.123:/work/nfs_root/fs_mini.jffs2 // nfs下载fs_mini.jffs2

- end -

相关问答

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

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

360p4路由器刷第三方固件?

能刷第三方固件。首先下载360最新的固件包。360art.bin:u-boot控制台里会用到。只有同时刷入这个才能进入【无线】页面,才能设置无线相关东西。然后刷入该...

flash烧录和ic烧录?,IC烧录设备该怎么选,都来说说?

[回答](烧uboot和内核)比如直接nanderase全擦除。然后再把文件写到内存tftp内存地址文件名然后再nandwrite进去的。根文件系统是把板子分区挂载起来后再烧...

谁知道创维智能电视怎么升级?- 一起装修网

谁知道创维安卓智能电视怎么升级?

联想笔记本无法进入系统怎样系统恢復-ZOL问答

只要没有破坏隐藏分区,那就一键还原,C盘文件都没了,大部分找不回来。有用(0)...2).下载UBOOT软件把U盘制成启动盘,(制作启动盘一次不行可以多下几个试试)3)...

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

QQ

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

热线

188-0000-0000
专属服务热线

微信

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