分区客制化SOP

version 1.4


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配置。

  • MXPT

    分区配置相关的二进制档案。

  • UBOOT

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

  • UBOOT_ENV

    UBOOT的环境变量存放分区。

  • LOGO

    在NVR设备上会使用,存放的是开机logo相关的配置。

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

BOOT在linux的mtd block0的位置上,对应的设备节点/dev/mtdblock0。

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

  • KERNEL

    存放内核的二进制文件。

  • ROOTFS

    如题。

  • miservice

    这是公板定义的一个分区,它用来存储mi的库、一些配置文档,文件系统默认jiffs2。

  • customer

    用户定制的分区。


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

Layout图举例:

  • CIS

    SPI-NAND独有的分区,保存在flash 0地址的位置.一部分是spinand info,保存spinand的基本信息,会根据spi nand的种类而改变, 例如block page count、block count等; 另一部分是partinifo,保存分区信息,这些信息都是给rom code读取的,rom code通过读取正确的spinand参数和分区信息, 获取IPL的位置从而运行整个系统。

  • IPL

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

  • IPL_CUS

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

  • UBOOT

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

  • ENV

    UBOOT的环境变量存放分区。

  • LOGO

    在NVR设备上会使用,存放的是开机logo相关的配置。

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

  • KERNEL

    存放内核的二进制文件。

  • ROOTFS

    如题。

  • UBI

    UBI的内容在上图分区表中不会显示出来,UBI中会创建多个ubifs格式的子分区,用户可以根据需要自行创建。Spinand的miservice分区就是放在UBI中。


1.3. MISERVICE分区内容

在MISERVICE分区的内容被mount到了根目录/config/下面,下表中加粗字体的文件是必须保持路径一致的,否则有可能会导致系统无法启动。

└── config

├── board.ini ---->保存当前板子的信息

├── config_tool ---->mi sys初始化mmap内存的应用

├── dump_config -> config_tool ---->dump config 应用,config_tool的symbol link。

├── dump_mmap -> config_tool ---->dump mmap应用,config_tool的symbol link。

├── fbdev.ini ---->Framebuffer 配置,若无fbdev需求可删除。

├── iqfile

│   ├── imx307_iqfile.bin

│   ├── iqfile0.bin -> imx307_iqfile.bin ---->Sensor IQ相关的bin

│   ├── iqfile1.bin -> imx307_iqfile.bin

│   ├── iqfile2.bin -> imx307_iqfile.bin

│   ├── iqfile3.bin -> imx307_iqfile.bin

│   └── isp_api.xml

├── mmap.ini ---->Mmap。Mmap可以参考Memory Layout

├── model ---->模块相关配置,可以删除。

│   ├── Customer_1.ini

│   ├── Customer_2.ini

│   └── Customer_auto_test.ini

├── modules ---->系统KO存放路径。

│   └── 4.9.84

│   ├── cifs.ko

……

├── pq ---->NVR显示PQ相关。

│   ├── Bandwidth_RegTable.bin

│   ├── Main.bin

│   └── Main_Ex.bin

├── terminfo ---->Console显示相关。

│   └── v

│   ├── vt100

……

└── venc_fw ---->Encoder的firmware

└── chagall.bin


2. 分区变更


2.1. 分区变更前注意事项

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

  • 不建议改动的boot

  • 可以变动的sys

本章介绍的分区变更都是在sys部分上,包括如何配置脚本变更分区顺序,如何打包分区,如何生成烧录脚本,若用户有一套打包和烧录的流程,请忽略本章。注意:在miservice分区中加粗字体标注的文件需要放到指定的路径下系统才能运行,所以在制作分区时务必在根目录下创建/config/,并把相关的文件放到此路径下。


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

分区变更分为分区制作/打包和分区烧录脚本制作这两部分。

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

  • xxx.partition.config:

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

    通过build config找到该项目使用的分区config文件,例如某项目使用的build config:

    project/configs/ipc/$(CHIP)/nor.glibc-squashfs.009a.64.qfn88
    

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

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

    project/mage/configs/$(CHIP)/nor.squashfs.partition.config
    

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

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

    Spinor:
    
        mxp$(BOOTTAB) = ”xxx”
    
        mxp$(SYSTAB) = ”xxx”
    
    Spinand:
    
        cis$(BOOTTAB) = xxx
    
        cis $(SYSTAB) = xxx
    

    在config脚本文件中,每个分区由一组变量表示,以上mxp和cis是特殊的分区变量,存放的是一组规定的分区配置(raw data),特殊的分区由特别的指令生成,详细介绍请参见特殊分区处理

  • rootfs.mk:

    这是ROOTFS和miservice分区制作脚本,项目使用的是:

    project/mage/configs/$(CHIP)/rootfs.mk
    
  • script_nand.mk/script_nor.mk:

    这是制作spi-nand和spi-nor烧录脚本的脚本,使用的是:

    project/mage/configs/$(CHIP)/script_nor.mk
    
    project/mage/configs/$(CHIP)/script_nand.mk
    
  • image.mk:

    分区打包脚本,路径在project/mage/image.mk。


2.3. 分区位置变更

2.3.1. Spinor flash

改变mxp$(SYSTAB)中所定义的分区前后位置即可,语法格式与linux uboot中使用的mtdpart是一样的。

mxp$(SYSTAB) = "$(kernel$(PATSIZE))(KERNEL),$(rootfs$(PATSIZE))(rootfs),$(miservice$(PATSIZE))(miservice),$(customer$(PATSIZE))(customer)"

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

2.3.2. Spinand flash

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

cis$(SYSTAB) = $(kernel$(MTDPART)),$(rootfs$(MTDPART)),-(UBI)

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


2.4. 增加修改删除jiffs2分区

在spinor的flash上一般用jiffs2作为可读写的分区的文件系统,如下定义了customer分区的相关配置:

customer$(RESOUCE)   = $(OUTPUTDIR)/customer

customer$(FSTYPE)    = jffs2

customer$(PATSIZE)   = 0x6B0000

customer$(MOUNTTG)   = /customer

customer$(MOUNTPT)   = mtd:customer

customer$(OPTIONS)   = rw
  • customer$(RESOUCE)

    表示分区的资源文件放置的位置,rootfs.mk和image.mk分别会往此路径中添加必须的文件,以及把文件夹打包成bin文件。

  • customer$(FSTYPE)

    打包的文件系统类型。

  • customer$(PATSIZE)

    分区大小。

  • customer$(MOUNTTG)、customer$(MOUNTPT)、customer$(OPTIONS)

    分区在板子起来后需要mount的路径以及参数。rootfs.mk中会处理这些参数。

2.4.1. 修改

若要修改分区,请改动以上变量值。

2.4.2. 增加分区

  1. 假设增加一个分区名为aaa,然后配置其大小等信息。

    aaa$(RESOUCE)   = $(OUTPUTDIR)/aaa
    
    aaa$(FSTYPE)    = jffs2
    
    aaa$(PATSIZE)   = 0x6B0000
    
    aaa$(MOUNTTG)   = /aaa
    
    aaa$(MOUNTPT)   = mtd:aaa
    
    aaa$(OPTIONS)   = rw
    
  2. 分区相关的变量配置完成之后,在mxp$(SYSTAB) = ”xxx”中指定其放置的位置。

  3. 在变量“IMAGE_LIST”后追加“aaa”。

  4. 在表示需要mount的节点的变量“USR_MOUNT_BLOCKS”后追加“aaa”。

2.4.3. 删除分区

按照增加分区的操作,反过来执行。

2.4.4. 烧录脚本

系统在script_nor.mk中会根据分区的配置自动生成。


2.5. 增加修改删除squashfs分区

Squashfs的分区变更与jiffs2分区变更大同小异,主要在xxx$(FSTYPE)上有不同,除去rootfs这个比较特别的分区之外,miservice分区制作成squashfs:

miservice$(RESOUCE)   = $(OUTPUTDIR)/tvconfig/config

miservice$(FSTYPE)    = squashfs

miservice$(PATSIZE)   = 0x180000

miservice$(MOUNTTG)  = /config

miservice$(MOUNTPT)  = /dev/mtdblock3

miservice$(OPTIONS)   = ro

注意: 若用的是spinand的分区配置脚本,那么分区放在cis$(SYSTAB) = xxx中。

与jiffs2分区一样,系统在script_nor.mk/script_nand.mk中会根据分区的配置自动生成烧录脚本。


2.6. 增加修改删除UBIFS分区

UBIFS分区一般应用在spinand上作为可读写的分区文件系统。

BIFS的所有的分区都属于UBI的mtd block中的一个子分区。一个普通的UBI分区变量设置如下:

miservice$(RESOUCE)   = $(OUTPUTDIR)/miservice/config

miservice$(FSTYPE)    = ubifs

miservice$(PATSIZE)   = 0xA00000

miservice$(MOUNTTG)  = /config

miservice$(MOUNTPT)  = ubi0:miservice

miservice$(OPTIONS)   = rw

与jiffs2分区变更方法不同的是,ubifs分区不需要添加mtdpart信息,也就是无需在cis$(SYSTAB) = xxx中添加分区位置。


2.7. 特殊分区处理

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

2.7.1. Kernel分区处理

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

例如KERNEL分区打包命令:

kernel_nofsimage:
    @echo [[$@]]
    cp -rvf $($(patsubst %_nofsimage,%,$@)$(RESOUCE)) (IMAGEDIR)/$(patsubst %_nofsimage,%,$@)

script_nor.mk/ script _nand.mk中写上分区烧录脚本生成的命令。

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

kernel_$(FLASH_TYPE)__script:

    @echo "aaaabbbaaaaaaa $@"

    @echo "# <- this is for comment / total file size must be less than 4KB" > $(SCRIPTDIR)/[[kernel.es

    @echo tftp $(TFTPDOWNLOADADDR) kernel >> $(SCRIPTDIR)/[[kernel.es

    @echo nand erase.part KERNEL >> $(SCRIPTDIR)/[[kernel.es

    @echo nand write.e $(TFTPDOWNLOADADDR) KERNEL \$${filesize} >> $(SCRIPTDIR)/[[kernel.es

    @echo nand erase.part RECOVERY >> $(SCRIPTDIR)/[[kernel.es

    @echo nand write.e $(TFTPDOWNLOADADDR) RECOVERY \$${filesize} >> $(SCRIPTDIR)/[[kernel.es

    @echo "% <- this is end of file symbol" >> $(SCRIPTDIR)/[[kernel.es
    @echo kernel-image done!!!

2.7.2. 带备份的分区处理

SPINAND的分区中IPL、IPL_CUST、UBOOT分区一般多个备份。

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

设置带备份的分区,参考如下代码:

ipl$(RESOUCE) = $(PROJ_ROOT)/board/$(CHIP)/boot/ipl/IPL.bin

ipl$(DATASIZE) = 0x20000

ipl$(COPIES) = 6

ipl$(BKCOUNT) = 5

ipl$(PATSIZE) = $(call multiplyhex, $(ipl$(COPIES)), $(ipl$(DATASIZE)))

ipl$(MTDPART) = $(ipl$(DATASIZE))@$(cis$(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.7.3. MXP与PARTINFO

ARM启动后会先进到一段固定的ROM CODE中:

如图所示:

ROM code启动后会按照固定的地址启动到IPL,IPL会先去找一份原始的分区配置raw data,这部分就是MXP或PARTINFO。

MXP/PARTINFO保存的是SPINOR/SPINAND分区的配置信息,arm启动执行到IPL时还没有mtdpart的概念,所以去读MXP或PARTINFO中的内容才能找到IPL_CUST或者uboot,因此MXP/PARTINFO所在的地址是固定的。


2.8. SPINOR的MXP

SPINOR的分区修改由mxpgenerator通过传入的不同参数动态生成后汇总到MXP_SF.bin。在ALKAID的编译打包环境中image.mk负责分区的打包步骤,通过shell脚本生成MXP_SF.bin。

如图所示:

mxpgenerator执行命令:

mxpgenerator "0x10000(IPL),0x10000(IPL_CUST),0x10000(MXPT),0x1F000(UBOOT),0x1000(UBOOT_ENV)" "0x200000(KERNEL),0x400000(rootfs),0x300000(miservice),0x6B0000(customer)" /home/malloc.peng/ALKAID/project/image/output/images/boot/MXP_SF.bin

mxpgenerator有三个参数: mxpgenerator [v0] [v1] [v2]:

  • [v0]

    传入的是BOOT部分的分区配置

  • [v1]

    传入的是sys分区的部分

  • [v2]

    输出文件路径。

mxpgenerator工具的源码路径:

project/image/makefiletools/src/mxpgenerator/mxpgenerator.c

利用服务器上的gcc编译:

gcc mxpgenerator.c –o mxpgenerator

2.9. SPINAND的PARTINFO

PARTINFO.pni通过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,它可以支持spinandspinor的两种分区打包方式。

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


3.1. Spinor

参考脚本:

project/image/configs/i6b0/nor.squashfs.partition.boot.config

与普通的打包脚本对比:

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

    BOOT_IMAGE_LIST = ipl ipl_cust mxp uboot

  2. IMAGE_LIST中删除合并的分区,并添加合并后的分区名 boot

    IMAGE_LIST = boot kernel rootfs miservice customer

  3. 在config文件中添加sstar分区。

    boot$(RESOUCE) = $(IMAGEDIR)/boot/sstar.bin

    boot$(PATSIZE) = $(shell printf 0x%x $(shell stat -c "%s" $(sstar$(RESOUCE))))

  4. 在image.mk和script_nor.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_nor.mk:

    uboot_spi_nor__script:
        @echo "# <- this is for comment / total file size must be less than 4KB" > $(SCRIPTDIR)/[[uboot
        @echo mxp r.info UBOOT >> $(SCRIPTDIR)/[[uboot
        @echo sf probe 0 >> $(SCRIPTDIR)/[[uboot
        @echo sf erase \$${sf_part_start} \$${sf_part_size} >> $(SCRIPTDIR)/[[uboot
        @echo tftp $(TFTPDOWNLOADADDR) boot/$(notdir $(uboot$(RESOUCE))) >> $(SCRIPTDIR)/[[uboot
        @echo sf write $(TFTPDOWNLOADADDR) \$${sf_part_start} \$${filesize} >> $(SCRIPTDIR)/[[uboot
    @echo "% <- this is end of file symbol" >> $(SCRIPTDIR)/[[uboot
    

3.2. Spinand

参考脚本:

project/image/configs/i6b0/spinand.squashfs.partition.boot.config

与普通的打包脚本对比:

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

    BOOT_IMAGE_LIST = ipl ipl_cust uboot

  2. IMAGE_LIST中删除合并的分区,并添加合并后的分区名 boot

    IMAGE_LIST = cis boot kernel rootfs miservice customer

  3. MTDPART设定更新:

    MTDPARTS = "mtdparts=nand0:$(boot$(MTDPART)),$(cis$(SYSTAB))"

  4. 确认分区多份copy

    ipl_cust$(RESOUCE) = $(PROJ_ROOT)/board/$(CHIP)/boot/ipl-dualos/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),每个分区占三份,每一份大小是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_nand.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_nand.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