U-Boot-2010.12移植到2440
http://www.linuxidc.com/Linux/2011-02/32772.htm 【内容导航】
第1页:编译
2010年初曾经将uboot 2009.11.1移植到我们自己做的一块2440单板上,该单板具有64M SDRAM 和64M nand FLASH,网卡为DM9000。最新版本的uboot源码有较大的变化,此次计划利用几天时间将最新版本的u-boot-2010.12移植到该单板 上,在此记录移植过程及遇到的问题以备忘并供朋友参考。 移植的第一步当然是下载最新版本的uboot源码,下载地址如下: http://www.linuxidc.com/Linux/2011-07/38897.htm 进入相应路径: cd /home/bsc 解压缩: make distclean????????????? /*清除已经形成的链接,修改顶层Makefile文件必须执行*/ [root@localhost u-boot-2010.12]# make smdk2410_config awk '(NF && $1 !~ /^#/) { print $1 ": " $1 "_config; $(MAKE)" }' boards.cfg > .boards.depend Configuring for smdk2410 board... ?[root@localhost u-boot-2010.12]# make smdk2410_config Generating include/autoconf.mk Generating include/autoconf.mk.dep Configuring for smdk2410 board... [root@localhost u-boot-2010.12]# 修改完毕再次编译出现如下错误: arch/arm/lib/libarm.o: In function `arch_lmb_reserve': /home/bsc/u-boot-2010.12/arch/arm/lib/bootm.c:74: undefined reference to `get_sp' arm-linux-ld: BFD (Sourcery G++ Lite 2008q3-72) 2.18.50.20080215 assertion fail /scratch/julian/lite-respin/linux/obj/binutils-src-2008q3-72-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:9537 arm-linux-ld: BFD (Sourcery G++ Lite 2008q3-72) 2.18.50.20080215 assertion fail /scratch/julian/lite-respin/linux/obj/binutils-src-2008q3-72-arm-none-linux-gnueabi-i686-pc-linux-gnu/bfd/elf32-arm.c:9771 /bin/sh: line 1: 27564 Segmentation fault????? arm-linux-ld -Bstatic -T u-boot.lds -pie -Ttext 0x33F80000 $UNDEF_SYM arch/arm/cpu/arm920t/start.o --start-group api/libapi.o arch/arm/cpu/arm920t/libarm920t.o arch/arm/cpu/arm920t/s3c24x0/libs3c24x0.o arch/arm/lib/libarm.o common/libcommon.o disk/libdisk.o drivers/bios_emulator/libatibiosemu.o drivers/block/libblock.o drivers/dma/libdma.o drivers/fpga/libfpga.o drivers/gpio/libgpio.o drivers/hwmon/libhwmon.o drivers/i2c/libi2c.o drivers/input/libinput.o drivers/misc/libmisc.o drivers/mmc/libmmc.o drivers/mtd/libmtd.o drivers/mtd/nand/libnand.o drivers/mtd/onenand/libonenand.o drivers/mtd/spi/libspi_flash.o drivers/mtd/ubi/libubi.o drivers/net/libnet.o drivers/net/phy/libphy.o drivers/pci/libpci.o drivers/pcmcia/libpcmcia.o drivers/power/libpower.o drivers/rtc/librtc.o drivers/serial/libserial.o drivers/spi/libspi.o drivers/twserial/libtws.o drivers/usb/gadget/libusb_gadget.o drivers/usb/host/libusb_host.o drivers/usb/musb/libusb_musb.o drivers/usb/phy/libusb_phy.o drivers/video/libvideo.o drivers/watchdog/libwatchdog.o fs/cramfs/libcramfs.o fs/ext2/libext2fs.o fs/fat/libfat.o fs/fdos/libfdos.o fs/jffs2/libjffs2.o fs/reiserfs/libreiserfs.o fs/ubifs/libubifs.o fs/yaffs2/libyaffs2.o lib/libfdt/libfdt.o lib/libgeneric.o lib/lzma/liblzma.o lib/lzo/liblzo.o net/libnet.o post/libpost.o board/samsung/smdk2410/libsmdk2410.o --end-group /home/bsc/u-boot-2010.12/arch/arm/lib/eabi_compat.o -L /usr/local/arm/4.3.2/bin/../lib/gcc/arm-none-linux-gnueabi/4.3.2/armv4t -lgcc -Map u-boot.map -o u-boot make: *** [u-boot] Error 139 查看bootm.c:代码,发现里面明明存在get_sp()函数,支持在一些宏定义条件下。可能是这些宏未定义导致该函数未编译。查到网上一个patch: [PATCH] arm: get_sp() should always be compiled <ratbert.chuang <at> gmail.com> From: Po-Yu Chuang <ratbert <at> faraday-tech.com> get_sp() was incorrectly excluded if none of ? CONFIG_SETUP_MEMORY_TAGS ? CONFIG_CMDLINE_TAG ? CONFIG_INITRD_TAG ? CONFIG_SERIAL_TAG ? CONFIG_REVISION_TAG were defined. ? Signed-off-by: Po-Yu Chuang <ratbert <at> faraday-tech.com> --- ?arch/arm/lib/bootm.c |??? 4 +--- ?1 files changed,1 insertions(+),3 deletions(-) ? diff --git a/arch/arm/lib/bootm.c b/arch/arm/lib/bootm.c index a1649ee..7734953 100644 --- a/arch/arm/lib/bootm.c +++ b/arch/arm/lib/bootm.c @@ -327,12 +327,12 @@ void setup_revision_tag(struct tag **in_params) ?} ?#endif? /* CONFIG_REVISION_TAG */ ? - ?static void setup_end_tag (bd_t *bd) ?{ ??????? params->hdr.tag = ATAG_NONE; ??????? params->hdr.size = 0; ?} +#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */ ? ?static ulong get_sp(void) ?{ @@ -341,5 +341,3 @@ static ulong get_sp(void) ??????? asm("mov %0,sp" : "=r"(ret) : ); ??????? return ret; ?} - -#endif /* CONFIG_SETUP_MEMORY_TAGS || CONFIG_CMDLINE_TAG || CONFIG_INITRD_TAG */ 修改完毕后,再次编译通过(从编译过程来看,新版本的BUG还不少)。 第2页:移植在RAM中运行 Smdk2410可以编译通过之后,即可进入2440的移植了。2440和2410的资源差不多,主频和外设有点差别,所以我们就在board/samsung/下以smdk2410为模板建立自己目标板的项目,取名叫smdk2440。(代码中的修改用红色表示) 一、首先建立目标板文件 #cp -rf smdk2410/* smdk2440/???//将2410下所有的代码复制到2440下 #cd smdk2440??????? //进入smdk2440目录 #mv smdk2410.c smdk2440.c??//将smdk2440下的smdk2410.c改名为smdk2440.c #cd ../../../???????? //回到u-boot根目录 修改smdk2440下Makefile的编译项,如下: COBJS????:= smdk2440.o flash.o??//因在smdk2440下我们将smdk2410.c改名为smdk2440.c 老版本的uboot是需要修改顶层makefile文件 在其中加入: smdk2440_config????:????unconfig?????//2440编译选项格式 但是新版本的文件组织结构有很大变化,需要在boards.cfg文件中smdk2410的下面增加类似的一条: smdk2440?????? arm???????? arm920t???? -??????? ??samsung??????? s3c24x0 然后,测试下编译情况: Make distclean Make smdk2440_ config Make all 不幸,出现如下错误: ? board.c: In function 'board_init_f': board.c:279: error: 'CONFIG_SYS_TEXT_BASE' undeclared (first use in this function) board.c:279: error: (Each undeclared identifier is reported only once board.c:279: error: for each function it appears in.) make[1]: *** [board.o]?错误?1 make[1]:?离开目录“/home/bsc/samba/u-boot-2010.12/arch/arm/lib” make: *** [arch/arm/lib/libarm.o]?错误?2 ? 这说明我们前面为了编译通过而增加的宏定义可能是有问题的,事实上我们可以在网上查到一个patch,可以解决这些问题。但是这里,为了深入了解问题所在,我们手动一点点来修改而不是直接打上patch。 include/configs/smdk2410.h include/configs/smdk2440.h?文件中删除上面添加的宏定义: #define CONFIG_SYS_SDRAM_BASE???????????? 0x00000000 添加如下宏定义(参考该patch) #define CONFIG_SYS_SDRAM_BASE????? PHYS_SDRAM_1 #define CONFIG_SYS_INIT_SP_ADDR??? (CONFIG_SYS_SDRAM_BASE + 0x1000 -?? GENERATED_GBL_DATA_SIZE) 然后再次编译,此次编译可以通过?至此我们建立起了目标板的框架,我们可以开始修改代码以适应我们的目标板。 二、目标板u-boot的硬件设备初始化。 (1)入口代码分析 一般在嵌入式系统软件开发中,在所有源码文件编译完成之后,链接器要读取一个链接分配文件,在该文件中定义了程序的入口?点,代码段、数据段等分配情况等。那么我们的2440开发板u-boot的这个链接文件就是cpu/arm920t/u-boot.lds,打开该文件部分代码如下: OUTPUT_FORMAT("elf32-littlearm",?"elf32-littlearm",?"elf32-littlearm") 知道了程序的入口点是_start,那么我们就打开2440开发板u-boot第一个要运行的程序cpu/arm920t/start.S,查找到_start的位置如下: .globl _start 从这个汇编代码可以看到程序又跳转到start_code处开始执行,那么再查找到start_code处的代码如下: /* 由此可以看到,start_code处才是u-boot启动代码的真正开始处。 (2)初始化代码修改 start.S中注释掉LED相关代码: /*bl coloured_LED_init??//这两行是AT91RM9200DK开发板的LED初始化,注释掉 ???????/*注释掉以下两行代码以便在内存中调试 #ifndef CONFIG_SKIP_LOWLEVEL_INIT ???????bl????cpu_init_crit #endif */ 或者在在include/configs/smdk2440.h头文件中添加CONFIG_S3C2440宏 #define?CONFIG_SKIP_LOWLEVEL_INIT 在include/configs/smdk2440.h头文件中添加CONFIG_S3C2440宏 #define CONFIG_ARM920T????????1????/* This is an ARM920T Core?????*/ #define CONFIG_SYS_CLK_FREQ??? 16934400/* the SMDK2440 has 16MHz input clock? by bsc */ 在u-boot中添加对S3C2440一些寄存器的支持、添加中断禁止部分和时钟设置部分。 #ifdef CONFIG_S3C24X0 ?????? /* turn off the watchdog */ # if defined(CONFIG_S3C2400) #? define pWTCON????? 0x15300000 #? define INTMSK?????? 0x14400008??? /* Interupt-Controller base addresses */ #? define CLKDIVN???? 0x14800014??? /* clock divisor register */ #else #? define pWTCON????? 0x53000000 #? define INTMSK?????? 0x4A000008?? /* Interupt-Controller base addresses */ #? define INTSUBMSK?????? 0x4A00001C #? define CLKDIVN???? 0x4C000014?? /* clock divisor register */ # endif ? ?????? ldr?? r0,=pWTCON ?????? mov r1,#0x0 ?????? str??? r1,[r0] ? ?????? /* ?????? ?* mask all IRQs by setting all bits in the INTMR - default ?????? ?*/ ?????? mov r1,#0xffffffff ?????? ldr?? r0,=INTMSK ?????? str??? r1,[r0] # if defined(CONFIG_S3C2410) ?????? ldr?? r1,=0x3ff ?????? ldr?? r0,=INTSUBMSK ?????? str??? r1,[r0] # endif # if defined(CONFIG_S3C2440) ?????? ldr?? r1,=0x7fff ?????? ldr?? r0,[r0] # endif ? # if defined(CONFIG_S3C2440)?? //添加s3c2440的时钟部分 ? #define MPLLCON?? 0x4C000004?? //系统主频配置寄存器基地址 #define UPLLCON?? 0x4C000008?? //USB时钟频率配置寄存器基地址 #define CAMDIVN ???? 0x4C000018 ? ?????? ldr? r0,? = CAMDIVN ?????? mov? r1,? #0 ?????? str? r1,? [r0] ?????? ? ??? ?????? ldr? r0,= CLKDIVN?? ???????//设置分频系数FCLK:HCLK:PCLK = 1:3:6 ??? ?????? ldr? r1,? = 0x7 ??? ?????? str? r1,[r0] ? ?????? ldr? r0,=MPLLCON? //设置系统主频为405MHz ?????? ldr? r1,=0x6e031? //这个值参考芯片手册“PLL VALUE SELECTION TABLE”部分 ?????? str? r1,[r0] ?????? ?????? ldr? r0,=UPLLCON? //设置USB时钟频率为48MHz ?????? ldr? r1,=0x3c042? //这个值参考芯片手册“PLL VALUE SELECTION TABLE”部分 ?????? str? r1,[r0] # else //其他开发板的时钟部分,这里就不用管了,我们现在是做2440的 ?????? /* FCLK:HCLK:PCLK = 1:2:4 */ ?????? /* default FCLK is 120 MHz ! */ ?????? ldr?? r0,=CLKDIVN ?????? mov r1,#3 ?????? str??? r1,[r0] #endif???? /* CONFIG_S3C2440 */ #endif???? /* CONFIG_S3C24X0 */ ? S3C2440的时钟部分除了在start.S中添加外,还要在board/samsung/smdk2440/smdk2440.c修改或添加部分代码,如下: #define FCLK_SPEED 2?????? //设置默认等于2,by bsc 2010-2-22 20:49 #if FCLK_SPEED==0????????? /* Fout = 203MHz,Fin = 12MHz for Audio */ #define M_MDIV??? 0xC3 #define M_PDIV??? 0x4 #define M_SDIV??? 0x1 #elif FCLK_SPEED==1??????? /* Fout = 202.8MHz */ #define M_MDIV??? 0xA1 #define M_PDIV??? 0x3 #define M_SDIV??? 0x1 #elif FCLK_SPEED==2??????? /* Fout = 405MHz */ #define M_MDIV??? 0x6e???? //这三个值根据S3C2440芯片手册“PLL VALUE SELECTION TABLE”部分进行设置 #define M_PDIV??? 0x3 #define M_SDIV??? 0x1 #endif ? #define USB_CLOCK 2??????? //设置默认等于2,即下面红色代码部分有效 ? #if USB_CLOCK==0 #define U_M_MDIV??? 0xA1 #define U_M_PDIV??? 0x3 #define U_M_SDIV??? 0x1 #elif USB_CLOCK==1 #define U_M_MDIV??? 0x48 #define U_M_PDIV??? 0x3 #define U_M_SDIV??? 0x2 #elif USB_CLOCK==2????? ???/* Fout = 48MHz */ #define U_M_MDIV??? 0x3c?? //这三个值根据S3C2440芯片手册“PLL VALUE SELECTION TABLE”部分进行设置 #define U_M_PDIV??? 0x4 #define U_M_SDIV??? 0x2 #endif ? 修改/* arch number of SMDK2440-Board */ ???????gd->bd->bi_arch_number = MACH_TYPE_SMDK2440; 在dram_init(void)函数中添加gd->ram_size初始化(此句比较重要): gd->ram_size = PHYS_SDRAM_1_SIZE;?/*add by bsc 2011/2/21 20:14:46*/ 修改board/samsung/smdk2440/config.mk CONFIG_SYS_TEXT_BASE = 0x33000000/*0x3f800000改为0x33000000?以便内存中调试*/ 修改完毕后我们再重新编译u-boot,然后再下载到RAM中运行测试。tftp 0x33000000 u-boot.bin? go 0x33000000 结果终端有输出信息并且出现类似Shell的命令行,这说明这一部分移植完成。如果有其他问题可以在include/configs/smdk2440.h头文件中添加DEBUG宏用于调试。 第3页:DM9000网卡驱动移植 在这一篇中,我们让开发板实现对DM9000X网卡的支持,后续的移植及调试均依赖网络的支持。 u- boot的新版本已经对CS8900和DM9000X网卡有比较完善的代码支持(代码在drivers/net/目录下),而且在?S3C24XX系列中默认对CS8900网卡进行配置使用。只是在个别地方要根据开发板的具体网卡片选进行设置,就可以对S3C24XX系列中?CS8900网卡的支持使用。 由于我们的目标板采用的是dm9000网卡,我们通过drivers/net/目录下有关DM9000的代码,发现dm9000x.h中对CONFIG_DRIVER_DM9000宏的依 赖,dm9000x.c中对CONFIG_DM9000_BASE宏、DM9000_IO宏、DM9000_DATA等宏的依赖,所以我们修改代码如下: #define CONFIG_NET_MULTI??????? 1 /* * Hardware drivers */??屏蔽掉u-boot默认对CS8900网卡的支持 //添加u-boot对DM9000X网卡的支持 #define CONFIG_CMD_NET #define CONFIG_DRIVER_DM9000??? 1?? //给u-boot加上ping命令,用来测试网络通不通 #define CONFIG_CMD_PING? ? //恢复被注释掉的网卡MAC地址和修改你合适的开发板IP地址 #define CONFIG_ETHADDR???08:00:3e:26:0a:5b??//开发板MAC地址 #define CONFIG_SERVERIP??192.168.0.7??????//Linux主机IP地址 board/samsung/smdk2440/smdk2440.c?添加板载DM9000网卡初始化代码,如下: #include <net.h> #ifdef CONFIG_CMD_NET int board_eth_init(bd_t *bis) { ????int rc = 0; #ifdef CONFIG_CS8900 ????cs8900_initialize(0,CONFIG_CS8900_BASE); #endif ? #ifdef CONFIG_DRIVER_DM9000 ????rc = dm9000_initialize(bis); #endif ????return rc; } #endif 编译之后加载到内存运行,可以ping通,但是串口出现大量“raise:signal # 8 caught”.找到打印该语句的地方,?archarmlibeabi_compat.c, int raise (int signum) { ????/*printf("raise: Signal # %d caughtn",signum);*/ ????return 0; } 直接删除掉该打印(比较简单粗暴,但是验证证实确实可以的,目前未发现什么问题。) 然后下载运行ping命令,发现不通,出现“could not establish link”的错误,参考网友的处理方法:修改drivers/net/dm9000x.c #if 0? //屏蔽掉dm9000_init函数中的这一部分,不然使用网卡的时候会报“could not establish link”的错误 /* { #if 0 ??????DM9000_DBG("%sn",__func__); ??????/* RESET devie */ ??????phy_write(0,0x8000);??????/* PHY RESET */ ??????DM9000_iow(DM9000_GPR,0x01);???/* Power-Down PHY */ ??????DM9000_iow(DM9000_IMR,0x80);???/* Disable all interrupt */ ??????DM9000_iow(DM9000_RCR,0x00);??/* Disable RX */ #endif } 然后再次完全重新编译,测试ping和tftp命令,均正常,至此dm9000的驱动移植完成可以正常工作。至于“raise:signal # 8 caught”的错误,后续可以再仔细研究,目前怀疑是新版本的BUG。 第4页:支持nand flash启动 在这篇中,我们将移植nand flash部分,支持NAND启动及NAND FLASH的读写访问。 首先,我们在u-boot-2010.12includeconfigssmdk2440.h中注销如下定义。 //#define??CONFIG_ENV_IS_IN_FLASH????1 //#define CONFIG_ENV_SIZE???????????0x10000??/* Total Size of Environment Sector */ 增加如下定义: /*以下为NAND启动及驱动相关*/ #define CONFIG_S3C2440_NAND_BOOT??1 #define CONFIG_NAND_S3C2440 ? #define NAND_CTL_BASE??0x4E000000??//Nand Flash配置寄存器基地址,查2440手册可得知 #define oNFCONF??0x00 //相对Nand配置寄存器基地址的偏移量,还是配置寄存器的基地址 #define oNFCONT??0x04 //相对Nand配置寄存器基地址的偏移量,可得到控制寄存器的基地址(0x4E000004) #define oNFADDR??0x0c //相对Nand配置寄存器基地址的偏移量,可得到地址寄存器的基地址(0x4E00000c) #define oNFDATA??0x10 //相对Nand配置寄存器基地址的偏移量,可得到数据寄存器的基地址(0x4E000010) #define oNFCMD???0x08 //相对Nand配置寄存器基地址的偏移量,可得到指令寄存器的基地址(0x4E000008) #define oNFSTAT??0x20 //相对Nand配置寄存器基地址的偏移量,可得到状态寄存器的基地址(0x4E000020) #define oNFECC???0x2c //相对Nand配置寄存器基地址的偏移量,可得到ECC寄存器的基地址(0x4E00002c) ? #define UBOOT_LENGTH??0x40000 /*256K*/ #define STACK_BASE??0x33f00000?????//定义堆栈的地址 #define STACK_SIZE??0x8000?????????//堆栈的长度大小 ? #define CONFIG_CMD_NAND #define CONFIG_CMDLINE_EDITING #ifdef CONFIG_CMDLINE_EDITING #undef CONFIG_AUTO_COMPLETE #else #define CONFIG_AUTO_COMPLETE #endif ? /* NAND flash settings */ #if defined(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 NAND_SAMSUNG_LP_OPTIONS???????1??//注意:我们这里是64M的Nand Flash,所以不用,如果是128M的大块Nand Flash,则需加上 #endif ? //添加环境变量保存到Nand的宏(注意:如果你要使用从Nor启动的saveenv命令,则不要这些Nand宏定义) #define CONFIG_ENV_IS_IN_NAND??1 #define CONFIG_ENV_OFFSET??????0x30000 //将环境变量保存到nand中的0x30000位置 #define CONFIG_ENV_SIZE????????0x10000 /* Total Size of Environment Sector */ 在archarmcpuarm920tstart.S文件中增加如下代码: ? #ifndef CONFIG_SKIP_LOWLEVEL_INIT ???????bl????cpu_init_crit #endif ? //下面添加2440中u-boot从Nand Flash启动 ? #ifdef CONFIG_S3C2440_NAND_BOOT ????mov r1,#NAND_CTL_BASE???//复位Nand Flash ????ldr r2,=( (7<<12)|(7<<8)|(7<<4)|(0<<0) ) ????str r2,[r1,#oNFCONF]???//设置配置寄存器的初始值,参考s3c2440手册 ????ldr r2,#oNFCONF] ? ????ldr r2,=( (1<<4)|(0<<1)|(1<<0) ) ????str r2,#oNFCONT]???//设置控制寄存器 ????ldr r2,#oNFCONT] ? ????ldr r2,=(0x6)???????????//RnB Clear ????str r2,#oNFSTAT] ????ldr r2,#oNFSTAT] ????mov r2,#0xff????????????//复位command ????strb r2,#oNFCMD] ? ????mov r3,#0???????????????//等待 nand1: ????add r3,r3,#0x1 ????cmp r3,#0xa ????blt nand1 ? nand2: ????ldr r2,#oNFSTAT]???//等待就绪 ????tst r2,#0x4 ????beq nand2 ? ????ldr r2,#oNFCONT] ????orr r2,r2,#0x2?????????//取消片选 ????str r2,#oNFCONT] ? ????//get read to call C functions (for nand_read()) ????ldr sp,DW_STACK_START???//为C代码准备堆栈,DW_STACK_START定义在下面 ????mov fp,#0?????????????? ? ????//copy U-Boot to RAM ????ldr r0,=CONFIG_SYS_LOAD_ADDR//传递给C代码的第一个参数:u-boot在RAM中的起始地址?//暂时为这个值 ????mov r1,#0x0??????//传递给C代码的第二个参数:Nand Flash的起始地址 ????mov r2,#UBOOT_LENGTH??//传递给C代码的第三个参数:u-boot的长度大小 ????bl nand_read_ll???//此处调用C代码中读Nand的函数,现在还没有要自己编写实现 ????tst r0,#0x0 ????beq ok_nand_read ? bad_nand_read: ????loop2: b loop2????//infinite loop ? ok_nand_read: ????//检查搬移后的数据,如果前4k完全相同,表示搬移成功 ????mov r0,#0 ????ldr r1,=CONFIG_SYS_LOAD_ADDR//暂时为这个值 ????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,#4 ????beq board_init_f ????bne go_next ? notmatch: ????loop3: b loop3???????????//infinite loop #endif //CONFIG_S3C2440_NAND_BOOT ? .align 2???/*add by bsc 2010-2-6 13:11*/ DW_STACK_START: .word STACK_BASE+STACK_SIZE-4 ? 增加从NAND FLASH读取数据到内存的函数,文件名为nand_read.c放到boardsamsungsmdk2440nand_read.c下。 #include <config.h> ? #define NF_BASE???0x4E000000??//Nand Flash配置寄存器基地址 ? #define __REGb(x) (*(volatile unsigned char *)(x)) #define __REGi(x) (*(volatile unsigned int??*)(x)) ? #define NFCONF __REGi(NF_BASE + 0x0 )??//通过偏移量还是得到配置寄存器基地址 #define NFCONT __REGi(NF_BASE + 0x4 )??//通过偏移量得到控制寄存器基地址 #define NFCMD??__REGb(NF_BASE + 0x8 )??//通过偏移量得到指令寄存器基地址 #define NFADDR __REGb(NF_BASE + 0xC )??//通过偏移量得到地址寄存器基地址 #define NFDATA __REGb(NF_BASE + 0x10)??//通过偏移量得到数据寄存器基地址 #define NFSTAT __REGb(NF_BASE + 0x20)??//通过偏移量得到状态寄存器基地址 ? #define NAND_CHIP_ENABLE??(NFCONT &= ~(1<<1))??//Nand片选使能 #define NAND_CHIP_DISABLE (NFCONT |= (1<<1))???//取消Nand片选 #define NAND_CLEAR_RB?????(NFSTAT |= (1<<2)) #define NAND_DETECT_RB????{ while(! (NFSTAT&(1<<2)) );} ? ? #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; //地址或长度不对齐 ????} ? ????NAND_CHIP_ENABLE; //选中Nand片选 ? ????for(i=start_addr; i < (start_addr + size);) ????{ ????????//发出READ0指令 ? ????????NAND_CLEAR_RB; ????????NFCMD = 0; ? ????????//对Nand进行寻址 ????????NFADDR = i & 0xFF; ? ????????NFADDR = (i >> 9) & 0xFF; ????????NFADDR = (i >> 17) & 0xFF; ????????NFADDR = (i >> 25) & 0xFF; ? ????????NAND_DETECT_RB; ? ????????for(j=0; j < NAND_SECTOR_SIZE; j++,i++) ????????{ ????????????*buf = (NFDATA & 0xFF); ????????????buf++; ????????} ????} ? ????NAND_CHIP_DISABLE; //取消片选信号 ? ????return 0; } ? 修改board/samsung/smdk2440/?makefile COBJS????:= smdk2440.o flash.o?nand_read.o ? drivers/mtd/nand/s3c2440_nand.c??目录下新建s3c2440_nand.c文件实现对nand FLASH的操作。 ? #include <common.h> ? #if 0 #define DEBUGN????printf #else #define DEBUGN(x,args ...) {} #endif ? #include <nand.h> #include <asm/arch/s3c24x0_cpu.h> #include <asm/io.h> ? ? #define __REGb(x)????(*(volatile unsigned char *)(x)) #define __REGi(x)????(*(volatile unsigned int *)(x)) ? ? #define NF_BASE??0x4e000000?????????????//Nand配置寄存器基地址 #define NFCONF???__REGi(NF_BASE + 0x0)??//偏移后还是得到配置寄存器基地址 #define NFCONT???__REGi(NF_BASE + 0x4)??//偏移后得到Nand控制寄存器基地址 #define NFCMD????__REGb(NF_BASE + 0x8)??//偏移后得到Nand指令寄存器基地址 #define NFADDR???__REGb(NF_BASE + 0xc)??//偏移后得到Nand地址寄存器基地址 #define NFDATA???__REGb(NF_BASE + 0x10) //偏移后得到Nand数据寄存器基地址 #define NFMECCD0 __REGi(NF_BASE + 0x14) //偏移后得到Nand主数据区域ECC0寄存器基地址 #define NFMECCD1 __REGi(NF_BASE + 0x18) //偏移后得到Nand主数据区域ECC1寄存器基地址 #define NFSECCD??__REGi(NF_BASE + 0x1C) //偏移后得到Nand空闲区域ECC寄存器基地址 #define NFSTAT???__REGb(NF_BASE + 0x20) //偏移后得到Nand状态寄存器基地址 #define NFSTAT0??__REGi(NF_BASE + 0x24) //偏移后得到Nand ECC0状态寄存器基地址 #define NFSTAT1??__REGi(NF_BASE + 0x28) //偏移后得到Nand ECC1状态寄存器基地址 #define NFMECC0??__REGi(NF_BASE + 0x2C) //偏移后得到Nand主数据区域ECC0状态寄存器基地址 #define NFMECC1??__REGi(NF_BASE + 0x30) //偏移后得到Nand主数据区域ECC1状态寄存器基地址 #define NFSECC???__REGi(NF_BASE + 0x34) //偏移后得到Nand空闲区域ECC状态寄存器基地址 #define NFSBLK???__REGi(NF_BASE + 0x38) //偏移后得到Nand块开始地址 #define NFEBLK???__REGi(NF_BASE + 0x3c) //偏移后得到Nand块结束地址 ? #define S3C2440_NFCONT_nCE??(1<<1) #define S3C2440_ADDR_NALE???0x0c #define S3C2440_ADDR_NCLE???0x08 ? ulong IO_ADDR_W = NF_BASE; ? static void s3c2440_hwcontrol(struct mtd_info *mtd,int cmd,unsigned int ctrl) { ????struct nand_chip *chip = mtd->priv; ? ????DEBUGN("hwcontrol(): 0x%02x 0x%02xn",cmd,ctrl); ? ????if (ctrl & NAND_CTRL_CHANGE) { ????????IO_ADDR_W = NF_BASE; ? ????????if (!(ctrl & NAND_CLE))????????????????//要写的是地址 ????????????IO_ADDR_W |= S3C2440_ADDR_NALE; ????????if (!(ctrl & NAND_ALE))????????????????//要写的是命令 ????????????IO_ADDR_W |= S3C2440_ADDR_NCLE; ? ????????if (ctrl & NAND_NCE) ????????????NFCONT &= ~S3C2440_NFCONT_nCE;????//使能nand flash ????????else ????????????NFCONT |= S3C2440_NFCONT_nCE;?????//禁止nand flash ????} ? ????if (cmd != NAND_CMD_NONE) ????????writeb(cmd,(void *)IO_ADDR_W); } ? static int s3c2440_dev_ready(struct mtd_info *mtd) { ????DEBUGN("dev_readyn"); ????return (NFSTAT & 0x01); } ? int board_nand_init(struct nand_chip *nand) { ????u_int32_t cfg; ????u_int8_t tacls,twrph0,twrph1; ??????????????struct s3c24x0_clock_power * const clk_power = s3c24x0_get_base_clock_power(); ? ????DEBUGN("board_nand_init()n"); ? ????/*clk_power->CLKCON |= (1 << 4);*/ ????writel(readl(&clk_power->clkcon) | (1 << 4),&clk_power->clkcon); ? ????twrph0 = 4; twrph1 = 2; tacls = 0; ? ????cfg = (tacls<<12)|(twrph0<<8)|(twrph1<<4); ????NFCONF = cfg; ? ????cfg = (1<<6)|(1<<4)|(0<<1)|(1<<0); ????NFCONT = cfg; ? ????/* initialize nand_chip data structure */ ????nand->IO_ADDR_R = nand->IO_ADDR_W = (void *)0x4e000010; ? ????/* read_buf and write_buf are default */ ????/* read_byte and write_byte are default */ ? ????/* hwcontrol always must be implemented */ ????nand->cmd_ctrl = s3c2440_hwcontrol; ? ????nand->dev_ready = s3c2440_dev_ready; ? ????return 0; } 然后,在drivers/mtd/nand/Makefile文件中添加s3c2440_nand.c的编译项,如下: COBJS-$(CONFIG_NAND_S3C2440) += s3c2440_nand.o 在u-boot-2010.12includeconfigssmdk2440.h中增加宏定义: #?define??CONFIG_NAND_S3C2440 ? 重新编译,将u-boot.bin下载到内存运行,可以运行,FLASH也正常的读写。注意,此时我们的uboot还不支持从NAND FLASH启动,前面的步骤只是为了调试方便,我们将可以看到在内存中运行的u-boot成功的将NAND FLASH中的数据拷贝到了内存中CONFIG_SYS_LOAD_ADDR的位置。接下来我们让其支持在NAND FLASH中的启动。 ? 将上面的ldr r0,=CONFIG_SYS_LOAD_ADDR和ldr r1,=CONFIG_SYS_LOAD_ADDR替换为ldr r0,=CONFIG_SYS_TEXT_BASE和ldr r1,=CONFIG_SYS_TEXT_BASE。 ? 通过查看u-boot.map可以看到,我们的nand_read_ll()函数被连接在4K之后的位置,所以根本无法再启动时实现数据到内存的拷贝。因此我们根据网友的说法修改archarmcpuarm920tu-boot.lds如下: .text : ???????{ ??????????????arch/arm/cpu/arm920t/start.o?(.text) ??????????????board/samsung/smdk2440/lowlevel_init.o????(.text) ??????????????board/samsung/smdk2440/nand_read.o?(.text) ??????????????*(.text) ???????} 编译发现,编译通不过,出现重定义的错误。这可能是新版本的编译和连接规则有变化导致的,具体原因还不清楚,因此我们采用其他的办法。 board/samsung/smdk2440/libsmdk2440.o: In function `nand_read_ll': /home/bsc/samba/u-boot-2010.12/board/samsung/smdk2440/nand_read.c:30: multiple definition of `nand_read_ll' board/samsung/smdk2440/nand_read.o:/home/bsc/samba/u-boot-2010.12/board/samsung/smdk2440/nand_read.c:30: first defined here board/samsung/smdk2440/libsmdk2440.o: In function `lowlevel_init': /home/bsc/samba/u-boot-2010.12/board/samsung/smdk2440/lowlevel_init.S:137: multiple definition of `lowlevel_init' board/samsung/smdk2440/lowlevel_init.o:/home/bsc/samba/u-boot-2010.12/board/samsung/smdk2440/lowlevel_init.S:137: first defined here make: *** [u-boot]?错误?1 这可能是新版本的编译和连接规则有变化导致的,具体原因还不清楚,因此我们采用其他的办法。修改archarmcpuarm920tu-boot.lds如下: .text : ???????{ ??????????????arch/arm/cpu/arm920t/start.o?(.text) ??????????????board/samsung/smdk2440/?libsmdk2440.o????(.text) arch/arm/lib/libarm.o?????(.text) ??????????????*(.text) ???????} 编译之后发现,board_init_f函数还是超过了4K,我们只能对前面的代码进行瘦身了,我们的目标板没有NOR FLASH,所以我们取消NOR FLASH的支持。 在u-boot-2010.12includeconfigssmdk2440.h中增加宏定义: /*去掉NOR FLASH支持*/ #define CONFIG_SYS_NO_FLASH #define CONFIG_CMD_FLASH??/* flinfo,erase,protect???*/ #define CONFIG_CMD_IMLS????????????/* List all found images??*/ 修改board/samsung/smdk2440/ makefile,取消对flash的编译。 COBJS????:= smdk2440.o nand_read.o 编译后下载到内存,杯具又发生了,跑进board_init_r()函数的时候死机了。至此相当的郁闷了,没办法再修改archarmcpuarm920tu-boot.lds如下: .text : ???????{ ??????????????arch/arm/cpu/arm920t/start.o?(.text) ??????????????board/samsung/smdk2440/?libsmdk2440.o????(.text) ??????????????*(.text) ???????} 在编译,下载到内存运行,可以运行。但是还是相当杯具的,通过查看u-boot.map可以看到arch/arm/lib/libarm.o被连接到了4K之外,4K之内没有这个程序我们是不可能实现NAND启动的。但是天无绝人之路,我们可以让U-boot提前进入内存运行。思路是,我们提前将代码拷贝到内存中,提前跳转到内存中运行不再回来。修改archarmcpuarm920tstart.S文件如下: ? #ifndef CONFIG_SKIP_LOWLEVEL_INIT ???????bl????cpu_init_crit #endif ? //下面添加2440中u-boot从Nand Flash启动 #ifdef CONFIG_S3C2440_NAND_BOOT ????mov r1,=CONFIG_SYS_TEXT_BASE//传递给C代码的第一个参数:u-boot在RAM中的起始地址 ????mov r1,=CONFIG_SYS_TEXT_BASE ????mov r2,#4 ????beq relocations???????/*注意此句,直接跳转到relocate_code?函数的调整部分,因为我们不打算在board_init_f()函数中再回来了*/ ????bne go_next ? notmatch: ????loop3: b loop3???????????//infinite loop ? #endif //CONFIG_S3C2440_NAND_BOOT ? /*------------------------------------------------------------------------------*/ ? /* ?* 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???r2,_TEXT_BASE ???????ldr???r3,_bss_start_ofs ???????add??r2,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 ?????? relocations:?????/*增加标号,以便跳转到这里*/ ???????ldr r6,=CONFIG_SYS_TEXT_BASE?/*注意,R6下面被用到表示新的目标地址*/ ? #ifndef CONFIG_PRELOADER ???????/* ????????* 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,r0????????/* r2 <- rel dyn start in FLASH */ ???????ldr???r3,_rel_dyn_end_ofs?????/* r3 <- rel dyn end ofs */ ???????add??r3,r0????????/* r3 <- rel dyn end in FLASH */ fixloop: ???????ldr???r0,[r2]???????????/* r0 <- location to fix up,IN FLASH! */ ???????add??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,LSR #4??????????????/* r1 <- symbol index in .dynsym */ ???????add??r1,r1?????????????/* r1 <- address of symbol in table */ ???????ldr???r1,#4]????????????/* r1 <- symbol value */ ???????add??r1,r9????????/* r1 <- relocated sym addr */ ???????b?????fixnext fixrel: ???????/* relative fix: increase location by offset */ ???????ldr???r1,[r0] ???????add??r1,r9 fixnext: ???????str????r1,[r0] ???????add??r2,#8????????/* each rel.dyn entry is 8 bytes */ ???????cmp?r2,r3 ???????blo???fixloop #endif ? clear_bss: #ifndef CONFIG_PRELOADER ???????ldr???r0,_bss_start_ofs ???????ldr???r1,_bss_end_ofs ???????ldr???r3,_TEXT_BASE?????????/* Text base */ ???????mov?r4,r6?????????????/* reloc addr */ ???????add??r0,r3?????/*注意此句修改*/ ???????add??r1,r3????/*注意此句修改*/ ???????mov?r2,#0x00000000???????????/* clear??????????????????????*/ ? clbss_l:str???????r2,[r0]???????????/* clear loop...??????????????????*/ ???????add??r0,#4 ???????cmp?r0,r1 ???????bne??clbss_l /* ???????bl coloured_LED_init ???????bl red_LED_on *//* by bsc 2011/2/23 13:44:29*/ #endif ? /* Set stackpointer in internal RAM to call board_init_f */ call_board_init_f: ???????ldr???sp,=(CONFIG_SYS_INIT_SP_ADDR) ???????bic???sp,sp,#7 /* 8-byte alignment for ABI compliance */ ???????ldr???r0,=0x00000000 ???????/*bl??board_init_f*/?/*删除此句,我们用绝对地址跳转到内存去了,不再回来了*/ ???????ldr pc,_board_init_f?????/*增加此句,我们用绝对地址跳转到内存去了,不再回来了*/ ?????? _board_init_f:????????/*增加此句,我们用绝对地址跳转到内存去了,不再回来了*/ ???????.word board_init_f /* ?* We are done. Do not return,instead branch to second part of board ?* initialization,now running from RAM. ?*/ #ifdef CONFIG_NAND_SPL ???????ldr?????r0,_nand_boot_ofs ???????mov?pc,r0 ? _nand_boot_ofs: ???????.word nand_boot #else ???????ldr???r0,_board_init_r_ofs ???????adr???r1,_start ???????add??lr,r1 ???????add??lr,lr,r9 ???????/* setup parameters for board_init_r */ ???????mov?r0,r5?????????????/* gd_t */ ???????mov?r1,r6?????????????/* dest_addr */ ???????/* jump to it ... */ ???????mov?pc,lr ? _board_init_r_ofs: ???????.word board_init_r - _start #endif ? _rel_dyn_start_ofs: ???????.word __rel_dyn_start - _start _rel_dyn_end_ofs: ???????.word __rel_dyn_end - _start _dynsym_start_ofs: ???????.word __dynsym_start - _start ? .align 2???/*add by bsc 2010-2-6 13:11*/ DW_STACK_START: .word STACK_BASE+STACK_SIZE-4 修改完archarmcpuarm920tstart.S文件之后,我们会发现,有一句非常重要的代码被我们删除再也执行不到了,那就是设置堆栈指针:mov?sp,r4 因此我们需要在board_init_f()函数中设置。 修改archarmlibboard.c代码如下: ? 首先将board_init_f()与board_init_r()函数的顺序调换下,因为我们要在board_init_f()中调用board_init_r()。 ? gd->mon_len = 0x700000 ;?/*修改此句以保证与配置的一致性add by bsc??具体原因请查看代码中对此变量的使用即可明白,注意我们的?_TEXT_BASE=0x33f80000*/ ? 函数最后: __asm__ __volatile__("mov sp,%0"::"r"(addr_sp):"sp");/*add by bsc 2011/2/24 15:17:48*/ ????????????? #ifdef CONFIG_S3C2440_NAND_BOOT???/*add by bsc 2011/2/24 15:18:04*/ ???????board_init_r(id,addr); #else ???????relocate_code (addr_sp,id,addr); ???????/* NOTREACHED - relocate_code() does not return */ #endif ???????/*relocate_code (addr_sp,addr);*//*add by bsc 2011/2/24 15:18:28*/ ???????/* NOTREACHED - relocate_code() does not return */ ? 然后修改boardsamsungsmdk2440config.mk如下: CONFIG_SYS_TEXT_BASE = 0x33f80000 ? 然后修改includeconfigssmdk2440.h如下: 增加宏定义: #define UBOOT_LENGTH??0x40000 /*uboot大小256K*/ 删除宏定义: #define CONFIG_SKIP_LOWLEVEL_INIT?/*在内存中调试时增加此宏定义?by bsc */ ? 然后编译,烧写到NAND FLASH中,重启之后你会发现,终于可以运行啦。 测试中发现,go命令好像有问题,直接死机了,其他一切正常。 如果你还想看到u-boot启动时的输出版本信息等,修改archarmlibboard.c代码如下:board_init_r函数中修改 ?? board_init();?? ?/* Setup chipselects */ 好了,现在uboot已经可以支持NAND FLASH启动和读写了。 我们还可以在commonenv_common.c文件中的default_environment[]数组中增加 #if 1????/*add by bsc */ ???"uu="???"t 0x30000000 u-boot.bin;nand erase 0x0 0x30000;nand write 0x30000000 0x0 0x30000" " " ???"kkn="?"t 0x30008000 zImage_nfs;bootm" " " ???"kk="???"t 0x30000000 zImage;nand erase 0x50000 0x300000;nand write 0x30000000 0x50000 0x200000" " " ???"yy="???"t 0x30000000 rootyaffs2.img;nand erase 0x250000 0x3db0000;nand write.yaffs2 0x30000000 0x250000 $(filesize)" " " ???"firstboot="?"set bootcmd $(normalboot);save;nand erase 0x50000 0x3f00000;run kk;run yy" " " ???"normalboot="???"nand read 0x30008000 0x50000 0x200000;bootm 0x30008000" " " #endif 以使用?run uu;run yy这样的命令来实现一些操作。 第5页:yaffs2文件系统移植
Yaffs2文件系统的移植主要涉及到u-boot对yaffs2文件系统的烧写支持、linux内核对yaffs2文件系统的支持,以及yaffs2文件系统的制作,现在我们按照从下到上的顺序来实现各部分的功能。本文重点参考黄刚的博文。 1、实现u-boot对yaffs/yaffs2文件系统下载的支持。 注意:这里对Nand的操作是基于MTD架构方式。 通常一个Nnad Flash存储设备由若干块组成,1个块由若干页组成。一般128MB以下容量的Nand Flash芯片,一页大小为528B,被依次分为2个256B的主数据区和16B的额外空间;128MB以上容量的Nand Flash芯片,一页大小通常为2KB。由于Nand Flash出现位反转的概率较大,一般在读写时需要使用ECC进行错误检验和恢复。 Yaffs/yaffs2文件系统的设计充分考虑到Nand Flash以页为存取单位等的特点,将文件组织成固定大小的段(Chunk)。以528B的页为例,Yaffs/yaffs2文件系统使用前512B存储 数据和16B的额外空间存放数据的ECC和文件系统的组织信息等(称为OOB数据)。通过OOB数据,不但能实现错误检测和坏块处理,同时还可以避免加载 时对整个存储介质的扫描,加快了文件系统的加载速度。以下是Yaffs/yaffs2文件系统页的结构说明: ???? Yaffs页结构说明 好了,在了解Nand Flash组成和Yaffs/yaffs2文件系统结构后,我们再回到u-boot中。目前,在u-boot中已经有对Cramfs、Jffs2等文件系 统的读写支持,但与带有数据校验等功能的OOB区的Yaffs/Yaffs2文件系统相比,他们是将所有文件数据简单的以线性表形式组织的。所以,我们只要在此基础上通过修改u-boot的Nand Flash读写命令,增加处理00B区域数据的功能,即可以实现对Yaffs/Yaffs2文件系统的读写支持。 实现u-boot对Yaffs或者Yaffs2文件系统的读写支持步骤如下: ①、在include/configs/smdk2440.h头文件中定义一个管理对Yaffs2支持的宏和开启u-boot中对Nand Flash默认分区的宏,如下: #define CONFIG_MTD_NAND_YAFFS2???1?//定义一个管理对Yaffs2支持的宏 //开启Nand Flash默认分区,注意此处的分区要和你的内核中的分区保持一致 ? ②、在common/cmd_nand.c?原来对Nand操作的命令集列表中添加Yaffs2对Nand的写命令,如下://在U_BOOT_CMD中添加 U_BOOT_CMD(nand,CONFIG_SYS_MAXARGS,1,do_nand, //注意:这里只添加了yaffs2的写命令,因为我们只用u-boot下载(即写)功能,所以我们没有添加yaffs2读的命令
接着,在该文件中对nand操作的do_nand函数中添加yaffs2对nand的操作,如下: if (strncmp(cmd,"read",4) == 0 || strncmp(cmd,"write",5) == 0)? ??????? if (argc < 4) ??????? addr = (ulong)simple_strtoul(argv[2],NULL,16); ??????? read = strncmp(cmd,4) == 0; /* 1 = read,0 = write */ ??????? s = strchr(cmd,'.'); //添加yaffs2相关操作,注意该处又关联到nand_write_skip_bad函数 #if defined(CONFIG_MTD_NAND_YAFFS2) ??????? else if (!strcmp(s,".oob"))? ??????????? if (read) ??????? printf(" %zu bytes %s: %sn",size,read ? "read" : "written",ret ? "ERROR" : "OK"); ??????? return ret == 0 ? 0 : 1; ③、在include/linux/mtd/mtd.h头文件的mtd_info结构体中添加上面用到rw_oob和skipfirstblk数据成员,如下: #if defined(CONFIG_MTD_NAND_YAFFS2) ? ④、在第二步关联的drivers/mtd/nand/nand_util.c?的nand_write_skip_bad函数中添加对Nand OOB的相关操作,如下: int nand_write_skip_bad(nand_info_t *nand,loff_t offset,size_t *length,u_char *buffer) #if defined(CONFIG_MTD_NAND_YAFFS2)?//add yaffs2 file system support ??????? if (((*length)%(nand->oobsize+nand->writesize)) != 0)? ??????? datapages = *length/(datasize+oobsize); ??? /* Reject writes,which are not page aligned */ ??? len_incl_bad = get_len_incl_bad (nand,offset,*length); ??? if ((offset + len_incl_bad) >= nand->size) { #if !defined(CONFIG_MTD_NAND_YAFFS2)?//add yaffs2 file system support ??????? return rval; ??? while (left_to_write > 0) { ??????? WATCHDOG_RESET (); ??????? if (nand_block_isbad (nand,offset & ~(nand->erasesize - 1))) { #if defined(CONFIG_MTD_NAND_YAFFS2)?//add yaffs2 file system support ??????? if (left_to_write < (nand->erasesize - block_offset)) ????????printf("rWriting at 0x%llx -- ",offset);?//add yaffs2 file system support
??????? left_to_write -= write_size; #if defined(CONFIG_MTD_NAND_YAFFS2)?//add yaffs2 file system support ??? } ??? return 0; ⑤、在第四步nand_write_skip_bad函数中我们看到又对nand_write函数进行了访问,所以这一步是到drivers/mtd/nand/nand_base.c??的nand_write函数中添加对yaffs2的支持,如下: static int nand_write(struct mtd_info *mtd,loff_t to,size_t len,size_t *retlen,const uint8_t *buf) ? #if defined(CONFIG_MTD_NAND_YAFFS2)?//add yaffs2 file system support ??? int oldopsmode = 0; ??? if(mtd->rw_oob==1)???? ??????? size_t oobsize = mtd->oobsize; ??????? uint8_t oobtemp[oobsize]; ??????? for(i = 0; i < (datapages); i++)???? ? ??? /* Do not allow reads past end of device */ ??? nand_get_device(chip,mtd,FL_WRITING); ??? chip->ops.len = len; ? #if defined(CONFIG_MTD_NAND_YAFFS2)?//add yaffs2 file system support ??? if(mtd->rw_oob!=1)???? ? ??? ret = nand_do_write_ops(mtd,to,&chip->ops); ??? *retlen = chip->ops.retlen; ??? nand_release_device(mtd); ? #if defined(CONFIG_MTD_NAND_YAFFS2)?//add yaffs2 file system support ??? chip->ops.mode = oldopsmode; ? ??? return ret; OK,对yaffs2支持的代码已修改完毕,重新编译u-boot并下载到nand中,启动开发板,在u-boot的命令行输入:nand help查看nand的命令,可以看到多了一个nand write[.yaffs2]的命令,这个就是用来下载yaffs2文件系统到nand中的命令了。 ⑥、使用nand write[.yaffs2]命令把事前制作好的yaffs2文件系统下载到Nand Flash中(yaffs2文件系统的制作请参考后文),下载操作步骤和效果图如下: tftp 0x30000000 root.bin?//用tftp将yaffs2文件系统下载到内存的0x30000000位置 ? 2、Linux2.6.37下移植yaffs文件系统 原始的linux内核是不支持Yaffs2文件系统的,我们首先需要下载yaffs2的内核补丁,给内核打上yaff2补丁才能使内核支持该文件系统。 yaffs2?老版本不支持2.6.36以上内核。?网上下载的yaffs2常见版本(点击http://www.aleph1.co.uk/cgi-bin/viewcvs.cgi/下方的Download GNU tarball进行下载)一般不支持2.6.36/37。但2.6.36一下版本依然可以使用。 最新的yaffs2采用git发布,利用git工具下载到最新的yaffs2源代码,即可支持。办法是使用到www.yaffs.net发布的git方法获得最新版,并且查看readme确认其支持2.6.36/37。yaffs有一个较大的变化,是在2.6.36/37内核发布之后的一段时间里出现的,主要就是patch-ker.sh多了一个参数,m/s?是选择multi version支持,还是single version支持。(注意:在最新的linux版本下用multi version支持。) (1)下载源代码 如果系统已经安装git工具,就直接执行: git clone git://www.aleph1.co.uk/yaffs2 如果没有git工具,请首先下载安装git(http://git-scm.com/)。当然,也可以在windows下用git工具下载。 ?(2)给内核打补丁 yaffs源代码下载完后,放到某个目录下(但不要放在内核目录下!)进入yaffs源代码目录: #cd yaffs2 打补丁(注意参数顺序不能错): #./patch-kernel.sh?c?m??../linux-2.6.37.1 (3)然后配置内核: #cd???../linux-2.6.37.1? ?//返回内核根目录 #?make ARCH=arm CROSS_COMPILE=arm-linux-??menuconfig File systems --> Miscellaneous filesystems --> <*> YAFFS2 file system support (4)?重新编译内核 #?make ARCH=arm CROSS_COMPILE=arm-linux- 然后制作新的uImage,加载或者烧写到FLASH,如果能正确引导并加载yaffs文件系统则移植成功。 特别说明:一旦在使用新版本yaffs补丁之前使用过旧版本补丁,新版本的补丁则打不上了,建议使用新版本重新编译内核。 ======================= 需要注意:因为windows中下载导致文件编码和linux的不同。所以,如果是在windows下用git下载并传递到linux下的,则需要修改两个文件的编码: ?(1)?在linux下,进入yaffs2源代码目录 #vi patch-kernel.sh 然后在vi中执行如下命令: ?:set ff=unix 保存退出 然后修改权限使patch-kernel.sh具有可执行权限: #chmod? 755? patch-kernel.sh ?(3)修改fs/yaffs2/Kconfig的编码 #vi? fs/yaffs2/Kconfig 在vi中执行命令: :set? ff=unix 保存退出,按照上述步骤进行打补丁。 2、用busybox制作yaffs2根文件系统 所谓的根文件系统,就是创建各个目录,并且在里面创建各种文件,比如在/bin,/sbin/目录下存放各种可执行的程序,在/etc目录下存放配置文件,在/lib目录下存放库文件,下面就可以文件系统的移植。 1、根文件系统的目录结构 ? 2、建立根文件系统的目录 进入工作目录,创建一个shell的脚本用于构建根文件系统的各个目录。mkrootfs.sh,平且改变执行的权限。 sudo chmod 777?mkrootfs.sh 脚本内容如下: #!/bin/sh mkidr proc/sys mkidr proc/sys/kernel mkidr proc/sys/kernel/ echo?"make node in dev/console dev/null" ? 改变了tmp目录的使用权,让它开启sticky位,为tmp目录的使用权开启此位,可确保tmp目录底下建立的文件,,只有建立它的用户有权删除。 3、编译和安装Busybox Bosybox?是一个遵循?GPL v2协议的开源项目,它在编写过程总对文件大小进行优化,并考虑了系统资源有限(比如内存等)的情况,使用?Busybox?可以自动生成根文件系统所需的bin、sbin、usr?目录和?linuxrc?文件。? 首先下载busybox,下载地址:www.busybox.net 下载链接:http://www.busybox.net/downloads/busybox-1.18.3.tar.bz2 解压源代码: #tar?-jxvf? busybox-1.18.3.tar.bz2 修改Makefile中的交叉链和系统架构: CROSS_COMPILE ?=arm-linux- ARCH ?=arm 配置编译选项: 如果修改了Makefile则使用如下命令 #make? menuconfig 如果未修改Makefile则使用如下命令: #?make ARCH=arm CROSS_COMPILE=arm-linux- menuconfig ?[A]指定安装位置: Busybox Settings? ---> Installation Options ("make install" behavior)? ---> BusyBox installation prefix--> 输入:../rootfs?//实际中,要根据计划的文件系统根设定! [B]指定mdev动态文件系统 Linux System Utilities ---> [*]Support /etc/mdev.conf [*]Support command execution at device addition/removal 说明:在busybox中配置对dev下设备类型的支持dev的创建有三种方法:? ? 4、编译busybox? ? #etc/inittab ::sysinit:/etc/init.d/rcS ::respawn:-/bin/sh ::askfirst:-/bin/sh ::ctrlaltdel:/bin/umount -a –r ? 6、创建etc/init.d/rcS文件: #!/bin/sh 最后,还要改变它的属性,使它能够运行“ sudo chmod?777?etc/init.d/rcS 7、创建etc/fstab文件:? #device mount-point type option dump fsck order /etc/fstab/文件被用来定义文件系统的“静态信息”,这些信息被用来控制mount命令的行为,各个字段的含义以如下: #Ash profile 9、?制作根文件系统映像文件 我的目标板NandFlash是64MB的,所以要使用mkyaffs2image的64M版本这个可执行的文件生成映像文件。使用命令mkyaffs2image?rootfs?rootfs.img生成根文件系统映像文件。把生成的rootsfs.img文件烧写到nandFlash中的根文件系统区。重新引导操作系统即可实现文件系统的正确挂载。 ? 4、移植过程中遇到的问题及处理: 如果出现“Kernel panic - not syncing: Attempted to kill init!”错误,请在编译内核时选择EABI支持。 Kernel Features??---> [*] Use the ARM EABI to compile the kernel????????????????? [*]???Allow old ABI binaries to run with this kernel (EXPERIMENTA) 把这个选上重新编译就可以了,如果文件系统镜像也是新做的则也要考虑文件系统本身有问题的可能性。此外请注意mkyaffs2image?工具是否正确,我使用友善之臂的工具就出现此错误,但是使用天嵌提供的工具则可以正常使用。 如果出现“Failed_to_execute_/linuxrc”可以根据下面的建议逐个检查。 5、配置内核时是否取消ECC(我遇到此问题是通过取消ECC解决此问题。) NAND Flash support for Samsung S3C SoCs ???□Samsung S3C NAND Hardware ECC 第6页:支持内核引导 为了让U-boot支持内核引导,需要涉及u-boot和linux内核的配合,u-boot传递启动参数给linux内核。其中以machine ID最为重要,是内核能够正确引导的先决条件。其他参数则通过gd->bd数据结构传递给内核。 1、u-boot的配置和修改 首先需要在includeconfigssmdk2440.h中加入以下宏定义: #define CONFIG_SETUP_MEMORY_TAGS? ? 1?//如果没有定义这个参数,则uboot参数必须加入men=内存大小 #define CONFIG_INITRD_TAG??????????? 1 #define CONFIG_CMDLINE_TAG? ???????? 1?//设置bootargs出入内核必须 #define CONFIG_BOOTARGS??? ???? "root=/dev/mtdblock3 rw rootfstype=yaffs noinitrd init=/linuxrc console=ttySAC0,115200 ip=192.168.0.105:192.168.0.7:192.168.0.1:255.255.255.0:comleader:eth0:off" #define CONFIG_BOOTCOMMAND? "nand read 0x30008000 0x50000 0x200000;bootm 0x30008000" #define CONFIG_MTD_NAND_YAFFS2?? 1?//定义一个管理对Yaffs2支持的宏 //开启Nand Flash默认分区,注意此处的分区要和你的内核中的分区保持一致 #define MTDIDS_DEFAULT "nand0=nandflash0" #define MTDPARTS_DEFAULT "mtdparts=nandflash0:192k(bootloader)," ???????????????????? "64k(params)," ???????????????????? "2m(kernel)," ???????????????????? "-(root)" ? 修改boardsamsungsmdk2440smdk2440.c中的machine id: gd->bd->bi_arch_number = MACH_TYPE_SMDK2440; /*1008*/ ? 然后编译,发现有错误,有未定义函数,这又是新版本的一个BUG,在archarmlibbootm.c文件中增加头文件: #include <lmb.h>?? /*add by bsc*/ 编译之后运行,下载uImage到0x30008000地址,然后用GO命令直接运行: Tftp 0x30008000 uImage Go 0x30008040 出现错误“Error: unrecognized/unsupported machine ID (r1 = 0x338afef0).” 此时r1 = 0x338afef0,实际上R1中应该存有uboot传递给linux内核的machine ID?但是此时显然不是。这是因为go命令并未传递任何参数。因此我们通过bootm命令来引导: tftp 0x30008000 uImage bootm 0x30008000 ? 但是仍然在“Starting kernel ..”地方死机。找到到此处位置在archarmlibbootm.c中: static void announce_and_cleanup(void) { ????? printf("nStarting kernel ...nn"); ? #ifdef CONFIG_USB_DEVICE ????? { ?????????? extern void udc_disconnect(void); ?????????? udc_disconnect(); ????? } #endif ????? cleanup_before_linux(); } 怀疑cleanup_before_linux()函数有问题,以前的版本没有此函数,因此暂时注销此函数: static void announce_and_cleanup(void) { ????? printf("nStarting kernel ...nn"); ? #ifdef CONFIG_USB_DEVICE ????? { ?????????? extern void udc_disconnect(void); ?????????? udc_disconnect(); ????? } #endif ??????//cleanup_before_linux();/*delete by bsc */ } 重新编译,更新uboot之后再次引导内核,引导成功。此时的内核尚没有文件系统支持。cleanup_before_linux()函数的问题后续进一步研究。 然后,我们将内核烧写入NAND FLASH?然后让系统自动引导。我们可以在commonenv_common.c文件中的default_environment[]数组中增加: ???"kk="?? "t 0x30000000 zImage;nand erase 0x50000 0x300000;nand write 0x30000000 0x50000 0x200000" " " ?? "yy="?? "t 0x30000000 rootyaffs2.img;nand erase 0x250000 0x3db0000;nand write.yaffs2 0x30000000 0x250000 $(filesize)" " " ?? "firstboot=" "set bootcmd $(normalboot);save;nand erase 0x50000 0x3f00000;run kk;run yy" " " ?? "normalboot="?? "nand read 0x30008000 0x50000 0x200000;bootm 0x30008000" " " 然后我们只需用run kk命令即可实现内核的下载和烧写。重启之后通过bootm 0x30008000来实现引导。 2、制作u-boot能够直接引导的linux内核。 首先linux启动过程中需要校验machine ID,因此我们修改修改linux内核的文件archarmtoolsmach-types中: s3c2440????? ARCH_S3C2440??? S3C2440?????? 1008 //1008,与uboot中一致 说明:不建议直接修改arch/arm/kernel/head.S文件通过R1寄存器直接传递machine ID给内核。 U-boot并不能直接支持linux的zImage,u-boot支持的镜像文件格式为uImage。通 常,kernel的启动需要u-boot提供一些参数信息,比如ramdisk在RAM中的地址。经过编译后的u-boot在根目录下的tools目录 中,会有个叫做mkimage的工具,他可以给zImage添加一个header,也就是说使得通常我们编译的内核zImage添加一个数据头信息部分,我们把添加头后的image通常叫uImage,uImage是可以被u-boot直接引导的内核镜像。 mkimage工具的使用:中括号括起来的是可选的 mkimage [-x] -A arch -O os -T type -C comp -a addr -e ep -n name -d data_file[:data_file...] image 选项: 先将u- boot下的tools中的mkimage复制到主机的/usr/local/bin目录下,这样就可以在主机的任何目录下使用该工具了。现在我们进入?kernel生成目录(一般是arch/arm/boot目录),然后执行如下命令,就会在该目录下生成一个uImage.img的镜像文件,把他复制到?tftp目录下,这就是我们所说的uImage。 mkimage?-n?'linux-2.6.37.1'?-A arm?-O linux?-T kernel?-C none?-a 0x30008000?-e 0x30008000?-d zImage uImage ? 设置修改u-boot的启动参数,在u-boot命令行下输入: //设置启动参数,意思是将nand中0x50000-0x00200000(和kernel分区一致)的内容读到内存0x30008000中,然后用bootm命令来执行: set bootcmd 'nand read 0x30008000 0x50000 0x00200000;bootm 0x30008000' saveenv??//保存设置 把uImage用tftp下载到内存中,然后再固化到Nand Flash中,操作如下: tftp 0x30000000 uImage??//将uImage.img下载到内存0x30000000处 最后,我们重新启动开发板,可以看到,内核被u-boot成功引导起来了。 说明:linux最新版本的交叉编译过程参见另外的文章。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |