系统分区

Version 1.0


1. 分区介绍


1.1. SPI-NOR Flash基本分区介绍

ALKAID在make image完成后会打印所有分区的layout:

IPL: CPU上电后首先跑到的是rom code,顾名思义代码保存在特殊的ROM中,且是只读的。ROM code跑完后会读取NOR Flash 0地址的位置,这个位置就是IPL文件存放的位置,IPL里主要功能是做一些基础的硬件初始化,例如设定当前DDR参数,以及GPIO/IIC相关等。

IPL_CUST: IPL初始化的是一些共有的硬件模块,IPL_CUST中会根据当前板子的实际情况初始化客制化板子硬件的可执行的二进制文件,例如客制化的GPIO管教,IIC配置。

CIS: 包含 sni (default flash info),pni(partition table),sni_list(flash support list)。

UBOOT: UBOOT的二进制文件存放分区。

UBOOT_ENV: UBOOT的环境变量存放分区。

SPI-NOR的BOOT分区中的内容是不建议改动的,若有不符合公板release的地方,可能会导致系统无法启动。

BOOT的位置在mtd block0的位置上。

BOOT分区之后的分区,统称为SYS分区,SYS分区是可以修改的,根据实际的使用情况,大致分为:

rtos: 存放rtos的二进制文件。

misc: 公板定义的一个分区,用来存储一些配置文档,iq bin。文件系统默认fwfs。


1.2. SPI-NAND Flash基本分区介绍

Layout图:

CIS: 包含 sni (default flash info),pni(partition table),sni_list(flash support list)。

IPL: IPL分区的作用与SPI-NOR分区一样,但是从上图可知,IPL在spi-nand上保存了六份,每个block一份,目的是为了防止坏块而做的备份。

IPL_CUS: 作用同SPI-NOR,会有两个分区,IPL_CUS0, IPL_CUS1,每个分区中各三份IPL_CUS的data。

UBOOTL: UBOOT的二进制文件存放分区, 会有两个分区,每个分区中一份data。

ENV: UBOOT的环境变量存放分区。

以上是BOOT相关的分区信息,这部分无法任意修改。

rtos: 存放rtos的二进制文件。

misc: 公板定义的一个分区,它用来存储一些配置文档,iq bin。文件系统默认fwfs。


2. 分区变更


2.1. 分区变更前注意事项

无论是spi-nor flash上的分区,还是spi-nand flash上的分区。都可归为两类:

  1. 不建议改动的boot

  2. 可以变动的sys

本章介绍的分区变更都是在sys这部分上,包括如何配置脚本变更分区顺序,如何打包分区,如何生成烧录脚本,若用户有自己的一套打包和烧录的流程,可以忽略本章。


2.2. 分区变更的脚本代码架构介绍

分区变更分为分区制作、打包和分区烧录脚本制作这两部分,下面流程图的两个分支,左边走的是分区制作、打包流程,右边走的是分区烧录脚本制作的流程,分区烧录脚本仅支持tftp升级脚本,暂不支持usb升级脚本制作。

xxx.partition.config:

这是总的分区配置信息脚本,所有与分区调整相关的代码都在这个config文件中实现,这个config文件会有很多份,每个不同的chip、spinand分区还是spinor分区都会有各自的分区config文件。

通过build config,就可以找到该项目使用的分区config文件是什么,例如:

project/configs/defconfigs/usbcam-rtos_p3_nor.glibc-9.1.0-021a.64.qfn128_defconfig

此配置脚本中,变量IMAGE_CONFIG可以找到对应使用的分区配置脚本。

此项目的分区配置脚本存放的路径在:

project/image/configs/p3/nor-ramdisk.rtos.squashfs.partition_uvccam.config

可以看出,这是spinor flash分区配置脚本文件。

在分区config文件中用变量定义了分区BOOT的部分和SYS的部分:

Spinor:

cis$(BOOTTAB0) = ”xxx”
cis$(SYSTAB) = ”xxx”

Spinand:

cis$(BOOTTAB) = xxx
cis $(SYSTAB) = xxx

在config脚本文件中,每个分区由一组变量表示,cis是分区的一组变量之一,该分区很特殊,存放的是一组规定的分区配置raw data,这个是一个特殊的分区,特殊的分区由特别的指令生成,在后面章节会有介绍。

rootfs.mk:

ROOTFS和miservice分区制作脚本

project/image/configs/p3/rootfs.mk

script_usbcam-rtos.mk:

制作spi-nand和spi-nor烧录脚本的脚本

project/image/configs/p3/script_usbcam-rtos.mk

image.mk:

分区打包脚本

project/image/image.mk

2.3. 分区位置变更

2.3.1. Spinor flash

改变cis$(SYSTAB)中所定义的分区前后位置即可,语法格式与linux uboot中使用的mtdpart是一样的,这个变量的值也会保存到uboot中的环境变量中。

cis$(SYSTAB) = "$(misc$(MTDPART)),$(rtos$(MTDPART)) "

其中rtos和misc的分区信息由逗号 ’ , ’ 隔开。


2.3.2. Spinand flash

改变cis$(SYSTAB)中所定义的分区前后位置即可,语法格式与uboot中使用的mtdpart是一样的,这个变量的值也会保存到uboot中的环境变量中。

cis $(SYSTAB) =0x60000(ENV),$(misc$(MTDPART),$rtos$(MTDPART),$uboot$(MTDPART))

其中rtos和misc的分区信息由逗号 ’ , ’ 隔开。


2.4. 特殊分区处理

rtos、uboot、IPL等分区属于特殊分区,这些分区没有特别的文件系统,所以无法在Makefile脚本中做集中处理,必须by case去处理。因此添加一个特殊的分区需要清楚了解如下两个步骤:

2.4.1. rtos分区处理

image.mk中需要写上分区打包的脚本命令。例如rtos分区打包命令:

rtos_nofsimage:

@echo [[$@]]
#@$(PREFIX)objcopy -O binary -R .bss -R .bss_sram $($(patsubst %_nofsimage,%,$@)$(RESOUCE)) $(IMAGEDIR)/$(patsubst %_nofsimage,%,$@)
cp $($(patsubst %_nofsimage,%,$@)$(RESOUCE)) $(IMAGEDIR)/$(patsubst %_nofsimage,%,$@)

script_usbcam-rtos.mk中写上分区烧录脚本生成的命令。

例如制作rtos分区烧录脚本的脚本命令:

rtos_$(FLASH_TYPE)__script:
    @echo "# <- this is for comment / total file size must be less than 4KB" > $(SCRIPTDIR)/[[rtos.es
    @echo tftp $(TFTPDOWNLOADADDR) rtos >> $(SCRIPTDIR)/[[rtos.es
    @echo $(FLASH_PROBE) >> $(SCRIPTDIR)/[[rtos.es
    @echo $(FLASH_ERASE_PART) RTOS >> $(SCRIPTDIR)/[[rtos.es
    @echo $(FLASH_WRITE_PART) $(TFTPDOWNLOADADDR) RTOS \$${filesize} >> $(SCRIPTDIR)/[[rtos.es
    ifeq ($(FLASH_TYPE), spinand)
        @echo $(FLASH_ERASE_PART) RTOS_BACKUP >> $(SCRIPTDIR)/[[rtos.es
        @echo $(FLASH_WRITE_PART) $(TFTPDOWNLOADADDR) RTOS_BACKUP \$${filesize} >> $(SCRIPTDIR)/[[rtos.es
    endif
        @if [ -n "$(rtos$(BLKENV))" ]; then                     echo -e "$(rtos$(BLKENV))" | sed 's/^/setenv /g' >> $(SCRIPTDIR)/[[rtos.es;                     echo saveenv >> $(SCRIPTDIR)/[[rtos.es;         fi;
    @echo "% <- this is end of file symbol" >> $(SCRIPTDIR)/[[rtos.es

2.4.2. 带备份的分区处理

SPINAND的分区中IPL、IPL_CUST、UBOOT这些分区一般会有好几个备份,例如IPL在烧录时,每个IPL的data会在每个block开始各占一份,一个block有128kb这么大,一般IPL的data不超过20kb,因此假设IPL的数据有六个备份,那么整个IPL分区会有6个block这么大,那么在分区打包的时候会用到dd命令把IPL分区进行打包,使输出的bin文件能够与IPL分区完全映射,六份ipl的data各自分布在每个block的开头。

若要设置带备份的分区,可以按照如下代码设定:

ipl$(RESOUCE) = $(PROJ_ROOT)/board/$(CHIP)/boot-rtos/ipl/IPL.bin
ipl$(DATASIZE) = 0x20000
ipl$(COPIES) = 6
ipl$(BKCOUNT) = 5
ipl$(PATSIZE) = $(call multiplyhex, $(ipl$(COPIES)), $(ipl$(DATASIZE)))
ipl$(MTDPART) = $(ipl$(DATASIZE))@$(set_partition$(CISSIZE))(IPL0)$(ipl$(BKCOUNT))

‘ipl$(COPIES)’表示IPL的data会有多少个备份。

‘ipl$(DATASIZE)’表示一份data的大小,ipl的bin文件若不超过1个block的大小则按照1个block的大小来算。

‘ipl$(PATSIZE)’是IPL实际分区的大小,makefile中做了一个乘法计算,就是备份的个数乘以data大小。

‘ipl$(BKCOUNT)’是PNI数据结构中特有的一种数据,在系统真正跑起来时,若没有坏块的情况下,系统默认使用的是ipl的第一份data,但是第一份data所在的block产生坏块,则ROM code会偏移一个block去找ipl,这个BKCOUT变量就是告诉ROM code可以偏移block的最大个数。

‘ipl$(MTDPART)是给’pnigenerator用作解析分区配置的变量,它会传递给cis$(BOOTTAB)或者cis$(SYSTAB),若没有BKCOUNT的情况下,语法格式符合uboot mtaparts的标准,而在没有定义变量MTDPARTS的情况下,uboot在执行write cis命令时会解析pni的值,并且转换成mtdparts字串保存在环境变量中。


2.5. SPINAND的PARTINFO

通过工具pnigenerator生成的PARTINFO.pni,保存在CIS分区中,其中包括一些spinand的基本信息。

执行命令:

pnigenerator -s 64 -p 2048 -b 64 -k 1024 -u 8 -l 0x20000 -t "0x60000(CIS),
0x20000@0x60000(IPL0),0x20000(IPL1),0x20000(IPL2),0x20000(IPL_CUST0),
0x20000(IPL_CUST1),0x20000(IPL_CUST2),0x60000(UBOOT0),0x60000(UBOOT1),
0x20000(ENV)" -y "0x500000(KERNEL),0x500000(RECOVERY),0x600000(rootfs),-(UBI)" 
-o /home/malloc.peng/ALKAID/project/image/output/images/boot/PARTINFO.pni

pnigenerator [options] 参数含义:

-s Spare byte count.
-p Page byte count.
-b Block page count.
-k Block count.
-u Unit byte count.
-l Block size.
-t BOOT Part.
-y SYS Part.
-r Dump pni file.
-o Output file path.

pnigenerator工具的源码路径:

project/image/makefiletools/src/pnigenerator/pnigenerator.c

利用服务器上的gcc编译:

gcc pnigenerator.c –o pnigenerator

PARTINFO.bin中保存BOOT part的分区信息就已经足够,其他的分区可以追加到uboot的mtdparts中。


3. ONE BIN介绍

ONE BIN功能是基于ALKAID的打包脚本通过dd命令使BOOT PART分区合并成一个bin,它可以支持spinand和spinor的两种分区打包方式。

project/image/image.mk中有dd合并bin的具体做法。


3.1. Spinor

参考脚本:

project/image/configs/p3/nor-ramdisk.rtos.squashfs.partition_uvccam.config

与普通的打包脚本对比:

  1. 增加了需要合并的分区名。

    BOOT_IMAGE_LIST = ipl csi ipl_cust uboot
    
  2. 合并的分区从IMAGE_LIST中剔除,并把合并后的分区名 ’ boot ’ 加上。

    IMAGE_LIST = boot misc rtos
    
  3. 在config文件中添加sstar分区。

    sstar $(RESOUCE) = $(IMAGEDIR)/sstar.bin
    sstar $(PATSIZE) = 0x100000
    sstar $(MTDPART) = $(sstar$(PATSIZE))(SSTAR)
    
  4. 同时在image.mk和script_usbcam-rtos.mk中需要添加sstar的image生成脚本和tftp烧录脚本:

    image.mk:

    boot_nofsimage: $(BOOT_TARGET_NOFSIMAGE) $(BOOT_TARGET_FSIMAGE)
    @echo [[$@]]
    dd if=/dev/zero of=$(boot$(RESOUCE)) bs=1 count=0
    

    script_usbcam-rtos.mk:

    uboot_$(FLASH_TYPE)__script:
    @echo "# <- this is for comment / total file size must be less than 4KB" > $(SCRIPTDIR)/[[uboot.es
    @echo tftp $(TFTPDOWNLOADADDR) uboot_s.bin >> $(SCRIPTDIR)/[[uboot.es
    @echo $(FLASH_PROBE) >> $(SCRIPTDIR)/[[uboot.es
    @echo $(FLASH_ERASE_PART) UBOOT0 >> $(SCRIPTDIR)/[[uboot.es
    @echo $(FLASH_WRITE_PART) $(TFTPDOWNLOADADDR) UBOOT0 \$${filesize} >> $(SCRIPTDIR)/[[uboot.es
    @echo $(FLASH_ERASE_PART) UBOOT1 >> $(SCRIPTDIR)/[[uboot.es
    @echo $(FLASH_WRITE_PART) $(TFTPDOWNLOADADDR) UBOOT1 \$${filesize} >> $(SCRIPTDIR)/[[uboot.es
    @echo "% <- this is end of file symbol" >> $(SCRIPTDIR)/[[uboot.es
    

3.2. Spinand

参考脚本:

project/image/configs/p3/spinand-ramdisk.rtos.partition_uvccam.config

与普通的打包脚本对比:

  1. 增加了需要合并的分区名。

    BOOT_IMAGE_LIST = ipl ipl_cust uboot
    
  2. 合并的分区从IMAGE_LIST中剔除,并把合并后的分区名 boot 加上。

    IMAGE_LIST = cis boot misc rtos
    
  3. MTDPART设定更新:

    MTDPARTS = "mtdparts=nand0:$(boot$(MTDPART)),$(cis$(SYSTAB))"
    
  4. 确认分区多份copy

    ipl_cust$(RESOUCE) = $(PROJ_ROOT)/board/$(CHIP)/boot-rtos/ipl/IPL_CUST.bin
    ipl_cust$(DATASIZE) = 0x20000
    ipl_cust$(COPIES) = 3
    ipl_cust$(BKCOUNT) = 2
    ipl_cust$(PATSIZE) = $(call multiplyhex, $(ipl_cust$(COPIES)), $(ipl_cust$(DATASIZE)))
    ipl_cust$(PATCOUNT) = 2
    ipl_cust$(MTDPART) = $(ipl_cust$(DATASIZE))(IPL_CUST0)$(ipl_cust$(BKCOUNT)),$(ipl_cust$(DATASIZE))(IPL_CUST1)$(ipl_cust$(BKCOUNT))
    

    请注意PATSIZE要根据当前的data大小和一个分区中所包含的data个数而定。

    例如ipl_cust的data数量有六份,因此COPIES = 6。

    Data各自分散在两个分区中(IPL_CUST0/IPC_CUST1),每个分区占三份data,每一份data的size为0x20000,因此,PATSIZE为0x20000 * 3 = 0x60000。

  5. 在config文件中添加boot分区。

    boot$(RESOUCE) = $(IMAGEDIR)/boot.bin
    boot$(PATSIZE) = $(shell printf 0x%x $(shell stat -c "%s" $(boot$(RESOUCE))))
    boot$(MTDPART) = $(boot$(PATSIZE))@$(cis$(PATSIZE))(BOOT),0x40000(ENV)
    
  6. 同时在image.mk和script_usbcam-rtos.mk中需要添加boot的image生成脚本和tftp烧录脚本。

  7. ipl/uboot进行了合并后,对于系统的mtd device有减少,分区在mount的时候请注意/dev/mtdblock后block id是否对应。

    image.mk:

    boot_nofsimage: $(BOOT_TARGET_NOFSIMAGE) $(BOOT_TARGET_FSIMAGE)
    @echo [[$@]]
    dd if=/dev/zero of=$(boot$(RESOUCE)) bs=1 count=0
    

    script_usbcam-rtos.mk:

    boot_$(FLASH_TYPE)__script:
    @echo "# <- this is for comment / total file size must be less than 4KB" > $(SCRIPTDIR)/[[boot.es
    @echo tftp $(TFTPDOWNLOADADDR) boot.bin >> $(SCRIPTDIR)/[[boot.es
    @echo nand erase.part BOOT >> $(SCRIPTDIR)/[[boot.es
    @echo nand write.e $(TFTPDOWNLOADADDR) BOOT \$${filesize} >> $(SCRIPTDIR)/[[boot.es
    @echo "% <- this is end of file symbol" >> $(SCRIPTDIR)/[[boot.es