二 ok6410tftp下载内核,文件系统,地址整理
飞凌官方提供了一键下载烧写linux的方式,相对来说比较方便,但是对于开发来说不够灵活,因此这篇文章把tftp相关的点介绍一下,整理下其中遇到的一些问题。
一键烧写本质上是启动位于SD卡中的Uboot,通过uboot读取sd卡中的文件到SRAM最后通过nand指令实现一键烧写,这一块可以参考飞凌提供的uboot源码中include\configs 中的smdk6410.h 的529行,代码如下:
代码1:
#elif defined(FORLINX_BOOT_SD) #define FORLINX_DEBUG #define CONFIG_MMC 1 #define CONFIG_LCD #define CONFIG_BOOT_MOVINAND #define CFG_ENV_IS_IN_MOVINAND #define CONFIG_BOOTCOMMAND "nand led-start;nand erase ;fatload mmc 0:1 0x50008000 u-boot.bin;nand write.uboot 0x50008000 0 0x200000;fatload mmc 0:1 0x50008000 zImage;nand write.e 0x50008000 0x200000 0x500000; fatload mmc 0:1 0x50008000 rootfs.yaffs2; nand write.yaffs2 0x50008000 0x00700000 $filesize; nand beep; nand led-end"
从这段代码代码可以看出,uboot中通过宏定义的方式,当定义为FORLINX_BOOT_SD 式通过对相应配置相应的环境变量完成特定的操作,其中定义CONFIG_BOOTCOMMAND 后就可以自动进行nand的查处,从sd卡加载uboot等,这段代码内容稍后继续分析。
下面说一下tftp和地址相关的知识总结
tftp是指通过tftp协议通过网络的方式进行文件传输,需要说明的是ok6410的出厂uboot是不支持网络的,这也就意味着nfs根文件系统以及通过tftp下载内核等都无法操作,其实解决这个问题也很简单,只需要替换网卡相关的文件就可以了,改动不是很大,这个可以找到很多资料,这里不再赘述。不过飞凌在12年9月的更新光盘中已经做了更新,uboot已经支持网络操作了,查一下源码也就是改了那几个文件,因此可以下载烧写最新版uboot。
在进行tftp的操作时最开始可能容易搞混的就是烧写内核啥的应该烧写到哪一个地址去,最开始也有点混,比如有人的博客里是tftp c0008000 zImage 这个地址是c0008000,国嵌的视频教程中是c0800000,各不相同,没看到具体的叙述,而在通过usb等方式中通过usb传送的地址是50008000,因此可能会存在混乱,因此觉得有必要在博客中总结一下。关于地址空间的分配首先还需要看一下芯片手册。芯片手册中关于地址空间的安排如图所示。
有一点需要说明的是,图中的地址空间是针对通过地址总线与数据总线进行操作的设备的,通过不同的片选信号来确定对应的地址,所以可以通过图中查表可以确定ok6410的256M RAM的地址范围为0x50000000-0x5FFFFFFF 256M的地址空间,因此通过tftp下载到0x50008000也就是加载到RAM中(向后偏移了32K的地址,稍后在介绍)。到这儿对于0x50008000这个地址的由来就初步了解了。
再来看看很多资料中都提到的0xc0008000这个地址,smdk6410.h这个文件的501行可以找到这部分配置:
代码2
//uboot-2M ,zImage-5M ,FS-200M,user-other #define CFG_NAND_ERASE_LEN 0xCF00000 //200MB #if defined(FORLINX_BOOT_NAND) #define CONFIG_BOOT_NAND #define CFG_ENV_IS_IN_NAND //#define CFG_NAND_LARGEPAGE_SAVEENV //#define CFG_NAND_FLASH_BBT #define CONFIG_BOOTCOMMAND "nand read 0xc0008000 0x200000 0x500000;bootm 0xc0008000"
这部分定义了nand flash的地址空间划分和启动的地址:bootm 0xc0008000,也就是说是从内存中的这个地址启动内核的,但问题是在上图的地址划分中地址最大值也只到0x6FFFFFFF,0xc0008000这个地址是什么地方呢?一样从源码入手,继续找!
同样从smdk6410.h这个文件的452行可以找到这部分配置。
代码3
/* base address for uboot */ #ifdef CONFIG_ENABLE_MMU #define CFG_UBOOT_BASE TEXT_BASE #define CFG_PHY_UBOOT_BASE (MEMORY_BASE_ADDRESS + (TEXT_BASE - 0xC0000000)) #else #define CFG_UBOOT_BASE TEXT_BASE #define CFG_PHY_UBOOT_BASE TEXT_BASE #endif
看了这段代码就明白了,在使能了MMU之后,这段代码相当于对地址做了一个重映射,经过(MEMORY_BASE_ADDRESS + (TEXT_BASE - 0xC0000000))计算后,因为MEMORY_BASE_ADDRESS 为0x50000000(可以在文件开始找到定义)所以经过这样的一个计算,0xc0008000就是0x50008000。而0xc0008000是内核启动的起始虚拟地址,因此需要做这样的一个映射来和内核对应。
到这儿可能很多人和我当初有一样的疑惑,那就是如果tftp烧写文件系统应该烧写到哪一个地址去呢?在回到上面的地址图表,在最开始我就说过,这个表是针对使用地址总线与数据总线操作的设备而言,因此对于NOR flash、SRAM、DRAM等都是可以直接寻址读写的,而对于Nand Flash,可以参考下电路图,使用的是8个IO进行操作,右Nand控制器弯沉相关的操作,因此是没有一个绝对的地址的。需要注意图表中的黄色框部分,One Nand并不是普通Nand Flash,区别就在于这种Nand是和NOR、SRAM一样的通过地址总线、数据总线进行操作的方式,因此它是有地址的,对于板子所用的Nand Flash来说只有偏移地址,没有绝对地址。
到这里,对于tftp下载内核、文件系统的相关操作应该清楚了,具体地址其实看看uboot源码就清楚了,可以参考代码1中的这部分:
#define CONFIG_BOOTCOMMAND "nand led-start;nand erase ;fatload mmc 0:1 0x50008000 u-boot.bin;nand write.uboot 0x50008000 0 0x200000;fatload mmc 0:1 0x50008000 zImage;nand write.e 0x50008000 0x200000 0x500000; fatload mmc 0:1 0x50008000 rootfs.yaffs2; nand write.yaffs2 0x50008000 0x00700000 $filesize; nand beep; nand led-end"
如果通过sd卡启动时跳过自动操作进入手动选择操作的话就应该有印象,可以单独选择烧写某一个文件,例如单独烧写文件系统,操作如下图所示:
那么通过找到对应的命令源码也是可以的,源码位于common/mian.c 343行:
void arm_USBfuse(void) { unsigned char select; while(1) { printf("\n##### Select the fuction #####\n"); printf("[1] Flash u-boot\n"); printf("[2] Flash kernel\n"); printf("[3] Flash system\n"); printf("[4] Exit\n"); printf("Enter your Selection:"); select = getc(); printf("%c\n", select >= ' ' && select <= 127 ? select : ' '); void arm_sdfuse(void) { unsigned char select; while(1) { printf("\n##### flash from SDcard #####\n"); printf("\n##### Select the fuction #####\n"); printf("[1] Flash all image\n"); printf("[2] Flash u-boot\n"); printf("[3] Flash kernel\n"); printf("[4] Flash system\n"); printf("[5] Exit\n"); printf("Enter your Selection:"); select = getc(); printf("%c\n", select >= ' ' && select <= 127 ? select : ' '); switch(select) { case '1': ExecuteCmd("nand erase"); ExecuteCmd("fatload mmc 0:1 50008000 u-boot.bin"); ExecuteCmd("nand write.uboot 50008000 0 200000"); ExecuteCmd("fatload mmc 0:1 50008000 zImage"); ExecuteCmd("nand write.e 50008000 200000 500000"); ExecuteCmd("fatload mmc 0:1 50008000 rootfs.yaffs2"); ExecuteCmd("nand write.yaffs2 50008000 700000 $filesize"); break; case '2': ExecuteCmd("nand erase 0 200000"); ExecuteCmd("fatload mmc 0:1 50008000 u-boot.bin"); ExecuteCmd("nand write.uboot 50008000 0 200000"); break; case '3': ExecuteCmd("nand erase 200000 500000"); ExecuteCmd("fatload mmc 0:1 50008000 zImage"); ExecuteCmd("nand write.e 50008000 200000 500000"); break; case '4': ExecuteCmd("nand erase 700000"); ExecuteCmd("fatload mmc 0:1 50008000 rootfs.yaffs2"); ExecuteCmd("nand write.yaffs2 50008000 700000 $filesize"); break; case '5': return; default: break; } } }
通过tftp单独烧写内核或者文件系统时只需要参考一键烧写的命令烧写到对应的nand 偏移地址即可。