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引导内核全过程相关推荐

  1. u-boot移植随笔:关于u-boot引导内核出现“Error: unrecognized/unsupported machine ID (r1 = 0x33f4fee8)”的问题

    这个问题同样经典,大意是说u-boot传递的machine id不正确.在网上看到的文章几乎如出一辙:有两种方法,一是修改内核的head.S(具体在./arch/arm/kernel目录下),二是修改 ...

  2. Exynos4412 Uboot 移植(四)—— Uboot引导内核过程分析

    bootloader 要想启动内核,可以直接跳到内核的第一个指令处,即内核的起始地址,这样便可以完成内核的启动工作了.但是要想启动内核还需要满足一些条件,如下所示: 1.cpu 寄存器设置   * R ...

  3. uboot实践:uboot引导内核相关笔记

    前言 其实,就是一边工作,一边写的笔记. 一 将需要的文件通过scp命令发送发板子 语法如下: scp file_name user_name@192.168.0.250:/home/root/ 含义 ...

  4. u-boot移植随笔:解决引导内核遇到undefined instruction的错误

    前天解决了内核不能引导的问题了.在网上搜索了一些资料,才有点明白这个是怎么回事. 不能引导内核时提示的信息各种各样.像ERROR: can't get kernel image!.Bad Magic ...

  5. mini2440 uboot使用nfs方式引导内核,文件系统

    mini2440 uboot使用nfs方式引导内核,文件系统 成于坚持,败于止步 看了一段时间的u-boot了,到今天才真正完全实现u-boot引导内核和文件系统,顺利开机,在此记录完整过程 1.首先 ...

  6. U-BOOT下使用bootm引导内核方法

    U-BOOT下使用bootm引导内核方法 注:   u-boot 使用的是打上: http://www.hhcn.com/cgi-bin/topic.cgi?forum=3&topic=651 ...

  7. T2080RDB-PC uboot 引导 Linux 内核启动

    T2080RDB-PC uboot 引导Linux 内核启动 3162412793@qq.com 技术交流QQ群:691976956 U-Boot 2016.012.0+ga9b437f (May 1 ...

  8. tiny4412 uboot 2020.10版本移植(四)——uboot修改支持sd卡、eMMC引导内核及其他一些杂项设置

    本文在<tiny4412 uboot 2020.10版本移植(三)--uboot初步启动> 的基础上继续向tiny4412 uboot 2020.10版添加功能. 主要有三块内容:1. D ...

  9. uboot引导linux内核,u-boot启动内核的几种方式

    1.uboot启动内核的代码缩减如下: s = getenv ("bootcmd"); debug ("### main_loop: bootcmd=\"%s\ ...

  10. Debian 编译内核全过程[转]

    Debian 编译内核全过程1.安装内核编译工具 基本工具有:gcc,libc5-dev或libc6-dev,binutils,make,bin86,modutils,mawk或gawk,gzip,s ...

最新文章

  1. C# Base64编码/解码
  2. ASP调用存储过程详解。
  3. DFT实际应用-User-Defined Test Points Example
  4. html函数splice,js数组的常用函数(slice()和splice())和js引用的三种方法总结—2019年1月16日...
  5. caffe使用ctrl-c不能保存模型
  6. 计算机应用技术知识,计算机应用技术主要学什么
  7. sqlserver2005-error:4064
  8. 软件工程中国大学慕课mooc北京大学 答案
  9. 绝对实践,教你如何成功修改捕鱼达人ipad版 金币
  10. csgo autoexec.cfg
  11. 网络协议和浏览器到网络简单攻防实现的探索(二)
  12. win7安装高版本的node解决办法
  13. 根据两个经纬度点调用百度地图应用查询路线 适用android或者ios中及网页浏览(手机网页同样适用)
  14. 网络游戏装备是计算机数据,DNF装备搭配计算器_17173DNF专区_17173.com中国游戏门户站...
  15. 手把手教你获得电信公网ipv6
  16. 微信定位精灵服务器或网络异常,为什么微信定位精灵定位不了怎么办?
  17. 网管笔记之良好习惯的养成
  18. php session.cookie_path,php session和cookie使用说明
  19. 信息管理与信息系统与ERP
  20. 论文要查重的弟兄姐妹看过来

热门文章

  1. 二维数组按某个键值排序 FOR PHP
  2. 动态时间归整/规整/弯曲(Dynamic time warping,DTW)
  3. weblogic 10.x 上开发restful服务
  4. .Net remoting, Webservice,WCF,Socket区别
  5. ++i i++
  6. 介绍几种jquery ui使用方法
  7. android报错自动重启,Android Studio常见报错及处理办法
  8. 螃蟹保存方法保存时间_螃蟹吃不完怎么保存?学会这4招,不论是海蟹、河蟹通通都不愁...
  9. “迷失自我”,请记住下面5个网站,让你受益终身
  10. 系统架构技能之设计模式-单件模式