1. OpenHarmony 内核概述:LiteOS-A 与 LiteOS-M
各位同学,咱们今天正式开讲 OpenHarmony 内核。说实话,我第一次接触这个内核时,也被它「一核两体」的架构搞晕过。后来在移植一款传感器驱动时,才真正体会到这种设计的精妙之处。
OpenHarmony 内核不是「一个内核打天下」,而是针对不同硬件能力,提供了两套内核:LiteOS-A 和 LiteOS-M。你想想看,一个跑在智能手表上的内核,和一个跑在温湿度传感器上的内核,需求能一样吗?
1.1 LiteOS-A 与 LiteOS-M 架构对比
先看一张对比表,把两者的核心差异说清楚。
| 对比维度 | LiteOS-A | LiteOS-M |
|---|---|---|
| 目标硬件 | ARM Cortex-A 系列(如 Cortex-A7/A53) | ARM Cortex-M 系列(如 Cortex-M3/M4/M7) |
| MMU | 支持,提供进程隔离 | 不支持,无 MMU |
| 进程/线程 | 多进程 + 多线程 | 单进程多线程 |
| 内存管理 | 虚拟内存,支持动态映射 | 静态内存池,固定分配 |
| 系统调用 | 完整 syscall 机制 | 无 syscall,函数直接调用 |
| 典型场景 | 智能手表、带屏设备 | 传感器、MCU 控制类设备 |
这张表怎么看?我个人的理解是:LiteOS-A 是「大内核」,有 MMU、有进程隔离,适合跑复杂应用;LiteOS-M 是「小内核」,轻量、实时、无 MMU,适合资源受限的 MCU 场景。
核心要点:LiteOS-A 和 LiteOS-M 共享同一套内核抽象层(KAL),上层 API 基本一致。这意味着你写一个线程创建函数,在 A 核和 M 核上调用方式几乎一样——底层实现不同,但接口统一。这是 OpenHarmony 内核设计的高明之处。
1.2 内核启动流程分析
启动流程,说白了就是「从复位到 main 函数」这段路怎么走。我当年调试一块开发板时,发现系统死活跑不起来,最后定位到是启动文件里中断向量表地址配错了——嗯,这种坑踩过一次就忘不了。
咱们以 LiteOS-A 为例,看启动流程的关键步骤:
- 复位向量:CPU 上电后,从复位向量地址取第一条指令,跳转到启动代码入口。
- 初始化硬件:关闭中断、设置栈指针、初始化异常向量表。
- 初始化 BSS 段:将未初始化的全局变量清零。
- 跳转到 C 语言入口:调用
main()或osMain()。 - 内核初始化:初始化调度器、内存管理、中断子系统。
- 创建第一个任务:启动 Idle 任务和 Init 任务。
- 启动调度器:开始多任务调度。
下面这张 SVG 流程图,把启动过程画得更直观。
调试小技巧:如果你在移植过程中遇到系统启动后卡死,建议在启动代码的每个关键步骤加 GPIO 翻转或串口打印。我曾经用这种方法,在 10 分钟内定位到是 MMU 页表配置错误——比瞎猜快多了。
1.3 内核源码目录结构解析
源码目录结构,是每个内核开发者的「地图」。我刚接触 OpenHarmony 内核时,面对几十个文件夹也是一脸懵。后来我养成了一个习惯:先看顶层目录,再逐层深入。
下面这张表,把核心目录的作用说清楚。
| 目录路径 | 作用说明 |
|---|---|
kernel/liteos_a/ |
LiteOS-A 内核主目录,包含进程、内存、文件系统等模块 |
kernel/liteos_m/ |
LiteOS-M 内核主目录,轻量级实现 |
kernel/liteos_a/arch/ |
架构相关代码,如 ARM、RISC-V 的启动和中断处理 |
kernel/liteos_a/kernel/ |
核心调度、任务管理、IPC 等 |
kernel/liteos_a/mm/ |
内存管理,包括虚拟内存、页表、内存池 |
kernel/liteos_a/fs/ |
虚拟文件系统(VFS)层 |
kernel/liteos_a/net/ |
网络协议栈(LwIP 集成) |
kernel/liteos_a/drivers/ |
内核态驱动框架 |
kernel/liteos_a/include/ |
对外暴露的 API 头文件 |
我个人建议,初学者先从 kernel/liteos_a/kernel/ 和 kernel/liteos_a/include/ 入手。为什么?因为这两个目录包含了最核心的调度和 API 定义,你看懂了它们,就抓住了内核的「骨架」。
避坑指南:千万不要一上来就扎进 arch/ 目录。那里是汇编代码和底层硬件相关的实现,可读性较差。我见过不少新手,花了两周时间研究启动汇编,结果连任务怎么创建都没搞明白——方向错了,努力白费。
1.4 内核抽象层(KAL)的作用
前面提到,LiteOS-A 和 LiteOS-M 共享一套 KAL。这个层到底做了什么?说白了,就是「接口统一,实现分离」。
举个例子,你在应用层调用 LOS_TaskCreate(),KAL 会根据当前内核类型,自动路由到对应的实现:
- 在 LiteOS-A 上,走的是带 MMU 的多进程调度路径。
- 在 LiteOS-M 上,走的是单进程多线程的轻量路径。
这种设计的好处很明显:应用代码可以跨平台复用。你写一个传感器驱动,在 A 核上调试通过后,稍微改改配置就能跑在 M 核上。
我的经验:在移植驱动时,尽量使用 KAL 提供的 API,而不是直接调用内核内部函数。这样你的驱动代码就具备了「双核兼容」的能力。我在一个项目中,就是靠这个原则,把一套 BLE 驱动无缝移植到了两款不同芯片上。
1.5 本章小结
这一章,咱们把 OpenHarmony 内核的「骨架」搭起来了:
- LiteOS-A vs LiteOS-M:一个是大而全,一个是小而精。
- 启动流程:从复位到调度器启动,每一步都有章可循。
- 源码目录:知道去哪里找什么代码,比背代码更重要。
- KAL 抽象层:接口统一,双核兼容。