SSD_SD BOOT环境搭建


1. SD boot方案介绍

SD boot方案是只通过SD卡从rom启动到rootfs,即IPL, CUST, UBOOT, ENV, KERNEL, ROOTFS等image都存放在SD卡中。分区设计和image存放位置如下图所示:

如图,分区采用dos分区系统,分区1为fat32文件系统的用户分区,里面可以存放IPL, CUST, UBOOT等启动文件和SigmastarSDUpgrade.bin等升级包,同SD upgrade做法。

表头MBR与分区1之间会保留1M(0x800 block)的保留空间,env就存放在这段空间中,0x278~0x478。

kernel,rootfs等image各单独创建一个分区,以二进制数据保存在对应的分区的首地址处。


2. SD boot编译

2.1. 准备工作

P3开发板、SDHC卡(支持sd2.0协议,容量不小于2G),读卡器

工具链:

export ARCH=arm;
export CROSS_COMPILE=arm-linux-gnueabihf-;
export PATH=/tools/toolchain/gcc-sigmastar-9.1.0-2020.07-x86_64_arm-linux-gnueabihf/bin/:$PATH;

2.2. project

选择使用名字中与sdmmc相关的defconfig,以dispcam_p3_sdmmc.glibc-9.1.0-ext4fs.s01a.64.qfn128_defconfig为例:

cd ${alkaid_path}/project
make dispcam_p3_sdmmc.glibc-9.1.0-ext4fs.s01a.64.qfn128_defconfig
make clean; make image-nocheck -j32
ls image/output/images/

default编译方案的设定是:SD卡容量为4GB、kernel分区size为10M,rootfs--200M,miserver--300M,customer--2G。

编辑image/configs/p3/sdmmc.ext4fs.partition.config根据实际情况,可自行调整相关信息参数。


2.3. uboot

选择使用名字中与sdmmc相关的defconfig, 以pioneer3_sdmmc_defconfig为例:

cd ${alkaid_path}/boot
make pioneer3_sdmmc_defconfig
make clean; make -j32
cp ./u-boot.xz.img.bin ${alkaid_path}/project/image/output/images/boot/UBOOT

#和SD相关的配置如下
make menuconfig
#       Device Drivers  --->
#              [*] MStar drivers  --->
#                      [*]   MSTAR SDMMC
#                      [*]     Save environment to SDMMC  (要确保关闭Save env to ISP NOR FLASH和 Save env to NAND FLASH,否则会编译失败)
#                      [*]     Fake cdz, always detect SD is true  (fake cdz脚,忽略卡存在检测,贴片式sd需要开启)

2.4. kernel

选择使用名字中与sdmmc相关的defconfig,以pioneer3_ssc020a_s01a_str_sdmmc_defconfig为例:

cd ${alkaid_path}/kernel
make pioneer3_ssc020a_s01a_str_sdmmc_defconfig
make clean; make -j32
cp ./arch/arm/boot/uImage.xz ${alkaid_path}/project/image/output/images/kernel

#和SD相关的配置如下
make menuconfig
#       Enable the block layer -->
#              [*]Support for large (2TB+) block devices and files (ext4 fs需要)
#       Device Drivers -->
#              [*]MMC/SD/SDIO card support -->
#                      <*>HW reset support for eMMC
#                      <*>Simple HW reset support for MMC
#                      <*>MMC block device driver
#              [*]SStar SoC platform drivers -->
#                      < >EMMC driver (emmc与sd共pad,不要选中)
#                      <*>SStar SD/MMC Card Interface Support
#       File systems -->
#              <*>The Extended 4 (ext4) filesystem(emmc启动时需要,子选项保持默认)

3. SD boot烧录

3.1. 通过网络自动升级烧录

  1. 将images/boot目录下的IPL, IPL_CUST, UBOOT用读卡器拷贝到SD卡根目录下。

  2. 插上SD卡,将板子的启动方式切位不spinand/nor启动不skip SD,上电,这时候板子就会优先从SD卡启动,进到UBOOT了。

  3. 在uboot命令行下设置好网络信息后,敲estar,等待烧录完成。

  4. reset,SD卡能boot成功boot到rootfs。


3.2. 通过USB烧录

参考SSD_USB Device升级(onebin)


3.3. 烧录器烧录

3.3.1 工具准备

使用shell脚本将整套启动数据制作sd disk image,然后使用烧录器将该母片烧录到SD卡0地址处,即可完成烧录。

工具:

mk_sddisk.sh

脚本工具放在images-package包下。脚本运行环境是linux,有losetup、fdisk、mkfs.vfat、mount、umount、dd、rm、cp命令的root权限。


3.3.2 环境变量镜像

把需要设置的环境变量按照uboot printenv命令打印出来的格式写入到一个txt文件,例如:

$ cd ${alkaid_path}/boot
$ vi ./env.txt
autoestart=0
baudrate=115200
bootargs=console=ttyS0,115200 root=/dev/mmcblk0p3 rootwait rootfstype=ext4 rw init=/linuxrc LX_MEM=0x3FE0000 mma_heap=mma_heap_name0,miu=0,sz=0x1E00000 cma=2M highres=off mmap_reserved=fb,miu=0,sz=0x300000,max_start_off=0x3300000,max_end_off=0x3600000
bootcmd=fdisk -r 0:2 0x22000000 0 0x5000; dcache on ; bootm 0x22000000;
bootdelay=0
ethact=sstar_emac
fileaddr=239c14d0
sstar_bbm=off
stderr=serial
stdin=serial
stdout=serial

uboot编译后在tools目录下有一个mkenvimage工具,使用该工具制作env.bin:

$ ./tools/mkenvimage -s 0x20000 -o ./env.bin ./env.txt

将该env.bin放在images-package包下:

$ cp ./env.bin ${alkaid_path}/project/image/output/images/

3.3.3. 制作母片

$ sh mk_sddisk.sh -h

Usage: sh mk_sddisk.sh [option]

Support burn the disk image according to the iamges-package

[option]

-s The path of the source images-package

-o Output filename

-l Virtual block device

键入命令制作sd_disk.img,参数使用默认值,source为.,output filename为sd_disk.img,virtual block device是/dev/loop0

$ sh mk_sddisk.sh

注意:如果提示找不到src file,检查是-s 后面的path是否正确,且path最后不能以'/'结尾。


4. UBOOT下新增命令介绍

  • fatformat

    将分区格式化为fat32文件系统。举例:fatformat mmc 0:1

  • fdisk

    dos分区操作命令,可支持创建/删除/查看分区,读/写/擦除分区数据。


5. Alkaid下修改分区设计方法

SD启动方案的分区方案固定写在${alkaid_path}/project/image/configs/p3/sdmmc.ext4fs.partition.config文件中,default设定如下:

# FAT_IMAGE_LIST中的文件将存放在被格式化为FAT32fs的分区1中
FAT_IMAGE_LIST = ipl ipl_cust uboot

# SYS_IMAGE_LIST标识所有需要烧录的image,需要为这些image单独创建对应的分区
SYS_IMAGE_LIST = kernel rootfs miservice customer misc

# SD capacity,SD卡的实际总容量大小,以block(512bytes)为单位。 2GB:0x400000 | 4GB:0x800000 | 8GB:0x1000000 | 16GB:0x2000000 | 32GB:0x4000000 | 64GB:0x8000000

# SD卡的实际容量可能比理论容量小,因此该项值最好填小一点。
FLASH_BLK_CNT  = 0x800000

# rootfs起来后会自动挂载的image对应的分区
USR_MOUNT_BLOCKS:=miservice customer misc

...

kernel$(RESOUCE)    = $(PROJ_ROOT)/kbuild/$(KERNEL_VERSION)/arch/arm/boot/uImage.xz
kernel$(BOOTCMD)    = fdisk -r 0:$(kernel$(INDEX)) $(KERNELBOOTADDR) 0 $(kernel$(CNT))\;
kernel$(BOOTENV)    = $(KERNEL_BOOT_ENV)

# kernel分区的容量,以block(512bytes)为单位
kernel$(CNT)        = 0xA000

# kernel分区编号
kernel$(INDEX) = 2


rootfs$(RESOUCE)    = $(OUTPUTDIR)/rootfs
rootfs$(FSTYPE)     = ext4

# ext4fs格式的image的size,以byte为单位,需不小于resouce。
rootfs$(PATSIZE)    = 0x1400000
rootfs$(BOOTENV)    = console=ttyS0,115200 root=/dev/mmcblk0p3 rootwait rootfstype=ext4 rw init=/linuxrc

# rootfs分区的容量,以block(512bytes)为单位
rootfs$(CNT)        = 0x64000

# rootfs分区编号
rootfs$(INDEX)      = 3

miservice$(RESOUCE) = $(OUTPUTDIR)/miservice/config
miservice$(FSTYPE)  = ext4
miservice$(PATSIZE) = 0x1400000
miservice$(MOUNTTG) = /config
miservice$(MOUNTPT) = /dev/mmcblk0p5
miservice$(OPTIONS) = ro
miservice$(CNT)     = 0x96000

# 注意,分区4是扩展分区mbr,需要跳过。下面的分区编号要与上面的mount dev一致。
miservice$(INDEX)   = 5  # skip ext partition 4

...

# 计算SD卡剩余容量,创建P1分区。若不想把P1分区当作User分区来用,可固定该分区size为0x10000(32MB,FAT32分区size最小值)
user-fat$(CNT)      = $(shell ((cnt=$(FLASH_BLK_CNT)-$(FLASH_BLK_CNT_RESV)-$(kernel$(CNT))-$(rootfs$(CNT))-$(miservice$(CNT))-$(customer$(CNT))-$(misc$(CNT)))); printf 0x%X $$cnt)
user-fat$(TYPE)     = FAT32

# 分区1,格式化为fat32文件系统,存放IPL, CUST, UBOOT用于启动
user-fat$(INDEX)    = 1  # fat partition have to be part1

注意:在烧录完成后,查看分区表可能发现分区实际size与预设值不符(偏大),这是正常现象。因为小于8GB的SD卡使用CHS mode,其要求分区的起始地址和结束地址要满足units对齐导致的。


6. 常见问题分析

  1. 超SD卡容量问题,如下所示,当SD卡容量不够时会报该问题,可根据log信息中的sd max block count数,重新规划调整分区。

    >>  fdisk -c 0 0x400000
    MMC: block number 0x765a63 exceeds max(0x764000)
    ** Can't read partition table on 0:7756386 **
    
  2. 分区表被破坏,因为误操作,分区表可能会被破坏。

    Part    Start Sector    Num Sectors     UUID            Type
    1     7582            7742049         ffffffff-01     0c
    2     7756386         -6755           ffffffff-02     83
    3     7756386         -6755           ffffffff-03     83
    4     7756386         -6920           ffffffff-04     05 Extd
    MMC: block number 0x765a63 exceeds max(0x764000)
    ** Can't read partition table on 0:7756386 **
    

    此时可以使用mmc erase 0 0x2000将分区信息全擦除掉,然后再重建分区。示例命令中0代表的是sd卡的起始擦除位置,以block(512byte)为单位,0x2000是size,同样以block为单位,可根据实际情况调整。

  3. 识别分区失败。刚创建好了的分区,却报获取分区失败。

    [UFU runcmd] fdisk -c 0 0xA9667
    [UFU runcmd] fdisk -c 0 0x5000
    [UFU runcmd] fdisk -c 0 0xb000
    [UFU runcmd] fdisk -c 0 0xb000
    [UFU runcmd] fdisk -c 0 0x18000
    [UFU runcmd] fdisk -c 0 0xA000
    [UFU runcmd] fatformat mmc 0:1
    Start format MMC0 partition1 ....
    ERROR: v7_dcache_inval_range - start address is not aligned - 0x239bf168
    ERROR: v7_dcache_inval_range - stop address is not aligned - 0x239bf368
    ** Partition 1 not valid on device 0 **
    Format failure!!!
    
    [UFU runcmd] fdisk -e 0:2
    ** No partition table - mmc 0 **
    

    这大概率是因为此时sw识别该device的分区type异常,这是由于在空片状态下执行mmc rescan导致的,规避方法烧录前不用擦除sd为空片,或者擦完后,烧录前执行fdisk -c 0 0x200创建一个测试分区用于确保重识别卡为dos分区系统。

  4. 编译报错

    [[customer_sdmmc_ext4_fsimage]]
    mke2fs -d /home/jz.xiang/workspace/master_branch/project/image/output/customer -t ext4 /home/jz.xiang/workspace/master_branch/project/image/output/images/customer.ext4 $((0x1600000/1024/1024))M
    mke2fs 1.44.1 (24-Mar-2018)
    Creating regular file /home/jz.xiang/workspace/master_branch/project/image/output/images/customer.ext4
    Creating filesystem with 22528 1k blocks and 5640 inodes
    Filesystem UUID: 186d8272-6e05-4029-a692-e4ede64fdebd
    Superblock backups stored on blocks: 
            8193
    
    Allocating group tables: done                            
    Writing inode tables: done                            
    Creating journal (1024 blocks): done
    Copying files into the device: __populate_fs: Could not allocate block in ext2 filesystem while writing file "prog_dla_classify"
    mke2fs: Could not allocate block in ext2 filesystem while populating file system
    image.mk:24: recipe for target 'customer_sdmmc_ext4_fsimage' failed
    

    这是设定的image size不够大导致的,修改sdmmc.ext4fs.partition.config中对应项即可

    customer$(RESOUCE)  = $(OUTPUTDIR)/customer
    customer$(FSTYPE)   = ext4
    customer$(PATSIZE)  = 0x3600000          # image size, need to larger than root-directory
    customer$(MOUNTTG)  = /customer