上一节:3、移植UBOOT之新建单板-时钟-SDRAM-串口
0、总体流程
修改UBOOT支持NAND启动,原来的代码在链接时加了"-pie"
选项, 使得u-boot.bin里多了"*(.rel*)", "*(.dynsym)"
,使得程序非常大,不利于从NAND启动(重定位之前的启动代码应该少于4K)
- 1、去掉 "-pie"选项
arch/arm/config.mk:75:LDFLAGS_u-boot += -pie
去掉这行 - 2、参考"毕业班第1课"的
start.S, init.c
来修改代码
把init.c
放入board/samsung/smdk2440
目录, 修改Makefile
修改CONFIG_SYS_TEXT_BASE
为0x33f80000
修改start.S - 3、修改
board_init_f
, 把relocate_code
去掉 - 4、修改链接脚本: 把
start.S, init.c, lowlevel.S
等文件放在最前面
1、去除 -pie 编译选项
使用grep “-pie” * -nR找到:
arch/arm/config.mk:75:LDFLAGS_u-boot += -pie // LDFLAGS: arm-linux-ld的参数
所以屏蔽arch/arm/config.mk
文件的"LDFLAGS_u-boot += -pie"
这行即可
2、修改之前写的 init.c文件
将以前写uboot里的init.c放入board/samsung/smdk2440目录;
并检查是否有同名函数名,若函数只在同文件使用,则添加static.并修改Makefile;
修改vim board/samsung/smdk2440/Makefile
添加init.o
;
修改include/configs/smdk2440.h
文件,将CONFIG_SYS_TEXT_BASE
宏改为0x33f80000
,也就是uboot重定位后的位置, 这里留了512K空间供给uboot重定位,修改完的代码如下所示。
/* NAND FLASH控制器 */
#define NFCONF (*((volatile unsigned long *)0x4E000000))
#define NFCONT (*((volatile unsigned long *)0x4E000004))
#define NFCMMD (*((volatile unsigned char *)0x4E000008))
#define NFADDR (*((volatile unsigned char *)0x4E00000C))
#define NFDATA (*((volatile unsigned char *)0x4E000010))
#define NFSTAT (*((volatile unsigned char *)0x4E000020))
/* GPIO */
#define GPHCON (*(volatile unsigned long *)0x56000070)
#define GPHUP (*(volatile unsigned long *)0x56000078)
/* UART registers*/
#define ULCON0 (*(volatile unsigned long *)0x50000000)
#define UCON0 (*(volatile unsigned long *)0x50000004)
#define UFCON0 (*(volatile unsigned long *)0x50000008)
#define UMCON0 (*(volatile unsigned long *)0x5000000c)
#define UTRSTAT0 (*(volatile unsigned long *)0x50000010)
#define UTXH0 (*(volatile unsigned char *)0x50000020)
#define URXH0 (*(volatile unsigned char *)0x50000024)
#define UBRDIV0 (*(volatile unsigned long *)0x50000028)
#define TXD0READY (1<<2)
void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len);
static int isBootFromNorFlash(void)
{
volatile int *p = (volatile int *)0;
int val;
val = *p;
*p = 0x12345678;
if (*p == 0x12345678)
{
/* 写成功, 是nand启动 */
*p = val;
return 0;
}
else
{
/* NOR不能像内存一样写 */
return 1;
}
}
void copy_code_to_sdram(unsigned char *src, unsigned char *dest, unsigned int len)
{
int i = 0;
/* 如果是NOR启动 */
if (isBootFromNorFlash())
{
while (i < len)
{
dest[i] = src[i];
i++;
}
}
else
{
//nand_init();
nand_read_ll((unsigned int)src, dest, len);
}
}
void clear_bss(void)
{
extern int __bss_start, __bss_end__;
int *p = &__bss_start;
for (; p < &__bss_end__; p++)
*p = 0;
}
void nand_init_ll(void)
{
#define TACLS 0
#define TWRPH0 1
#define TWRPH1 0
/* 设置时序 */
NFCONF = (TACLS<<12)|(TWRPH0<<8)|(TWRPH1<<4);
/* 使能NAND Flash控制器, 初始化ECC, 禁止片选 */
NFCONT = (1<<4)|(1<<1)|(1<<0);
}
static void nand_select(void)
{
NFCONT &= ~(1<<1);
}
static void nand_deselect(void)
{
NFCONT |= (1<<1);
}
static void nand_cmd(unsigned char cmd)
{
volatile int i;
NFCMMD = cmd;
for (i = 0; i < 10; i++);
}
static void nand_addr(unsigned int addr)
{
unsigned int col = addr % 2048;
unsigned int page = addr / 2048;
volatile int i;
NFADDR = col & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (col >> 8) & 0xff;
for (i = 0; i < 10; i++);
NFADDR = page & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (page >> 8) & 0xff;
for (i = 0; i < 10; i++);
NFADDR = (page >> 16) & 0xff;
for (i = 0; i < 10; i++);
}
static void nand_wait_ready(void)
{
while (!(NFSTAT & 1));
}
static unsigned char nand_data(void)
{
return NFDATA;
}
void nand_read_ll(unsigned int addr, unsigned char *buf, unsigned int len)
{
int col = addr % 2048;
int i = 0;
/* 1. 选中 */
nand_select();
while (i < len)
{
/* 2. 发出读命令00h */
nand_cmd(0x00);
/* 3. 发出地址(分5步发出) */
nand_addr(addr);
/* 4. 发出读命令30h */
nand_cmd(0x30);
/* 5. 判断状态 */
nand_wait_ready();
/* 6. 读数据 */
for (; (col < 2048) && (i < len); col++)
{
buf[i] = nand_data();
i++;
addr++;
}
col = 0;
}
/* 7. 取消选中 */
nand_deselect();
}
3、修改start.S的重定位部分
修改arch/arm/cpu/arm920t/start.S
,更改重定位代码,由于nand启动时2440未初始化之前只有前4K可读写,所以将重定位代码放在start.S的cpu_init_crit
(初始化SDRAM)段后面,修改后代码如下:
#ifndef CONFIG_SKIP_LOWLEVEL_INIT
bl cpu_init_crit
#endif
//添加以下代码。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
//设置栈
ldr sp, =(CONFIG_SYS_INIT_SP_ADDR) //等于0x30000f80
bic sp, sp, #7 /* 8-byte alignment for ABI compliance */
//初始化nand flash
bl nand_init_ll
/* 重定位 */
mov r0, #0 //r0->src
//ldr r1, =_start
ldr r1,_TEXT_BASE //链接地址 _TEXT_BASE : 0x33f80000 0x34000000-0x33f80000=512k uboot 512k足以
ldr r2,_bss_start_ofs // _bss_start_ofs: __bss_start - _start (有效代码大小)
bl copy_code_to_sdram
bl clear_bss //清除bss段(参考自制uboot章节)
ldr pc,=call_board_init_f //绝对跳转,跳到SDRAM上执行
//添加以上代码。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
call_board_init_f:
ldr r0,=0x00000000
bl board_init_f
上面的_TEXT_BASE
,在start.S靠前处定义:
由于它位于靠前处,保证了_TEXT_BASE
存在前4k
空间里,若直接使用ldr r1,=CONFIG_SYS_TEXT_BASE
,编译器可能会将这个宏定义放在SDRAM上,则会出错。
重定位写在前面了,所以我们还要删除start.S
后面的u-boot-2012.04.01\arch\arm\lib\board.c
中的 relocate_code
重定位段,清除BSS段。同时在relocate_code(addr_sp, id, addr);
后面增加return (unsigned int) id;
,修改函数为unsigned int board_init_f(ulong bootflag)
。
同时注释掉board.c中如下的内容,固定addr的值。
删除start.s中原有的重定位代码,删除部分如下
/*
* void relocate_code (addr_sp, gd, addr_moni)
*
* This "function" does not return, instead it continues in RAM
* after relocating the monitor code.
*
*/
.globl relocate_code
relocate_code:
mov r4, r0 /* save addr_sp */
mov r5, r1 /* save addr of gd */
mov r6, r2 /* save addr of destination */
/* Set up the stack */
stack_setup:
mov sp, r4
adr r0, _start
cmp r0, r6
beq clear_bss /* skip relocation */
mov r1, r6 /* r1 <- scratch for copy_loop */
ldr r3, _bss_start_ofs
add r2, r0, r3 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r9-r10} /* copy from source address [r0] */
stmia r1!, {r9-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end address [r2] */
blo copy_loop
#ifndef CONFIG_SPL_BUILD
/*
* fix .rel.dyn relocations
*/
ldr r0, _TEXT_BASE /* r0 <- Text base */
sub r9, r6, r0 /* r9 <- relocation offset */
ldr r10, _dynsym_start_ofs /* r10 <- sym table ofs */
add r10, r10, r0 /* r10 <- sym table in FLASH */
ldr r2, _rel_dyn_start_ofs /* r2 <- rel dyn start ofs */
add r2, r2, r0 /* r2 <- rel dyn start in FLASH */
ldr r3, _rel_dyn_end_ofs /* r3 <- rel dyn end ofs */
add r3, r3, r0 /* r3 <- rel dyn end in FLASH */
fixloop:
ldr r0, [r2] /* r0 <- location to fix up, IN FLASH! */
add r0, r0, r9 /* r0 <- location to fix up in RAM */
ldr r1, [r2, #4]
and r7, r1, #0xff
cmp r7, #23 /* relative fixup? */
beq fixrel
cmp r7, #2 /* absolute fixup? */
beq fixabs
/* ignore unknown type of fixup */
b fixnext
fixabs:
/* absolute fix: set location to (offset) symbol value */
mov r1, r1, LSR #4 /* r1 <- symbol index in .dynsym */
add r1, r10, r1 /* r1 <- address of symbol in table */
ldr r1, [r1, #4] /* r1 <- symbol value */
add r1, r1, r9 /* r1 <- relocated sym addr */
b fixnext
fixrel:
/* relative fix: increase location by offset */
ldr r1, [r0]
add r1, r1, r9
fixnext:
str r1, [r0]
add r2, r2, #8 /* each rel.dyn entry is 8 bytes */
cmp r2, r3
blo fixloop
#endif
clear_bss:
#ifndef CONFIG_SPL_BUILD
ldr r0, _bss_start_ofs
ldr r1, _bss_end_ofs
mov r4, r6 /* reloc addr */
add r0, r0, r4
add r1, r1, r4
mov r2, #0x00000000 /* clear */
clbss_l:str r2, [r0] /* clear loop... */
add r0, r0, #4
cmp r0, r1
bne clbss_l
bl coloured_LED_init
bl red_led_on
#endif
start.s增加第二阶段启动代码
call_board_init_f:
ldr r0,=0x00000000
bl board_init_f
/*unsigned int id 的值存在r0中,正好给board_init_r使用*/
ldr r1, =_TEXT_BASE
/*调用第二阶段代码*/
bl board_init_r
4、修改链接脚本文件u-boot.lds
把start.S, init.c
(实现重定位), lowlevel.S
(实现初始化SDRAM)等文件放在最前面。
rm u-boot.lds
vim arch/arm/cpu/u-boot.lds
添加以下字段:
. = ALIGN(4);
.text :
{
__image_copy_start = .;
CPUDIR/start.o (.text) //CPUDIR为arch/arm/cpu/arm920t目录
board/samsung/smdk2440/libsmdk2440.o (.text)
*(.text)
}
libsmdk2440.o
是将smdk2440
单板目录下的所有*.c,*S
文件编译后,连接成一个库文件。
5、其他修改
报错:
board.c:259: error: conflicting types for 'board_init_f'
/work/system/u-boot-2012.04.01/include/common.h:276: error: previous declaration of 'board_init_f' was here
/work/system/u-boot-2012.04.01/config.mk:312: recipe for target 'board.o' failed
根据指示修改u-boot-2012.04.01/include/common.h 276行
如下
报错:
board/samsung/smdk2440/libsmdk2440.o: In function `clear_bss':
/work/system/u-boot-2012.04.01/board/samsung/smdk2440/init.c:77: undefined reference to `__bss_end_'
Makefile:472: recipe for target 'u-boot' failed
根据指示修改u-boot-2012.04.01/board/samsung/smdk2440/init.c:77行
如下,其中__bss_end_
修改为__bss_end__
。
6、重新修改链接地址
我们指定了 CONFIG_SYS_TEXT_BASE 0x33f80000
,所以我们的uboot不能超过512k,0x33f80000这个是不包括bss段的全局变量的。查看start.s文件。
在反汇编中搜索_bss_end_ofs
,00094b40
为整个代码段的大小(包括了bss段),转换为10进制609088
,已经大于了512k
,所以重新修改CONFIG_SYS_TEXT_BASE 0x33f00000
。预留uboot空间为0x34000000-0x33f00000 = 1M
修改:smdk2440.h (u-boot-2012_project\u-boot-2012.04.01\include\configs) 42行
:
然后通过旧的uboot,将新的uboot烧写到nand中:
usb 1 30000000 //先下载到SDRAM上
nand erase 0 0x80000 //擦除512kb,必须大于新的uboot
nand write 30000000 0 0x80000 //将SDRAM上的新uboot写入nand
查看u-boot.lds
烧写后,如下图所示:
nand启动便实现完成了,上面的Flash: *** failed ***
是属于uboot第二阶段函数board_init_r()
里的代码,表示不支持nor flash
,不能实现读、
写、擦除等命令。