u-boot引导内核过程
目标板:2440
u-boot引导内核启动时,传入内核的参数为bootcmd=nand read.jffs2 0x30007FC0 kernel; bootm 0x30007FC0
一、nand read.jffs2 0x30007FC0 kernel
从nand Flash中将内核读取出来,写到地址为0x30007FC0的内存区域。在嵌入式系统中,Flash是没有分区的,但是为什么在应用过程中,我们总是说Flash已经被分区,那是因为在u-boot源码中,将Flash的空间地址绑定了,比如Flash分为boot区,kernel区,fs区,但是在源码中,只是将boot变量赋予一个地址,将kernel这个变量指向了另一个地址。在代码中的具体体为:/include/configs/
100ask24x0.h
#define MTDPARTS_DEFAULT "mtdparts=nandflash0:256k @0(bootloader)," \
"128k(params)," \
"2m(kernel)," \
"-(root)"
那么内核是如何被读出来的,在/common/cmd_nand.c中do_nand函数中
/* read write */ ) == || strncmp(cmd, ) == )
当内核被读取出来之后,就进入下边的过程了。
二、bootm 0x30007FC0
在/common/cmd_bootm.c中do_bootm函数中启动内核。启动内核的时候,首先对内核的头部要进行操作,原因是
在Flash中保存的内核是由两部分构成的,第一部分是头部,第二部分是真正的内核。而头部的结构如下:
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;
ih_load是加载地址,内核在运行的时候先要将内核放在加载地址,比如参数为bootm 0x30007FC0,如果内核不在0x30007FC0地址,那么u-boot在执行bootm 0x30007FC0命令的时候就重新将内核加载到0x30007FC0地址。
ih_ep是入口地址,若要运行内核,直接跳到ih_ep这个地址就可以运行了。如0x30008000就是内核运行地址。
在/common/cmd_bootm.c中
memmove ((void *) ntohl(hdr->ih_load), (uchar *)data, len);
该函数是将内核移到地址为ih_load(加载地址)的内存中。
if(ntohl(hdr->ih_load) == data) {
printf (" XIP %s ... ", name);
} else {
#if defined(CONFIG_HW_WATCHDOG) || defined(CONFIG_WATCHDOG)
size_t l = len;
void *to = (void *)ntohl(hdr->ih_load);
void *from = (void *)data;
printf (" Loading %s ... ", name);
) {
size_t tail = (l > CHUNKSZ) ? CHUNKSZ : l;
WATCHDOG_RESET();
memmove (to, from, tail);
to += tail;
from += tail;
l -= tail;
}
这段代码的解释如下:
在ih_load和 ih_ep之间,存在的是内核的头部image_header_t。如果ih_load和 ih_ep之间的大小恰好等于内核的头部的大小的话,那么真正的内核就开始从ih_ep运行。不用再次移动内核,这样就可以加快启动速度。如果ih_load和 ih_ep之间的大小不等于内核的头部的大小那么内核就必须重新移动到ih_ep地址,这样就延长启动时间。
bootm的第一个作用:根据头部将内核移到合适的地方。
当内核移动到正确的地址之后,启动内核的函数为
case IH_OS_LINUX:
#ifdef CONFIG_SILENT_CONSOLE
fixup_silent_linux();
#endif
do_bootm_linux (cmdtp, flag, argc, argv,
addr, len_ptr, verify);
break;
进入/lib_arm/armLinux.c文件do_bootm_linux函数
do_bootm_linux的作用:
1.启动时会检测内存、Flash……并且将相应的参数告诉内核,设置启动参数。
启动参数的格式为TAG类型。
代码中要设置好几个参数,这儿只是选择性的说几个
setup_start_tag (bd);
setup_memory_tags (bd); 设置内存的参数
setup_commandline_tag (bd, commandline);设置启动时传入内核的参数
setup_end_tag (bd);设置完毕
跳入函数可得:
static void setup_start_tag (bd_t *bd)
{
params = (struct tag *) bd->bi_boot_params;
params->hdr.tag = ATAG_CORE;
params->hdr.size = tag_size (tag_core);
;
;
;
params = tag_next (params);
}
由代码可以得到tag是一个结构体,bi_boot_params为0x300000100,ATAG_CORE为54410001
static void setup_memory_tags (bd_t *bd)
{
int i;
; i < CONFIG_NR_DRAM_BANKS; i++) {
params->hdr.tag = ATAG_MEM;
params->hdr.size = tag_size (tag_mem32);
params->u.mem.start = bd->bi_dram[i].start;
params->u.mem.size = bd->bi_dram[i].start;;
params = tag_next (params);
}
}
bi_dram[i].start;内存的初始地址
bi_dram[i].start;内存的大小
这两个参数的初始值在start_armboot()函数中dram_init可以设置。
static void setup_commandline_tag (bd_t *bd, char *commandline)
{
char *p;
if (!commandline)
return;
/* eat leading white space */
for (p = commandline; *p == ' '; p++);
/* skip non-existent command lines so the kernel will still
* use its default command line.
*/
if (*p == '\0')
return;
params->hdr.tag = ATAG_CMDLINE;
params->hdr.size =
( + ) >> ;
strcpy (params->u.cmdline.cmdline, p);
params = tag_next (params);
}
*commandlinechar 的来源为*commandline = getenv ("bootargs");
那么在终端所获得的信息是bootargs=noinitrd root=/dev/mtdblock3 init=/linuxrc console=ttySAC0
root=/dev/mtdblock3 根文件系统在Flash中的第三分区
init=/linuxrc 第一个进程为linuxrc
console=ttySAC0 内核打印信息从串口输出
static void setup_end_tag (bd_t *bd)
{
params->hdr.tag = ATAG_NONE;
;
}
参数设置结束的时候将tag设置为空,size设置为0.
2.跳到入口地址(还是在do_bootm_linux中)。
void (*theKernel)(int zero, int arch, uint params); theKernel = (void (*)(int, int, uint))ntohl(hdr->ih_ep);
thekernel为函数指针指向ih_ep头部的入口地址。
theKernel (, bd->bi_arch_number, bd->bi_boot_params);
调用thekernel直接到入口地址执行内核,此时控制权交给kernel,u-boot的任务就完成了。
bi_arch_number 为机器ID,内核在启动时会比对是否支持硬件平台。
bd->bi_boot_params为传入的参数。
u-boot引导内核过程的更多相关文章
- The Kernel Boot Process.内核引导过程
原文标题:The Kernel Boot Process 原文地址:http://duartes.org/gustavo/blog/ [注:本人水平有限,只好挑一些国外高手的精彩文章翻译一下.一来自己 ...
- mini2440 uboot使用nfs方式引导内核,文件系统
mini2440 uboot使用nfs方式引导内核,文件系统 成于坚持,败于止步 看了一段时间的u-boot了,到今天才真正完全实现u-boot引导内核和文件系统,顺利开机,在此记录完整过程 1.首先 ...
- Tiny4412 u-boot分析(3)u-boot 引导内核流程
在u-boot中,通过bootm命令启动内核.bootm命令的作用是将内核加载到指定的内存地址,然后通过R0.R1.R2寄存器传递启动参数之后启动内核.在启动内核之前需要对环境做一些初始化工作,主要有 ...
- u-boot-2011.06在基于s3c2440开发板的移植之引导内核与加载根文件系统
http://www.linuxidc.com/Linux/2012-09/70510.htm 来源:Linux社区 作者:赵春江 uboot最主要的功能就是能够引导内核启动.本文就介绍如何实现该 ...
- 嵌入式linux加载引导内核和根文件系统的方法
总体来说,嵌入式Linux内核和根文件的引导与PC机差不多.嵌入式linux内核和根文件系统可以存放在各种可能的存储设备中,一般情况下我 们将内核和根文件系统直接烧入到Flash中(包括NOR和NAN ...
- uboot引导linux内核过程详解【转】
http://blog.chinaunix.net/uid-7828352-id-4472376.html 写的不错,尤其是uboot向linux内核传递参数的过程写的比较详细.
- 使用centos引导内核错误:kernel: pnp 00:0b: can't evaluate _CRS: 8
CentOS系统在开机过程中,一直遇到黑屏提示:“kernel: pnp 00:0b: can't evaluate _CRS: 8”,不理会它仍能启动系统并正常工作,未知何故. 经查,这是内核引导的 ...
- <linux是怎么跑的?>傻瓜视角看linux引导启动过程
每天开机关机,除了“等”之外,你得了解你的操作系统开机的时候真正做了什么? 一. 书上都是这么讲的 CPU自身初始化:硬件初始工作,以PC/IP寄存器跳转到BIOS首地址为结束标志. ->加电自 ...
- spring boot 引导
链接:https://www.zhihu.com/question/39483566/answer/243413600 Spring Boot 的优点快速开发,特别适合构建微服务系统,另外给我们封装了 ...
随机推荐
- 题解 P5015 【标题统计】
既然这个题这么水 大家不如来盘点一下算法呗 首先说一个事:逗号表达式 这玩意的值是最后一个表达式的值 那么我们就可以愉快的放进循环条件里摩擦 话说这个应该是基础吧,大多数代码都可以这样干 具体可以后面 ...
- mysql索引长度的一些限制
一.myisam存储引擎 1. 数据库版本:阿里云RDS MySQL5.1 mysql> select @@version;+-------------------------------+| ...
- BZOJ1072 排列perm 【状压dp】
Description 给一个数字串s和正整数d, 统计s有多少种不同的排列能被d整除(可以有前导0).例如123434有90种排列能 被2整除,其中末位为2的有30种,末位为4的有60种. Inpu ...
- MapReduce(一) mapreduce基础入门
一.mapreduce入门 1.什么是mapreduce 首先让我们来重温一下 hadoop 的四大组件:HDFS:分布式存储系统MapReduce:分布式计算系统YARN: hadoop 的资源调度 ...
- Hive(一)基础知识
一.Hive的基本概念 (安装的是Apache hive 1.2.1) 1.hive简介 Hive 是基于 Hadoop 的一个数据仓库工具,可以将结构化的数据文件映射为一张数据库表, 并提供类 SQ ...
- [CodeVs1515]跳(lucas定理+费马小定理)
嘿嘿嘿好久没写数学题了,偶尔看到一道写一写... 题目大意:一个(n+1)*(m+1)[0<=n, m<=10^12,n*m<=10^12]的矩阵,C(0,0)=1,C(x,y)=C ...
- 手把手教你如何玩转Activiti工作流
手把手教你如何玩转Activiti工作流 置顶 2018年01月30日 19:51:36 Cs_hnu_scw 阅读数:24023 版权声明:本文为博主原创文章,未经博主允许不得转载. https ...
- move_base的全局路径规划代码研究
algorithmn parameter code 主要是以下三个函数 计算所有的可行点 怎么计算一个点的可行点 从可行点中计算路径path todo algorithmn 算法的解释 Dijkstr ...
- php使用 SImpleXMLElement 把 xml 和 数组 互转
<?php $xml = <<<XML <xml> <ToUserName><![CDATA[toUser]]></ToUserNam ...
- tp between
$a = array( 'time' => array('between',[c,d]) ); c<= time <= d