鸿蒙os编码_鸿蒙OS内核分析解读鸿蒙源码
本⽂对鸿蒙OS内核进⾏了简单的分析,涉及鸿蒙OS内核的架构,鸿蒙OS内核的三⼤核⼼模块(进程管理,虚拟内存,⽂件系统)。
⾸先,作者先阐述⼏个关键的名词。
操作系统(Operating System): 操作系统的功能是负责管理各种硬件设备,同时对底层硬件设备进⾏抽象,为上层软件提供⾼效的系统接⼝。操作系统设计和实现的优劣直接决定了系统栈的各个⽅⾯,⽐如性能,可靠性,甚⾄安全性。操作系统的设计实现是计算机系统研究最古⽼最困难的⽅向之⼀。因为底层设备的复杂性,操作系统实现的代码量巨⼤。从系统架构上可以将操作系统分为三类:宏内核(Monolithic Kernel)操作系统,微内核(Microkernel)操作系统,外内核(Exokernel)操作系统。
内核(kernel): ⼏乎所有的处理器⼚商都将处理器的执⾏状态分为了两个级别:特权级(priviledge)和⾮特权级(non-priviledge)。处理器只有在特权级时才可以执⾏⼀些特权级的指令和访问特殊的寄存器。特权级和⾮特权级的划分是为了防⽌不可信的⽤户和应⽤程序破坏系统的状态和数据。特权级⼜称为ring 0。在特权级执⾏的代码称为内核。所以,内核实际上是⼀段在处理器特权级执⾏的代码。只不过代码量越写越⼤,最后变成了软件。
操作系统与内核的关系。狭义上讲,操作系统指的就是内核。⽐如Linux内核,所有的操作系统代码都在核⼼态执⾏,这样的操作系统称为宏内核操作系统。但是随着操作系统技术的不断发展,操作系统本⾝的架构也在不断的演进。⼀些操作系统为了追求架构设计的简洁和系统的安全性,将部分操作系统模块的代码从内核态剥离出来,放到⽤户态执⾏(⽐如Minix操作系统)。这样内核只包括了少量的核⼼功能模块,在极⼤的程度上简化了内核的设计和实现。⽽剥离到⽤户态的操作系统代码可以以服务进程的⽅式去运⾏,或者以库的形式存在(Library OS),链接到其他的内核上去。
鸿蒙OS内核包括了liteos-a内核和liteos-m内核。liteos-m内核是最早⾯向物联⽹设备开发的,内存要求⼩于128MB。⽽liteos-a针对的是资源较为丰富的嵌⼊式设备,内存可以达到4GB。本⽂分析的是liteos-a内核。
鸿蒙OS内核的架构
鸿蒙OS内核最主要的特性之⼀就是微内核的操作系统内核架构设计。那么如何分析操作系统设计采⽤的内核架构呢?⼀个简单直接的⽅法就是观察操作系统内核接⼝的设计。操作系统内核接⼝⼜称为系统调⽤(System Call)。操作系统内核接⼝的设计体现了操作系统内核本⾝设计的复杂度。⽐如Linux内核作为宏内核的代表,系统调⽤数量在325个。⼏乎全部的操作系统功能实现都在内核中。Windows内核的系统调⽤数量据说有上千个。⽽微内核的代表的操作系统内核Minix,最早其系统调⽤的数量仅
仅为2个。内核对上层软件只提供了消息传递的服务功能。下⾯通过鸿蒙OS内核的系统调⽤实现来简单分析⼀下鸿蒙OS内核的架构。
鸿蒙OS运⾏库采⽤了第三⽅的musl libc库。在musl libc库中,系统调⽤的实现是应⽤程序在寄存器中设置好系统调⽤号和系统调⽤参数后,执⾏svc指令陷⼊到内核,如下⾯代码所⽰:
static inline long __syscall3(long n, long a, long b, long c)
{
register long r7 __ASM____R7__ = n; // 系统调⽤号
register long r0 __asm__("r0") = a; //参数0
register long r1 __asm__("r1") = b; // 参数1
register long r2 __asm__("r2") = c; // 参数2
do { \
__asm__ __volatile__ ( "svc 0" \
: "=r"(r0) : "r"(r7), "0"(r0), "r"(r1), "r"(r2) : "memory"); \
return r0; \
} while (0);
}
liteos-a内核在函数OsArmA32SyscallHandle中处理这个中断。函数OsArmA32SyscallHandle根据系统调⽤号执⾏预先设置好的系统调⽤服务例程。
LITE_OS_SEC_TEXT UINT32 *OsArmA32SyscallHandle(UINT32 *regs)
{
UINT32 ret;
UINT8 nArgs;
UINTPTR handle;
UINT32 cmd = regs[REG_R7];
if (cmd >= SYS_CALL_NUM) {
PRINT_ERR("Syscall ID: error %d \n", cmd);
return regs;
}
if (cmd == __NR_sigreturn) {
OsRestorSignalContext(regs);
return regs;
}
handle = g_syscallHandle[cmd];
nArgs = g_syscallNArgs[cmd / NARG_PER_BYTE]; /* 4bit per nargs */
nArgs = (cmd & 1) ? (nArgs >> NARG_BITS) : (nArgs & NARG_MASK);
if ((handle == 0) || (nArgs > ARG_NUM_7)) {
PRINT_ERR("Unsupport syscall ID: %d nArgs: %d\n", cmd, nArgs);
regs[REG_R0] = -ENOSYS;
return regs;
}
switch (nArgs) {
case ARG_NUM_0:
case ARG_NUM_1:
ret = (*(SyscallFun1)handle)(regs[REG_R0]);
break;
case ARG_NUM_2:
case ARG_NUM_3:
ret = (*(SyscallFun3)handle)(regs[REG_R0], regs[REG_R1], regs[REG_R2]);
break;
case ARG_NUM_4:
case ARG_NUM_5:
ret = (*(SyscallFun5)handle)(regs[REG_R0], regs[REG_R1], regs[REG_R2], regs[REG_R3],
regs[REG_R4]);
break;
default:
ret = (*(SyscallFun7)handle)(regs[REG_R0], regs[REG_R1], regs[REG_R2], regs[REG_R3],
regs[REG_R4], regs[REG_R5], regs[REG_R6]);
}
regs[REG_R0] = ret;
OsSaveSignalContext(regs);
/* Return the last value of curent_regs. This supports context switches on return from the exception.
* That capability is only used with theSYS_context_switch system call.
*/
return regs;
}
liteos-a内核中的全部系统调⽤都定义在⽂件syscall/los_syscall.h中。通过观察这个⽂件可以发现liteos-a类似于Linux内核,定义了⼤量的系统调⽤,并且这些系统调⽤全部都实现在内核态当中。
syscall/los_syscall.h
extern unsigned int SysGetGroupId(void);
extern unsigned int SysGetTid(void);
extern void SysSchedYield(int type);
extern int SysSchedGetScheduler(int id, int flag);
extern int SysSchedSetScheduler(int id, int policy, int prio, int flag);
extern int SysSchedGetParam(int id, int flag);
extern int SysSchedSetParam(int id, unsigned int prio, int flag);
extern int SysSetProcessPriority(int which, int who, unsigned int prio);
extern int SysGetProcessPriority(int which, int who);
extern int SysSchedGetPriorityMin(int policy);
....
相⽐于传统的微内核,liteos-a内核稍显复杂。微内核最主要的代表Minix操作系统,其系统接⼝设计简
洁到只有两个系统调⽤:发送消息send和接收消息receive。任何的系统调⽤请求都⽤消息封装好,然后在⽤户态的服务进程之间互相传递。内核只提供了三个基本的功能:时钟中断,进程调度和消息传递。
笔者统计了⼀下鸿蒙OS内核的代码量,如下表所⽰:
liteos-a内核
NuttX虚拟⽂件系统
lwIP⽹络协议栈
69265
16056
89485
其中liteos-a内核将近7万⾏,NuttX虚拟⽂件系统1.6万⾏左右,lwIP⽹络协议栈近9万⾏。这⼗⼏万⾏的代码包含了操作系统最核⼼的⼏个功能模块(进程管理,虚拟内存,⽂件系统,⽹络传输),这些功能
模块全部运⾏在内核态。⽬前liteos-a内核的实现在宏内核和微内核之间更偏向于宏内核。或许后期鸿蒙OS还会对其内核架构有进⼀步的调整。
鸿蒙OS内核还有另外⼀个重要特点:安全性。鸿蒙OS内核的安全性可以通过其内核架构来保证。微内核架构因为其较⼩的内核设计实现,相⽐于宏内核庞⼤的功能实现,其⼤⼤减少了攻击⾯的⼤⼩。另外,微内核的架构也可以⽅便后期系统整体的形式化验证。鸿蒙OS内可能会借助于形式化技术来保证其内核设计实现的正确性。⽬前被验证系统的代码量与形式化技术验证软件系统需要的代码量⽐例⼤概在1:20左右。即⼀⾏c语⾔代码需要⼆⼗⾏形式化验证代码去验证。微内核简单的内核设计和极⼩的内核代码量⽆疑会⼤⼤减轻后期操作系统形式化验证的代码量。⽬前鸿蒙OS内核在开发时代码注释写的⾮常规范。如下图所⽰,猜测也是为了后期系统形式化验证时接⼝规约的⽅便。注释⽐代码长,囧。
/**
* @ingroup los_sys
* @brief Obtain the number of cycles in one second.
*
* @par Description:
* This API is used to obtain the number of cycles in one second.
* @attention
*
*
None
*
*
* @param None
*
* @retval UINT32 Number of cycles obtained in one second.
* @par Dependency:
*
los_sys.h: the header file that contains the API declaration.
* @see None
*/
extern UINT32 LOS_CyclePerTickGet(VOID);
总结⼀下鸿蒙OS内核架构的设计:
优点: 微内核的设计简化了操作系统内核设计实现的复杂度,提⾼了系统的安全性和可靠性,减轻了后期形式化验证的⼯作量,:)。
缺点: ⽬前liteos-a内核的设计实现更偏向于宏内核⽽不是微内核,囧z。
鸿蒙OS内核的进程管理
liteos-a内核同时⽀持了进程和线程的实现。进程描述符为LosProcessCB,线程描述符为LosTaskCB。
进程描述符LosProcessCB包含了进程的所有信息:进程号,进程调度状态,进程信号状态,虚拟内存信息,⽂件系统状态,以及进程的权能信息。所有的进程描述符LosProcessCB的指针保存在⼀个全局的数组g_processCBArray中。通过processID进⾏索引,可以获得对应的LosProcessCB结构。系统中的所有进程通过childrenList,exitChildList,siblingList组织成⼀个树状的结构。capability字段是进程的权能信息,⽤来实现主体对客体资源的访问控制。
typedef struct ProcessCB {
CHAR processName[OS_PCB_NAME_LEN]; /**< Process name */
UINT32 processID; /**< process ID = leader thread ID */
UINT16 processStatus; /**< [15:4] process Status; [3:0] The number of threads currently
running in the process */
UINT16 priority; /**< process priority */
UINT16 policy; /**< process policy */
UINT16 timeSlice; /**< Remaining time slice */
UINT16 consoleID; /**< The console id of task belongs */
UINT16 processMode; /**< Kernel Mode:0; User Mode:1; */
UINT32 parentProcessID; /**< Parent process ID */
UINT32 exitCode; /**< process exit status */
LOS_DL_LIST pendList; /**< Block list to which the process belongs */
LOS_DL_LIST childrenList; /**< my children process list */
LOS_DL_LIST exitChildList; /**< my exit children process list */
LOS_DL_LIST siblingList; /**< linkage in my parent's children list */
ProcessGroup *group; /**< Process group to which a process belongs */
LOS_DL_LIST subordinateGroupList; /**< linkage in my group list */
UINT32 threadGroupID; /**< Which thread group , is the main thread ID of the process */
UINT32 threadScheduleMap; /**< The scheduling bitmap table for the thread group of the
linux内核设计与实现 pdfprocess */
LOS_DL_LIST threadSiblingList; /**< List of threads under this process */
LOS_DL_LIST threadPriQueueList[OS_PRIORITY_QUEUE_NUM]; /**< The process's thread group schedules the
priority hash table */
volatile UINT32 threadNumber; /**< Number of threads alive under this process */
UINT32 threadCount; /**< Total number of threads created under this process */
LOS_DL_LIST waitList; /**< The process holds the waitLits to support wait/waitpid */
#if (LOSCFG_KERNEL_SMP == YES)
UINT32 timerCpu; /**< CPU core number of this task is delayed or pended */
#endif
UINTPTR sigHandler; /**< signal handler */
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论