系统分区


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的一些基本信息,例如block page count、blockcount等,这些信息会根据spinand的种类而改变,另一部分是partinifo,保存的分区信息,这些信息都是给romcode读取的,romcode通过读取正确的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介绍.pdf》

├── 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:**是总的分区配置信息脚本,所有与分区调整相关的代码都在这个config文件中实现,这个config文件会有很多份,每个不同的chip、spinand分区还是spinor分区都会有各自的分区config文件。

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

例如SSC335的项目使用的build config:

project/configs/ipc/i6b0/nor.glibc-squashfs.009a.64.qfn88

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

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

project/image/configs/i6b0/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分区制作脚本,ssc335项目使用的是:project/image/configs/i6b0/rootfs.mk

**script_nand.mk/script_nor.mk:**是制作spi-nand和spi-nor烧录脚本的脚本,ssc335项目使用的是:

project/image/configs/i6b0/script_nor.mk

project/image/configs/i6b0/script_nand.mk

image.mk: 分区打包脚本

路径:

project/image/image.mk。

2.3. 分区位置变更


2.3.1. Spinor flash

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

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中的环境变量中。

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

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

2.3.3. 增加修改删除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.3.4. 修改

若要修改分区,则改动以上变量值即可。

2.3.5. 增加分区

  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.3.6. 删除分区

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

2.3.7. 烧录脚本

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


2.4. 增加修改删除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的分区配置脚本,那么分区位置放在:

set_partition$(SYSTAB) = xxx中。

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


2.5. 增加修改删除ubifs分区

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

UBIFS的所有的分区都属于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讯息,也就是无需在set_partition$(SYSTAB) = xxx中添加分区位置。


2.6. 特殊分区处理

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


2.7. 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.1. 带备份的分区处理

SPINAND的分区中IPL、IPL_CUST、UBOOT这些分区一般会有好几个备份。

例如IPL在烧录时,每个IPL的data会在每个block开始各占一份,一个block有128kb这么大,一般IPL的data不超过20kb,不会超过128kb,因此假设IPL的数据有六个备份,那么整个IPL分区会有6个block这么大,那么在分区打包的时候会用到dd命令把IPL分区进行打包,使输出的bin文件能够与IPL分区完全映射,六份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))@$(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.7.2. MXP与PARTINFO

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

如图所示:

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

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


2.8. SPINOR的MXP

SPINOR的分区修改全部汇总到MXP_SF.bin,这个bin是由一个tool通过传入不同的参数动态生成。在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,它可以支持spinand和spinor的两种分区打包方式。

在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)(DATASIZE))(IPL_CUST0)(DATASIZE))(IPL_CUST0)(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))@(PATSIZE))@(PATSIZE))@(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