Edit online

生成量产固件

Read time: 8 minute(s)

按照本节流程编译加密的量产固件。

配置 BootLoader

  1. 进入 SDK 根目录:
    cd <SDK_ROOT>
  2. 在 SDK 根目录中执行下列命令:
    scons --apply-def=d21x_demo88-nand_rt-thread_bootloader_defconfig
  3. 打开 BootLoader 的 menuconfig 菜单:
    scons --menuconfig
  4. 在配置界面,勾选或确认已勾选下列参数:
    AIC_USING_SPIENC
    AIC_SPIENC_BYPASS_IN_UPGMODE
    参数对应的配置界面如下:
    Board options  --->
        [*] Using Spienc
        [*]   Enc qspi0
        (0)     set qspi0 tweak
        [*] Using Efuse/SID
            SID Parameter  --->
                (64) set efuse max word
    Bootloader options  --->
        [*] Upgrading  --->
            [*]   Secure transfer firmware and burn
    注:

    编译量产固件时,需将编译烧录 eFuse 程序时的代码修改还原。

  5. 在正式发布的固件中,建议将下列参数选项去掉,防止攻击者通过控制台读出 Flash 中的数据,否则可跳过:
    AIC_BOOTLOADER_CMD_MTD
    AIC_MTD_BARE_TEST
    
    参数对应的功能配置界面如下:
    BootLoader options  --->
        Commands  --->
            [ ] mtd read/write
    
    Drivers options  --->
        Drivers examples  --->
            [ ] Enable MTD driver test command

配置应用程序

  1. 进入 SDK 根目录:
    cd <SDK_ROOT>
  2. 在 SDK 根目录,执行下列命令:
    scons --apply-def=d21x_demo88-nand_rt-thread_bootloader_defconfig
  3. 打开 Application 的 menuconfig 菜单:
    scons --menuconfig
  4. 勾选或确认已勾选下列选项:
    AIC_USING_SPIENC
    对应的配置界面如下:
    Board options  --->
    
        [*] Using Spienc
        [*]   Enc qspi0
        (0)     set qspi0 tweak
  5. 在正式版本的固件中,建议删除 bsp/examples/test-spinor/test_sfud.c bsp/examples/test-spinor/test_fal.c bsp/examples/test-spinand/test_mtd.c 文件中的 sffalmtd_nand 命令命令,防攻击者通过控制台读出 Flash 中的数据,否则可跳过此步。

固件签名加密

SDK/target/<SoC>/<board>/pack/image_cfg.json 文件中配置并生成签名加密固件,例如 SDK/target/d21x/demo88-nand/pack/image_cfg.json

  1. 配置生成签名的组件
    开启了安全启动后,需要对 BootLoader 进行签名。参考签名相关部分的内容进行修改:
    {
        "spi-nand": {
            ...
        },
        "image": {
            ...
        },
        "info": { // Header information about image
            ...
        },
        "updater": { // Image writer which is downloaded to RAM by USB/UART
            ...
        },
        "target": { // Image components which will be burn to device's partitions
            ...
        },
        "pre-process": { // before v1.0.6 is the name "temporary"
            "aicimage": { // Create aic boot image
                "usbupg-ddr-init.aic": { // No loader, only PreBootProgram to initialize DDR
                    "head_ver": "0x00010001",
                    "resource": {
                        "private": "ddr_init.bin",
                        "pubkey": "keys/rsa_public_key.der",   // 签名相关
                        "pbp": "d21x.pbp",
                    },
                    "signature": {
                         "algo": "rsa,2048",
                         "privkey": "keys/rsa_private_key.der",   // 签名相关
                    },
                },
                "pbp_ext.aic": {
                    "head_ver": "0x00010001",
                    "resource": {
                        "pbp": "d21x.pbp",
                        "pubkey": "keys/rsa_public_key.der",   // 签名相关
                        "private": "pbp_cfg.bin",
                    },
                    "signature": {   // 签名相关
                         "algo": "rsa,2048",
                         "privkey": "keys/rsa_private_key.der",
                    },
                    // combine to use with loader.aic
                    "with_ext": "true",
                },
                "loader.aic": {
                    "head_ver": "0x00010001",
                    "loader": {
                        "file": "bootloader.bin",
                        "load address": "CONFIG_AIC_BOOTLOADER_LOAD_BASE",
                        "entry point": "CONFIG_AIC_BOOTLOADER_TEXT_BASE", // 256 byte aic header
                    },
                    "resource": {
                        "private": "ddr_init.bin",
                        "pubkey": "keys/rsa_public_key.der",  // 签名相关
                    },
                    "signature": {  // 签名相关
                         "algo": "rsa,2048",
                         "privkey": "keys/rsa_private_key.der",
                    },
                },
            },
        },
    }
  2. 对组件进行加密

    image_cfg.json 的 “temporary” 或 “pre-process” 对象的最后,添加 “data_crypt” 对象配置。

    此处使用的 AES 加密密钥,即为SDK/target/<soc>/<board>/pack/keys/ 文件目录中生成的密钥。

    在下列示例中,配置了一组需要使用 “data_crypt” 工具进行加密的组件,其中生成 bootloader.aic.enc 组件的配置参数为:
    • algo: 加密的算法

    • file: 加密的源文件,此处为前面生成的 bootloader.aic 文件

    • key: 使用的加密密钥

    • nonce: 使用的加密 Nonce 值

    • tweak: 该值不需要配置,保持为 0 即可

    {
        "spi-nand": {
            ...
        },
        "image": {
            ...
        },
        "info": { // Header information about image
            ...
        },
        "updater": { // Image writer which is downloaded to RAM by USB/UART
            ...
        },
        "target": { // Image components which will be burn to device's partitions
            ...
        },
        "pre-process": { // before v1.0.6 is the name "temporary"
            "data_crypt": {
                "bootloader.aic.enc": { //加密 bootloader 分区
                    "algo": "spienc-aes-128-ecb",
                    "file": "bootloader.aic", // File to be encrypted
                    "key": "keys/spi_aes.key", // Keys the same in eFuse
                    "nonce": "keys/spi_nonce.key", // Nonce the same in eFuse
                    "tweak": "0",
                },
                "env.bin.enc": { //加密 env 分区,备份分区使用同一个组件
                    "algo": "spienc-aes-128-ecb",
                    "file": "env.bin", // File to be encrypted
                    "key": "keys/spi_aes.key", // Keys the same in eFuse
                    "nonce": "keys/spi_nonce.key", // Nonce the same in eFuse
                    "tweak": "0",
                },
                "d21x_os.itb.enc": { //加密 os 分区
                    "algo": "spienc-aes-128-ecb",
                    "file": "d21x_os.itb", // File to be encrypted
                    "key": "keys/spi_aes.key", // Keys the same in eFuse
                    "nonce": "keys/spi_nonce.key", // Nonce the same in eFuse
                    "tweak": "0",
                },
                "rodata.fatfs.enc": { //加密 rodata 分区
                    "algo": "spienc-aes-128-ecb",
                    "file": rodata.fatfs", // File to be encrypted
                    "key": "keys/spi_aes.key", // Keys the same in eFuse
                    "nonce": "keys/spi_nonce.key", // Nonce the same in eFuse
                    "tweak": "0",
                },
                "data.fatfs.enc": { //加密 data 分区
                    "algo": "spienc-aes-128-ecb",
                    "file": "data.fatfs.itb", // File to be encrypted
                    "key": "keys/spi_aes.key", // Keys the same in eFuse
                    "nonce": "keys/spi_nonce.key", // Nonce the same in eFuse
                    "tweak": "0",
                },
                ...
            },
        },
    }

    对于一个或者多个需要进行加密的组件,都应按照上述方式进行配置。

    mk_image.py 工具在读取 image_cfg.json 文件时,逐个处理放在 “data_crypt” 中的配置,生成对应的加密组件,然后再进行打包。

    重要:

    “data_crypt” 字段应放在 “temporary”/”pre-process” 的最后,因为处理 “data_crypt” 时,可能需要依赖前面配置生成的文件,比如 ”aicimage”。

  3. 配置烧录加密组件

    image_cfg.json 中配置下列参数,打包加密组件,以适配烧录加密固件的要求:

    1. updater 中打包的程序,应为非加密程序

      updater 中配置的参数,都不是 .enc 结尾的组件

    2. target 中打包的程序和数据,应为加密后的程序

      target 中配置的参数,都是 .enc 结尾的组件

    这是因为:
    • SD 卡启动时,首先运行 updater 中的程序,进入烧录模式。此时由于数据是从 SD 卡加载的,不能为加密程序,否则无法正常执行

    • target 中打包的程序是要烧录到 Flash 的数据,如果不加密,则无法起到保护的作用,因此需要打包加密后的组件

    { "image": {
            ...
        },
        "info": { // Header information about image
            ...
        },
        "updater": { // Image writer which is downloaded to RAM by USB/UART
            "ddr": {
                "file": "usbupg-ddr-init.aic",
                "attr": ["required", "run"],
                "ram": "0x00103000"
            },
            "spl": {
                "file": "bootloader.aic",
                "attr": ["required", "run"],
                "ram": "0x41000000"
            },
        },
        "target": { // Image components which will be burn to device's partitions
            "spl": {
                "file": "bootloader.aic.enc", //使用 enc 结尾的加密组件
                "attr": ["mtd", "required"],
                "part": ["spl"]
            },
            "os": {
                "file": "d21x_os.itb.enc",   //使用 enc 结尾的加密组件
                "attr": ["mtd", "required"],
                "part": ["os"]
            },
            "rodata": {
                "file": "rodata.fatfs.enc", //使用 enc 结尾的加密组件
                "attr": ["mtd", "optional"],
                "part": ["rodata"]
            },
            "data": {
                "file": "data.fatfs.enc", //使用 enc 结尾的加密组件
                "attr": ["mtd", "optional"],
                "part": ["data"]
            },
        },
        "pre-process": { // before v1.0.6 is the name "temporary"
            ...
        },
    }

USB 烧录

直接使用编译生成的 img 文件进行量产烧录即可。

SD 卡量产

  • 标准方式

    编译生成下列文件后,将其复制到 SD 卡 FAT32 文件系统的根目录中,等待平台重新上电即可进入烧录:

    • bootcfg.txt

    • 打包后的 img 文件,例如 d21x_demo88-nand_v1.0.0.img

  • Direct Mode

    修改 bootcfg.txt,并且将 bootcfg.txt 和使用到的组件复制到 SD 卡 FAT32 文件系统的根目录,等待平台重新上电即可进入烧录模式。

    bootcfg.txt 示例:

    boot0=bootloader.aic
    writetype=spi-nand
    writeintf=0
    write0=bootloader.aic.enc
    write1=d21x_os.itb.enc,0x40000
    write2=rodata.fatfs.enc,0x240000
    write3=data.fatfs.enc,0x840000
    重要:

    在修改 bootcfg.txt 文件后,确保使用 UNIX 格式的换行符,而非 DOS 格式的换行符,即 ‘n’ 换行,而非 ‘rn’ 换行。