完整代码见board/samsung/mini2440/nand_read.c中的nand_read_ll函数,这里给出伪代码:
int nand_read_ll(unsigned char *buf,unsigned long start_addr, int size)
{
//根据NFCONF寄存器的Bit3来区分2种NAND Flash
if(NFCONF & 0x8 )
/* Bit是1,表示是2KB/page的NAND Flash */
{
////////////////////////////////////
读取2K block 的NAND Flash
////////////////////////////////////
}
else
/* Bit是0,表示是512B/page的NAND Flash */
{
/////////////////////////////////////
读取512B block 的NAND Flash
/////////////////////////////////////
}
return 0;
}
(10)设置堆栈
/*
设置堆栈*/
stack_setup:
ldr
r0, _TEXT_BASE
/* upper 128 KiB: relocated uboot
*/
sub
r0, r0, #CONFIG_SYS_MALLOC_LEN
/* malloc area
*/
sub
r0, r0, #CONFIG_SYS_GBL_DATA_SIZE /*
跳过全局数据区
*/
#ifdef CONFIG_USE_IRQ
sub
r0, r0,#(CONFIG_STACKSIZE_IRQ+CONFIG_STACKSIZE_FIQ)
#endif
sub
sp, r0, #12
/*leave 3 words for abort-stack
*/
只要将sp指针指向一段没有被使用的内存就完成栈的设置了。根据上面的代码可以知道U-Boot内存使用情况了,如下图所示:
图2.2 U-Boot内存使用情况
(11)清除BSS段
clear_bss:
ldr
r0, _bss_start
/* BSS段开始地址,在u-boot.lds中指定*/
ldr
r1, _bss_end
/*BSS段结束地址,在u-boot.lds中指定*/
mov
r2, #0x00000000
clbss_l:str
r2, [r0]
/* 将bss段清零*/
add
r0, r0, #4
cmp
r0, r1
ble
clbss_l
初始值为0,无初始值的全局变量,静态变量将自动被放在BSS段。应该将这些变量的初始值赋为0,否则这些变量的初始值将是一个随机的值,若有些程序直接使用这些没有初始化的变量将引起未知的后果。
(12)跳转到第二阶段代码入口
ldr
pc, _start_armboot
_start_armboot:
.word
start_armboot
跳转到第二阶段代码入口start_armboot处。
1.1.2
U-Boot启动第二阶段代码分析
start_armboot函数在lib_arm/board.c中定义,是U-Boot第二阶段代码的入口。U-Boot启动第二阶段流程如下:
图 2.3 U-Boot第二阶段执行流程
在分析start_armboot函数前先来看看一些重要的数据结构:
(1)gd_t结构体
U-Boot使用了一个结构体gd_t来存储全局数据区的数据,这个结构体在include/asm-arm/global_data.h中定义如下:
typedef
struct
global_data {
bd_t
*bd;
unsignedlong
flags;
unsignedlong
baudrate;
unsignedlong
have_console;
/* serial_init() was called */
unsignedlong
env_addr;
/* Address
of Environmentstruct */
unsignedlong
env_valid;
/* Checksum of Environment valid? */
unsignedlong
fb_base;
/* base address of frame buffer */
void
**jt;
/* jump table */
} gd_t;
U-Boot使用了一个存储在寄存器中的指针gd来记录全局数据区的地址:
#define DECLARE_GLOBAL_DATA_PTR
register volatile gd_t *gd asm("r8")
DECLARE_GLOBAL_DATA_PTR定义一个gd_t全局数据结构的指针,这个指针存放在指定的寄存器r8中。这个声明也避免编译器把r8分配给其它的变量。任何想要访问全局数据区的代码,只要代码开头加入“DECLARE_GLOBAL_DATA_PTR”一行代码,然后就可以使用gd指针来访问全局数据区了。
根据U-Boot内存使用图中可以计算gd的值:
gd = TEXT_BASE -CONFIG_SYS_MALLOC_LEN - sizeof(gd_t) |