4. Linux6.6_SDK编译

4.1. 获取源码

从网盘资源 4-SDK源码压缩包 中获取最新日期的LubanCat_Hi3403_Linux6.6_SDK源码压缩包,使用下面的命令将源码压缩包解压到当前用户的家目录,方便后续操作。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
# 将源码压缩包移动到用户家目录,xxxxxxxx为源码压缩包发布日期
mv LubanCat_Hi3403_Linux6.6_SDK_xxxxxxxx.tgz ~/LubanCat_Hi3403_Linux6.6_SDK.tgz

# 进入用户家目录
cd ~

# 解压源码压缩包
tar -xf LubanCat_Hi3403_Linux6.6_SDK.tgz

# 进入SDK源码目录
cd ~/LubanCat_Hi3403_Linux6.6_SDK
../../_images/tar-sdk-6.6.png

如图所示,解压后的源码各文件夹。

4.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
.
├── open_source     # SDK使用到的第三方开源项目源码
│   ├── buildroot           # Buildroot目录
│   │   ├── buildroot-2024.02.10        # Buildroot源码
│   │   ├── buildroot-2024.02.10.tar.gz # Buildroot源码压缩包
│   │   ├── dl                          # Buildroot下载的源码压缩包保存位置
│   │   ├── Makefile                    # Buildroot项目的Makefile,对接SDK的Makefile
│   │   ├── overlay                     # Buildroot根文件系统配置文件覆盖层
│   │   ├── readme.txt                  # Buildroot源码压缩包下载说明
│   │   └── ss928_lbc_defconfig         # Buildroot编译时的配置文件
│   ├── linux               # Linux内核
│   │   ├── linux-6.6.86.patch          # Linux内核补丁
│   │   ├── linux-6.6.y                 # Linux内核源码目录
│   │   ├── Makefile                    # Linux项目的Makefile,对接SDK的Makefile
│   │   └── readme.txt                  # Linux源码下载说明
│   ├── lvgl                # LVGL图形框架
│   │   ├── lv_port_linux               # LVGL的Linux系统适配接口
│   │   │   └── lvgl                    # LVGL源码目录
│   │   └── Makefile                    # LVGL的Makefile,对接SDK的Makefile
│   ├── mbedtls             # 加密库
│   ├── trusted-firmware-a  # 可信固件
│   ├── u-boot              # U-Boot
│   └── ubuntu              # Ubuntu根文件系统构建脚本
├── osdrv           # 操作系统相关目录
│   ├── BoardConfig         # 板级配置文件目录
│   │   └── BoardConfig配置说明         # 配置项说明文件
│   ├── components
│   │   ├── boot            # boot相关工具
│   │   │   ├── gsl             # GSL源码
│   │   │   └── image_map       # boot镜像制作工具
│   │   └── secure_c            # 安全函数库源码
│   ├── lunch               # 板级配置选择脚本
│   ├── Makefile            # SDK编译入口
│   ├── pub                 # 编译生成的镜像等文件存放位置
│   └── tools               # 系统工具源码
│       ├── board               # 板卡工具
│       │   └── reg-tools-1.0.0         # 寄存器读写工具、i2c读写工具
│       └── pc                  # 编译机工具
│           ├── kdf_customer
│           ├── nand_production
│           ├── rootfs_tools    # 根文件系统镜像打包脚本
│           ├── uboot_env       # env镜像制作工具
│           └── uboot_tools
│               ├── regbin-v1.0.2       # regbin转换工具,将xlsm格式的u-boot表格转换为bin文件
│               └── SS928V100_LubanCat_LPDDR4x_3733M-8GB_32bitx2-A55_1400M-emmc.xlsm    # u-boot表格,寄存器配置表
├── README_zh.md
└── smp     # smp目录
    └── a55_linux       # arm核代码
        ├── interdrv        # 主芯片外设驱动
        ├── mpp             # mpp源码
        └── osal            # 操作系统适配层

4.3. 一键编译Linux系统

提示

如果没有特别说明,本章节中Linux系统的编译命令都在osdrv目录下执行。

4.3.1. 选择板级配置文件

由于不同存储类型,不同DDR容量、不同系统都要设置不同的编译参数,配置项众多。

为了便于用户使用,添加了配置文件选择机制。将配置参数写入预设的板级配置文件中,只需要在编译前选择不同的配置文件,就可以直接编译出对应方案的镜像了。

在osdrv目录中执行 ./lunch 命令

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
# 配置文件选择命令
./lunch

# 根据提示信息,输入配置文件对应的数字
==================================================
启动存储:EMMC/SPI-NAND/SPI-NOR
内存类型:LPDDR4x-4GB/LPDDR4x-8GB
板卡名称:Hi3403
系统类型:Ubuntu/Buildroot
==================================================
请选择一个 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-Ubuntu_Lite.mk
输入数字选择: 0
已选择 BoardConfig.mk -> BoardConfig-EMMC-LPDDR4x_4GB-Hi3403-Buildroot.mk
../../_images/boardconfig-6.6.png

配置文件选择完成。如果想查看当前的配置文件,可以用 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
# Target CHIP
# 目标芯片,默认为ss928v100
export CHIP=

# Kernel config
# 内核配置文件,编译内核时使用
export KERNEL_CFG=

# Target rootfs: buildroot/ubuntu
# 目标根文件系统,可选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=

# 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=

# lvgl project enable
# lvgl示例程序,设置为yes则安装到根文件系统中
export LVGL_PROJECT=

4.3.2. 一键编译命令

配置文件选择完成之后,可以使用一键编译命令来构建系统镜像,将会自动构建boot、env、kernel和rootfs镜像。

在osdrv目录下执行下面的命令

1
2
# 一键编译命令
make

以BoardConfig-EMMC-LPDDR4x_4GB-Hi3403-Buildroot.mk为例,编译完成后生成的镜像文件保存在osdrv/pub/ss928v100_emmc_image_glibc目录下。

文件名称

说明

boot_image_4GB.bin

boot镜像(GSL+U-Boot)

emmc_burn_table.xml

烧录工具分区配置表

emmc_env.bin

env分区镜像

rootfs_ss928v100_buildroot.ext4

ext4格式buildroot根文件系统镜像

u-boot-ss928v100.bin

U-Boot镜像

uImage_ss928v100

kernel镜像(ATF+uImage+dtb)

以上编译生成的文件仅针对当前配置方案,更详细的生成文件列表请查看 分区镜像文件说明

镜像烧录方法请查看: 系统镜像烧录 章节

4.4. 分区镜像编译

当我们修改SDK的部分内容后需要重新编译生成镜像,如果还是完整的去编译SDK会耗费很多时间, 此时可以单独编译修改的部分生成镜像,来增加开发效率。

一键编译命令 章节中生成的镜像文件,有4个文件用于板卡烧录,对应存储中的4个分区:

  • boot镜像:boot_image.bin

  • env镜像:env.bin

  • kernel镜像:uImage_ss928v100

  • rootfs镜像:rootfs_ss928v100.ext4

下面对各分区镜像的作用和编译步骤做详细说明

4.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相关的内容。

4.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

4.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

4.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
# 构建ubuntu根文件系统基础压缩包
make ubuntu


# 构建buildroot根文件系统基础压缩包
make buildroot

# 清理buildroot
make buildroot_clean

# 修改buildroot配置文件(完整命令)
make buildroot_menuconfig

# 修改buildroot配置文件(简短命令)
make bconfig

在osdrv/Makefile中可以看到

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
prepare:
rootfs_prepare: prepare

kernel: prepare

TARGET_ROOTFS=ubuntu或buildroot
ubuntu: prepare rootfs_prepare
buildroot: prepare rootfs_prepare

secure_libs:
reg_tools: rootfs_prepare secure_libs

TARGET_ALL=hi_mpp、lvgl
hi_mpp:
lvgl:

rootfs_build: rootfs_prepare kernel $(TARGET_ROOTFS) reg_tools $(TARGET_ALL)

根据Makefile的规则整理一下,当我们运行 make rootfs_build 时流程如下:

  1. prepare:创建工作目录

  2. rootfs_prepare:清理rootfs构建目录,创建工作目录

  3. kernel:编译内核模块

  4. $(TARGET_ROOTFS):根据TARGET_ROOTFS的值,运行对应的根文件系统构建命令、安装内核模块、处理目录路径

  5. secure_libs:生成libsecurec.a安全函数库供reg_tools使用

  6. rootfs_build:将生成的命令工具打包进行rootfs,并按照存储类型生成rootfs镜像

  7. $(TARGET_ALL):根据配置文件中的配置项,编译额外的组件添加到rootfs中

$(TARGET_ROOTFS)是核心操作,根据变量值的不同,调用对应的根文件系统构建脚本,生成基础的根文件系统压缩包。

$(TARGET_ALL)则是根据配置文件中的配置项,追加不同的目标到rootfs_build,来实现对rootfs功能的裁剪。

4.4.5. 分步构建注意事项

  • 分步构建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。 删除open_source/ubuntu中的上述文件后再执行 make ubuntumake rootfs_build 来重新构建ubuntu基础根文件系统压缩包。