OpenHarmony设备开发 小型系统内核(LiteOS-A)
版本:V3.2Beta
内核概述
简介
OpenHarmony 轻量级内核是基于IoT领域轻量级物联网操作系统Huawei LiteOS内核演进发展的新一代内核,包含LiteOS-M和LiteOS-A两类内核。LiteOS-M内核主要应用于轻量系统,面向的MCU(Microprocessor Unit)一般是百K级内存,可支持MPU(Memory Protection Unit)隔离,业界类似的内核有FreeRTOS或ThreadX等;LiteOS-A内核主要应用于小型系统,面向设备一般是M级内存,可支持MMU(Memory Management Unit)隔离,业界类似的内核有Zircon或Darwin等。
说明:
OpenHarmony针对不同量级的系统,分别使用了不同形态的内核,小型系统支持LiteOS和Linux,本开发指南适用于LiteOS-A内核,linux内核的相关操作请参考
Linux内核概述。
为适应IoT产业的高速发展,OpenHarmony 轻量级内核不断优化和扩展,能够带给应用开发者友好的开发体验和统一开放的生态系统能力。轻量级内核LiteOS-A重要的新特性如下:
- 新增了丰富的内核机制 新增虚拟内存、系统调用、多核、轻量级IPC(Inter-Process Communication,进程间通信)、DAC(Discretionary Access Control,自主访问控制)等机制,丰富了内核能力;为了更好的兼容软件和开发者体验,新增支持多进程,使得应用之间内存隔离、相互不影响,提升系统的健壮性。
- 引入统一驱动框架HDF(Hardware Driver Foundation) 引入统一驱动框架HDF,统一驱动标准,为设备厂商提供了更统一的接入方式,使驱动更加容易移植,力求做到一次开发,多系统部署。
- 支持1200+标准POSIX接口 更加全面的支持POSIX标准接口,使得应用软件易于开发和移植,给应用开发者提供了更友好的开发体验。
- 内核和硬件高解耦 轻量级内核与硬件高度解耦,新增单板,内核代码不用修改。
内核架构
轻量级内核主要由基础内核、扩展组件、HDF框架、POSIX接口组成。轻量级内核的文件系统、网络协议等扩展功能(没有像微内核那样运行在用户态)运行在内核地址空间,主要考虑组件之间直接函数调用比进程间通信或远程过程调用要快得多。
图1 OpenHarmony LiteOS-A内核架构图
- 基础内核主要包括内核的基础机制,如调度、内存管理、中断异常等
- 扩展组件主要包括文件系统、网络协议和安全等扩展功能
- HDF框架是外设驱动统一标准框架
- POSIX接口是为兼容POSIX标准的应用方便移植到OpenHarmony
基础内核
基础内核组件实现精简,主要包括内核的基础机制,如调度、内存管理、中断异常、内核通信等;
- 进程管理:支持进程和线程,基于Task实现进程,进程独立4GiB地址空间
- 多核调度:支持任务和中断亲核性设置,支持绑核运行
- 实时调度:支持高优先级抢占,同优先级时间片轮转
- 虚拟内存:内核空间静态映射到0-1GiB地址,用户空间映射到1-4GiB地址
- 内核通信:事件、信号量、互斥锁、队列
- 时间管理:软件定时器、系统时钟
文件系统
轻量级内核支持FAT,JFFS2,NFS,ramfs,procfs等众多文件系统,并对外提供完整的POSIX标准的操作接口;内部使用VFS层作为统一的适配层框架,方便移植新的文件系统,各个文件系统也能自动利用VFS层提供的丰富的功能。
主要特性有:
- 完整的POSIX接口支持
- 文件级缓存(pagecache)
- 磁盘级缓存(bcache)
- 目录缓存(pathcache)
- DAC能力
- 支持嵌套挂载及文件系统堆叠等
- 支持特性的裁剪和资源占用的灵活配置。
网络协议
轻量级内核网络协议基于开源lwIP(lightweight IP)构建,对lwIP的RAM占用进行优化,同时提高lwIP的传输性能。
- 协议: IP、IPv6、 ICMP、 ND、MLD、 UDP、 TCP、IGMP、ARP、PPPoS、PPPoE
- API:socket API
- 扩展特性:多网络接口IP转发、TCP拥塞控制、RTT估计和快速恢复/快速重传
- 应用程序:HTTP(S)服务、SNTP客户端、SMTP(S)客户端、ping工具、NetBIOS名称服务、mDNS响应程序、MQTT客户端、TFTP服务、DHCP客户端、DNS客户端、AutoIP/APIPA(零配置)、SNMP代理
HDF框架
轻量级内核集成HDF框架,HDF框架旨在为开发者提供更精准、更高效的开发环境,力求做到一次开发,多系统部署。
- 支持多内核平台
- 支持用户态驱动
- 可配置组件化驱动模型
- 基于消息的驱动接口模型
- 基于对象的驱动、设备管理
- HDI(Hardware Device Interface)统一硬件接口
- 支持电源管理、PnP
扩展组件
对内核功能进行扩展,可选但很重要的机制。
- 动态链接:支持标准ELF链接执行、加载地址随机化
- 进程通信:支持轻量级LiteIPC,同时也支持标准的Mqueue、Pipe、Fifo、Signal等机制
- 系统调用:支持170+系统调用,同时有支持VDSO机制
- 权限管理:支持进程粒度的特权划分和管控,UGO三种权限配置
目录
/kernel/liteos_a
├── apps # 用户态的init和shell应用程序
├── arch # 体系架构的目录,如arm等
│ └── arm # arm架构代码
├── bsd # freebsd相关的驱动和适配层模块代码引入,例如USB等
├── compat # 内核接口兼容性目录
│ └── posix # posix相关接口
├── drivers # 内核驱动
│ └── char # 字符设备
│ ├── mem # 访问物理IO设备驱动
│ ├── quickstart # 系统快速启动接口目录
│ ├── random # 随机数设备驱动
│ └── video # framebuffer驱动框架
├── figures # 内核架构图
├── fs # 文件系统模块,主要来源于NuttX开源项目
│ ├── fat # fat文件系统
│ ├── jffs2 # jffs2文件系统
│ ├── include # 对外暴露头文件存放目录
│ ├── nfs # nfs文件系统
│ ├── proc # proc文件系统
│ ├── ramfs # ramfs文件系统
│ └── vfs # vfs层
├── kernel # 进程、内存、IPC等模块
│ ├── base # 基础内核,包括调度、内存等模块
│ ├── common # 内核通用组件
│ ├── extended # 扩展内核,包括动态加载、vdso、liteipc等模块
│ ├── include # 对外暴露头文件存放目录
│ └── user # 加载init进程
├── lib # 内核的lib库
├── net # 网络模块,主要来源于lwip开源项目
├── platform # 支持不同的芯片平台代码,如Hi3516DV300等
│ ├── hw # 时钟与中断相关逻辑代码
│ ├── include # 对外暴露头文件存放目录
│ └── uart # 串口相关逻辑代码
├── security # 安全特性相关的代码,包括进程权限管理和虚拟id映射管理
├── shell # 接收用户输入的命令,内核去执行
├── syscall # 系统调用
├── testsuilts # 测试套件
└── tools # 构建工具及相关配置和代码
text
约束
- 开发语言:C/C++;
- 适用于Hi3516DV300单板;
- Hi3516DV300默认使用FAT文件系统。
使用说明
OpenHarmony LiteOS-A内核支持Hi3516DV300单板。开发者可基于此单板开发运行自己的应用程序。
准备
开发者需要在Linux上搭建编译环境。
获取源码
在Linux服务器上下载并解压一套源代码,源码获取方式参考源码获取。
编译构建
如果这是您的首次应用程序开发,可参考:
相关仓
内核子系统
内核态启动
内核启动流程
内核启动流程包含汇编启动阶段和C语言启动阶段2部分,如图1所示。汇编启动阶段完成CPU初始设置,关闭dcache/icache,使能FPU及neon,设置MMU建立虚实地址映射,设置系统栈,清理bss段,调用C语言main函数等。C语言启动阶段包含OsMain函数及开始调度等,其中如图1所示,OsMain函数用于内核基础初始化和架构、板级初始化等,其整体由内核启动框架主导初始化流程,图中右边区域为启动框架中可接受外部模块注册启动的阶段,各个阶段的说明如下表1所示。
图1 内核启动流程图
表1 启动框架层级
层级 | 说明 |
LOS_INIT_LEVEL_EARLIEST | 最早期初始化 说明:不依赖架构,单板以及后续模块会对其有依赖的纯软件模块初始化 例如:Trace模块 |
LOS_INIT_LEVEL_ARCH_EARLY | 架构早期初始化 说明:架构相关,后续模块会对其有依赖的模块初始化,如启动过程中非必需的功能,建议放到LOS_INIT_LEVEL_ARCH层 |
LOS_INIT_LEVEL_PLATFORM_EARLY | 平台早期初始化 说明:单板平台、驱动相关,后续模块会对其有依赖的模块初始化,如启动过程中必需的功能,建议放到LOS_INIT_LEVEL_PLATFORM层 例如:uart模块 |
LOS_INIT_LEVEL_KMOD_PREVM | 内存初始化前的内核模块初始化 说明:在内存初始化之前需要使能的模块初始化 |
LOS_INIT_LEVEL_VM_COMPLETE | 基础内存就绪后的初始化 说明:此时内存初始化完毕,需要进行使能且不依赖进程间通讯机制与系统进程的模块初始化 例如:共享内存功能 |
LOS_INIT_LEVEL_ARCH | 架构后期初始化 说明:架构拓展功能相关,后续模块会对其有依赖的模块初始化 |
LOS_INIT_LEVEL_PLATFORM | 平台后期初始化 说明:单板平台、驱动相关,后续模块会对其有依赖的模块初始化 例如:驱动内核抽象层初始化(mmc、mtd) |
LOS_INIT_LEVEL_KMOD_BASIC | 内核基础模块初始化 说明:内核可拆卸的基础模块初始化 例如:VFS初始化 |
LOS_INIT_LEVEL_KMOD_EXTENDED | 内核扩展模块初始化 说明:内核可拆卸的扩展模块初始化 例如:系统调用初始化、ProcFS初始化、Futex初始化、HiLog初始化、HiEvent初始化、LiteIPC初始化 |
LOS_INIT_LEVEL_KMOD_TASK | 内核任务创建 说明:进行内核任务的创建(内核任务,软件定时器任务) 例如:资源回收系统常驻任务的创建、SystemInit任务创建、CPU占用率统计任务创建 |
LOS_INIT_LEVEL_FINISH | 内核初始化完成 |
编程样例
实例描述
新增一个内核模块,需要在内核初始化时进行该模块的初始化,则通过内核启动框架将该模块的初始化函数注册进内核启动流程中。
为方便学习,本演示代码直接在 . kernel /liteos_a/testsuites /kernel /src /osTest.c中编译验证即可。
示例代码
/* 内核启动框架头文件 */
#include "los_init.h"
/* 新增模块的初始化函数 */
unsigned int OsSampleModInit(void)
{
PRINTK("OsSampleModInit SUCCESS!\n");
}
/* 在启动框架的目标层级中注册新增模块 */
LOS_MODULE_INIT(OsSampleModInit, LOS_INIT_LEVEL_KMOD_EXTENDED);
c
结果验证
main core booting up...
/* 根据实际运行环境,过程打印会有差异 */
......
/* 打印测试代码新增模块初始化函数 */
OsSampleModInit SUCCESS!
根据上述系统启动阶段的打印可知,内核在启动时进行了该注册模块的初始化函数调用,完成该模块的初始化操作。
说明:
启动框架中同一层级内的注册模块不能有依赖关系,建议新增模块按照上述启动阶段进行模块初始化的拆分,按需注册启动。
可通过查看系统编译生成文件OHOS_Image.map中.rodata.init.kernel.*段内的符号表来了解当前已注册进内核启动框架中的各个模块初始化入口,以及检查新注册的模块初始化入口是否生效。
用户态启动
用户态根进程启动
根进程是系统第一个用户态进程,进程ID为1,它是所有用户态进程的祖先。
图1 进程树示意图
根进程的启动过程
使用链接脚本将如下init启动代码放置到系统镜像指定位置。
#define LITE_USER_SEC_ENTRY __attribute__((section(".user.entry")))
LITE_USER_SEC_ENTRY VOID OsUserInit(VOID *args)
{
#ifdef LOSCFG_KERNEL_DYNLOAD
sys_call3(__NR_execve, (UINTPTR)g_initPath, 0, 0);
#endif
while (true) {
}
}
c
上述启动代码已在 kernel/liteos_a/kernel/user/src/los_user_init.c 中,g_initPath 根据启动设置的不同,其值为 /dev/shm/init 或 /bin/init。
系统启动阶段,OsUserInitProcess启动init进程。具体过程如下:
- 由内核OsLoadUserInit加载上述代码。
- 创建新的进程空间,启动/bin/init进程。
根进程的职责
- 启动关键系统程序或服务,如交互进程shell。
说明:
在OpenHarmony 中
init
进程通过读取/etc/init.cfg,根据配置执行指定命令,或启动指定进程(详见:
)。
- 监控回收孤儿进程,清理子进程中的僵尸进程。
用户态程序运行
用户态程序启动有如下常见方式:
- shell命令启动进程。
OHOS $ exec helloworld
OHOS $ ./helloworld
OHOS $ /bin/helloworld
- 通过POSIX接口启动新进程。 Fork方法创建一个新的进程,exec类接口执行一个全新的进程。
文章转载自:https://docs.openharmony.cn/pages/v3.2Beta/zh-cn/device-dev/kernel/kernel-small-overview.md/