系统分区


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、block count等,这些信息会根据spi nand的种类而改变,另一部分是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.ini

│   ├── LCM.ini

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

│   └── 4.9.227

│   ├── cifs.ko

……

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

│   └── v

│   ├── vt100

……

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

└── chagall.bin


2. 分区变更


2.1. 分区变更前注意事项

spi-nor flash和spi-nand flash上的分区都可归为两类:

  1. 不建议改动的boot

  2. 一类是可以变动的sys

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

注意:在上一章中miservice分区中有特别标注出来的文件需要放到指定的路径下系统才能运行,所以在制作分区时务必在根目录下创建/config/,并把相关的文件放到此路径下。


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

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

xxx.partition.config:

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

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

project/config/defconfigs/ipc_m6_spinand.glibc-9.1.0-squashfs.016a.512x512.bga2_defconfig

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

此项目的分区配置脚本存放的路径为project/config/defconfigs

可以看出,这是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分区制作脚本,Tiramisu项目使用的是project/image/configs/m6/rootfs.mk

script_nand.mk/script_nor.mk:

这是制作spi-nand和spi-nor烧录脚本的脚本,Tiramisu项目使用的是project/image/configs/m6/script_nor.mk, project/image/configs/m6/script_nand.mk

image.mk:

分区打包脚本,路径在project/mage/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.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的分区配置脚本,那么分区位置放在set_partition$(SYSTAB) = xxx中。

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


2.6. 增加修改删除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.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,不会超过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.3. MXP与PARTINFO

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

如图所示:

ROM code启动后会按照固定的地址启动到IPL,IPL会先去找一份原始的分区配置raw data,这部分就是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中。