Hi3536 uboot引导内核全过程
Hi3536uboot引导内核全过程
本文讲述uboot引导内核启动的全部过程,uboot版本为2010.06
1、arch/arm/cpu/hi3536/u-boot.lds
连接文件,不同平台不一样。
OUTPUT_FORMAT("elf32-littlearm","elf32-littlearm", "elf32-littlearm") //elf格式 32位,小端
OUTPUT_ARCH(arm)//arm架构
ENTRY(_start)//代码进入点arch/arm/cpu/hi3536/start.S中定义,一切从这里开始
SECTIONS
{
.= 0x00000000; //可执行文件入口地址
.= ALIGN(4);
.text ://代码段
{
__text_start = .;
arch/arm/cpu/hi3536/start.o (.text)
drivers/ddr/ddr_training_impl.o (.text)
drivers/ddr/ddr_training_ctl.o (.text)
drivers/ddr/ddr_training_boot.o (.text)
drivers/ddr/ddr_training_custom.o (.text)
__init_end = .;
ASSERT(((__init_end - __text_start) < 0x16000), "init sectionstoo big!");
*(.text)
}
.= ALIGN(4);
.rodata : { *(SORT_BY_ALIGNMENT(SORT_BY_NAME(.rodata*))) } //只读数据段
.= ALIGN(4);
.data : { *(.data) } //数据段
.= ALIGN(4);
.got : { *(.got) }
__u_boot_cmd_start = .; //存放uboot命令
.u_boot_cmd : { *(.u_boot_cmd) }
__u_boot_cmd_end = .;
.= ALIGN(4);
__bss_start = .; //bss段
.bss : { *(.bss) }
_end = .;
}
2、arch/arm/cpu/hi3536/start.S
Arm在uboot下的入口文件,纯汇编,由于代码太多,这里描述基本过程:
(1)定义入口
.globl _start
_start: b reset //跳转到复位
//以下是各种异常处理入口定义
ldr pc, _undefined_instruction
ldr pc, _software_interrupt
ldr pc, _prefetch_abort
ldr pc, _data_abort
ldr pc, _not_used
ldr pc, _irq
ldr pc, _fiq
(2)进入reset第一步
A. set the cpu to SVC32 mode
B. Invalidate L1 I/D
C. Invalidate L1 D-cache
D. disable MMU stuff and caches
(3)第二步
判断boot方式,从bootrom / spi /nand中的一种启动,撤销地址空间映射。
假设启动方式为spi nor flash启动,这时起始地址空间映射到spi nor flash地址空间,但是spi nor flash不能直接执行代码,这里猜测是:映射后硬件固化程序从spi nor flash中将部分代码搬运到内部RAM开始执行。
(4)第三步
进行pll /flash/ddr等的初始化
(5)第4步
拷贝flash数据到DDR空间
在这之前只是搬运了初始化用的最基本的部分到内部,但是整个uboot并未搬运到DDR,这里则进行完整的搬运:r1-DDR地址0x40c00000,r0-flash地址为spi地址,r2大小为_bss_start - _armboot_start(_start),memcpy(r1, r0, r2)。内存布局见第8节
(6)第5步
跳转到DDR,进入第一个C语言入口
clbss_l:
str r2, [r0] @ clear BSSlocation
cmp r0, r1 @ are we atthe end yet
add r0, r0, #4 @ incrementclear index pointer
bne clbss_l @ keepclearing till at end
ldr pc, _start_armboot @ jump to C code
_start_armboot: .word start_armboot
3、src/arch/arm/lib/board.c
init_fnc_t *init_sequence[] = { //初始化函数列表
timer_init, /* initializetimer before usb init */
board_init, /* basic boarddependent setup */
env_init, /* initializeenvironment */
init_baudrate, /* initialzebaudrate settings */
serial_init, /* serialcommunications setup */
console_init_f, /* stage 1init of console */
display_banner, /* say that weare here */
dram_init, /* configureavailable RAM banks */
NULL,
};
void start_armboot (void)
{
/* Pointer iswritable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CONFIG_SYS_MALLOC_LEN - sizeof(gd_t));
_armboot_start = 0x40c00000(内存起始地址0x40000000,预留了12M)
CONFIG_SYS_MALLOC_LEN = 4 * 1024 * 1024(自己修改)
…
//运行所有初始化函数
for(init_fnc_ptr = init_sequence; *init_fnc_ptr;++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
…
#ifdefCONFIG_CMD_SF
spi_flash_probe(0, 0, 0, 0); //初始化spi flash
#endif
env_relocate ();//初始化uboot环境变量
…
#ifdefined(CONFIG_CMD_NET)
eth_initialize(gd->bd); //网络初始化
#endif
#ifdefSTART_UBOOT_NO_NET_OPERATION
int ret = 0;
ret = eth_init(gd->bd); //网络驱动初始化,该部分自己添加
if(!ret)
eth_halt();
#endif
…
for(;;) {
main_loop (); //进入main主函数
}
}
4、src/common/main.c
void main_loop (void)
{
…
#ifdefined(CONFIG_BOOTDELAY) && (CONFIG_BOOTDELAY >= 0)
s= getenv ("bootdelay"); //获取bootdelay次数(即秒数)
bootdelay = s ? (int)simple_strtol(s, NULL, 10) : CONFIG_BOOTDELAY;
debug ("### main_loop entered: bootdelay=%d\n\n", bootdelay);
#ifdef CONFIG_HI3536_A7
//modify by hlb
//s = getenv("slave_cmd");
s = getenv("bootcmd");
#else
s = getenv("bootcmd"); //获取bootcmd命令内容
/*bootcmd=usbupdate; tftpupdate; fsload; bootm
usbupdate: 扫描U盘,升级U盘文件,自己添加不进行说明
tftpupdate: tftp自动化升级,自己添加不进行说明
fsload:加载内核文件,自己修改,后续章节说明
bootm:引导内核,后续章节说明
*/
#endif
debug ("### main_loop: bootcmd=\"%s\"\n", s ? s :"<UNDEFINED>");
//在bootdelay时间内连续输入3个字符*(自己修改为*),则不执行bootcmd命令,进入uboot命令行,否则执行bootcmd命令
if (bootdelay >= 0 && s && !abortboot (bootdelay)) {
# ifndef CONFIG_SYS_HUSH_PARSER
run_command (s, 0); //执行bootcmd命令
# else
parse_string_outer(s, FLAG_PARSE_SEMICOLON |
FLAG_EXIT_FROM_LOOP);
# endif
}
…
//进入uboot命令行,响应用户输入的命令
for (;;) {
len = readline (CONFIG_SYS_PROMPT);
flag = 0; /* assume no special flags for now */
if (len > 0)
strcpy (lastcommand, console_buffer);
else if (len == 0)
flag|= CMD_FLAG_REPEAT;
if (len == -1)
puts ("<INTERRUPT>\n");
else
run_command(lastcommand, flag);
/* invalid command or not repeatable,forget it */
lastcommand[0] = 0;
}
}
5、src/common/cmd_fsload.c
bootcmd环境变量中fsload命令,实际运行函数就为该文件的do_fsload函数。
int do_fsload(cmd_tbl_t *cmdtp, int flag,int argc, char *argv[])
{
char *fsname;
char *filename = "/boot/uImage"; //读取内核完整路径名
int size = 0;
struct part_info *part;
ulong offset = CONFIG_SYS_LOAD_ADDR; //=0x42000000,内核加载的内存地址
part = spi_cramfs_init(); //读取内核所在根文件系统信息
if (part ==0)
{
return 1;
}
printf("### squashfs loading '%s' to 0x%lx\n", filename,offset);
if(squashfs_check(part)) //这里使用自己添加的squashfs文件系统,默认是cramfs。
{
size = squashfs_fload((char *) offset, part, filename); //加载内核到上述内存地址
}
if (size > 0) { //加载成功
char buf[10];
printf("### %s load complete: %d bytes loaded to 0x%lx\n",
fsname, size, offset);
sprintf(buf, "%x", size);
setenv("filesize", buf);
}else { //加载失败
printf("### %s LOAD ERROR<%x> for %s!\n", fsname, size,filename);
}
return !(size > 0);
}
6、src/common/cmd_bootm.c
bootcmd环境变量中bootm命令,实际运行函数就为该文件的do_bootm函数。
int do_bootm (cmd_tbl_t *cmdtp, int flag,int argc, char *argv[])
{
…
if(bootm_start(cmdtp, flag, argc, argv)) //该函数解析内核image头,获取内核信息
return 1;
/*
images.os.image_start= 0x42000040 (0x40 64字节头大小)
images.os.image_len= 0x25fa88
images.os.type= IH_TYPE_KERNEL
images.os.comp= IH_COMP_NONE
images.os.os= IH_OS_LINUX
images.os.start= 0x42000000
images.os.end = 0x4225fac8
images.os.load= 0x40008000 真正的内核会加载到该地方
*/
…
ret = bootm_load_os(images.os,&load_end, 1);
/*
将内核从os.image_start搬运到os.load地址
load_end = 0x40267a88(0x40008000+0x25fa88)
*/
…
boot_fn= boot_os[images.os.os]; //根据操作系统类型获取对应操作系统入口函数,这里为do_bootm_linux
…
boot_fn(0, argc, argv, &images); //运行do_bootm_linux函数,成功则会进入内核
…
do_reset (cmdtp, flag, argc, argv); //如果失败则重启uboot
}
7、src/arch/arm/lib/bootm.c
int do_bootm_linux(int flag, int argc, char*argv[], bootm_headers_t *images)
{
intmachid = bd->bi_arch_number; //传递给内核的机器码hi3536 0x8000
void (*theKernel)(int zero, intarch, uint params); //进入内核函数指针
theKernel= (void (*)(int, int, uint))images->ep; //ep = 0x40008000
…
#ifdefined (CONFIG_SETUP_MEMORY_TAGS) || \
defined (CONFIG_CMDLINE_TAG) || \
defined (CONFIG_INITRD_TAG) || \
defined (CONFIG_SERIAL_TAG) || \
defined (CONFIG_REVISION_TAG)
setup_start_tag (bd);
#ifdefCONFIG_SETUP_MEMORY_TAGS
setup_memory_tags (bd);
#endif
#ifdefCONFIG_CMDLINE_TAG
setup_commandline_tag (bd,commandline);
#endif
….
setup_end_tag (bd);
#endif
/* 需要传递给内核的各个TAG,放入参数列表 */
…
theKernel (0, machid, bd->bi_boot_params); //进入内核,无返回
/* 第2个参数为机器码,第二个参数为传递给内核参数列表的首地址=0x40000100 */
}
8、uboot阶段的内存布局
Hi3536 uboot引导内核全过程相关推荐
- u-boot移植随笔:关于u-boot引导内核出现“Error: unrecognized/unsupported machine ID (r1 = 0x33f4fee8)”的问题
这个问题同样经典,大意是说u-boot传递的machine id不正确.在网上看到的文章几乎如出一辙:有两种方法,一是修改内核的head.S(具体在./arch/arm/kernel目录下),二是修改 ...
- Exynos4412 Uboot 移植(四)—— Uboot引导内核过程分析
bootloader 要想启动内核,可以直接跳到内核的第一个指令处,即内核的起始地址,这样便可以完成内核的启动工作了.但是要想启动内核还需要满足一些条件,如下所示: 1.cpu 寄存器设置 * R ...
- uboot实践:uboot引导内核相关笔记
前言 其实,就是一边工作,一边写的笔记. 一 将需要的文件通过scp命令发送发板子 语法如下: scp file_name user_name@192.168.0.250:/home/root/ 含义 ...
- u-boot移植随笔:解决引导内核遇到undefined instruction的错误
前天解决了内核不能引导的问题了.在网上搜索了一些资料,才有点明白这个是怎么回事. 不能引导内核时提示的信息各种各样.像ERROR: can't get kernel image!.Bad Magic ...
- mini2440 uboot使用nfs方式引导内核,文件系统
mini2440 uboot使用nfs方式引导内核,文件系统 成于坚持,败于止步 看了一段时间的u-boot了,到今天才真正完全实现u-boot引导内核和文件系统,顺利开机,在此记录完整过程 1.首先 ...
- U-BOOT下使用bootm引导内核方法
U-BOOT下使用bootm引导内核方法 注: u-boot 使用的是打上: http://www.hhcn.com/cgi-bin/topic.cgi?forum=3&topic=651 ...
- T2080RDB-PC uboot 引导 Linux 内核启动
T2080RDB-PC uboot 引导Linux 内核启动 3162412793@qq.com 技术交流QQ群:691976956 U-Boot 2016.012.0+ga9b437f (May 1 ...
- tiny4412 uboot 2020.10版本移植(四)——uboot修改支持sd卡、eMMC引导内核及其他一些杂项设置
本文在<tiny4412 uboot 2020.10版本移植(三)--uboot初步启动> 的基础上继续向tiny4412 uboot 2020.10版添加功能. 主要有三块内容:1. D ...
- uboot引导linux内核,u-boot启动内核的几种方式
1.uboot启动内核的代码缩减如下: s = getenv ("bootcmd"); debug ("### main_loop: bootcmd=\"%s\ ...
- Debian 编译内核全过程[转]
Debian 编译内核全过程1.安装内核编译工具 基本工具有:gcc,libc5-dev或libc6-dev,binutils,make,bin86,modutils,mawk或gawk,gzip,s ...
最新文章
- C# Base64编码/解码
- ASP调用存储过程详解。
- DFT实际应用-User-Defined Test Points Example
- html函数splice,js数组的常用函数(slice()和splice())和js引用的三种方法总结—2019年1月16日...
- caffe使用ctrl-c不能保存模型
- 计算机应用技术知识,计算机应用技术主要学什么
- sqlserver2005-error:4064
- 软件工程中国大学慕课mooc北京大学 答案
- 绝对实践,教你如何成功修改捕鱼达人ipad版 金币
- csgo autoexec.cfg
- 网络协议和浏览器到网络简单攻防实现的探索(二)
- win7安装高版本的node解决办法
- 根据两个经纬度点调用百度地图应用查询路线 适用android或者ios中及网页浏览(手机网页同样适用)
- 网络游戏装备是计算机数据,DNF装备搭配计算器_17173DNF专区_17173.com中国游戏门户站...
- 手把手教你获得电信公网ipv6
- 微信定位精灵服务器或网络异常,为什么微信定位精灵定位不了怎么办?
- 网管笔记之良好习惯的养成
- php session.cookie_path,php session和cookie使用说明
- 信息管理与信息系统与ERP
- 论文要查重的弟兄姐妹看过来
热门文章
- 二维数组按某个键值排序 FOR PHP
- 动态时间归整/规整/弯曲(Dynamic time warping,DTW)
- weblogic 10.x 上开发restful服务
- .Net remoting, Webservice,WCF,Socket区别
- ++i i++
- 介绍几种jquery ui使用方法
- android报错自动重启,Android Studio常见报错及处理办法
- 螃蟹保存方法保存时间_螃蟹吃不完怎么保存?学会这4招,不论是海蟹、河蟹通通都不愁...
- “迷失自我”,请记住下面5个网站,让你受益终身
- 系统架构技能之设计模式-单件模式