4、移植UBOOT之支持nand启动

上一节:3、移植UBOOT之新建单板-时钟-SDRAM-串口

下一节:5、移植UBOOT之支持Nor Flash

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_BASE0x33f80000
    修改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_ofs00094b40为整个代码段的大小(包括了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,不能实现读、
写、擦除等命令。

上一节:3、移植UBOOT之新建单板-时钟-SDRAM-串口

下一节:5、移植UBOOT之支持Nor Flash

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ZhangDaniel_ZD

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值