为阅读BLOB首先阅读了杜云海的ARM学习报告,对在ADS调试时生成的AXF和BIN文件以及GNU编译生成的ELF文件和可执行文件有了一些了解。
对于ARM学习报告1关键要理解加载域和运行时域的概念,加载域即下载到FLASH中的BIN文件的地址分配,运行时域就是在程序运行时把BIN文件的各个段拷贝到RAM中的地址分配情况。对于学习报告中给的启动代码,在ARM启动时,flash地址为0-2M,RAM地址为2M-18M,启动时从FLASH中运行BOOT程序,在运行BOOT程序的过程中先将BOOT程序本身拷贝到2M后的地址空间(以地址0x200000开始的地址空间),然后将RAM的地址映射为0-16M的,将FLASH地址映射为16M-18M。即可实现代码的连接。
对于ARM学习报告3关键要理解SECTION的概念,ELF+.ld文件通过LD工具重定位连接就会生成可执行文件,要能读懂LD文件,其中的地址是指的可执行文件在内存中运行时相应的段所处的位置。即运行时域的地址分配情况。
对BLOB的阅读:
/* First, mask **ALL** interrupts */
/* switch CPU to correct speed */
/* init LED */
/* setup memory */
对于SA1100来说是对地址为0xa000 0000开始的几个寄存器进行配置MDCNFG、MDCAS0、MDCAS1、MDCAS2、MCS0
/* check the first 1MB of BLOB_START in increments of 4k */
/* relocate the second stage loader */
relocate:
adr r0, _start
add r2, r0, #(64 * 1024) /* blob maximum size is 64kB */
add r0, r0, #0x400 /* skip first 1024 bytes */
ldr r1, BLOB_START
/* r0 = source address
* r1 = target address
* r2 = source end address
*/
source address为FLASH的0x00000000位置,target address为BLOB_START
从BLOB_START: .word BLOB_ABS_BASE_ADDR可以看出BLOB_ABS_BASE_ADDR和BLOB_START是相等的。
而BLOB_ABS_BASE_ADDR在blob-2.0.5-pre2\include\blob\arch下定义,和具体的芯片有关。
/src/blob/rest-ld-script.in文件为
OUTPUT_FORMAT("elf32-littlearm", "elf32-littlearm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_trampoline)
SECTIONS
{
. = BLOB_ABS_BASE_ADDR;
. = ALIGN(4);
.text : {
__text_start = .;
*(.text)
__text_end = .;
}
……
}
BLOB_ABS_BASE_ADDR为SECTIONS段在内存中映射的地址,可以看到以_trampoline开始的STAGE2 的代码在内存中的映射确实是从BLOB_ABS_BASE_ADDR开始的,它和relocate的代码是一致的
变量BLOB_START就是blob复制到内存中的起始地址。开始看这段代码,其中令人不解的地方就是常数0x400,为什么_start地址加上0x400就是第二阶段blob-reset的代码呢?这里稍做重复:dd if=blob-rest of=$@ bs=1k seek=1(./src/blob/Makefile.am)这一行命令中seek=1 表示从第1 个数据块后开始写输出数据。这一行的作用实际是将blob-rest 文件写入到blob 文件的第1024 字节开始处,也就是0x400的地方。
/* blob is copied to ram, so jump to it */
下一步跳到BLOB_ABS_BASE_ADDR处,从ENTRY(_trampoline)看出BLOB_ABS_BASE_ADDR处是以_trampoline为入口的,trampoline.c对堆栈进行了清空,然后跳到main函数去执行。
Main()函数解读
init_subsystems()
首先执行函数init_subsystems(),按照优先级从小到大调用各个初始化函数。call_funcs是调用初始化函数的函数。具体的初始化函数如下表所列:
src/lib/command.c:78:__initlist(init_commands, INIT_LEVEL_OTHER_STUFF);
src/blob/flash.c:165:__initlist(init_flash, INIT_LEVEL_OTHER_STUFF + 1);
src/blob/initcalls.c:49:__initlist(serial_default_init, INIT_LEVEL_INITIAL_HARDWARE);
src/blob/initcalls.c:50:__initlist(enable_icache, INIT_LEVEL_INITIAL_HARDWARE);
src/blob/initcalls.c:51:__initlist(led_init, INIT_LEVEL_INITIAL_HARDWARE);
src/blob/initcalls.c:52:__initlist(TimerInit, INIT_LEVEL_OTHER_HARDWARE);
src/blob/assabet.c:58:__initlist(init_assabet_flash_driver, INIT_LEVEL_DRIVER_selectION);
src/blob/assabet.c:78:__initlist(assabet_init_hardware, INIT_LEVEL_DRIVER_selectION);
src/blob/brutus.c:55:__initlist(init_brutus_flash_driver, INIT_LEVEL_DRIVER_selectION);
src/blob/brutus.c:66:__initlist(brutus_init_hardware, INIT_LEVEL_DRIVER_selectION);
src/blob/badge4.c:65:__initlist(init_flash_driver, INIT_LEVEL_DRIVER_selectION);
src/blob/badge4.c:82:__initlist(init_hardware, INIT_LEVEL_DRIVER_selectION);
src/blob/clart.c:58:__initlist(init_clart_flash_driver, INIT_LEVEL_DRIVER_selectION);
src/blob/clart.c:69:__initlist(clart_init_hardware, INIT_LEVEL_DRIVER_selectION);
src/blob/h3600.c:118:__initlist(init_h3600_flash_driver, INIT_LEVEL_DRIVER_selectION);
src/blob/h3600.c:133:__initlist(h3600_init_hardware, INIT_LEVEL_DRIVER_selectION);
src/blob/idr.c:52:__initlist(init_idr_flash_driver, INIT_LEVEL_DRIVER_selectION);
src/blob/idr.c:61:__initlist(idr_init_hardware, INIT_LEVEL_DRIVER_selectION);
src/blob/jornada720.c:78:__initlist(init_flash_driver, INIT_LEVEL_DRIVER_selectION);
src/blob/jornada720.c:103:__initlist(init_hardware, INIT_LEVEL_DRIVER_selectION);
src/blob/lart.c:67:__initlist(init_lart_flash_driver, INIT_LEVEL_DRIVER_selectION);
src/blob/lart.c:78:__initlist(lart_init_hardware, INIT_LEVEL_DRIVER_selectION);
src/blob/nesa.c:62:__initlist(init_nesa_flash_driver, INIT_LEVEL_DRIVER_selectION);
src/blob/nesa.c:73:__initlist(nesa_init_hardware, INIT_LEVEL_DRIVER_selectION);
src/blob/pleb.c:48:__initlist(lock_pleb_led, INIT_LEVEL_INITIAL_HARDWARE + 1);
src/blob/pleb.c:72:__initlist(init_pleb_flash_driver, INIT_LEVEL_DRIVER_selectION);
src/blob/pleb.c:83:__initlist(pleb_init_hardware, INIT_LEVEL_DRIVER_selectION);
src/blob/shannon.c:61:__initlist(init_shannon_flash_driver, INIT_LEVEL_DRIVER_selectION);
src/blob/shannon.c:72:__initlist(shannon_init_hardware, INIT_LEVEL_DRIVER_selectION);
src/blob/system3.c:99:__initlist(init_system3_flash_driver, INIT_LEVEL_DRIVER_selectION);
src/blob/system3.c:110:__initlist(system3_init_hardware, INIT_LEVEL_DRIVER_selectION);
参数(initlist_t *)&__initlist_start和参数(initlist_t *)&__initlist_end,分别为内存中initlist段的开始地址和结束地址。rest-ld-script.in中有如下定义:
. = ALIGN(4);
.initlist : {
// 在文件include/blob/init.h中第43行有:
//#define __init __attribute__((unused, __section__(".initlist")))
__initlist_start = .;
*(.initlist)
__initlist_end = .;
在这个段中存放着若干个下面这种结构体:
typedef void(*initfunc_t)(void);
typedef struct {
u32 magic;
initfunc_t callback;
int level;
} initlist_t;
call_funcs()函数的作用就是在这若干个结构体中找出需要执行的函数运行。
上面列表中的函数都是call_funcs()可能执行的,但具体会做哪几个,由编译时的配置决定。
一般执行最前面的(公共的)6个和后面两个和体系结构相关的:***_flash_driver、
***_init_hardware。移植BLOB时只需要将要执行的那些初始化函数编译进initlist段即可。
下面分析前面六个初始化函数:
commands(void)函数负责初始化全局变量commandlist_t *commands,将内存commandlist段中的所有commandlist_t结构体组成一个以*commands为头的链表。
init_flash
发表于 @ 2007年04月18日 18:05:00|评论(loading...)|编辑