UBoot支持双启动(Nor and Nand)及环境变量保存的实现
2011-09-20 11:49
489 查看
本文所要讲述的是如何使UBoot只编译一次就能支持从Nor Flash和Nand Flash启动,并且在保存环境变量时能够保存在其所在的Flash中.
注意,本文针对的为S3C2410芯片,其他芯片原理相同,可在适当修改代码后进行移植.
我们知道UBoot源码本身直接支持从Nor Flash启动,这是Nor Flash的可执行特性决定的.而针对Nand Flash,则涉及到前4K数据的问题.S3C2410的Nand Flash控制器有一个特殊的功能,就是能在上电后自动将Nand Flash中的前4K数据搬移到4K内部的RAM中,并把0x00000000设置为内部RAM的起始地址,然后CPU从内部RAM的0x000000位置启动,该过程由硬件自动完成.
所以,要使UBoot支持从Nand Flash启动,必须在其前4K代码执行过程中完成将自身复制到RAM中的工作.
但是,我们现在需要让UBoot支持双启动,现在的问题就是该如何判断UBoot是在Nor Flash还是在Nand Flash中呢?呵呵,在S3C2410(S3C2440)中,这个可以通过BWSCON(BUS WIDTH & WAIT CONTROL REGISTER)控制寄存器[2:1]的值进行判断,如果为00则表示是从Nand Flash启动的.因此,我们可以直接通过如下代码进行判断并在BWSCON[2:1]为00时跳转到UBoot复制自身(copy_myself)的代码处:
下面讲解具体的修改过程(以u-boot-2010.09为例).
首先,修改include/configs/smdk2410.h文件,添加如下宏定义:
nand_read_ll为新增加的Nand Flash读取方法,在board/samsung/smdk2410目录下新建文件nand_read.c,并添加如下代码:
COBJS := smdk2410.o flash.o nand_read.o
为了保证nand_read_ll方法能够被编译到UBoot代码的前4K中,以确保代码的正确执行,还需修改链接文件arch/arm/cpu/arm920t/u-boot.lds,如下:
在UBoot中,环境变量操作的命令在文件common/cmd_nvedit.c中定义和实现,而针对不同Flash的操作,如env_init,saveenv和env_relocate_spec,则在common/env_flash.c和common/env_nand.c中进行定义和实现.
为了双启动的支持,并且能够支持单启动(Nor或Nand启动),我们将上面三个方法整合到了cmd_nvedit.c中,并将env_flash.c和env_nand.c中的这三个方法添加上nor和nand前缀,用于区分调用,并防止同时编译时的重定义.
然后,将env_flash.c和env_nand.c中定义的env_name_spec和env_ptr两个变量放到cmd_nvedit.c中进行定义,这两个文件直接使用extern关键字引用这两个变量.由于函数env_get_char_spec在env_flash.c和env_nand.c中都进行了定义,所以也和env_init一样转到cmd_nvedit.c中进行定义.
接着,就是定义启动标志boot_flash,并设置初值为1.
具体修改如下:
在common/cmd_nvedit.c中增加如下代码:
好了,现在编译UBoot:
参考资料:
1. <<如何让U-boot实现Nand/Nor 双启动>>
2. <<Nand Flash 和 Nor Flash 双启动方法探究>> 关于S3C2440的
3. <<成功在skyeye 上实现U-Boot 的Nand命令并从Nand中启动Linux>>
4. <<从Nand Flash启动U-BOOT的基本原理>>
5. <<关于u-boot同时支持nand启动和Nor启动环境变量的保存位置>> 标志修改的代码放置位置好像不行,我这没有成功
注意,本文针对的为S3C2410芯片,其他芯片原理相同,可在适当修改代码后进行移植.
我们知道UBoot源码本身直接支持从Nor Flash启动,这是Nor Flash的可执行特性决定的.而针对Nand Flash,则涉及到前4K数据的问题.S3C2410的Nand Flash控制器有一个特殊的功能,就是能在上电后自动将Nand Flash中的前4K数据搬移到4K内部的RAM中,并把0x00000000设置为内部RAM的起始地址,然后CPU从内部RAM的0x000000位置启动,该过程由硬件自动完成.
所以,要使UBoot支持从Nand Flash启动,必须在其前4K代码执行过程中完成将自身复制到RAM中的工作.
但是,我们现在需要让UBoot支持双启动,现在的问题就是该如何判断UBoot是在Nor Flash还是在Nand Flash中呢?呵呵,在S3C2410(S3C2440)中,这个可以通过BWSCON(BUS WIDTH & WAIT CONTROL REGISTER)控制寄存器[2:1]的值进行判断,如果为00则表示是从Nand Flash启动的.因此,我们可以直接通过如下代码进行判断并在BWSCON[2:1]为00时跳转到UBoot复制自身(copy_myself)的代码处:
#define BWSCON 0x48000000 ldr r0, =BWSCON ldr r0, [r0] ands r0, r0, #6 @ 判断BWSCON[2:1]是否为00,如果是,则跳转到copy_myself beq copy_myself好了,双启动问题算是解决了,但是新的问题又来了,这个环境变量又应该如何保存呢?是都保存到Nor Flash还是Nand Flash呢?当然,最好的方式还是保存到各自所在的Flash中.这个可以设置一个标志,在进入Nand Flash启动代码时设置该标志,表示从Nand Flash启动,然后,在保存环境变量时通过该标志的值判断是调用Nor Flash的保存方法还是Nand Flash的保存方法.
下面讲解具体的修改过程(以u-boot-2010.09为例).
首先,修改include/configs/smdk2410.h文件,添加如下宏定义:
#define CONFIG_CMD_ENV // 开启环境变量操作命令 #define CONFIG_CMD_NAND // 开启Nand Flash操作命令 #ifdef CONFIG_CMD_NAND # define CONFIG_SYS_NAND_BASE 0x4E000000 //Nand配置寄存器基地址 # define CONFIG_SYS_MAX_NAND_DEVICE 1 # define CONFIG_MTD_NAND_VERIFY_WRITE 1 # define CONFIG_NAND_S3C2410 # define STACK_BASE 0x33f00000 /* 堆栈基址 */ # define STACK_SIZE 0x8000 /* 堆栈大小 */ #endif /*--------------------------------------------------------------------- * Boot From Nor or Nand Flash or both */ #define CONFIG_NOR_BOOT #define CONFIG_NAND_BOOT #ifdef CONFIG_NOR_BOOT # define PHYS_FLASH_1 0x00000000 /* Flash Bank #1 */ # define CONFIG_SYS_FLASH_BASE PHYS_FLASH_1 # define CONFIG_AMD_LV160B /* 使用AM29LV160DB Nor Flash芯片 */ # define CONFIG_SYS_MAX_FLASH_BANKS 1 /* max number of memory banks */ /* timeout values are in ticks */ # define CONFIG_SYS_FLASH_ERASE_TOUT (5*CONFIG_SYS_HZ) /* Timeout for Flash Erase */ # define CONFIG_SYS_FLASH_WRITE_TOUT (5*CONFIG_SYS_HZ) /* Timeout for Flash Write */ # define CONFIG_ENV_IS_IN_FLASH /* 将环境变量保存到Nor Flash中*/ #endif #ifdef CONFIG_NAND_BOOT # define UBOOT_RAM_BASE 0x33f80000 # define NAND_CTL_BASE 0x4E000000 # define bINT_CTL(Nb) __REG(INT_CTL_BASK + (Nb)) # define oNFCONF 0x00 # define oNFCMD 0x04 # define oNFADDR 0x08 # define oNFDATA 0x0c # define oNFSTAT 0x10 # define oNFECC 0x14 # define CONFIG_UBOOT_SIZE 0x30000 # define CONFIG_ENV_IS_IN_NAND /* common/env_nand.c */ # ifndef CONFIG_NOR_BOOT # define CONFIG_SYS_NO_FLASH # undef CONFIG_CMD_FLASH # undef CONFIG_CMD_IMLS # endif #endif /*--------------------------------------------------------------------------- * Nor Flash Device */ #ifdef CONFIG_AMD_LV160B # define PHYS_FLASH_SIZE 0x00200000 /* 2MB */ # define CONFIG_SYS_MAX_FLASH_SECT (35) /* max number of sectors on one chip */ # define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x030000)/* addr of environment */ #endif /*-------------------------------------------------------------------------- * Environment Setting */ // 环境变量的大小必须为sector的整数倍,此处直接设置为0x1000, // 能够同时满足Nor Flash和Nand Flash的要求 #define CONFIG_ENV_SIZE 0x10000 #ifdef CONFIG_ENV_IS_IN_FLASH //# define CONFIG_ENV_ADDR (CONFIG_SYS_FLASH_BASE + 0x30000) #endif #ifdef CONFIG_ENV_IS_IN_NAND # define CONFIG_ENV_OFFSET CONFIG_UBOOT_SIZE /* 环境变量紧接在uboot之后 */ #endif然后,修改启动文件arch/arm/cpu/arm920t/start.S,增加Nand Flash启动代码和启动标志的设置(直接修改relocate代码段):
/* 双启动判断 */其中,boot_flash为1表示从Nor Flash启动,为0则表示从Nand Flash启动,为使该值能够正确被修改,所以将其在UBoot复制完毕后进行修改.代码中的UBOOT_RAM_BASE不要直接替换为_TEXT_BASE,虽然两者值相同,但是在运行中却有问题,我就因为使用了_TEXT_BASE,导致费了很多时间,前车之荐,请勿效仿!
#define BWSCON 0x48000000 ldr r0, =BWSCON ldr r0, [r0] ands r0, r0, #6 @ 判断BWSCON[2:1]是否为00,如果是,则跳转到copy_myself beq copy_myself
#ifdef CONFIG_NOR_BOOT
#ifndef CONFIG_SKIP_RELOCATE_UBOOT
relocate: /* relocate U-Boot to RAM */
adr r0, _start /* r0 <- current position of code */
ldr r1, _TEXT_BASE /* test if we run from flash or RAM */
cmp r0, r1 /* don't reloc during debug */
beq stack_setup
ldr r2, _armboot_start
ldr r3, _bss_start
sub r2, r3, r2 /* r2 <- size of armboot */
add r2, r0, r2 /* r2 <- source end address */
copy_loop:
ldmia r0!, {r3-r10} /* copy from source address [r0] */
stmia r1!, {r3-r10} /* copy to target address [r1] */
cmp r0, r2 /* until source end addreee [r2] */
ble copy_loop
b stack_setup /* 跳过nand启动代码 */
#endif /* CONFIG_SKIP_RELOCATE_UBOOT */
#endif /* CONFIG_NOR_BOOT */
#ifdef CONFIG_NAND_BOOT
copy_myself:
@ reset NAND
mov r1, #NAND_CTL_BASE
ldr r2, =0xf830 @ initial value
str r2, [r1, #oNFCONF]
ldr r2, [r1, #oNFCONF]
bic r2, r2, #0x800 @ enable chip
str r2, [r1, #oNFCONF]
mov r2, #0xff @ RESET command
strb r2, [r1, #oNFCMD]
mov r3, #0 @ wait
nand1:
add r3, r3, #0x1
cmp r3, #0xa
blt nand1
nand2:
ldr r2, [r1, #oNFSTAT] @ wait ready
tst r2, #0x1
beq nand2
ldr r2, [r1, #oNFCONF]
orr r2, r2, #0x800 @ disable chip
str r2, [r1, #oNFCONF]
@ get read to call C functions (for nand_read())
ldr sp, DW_STACK_START @ setup stack pointer
mov fp, #0 @ no previous frame, so fp=0
@ copy U-Boot to RAM
ldr r0, =UBOOT_RAM_BASE @ buf : first parameter of nand_read_ll()
mov r1, #0x0 @ start_addr : second parameter of nand_read_ll()
mov r2, #CONFIG_UBOOT_SIZE @ size : third parameter of nand_read_ll()
bl nand_read_ll
tst r0, #0x0
beq ok_nand_read
bad_nand_read:
loop2: b loop2 @ infinite loop
ok_nand_read:
@ set flag : 0->boot from nand;1->boot from nor
@ set flag after finishing to copy U-Boot to memory
ldr r0, =boot_flash @ defined in common/cmd_nvedit.c
mov r1, #0x0
str r1, [r0]
@ verify
mov r0, #0
ldr r1, =UBOOT_RAM_BASE @ NOTE: DON'T USE '_TEXT_BASE'
mov r2, #0x400 @ 4 bytes * 1024 = 4K-bytes
go_next:
ldr r3, [r0], #4
ldr r4, [r1], #4
teq r3, r4
bne notmatch
subs r2, r2, #4
beq stack_setup
bne go_next
notmatch:
loop3: b loop3 @ infinite loop
#endif /* CONFIG_NAND_BOOT */
.align 2
DW_STACK_START: .word STACK_BASE+STACK_SIZE-4
nand_read_ll为新增加的Nand Flash读取方法,在board/samsung/smdk2410目录下新建文件nand_read.c,并添加如下代码:
#include <config.h> #define __REGb(x) (*(volatile unsigned char *)(x)) #define __REGi(x) (*(volatile unsigned int *)(x)) #define NF_BASE 0x4e000000 #define NFCONF __REGi(NF_BASE + 0x0) #define NFCMD __REGb(NF_BASE + 0x4) #define NFADDR __REGb(NF_BASE + 0x8) #define NFDATA __REGb(NF_BASE + 0xc) #define NFSTAT __REGb(NF_BASE + 0x10) #define BUSY 1 inline void wait_idle(void) { int i; while(!(NFSTAT & BUSY)) for(i=0; i<10; i++); } #define NAND_SECTOR_SIZE 512 #define NAND_BLOCK_MASK (NAND_SECTOR_SIZE - 1) /* low level nand read function */ int nand_read_ll(unsigned char *buf, unsigned long start_addr, int size) { int i, j; if ((start_addr & NAND_BLOCK_MASK) || (size & NAND_BLOCK_MASK)) { return -1; /* invalid alignment */ } /* chip Enable */ NFCONF &= ~0x800; for(i=0; i<10; i++); for(i=start_addr; i < (start_addr + size);) { /* READ0 */ NFCMD = 0; /* Write Address */ NFADDR = i & 0xff; NFADDR = (i >> 9) & 0xff; NFADDR = (i >> 17) & 0xff; NFADDR = (i >> 25) & 0xff; wait_idle(); for(j=0; j < NAND_SECTOR_SIZE; j++, i++) { *buf = (NFDATA & 0xff); buf++; } } /* chip Disable */ NFCONF |= 0x800; /* chip disable */ return 0; }修改Makefile,使nand_read.c能够被编译进UBoot:
COBJS := smdk2410.o flash.o nand_read.o
为了保证nand_read_ll方法能够被编译到UBoot代码的前4K中,以确保代码的正确执行,还需修改链接文件arch/arm/cpu/arm920t/u-boot.lds,如下:
.text : { arch/arm/cpu/arm920t/start.o (.text) board/samsung/smdk2410/lowlevel_init.o (.text) board/samsung/smdk2410/nand_read.o (.text) *(.text) }最后,该修改代码以支持环境变量的保存了.
在UBoot中,环境变量操作的命令在文件common/cmd_nvedit.c中定义和实现,而针对不同Flash的操作,如env_init,saveenv和env_relocate_spec,则在common/env_flash.c和common/env_nand.c中进行定义和实现.
为了双启动的支持,并且能够支持单启动(Nor或Nand启动),我们将上面三个方法整合到了cmd_nvedit.c中,并将env_flash.c和env_nand.c中的这三个方法添加上nor和nand前缀,用于区分调用,并防止同时编译时的重定义.
然后,将env_flash.c和env_nand.c中定义的env_name_spec和env_ptr两个变量放到cmd_nvedit.c中进行定义,这两个文件直接使用extern关键字引用这两个变量.由于函数env_get_char_spec在env_flash.c和env_nand.c中都进行了定义,所以也和env_init一样转到cmd_nvedit.c中进行定义.
接着,就是定义启动标志boot_flash,并设置初值为1.
具体修改如下:
在common/cmd_nvedit.c中增加如下代码:
// 1:NOR FLASH启动,0:NAND FLASH启动 // boot_flash将在start.S中被修改 int boot_flash = 1; char * env_name_spec; env_t * env_ptr; extern nor_env_get_char_spec(int index); extern nand_env_get_char_spec(int index); extern int nor_env_init(void); extern int nand_env_init(void); extern int nor_saveenv(void); extern int nand_saveenv(void); extern void nor_env_relocate_spec(void); extern void nand_env_relocate_spec(void); #ifdef ENV_IS_EMBEDDED extern uchar environment[]; #endif uchar env_get_char_spec(int index) { if (boot_flash) { return nor_env_get_char_spec(index); } else { return nand_env_get_char_spec(index); } } int env_init(void) { if (boot_flash) { #ifdef ENV_IS_EMBEDDED env_ptr = (env_t *)(&environment[0]); #else env_ptr = (env_t *)CONFIG_ENV_ADDR; #endif env_name_spec = "Flash"; return nor_env_init(); } else { #if defined(ENV_IS_EMBEDDED) env_ptr = (env_t *)(&environment[0]); #elif defined(CONFIG_NAND_ENV_DST) env_ptr = (env_t *)CONFIG_NAND_ENV_DST; #else env_ptr = NULL; #endif env_name_spec = "NAND"; return nand_env_init(); } } int saveenv(void) { if (boot_flash) { return nor_saveenv(); } else { return nand_saveenv(); } } void env_relocate_spec(void) { if (boot_flash) { return nor_env_relocate_spec(); } else { return nand_env_relocate_spec(); } }在common/env_flash.c和common/env_nand.c中,去掉对env_name_spec和env_ptr的定义,改为外部引用:
extern char * env_name_spec; extern env_t *env_ptr;最后,在env_get_char_spec,env_init,saveenv和env_relocate_spec方法前分别添加前缀"nor_"和"nand_".
好了,现在编译UBoot:
make smdk2410_config && make all下载到开发板上试试吧!
参考资料:
1. <<如何让U-boot实现Nand/Nor 双启动>>
2. <<Nand Flash 和 Nor Flash 双启动方法探究>> 关于S3C2440的
3. <<成功在skyeye 上实现U-Boot 的Nand命令并从Nand中启动Linux>>
4. <<从Nand Flash启动U-BOOT的基本原理>>
5. <<关于u-boot同时支持nand启动和Nor启动环境变量的保存位置>> 标志修改的代码放置位置好像不行,我这没有成功
相关文章推荐
- 关于u-boot同时支持nand启动和Nor启动环境变量的保存位置
- 关于u-boot同时支持nand启动和Nor启动环境变量的保存位置
- 关于u-boot同时支持nand启动和Nor启动环境变量的保存位置
- 关于u-boot同时支持nand启动和Nor启动 环境变量的保存位置
- U-BOOT环境变量的获取和保存的实现分析
- 如何让U-boot实现Nand/Nor 双启动
- U-BOOT环境变量的获取和保存的实现分析
- uboot for s3c2410 nandboot 使用saveenv保存环境变量
- uboot环境变量设置好后烧写启动内核,文件系统出现的问题
- uboot环境变量实现分析
- uboot 源码分析(2)uboot 环境变量实现简析
- uboot启动参数,机器码,环境变量
- uboot移植,编译及环境变量,启动等方面---from README
- uboot 源码分析(2)uboot 环境变量实现简析
- 移植u-boot2012.04.1 -》2440 (五)支持 nand nor 两种启动方式(完结)
- uboot环境变量的实现和读取设置
- 2013.10u-boot移植之增加nand保存环境变量
- s5pv210 uboot-2012-10移植(八) 之支持SD卡保存环境变量
- norflash移植及uboot 保存环境变量实验
- window下实现tomcat不需要配置环境变量就可以直接运行startup.bat启动