[1],先看一下整个系统的结构(软件是灵魂,硬件是驱体,再强大的灵魂力若没有躯体终将是游魂野鬼,再强壮的驱体若没有灵魂终将是植物人)

结构 作用 备注
硬件 一切软件的载体  
xloader                   引导uboot                                   
uboot 启动加载或下载linux kernel  
linux kernel OS,承载android  
android OS,承载APP  

[2],为什么需要xloader?

cpu上电后会自动加载一小段程序到内部ram中运行,内部的ram资源很小,一般只有几十k的空间,比如我现在用的cpu就只有32k的空间。uboot功能很强,具有初始化,交互操作,下载和引导linux的作用,因此体积上会超过cpu内部的ram大小,所以我们需要更小的xloader来为我们加载引导uboot。xloader一般只作一些最最核心的硬件初始化,比如cpu时钟,外部内存,flash和usb/SD/uart的初始化工作,然后就加载uboot,把更深入的初始就交给uboot来执行。

[3],xloader执行流程

[首先],看x-loader.lds文件,通过以下命令得到lds文件的路径

 $ find -name "*.lds"

打开x-loader.lds如下:

 /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//指定输出可执行文件是elf格式,32位ARM指令,小端
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
//指定输出可执行文件的平台为ARM
OUTPUT_ARCH(arm)
//指定输出可执行文件的起始代码段为_start
ENTRY(_start)
SECTIONS
{
//从0x0位置开始,但会在vim board/copener_pad_ref/config.mk 文件里面定义为TEXT_BASE = 0x07041000
. = 0x00000000; //代码以4字节对齐
. = ALIGN();
//指定代码段
.text :
{
cpu/copener/start.o (.text) //代码的第一个代码部分
*(.text) //其它代码部分
} . = ALIGN(); //指定只读数据段
.rodata : { *(.rodata) } . = ALIGN(); //指定可读写数据段
.data : { *(.data) } . = ALIGN(); //指定got段, got段式是uboot自定义的一个段, 非标准段
.got : { *(.got) } . = ALIGN(); //把__bss_start赋值为当前位置,即bss段的开始位置
__bss_start = .; //指定bss段
.bss : { *(.bss) } //把_end赋值为当前位置,即bss段的结束位置
_end = .;
}

  由上面可知程序的入口为“cpu/copener/start.S”文件,且入口函数为“_start”,开头已经有了,接下来就是怎么跟踪代码了。

  [然后],跟踪start.S文件:

  start.S是汇编写的文件,主要是执行了下面的操作  

 // set the cpu to SVC32 mode
// disable MMU
// Enable all domains to client mode
// Invalidate instruction cache
// Invalidate data cache
// Invalidate entire Unified main TLB ldr pc, _start_armboot /* jump to C code */
_start_armboot: .word start_armboot

  start.S的最后通过“ldr pc, _start_armboot”跳入C代码中运行了。通过下面的命令把start_armboot函数所在文件lib/board.c找出。  

 $ grep -rnws start_armboot 

  打开board.c,该函数简化后的操作如下

 void start_armboot (void)
{
board_init(); //pad_ref.c 空函数
uart_init(CFG_UART_BAUD_RATE); //uart.c 初始化串口
cpu_init(); //cpu.c 设置一下cpu的频率
ddr_init(); //ddr_init.c 初始化ddr
mem_test(); //board.c 内存测试 for(idx = ;idx < ;) {
sram_dat = readl(SRAM_BASE_ADDR + idx);
writel(sram_dat,DDR_DATA_BASE + idx);
idx = idx + ;
} if (check_romloader_fastboot()) { //检测引导设置,若符合usb引导则fastboot USB
TRACE(KERN_INFO, "enter fastboot USB boot\n");
usb_boot(0x02); //进入USB引导操作
} switch(readl(CFG_BOOT_MODE) & 0x3){ //检测其它引导模式进入相应操作
case 0x00:
TRACE(KERN_INFO,"SDIO\n");
sdmmc_continue_boot(0x0); case 0x02:
TRACE(KERN_INFO,"USB\n");
usb_boot(0x02);
break; case 0x03:
TRACE(KERN_UART,"UART\n");
uart_boot(0x03);
break;
default:
TRACE(KERN_ERROR,"No Boot Source\n");
break;
}
TRACE(KERN_ERROR,"No U-boot found\n");
while();
}

  而后面的usb_boot(0x02)又会调用handle_fastboot(rxdata, rxsize, boot_mode),进而调用enter_entry(head.entry, boot_mode),最后调用(*(void(*)())buf)(boot_mode),然后就跳进uboot里面去运行了。

  (*(void(*)())buf)(boot_mode)是一个函数指针,类型为void(*)(),指向的是buf地址,即head.entry,涉及到的结构体如下:  

 typedef struct {
char tag[]; //NUFX
unsigned int offset; //
unsigned int entry; //where to place
unsigned int size; //size of binary
unsigned int loader_cksum; //chsum of binary
unsigned int header_cksum; //cksum of first 16 bytes of header
}xl_header;
extern xl_header head;

  由config.mk文件指定TEXT_BASE = 0x07041000,然后通过偏移算出Head.entry = 0x7041008。即xloader最后要跳转的地址为0x7041008。

[4]xloader的编译  

 //清除上一次编译
$ make distclean //配置当前编译
$ make copener_pad_ref_config //编译
$ make //////////////////////////////////////生成文件时打印的信息//////////////////////////////////////
Generate x-load.img from x-load
ELF Entry = 0x7041008
ELF Program number =
ELF Program Header Offset =
Program[]: offset=0x200, Size=0x74f8
Program[]: offset=0x61656100, Size=0x412d3705
Head.tag = NUFX
Head.offset = 0x200
Head.entry = 0x7041008
Head.size = 0x74fc
Head.loader_cksum = 0x55157080
Head.header_cksum = 0xb4604cd2

  生成的文件为:  

 oee@copener:/opt/ns115_jb/bsp/xloader$ ls -lh
-rwxrwxr-x oee oee 30K 5月 : x-load.bin
-rw-rw-r-- oee oee 30K 5月 : x-load.img

  

xloader的更多相关文章

  1. Pandaboard ES编译bootloader、xloader、内核、以及安卓系统

    Building bootloader and kernel Bootloader Startwith building the bootloader. To learn more about the ...

  2. 嵌入式Linux引导过程之1.5——从BootRom到Xloader

    在开始看Xloader_Entry的代码之前,我想先总结一下从芯片上电到开始运行Xloader的代码的过程,这是我目前理解的一个过程,可能有所出入,待以后继续完善. 当 系统上电之后,首先会将PC寄存 ...

  3. 嵌入式Linux引导过程之1.6——Xloader的Xloader_Entry

    我们已经看完了XLOADER_ENTRY里调用的前两个标号的代码,分别是sys_init和ddr_init.对于一个嵌入式系统来说,这两 个部分的代码是在一开始就执行的,至少是在从bootrom里面的 ...

  4. 嵌入式Linux引导过程之1.4——Xloader的ddr_init

    这里我们来看XLOADER_ENTRY中调用的第二个标号ddr_init处的代码,这部分代码的作用是对外部内存SDRAM进行初始化,在我 spearplus开发板中,使用的是DDR SDRAM.在调用 ...

  5. 嵌入式Linux引导过程之1.3——Xloader的sys_init

    上一篇文章对XLOADER_ENTRY进行了分析,看到其中调用的第一个标号就是sys_init,本文就对这个标号对应的代码段进行粗略的分析,这里我也还有好多没有搞明白的,就先留着,日后慢慢明白,先把自 ...

  6. 嵌入式Linux引导过程之1.1——Xloader的xloader.lds

    本文中的所有代码版本都是基于ST的SpearPlus开发板的. xloader是在系统上电之后,执行完ROM中的frimware后最先开始执行的用户程序,它的体积很小,执行的功能也很简单,主要是对系统 ...

  7. 嵌入式Linux引导过程之1.2——Xloader的XLOADER_ENTRY

    根据上文中获得的线索,本文分析init.S中的XLOADER_ENTRY. 在init.S中,定义了好多与平台相关的寄存器地址宏以及好多其他函数,我们在用到的时候再回过头来分析,这里,我们只看其中的一 ...

  8. Android刷机教程

    我的机器是Nexus 5 一. 安装驱动 如何进入fastboot模式 1. 拔掉数据线,将手机关机 2. 关机后同时按住[音量减小键]和[开关机键]即可进入Fastboot模式 开启usb调试  - ...

  9. ns115 step by step

    一,安装环境: sudo apt-get install git-core gnupg flex bison gperf build-essential zip curl zlib1g-dev lib ...

随机推荐

  1. CentOS 6.6编译安装Nginx1.6.2+MySQL5.6.21+PHP5.6.3

    http://www.osyunwei.com/archives/8867.html 一.配置防火墙,开启80端口.3306端口 vi /etc/sysconfig/iptables #编辑防火墙配置 ...

  2. SQLSERVER跨数据库操作 ---- sp_addlinkedserver

    由于项目需要跨数据库进行相应的sql操作(这里遇到的是sqlserver的A库,到sqlserver的B库) sp_addlinkedserver [ @server = ] ' server ' [ ...

  3. React之Composition Vs inheritance 组合Vs继承

    React的组合   composition: props有个特殊属性,children,组件可以通过props.children拿到所有包含在内的子元素, 当组件内有子元素时,组件属性上的child ...

  4. JDBC driver connection string大全

    Database   / data source URL format /   driver name Value Default port MySQL URL format: jdbc:mysql: ...

  5. Ext JS 4 新特性2:配置项属性(config)之二

    Ext JS 4 新特征2:配置项属性config之二 ☞ Config(自动的setters和getters) Ext JS 4介绍了config声明方式,在Ext JS 中也有几个例子:在运行程序 ...

  6. 一个很奇怪的问题,程序没有改动加密参数应该也没有变化.但是两次的加密结果却不一致.md5加密问题

    从图上我们看出20160803的加密结果是AAEBA9C578EA522215EAE76AFCAF250.时间是9.4分 现在我们再看这个同样的加密地址与时间结果却是另一种 31672B16..... ...

  7. C#生成图片缩略图(2种思路)

    前言:在日常图片浏览中,如果图片过多,只有一张张的打开图片才能知道图片的内容,显然这样浏览起来非常不便.Windows系统在浏览图片时提供了缩略图的功能,这样大大的方便了浏览者了解每张图片的内容,本实 ...

  8. 用户、角色、权限三者多对多用hibernate的一对多注解配置

    用户.角色.权限三者多对多用hibernate的一对多注解配置 //权限表@Table(name = "p")public class P { @Id @GeneratedValu ...

  9. Integer to Roman -- LeetCode 012

    Given an integer, convert it to a roman numeral. Input is guaranteed to be within the range from 1 t ...

  10. MySQL知识树-查询语句

    在日常的web应用开发过程中,一般会涉及到数据库方面的操作,其中查询又是占绝大部分的.我们不仅要会写查询,最好能系统的学习下与查询相关的知识点,这篇随笔我们就来一起看看MySQL查询知识相关的树是什么 ...