OpenHarmony设备开发轻量系统芯片移植指导
概述
本文档从芯片适配的端到端视角,为芯片/模组制造商提供基于OpenHarmony的芯片适配指导。典型的芯片架构,例如cortex-m、risc-v系列都可以按照本文档进行适配移植。
约束与限制
本文档适用于OpenHarmony LTS 3.0.1及之前版本的轻量系统的适配。
说明:
本文仅对OpenHarmony移植适配过程中需要关注的文件和配置项进行介绍,其他文件以及配置项开发者无需关注,故不作详细介绍。
适配流程
主要开展基于伙伴硬件平台面向OpenHarmony系统的移植适配工作,具体细分为:移植准备、移植内核、移植子系统和移植验证四个环节,见表1芯片适配步骤。
表1 芯片适配步骤
步骤 | 介绍 |
移植准备 | 从OpenHarmony开源社区下载代码,并完成编译环境搭建,基于此初步熟悉和了解OpenHarmony的编译构建框架。 |
移植内核 | 将伙伴的SDK移植到OpenHarmony平台,同时根据芯片arch支持情况确认是否需要开展arch的适配工作。 |
移植子系统 | 开展包括启动子系统、文件子系统、安全子系统、通信子系统和外设驱动的移植。 |
移植验证 | 在适配完成之后使用OpenHarmony社区提供的兼容性测试套件对适配的工程进行基本接口的测试验证,同时伙伴需要使用自有测试能力对适配工程开展质量验证活动。 |
图1 业务总体流程
基本概念
表2 基本概念
名词 | 介绍 |
子系统 | 是一个逻辑概念,它由一个或多个具体的部件组成。OpenHarmony整体遵从分层设计,从下向上依次为:内核层、系统服务层、框架层和应用层。系统功能按照“系统 > 子系统 > 部件”逐级展开,在多设备部署场景下,支持根据实际需求裁剪某些非必要的子系统或部件。 |
部件 | 系统最小的可复用、可配置、可裁剪的功能单元。部件具备目录独立可并行开发、可独立编译、可独立测试的特征。 |
hb | OpenHarmony的命令行工具,用来执行编译命令。 |
kv | 键值对(key-value),描述数据存储的格式。 |
移植准备
由于OpenHarmony工程需要在Linux环境下进行编译,此章节将指导厂商搭建OpenHarmony的编译环境、获取OpenHarmony源码,并且创建厂商工作目录完成厂商芯片的编译框架适配。
搭建编译环境
开展移植前请参考开发环境准备完成环境搭建工作。
获取源码
获取操作
请参考获取源码完成源码下载并进行编译。
说明:
本文档仅适用于OpenHarmony LTS 3.0.1及之前版本,所以请获取对应版本的源码。
目录介绍
OpenHarmony源码重要目录介绍见表1 OpenHarmony重要目录,其中device和vendor目录为芯片厂商和终端模组厂商工作区域(在搭建编译框架部分详细介绍)。
表1 OpenHarmony重要目录
目录 | 用途 |
build | 编译框架所在目录。 |
kernel/liteos_m | 内核所在的目录,其中arch目录描述支撑的内核架构。 |
device | 芯片厂商适配目录,其中“config.gni”描述当前芯片使用的arch,工具链,编译链接选项等。 |
vendor | 终端模组厂商适配目录,其中“config.json”描述需要集成的OpenHarmony子系统列表。 |
utils | file,kv等相关的适配。 |
搭建编译框架
厂商开展移植工作时,需要在工程中按照公司名、芯片型号、开发板型号等创建工作目录,并且将所创目录加入到OpenHarmony的编译框架中,使厂商的工作目录能够参与编译,开发者可参照以下步骤进行操作。
- 新增芯片厂商。 基于某款芯片进行OpenHarmony的适配,需要在device目录下创建芯片厂商目录,目录内文件描述内核类型,编译工具链,编译链接选项,内核配置选项等。
创建目录规则:“device/{芯片厂商}/{芯片开发板}”。
例:“device/MyDeviceCompany/MyBoard”
device
├── hisilicon # hisilicon芯片相关目录,创建目录时可供参考
├── MyDeviceCompany # MyDeviceCompany 芯片厂商
│ └── MyBoard # MyBoard 芯片型号
│ ├── BUILD.gn
│ ├── liteos_m
│ │ └── config.gni # 芯片工具链,编译链接选项
│ └── target_config.h # 内核配置选项
└── qemu # qemu相关
编译脚本:将“device/MyDeviceCompany/MyBoard”下的文件添加到OpenHarmony编译框架中。
路径:“device/MyDeviceCompany/MyBoard/BUILD.gn”
group("MyBoard") { #将此BUILD.gn文件加入解析
print("MyDeviceCompany MyBoard is under developing.")
}
开发板编译配置:包括内核类型、工具链类型以及编译参数等内容(详见表2“config.gni”主要配置项)。
路径:“device/MyDeviceCompany/MyBoard/liteos_m/config.gni”
# Kernel type, e.g. "linux", "liteos_a", "liteos_m".
kernel_type = "liteos_m"
# Kernel version.
kernel_version = ""
# Board CPU type, e.g. "cortex-a7", "riscv32".
board_cpu = "cortex-m4"
# Board arch, e.g. "armv7-a", "rv32imac".
board_arch = ""
# Toolchain name used for system compiling.
# E.g. gcc-arm-none-eabi, arm-linux-harmonyeabi-gcc, ohos-clang, riscv32-unknown-elf.
# Note: The default toolchain is "ohos-clang". It's not mandatory if you use the default toochain.
board_toolchain = "arm-none-eabi-gcc"
# The toolchain path instatlled, it's not mandatory if you have added toolchian path to your ~/.bashrc.
board_toolchain_path = ""
# Compiler prefix.
board_toolchain_prefix = "arm-none-eabi-"
# Compiler type, "gcc" or "clang".
board_toolchain_type = "gcc"
# Board related common compile flags.
board_cflags = []
board_cxx_flags = board_cflags
board_ld_flags = []
# Board related headfiles search path.
board_include_dirs = []
# Board adapter dir for OHOS components.
board_adapter_dir =""
表2 “config.gni”主要配置项
配置项 | 介绍 |
kernel_type | 开发板使用的内核类型,例如:“liteos_a”,“liteos_m”,“linux”。 |
kernel_version | 开发板使用的内核版本。 |
board_cpu | 开发板CPU类型,例如:“cortex-m4”,“cortex-a7”,“riscv32”。 |
board_arch | 开发芯片arch指令集, 例如:“armv7-a”。 |
board_toolchain | 开发板自定义的编译工具链名称,例如:“gcc-arm-none-eabi”。若为空,则使用默认为ohos-clang。 |
board_toolchain_path | 编译工具链路径,为空则默认使用环境变量中的工具链。 |
board_toolchain_prefix | 编译工具链前缀,例如:“arm-none-eabi-”。 |
board_toolchain_type | 编译工具链类型,目前支持gcc和clang。 |
board_cflags | 开发板配置的c文件编译选项。 |
board_cxx_flags | 开发板配置的cpp文件编译选项。 |
board_ld_flags | 开发板配置的链接选项。 |
board_include_dirs | 开发板配置的系统头文件路径列表。 |
board_adapter_dir | 开发板适配文件路径。 |
2.新增模组终端厂商。 基于某款具备OpenHarmony能力的芯片进行模组终端开发,需要在vendor下创建模组厂商目录,目录内容主要是使用的OpenHarmony子系统能力。
创建目录规则:“vendor/{产品模组厂商}/{产品模组名称}”。
例:“vendor/MyVendorCompany/MyProduct”
vendor
├── hisilicon # hisilicon 产品相关目录,可供参考
└── MyVendorCompany # MyVendorCompany 产品模组厂商
└── MyProduct # 具体产品
├── BUILD.gn
└── config.json # 产品子系统列表
编译脚本:将“vendor/MyVendorCompany/MyProduct/BUILD.gn”下的文件添加到OpenHarmony编译框架中。
路径:“vendor/MyVendorCompany/MyProduct/BUILD.gn”
group("MyProduct") {
print("MyVendorCompany MyProduct is under developing.")
}
产品配置信息:包括产品名、设备厂商、内核类型以及所添加的子系统列表等信息(详见表3)。
路径:“vendor/MyVendorCompany/MyProduct/config.json”
{
"product_name": "MyProduct",
"ohos_version": "OpenHarmony 1.0",
"device_company": "MyDeviceCompany",
"board": "MyBoard",
"kernel_type": "liteos_m",
"kernel_version": "",
"subsystems": [
{
"subsystem": "startup",
"components": [
{ "component": "bootstrap", "features":[] },
{ "component": "syspara_lite", "features":
[
"enable_ohos_startup_syspara_lite_use_thirdparty_mbedtls = false"
]
}
]
}
],
"vendor_adapter_dir": "",
"third_party_dir": "",
"product_adapter_dir": "//vendor/MyVendorCompany/MyProduct/hals",
}
表3 “config.json”文件配置项
配置项 | 介绍 |
product_name | 产品名称,hb set时显示产品名称。 |
ohos_version | OpenHarmony版本号,与实际版本保持一致即可。 |
device_company | 芯片厂商名称,与device的二级目录名称一致。 |
board | 开发板名称,与device的三级目录名称一致。 |
kernel_type | 内核类型,应与开发板移植的OpenHarmony系统内核类型匹配。 |
kernel_version | 内核版本号,与config.gni中kernel_version值匹配。 |
subsystem | 产品选择的子系统,应为OS支持的子系统。子系统定义请见build/lite/components目录下的各子系统描述文件。 |
components | 产品选择的某个子系统下的组件,子系统支持的组件详见build/lite/components/{子系统}.json文件。 |
features | 产品配置的某个组件的特性,详见子系统源码目录对应的BUILD.gn文件。 |
vendor_adapter_dir | 适配IOT外设,UtilsFile文件读写能力,一般指向device下目录。使用详见文件子系统移植实例步骤2。 |
third_party_dir | 芯片厂自身三方软件目录,例如mbedtls,lwip等。如果使用OpenHarmony提供的三方软件,可暂时设空,也可参考hispark_pegasus的配置 。 |
product_adapter_dir | 适配hal_token以及系统参数,一般指向vendor下目录。使用详见启动恢复子系统移植实例步骤1。 |
说明:
- 编译构建系统会对字段进行有效性检查,其中:
- device_company,board,kernel_type,kernel_version应与芯片厂商配置匹配。
- subsystem,component应与“build/lite/components”下的部件描述匹配。
移植内核
移植芯片架构
芯片架构的移植是内核移植的基础,在OpenHarmony中芯片架构移植是可选过程,如果当前OpenHarmony已经支持对应芯片架构则不需要移植操作,在“liteos_m/arch”目录下可看到当前已经支持的架构,如表1:
表1 OpenHarmony已支持的架构
系列 | 型号 |
arm | arm9 cortex-m3 cortex-m4 cortex-m7 cortex-m33 |
csky | v2 |
risc-v | nuclei riscv32 |
xtensa | lx6 |
如果当前OpenHarmony尚未支持对应芯片架构,则需要芯片厂商自行适配,arch/include目录包含了通用的芯片架构适配所需要实现的函数。部分芯片架构代码由汇编实现,而汇编代码会因编译器的不同而不同,因此在具体的芯片架构下,还包含使用不同编译器(iar、keil、gcc等)编译的架构代码。
kernel/liteos_m/arch # 不同版本路径有差异
├── arm # arm系列
│ ├── arm9
│ ├── cortex-m3
│ ├── cortex-m33
│ │ ├── gcc # 使用gcc编译器编译的架构代码
│ │ └── iar # 使用iar编译器编译的架构代码
│ ├── cortex-m4
│ ├── cortex-m7
├── csky # csky系列
├── include # 包含通用的芯片架构所需要实现的函数
│ ├── los_arch.h # 定义芯片架构初始化所需要的函数
│ ├── los_atomic.h # 定义芯片架构所需要实现的原子操作函数
│ ├── los_context.h # 定义芯片架构所需要实现的任务上下文相关函数
│ ├── los_interrupt.h # 定义芯片架构所需要实现的中断和异常相关的函数
│ └── los_timer.h # 定义芯片架构所需要实现的系统时钟相关的函数
├── risc-v # risc-v系列
│ ├── nuclei
│ └── riscv32
└── xtensa # xtensa系列
└── lx6
移植芯片厂商SDK
编译框架搭建完成后,需要将芯片厂商的SDK加入OpenHarmony编译框架,从而可以编译出带SDK的烧录文件(此时编译出的是不带系统的裸机工程),以便OpenHarmony可以调用SDK中的接口。通过以下步骤将厂商SDK加入OpenHarmony编译框架中:
- 将芯片厂商sdk置于device目录下合适的位置,SDK的编译脚本/镜像打包脚本整合进编译框架中。 参考编译脚本:“device/MyDeviceCompany/MyBoard/BUILD.gn”
import("//build/lite/config/component/lite_component.gni")
executable("OHOS_Image.elf") { # 生成可执行程序
libs = [
"xxx/xxx/libxxx.a", # 链接厂商闭源静态库方法一
]
asmflags = [ # 汇编编译参数
"",
]
ldflags = [
"-T./xxx/xxx/xxx.ld", # 链接脚本文件
"-Lxxx/xxx/", # 指定厂商静态库路径
"-lxxx", # 链接厂商闭源静态库方法二
"-Wl,--whole-archive",
"-lmodule_xxx",
"-Wl,--no-whole-archive",
]
deps = [
"//build/lite:ohos", # 依赖OpenHarmony静态库编译完成,链接OpenHarmony编译出来的静态库
":sdk", # 依赖厂商源码静态库编译完成,链接厂商源码生成的静态库
]
}
copy("prebuilt") { # 准备镜像生成工具等,一般把镜像生成工具拷贝到out目录
sources = [ ] # 复制的源文件
outputs = [ ] # 复制的目标文件
}
static_library("sdk") {
sources = [ ] # 添加厂商源码编译成静态库
include_dirs = [ ] # 厂商源码包含头文件路径
}
build_ext_component("image") { # 调用shell命令,生成可烧写镜像文件
exec_path = rebase_path(root_out_dir) #指定shell命令执行目录
objcopy = "arm-none-eabi-objcopy"
objdump = "arm-none-eabi-objdump"
command = "$objcopy -O binary OHOS_Image.elf OHOS_Image.bin"
command += " && sh -c '$objdump -t OHOS_Image.elf | sort > OHOS_Image.sym.sorted'"
command += " && sh -c '$objdump -d OHOS_Image.elf > OHOS_Image.asm'"
deps = [
":prebuilt", # 无需准备镜像生成工具等可以删除此依赖
":OHOS_Image.elf", # 依赖elf文件的生成
]
}
group("MyBoard") { # MyBoard与当前路径名称一致
}
图1 目标的依赖执行顺序
2.自定义芯片厂“target_config.h”文件。 厂商应在“device/MyDeviceCompany/MyBoard”下合适位置创建内核配置文件“target_config.h”,并根据芯片的硬件资源修改参数(具体参数介绍详见表2target_config.h文件主要配置项)。
参考文件路径:“device/hisilicon/hispark_pegasus/sdk_liteos/platform/os/Huawei_LiteOS/targets/hi3861v100/include/target_config.h”
说明:
- 若已有的配置项不能满足需求,可查看“kernel/liteos_m/kernel/include/los_config.h”,其为liteos_m内核的全量配置文件。
- “target_config.h”文件中出现的配置将会覆盖“los_config.h”中的配置。
表2 target_config.h文件主要配置项
配置项 | 说明 | 参考值 |
OS_SYS_CLOCK | 系统时钟。 | 40000000UL |
LOSCFG_BASE_CORE_TICK_PER_SECOND | 操作系统节拍的时钟周期。 | 100UL |
LOSCFG_BASE_CORE_TICK_HW_TIME | 定时器裁剪的外部配置项。 | YES |
LOSCFG_PLATFORM_HWI | 是否采用接管中断的方式。 | YES |
LOSCFG_BASE_CORE_TSK_LIMIT | 支持的最大任务个数(除去空闲任务)。 | 32 |
LOSCFG_BASE_CORE_TSK_IDLE_STACK_SIZE | 空闲任务的堆栈大小。 | 0x180UL |
LOSCFG_BASE_CORE_TSK_DEFAULT_STACK_SIZE | 指定默认的任务栈大小,任务栈的大小按 8 字节大小对齐。 | 0x1000UL |
LOSCFG_BASE_CORE_TSK_MIN_STACK_SIZE | 表示任务最小需要的堆栈大小。 | ALIGN(0x180, 4) |
LOSCFG_BASE_CORE_TIMESLICE_TIMEOUT | 具有相同优先级任务的最长执行时间。 | 2 |
LOSCFG_BASE_IPC_SEM_LIMIT | 最大支持信号量的个数。 | 100 |
LOSCFG_BASE_IPC_MUX_LIMIT | 最大支持互斥量的个数。 | 64 |
LOSCFG_BASE_IPC_QUEUE_LIMIT | 最大支持消息队列量的个数。 | 64 |
LOSCFG_BASE_CORE_SWTMR_LIMIT | 支持的最大软件定时器数量,而不是可用的软件定时器数量。 | 80 |
LOSCFG_BASE_MEM_NODE_SIZE_CHECK | 配置内存节点大小检查。 | NO |
LOSCFG_PLATFORM_EXC | 异常模块配置项。 | YES |
LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT | 是否使用OS默认的中断。 | NO |
3.修改内核中断。 内核提供了两种中断修改方式:
- 使用厂商默认中断。
将“target_config.h”中的宏"LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT"置为NO (0),但需要在xxx.s启动文件中作以下修改:
- PendSV_Handler:厂商sdk自带中断入口函数,需要替换为OpenHarmony的接口HalPendSV;
- SysTick_Handler:厂商sdk自带时钟中断入口函数,需要替换为OpenHarmony的接口OsTickHandler。
- 系统初始化时重定向中断。
将“target_config.h”中的宏"LOSCFG_USE_SYSTEM_DEFINED_INTERRUPT"和"LOSCFG_PLATFORM_HWI"置为YES (1)。
说明:
重定向后的中断向量表g_hwiForm需要根据arch手册要求进行字节对齐,通常0x200字节对齐。
添加内核子系统
添加完内核子系统后,可以编译出带有系统的工程。通过以下步骤添加内核子系统:
- 在“config.json”中添加内核子系统。 路径:“vendor/MyVendorCompany/MyProduct/config.json”
修改如下:
{
"subsystem": "kernel", # 添加内核子系统
"components": [
{
"component": "liteos_m", "features":[""]
}
]
},
2.开启/关闭内核特性。 轻量级系统的内核提供了一些特性,此步骤将指导如何查看、开启/关闭这些特性。
内核特性:liteos_m提供了包括文件系统、backtrace在内的一系列内核特性开关。
路径:“kernel/liteos_m/BUILD.gn”
declare_args() {
enable_ohos_kernel_liteos_m_cppsupport = true # cpp支持
enable_ohos_kernel_liteos_m_cpup = true # CPU占用率支持
enable_ohos_kernel_liteos_m_exchook = true # 异常处理支持
enable_ohos_kernel_liteos_m_kal = true # kal接口支持
enable_ohos_kernel_liteos_m_fs = true # 文件系统支持
enable_ohos_kernel_liteos_m_backtrace = true # backtrace支持
}
group("kernel") {
deps = [
"components/bounds_checking_function:sec",
"kernel:kernel",
"utils:utils",
]
if (enable_ohos_kernel_liteos_m_cppsupport == true) {
deps += [ "components/cppsupport:cppsupport" ] # 如果内核特性true,则会加入相应的代码进行编译
}
……
if (enable_ohos_kernel_liteos_m_kal == true) {
deps += [ "kal:kal" ]
}
}
特性:可以选择cmsis接口或者posix接口支持。
路径:“kernel/liteos_m/kal/BUILD.gn”
declare_args() {
enable_ohos_kernel_liteos_m_cmsis = true # cmsis支持
enable_ohos_kernel_liteos_m_posix = true # posix支持
}
static_library("kal") {
sources = [ "kal.c" ]
if (enable_ohos_kernel_liteos_m_cmsis == true) {
deps += [ "cmsis/" ] # 如果cmsis enable,加入cmsis目录编译
}
if (enable_ohos_kernel_liteos_m_posix == true) {
deps += [ "posix/" ] # 如果posix enable,加入posix目录编译
}
}
特性:可以选择fatfs支持。
路径:“kernel/liteos_m/components/fs/BUILD.gn”
declare_args() {
enable_ohos_kernel_liteos_m_fatfs = true # fatfs支持
}
group("fs") {
deps = []
if (enable_ohos_kernel_liteos_m_fatfs == true) {
deps += [ "fatfs:fatfs" ]
}
}
说明:
内核特性开关可以在具体产品模组中配置。例如关闭fs和cppsupport特性
“vendor/MyVendorCompany/MyProduct/config.json”
"subsystem": "kernel",
"components": [
{
"component": "liteos_m",
"features":["enable_ohos_kernel_liteos_m_fs = false",
"enable_ohos_kernel_liteos_m_cppsupport = false"]
}
]
}
文章转载自:https://docs.openharmony.cn/pages/v3.2Beta/zh-cn/device-dev/porting/porting-minichip-kernel.md/
写的很详细 好好好!
非常详细,感谢