# Qualcomm Linux 功能
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
本章提供了有关 Qualcomm Linux 功能的信息,具体包括以下主题:
- 元数据层,包含在 Qualcomm Linux 中
- Qualcomm Linux 元数据层中的配方和配置
- Qualcomm 在 Qualcomm Linux 中添加的软件功能
- Qualcomm 在发行版本中推出的工具
- 有关如何编译 Qualcomm Linux 镜像和元数据层的说明
Note: Qualcomm 软件发行版本基于 Yocto Kirkstone 发行版本。
有关 Kirkstone 发行版本对应的 Yocto Project 文档的完整索引,可访问 [https://docs.yoctoproject.org/4.0.18/singleindex.html](https://docs.yoctoproject.org/4.0.18/singleindex.html)。对于 Yocto Project 新用户,如果想要了解有关编译的信息,则在第一次尝试编译时,必须参考 Yocto Project 文档,网址 [https://docs.yoctoproject.org/4.0.18/singleindex.html#document-brief-yoctoprojectqs/index](https://docs.yoctoproject.org/4.0.18/singleindex.html#document-brief-yoctoprojectqs/index)。
Qualcomm Linux 环境由多个社区维护的元数据层组成,提供配方、软件包组、镜像和配置。Qualcomm 元数据层位于 community layer 上,为 Qualcomm 参考设备提供所需的额外软件组件。
## 元数据层概述
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
元数据层概述介绍了 Qualcomm 清单 ([https://github.com/quic-yocto/qcom-manifest](https://github.com/quic-yocto/qcom-manifest)) 中包含的层。该清单中包含重新生成参考版本所需的所有层。以下章节介绍了 Yocto Project 维护的层。Qualcomm 维护特定于 Qualcomm 参考设备的层,参考设备依赖 community layer 来实现全部功能。下图显示了 Qualcomm Linux 发行版本中包含的层:
Figure : Qualcomm Linux 元数据层

Table : Qualcomm Linux 元数据层及说明
| 元数据层 | 说明 |
| --- | --- |
| `meta-qcom-distro` | 该层为 Qualcomm 产品提供参考发行版本配置。镜像配方和软件包组在该层定义。 |
| `meta-qcom-extras` | 该层是已注册用户可选的元数据层。该层支持对所选组件进行源代码编译,这些组件以二进制形式存在于 `meta-qcom-hwe` 中。 |
| `meta-qcom-qim-product-sdk` | 该层提供 Qualcomm 基于 GStreamer 框架的 Qualcomm Intelligent Multimedia (QIM) 和 AI SDK。其中包括一组适用于实现多媒体和 AI 用例的 GStreamer 插件示例程序。 |
| `meta-qcom-realtime` | 该层包含特定于实时内核配置的更改。 |
| `meta-qcom-hwe` | 该层包含用于编译软件组件从而实现对 Qualcomm 设备的支持的配方,以及适用于 Qualcomm SoC 的增值软件功能。 |
| `meta-qcom` | 该层包含对 Qualcomm 设备的支持和上游 OSS 软件组件。 |
| `meta-virtualization`
[https://git.yoctoproject.org/meta-virtualization](https://git.yoctoproject.org/meta-virtualization) | 该层包含用于编译 OpenEmbedded 虚拟化解决方案和虚拟化工具栈(例如 dockerd 和 Kubernetes)的软件包。 |
| `meta-selinux`
[https://git.yoctoproject.org/meta-selinux/](https://git.yoctoproject.org/meta-selinux/) | 该层使能 SELinux。 |
| `poky/meta`
[https://git.yoctoproject.org/poky/](https://git.yoctoproject.org/poky/) | 该层提供编译工具和文件,即提供编译嵌入式操作系统所需的各种软件组件。 |
| `meta-openembedded`
[https://git.openembedded.org/meta-openembedded/](https://git.openembedded.org/meta-openembedded/) | 该层提供交叉编译环境。 |
### Qualcomm BSP 元数据层
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
以下层代表 Qualcomm BSP 元数据:
- [meta-qcom](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html#qualcomm_bsp_metadata_layers__section_ebf_3dd_51c_vinayjk_03-18-24-1703-23-746)
- [meta-qcom-hwe](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html#qualcomm_bsp_metadata_layers__section_tg5_3dd_51c_vinayjk_03-18-24-1703-34-31)
- [meta-qcom-realtime](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html#qualcomm_bsp_metadata_layers__section_atv_3dd_51c_vinayjk_03-18-24-1703-35-26)
- [meta-qcom-distro](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html#qualcomm_bsp_metadata_layers__section_yzv_3dd_51c_vinayjk_03-18-24-1703-35-206)
- [meta-qcom-extras](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html#qualcomm_bsp_metadata_layers__section_n3w_3dd_51c_vinayjk_03-18-24-1703-35-429)
- [meta-qcom-qim-product-sdk](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html#qualcomm_bsp_metadata_layers__section_rpw_3dd_51c_vinayjk_03-18-24-1703-35-615)
### meta-qcom
`meta-qcom` 元数据层托管于 [git.yoctoproject.org](http://git.yoctoproject.org),提供用于编译 Qualcomm OSS 的配方。软件镜像使用 `meta-qcom` 层的以下配方编译:
| `recipes-devtools/qdl/qdl_git.bb` | Qualcomm downloader (QDL) 刷写工具。
QDL 与 ID 为 05c6:9008 的 USB 设备通信,上传刷写加载程序并使用它来刷写镜像。 |
| --- | --- |
| `recipes-support/pd-mapper/pd-mapper_git.bb` | Qualcomm 保护域映射器应用程序。
pd-mapper 是保护域映射器服务的一种实现。
通过使用保护域映射器服务,用户空间应用程序可以访问 Qualcomm SoC 上的远程处理器。 |
| `recipes-support/qrtr/qrtr_git.bb` | Qualcomm QRTR 应用程序和库。 |
| `recipes-support/initrdscripts/initramfs-module-copy-modules_1.0.bb` | 用于将内核模块从 `initramfs` 复制到 `rootfs` 的 `initramfs-framework` 模块。 |
### meta-qcom-hwe
`meta-qcom-hwe` 元数据层托管于 [https://github.com/quic-yocto/meta-qcom-hwe](https://github.com/quic-yocto/meta-qcom-hwe)。它为使能 Qualcomm 设备提供了额外的软件支持。
- **BitBake 类**
有关 BitBake 类的介绍,可访问 [https://github.com/quic-yocto/meta-qcom-hwe/tree/kirkstone/classes](https://github.com/quic-yocto/meta-qcom-hwe/tree/kirkstone/classes)。
| `classes/uki.bbclass` | 实现将内核镜像打包为统一内核镜像 (UKI) 的逻辑。
UKI 由以下各项组成:
如需了解 UKI 镜像,可参见 [systemd-boot](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html#systemd_boot) |
| --- | --- |
| `classes/image-efi.bbclass` | 实现生成要打包到可扩展固件接口 (EFI) 系统分区中的镜像的逻辑。
生成的镜像包含设备树 blob (DTB)、内核镜像和 `systemd-boot` 管理器二进制文件。 |
| `classes/qprebuilt.bbclass` | 实现使用预编译软件包代替获取和编译源代码的逻辑。对于继承 **qprebuilt** 的任何配方,该类支持对打包在 `tar.gz` 中的二进制文件进行解包,并使用 BitBake 任务对其进行打包。 |
| `classes/qmodule.bbclass` | 默认情况下,Qualcomm BSP 通过在内核中启用 `CONFIG_MODULE_SIG_FORCE` 来强制对内核模块进行签名。但是,一些树外模块可能未正确签名。为了避免出现模块加载问题,`qmodule.bbclass` 会检查所有提供内核模块的软件包,如果尚未签名,则对其进行签名。 |
- **机器配置**
Qualcomm Linux 机器配置文件可在此处获取:[https://github.com/quic-yocto/meta-qcom-hwe/tree/kirkstone/conf/machine](https://github.com/quic-yocto/meta-qcom-hwe/tree/kirkstone/conf/machine)。
| `conf/machine/qcm6490.conf` | 搭载 Qualcomm QCM6490 的开发板(例如 RB3 Gen 2 核心套件、RB3 Gen 2 视频 Mezzanine 卡和 RB3 Gen 2 视觉 Mezzanine 卡)的机器配置。 |
| --- | --- |
- **内核命令行**
要更新内核命令行参数,应更新 `KERNEL_CMDLINE_EXTRA` 变量。
`KERNEL_CMDLINE_EXTRA`
`DBG_CMDLINE = "${@oe.utils.conditional('DEBUG_BUILD','1','qcom_scm.download_mode=1 slub_debug=FZP,zs_handle,zspage; FZPU','',d)}"`
`KERNEL_CMDLINE_EXTRA ?= "root=/dev/disk/by-partlabel/system rw rootwait ${CONSOLE_CMDLINE} pcie_pme=nomsi kernel.sched_pelt_multiplier=4 rcupdate.rcu_expedited=1 rcu_nocbs=0-7 kpti=off kasan=off kasan.stacktrace=off no-steal-acc page_owner=on ${DBG_CMDLINE} swiotlb=128"`
- **包含 DTB**
要包含相应的 DTB,应更新 `KERNEL_DEVICETREE`:
`KERNEL_DEVICETREE = " \`
`qcom/qcm6490-addons-idp.dtb \`
`qcom/qcs5430-fp1-addons-rb3gen2.dtb \`
`qcom/qcs5430-fp1-addons-rb3gen2-vision-mezz.dtb \`
`qcom/qcs5430-fp1p5-addons-rb3gen2.dtb \`
`qcom/qcs5430-fp1p5-addons-rb3gen2-vision-mezz.dtb \`
`qcom/qcs5430-fp2-addons-rb3gen2.dtb \`
`qcom/qcs5430-fp2-addons-rb3gen2-vision-mezz.dtb \`
`qcom/qcs6490-addons-rb3gen2.dtb \`
`qcom/qcs6490-addons-rb3gen2-video-mezz.dtb \`
`qcom/qcs6490-addons-rb3gen2-vision-mezz.dtb \`
`qcom/qcs6490-addons-rb3gen2-ptz-mezz.dtb \`
`qcom/qcs6490-addons-rb3gen2-ia-mezz.dtb \`
`"`
- **包含其他的 DTBO**
如需添加要叠加在基本内核设备树之上的设备树叠加 (DTBO),应更新 `KERNEL_TECH_DTBOS`:
`# Additional dtbo to overylay on top of kernel devicetree filesKERNEL_TECH_DTBOS[qcm6490-addons-idp] = "qcm6490-graphics.dtbo qcm6490-display.dtbo qcm6490-camera.dtbo qcm6490-bt.dtbo qcm6490-wlan-idp.dtbo qcm6490-video.dtbo"`
`KERNEL_TECH_DTBOS[qcs6490-addons-rb3gen2] = "qcm6490-graphics.dtbo qcm6490-wlan-rb3.dtbo qcm6490-display-rb3.dtbo qcm6490-bt.dtbo qcm6490-video.dtbo"`
`KERNEL_TECH_DTBOS[qcs6490-addons-rb3gen2-video-mezz] = "qcm6490-graphics.dtbo qcm6490-camera-rb3.dtbo qcm6490-display-rb3.dtbo qcm6490-wlan-rb3.dtbo qcm6490-bt.dtbo qcm6490-video.dtbo"`
`KERNEL_TECH_DTBOS[qcs6490-addons-rb3gen2-vision-mezz] = "qcm6490-graphics.dtbo qcm6490-camera-rb3.dtbo qcm6490-display-rb3.dtbo qcm6490-wlan-rb3.dtbo qcm6490-bt.dtbo qcm6490-video.dtbo"`
`KERNEL_TECH_DTBOS[qcs6490-addons-rb3gen2-ptz-mezz] = ""`
`KERNEL_TECH_DTBOS[qcs6490-addons-rb3gen2-ia-mezz] = ""`
`KERNEL_TECH_DTBOS[qcs5430-fp1-addons-rb3gen2] = "qcs5430-graphics.dtbo qcm5430-camera-rb3.dtbo qcs5430-wlan-rb3.dtbo qcm6490-bt.dtbo qcm6490-display-rb3.dtbo qcm6490-video.dtbo"`
`KERNEL_TECH_DTBOS[qcs5430-fp1-addons-rb3gen2-vision-mezz] = "qcs5430-graphics.dtbo qcm5430-camera-rb3.dtbo qcs5430-wlan-rb3.dtbo qcm6490-bt.dtbo qcm6490-display-rb3.dtbo qcm6490-video.dtbo"`
`KERNEL_TECH_DTBOS[qcs5430-fp1p5-addons-rb3gen2] = "qcs5430-graphics.dtbo qcm5430-camera-rb3.dtbo qcs5430-wlan-rb3.dtbo qcm6490-bt.dtbo qcm6490-display-rb3.dtbo qcm6490-video.dtbo"`
`KERNEL_TECH_DTBOS[qcs5430-fp1p5-addons-rb3gen2-vision-mezz] = "qcs5430-graphics.dtbo qcm5430-camera-rb3.dtbo qcs5430-wlan-rb3.dtbo qcm6490-bt.dtbo qcm6490-display-rb3.dtbo qcm6490-video.dtbo"`
`KERNEL_TECH_DTBOS[qcs5430-fp2-addons-rb3gen2] = "qcs5430-graphics.dtbo qcm5430-camera-rb3.dtbo qcs5430-wlan-rb3.dtbo qcm6490-bt.dtbo qcm6490-display-rb3.dtbo qcm6490-video.dtbo"`
`KERNEL_TECH_DTBOS[qcs5430-fp2-addons-rb3gen2-vision-mezz] = "qcs5430-graphics.dtbo qcm5430-camera-rb3.dtbo qcs5430-wlan-rb3.dtbo qcm6490-bt.dtbo qcm6490-display-rb3.dtbo qcm6490-video.dtbo"`
用于生成 DTBO 的软件包必须添加到 `MACHINE_EXTRA_RDEPENDS` 变量以设置依赖项。例如,`qcm6490-graphics.dtbo` 添加到上述 `KERNEL_TECH_DTBOS` 列表,相应的软件包 `graphicsdevicetree`(用于生成 DTBO)添加到 `MACHINE_EXTRA_RDEPENDS` 变量,具体如下所示:
`MACHINE_EXTRA_RDEPENDS += " \`
`packagegroup-firmware-qcm6490 \`
`graphicsdevicetree \`
`displaydevicetree \`
`cameradtb \`
`wlan-devicetree \`
`btdevicetree \`
`videodtb \`
`"`
- **固件配方**
Qualcomm Linux 固件配方文件位于此处:[https://github.com/quic-yocto/meta-qcom-hwe/tree/kirkstone/recipes-firmware](https://github.com/quic-yocto/meta-qcom-hwe/tree/kirkstone/recipes-firmware)。当 Qualcomm Linux 源代码同步时,固件配方位于以下目录中:`/layers/meta- qcom-hwe/recipes-firmware/firmware`。
- **关键的启动二进制文件**
需要使用关键的启动镜像来启动设备上的内核。以下固件配方提供特定于 SOC 的启动固件:
| `firmware-qcom-bootbins_1.0.bb` | 处理对兼容目标的关键启动固件二进制文件的获取、解包和部署。
对于基于 QCM6490 的目标,该文件打包在 `QCM6490_bootbinaries.zip` 文件中。 |
| --- | --- |
完成编译后,可从以下目录中找到这些 zip 文件中的固件二进制文件以进行刷写:`/build-qcom-wayland/tmp-glibc/deploy/images///`。
`firmware-qcom-bootbins_1.0.bb` 配方根据 SRC\_URI 获取启动二进制文件,并解压 zip 文件。解压后的二进制文件位于以下目录中:`tmp-glibc/deploy/images//`。
- **子系统固件二进制文件**
Qualcomm Linux 包含在相应子系统上加载并运行的固件二进制文件。当 Qualcomm SoC 启动时,各个子系统会在复位后执行以下固件:
| `firmware-qcom-hlosfw_1.0.bb` | 处理对子系统固件二进制文件(例如 aDSP、cDSP、Modem 和 WLAN)的获取、解包和安装。
基于 QCM6490 的目标的固件文件打包在 `QCM6490_fw.zip` 文件中。 |
| --- | --- |
`firmware-qcom-hlosfw_1.0.bb` 配方根据 SRC\_URI 从远程服务器获取子系统固件二进制文件,解压 zip 文件,并将固件安装在 `rootfs` 中。
- **DSP 库**
用户空间实用工具引用 DSP 库,这些库必须位于 `rootfs` 镜像中。以下固件配方提供特定于 SOC 的 DSP 库:
| `firmware-qcom-dspso_1.0.bb` | 处理对 DSP 库的获取、解包和安装。
基于 QCM6490 的目标的库打包在 `QCM6490_dspso.zip` 文件中。 |
| --- | --- |
`firmware-qcom-dspso_1.0.bb` 配方根据 SRC\_URI 从远程服务器获取 DSP 库,解压 zip 文件,并将 DSP 库安装在 `rootfs` 中。
- **安装 boot、subsystem 和 dspso**
编译 Qualcomm Linux 源代码时,编译系统使用固件配方根据 MACHINE\_EXTRA\_RDEPENDS 配置(在机器配置文件中设置)来部署预编译的固件。例如,在 `layers/meta-qcom-hwe/conf/machine/qcm6490.conf` 中,可以看到在 MACHINE\_EXTRA\_RDEPENDS 变量中包含 `packagegroup-firmware-qcm6490`:
`MACHINE_EXTRA_RDEPENDS += " \`
`packagegroup-firmware-qcm6490 \`
`graphicsdevicetree \`
`displaydevicetree \`
`cameradtb \`
`wlan-devicetree \`
`btdevicetree \`
`videodtb \`
`"`
Note: `packagegroup-firmware-qcm6490` 配方位于 `/layers/meta-qcom-hwe/recipes-firmware/packagegroups/` 中,该配方会用于将生成镜像的固件配方分组。
在编译 Qualcomm Linux 时,根据 `qcm6490.conf` 中的配置和软件包组配方文件从 `/layers/meta-qcom-hwe/recipes-firmware/firmware` 中编译相应的固件配方。
- **内核配方**
Qualcomm Linux 使用的 Linux 内核配方位于 [https://github.com/quic-yocto/meta-qcom-hwe/tree/kirkstone/recipes-kernel/linux](https://github.com/quic-yocto/meta-qcom-hwe/tree/kirkstone/recipes-kernel/linux)。
Qualcomm Linux 支持 6.6 LTS 内核,并通过 Yocto 配方 `linux-kernel-qcom_6.6.bb` 进行维护,该配方位于 `recipes-kernel/linux` 的 `meta-qcom-hwe` 层下。该配方引用 Qualcomm 内核源代码,该源代码公开托管于 [https://git.codelinaro.org/clo/la/kernel/qcom.git](https://git.codelinaro.org/clo/la/kernel/qcom.git)。Qualcomm Linux 内核配方称为 `linux-kernel-qcom`。
例如,`qcm6490.conf` 是托管于 `meta-qcom-hwe/conf/machine` 的机器配置文件,支持 QCM6490 机器,并选择内核 `linux-kernel-qcom`。
***内核配置***
Qualcomm Linux 内核配方使用以下内核配置文件:
| 内核配置文件 | 说明 |
| --- | --- |
| `/arch/arm64/configs/qcom_defconfig` | 与产品/性能需求和上游内核一致的基本配置 |
| `/arch/arm64/configs/qcom_debug.config` | 来自上游内核的调试配置文件 |
| `/arch/arm64/configs/qcom_addons.config` | 在与上游一致的基本配置之上增加的 Qualcomm 下游配置 |
| `/arch/arm64/configs/qcom_addons_debug.config` | 启用 Qualcomm 下游调试 |
对于 QCM6490 机器配置,Qualcomm Linux 内核配方支持两种编译版本:`perf` 和 `debug`。默认编译版本为 `perf`。
| 编译版本 | Defconfig/config 文件 |
| --- | --- |
| `Perf` | |
| `调试` | |
通过更新内核配方 `linux-kernel-qcom_6.6.bb` 中的 KERNEL\_DEFCONFIG 和 KERNEL\_CONFIG\_FRAGMENTS 变量,可以修改内核编译配置:
`KERNEL_DEFCONFIG = "${S}/arch/arm64/configs/qcom_defconfig"`
`KERNEL_CONFIG_FRAGMENTS:append = " ${S}/arch/arm64/configs/qcom_addons.config"`
`KERNEL_CONFIG_FRAGMENTS:append = " ${@oe.utils.vartrue('DEBUG_BUILD', '${S}/arch/arm64/configs/qcom_debug.config', '', d)}"`
`KERNEL_CONFIG_FRAGMENTS:append = " ${@oe.utils.vartrue('DEBUG_BUILD', '${S}/arch/arm64/configs/qcom_addons_debug.config', '', d)}"`
如果 distro 支持 SELinux,则 SELinux 配置文件 `selinux.cfg` 和 `selinux_debug.cfg` 位于 `recipes-kernel/linux/linux-kernel-qcom`:
`SELINUX_CFG = "${@oe.utils.vartrue('DEBUG_BUILD', 'selinux_debug.cfg', 'selinux.cfg', d)}"`
`KERNEL_CONFIG_FRAGMENTS:append = " ${@bb.utils.contains('DISTRO_FEATURES', 'selinux', '${WORKDIR}/${SELINUX_CFG}', '', d)}"`
通过更新 Qualcomm Linux 内核配方中的 KERNEL\_MODULE\_AUTOLOAD 变量,可以为 Qualcomm 平台自动加载内核模块。下面给出了自动加载 CoreSight 和 STM 模块的示例:
`# Coresight and STM modules for QDSS functions`
`KERNEL_MODULE_AUTOLOAD += "coresight coresight-tmc coresight-funnel"`
`KERNEL_MODULE_AUTOLOAD += "coresight-replicator coresight-etm4x coresight-stm"`
`KERNEL_MODULE_AUTOLOAD += "coresight-cti coresight-tpdm coresight-tpda coresight-dummy"`
`KERNEL_MODULE_AUTOLOAD += "coresight-remote-etm coresight-tgu"`
`KERNEL_MODULE_AUTOLOAD += "stm_core stm_p_ost stm_console stm_heartbeat stm_ftrace "`
- **许可证**
`meta-qcom-hwe` 中的配方使用的 License 文件托管于 `/meta-qcom-hwe/files/common-licenses`。
common-licenses/
├── BSD-3-Clause-Clear
├── GPLv2.0-with-linux-syscall-note
└── Qualcomm-Technologies-Inc.-ProprietaryCopy to clipboard
Yocto 支持根据镜像生成自动创建 SPDX SBOM 文档。为实现这一点,需要在 `local.conf` 中继承 `create-spdx` 类,如下所示:
INHERIT += "create-spdx"Copy to clipboard
继承该类后,用户可以使用 BitBake 命令来重新编译镜像:
bitbake qcom-multimedia-imageCopy to clipboard
SPDX 生成的内容位于以下路径:
- 对于每个配方,生成的文件位于 `tmp/deploy/spdx/` 目录中。
- 顶层 SPDX 输出文件为 `tmp/deploy/images/MACHINE/-.spdx.json`。
### meta-qcom-realtime
`meta-qcom-realtime` 元数据层托管于 [https://github.com/quic-yocto/meta-qcom-realtime](https://github.com/quic-yocto/meta-qcom-realtime)。该层为编译 Qualcomm 设备的实时内核提供额外的软件支持。
- **内核配方**
Qualcomm Linux 支持 6.6 LTS 内核与实时扩展,并通过 Yocto 配方 `linux-kernel-qcom-rt_6.6.bb` 进行维护,该配方位于 `recipes-kernel/linux` 的 `meta-qcom-realtime` 层下。Pending 的抢占式 RT 补丁位于 [https://wiki.linuxfoundation.org/realtime/start](https://wiki.linuxfoundation.org/realtime/start)。获取这些补丁后将应用于 Qualcomm Linux 内核源代码,该源代码公开托管于 [https://git.codelinaro.org/clo/la/kernel/qcom.git](https://git.codelinaro.org/clo/la/kernel/qcom.git)。
Qualcomm Linux 实时配方称为 `linux-kernel-qcom-rt`。在为 Qualcomm 机器编译实时内核时,`conf/layer.conf` 选择 `linux-kernel-qcom-rt` 作为内核。
***内核配置***
KERNEL_CONFIG_FRAGMENTS:append = " ${WORKDIR}/qcom_rt.cfg"Copy to clipboard
- **在编译中启用 `meta-qcom-realtime`**
要在编译中包含 `meta-qcom-realtime`,应按照以下步骤将 `meta-qcom-realtime` 层导出至 `bblayers.conf`中的 EXTRALAYERS:
1. 导入环境,以下是导入 QCM6490 和 `qcom-wayland` distro 的环境的示例:
MACHINE=qcm6490 DISTRO=qcom-wayland source setup-environmentCopy to clipboard
2. 打开 `build-qcom-wayland/conf/bblayers.conf` 文件并更新 EXTRALAYERS 变量,如下所示:
EXTRALAYERS ?= " \
${WORKSPACE}/layers/meta-qcom-realtime \
"Copy to clipboard
3. 运行编译命令以使用 `meta-qcom-realtime` 重新编译,如下所示:
bitbake qcom-multimedia-imageCopy to clipboard
### meta-qcom-distro
该层为 Qualcomm 产品提供参考发行版本配置。镜像配方和软件包组在该层定义。
- **BitBake 类**
下表提供了有关 BitBake 类的介绍,这些类位于 [https://github.com/quic-yocto/meta-qcom-distro/tree/kirkstone/classes](https://github.com/quic-yocto/meta-qcom-distro/tree/kirkstone/classes)。
| `image-adbd.bbclass` | Qualcomm Linux 支持 SSH 和 UART 串口 shell。使用 SSH 或 UART 访问设备。
一些用户发现,当 IP 端口断开或需要传输大文件时,使用 ADB 调试问题会更加容易。对于这些用户,ADB 将作为一个选项提供给他们。
该类将 adbd 安装到镜像中。
除非 IMAGE\_FEATURES 包含 enable-adbd,否则禁用 adbd 后台程序。
可以通过手动从 `rootfs` 中移除 `/var/usb-debugging-enabled` 来禁用 adbd。 |
| --- | --- |
| `image-qcom-deploy.bbclass` | 在 `tmp-glibc/deploy/images//` 路径下部署镜像文件。
生成的镜像存放在 `` 子目录下。 |
- **Distro 配置**
下表提供了有关 distro 配置的介绍,这些配置在 [https://github.com/quic-yocto/meta-qcom-distro/tree/kirkstone/conf/distro](https://github.com/quic-yocto/meta-qcom-distro/tree/kirkstone/conf/distro) 定义。
| `conf/distro/qcom-wayland.conf` | 该 distro 配置文件定义了 `qcom-wayland` distro,用户可在以下示例命令中使用它。
MACHINE=qcm6490 DISTRO=qcom-wayland source setup-environmentCopy to clipboard
该配置文件中包含 `meta-qcom-distro/conf/distro/include/qcom-base.inc`文件,该文件定义常用的 DISTRO\_FEATURES 并添加以下 DISTRO\_FEATURES:
这些 distro 功能由 Yocto Project 文档定义,它们位于以下位置:[https://docs.yoctoproject.org/4.0.18/singleindex.html#distro-features](https://docs.yoctoproject.org/4.0.18/singleindex.html#distro-features)。 |
| --- | --- |
| `conf/distro/include/qcom-base.inc` | INIT\_MANAGER 设为 `systemd`。有关 INIT\_MANAGER 的 Yocto 文档,可访问 [https://docs.yoctoproject.org/4.0.18/singleindex.html#term-INIT_MANAGER](https://docs.yoctoproject.org/4.0.18/singleindex.html#term-INIT_MANAGER)。
启用的其他 DISTRO\_FEATURES 包括:
DISTRO_FEATURES:append = " pam overlayfs acl xattr selinux ptest security virtualization"Copy to clipboard
如需了解这些 DISTRO\_FEATURES 的用途,可访问 [https://docs.yoctoproject.org/4.0.18/singleindex.html#distro-features](https://docs.yoctoproject.org/4.0.18/singleindex.html#distro-features)。
该文件选择 `systemd` 作为 INIT\_MANAGER,并选择 `udev` 作为设备管理器。 |
| `conf/distro/include/qcom-security_flags.inc` | 该文件包含 [https://git.yoctoproject.org/poky/tree/meta/conf/distro/include/security_flags.inc?h=kirkstone](https://git.yoctoproject.org/poky/tree/meta/conf/distro/include/security_flags.inc?h=kirkstone) 中定义的安全标志。 |
- **软件包组**
软件包组在 `meta-qcom-hwe` 和 `meta-qcom-distro` 中定义。这些软件包组可帮助了解 Qualcomm BSP 定义的功能。
| `packagegroup-qcom.bb` | 包含所有基本软件包的软件包组 |
| --- | --- |
| `packagegroup-qcom-multimedia.bb` | 包含用于启用多媒体支持的软件包的软件包组: |
| `packagegroup-qcom-test-pkgs.bb` | – |
- **镜像配方**
Qualcomm Linux 元数据层 `meta-qcom-distro` 定义镜像配方,这些配方位于 [https://github.com/quic-yocto/meta-qcom-distro/tree/kirkstone/recipes-products/images](https://github.com/quic-yocto/meta-qcom-distro/tree/)。下表列出了各种镜像及其 IMAGE\_FEATURES,以及这些镜像的功能:
| 镜像配方 | 镜像说明 |
| --- | --- |
| `qcom-minimal-image.bb` | 定义一个较小的 `rootfs` 以启动至 shell。
启用的 IMAGE\_FEATURES 功能如下:
IMAGE_FEATURES += "splash tools-debug debug-tweaks enable-adbd read-only-rootfs"Copy to clipboard
有关 IMAGE\_FEATURES 的更多信息,可访问 [https://docs.yoctoproject.org/4.0.18/singleindex.html#image-features](https://docs.yoctoproject.org/4.0.18/singleindex.html#image-features)。 |
| `qcom-console-image.bb` | 通过添加更多镜像并启用更多 IMAGE\_FEATURES 来扩展 `qcom-minimal-image`:
IMAGE_FEATURES += "package-management ssh-server-openssh" Copy to clipboard |
| `qcom-multimedia-image.bb` | 需要 DISTRO\_FEATURE Wayland,以在 `rootfs` 中包含所有多媒体软件包。 |
| `qcom-multimedia-full-image.bb` | 提供对 `qcom-multimedia-image.bb` 的扩展以实现对 GStreamer 的支持。 |
| `qcom-multimedia-test-image.bb` | 在 `rootfs` 中包含测试包以测试 `qcom-multimedia-image`。 |
| `qcom-multimedia-crossesdk-image.bb` | 生成适用于 `qcom-multimedia-image` 的 eSDK。 |
- **QDL 刷写工具**
Qualcomm download tool (QDL) 是一款刷写工具,可与 ID 为 05c6:9008 的 USB 设备通信以将刷写加载程序上传到设备。刷写加载程序将镜像刷写到设备中的 UFS 或 eMMC。
可通过以下两种方法在主机 PC 上设置 QDL:
- QDL 工具默认在 Qualcomm Linux 工作区中编译。
QDL 工具集成在编译工作流中,以方便使用。QDL 配方位于以下路径:`/meta-qcom/recipes-devtools/qdl/qdl_git.bb`。该配方获取并编译 QDL 工具,之后即可对该配方进行 BitBake。由于 `image-qcom-deploy.bbclass` 的原因,默认集成 QDL 工具,作为编译的镜像的依赖项:
DEPENDS:append = " \
python3-native \
qdl-native \
"Copy to clipboard
镜像编译完成后,将在以下目录中生成 QDL 二进制文件:`tmp-glibc/deploy/image//`。该 QDL 二进制文件适用于主机架构。
- **QDL 作为独立项目编译**
克隆源项目,安装设备依赖项,并编译 QDL。
在主机 PC 上:
git https://github.com/linux-msm/qdl.git
sudo apt-get install libxml2-dev libudev-dev
cd qdl
makeCopy to clipboard
以这种方式编译的 QDL 可以在主机 PC 上进行复制和移动,因为它链接到 `/lib64/ld-linux-x86-64.so.2` 处的动态链接程序,该链接程序是所用主机 PC 的本地链接库。
**运行 QDL 的前提条件**
- 要使用 QDL 刷写工具,主机上需进行一次前提条件配置。
按照以下步骤使主机 PC 能够正确枚举主机的 Qualcomm 设备,以便 QDL 能够进行刷写:
1. 将目录更改为 `/etc/udev/rules.d`。
2. 在该路径上创建 `51-qcom-usb.rules` 文件。
3. 在 `51-qcom-usb.rules` 文件中添加以下代码行:
SUBSYSTEMS=="usb", ATTRS{idVendor}=="05c6", ATTRS{idProduct}=="9008", MODE="0666", GROUP="plugdev"Copy to clipboard
- 检查主机 PC 是否正在运行 `ModemManager`。
Note: 每次使用 QDL 时都要检查。
有些 Linux 发行版本随附 `ModemManager`,即一款用于配置移动宽带的工具。当基于 Qualcomm SoC 的设备以 USB 模式连接时,它会被识别为 Qualcomm Modem,`ModemManager` 会试图配置该设备。`ModemManager` 会干扰 QDL 刷写,因此如果正在运行 `ModemManager`,必须先将其禁用再连接测试设备。如果使用的 Linux 发行版本自带 `systemd`,则可通过 `systemctl` 停止 `ModemManager`。要确定如何在 QDL 刷写时管理 `ModemManager`,可参见 [QDL 和 ModemManager](https://docs.qualcomm.com/doc/80-70014-27Y/topic/debug.html#qdl_and_modemmanager) 章节。
**使用 QDL 进行刷写**
以下是运行 QDL 的通用命令:
qdl [ ]Copy to clipboard
该示例通用输入表明 QDL 工具需要三种类型的输入文件。所有这些输入文件均在目录 `tmp-glibc/deploy/image//` 下生成。当镜像配方成功完成后,必须执行以下步骤来刷写设备。如果想要使用在编译过程中生成的 QDL,应将目录更改为 `tmp-glibc/deploy/image//`,因为 Qualcomm Linux 工作流程会在该路径下生成并部署 QDL。例如:
cd /build-qcom-wayland/tmp-glibc/deploy/images/qcm6490/qcom-multimedia-image/Copy to clipboard
运行如下刷写命令:
./qdl prog_firehose_ddr.elf rawprogram*.xml patch*.xmlCopy to clipboard
**将 QDL 复制到其他位置**
`/build-qcom-wayland/tmp-glibc/deploy/images/qcm6490/qcom-multimedia-image/` 中的 QDL 二进制文件(在 Qualcomm Linux 编译工作流程中进行编译)可能无法复制或移动到其他路径,只能在原路径使用,这是由于相关依赖项导致的。如需了解这些依赖项,可运行以下命令:
file qdlCopy to clipboard
输出如下:
qdl: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter <workspace>/build-qcom-wayland/tmp-glibc/sysroots-uninative/x86_64-linux/lib/ld\u0002linux-x86-64.so.2, BuildID[sha1]=430c23d51190ef6c225586c5d63d2a7c9cd50430, for GNU/Linux 3.2.0, stripped
该输出表明 `/build-test-distro/tmp-glibc/sysroots-uninative/x86_64-linux/lib/ld-linux-x86-64.so.2` 存在依赖项,这是由于 Qualcomm Linux 编译 QDL 的方式所致。如果想要单独运行 QDL,可参见[独立 QDL](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html#qualcomm_bsp_metadata_layers__qdl_standalone)。
**QDL 高级选项**
QDL 支持更多高级选项,这些选项作为可选项通过命令行传递给 QDL。下表说明了这些高级选项:
| 选项 | 说明 |
| --- | --- |
| `--debug` | 在刷写镜像时打印调试日志 |
| `--storage ` | 该选项用于定义存储类型。如果未提供该选项,QDL 将检测存储类型。 |
| `--finalize-provisioning` | 关于 UFS 存储不可撤销的一次性配置 (OTP)。执行以下安全机制以防止设备意外锁定:
Note: 如果命令行参数与 XML 不匹配,则不会执行配置。 |
| `--include` | 指向镜像所在的路径。默认情况下为 NULL,即镜像位于同一位置。这在 QDL 作为独立项目编译时很有用,`--include` 用于指向镜像所在的路径。 |
标志的使用示例:
/qdl --storage ufs --include /qcm6490_images/qcom-multimedia-image /qcm6490_images/qcom-multimedia-image/prog_firehose_ddr.elf /qcm6490_images/qcom-multimedia-image/rawprogram*.xml /qcm6490_images/qcom-multimedia-image/patch*.xml
Copy to clipboard
### meta-qcom-extras
该层是已注册用户可选的元数据层。该层支持对所选组件进行源代码编译,这些组件以二进制形式存在于 `meta-qcom-hwe` 中。如果有权接收该元数据层,则可以使用 [Qualcomm Linux 编译指南](https://docs.qualcomm.com/bundle/publicresource/topics/80-70014-254/introduction.html)中分享的克隆步骤。
- **固件配方**
`meta-qcom-extras` 中的固件配方集成了编译其他子系统时生成的固件 ZIP。
| ├── recipes-firmware
├── firmware
│ ├── firmware-qcm6490-boot_2.0.bb
│ ├── firmware-qcm6490-dspso_2.0.bb
│ └── firmware-qcm6490-msl_2.0.bb
└── packagegroups
└── packagegroup-firmware-qcm6490.bbCopy to clipboard | `meta-qcom-extras` 中的配方会覆写 `meta-qcom-hwe` 中的配方。
`meta-qcom-hwe` 默认使用预编译的固件二进制文件,而 `meta-qcom-extras` 从 Qualcomm 专有存储库编译固件。
`meta-qcom-extras` 层会忽略以下 .zip 文件中的预编译二进制文件。这些配方会转为搜索 FWZIP\_PATH 路径下设置的 zip 文件,如下所述:
|
| --- | --- |
### meta-qcom-qim-product-sdk
- **BitBake 类**
| BitBake 类 | 说明 |
| --- | --- |
| `qim-prod-sdk-pkg.bbclass` | |
| `qimsdk-pkg.bbclass` | |
| `tflitesdk-pkg.bbclass` | |
- **Distro 配置**
| `layer.conf` | 使用以下信息配置项目层:
|
| --- | --- |
- **镜像配方**
| 配方 | 说明 |
| --- | --- |
| `recipes-gst` | 包括上游 GStreamer 配方更改 (`.bbapend`),以及 Qualcomm 配方: |
| `recipes-qcom-ml` | 包含两个配方: |
| `recipes-qim-product-sdk` | 用于安装包含 QIM、Qualcomm Neural Processing、QNN 和 TensorFlow Lite SDK 的 QIM product SDK 的配方 |
| `recipes-tensorflow-lite` | TensorFlow Lite 配方编译并安装以下版本的 TensorFlow Lite: |
- **软件包组**
| 软件包组 | 说明 |
| --- | --- |
| `packagegroup-qcom-gst` | 用于启用上游基本 GStreamer 以及 Qualcomm 插件的软件包组:
该软件包组还用于打包上游 GStreamer 软件包: |
| `packagegroup-qcom-gst-basic` | 用于启用上游 GStreamer 的软件包组: |
| `packagegroup-qcom-qim-product` | 用于将以下软件包与安装脚本一起打包的软件包组: |
| `packagegroup-qcom-ml` | 用于打包 Qualcomm ML 框架的软件包组: |
## Qualcomm Linux 软件组件
### 文件系统叠加
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
Qualcomm Linux 使用 overlay 文件系统在某些挂载点上创建叠加。建议使用只读的 rootfs,但许多应用程序可能需要对文件系统的某些部分进行读写访问。这通过 `overlayfs` bbclass 使基本 rootfs 保持只读来实现。
`overlayfs-qcom-paths` 配方创建 `/var`、`/etc` 和 `/opt` 作为叠加挂载点,并继承 `overlayfs` bbclass。在该配方中,变量 `overlayfs_mount_point` 定义为 `mnt-overlay`,这意味着 `mnt-overlay.mount` systemd 单元在 BSP 中定义并安装到镜像中。在启动时,systemd 单元 `mnt-overlay.mount` 将 `/dev/disk/by-partlabel/overlay` 磁盘分区挂载到所有挂载点。
变量 `overlayfs_writable_paths` 指定运行时使用的可写路径,即 `/opt`、`/etc` 和 `/var`。
要包含 `overlayfs`支持,必须将其添加到 DISTRO\_FEATURES。
- `/var` 叠加
要查看 `/var` overlayfs 挂载点,应运行以下挂载命令:
sh-5.1# mount | grep var
overlay on /var type overlay (rw,relatime,seclabel,lowerdir=/var,upperdir=/mnt/overlay/upper/var,workdir=/mnt/overlay/workdir/var)Copy to clipboard
- `/etc` 叠加
sh-5.1# mount | grep etc
/dev/sda11 on /mnt/overlay type ext4 (rw,relatime,rootcontext=system_u:object_r:etc_t:s0,seclabel,stripe=128,inlinecrypt)
overlay on /etc type overlay (rw,relatime,seclabel,lowerdir=/etc,upperdir=/mnt/overlay/upper/etc,workdir=/mnt/overlay/workdir/etc)Copy to clipboard
- `/opt` 叠加
sh-5.1# mount | grep opt
overlay on /opt type overlay (rw,relatime,seclabel,lowerdir=/opt,upperdir=/mnt/overlay/upper/opt,workdir=/mnt/overlay/workdir/opt)Copy to clipboard
- `/home` 叠加
sh-5.1# mount | grep home
overlay on /home type overlay (rw,relatime,seclabel,lowerdir=/home,upperdir=/mnt/overlay/upper/home,workdir=/mnt/overlay/workdir/home)Copy to clipboard
- 调整 overlay 分区的大小:这使用配方 `resize-partitions.bb` 和 `resize-partition.service.in`文件来实现。调整分区大小的服务在设备启动时运行,以根据分区的大小创建和设置文件系统。在调整分区大小服务中,运行调整 overlay 分区大小的命令将执行以下操作:
- `/sbin/e2fsck -n /dev/disk/by-partlabel/%i` 根据分区标签检查指定文件系统是否存在错误,但不做任何更改。
- `/sbin/mkfs.ext4 /dev/disk/by-partlabel/%i` 调用 `mkfs.ext4` 实用工具并对 ext4 文件系统的分区进行格式化。
- `/sbin/resize2fs /dev/disk/by-partlabel/%i` 尝试增加分区的大小。
- `/sbin/tune2fs -O encrypt,stable_inodes /dev/disk/by-partlabel/overlay` 修改各种参数。例如,`encrypt` 可用于对存储在文件系统上的数据进行加密,stable\_inodes 选项可确保 inode 编号在文件系统操作中保持稳定。
### 系统初始化脚本
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
下面列出了通过 `meta-qcom-hwe` 添加到镜像的系统初始化脚本:
| 系统初始化脚本 | 说明 |
| --- | --- |
| `mnt-overlay.mount` | 将 `/dev/disk/by-partlabel/overlay` 磁盘分区挂载到所有挂载点。 |
| `var-persist.mount` | 将 `/dev/disk/by-partlabel/persist` 磁盘分区挂载到 `/var/persist`。 |
| `android-tools-adbd.service` | 在设备上提供 adbd 后台程序。 |
| `logrotate.service` | 对旧日志进行保存。有关该服务的更多信息,参见 [syslog() 的日志工具](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html#logging_shim_for_syslog)章节。`logrotate.service` 是上游 systemd 单元。
在 Qualcomm Linux 中修改了 `rsyslog.logrotate` 配置文件,以管理设备上的日志。修改后的 `rsyslog.logrotate` 文件位于 `meta-qcom-hwe/dynamic-layers/openembedded-layer/recipes-devtools/rsyslog/rsyslog/rsyslog.logrotate` 目录中。它将覆盖上游在 `meta-openembedded/meta-oe/recipes-extended/rsyslog/rsyslog/rsyslog.logrotate` 目录中提供的默认配置文件。 |
| `pd-mapper.service` | 配置和管理保护域。`pd-mapper.service.in` 文件通过 Qualcomm Linux BSP 层 `meta-qcom-hwe` 中的 `pd-mapper_git.bbappend` 更新,以便以系统用户身份而非 root 用户身份运行服务。
do_install:prepend() {
# convert the service from root user to system user
sed -i "/ExecStart=/i\User=system\nGroup=system" pd-mapper.service.in
}Copy to clipboard |
| `property-vault.service` | 实现 `property_get` 和 `property_set` 功能。有关该服务的更多信息,参见[属性](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html#properties)章节。 |
| `persist-property-vault.service` | 运行 `set-persist-prop.sh`,将标志 `le.persistprop.enable` 设为 true。要使用保留属性,需设置此标志。 |
| `resize-partition@.service` | 在启动时根据分区大小调整文件系统大小。
ExecStart=/bin/sh -c "/sbin/e2fsck -n /dev/disk/by-partlabel/%i; if [ $? -gt 1 ]; then /sbin/mkfs.ext4 /dev/disk/by-partlabel/%i; /sbin/resize2fs /dev/disk/by-partlabel/%i; #COMMAND# fi;"Copy to clipboard |
| `rsyslog.service` | 根据指定的配置重新定向日志。有关该服务的更多信息,参见 [syslog() 的日志工具](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html#logging_shim_for_syslog)章节。 |
| `sys-kernel-debug.mount` | 在编译 `perf` 时屏蔽 `sys-kernel-debug.mount` 点。 |
### 调试工具
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
调试工具由 `/layers/poky/meta` 目录中定义的 `packagegroup-core-tool-debug` 添加为 `rootfs` 的一部分。该配方以 `packagegroup-core-tools-debug.bbappend` 形式附加在 `/layers/meta-qcom-hwe/recipes-devtools/` 中。该附加文件添加 `valgrind` 和 `ltrace`。更多信息,参见[调试 Linux 用户空间](https://docs.qualcomm.com/bundle/publicresource/topics/80-70014-12/using_open_source_debug_tools.html)。
### systemd-boot
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
systemd-boot 为统一可扩展固件接口 (UEFI) 启动管理器。它提供了一个启动选项菜单来控制启动流程并加载用户选择的 boot loader。systemd-boot 可支持不同操作系统下的不同 boot loader。将内核和其他相关信息打包到 EFI 分区中。
必须使用 `EFI_CONFIG_STUB` 将内核编译为 EFI。systemd-boot 支持 Type1 和 Type2 配置。Type1 配置未经测试。启用 Type2 配置时,内核和其他详细信息打包到 UKI 中。启用 Type2 以提高安全性。UKI 包含设备启动所需的所有信息。对 UKI 镜像签名可确保其中包含的所有实体都是安全的。如果启用了 UEFI 安全启动,则仅加载已签名的镜像;因此,需要进行签名。有关 Systemd-boot 的更多详细信息,参见 [systemd-boot](https://wiki.archlinux.org/title/systemd-boot)。
Note: 在开发阶段,签名不是强制性的。
- **UKI**
UKI 是单个 UEFI 可移植可执行 (PE) 文件中 UEFI boot stub 程序、Linux 内核镜像、initrd 和其他资源的组合。UEFI boot stub 在 UEFI PE 二进制文件内部搜索用于内核调用的各种资源。这样可以在单个 PE 二进制镜像 (UKI) 内部组合各种资源,然后可以使用 OpenSSL 实用工具进行签名。
有关 UKI 的更多详细信息,参见 [unified_kernel_image](https://uapi-group.org/specifications/specs/unified_kernel_image/)。下图显示了 `uki.efi`的内容。其中包括:
- Ramdisk 镜像
- 未压缩 kernel image
- 架构信息
- systemd-boot stub
- 传递给内核的命令行参数
- 操作系统发行版本信息
Table : uki.efi 文件
| uki.efi 文件的组件 | 内容 |
| --- | --- |
| Initrd = Init ramdisk | `initramfs-qcom-image-qcm6490.cpio.gz` |
| Linux = 内核镜像 | 镜像 |
| Efi-arch = 架构 | `aa64` |
| Stub = System-boot efi stub | `linuxx64.efi.stub` |
| Cmdline = 命令行参数 | `root=/dev/disk/by-partlabel/system rw rootwait console=ttyMSM0,1150200n8 pcie_pme=nomsi earlycon kernel.sched_pelt_multiplier=4` |
| OS-release = 操作系统发行版本 |
ID = qcom-wayland
Name = “QCOM Reference Distro with Wayland”
VERSION = “1.0”
VERSION_ID = 1.0
PRETTY_NAME = “QCOM Reference Distro with Wayland 1.0”
|
**Image classes**
`meta-qcom-hwe/classes` 包含两个 class `uki.bbclass` 和 `image-efi.bbclass`:
- `uki.bbclass` 生成 `uki.efi`。
- `image-efi.bbclass` 使用 `uki.efi` 生成 `efi.bin`。
- `qcom-minimal-image` 继承 `image-efi.bbclass`。
- **EFI 镜像**
EFI 系统分区 (ESP) 包含 `efi.bin`,即 vfat 文件。该文件包含 UEFI 启用 systemd-boot 所需的所有详细信息。UEFI 挂载 ESP 分区并执行 systemd-boot 管理器 (`bootaa64.efi`)。systemd-boot 管理器解析 UKI 镜像,加载内核镜像,然后将控制权转交给内核镜像。
有关 ESP 结构的更多信息,参见 [EFI 系统分区](https://wiki.archlinux.org/title/EFI_system_partition)。下图显示了 ESP 分区的结构示例。其中包含 systemd-boot (`bootaa64.efi`) 和 UKI (`uki.efi`)。
Figure : efi.bin 文件

- **签名**
安全启动是 UEFI 标准中的一项安全功能,在开发设备中尚未启用。该功能通过维护被授权或禁止在启动时运行的加密签名二进制文件的列表,为预启动过程增添了一层保护。它有助于确保机器启动固件和 HLOS 启动组件(boot manager、kernel 和 initramfs)不会被篡改。
UEFI 安全启动使用数字签名来验证其加载的代码的真实性和完整性。所有密钥都存储在 UEFI 安全变量中。UEFI 安全启动通过使用 PK、KEK、db 和 dbx 密钥来实现。
要使用安全启动功能,需要使用 PK、KEK 和 db 密钥。虽然可以添加多个 KEK、db 和 dbx 证书,但只允许使用一个平台密钥。
只有在系统中注册 PK 后,才会启用 UEFI 安全启动。建议在安全启动启用过程的最后一步提供 PK 密钥。有关 Qualcomm 实现 UEFI 安全启动的更多信息,可参阅 [安全启动](https://docs.qualcomm.com/bundle/publicresource/topics/80-70014-11/secure-boot.html)。
**用于对 HLOS 镜像进行签名的 host tool**
启用 UEFI 安全启动后,必须对 EFI 和 DTB 镜像进行签名。为简化此过程,可以使用 host signing tool。此命令行 Python 脚本在 Linux 主机(最好是 Ubuntu 18.04 或更高版本)上运行。它通过两个单独的操作自动对 EFI 和 DTB 镜像进行签名,这两个操作在编译过程完成后调用。
**host signing tool 概述**
host signing tool 在安装了 Python3 的 Linux 机器上运行。它可以在单个操作中对 EFI 镜像或 DTB 镜像进行签名。若要同时对 EFI 和 DTB 镜像进行签名,用户必须以不同的输入调用该工具两次。

host tool 需要将未签名的 EFI 或 DTB 文件以及证书和密钥作为输入。调用后,该工具将解包未签名的镜像,使用提供的密钥和证书对可用项目进行签名,然后重新将镜像打包,将未签名的版本替换为已签名的版本。
**host signing tool 的使用方法**
- **运行该工具的前提条件**
若要运行此工具,Linux 主机必须安装以下各项:
- OpenSSL 和 sbsign 工具
- Python3
- pip、subprocess、shlex、socket 和 shutil python 模块
- **配置 host signing tool**
用户在开始操作之前必须对 host signing tool 进行配置。
- **`config.in` 文件**
host tool 需要用户在 `config.ini` 配置文件中提供必要的信息。启动时,脚本会读取此文件并相应地对镜像进行签名。以下是配置文件中列出的变量:
Figure : config.ini 文件

Table : config.ini 文件中的变量
| config.ini 中的变量 | 值 | 说明 |
| --- | --- | --- |
| `image_type` | `efi/dtb` | 使用该配置来单独选择 `efi` 或 `dtb` 进行签名。 |
| `file_path` | `local/remote` | `local` – 密钥及 `efi.bin`/`dtb.bin` 与脚本位于同一路径下。
`remote` – 将 `efi.bin`/`dtb.bin` 及密钥从远程 Linux 机器复制到当前路径。 |
| `local_machine_private_key_path` | `` | 如果 `file_path = remote`,则该文件与远程计算机建立 SSH 连接。 |
| `loader_conf_timeout` | `` | systemd-boot menu 等待时间,用于验证二进制文件。对 `efi.bin` 进行签名时需要使用此选项。 |
| `efi/keys/dtb_remote_hostname` | `` | 如果 `file_path = remote`,则 host tool 选择远程机器的主机名称,以便使用 SCP 从远程机器复制 `efi/keys/dtb` 文件。 |
| `efi/keys/dtb_remote_username` | `` | 如果 `file_path = remote`,则 host tool 选择远程机器的用户名,以便使用 SCP 从远程机器复制 `efi/keys/dtb` 文件,但前提是已在本地机器上创建用户名。 |
| `efi/keys/dtb_remote_filepath` | `` | 如果 `file_path = remote`,则 host tool 选择远程机器上 `efi/key/dtb` 文件的路径,以便使用 SCP 从远程机器复制该文件。 |
- **使用 config.ini 文件进行配置**
1. 镜像选择:用户必须通过设置 `image_type` 变量来指定要对哪个镜像进行签名。选项包括 `efi` 或 `dtb`。
2. 文件位置:用户必须使用 `file_path` 变量来指示未签名的 EFI/DTB 镜像、密钥和证书的位置。
如果用户在配置文件中选择 `local`,则必须手动将 EFI/DTB 镜像、密钥和证书文件复制到本地工作目录。
1. 在与脚本相同的路径中创建 `unsigned_binaries` 目录,然后将 `efi.bin`/`dtb.bin` 镜像复制到该目录中。
2. 在与脚本相同的路径中创建 `keys` 目录,然后将 `db.auth`、`db.crt`、`db.key`、`KEK.auth` 和 `PK.auth` 文件复制到该目录中。
如果用户希望脚本从同一网络上的远程 Linux 机器自动复制所需的文件,则必须在配置文件中选择 `remote`。
在配置文件中,用户必须提供以下变量的信息:
- `local_machine_private_key_path`(必须提供)
- `[efi_config]` 部分(如果 `image_type` 为 `efi`)
- `[keys_config]` 部分(必须提供)
- `[dtb_config]` 部分(如果 `image_type` 为 `dtb`)
Note: 该脚本支持在同一网络内通过 SCP 从另一台 Linux 机器复制文件。
3. Loader 配置超时:如果在配置文件中将 `image_type` 设置为 `efi`,则用户必须更新 `loader_conf_timeout` 变量。
4. 处理缺失的配置:如果用户未提供配置信息,脚本仍会运行并通过命令行提示用户输入缺少的信息。
- **运行 host signing tool**
1. 调用 host tool:完成代码编译过程并获取未签名的 `efi.bin` 和 `dtb.bin` 镜像后,调用 host signing tool。
2. 准备好主机:将 host signing tool 文件(`signing_tool.py` 和 `config.ini`)存储在 Linux 机器上。确保两个文件位于同一工作目录中。
3. 配置工具:根据配置说明对 host signing tool 进行配置。
4. 运行工具:在命令行中使用以下命令执行 host tool: `$python3 signing_tool.py`
5. 交互过程:host signing tool 将用户所做的选择和操作命令显示在屏幕上,将错误显示在命令行中。
6. 已签名的镜像:该工具完成其过程后,会在同一工作目录中创建一个名为 `signed_binaries` 的目录。已签名的 `efi.bin` 或 `dtb.bin` 镜像存储在该位置。该工具会在签名后删除用户创建的其他目录。
7. 对两个镜像重复执行上述步骤:将此过程执行两次,一次用于对 `efi.bin` 进行签名,一次用于对 `dtb.bin` 进行签名。在每次签名操作后,应先删除 `signed_binaries` 目录,然后再开始新的操作。
- **host signing tool 工作流程**
下图所示为 host signing tool 的工作流程:
Figure : host signing tool 工作流程

- host tool 需要使用 `efi.bin` 和 `dtb.bin`路径(绝对路径或网络路径)。
- `efi.bin` 包含 `uki.efi`(Linux 内核镜像)和 `bootaa64.efi`(boot loader 镜像)。
- `dtb.bin` 包含 `combined-dtb.dtb`。
- host tool 需要使用 `certificate` 和 `key` 的路径(绝对路径或网络路径)来对镜像进行签名。
- host tool 将 `efi.bin`/`dtb.bin` 挂载在 FAT 分区,其中提供以下目录结构并遵循单独的签名过程:


- 对镜像签名后,host tool 会复制 `efi.bin` 和 `dtb.bin` 在 `/loader/keys/authkeys` 目录下的 *Auth* 文件。*Auth* 文件必须与密钥和证书一同位于目标或安全团队托管的路径下。
- host tool 必须在 `systemdboot` 加载程序配置中配置等待时间。该等待时间会暂停内核加载,并允许用户查看和选择 `systemdboot` 菜单选项。`loader.conf` 文件必须位于更新后的 `efi.bin` 文件中。
Note: `dtb.bin` 文件不遵循该过程。
- host tool 配置 `/loader/loader.conf`。
- `loader.conf` 的语法如下:`timeout x`,其中 x = 超时时间(秒)。
- 完成镜像签名后,host tool 必须从 FAT 分区卸载 `efi.bin/dtb.bin`。将主机上已签名的 `efi.bin/dtb.bin` 存储在 `signed_binaries` 目录下(与 host tool 的路径类似)。
- 以下是已签名的 `efi.bin` 和 `dtb.bin` 的目录结构。


**`efi.bin` 签名过程**
- host tool 使用 `sbsign` 工具分别对 `uki.efi` 和 `bootaa64.efi` 镜像进行签名。
- `sbsign` 需要使用 `certificate` 和 `key` 来完成签名过程。其语法如下所示,其中 `dsk1.key` 为密钥,`dsk1.crt` 为证书,输出文件名与输入文件名相同:
sbsign --key --cert Copy to clipboard
示例:
- sbsign --key dsk1.key --cert dsk1.crt bootaa64.efi bootaa64.efiCopy to clipboard
- sbsign --key dsk1.key --cert dsk1.crt uki.efi uki.efiCopy to clipboard
**`dtb.bin` 签名过程**
- host tool 需要使用 `dtb.bin` 文件的路径。
- host tool 需要使用 `key` 和 `certificate` 的路径(绝对路径或网络路径)来对镜像进行签名。
- UEFI 安全启动需要使用 PE 格式的文件进行验证。非 PE 文件(如 `dtb`)无法使用 `sbsign` 进行签名,因为该签名工具需要使用 PE 格式的文件作为输入。
- host tool 使用 `openssl` 工具对 `dtb` 文件进行签名。其语法如下所示,其中 `dsk1.key` 为密钥,`dsk1.crt` 为证书:
openssl cms -sign -inkey <.key file> -signer <.crt file> -binary -in --out -outform DERCopy to clipboard
示例:
openssl cms -sign -inkey dsk1.key -signer dsk1.crt -binary -in --out -outform DERCopy to clipboard
该命令将 dtb 文件的签名添加到单独的文件 (`foo.dtb.sig`) 中,不改变原先的文件 (`foo.dtb`)。因此,host tool 必须同时保留这两个文件,其中的 `*.dtb.sig` 文件在 UEFI 安全启动验证期间使用。
- **Multi-DTB 支持**
Qualcomm 支持基于同一 SoC 的多种板卡。例如,基于 QCS6490 的板卡包括 RB3 核心套件和 RB3 Gen2 视觉套件。每种板卡在内核中都有自己的 DTB。在启动过程中,UEFI 会根据特定的板卡选择合适的 DTB。为便于实现这一点,基于同一 SoC 的板卡的所有 DTB 都组合在一起并存储在 DTB 分区中。
**生成组合 DTB**
为了实现多 DTB 支持,所有支持的 DTB 会逐一附加,从而生成一个组合 DTB。

对于 RB3 Gen 2,以下 DTB 将合并生成一个组合 DTB,`combined-dtb.dtb`。
qcom/qcm6490-addons-idp.dtb \
qcom/qcs5430-fp1-addons-rb3gen2.dtb \
qcom/qcs5430-fp1-addons-rb3gen2-vision-mezz.dtb \
qcom/qcs5430-fp1p5-addons-rb3gen2.dtb \
qcom/qcs5430-fp1p5-addons-rb3gen2-vision-mezz.dtb \
qcom/qcs5430-fp2-addons-rb3gen2.dtb \
qcom/qcs5430-fp2-addons-rb3gen2-vision-mezz.dtb \
qcom/qcs6490-addons-rb3gen2.dtb \
qcom/qcs6490-addons-rb3gen2-video-mezz.dtb \
qcom/qcs6490-addons-rb3gen2-vision-mezz.dtb \
qcom/qcs6490-addons-rb3gen2-ptz-mezz.dtb \
qcom/qcs6490-addons-rb3gen2-ia-mezz.dtb \Copy to clipboard
**DTB 分区**
- `dtb.bin`(生成 `vfat` 镜像),其中包含组合 DTB 镜像。创建了一个名为 `dtb` 的专用分区,并在该分区刷写 `dtb.bin`。
- UEFI 解析位于 `dtb` 分区的组合 DTB,并为硬件选择匹配的 DTB。
Figure : 创建/签名 DTB

### 分区
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
Yocto 工作流程中的分区涉及以下实体:
| 实体 | 说明 |
| --- | --- |
| 分区布局文件 | 以 JSON 格式定义所有存储分区。 |
| gen\_partition工具 | 读取分区布局文件并生成由 Qualcomm Ptool 处理的内部 XML 格式。 |
| 分区 XML | 定义 Qualcomm 内部 XML 格式。 |
| Ptool | 提供 Qualcomm 分区工具,以将分区 XML 中的信息转换为 GPT 二进制文件。 |
下面详细介绍分区定义、现有分区,以及用于为 Qualcomm 电路板生成 GUID 分区表的工具:
Note: 以下分区布局和示例为 UFS 特定。
- **分区布局文件**
设备上的 UFS 被划分为不同的区域来分别存储启动链和 high-level OS 的各种镜像。为特定板卡定义的分区的完整信息在配置文件中定义。对于 RB3 Gen 2 板卡,UFS 闪存分区在工作区中的以下配置文件中定义:`meta-qcom-hwe/recipes-devtools/partition-utils/partition-confs/generic-ufs-partitions.conf`。
- **分区布局文件语法**
为了方便理解分区布局文件的语法,下面给出了 `generic-ufs-partitions.conf` 文件中的一些示例。配置文件中的前几个条目之一定义了磁盘类型、磁盘大小、LBA 大小(扇区大小),以及最后一个分区是否应该扩展到最后一个可用的 LBA。
# select disk type emmc | nand | ufs mandatory
# disk size in bytes is mandatory
--disk --type=ufs --size=137438953472 --write-protect-boundary=0 --sector-size-in-bytes=4096 --grow-last-partitionCopy to clipboard
下面给出了 `generic-ufs-partitions.conf` 文件中定义的一些分区示例。LUN0 中定义了多个分区,每一行定义一个单独的分区:
Note: 在以下示例中,GUID 取自 `partition.xml` 文件。
- 示例 1:LUN0 中定义的大小为 8 kB 的 `ssd` 分区。该分区不需要刷入文件。
--partition --lun=0 --name=ssd --size=8KB --type-guid=2C86E742-745E-4FDD-BFD8-B6A7AC638772Copy to clipboard
- 示例 2:LUN0 中定义的大小为 1024 kB 的 `misc` 分区。该分区不需要刷入文件。
--partition --lun=0 --name=misc --size=1024KB --type-guid=82ACC91F-357C-4A68-9C8F-689E1B1A23A1Copy to clipboard
LUN1 中定义了多个分区。每一行定义一个单独的分区:
- 示例 3:LUN1 中定义的大小为 3604 kB 的 `xbl_a` 分区。`xbl.elf` 文件刷写到该分区。
#This is LUN 1 - Boot LUN A
--partition --lun=1 --name=xbl_a --size=3604KB --type-guid=DEA0BA2C-CBDD-4805-B4F9-F428251C3E98 --filename=xbl.elfCopy to clipboard
- 示例 4:LUN1 中定义的大小为 300 kB 的 `xbl_config_a` 分区。`xbl_config.elf` 文件刷写到该分区。
#This is LUN 1 - Boot LUN A
--partition --lun=1 --name=xbl_config_a --size=300KB --type-guid=5A325AE4-4276-B66D-0ADD-3494DF27706A --filename=xbl_config.elfCopy to clipboard
LUN4 中定义一个分区:
- 示例 5:LUN4 中定义的大小为 512 kB 的 `aop_a` 分区。`x` 文件刷写到该分区。
--partition --lun=4 --name=aop_a --size=512KB --type-guid=D69E90A5-4CAB-0071-F6DF-AB977F141A7F --filename=aop.mbnCopy to clipboard
每个分区条目使用的选项如下:
- 必选选项:
--lun (mandatory for UFS, optional for emmc. Expressed as number)
--name (name for the partition, a string)
--size (size of the partition, generally expressed in KB)
--type-guid (GUID for the partition)Copy to clipboard
- 可选选项:
--attributes (Optional 64 bit attribute, e.g., 1000000000000004)
--filename (Name of the file that is flashed to the partition)
--readonly (whether the partition should be read-only, values true or false)
--sparse (whether the partition is for a sprased image, values true or false)Copy to clipboard
- **Linux HLOS 分区**
| 分区 | 说明 |
| --- | --- |
| EFI 分区 | EFI 系统分区 (ESP) 包含 `Esp.bin` 和 `vfat` 文件。该文件包含 UEFI 启用 systemd-boot 所需的所有详细信息。有关该镜像的更多信息,参见 [EFI 镜像](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html#systemd_boot__efi_image)章节。 |
| Rootfs 分区 | 该分区用于刷写 `system.img` 镜像文件。该镜像包含所有用户空间库和二进制文件。 |
| Overlay 分区 | 该分区留空。在启动时,文件系统被植入该分区,以用作一些 `/var` 挂载点的叠加。该文件系统中的镜像作为可写存储文件系统工作。与该镜像关联的 IMAGE\_FEATURES 为 `overlay-etc`。 |
- **分区工具 (Ptool)**
要对设备上的存储空间进行分区,可使用 `gen_partition` 命令生成 `partitions.xml` 文件,然后使用 Ptool 处理 `partitions.xml` 文件。Ptool 生成 GUID 分区表二进制文件,QDL 工具使用该二进制文件对闪存进行分区。Ptool 工作流程如下图所示:
Figure : Ptool 工作流程

位于 `/layers/meta-qcom-hwe/recipes-devtools/partition-utils/partition-confs` 中的 `generic-ufs-partitions.conf` 文件定义所有分区。`gen_partition.py` 工具处理并生成 `partition.xml`,这是 `ptool.py` 的必要输入。最后一步,Ptool 生成文件 `rawprogram.xml`、`patch.xml`、`gpt_main*.bin` 和 `gpt_backup*.bin`,这些文件对于 QDL 工具刷写设备至关重要。
要添加分区,应在配置文件(如 `generic-ufs-partitions.conf`)中使用通用唯一标识符 (UUID) 创建分区条目。添加条目后,运行 BitBake 命令以生成所有必要的文件:
bitbake Copy to clipboard
当镜像编译完成后,刷写镜像:
cd /build-qcom-wayland/tmp-glibc/deploy/images/qcm6490/qcom-console-image
./qdl prog_firehose_ddr.elf rawprogram*.xml patch*.xmlCopy to clipboard
### 容器化
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
Docker 容器可在 Qualcomm Linux 中启用。若要使用 Docker,需确保在 Qualcomm BSP 中已启用容器化功能,这些功能已经过集成和测试。要在 Qualcomm LE 设备上使用容器化功能,应确保添加 `meta-virtualization` 层 ([https://git.yoctoproject.org/meta-virtualization](https://git.yoctoproject.org/meta-virtualization)) 作为工作区的一部分。
- **Docker**
Docker 可在 `qcom-multimedia-image`中启用:
1. 对于镜像配方 `qcom-multimedia-image`,使用 `meta-qcom-distro/recipes-products/packagegroups/packagegroup-qcom-multimedia.bb` 包含 `packagegroup-container`。
2. 在编译并刷写镜像后,即可在设备上使用 Docker。
3. 若要检查内核兼容性,可在设备上运行 `check-config.sh` 脚本。若要检查配置,必须启用所需的内核配置并重新编译镜像。更多信息,参见[内核兼容性](https://docs.docker.com/engine/install/troubleshoot/#:~:text=Kernel%20compatibility,check%2Dconfig.sh%20script.&text=The%20script%20only%20works%20on%20Linux)。
4. | 在设备上运行任何 docker 命令后的 `systemctl status docker` 输出。 | 在设备上未运行任何 docker 命令时的 `systemctl status docker` 输出。 |
| --- | --- |
| 非活动(死锁) | 活动(运行中) |
以下用例已在启用 Docker 的情况下经过验证:
1. 从 `Linux/arm64`平台的 Docker 存储库中获取并在设备上测试成功运行的镜像如下:
- `busybox`
- `python`
- `alpine`
- `ubuntu`
- `postgres`
- `mongo`
- `nginx`
- `redis`
2. 使用 Docker 加载实用工具通过 tar 文件加载 Docker 镜像。
3. 通过 Docker 文件编译 Docker 镜像。
4. 将获取/编译的 Docker 镜像保存到 `.tar` 文件中。
5. 加载保存为 `.tar` 文件的 Docker 镜像。
6. 运行多个获取/编译的镜像的多个容器实例。
7. 检查设备上已加载的 Docker 镜像列表。
8. 检查设备上活动容器和全部容器的列表。
9. 使用 Docker 检查实用工具检查 Docker 镜像。
10. 使用 Docker 日志实用工具从容器中获取日志。
11. 使用 Docker 停止实用工具和 Docker 终止实用工具停止和终止容器。
12. 从设备中删除容器和 Docker 镜像。
- **从 Docker 访问硬件节点**
在 Docker 容器内运行的应用程序可能需要访问设备 (target-host) 中的设备节点和文件。在容器内运行的应用程序可以访问设备节点。这通过使用 Docker 运行命令将相应的设备节点作为选项进行传递来执行:
docker run -it --rm --device= --device= Copy to clipboard
要传递的设备节点在设备上的 `/dev/` 目录下。根据用例,例如,在图形场景中,`/dev/kgsl-3d0` 是使用 `--device=/dev/kgsl-3d0` 传递给 Docker 的节点之一。
从设备 (target-host) 中 Docker 文件/目录进行的存储分区访问也可以在容器内公开。使用以下命令可以将文件/目录作为绑定挂载公开:
docker run -it --rm --mount type=bind,source=,target= Copy to clipboard
使用以下命令可以运行在容器内公开多个目录、文件和设备节点的 Docker 容器:
docker run -it --rm --device= --device= --mount type=bind,source=,target= --mount type=bind,source=,target=
Copy to clipboard
- **Docker-compose**
Docker-compose 是一个用于定义和运行多容器应用程序的强大工具。使用该工具可以在单个易于理解的 YAML 配置文件中定义服务、网络和卷,从而简化对整个应用程序栈的管理。默认情况下,Qualcomm Linux 发行版将 Docker-compose 包含在镜像中:
- `python3-docker-compose` 软件包将添加到 `meta-qcom-distro` 元数据层的 `packagegroup-qcom-multimedia` 软件包组中。
**在设备上运行 docker-compose:**
1. 在设备上的可写路径(例如 `/var`)下创建或复制 Docker-compose YAML 文件(例如 `/var/docker-compose-yaml`),以便与设备上的 Docker-compose 一起使用。
2. 确保设备上提供了 Docker-compose YAML 文件中列出的 Docker 镜像。由 Docker-compose 实用工具启动的容器需要使用这些镜像。
3. 若要对多个 YAML 文件运行 Docker-compose,可使用以下命令:
docker-compose -f .yml -f .yml upCopy to clipboard
Docker-compose 按照 Docker-compose YAML 文件中的配置运行并启动 Docker 容器。Docker-compose 命令返回结果后,运行 `docker ps -a` 和 docker 日志 `` 以检查 Docker 容器是否按预期运行。
如需了解有关 Docker-compose 的更多信息,可访问 [https://docs.docker.com/compose](https://docs.docker.com/compose)。
### Kubernetes
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
Kubernetes 是一个开源平台,用于自动部署、扩展和管理容器中运行的应用程序。它有助于跨多个设备协调容器,确保应用程序实现高效资源利用、高可用性和可扩展性。有关 Kubernetes 的更多信息,可访问 [https://kubernetes.io/](https://kubernetes.io/)。
- **启用 Kubernetes**
- Qualcomm Linux 发行版通过如下更改默认在 `qcom-multimedia-image`中启用 Kubernetes:
- 在 `meta-qcom-hwe` 中定义 `packagegroup-qcom-k8s`。
- `packagegroup-qcom-k8s` 包含在 `recipes-products/packagegroups/packagegroup-qcom-multimedia.bb` 中。
- Qualcomm Linux 内核在 `arch/arm64/configs/qcom_defconfig`中启用了以下内核配置,以支持 Kubernetes runtime:
- CONFIG_CGROUP_FAVOR_DYNMODS=yCopy to clipboard
- CONFIG_CFS_BANDWIDTH=yCopy to clipboard
- CONFIG_CGROUP_HUGETLB=yCopy to clipboard
- CONFIG_NETFILTER_XT_MATCH_COMMENT=mCopy to clipboard
- CONFIG_IP_NF_TARGET_REDIRECT=mCopy to clipboard
- CONFIG_HUGETLBFS=yCopy to clipboard
- | 未使用 `kubeadm` 将设备设置为 Kubernetes 节点时的 `systemctl status kubelet` 输出。 | 使用 `kubeadm` 将设备设置为 Kubernetes 节点时的 `systemctl status kubelt` 输出。 |
| --- | --- |
| 非活动(死锁) | 活动(运行中) |
Kubernetes 会将多个容器视为一个容器组来进行协调,允许用户将应用程序及其依赖项(库和配置文件)打包到一个单元中。这样可简化部署,并确保集群中不同环境和节点之间的一致性。在 Kubernetes 的上下文中,节点是指设备或机器。Kubernetes 的架构有两种类型的资源:
- **主节点/控制平面:**主节点是充当 Kubernetes 的控制平面的设备。它对集群做出全局决策(例如调度),并检测和响应集群事件(例如在不符合部署的复制字段时启动新容器)。
- **工作节点:**这些节点是包含运行容器所需服务的设备,由主节点管理。每个工作节点都会运行 `Kubelet`,这一进程负责 Kubernetes 主节点与工作节点之间的通信;它管理机器上运行的容器组。
容器组是 Kubernetes 中最小的执行单元。它代表集群中正在运行的进程的单个实例,作为对 Kubernetes 运行的容器的抽象。
- **使用 Kubernetes**
以下是两个设备作为节点连接到公共接入点的示例:
- **主节点**:其中一个设备被指定为主节点。
- **工作节点**:另一个设备充当工作节点。从主节点创建的部署和容器组在工作节点上运行。
部署和容器组使用 YAML 文件创建。这些文件定义了在创建过程中部署和容器组的首选状态。用户可以从主节点和工作节点进入这些容器组/容器的 shell 来执行调试、监测和其他任务。
- **将设备设为主节点**
以下是将设备设为主节点的步骤:
1. 将设备连接至 Wi-Fi。
2. 运行以下命令:
kubeadm init --ignore-preflight-errors=SystemVerification
--apiserver-advertise-address=Copy to clipboard
Note: `` 是 `wlan0` 接口的 IP 地址,同时也是将设备连接到 Wi-Fi 后 `ifconfig` 命令的输出。
3. 上述命令初始化 Kubernetes 控制平面。要开始使用集群,应以 root 用户身份运行以下命令:
mount -o remount, rw /
mkdir -p $HOME/.kube
cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
chown $(id -u):$(id -g) $HOME/.kube/configCopy to clipboard
使用 `kubeadm init` 成功将设备初始化为主节点/控制平面后,`kubeadm` 将打印任何设备在作为工作节点加入集群时必须使用的命令。
- **将设备设为工作节点**
要将设备设置为工作节点并加入集群,应运行 `kubeadm join` 命令,其中 `kubeadm` 将在初始化主节点后打印命令。
Note: 要抑制 Kubernetes 在使用 vfs 图形驱动程序运行 Docker 时报告的错误,应运行 `--ignore-preflight-errors=SystemVerification flag` 与 `kubeadm join` 命令。
Note: 集群中的每个节点都应该具有不同的 hostname。如果尝试将多个具有相同 hostname 的设备添加到单个集群时失败,应使用 `hostname ` 命令更改设备的 hostname。
- **从主节点创建部署和容器组**
要在工作节点上创建部署/容器组,应运行以下命令:
kubectl apply -f Copy to clipboard
在某个位置(如 `/var`)创建用户自己的 YAML 文件。YAML 文件示例:
- 用于针对 Ubuntu 镜像创建部署的 YAML 文件:
**ubuntu-deployment.yaml**
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app: ubuntu-deployment
name: ubuntu-deployment
spec:
replicas: 2
selector:
matchLabels:
app: ubuntu-deployment
template:
metadata:
labels:
app: ubuntu-deployment
spec:
containers:
- name: ubuntu-depl-pod
image: ubuntu:latest
command: ["sleep", "3650d"]Copy to clipboard
- 用于针对 Ubuntu 镜像创建容器组的 YAML 文件:
**ubuntu-pod.yaml**
apiVersion: v1
kind: Pod
metadata:
name: ubuntu-pod
labels:
app: ubuntu-pod
spec:
containers:
- name: ubuntu
image: ubuntu:latest
command: ["sleep", "604800"]
imagePullPolicy: IfNotPresent
restartPolicy: AlwaysCopy to clipboard
- **通过 `kubectl` 使用 Kubernetes 容器组**
- **使用 `kubectl` 获取集群中的节点**
要列出集群中的节点,应在主节点上运行以下命令:
kubectl get nodesCopy to clipboard
- **使用 `kubectl` 获取集群中现有的部署**
要列出集群中现有的部署,应在主节点上运行以下命令:
kubectl get deploymentCopy to clipboard
- **使用 `kubectl` 获取集群中现有的容器组**
要列出集群中现有的容器组,应在主节点上运行以下命令:
kubectl get podsCopy to clipboard
- **从主节点访问容器组的 shell**
要从主节点访问容器组的 shell 实例,应在主节点上运行以下命令:
kubectl exec -it -- Copy to clipboard
- **从工作节点访问容器组的 shell**
要使用 Docker 访问容器组(容器)的 shell 实例,应在工作节点上运行以下命令:
docker exec -it Copy to clipboard
Note: 通过使用 `docker ps -a` 命令列出所有容器来获得 ``。
**Docker 和 Kubernetes 相较于上游解决方案的更改**
- 配方 `meta-qcom-hwe`/`recipes-containers`/`docker`/`docker-ce_git.bbappend` 对 `/lib/systemd/system/docker.service` 进行了更改。在此更改过程中,`--exec-opt native.cgroupdriver=systemd` 被传递给作为服务的 `ExecStart` 的一部分运行的 `dockerd` 命令。这样做是为了在 Docker 与 Kubernetes 之间保持 `cgroupdriver` 的一致性。
- 配方`meta-qcom-hwe`/`recipes-containers`/`kubernetes`/`kubernetes_git.bbappend` 对 `/lib/systemd/system/kubelet.service.d/10-kubeadm.conf` 进行了更改。在此更改过程中,`--fail-swap-on=false` 作为 `KUBELET_EXTRA_ARGS` 的一部分进行传递。之所以这样做是因为 Kubernetes 预计 swap 会设为 **OFF**。由于 Qualcomm 的平台软件已启用 zram,因此 swap 设为 **ON**。
- 上游 `kubelet.service` 会尝试在设备启动时自动启动,即使设备未配置为 Kubernetes 节点也是如此。但是,此行为会占用资源并降低功耗效率。为解决这个问题,可删除 `meta-qcom-hwe/recipes-containers/kubernetes/kubernetes_git.bbappend` 文件中的 `WantedBy=multi-user.target`,以此来修改 `kubelet.service`。现在,它会在使用 `kubeadm` 将设备设置为 Kubernetes 节点时启动,而不是在 `multi-user.target` 中自动启动。
### 属性
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
属性 (`property-vault`) 提供在系统中以字符串形式存储和共享键值对的功能。任何软件组件都可以共享特定键的任何值,并且任何其他进程都可以使用相同的键访问该值。`property-vault` 提供一个在重启后定义保留属性的选项。组件可以使用 `property-vault`共享特定信息,这些信息可能与设备上的任何其他模块相关。可以使用命令行界面 (CLI) 访问这些键值对。
- **使用 CLI 对属性进行操作**
要使用 CLI 设置属性,应使用以下命令:
setprop "my-key" "my-value"Copy to clipboard
要使用 CLI 访问属性,应使用以下命令:
getprop "my-key"Copy to clipboard
# Result of the previous command: my-value
要使用 CLI 设置属性并在重启后保留该属性,应使用以下命令:
setprop "persist.my-key" "my-value"Copy to clipboard
- **在 C/C++ 源文件中使用属性**
在 C/C++ 源文件中使用属性的设置如下:
1. 如果必须在配方(例如 `example-recipe.bb`)中使用 `property-vault` 等属性,应对 `property-vault` 添加依赖项:
DEPENDS = "glib-2.0 property-vault"
RDEPENDS:${PN} = "property-vault"Copy to clipboard
2. 更改 `make`文件:
1. 如果使用 `automake`:
`configure.ac`
...
PKG_CHECK_MODULES(GLIB, glib-2.0 >= 2.16, dummy=yes, AC_MSG_ERROR(GLib >= 2.16 is required))
GLIB_CFLAGS="$GLIB_CFLAGS"
GLIB_LIBS="$GLIB_LIBS"
AC_SUBST(GLIB_CFLAGS)
AC_SUBST(GLIB_LIBS)
AC_CONFIG_FILES([Makefile])
...Copy to clipboard
`Makefile.am`
root_sbindir = "/sbin"
root_sbin_PROGRAMS = property-test
property_test_SOURCES = source.c
property_test_CFLAGS = @GLIB_CFLAGS@
property_test_LDFLAGS = @GLIB_LIBS@ -lpropertyvaultCopy to clipboard
2. 如果使用 `cmake`:
`CMakeList.txt`
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99 -lpthread -lrt -lm -lglib-2.0 -ldl -latomic")
target_link_libraries (techteamlocalibname propertyvault)Copy to clipboard
3. 将源文件修改为 `get` 和 `set` 属性:
`source.c`
#include "properties.h"
int main() {
// setting a property
property_set("my-key", "my-value");
// getting a property
char paramstr[PROPERTY_VALUE_MAX];
property_get("my-key", paramstr, ""); // value gets stored in paramstr
// setting a property and persisting it across reboot
property_set("persist.my-key", "my-value");
return 0;
}Copy to clipboard
### syslog() 的日志工具
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
Qualcomm 专有项目和开源项目中的日志被记录到 `syslog` 中。
`syslog()` 用于将日志写入设备。使用 `rsyslog` 作为日志系统,根据指定规则处理日志。`rsyslog` 不仅可以接受来自系统和内核消息的输入,还可以接受来自使用 `syslog protocol` 进行记录的应用程序的日志。
当应用程序调用 `syslog` 时,`rsyslog` 会根据其配置重定向这些日志。`rsyslog` 配置位于 `/etc/rsyslog.conf` 或 `/etc/rsyslog.d` 目录下。
使用 `logrotate` 服务对旧日志进行存档。
### persist 分区
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
为 UFS 定义的 persist 分区用于存储 BSP 软件组件在重启期间所需的持久性数据。在设备生命周期内,用户请求的操作不得擦除此数据。
- **persist 挂载点**
`/var/persist` 目录用作文件系统的挂载点,该文件系统在名为 persist 的分区上创建。配方 `overlayfs-qcom-paths_1.0.bb` 负责在 rootfs 上创建目录并将 systemd 单元 `var-persist.mount` 安装到 `local-fs.target`。
在启动时,systemd 单元 `var-persist.mount` 将 `/dev/disk/by-partlabel/persist` 挂载到 `/var/persist`。通过运行如下挂载命令显示 persist 挂载点:
sh-5.1# mount | grep persist
/dev/sda10 on /var/persist type ext4 (rw,relatime,rootcontext=system_u:object_r:qcom_persist_t:s0,seclabel,stripe=128)Copy to clipboard
- **调整 persist 分区的大小**
使用配方 `resize-partitions.bb` 和 `resize-partition.service.in` 文件调整 overlay 分区的大小。调整分区大小的服务在设备启动时运行,以根据分区的大小创建和设置文件系统。
### 辅助虚拟机
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
### About this task
本节提供了详细步骤,用于编译支持访客虚拟机 (guest VM) 的 Qualcomm Linux 镜像,包括 VM 管理工具(`crosvm`、`qemu`)、内核镜像和 guest VM 的 rootfs。编译完成后,会生成一个 Guest VM 内核(镜像)和 rootfs (`initrd.img`),并打包到系统根文件系统中。以下小节提供了有关用户如何为镜像启用 VM 支持的分步指南。
### Procedure
1. **设置主机**
使用以下命令在主机上安装 clang:
sudo apt install clang-11Copy to clipboard
2. **启用 meta-rust 层**
meta-rust 层提供 rust 编译器 (rustc) 和软件包管理器 (cargo) 来编译 crosvm(使用 rust 语言实现)。
向 `meta-qcom-distro/conf/bblayers.conf` 目录中的 EXTRALAYERS 添加 meta-rust 层。
`vi conf/bblayers.conf`
EXTRALAYERS ?= " \
${WORKSPACE}/layers/meta-rust \
"Copy to clipboard
3. **升级 rust 版本**
创建文件 `meta-qcom-distro/conf/distro/include/rust_version.inc`,内容如下:
`vi meta-qcom-distro/conf/distro/include/rust_version.inc`
# include this in your distribution to easily switch between versions
# just by changing RUST_VERSION variable
RUST_VERSION ?= "1.73.0"
PREFERRED_VERSION_cargo ?= "${RUST_VERSION}"
PREFERRED_VERSION_cargo-native ?= "${RUST_VERSION}"
PREFERRED_VERSION_libstd-rs ?= "${RUST_VERSION}"
PREFERRED_VERSION_rust ?= "${RUST_VERSION}"
PREFERRED_VERSION_rust-cross-${TARGET_ARCH} ?= "${RUST_VERSION}"
PREFERRED_VERSION_rust-llvm ?= "${RUST_VERSION}"
PREFERRED_VERSION_rust-llvm-native ?= "${RUST_VERSION}"
PREFERRED_VERSION_rust-native ?= "${RUST_VERSION}"Copy to clipboard
将 `rust_version.inc` 文件包含在 `meta-qcom-distro/conf/distro/qcom-wayland.conf` 路径中。
`conf/distro/qcom-wayland.conf`
require conf/distro/include/rust_version.incCopy to clipboard
4. **将 VM 软件包添加到镜像中**
创建一个软件包组 `packagegroup-qcom-vm` 并通过 `packagegroup-qcom` 将其添加到镜像中。更新软件包 `RDEPENDS:${PN}` 变量并添加 `RDEPENDS:packagegroup-qcom-vm`,如下所示:
`meta-qcom-distro/recipes-products/packagegroups/packagegroup-qcom.bb`
PACKAGES += "packagegroup-qcom-vm"
RDEPENDS:${PN} += "packagegroup-qcom-vm"
RDEPENDS:packagegroup-qcom-vm = "\
crosvm \
pack-svm \
kvmtool \
qemu \
"Copy to clipboard
5. **编译镜像**
要编译镜像,应使用以下命令:
bitbake qcom-console-imageCopy to clipboard
6. **启动 VM**
若要查看 [Guest VM 编译支持](https://docs.qualcomm.com/bundle/publicresource/topics/80-70014-3/features.html#guest-vm-build-support)所述的预期输出,需启动 VM。
### 使用配方处理 out-of-tree kernel modules 和设备树
Source: [https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html](https://docs.qualcomm.com/doc/80-70014-27Y/topic/platform_software_features.html)
有关编译 out-of-tree kernel module 的信息,参见[添加内核模块](https://docs.qualcomm.com/bundle/publicresource/topics/80-70014-3/customize.html#add-kernel-module)。
有关设备树/设备树 blob 管理的信息,参见[平台支持](https://docs.qualcomm.com/bundle/publicresource/topics/80-70014-3/customize.html#platform-support_0)。
Last Published: Oct 09, 2024
[Previous Topic
概述](https://docs.qualcomm.com/bundle/publicresource/80-70014-27Y/topics/intro_yocto_linux_qualcomm.md) [Next Topic
用户定制](https://docs.qualcomm.com/bundle/publicresource/80-70014-27Y/topics/user_customizations.md)