2. SDK编译¶
2.1. 获取源码¶
从网盘资源 4-SDK源码压缩包 中获取LubanCat_Hi3403_SDK.tar.gz压缩包,使用下面的命令将源码压缩包解压到当前用户的家目录,方便后续操作。
1 2 3 4 5 6 7 8 9 10 11 | # 将源码压缩包移动到用户家目录
mv LubanCat_Hi3403_SDK.tar.gz ~/LubanCat_Hi3403_SDK.tar.gz
# 进入用户家目录
cd ~
# 解压源码压缩包
tar -xf LubanCat_Hi3403_SDK.tar.gz
# 进入SDK源码目录
cd ~/LubanCat_Hi3403_SDK
|
如图所示,解压后的源码各文件夹。
2.2. SDK目录介绍¶
提示
以下目录结构不需要深入了解,只需要在修改对应项目时找得到即可。
SDK源码目录结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 | .
├── open_source # SDK使用到的第三方开源项目源码
│ ├── buildroot # Buildroot目录
│ │ ├── buildroot-2024.02.10 # Buildroot源码
│ │ ├── dl # Buildroot下载的源码压缩包保存位置
│ │ ├── Makefile # Buildroot项目的Makefile,对接SDK的Makefile
│ │ └── ss928_lbc_defconfig # Buildroot编译时的配置文件
│ ├── busybox # busybox目录
│ │ ├── busybox-1.31.1 # busybox源码
│ │ ├── busybox-1.31.1.patch # 基于busybox源码修改的补丁文件
│ │ ├── busybox-1.31.1.tar.bz2 # busybox源码压缩包
│ │ ├── busybox_CVE-2021-42374.patch # CVE漏洞补丁
│ │ └── Makefile # busybox项目的Makefile,对接SDK的Makefile
│ ├── linux # Linux内核
│ │ ├── linux-4.19.90.patch # Linux内核补丁
│ │ ├── linux-4.19.90.tar.gz # Linux源码压缩包
│ │ ├── linux-4.19.y # Linux源码目录
│ │ └── Makefile # Linux项目的Makefile
│ ├── lvgl # LVGL图形框架
│ │ ├── lv_port_linux
│ │ └── Makefile
│ ├── u-boot # U-Boot
│ ├── ubuntu # Ubuntu根文件系统构建脚本
│ ├── e2fsprogs # 第三方开源工具
│ ├── eigen
│ ├── ethtool
│ ├── eudev
│ ├── iniparser
│ ├── mbedtls
│ ├── mtd-utils
│ ├── optee
│ ├── squashfs
│ ├── trusted-firmware-a
│ ├── util-linux
│ ├── xz
│ └── zlib
├── osdrv # 操作系统相关目录
│ ├── BoardConfig # 板级配置文件目录
│ │ └── BoardConfig配置说明 # 配置项说明文件
│ ├── components # 海思自研组件源码
│ │ ├── boot # boot相关工具
│ │ │ ├── gsl # GSL源码
│ │ │ └── image_map # boot镜像制作工具
│ │ ├── ipcm # 多核通信工具源码
│ │ ├── pcie_mcc
│ │ └── secure_c # 安全函数库
│ ├── lunch # 板级配置选择脚本
│ ├── Makefile # SDK编译入口
│ ├── pub # 编译生成的镜像等文件存放位置
│ ├── rootfs_scripts # busybox使用的根文件系统预定义文件
│ │ └── rootfs.tgz
│ └── tools # 系统工具源码
│ ├── board # 板卡工具
│ │ ├── load_riscv # mcu镜像加载工具
│ │ └── reg-tools-1.0.0 # 寄存器读写工具、i2c读写工具
│ └── pc # 编译主机工具
│ ├── kdf_customer
│ ├── mkimage_tool # mkimage工具说明
│ ├── nand_production # nand工具
│ ├── ubi_sh # ubifs镜像制作工具
│ ├── uboot_env # u-boot env镜像制作工具
│ └── uboot_tools # u-boot工具
│ ├── regbin-v1.0.2 # regbin转换工具,将xlsm格式的u-boot表格转换为bin文件
│ └── SS928V100_LubanCat_LPDDR4x_3733M-8GB_32bitx2-A55_1400M-emmc.xlsm # u-boot表格,寄存器配置表
├── platform # 平台代码
│ └── liteos # LiteOS代码
├── readme.md # SDK说明文件
└── smp # smp目录
├── a55_linux # arm核代码
│ ├── interdrv # 主芯片外设驱动
│ ├── mpp # mpp源码
│ ├── osal # 操作系统适配层
│ └── vendor # 外围设备驱动
└── dsp_liteos # dsp核代码
├── dsp0 # dsp0核代码
└── dsp1 # dsp1核代码
|
2.3. 一键编译Linux系统¶
提示
如果没有特别说明,本章节中Linux系统的编译命令都在osdrv目录下执行。
2.3.1. 选择板级配置文件¶
由于不同存储类型,不同DDR容量、不同系统都要设置不同的编译参数,配置项众多。
为了便于用户使用,添加了配置文件选择机制。将配置参数写入预设的板级配置文件中,只需要在编译前选择不同的配置文件,就可以直接编译出对应方案的镜像了。
在osdrv中执行 ./lunch 命令
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 配置文件选择命令
./lunch
# 根据提示信息,输入配置文件对应的数字
==================================================
启动存储:EMMC/SPI-NAND/SPI-NOR
内存类型:LPDDR4x-4GB/LPDDR4x-8GB
板卡名称:Hi3403
系统类型:Ubuntu/Buildroot/Busybox
==================================================
请选择一个 BoardConfig 文件:
1) BoardConfig-EMMC-LPDDR4x_4GB-Hi3403-Buildroot.mk
2) BoardConfig-EMMC-LPDDR4x_4GB-Hi3403-Ubuntu_Lite.mk
3) BoardConfig-EMMC-LPDDR4x_8GB-Hi3403-Buildroot.mk
4) BoardConfig-EMMC-LPDDR4x_8GB-Hi3403-Busybox.mk
5) BoardConfig-EMMC-LPDDR4x_8GB-Hi3403-Ubuntu_Lite.mk
6) BoardConfig-SPI_NAND-LPDDR4x_8GB-Hi3403-Buildroot.mk
7) BoardConfig-SPI_NAND-LPDDR4x_8GB-Hi3403-Busybox.mk
8) BoardConfig-SPI_NOR-LPDDR4x_8GB-Hi3403-Busybox.mk
输入数字选择: 0
已选择 BoardConfig.mk -> BoardConfig-EMMC-LPDDR4x_4GB-Hi3403-Buildroot.mk
|
配置文件选择完成。如果想查看当前的配置文件,可以用 ls -al 命令查看osdrv目录下BoardConfig.mk指向的配置文件
以下是配置文件中各配置项的说明:
注解
文档可能更新不及时,以 osdrv/BoardConfig/BoardConfig配置说明 中的内容为准。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 | # Target CHIP
# 目标芯片,默认为ss928v100
export CHIP=
# Kernel config
# 内核配置文件,编译内核时使用
export KERNEL_CFG=
# Target rootfs: buildroot/busybox/ubuntu
# 目标根文件系统,可选busybox、buildroot、ubuntu
export TARGET_ROOTFS=
# Target version: ubuntu: lite/xfce
# 根文件系统版本,仅在TARGET_ROOTFS=ubuntu时有效,可选lite、xfce
export TARGET_VERSION=
# set rootfs type: ubifs/jffs2/ext4
# 根文件系统镜像分区格式,支持ubifs(nand-flash)、jffs2(nor-flash)、ext4(emmc)
export ROOTFS_TYPE=
# Set buildroot config only TARGET_ROOTFS=buildroot
# buildroot配置文件,编译buildroot时使用,仅在TARGET_ROOTFS=buildroot时有效
export BUILDROOT_CFG=
# Target boot medium: spi(Nand/Nor)/emmc
# 目标存储芯片,可选spi(Nand-flash/Nor-flash)或emmc
export BOOT_MEDIA=
# EMMC rootfs size(MB), default 96MB
# EMMC根文件系统分区大小,单位MB,默认96MB,仅在ROOTFS_TYPE=ext4时有效。
# 设置值应略大于实际的根文件系统文件总体积,设置为0时自动计算文件大小
export EMMC_ROOTFS_SIZE=
# Nand chip size
# 生成镜像适配SPI_NAND的大小,仅在ROOTFS_TYPE=ubifs时有效。
# 设置多个值表示同时生成多个对应的下载配置文件和env镜像,中间用英文字符逗号隔开。
# 目前仅支持128M和256M两个值可供配置,不配置则使用默认值
export NAND_CHIPSIZE=128M,256M
# U-boot xlsm
# u-boot配置文件表格,不建议修改
export REGBIN_XLSM=
# mpp module and lib install rootfs: smp/a55_linux/mpp/out
# mpp模块和库,设置为yes则安装到根文件系统中
export HI_MPP_KO_LIB=
# mpp sample enable when HI_MPP_KO_LIB=yes: smp/a55_linux/mpp/sample
# mpp示例程序,设置为yes则安装到根文件系统中
export HI_MPP_SAMPLE=
# interdrv modules and sample enable when HI_MPP_KO_LIB=yes: smp/a55_linux/interdrv
# interdrv模块和示例程序,设置为yes则安装到根文件系统中
export HI_INTERDEV=
# lvgl project enable
# lvgl示例程序,设置为yes则安装到根文件系统中
export HI_LVGL_PROJECT=yes
|
2.3.2. 一键编译命令¶
配置文件选择完成之后,可以使用一键编译命令来构建系统镜像,将会自动构建boot、env、kernel和rootfs镜像。
在osdrv目录下执行下面的命令
1 2 | # 一键编译命令
make
|
编译完成后生成的镜像文件保存在osdrv/pub/{CHIP}_{BOOT_MEDIA}_image_glibc_{TARGET_ROOTFS}目录下。
文件名称 |
说明 |
boot_image.bin |
boot镜像(GSL+U-Boot) |
emmc_burn_table.xml |
烧录工具分区配置表 |
emmc_env.bin |
env分区镜像 |
rootfs_ss928v100_xxxM.ext4 |
rootfs分区镜像 |
sample.bin |
mcu镜像 |
u-boot-ss928v100.bin |
uboot镜像 |
uImage_ss928v100 |
kernel镜像(ATF+uImage+dtb) |
以上编译生成的文件可以用于镜像烧录,烧录说明请查看: 系统镜像烧录 章节
2.4. 分区镜像编译¶
当我们修改SDK的部分内容后需要重新编译生成镜像,如果还是完整的去编译SDK会耗费很多时间, 此时可以单独编译修改的部分生成镜像,来增加开发效率。
在 一键编译命令 章节中生成的镜像文件,有4个文件用于板卡烧录,对应存储中的4个分区:
boot镜像:boot_image.bin
env镜像:env.bin
kernel镜像:uImage_ss928v100
rootfs镜像:rootfs_ss928v100_xxxM.ext4
下面对各分区镜像的作用和编译步骤做详细说明
2.4.1. boot镜像编译¶
boot镜像包含GSL和U-Boot两部分,用于一步一步初始化芯片,最后启动内核。
当芯片上电后,先运行位于固化在芯片内部的代码BootROM,进行最基础的初始化,并根据启动模式配置加载对应存储中的GSL运行。
GSL根据U-boot表格(uboot寄存器配置表格)中的寄存器配置继续对DDR、时钟、引脚等外设进行初始化,然后加载U-boot并运行。
到U-Boot就能更全面的对系统外设进行初始化了,并支持一些高级操作,如网络通信、存储设备读写等。一切准备就绪,U-Boot将内核镜像加载到内存中,然后跳转到内核开始启动内核。
整个过程从BootROM → GSL → U-Boot → 内核,像阶梯一样逐级完成初始化,我们通常将BootROM到内核启动之间的全部阶段统称为BootLoader。
在osdrv目录下执行下面的命令构建boot镜像
1 | make gslboot_build
|
在osdrv/Makefile中可以看到
1 2 3 4 | prepare: # 准备工作
regbin_prepare: # 将U-boot寄存器配置表格转换为{chip}_reg_info.bin
boot: prepare regbin_prepare # 编译U-Boot源码,生成u-boot-{chip}.bin
gslboot_build: boot # 编译gsl源码,生成gsl.bin,然后将这三个文件合并成一个boot镜像boot_image.bin
|
据 Makefile 的语法规则,冒号前的名称是目标(target),冒号后的内容是该目标的依赖(prerequisites)。 在执行某个目标之前,Make 会自动先执行它的所有依赖。
在执行gslboot_build时,会先执行他的依赖boot,而boot又依赖于prepare和regbin_prepare。
所以运行 make gslboot_build 命令的完整流程是 prepare → regbin_prepare → boot → gslboot_build
U-Boot和GSL代码一般不用修改,uboot表格仅在修改ddr配置或初始引脚复用时修改。在SDK开发过程中,相对来说很少修改boot相关的内容。
2.4.2. env镜像编译¶
我们将U-Boot的环境变量打包成一个镜像,在U-Boot中对env镜像中保存的环境变量自动读取,可以更灵活的对U-Boot环境变量进行设置,方便用户使用。
在osdrv目录下执行下面的命令构建env镜像
1 | make uboot_env
|
查看osdrv/Makefile中的 uboot_env: prepare 可以可知,当我们执行命令时,
会根据存储的类型和存储的大小将u-boot环境变量(env)从文本转换成可直接烧写的二进制镜像env.bin,
并根据env中的bootargs的分区信息生成烧录工具分区配置文件burn_table.xml。
此工具的路径是osdrv/tools/pc/uboot_env,其中env_text目录下保存的是原始的env文本文件, 当我们想要修改默认的u-boot环境变量时可以修改对应的文本文件并重新生成env镜像进行烧录。
烧录env镜像可以给U-boot传递预先定义好的U-Boot环境变量,如果我们在板卡运行时需要修改, 还可以通过串口登录到U-boot命令行终端,使用命令进行修改。
U-boot环境变量相关的命令如下:
1 2 3 4 5 6 7 8 9 10 11 | # 打印当前环境变量
printenv
# 新增或修改环境变量
setenv [变量名] [变量值]
# 删除环境变量
setenv [变量名]
# 保存环境变量
saveenv
|
2.4.3. kernel镜像编译¶
Linux 内核(Linux Kernel)在整个操作系统中是核心组件,它介于硬件和应用程序之间,负责管理系统资源、提供底层服务、实现硬件抽象,是软件与硬件沟通的桥梁。
在Linux系统开发过程中,我们经常要对内核功能进行裁剪,为硬件添加驱动支持、为软件提供运行环境,所以需要经常修改并编译内核。
在osdrv目录下执行下面的命令构建kernel镜像
1 | make atf
|
在osdrv/Makefile中可以看到
1 2 3 | prepare: # 准备工作
kernel: prepare # 编译内核源码并生成内核镜像uImage
atf: kernel # 编译atf,并将生成的文件与uImage一起打包为完整的kernel镜像uImage_{chip}
|
需要注意的是,当我们修改内核配置文件时:
将配置项设置为[y]:对应代码会直接编译进内核镜像uImage
将配置项设置为[m]:对应代码会被编译成独立的内核模块(.ko)
上面命令生成的uImage_{chip}镜像中不包含被编译为模块[m]的驱动,在编译内核时这些模块会单独生成,需要放在rootfs的/usr/lib/modules目录中,由系统在启动时按需加载。
所以在修改内核代码后要注意,需要更新内核镜像还是更新rootfs中的ko文件。
除了上面编译kernel镜像的命令外,还有几个辅助命令可以提高效率:
1 2 3 4 5 6 7 8 | # 修改内核配置文件(完整命令)
make kernel_menuconfig
# 修改内核配置文件(简短命令)
make kconfig
# 清理内核
make kernel_clean
|
2.4.4. rootfs镜像构建¶
rootfs(Root File System,根文件系统)是Linux用户空间的基础环境,包含系统运行所需的程序、库和配置文件。 内核启动后会挂载rootfs,并在其中启动用户空间的第一个进程。因此,我们在Linux系统上的所有用户操作(包括执行命令、运行程序、文件管理等)都是在rootfs环境中进行的。
在开发过程中,如果我们希望将某些配置文件、脚本、驱动模块(.ko)或应用程序预置到rootfs镜像中,就必须重新构建rootfs才能将这些内容打包进去。
以Buildroot系统为例,由于它不支持在线包管理,所有的软件包和文件内容都需要在构建时选定并打包,因此在开发过程中需要频繁重新构建 rootfs。
在osdrv目录下执行下面的命令构建rootfs镜像
1 | make rootfs_build
|
除了上面编译kernel镜像的命令外,还有几个辅助命令可以提高效率:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 构建ubuntu根文件系统基础压缩包
make ubuntu
# 构建buildroot根文件系统基础压缩包
make buildroot
# 清理buildroot
make buildroot_clean
# 修改buildroot配置文件(完整命令)
make buildroot_menuconfig
# 修改buildroot配置文件(简短命令)
make bconfig
# 构建busybox根文件系统
make busybox
# 清理buildroot
make busybox_clean
|
在osdrv/Makefile中可以看到
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | prepare:
rootfs_prepare: prepare
TARGET_ROOTFS=ubuntu、buildroot或busybox
ubuntu: prepare rootfs_prepare
buildroot: prepare rootfs_prepare
busybox: prepare
secure_libs:
pctools: prepare secure_libs
boardtools: rootfs_prepare secure_libs
kernel: prepare
release_liteos:
ipcm:prepare kernel release_liteos secure_libs
rootfs_notools_build: rootfs_prepare $(TARGET_ROOTFS) pctools boardtools ipcm
rootfs_build: rootfs_notools_build
|
根据Makefile的规则整理一下,当我们运行 make rootfs_build 时流程如下:
prepare:创建工作目录
rootfs_prepare:清理rootfs构建目录
$(TARGET_ROOTFS):根据TARGET_ROOTFS的值,运行对应的根文件系统构建命令、安装内核模块、处理目录路径
secure_libs:生成libsecurec.a安全函数库供board和pc工具使用
pctools:编译pc使用的命令工具,如mkfs、zlib、mksquashfs等
boardtools:编译board使用的命令工具,如load_riscv、mkfs、ethtool等
kernel:编译内核模块
release_liteos:编译mcu固件
ipcm:编译ipcm工具,用于liteos和Linux间通信
rootfs_notools_build:将生成的命令工具打包进行rootfs,并按照存储类型生成rootfs镜像
rootfs_build:rootfs_notools_build的别称
其中$(TARGET_ROOTFS)是核心操作,根据变量值的不同,调用对应的根文件系统构建脚本,生成基础的根文件系统压缩包。 后面就是编译一下板卡用到的工具,并打包进根文件系统,最后打包成rootfs.img镜像用于烧录。
2.4.5. 分步构建注意事项¶
分步构建rootfs时,只会将ko文件打包进rootfs,而不会重新编译内核。如果修改了内核ko需要重新打包rootfs, 则需要先运行
make kernel编译kernel重新生成ko文件,然后再运行make rootfs_build手动构建rootfs镜像。 一键编译时则不存在此问题,构建rootfs前会将内核先编译一遍生成ko模块文件。分步构建ubuntu rootfs时,为了增加构建效率,默认会使用已经构建好的历史版本的ubuntu基础根文件系统压缩包。 如果修改了除mk-base-ubuntu.sh之外的文件,则需要删除ubuntu-jammy-lite-arm64-rootfs.tar.gz, 如果修改了mk-base-ubuntu.sh,则还需要删除ubuntu-base-lite-arm64-${date}.tar.gz。 删除上述文件后再执行
make ubuntu或make rootfs_build来重新构建ubuntu基础根文件系统压缩包。分步构建rootfs时,只会将mpp项目生成的库文件、示例程序打包进rootfs,不会重新编译mpp, 如果要重新编译mpp,则需要使用
make hi_mpp或在smp/a55_linux/mpp/out/obj下运行make clean; make来手动编译。 一键编译时则不存在此问题,会根据板级配置文件中的 HI_MPP_KO_LIB 和 HI_MPP_SAMPLE 设置修改 TARGET_ALL 变量来追加到编译流程中。分步构建rootfs时,只会将interdrv项目生成的ko文件、示例程序打包进rootfs,不会重新编译interdrv, 如果要重新编译interdrv,则需要使用
make hi_mpp或在smp/a55_linux/interdrv下运行make clean; make来手动编译。 一键编译时则不存在此问题,会根据板级配置文件中的 HI_INTERDEV 设置修改 TARGET_ALL 变量来追加到编译流程中。分步构建rootfs时,只会将lvgl项目生成的lvgl示例程序打包进rootfs,不会重新编译lvgl, 如果要重新编译lvgl,则需要使用
make hi_lvgl_project来手动编译。 一键编译时则不存在此问题,会根据板级配置文件中的 HI_LVGL_PROJECT 设置修改 TARGET_ALL 变量来追加到编译流程中。
