DM646x的启动程序备份机制实现(二)
第二部分,kernel与rootfs的备份
下面对kernel与rootfs的备份方法进行研究,主要是回答了下面几个问题:
1,kernel是如何写入的?
2,rootfs的概念
3,rootfs是如何写入的?
4,kernel与rootfs写在什么位置上?
5,由谁来备份?
6,由谁来使用备份?
7,具体如何实现备用功能?
1,kernel是如何写入的?
?????? kernel是在uboot中写入的。一般的步骤是通过tftp下载到内存中,然后写入到nand flash中。例如如下命令:
tftp 0x80700000 uImage???//从tftp服务器拷贝至内存中
nand erase 0x200000 0x200000? ??//擦除2M的空间
nand write 0x80700000 0x200000 0x200000?//从内存拷贝至nand flash中
由这些命令,可以知道,只需要指定不同的nand 地址,很容易实现多次写入内核。
2,rootfs的概念
?????? rootfs即根文件系统。 Linux启动时,第一个必须挂载的是根文件系统;若系统不能从指定设备上挂载根文件系统,则系统会出错而退出启动。根文件系统包含系统引导和使其他文件系统得以挂载(mount)所必要的文件。根文件系统包括Linux启动时所必须的目录和关键性的文件,例如Linux启动时都需要有init目录下的相关文件,在 Linux挂载分区时Linux一定会找/etc/fstab这个挂载文件等。
3,rootfs是如何写入的?
?????? 通常有两种方法:在uboot下烧写,或者使用nfs启动系统,然后在linux下烧写。
?????? (1)在uboot下烧写
?????? 在uboot下烧写时,需要注意uboot烧写nand的方式,是否与内核中使用的方式相同,特别是nand的ecc校验方式,在不同版本的uboot与不同的内核版本中,都会有所不同。另外,不同的文件系统也会有不同的需求。
步骤:
tftp 0x90700000 root_fs.jffs2???//从tftp服务器拷贝至内存中
nand erase 0x800000 0x700000??//擦除6M的空间
nand write.jffs2 0x90700000 0x800000 0x700000//从内存拷贝至Flash中
?????? (2)在nfs下烧写
?????? 通常,在nfs启动linux系统后的烧写方式是安全的。步骤如下:
?????? 先在linux服务器下建立一个目录,在该目录下存放根文件系统所有文件。将该目录设置为nfs可访问目录,并从板卡的uboot中设置为启动的根文件系统。
在linux服务器下生成映像文件:
./mkfs.jffs2 -n -s 2048 -e 128KiB -d /home/root/root_fs -o root_fs.jffs2 --pad=0x700000
启动板卡,运行起来linux系统后,使用:
flash_eraseall /dev/mtd3? //删除整个分区
nandwrite -a? -m -p /dev/mtd3 /root_fs.jffs2?? //写入文件系统内容
重启板卡,设置使用flash上的文件系统即可。
4,kernel与rootfs写在什么位置上?
?????? 通常,kernel是存放在uboot之后,是在uboot的烧写命令中确定的。而rootfs存放在kernel之后,这个位置,是由内核指定的分区情况来决定的。具体的使用情况,在本部分的结尾有一个实例。
5,由谁来备份?
?????? kernel的备份,是在uboot下通过命令烧写的。多次烧写,指定不同地址即可。
?????? rootfs的备份,这里涉及到nand的分区了。在内核启动前,都是直接使用偏移地址来访问nand上存放的东西,内核启动后,就使用分区的概念进行访问数据了。
?????? 首先,要将nand分为多个区,包括ubl、uboot、内核、文件系统四大部分。在文件系统这个概念下,由于要做备份,就需要至少分出两个区。通常的做法,是分3个区,一个是数据与应用程序区,比较大,存放所有与应用相关的代码与数据。另外两个分区都存放同样的rootfs,由于把应用程序分离出去,就可以将rootfs做得很小,这样便于节省存储空间,实现在一个nand上保存两份rootfs。
?????? 做好rootfs之后,就可以采用第3步介绍的方法烧写了。
6,由谁来使用备份?
?????? kernel的备份使用,是在uboot下设置的启动参数来使用的。当然,也可以修改uboot源码来实现,但是由于uboot的启动参数比较灵活,已经能够实现,就不需要拿把牛刀来杀鸡了。
?????? 假定两次烧写的位置分别是2M与5M的位置,可以如下设置启动参数:
setenv bootcmd 'nboot 0x80700000 0 0x200000; bootm;nboot 0x80700000 0 0x500000; bootm'
?????? 对于bootcmd命令,会一句一句的执行。执行第一句nboot 0x80700000 0 0x200000,就是从nand 偏移地址2M的地方读取内核,然后执行第二句bootm,即进行启动。若启动失败,会执行第三句,后面的过程就是类似的操作了,只是内核的偏移地址不同。
?????? rootfs的备份使用,是内核来实现的,需要修改内核源码,在启动内核成功后,寻找有效的rootfs时,若发现不是有效的,就去寻找第二个rootfs。
7,具体如何实现备用功能?
?????? 备份的使用,是在默认启动程序有问题的时候,才启用的。而这个判断默认启动程序是否有问题,是需要上一级的启动程序来进行判断的。所以,内核的默认启动程序是否异常,需要uboot来判断,出了异常后,如何处理,是否启用备用程序,也是由uboot来决定的。同样,rootfs的备份是否使用,是依赖于kernel程序的。
?????? 对于kernel的备份与使用,在uboot已经支持,只要配置好启动参数就行了。
?????? 对于rootfs的备份,首先需要修改内核的分区情况,然后需要在读取rootfs时添加有效性判断,并进行异常后的再次处理。
?
?烧写之后的nand存储格局示例:
?
?第0个块 (0-128k)为空。
?第1个块 (20000存放块头)保存了ubl? ,20800--238ab
?第2个块 (40000存放块头),ubl
?第3个块 (60000存放块头),ubl
?第4个块 (80000),没有块头信息,存放uboot的参数。
?第5个块 (a0000存放块头),ubl
?第6-7个块? (C0000存放块头),?? 保存uboot,c0800--e261b
?第8-9个块? (100000存放块头),? 保存uboot,100800--12261b
?第10-11个块 (140000存放块头),? 保存uboot,140800--16261b
?第12-13个块 (180000存放块头),? 保存uboot,180800--1a261b
?第14-15个块 (1c0000存放块头),? 保存uboot,1C0800--1e261b
200000-400000?uImage??16-31
400000-500000?空??32-39?-留空
500000-700000?uImage??40-55
700000-800000?空??56-63?-留空
0800000-0F00000?空??7M,第一个rootfs
0F00000-1000000?空??1M?-留空
1000000-1700000?空??7M,第二个rootfs
1700000-1800000?空??56-63?-留空
1800000-7800000?空??96M,存放应用程序的分区
?
说明:
?????? 我使用的nand flash,一个块的大小为128k,总大小为128M。
?????? 只所以每两个数据块之间,都要留空,是考虑到在使用flash烧写器进行整片nand数据拷贝时,可能会遇到坏块,需要将有效数据往后平移,从而避免覆盖后面的有效数据。?