Chinaunix首页 | 论坛 | 博客
  • 博客访问: 9152535
  • 博文数量: 1727
  • 博客积分: 12961
  • 博客等级: 上将
  • 技术积分: 19860
  • 用 户 组: 普通用户
  • 注册时间: 2009-01-09 11:25
个人简介

偷得浮生半桶水(半日闲), 好记性不如抄下来(烂笔头). 信息爆炸的时代, 学习是一项持续的工作.

文章分类

全部博文(1727)

文章存档

2024年(3)

2023年(26)

2022年(112)

2021年(217)

2020年(157)

2019年(192)

2018年(81)

2017年(78)

2016年(70)

2015年(52)

2014年(40)

2013年(51)

2012年(85)

2011年(45)

2010年(231)

2009年(287)

分类: LINUX

2009-02-06 15:37:28

start_armboot浅析

start_armboot浅析ARM920t架构的CPU在完成基本的初始化后(ARM汇编代码),就进入它的C语言代码,而C语言代码的入口就是start_armboot, start_armbootlib_arm/board.c中。start_armboot将完成以下工作。

1.全局数据结构的初始化比如gd_t结构的初始化:

251 gd = (gd_t*)(_armboot_start – CFG_MALLOC_LEN – sizeof(gd_t));

_armboot_startu-bootRAM中的开始地址(对于u-boot最终搬移到RAM中运行的情况),CFG_MALLOC_LENinclude/configs/.h中定义。


bd_t结构的初始化:

272 gd->bd = (bd_t*)((char*)gd-sizeof(bd_t));

u-bootbd_t结构紧接着gd_t结构存放。


内存分配的初始化

316 mem_malloc_init(_armboot_start-CFG_MALLOC_LEN);

经过以上的初始化后,u-boot在内存中的布局为(在底端为低地址)

-----------------------------

BSS

-----------------------------

U-BOOT TEXT/DATA

-----------------------------

CFG_MALLOC_LEN

-----------------------------

gd_t

-----------------------------

bd_t

-----------------------------

STACK

-----------------------------

2.调用通用初始化函数for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {

if ((*init_fnc_ptr)() != 0) {

hang ();

}

}

init_sequence[]init_fnc_t函数指针数组,这个数组包含了众多初始化函数,比如cpu_initboard_init等。


3.初始化具体设备这一部分包括对FlashLCD,网络的初始化等,例如

318 #if (CONFIG_COMMANDS & CFG_CMD_NAND)

puts ("NAND: ");

nand_init(); /* go init the NAND */

#endif


367 devices_init();


386 #ifdef CONFIG_DRIVER_CS8900

cs8900_get_enetaddr (gd->bd->bi_enetaddr);

#endif

4.初始化环境变量环境变量在通用初始化函数里面,已经初始化一次(env_init),这里调用env_relocate对环境变量进行重新定位。在我的另一篇文章”U-BOOT ENV 实现”中有对环境变量实现的讨论。


5.进入主循环当然start_armboot除了以上工作外,还完成其它的初始化工作,具体参考lib_arm/board.c,在一切准备就绪之后,就进入u-boot的主循环:

416 for (;;) {

main_loop ();

}

main_loop的代码比较长,基本是就是执行用户的输入命令。


开发板上电后,执行U-Boot的第一条指令,然后顺序执行U-Boot启动函数。函数调用顺序如图6.3所示。
看一下 board/smsk2410/u-boot.lds这个链接脚本,可以知道目标程序的各部分链接顺序。第一个要链接的是cpu/arm920t /start.o,那么U-Boot的入口指令一定位于这个程序中。下面详细分析一下程序跳转和函数的调用关系以及函数实现。
1
cpu/arm920t/start.S这个汇编程序是U-Boot的入口程序,开头就是复位向量的代码。

6.3 U-Boot启动代码流程图


_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 //
中断向量

/* the actual reset code */
reset: //
复位启动子程序
/*
设置CPUSVC32模式 */
mrs r0,cpsr
bic r0,r0,#0x1f
orr r0,r0,#0xd3
msr cpsr,r0
/*
关闭看门狗 */

/*
这些初始化代码在系统重起的时候执行,运行时热复位从RAM中启动不执行 */
#ifdef CONFIG_INIT_CRITICAL
bl cpu_init_crit
#endif

relocate: /*
U-Boot重新定位到RAM */
adr r0, _start /* r0
是代码的当前位置 */
ldr r1, _TEXT_BASE /*
测试判断是从Flash启动,还是RAM */
cmp r0, r1 /*
比较r0r1,调试的时候不要执行重定位 */
beq stack_setup /*
如果r0等于r1,跳过重定位代码 */
/*
准备重新定位代码 */
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2
得到armboot的大小 */
add r2, r0, r2 /* r2
得到要复制代码的末尾地址 */
copy_loop: /*
重新定位代码 */
ldmia r0!, {r3-r10} /*
从源地址[r0]复制 */
stmia r1!, {r3-r10} /*
复制到目的地址[r1] */
cmp r0, r2 /*
复制数据块直到源数据末尾地址[r2] */
ble copy_loop

/*
初始化堆栈等 */
stack_setup:
ldr r0, _TEXT_BASE /*
上面是128 KiB重定位的u-boot */
sub r0, r0, #CFG_MALLOC_LEN /*
向下是内存分配空间 */
sub r0, r0, #CFG_GBL_DATA_SIZE /*
然后是bdinfo结构体地址空间 */
#ifdef CONFIG_USE_IRQ
sub r0, r0, #(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub sp, r0, #12 /*
abort-stack预留3个字 */
clear_bss:
ldr r0, _bss_start /*
找到bss段起始地址 */
ldr r1, _bss_end /* bss
段末尾地址 */
mov r2, #0x00000000 /*
清零 */
clbss_l:str r2, [r0] /* bss
段地址空间清零循环... */
add r0, r0, #4
cmp r0, r1
bne clbss_l
/*
跳转到start_armboot函数入口,_start_armboot字保存函数入口指针 */
ldr pc, _start_armboot
_start_armboot: .word start_armboot //start_armboot
函数在lib_arm/board.c中实现
/*
关键的初始化子程序 */

cpu_init_crit:
…… //
初始化CACHE,关闭MMU等操作指令
/*
初始化RAM时钟。
*
因为内存时钟是依赖开发板硬件的,所以在board的相应目录下可以找到memsetup.S文件。
*/
mov ip, lr
bl memsetup//memsetup
子程序在board/smdk2410/memsetup.S中实现
mov lr, ip
mov pc, lr

2
lib_arm/board.cstart_armbootU-Boot执行的第一个C语言函数,完成系统初始化工作,进入主循环,处理用户输入的命令。


void start_armboot (void)
{
DECLARE_GLOBAL_DATA_PTR;
ulong size;
init_fnc_t **init_fnc_ptr;
char *s;
/* Pointer is writable since we allocated a register for it */
gd = (gd_t*)(_armboot_start - CFG_MALLOC_LEN - sizeof(gd_t));
/* compiler optimization barrier needed for GCC >= 3.4 */
__asm__ __volatile__("": : :"memory");
memset ((void*)gd, 0, sizeof (gd_t));
gd->bd = (bd_t*)((char*)gd - sizeof(bd_t));
memset (gd->bd, 0, sizeof (bd_t));
monitor_flash_len = _bss_start - _armboot_start;
/*
顺序执行init_sequence数组中的初始化函数 */
for (init_fnc_ptr = init_sequence; *init_fnc_ptr; ++init_fnc_ptr) {
if ((*init_fnc_ptr)() != 0) {
hang ();
}
}
/*
配置可用的Flash */
size = flash_init ();
display_flash_config (size);
/* _armboot_start
u-boot.lds链接脚本中定义 */
mem_malloc_init (_armboot_start - CFG_MALLOC_LEN);
/*
配置环境变量,重新定位 */
env_relocate ();
/*
从环境变量中获取IP地址 */
gd->bd->bi_ip_addr = getenv_IPaddr ("ipaddr");
/*
以太网接口MAC 地址 */
……
devices_init (); /*
获取列表中的设备 */
jumptable_init ();
console_init_r (); /*
完整地初始化控制台设备 */
enable_interrupts (); /*
使能例外处理 */
/*
通过环境变量初始化 */
if ((s = getenv ("loadaddr")) != NULL) {
load_addr = simple_strtoul (s, NULL, 16);
}
/* main_loop()
总是试图自动启动,循环不断执行 */
for (;;) {
main_loop (); /*
主循环函数处理执行用户命令 -- common/main.c */
}
/* NOTREACHED - no way out of command loop except booting */
}

3
init_sequence[]init_sequence[]数组保存着基本的初始化函数指针。这些函数名称和实现的程序文件在下列注释中。

init_fnc_t *init_sequence[] = {
cpu_init, /*
基本的处理器相关配置 -- cpu/arm920t/cpu.c */
board_init, /*
基本的板级相关配置 -- board/smdk2410/smdk2410.c */
interrupt_init, /*
初始化例外处理 -- cpu/arm920t/s3c24x0/interrupt.c */
env_init, /*
初始化环境变量 -- common/cmd_flash.c */
init_baudrate, /*
初始化波特率设置 -- lib_arm/board.c */
serial_init, /*
串口通讯设置 -- cpu/arm920t/s3c24x0/serial.c */
console_init_f, /*
控制台初始化阶段1 -- common/console.c */
display_banner, /*
打印u-boot信息 -- lib_arm/board.c */
dram_init, /*
配置可用的RAM -- board/smdk2410/smdk2410.c */
display_dram_config, /*
显示RAM的配置大小 -- lib_arm/board.c */
NULL,
};

阅读(1306) | 评论(0) | 转发(0) |
0

上一篇:uboot分析

下一篇:系统移植的部分文档

给主人留下些什么吧!~~