本篇关键词:、、、

下载 >> 离线文档.鸿蒙内核源码分析(百篇博客分析.挖透鸿蒙内核).pdf

基础知识相关篇为:

几个概念

您肯定听过 APIPosixC语言库函数,系统调用这些概念,但之间有什么区别和联系,估计一些人没弄明白,本篇重点把它们整明白了。

  • API : 搞应用开发的同学不会陌生,应用编程接口的缩写 ,它是对函数的定义,规定了这个函数的功能。任何公司,个人都可以定义自有特色的API。可以称之为 私有标准 。打个比方就相当于是地方方言,十里不同音,只有这个地方的人能搞懂,对外会带来极高的沟通成本。
  • PosixUnix开源后很多公司都推出了不同的版本的Unix系统。他们的API各不相同。这给软件的移植带来了很大的困难。于是IEEE制定了基于Unix的可移植操作系统接口,目的是为了统一这些 私有标准 , 可以称之为 公共的类Unix接口标准,所以posix标准也是一种APIIEEE这个协会很牛,制定过很多标准,涵盖太空、计算机、电信、生物医学、电力及消费性电子产品等领域,可以说是科技界标准话事人。对应地方方言,它就相当于是普通话,其实呢它也是一种方言。
  • C语言库函数: 是基于Posix标准的具体实现, 相当于中国人说的普通话
  • 系统调用: 是内核对外提供的服务总称, 它一般被C语言库函数所调用, 相当于政府对老百姓的办事窗口, 想访问内部资源就需要填表格, 走流程。

POSIX简介

当前的POSIX主要分为四个部分:

  • XBD(Base Definitions):包含一些通用的术语、概念、接口以及工具函数(cd,mkdir, cp,mv等)和头文件定义(stdio.h, stdlib.h,pthread.h等)。

  • XSH(System Interfaces):包含系统服务函数的定义,例如线程、套接字、标准IO、信号处理、错误处理等。

  • XCU(Shell and Utilities):包含shell脚本书写的语法、关键字以及工具函数(break,cd,cp,continue,pwd,return)的定义。

  • XRAT(Rationale):包含与本标准有关的历史信息以及采用或舍弃某功能的扩展基本原理。 具体查看 >> 官方网站 | opengroup 目前单一UNIX规范第4版中定义了 1447 个接口。

    XBD XSH XCU 全部的
    82 1191 174 1447

鸿蒙支持部分标准POSIX接口 ,并不是很多 >> 可查看源码 compat/posix

compat/posix/src
├── map_error.c //错误码映射 例如: ENOERR EINTR  ESRCH
├── malloc.c //内存分配 例如: malloc zalloc r
├── misc.c //系统信息
├── mqueue.c //消息队列
├── posix_memalign.c //内存对齐分配
├── pprivate.h //描述 _pthread_data 结构体
├── pthread.c //线程 
├── pthread_attr.c //线程属性
├── pthread_cond.c //线程条件
├── pthread_mutex.c //线程互斥
├── sched.c //任务调度
├── semaphore.c //信号量
├── socket.c //网络
└── time.c //时间
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

系统调用

>> 可查看源码 syscall

syscall/
├── Makefile
├── fs_syscall.c    //文件模块
├── ipc_syscall.c   //进程通讯模块
├── los_syscall.c   //系统调用主功能函数
├── los_syscall.h
├── misc_syscall.c  //信息配置
├── net_syscall.c   //网络模块
├── process_syscall.c   //进程模块
├── syscall_lookup.h
├── syscall_pub.c   //公有模块
├── syscall_pub.h
├── time_syscall.c  //时间模块
└── vm_syscall.c    //内存模块
1
2
3
4
5
6
7
8
9
10
11
12
13
14

系统调用的实现函数 OsArmA32SyscallHandle,实现过程在 v95.xx 鸿蒙内核源码分析(系统调用篇) 中详细说明

进程控制类系统调用,主要有:

  • 创建和终止进程的系统调用。
  • 获得和设置进程属性的系统调用。
  • 等待某事件出现的系统调用。
  • SysForkSysWaitSysSetProcessGroupIDSysGetUserIDSysSchedYieldSysThreadJoinSysIoctl

文件操纵类系统调用,主要有:

  • 创建和删除文件。
  • 打开和关闭文件的系统调用。
  • 读和写文件的系统调用。
  • SysPipeSysOpenSysStatSysReadSysWriteSysCreatSysIoctl

进程通讯类系统调用,主要有:

  • SysMqOpenSysSigActionSysKillSysMqNotifySysMqTimedSend

网络类系统调用,主要有:

  • SysSocketSysBindSysConnectSysListenSysAcceptSysRecv

信息配置类系统调用,主要有:

  • SysRebootSysInfoSysGetrusageSysSysconf

时间类系统调用,主要有:

  • SysTimerCreateSysTimerDeleteSysClockGettimeSysSetiTimer

内存类系统调用,主要有:

  • SysMmapSysMunmapSysBrkSysMremapSysShmGetSysShmAtSysShmCtlSysShmDt

musl | C标准库函数

musl,一种C标准库,官方网站 ,主要使用于以Linux内核为主的操作系统上,鸿蒙内核也使用了它,目标为嵌入式系统与移动设备,采用MIT许可证发布。作者为瑞奇·费尔克(Rich Felker)。开发此库的目的是写一份干净、高效、符合标准的C标准库。Musl声称与POSIX 2008标准和C11标准兼容。musl是一个非常庞大提供给应用程序使用的工具库,例如: 学习C语言的第一段代码

#include <stdio.h>
int main() {
   printf("Hello, World!");
   return 0;
}
1
2
3
4
5

中的printf就是由stdio.h提供,由标准库实现的。这是个可变参数实现函数。

int printf(const char *restrict fmt, ...)
{
	int ret;
	va_list ap;
	va_start(ap, fmt);
	ret = vfprintf(stdout, fmt, ap);
	va_end(ap);
	return ret;
}
1
2
3
4
5
6
7
8
9

如果你一直往下追,你会追到系统调用 write

ssize_t write(int fd, const void *buf, size_t count)
{
	return syscall_cp(SYS_write, fd, buf, count);
}

1
2
3
4
5
void SyscallHandleInit(void)
{
#define SYSCALL_HAND_DEF(id, fun, rType, nArg)                                             \
    if ((id) < SYS_CALL_NUM) {                                                             \
        g_syscallHandle[(id)] = (UINTPTR)(fun);                                            \
        g_syscallNArgs[(id) / NARG_PER_BYTE] |= ((id) & 1) ? (nArg) << NARG_BITS : (nArg); \
    }                                                                                      \

    #include "syscall_lookup.h"
#undef SYSCALL_HAND_DEF
}
1
2
3
4
5
6
7
8
9
10
11

\code-v1.1.1-LTS\prebuilts\lite\sysroot\usr\include\arm-liteos\bits\syscall.h

#define __NR_restart_syscall	0
#define __NR_exit	1
#define __NR_fork	2
#define __NR_read	3
#define __NR_write	4
#define __NR_open	5
#define __NR_close	6
#define __NR_creat	8
#define __NR_link	9
1
2
3
4
5
6
7
8
9
#define SYS_restart_syscall	0
#define SYS_exit	1
#define SYS_fork	2
#define SYS_read	3
#define SYS_write	4
#define SYS_open	5
#define SYS_close	6
#define SYS_creat	8
#define SYS_link	9

ssize_t read(int fd, void *buf, size_t count)
{
	return syscall_cp(SYS_read, fd, buf, count);
}
#define __syscall_cp(...) __SYSCALL_DISP(__syscall_cp,__VA_ARGS__)
#define syscall_cp(...) __syscall_ret(__syscall_cp(__VA_ARGS__))
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

\code-v1.1.1-LTS\third_party\musl\src\thread\arm\syscall_cp.s

__syscall_cp_asm:
	mov ip,sp
	stmfd sp!,{r4,r5,r6,r7}
__cp_begin:
	ldr r0,[r0]
	cmp r0,#0
	bne __cp_cancel
	mov r7,r1 //R7寄存器保存软中断号
	mov r0,r2
	mov r1,r3
	ldmfd ip,{r2,r3,r4,r5,r6}
	svc 0 //原 SWI 指令, 软中断指令
__cp_end:
	ldmfd sp!,{r4,r5,r6,r7}
	bx lr
__cp_cancel:
	ldmfd sp!,{r4,r5,r6,r7}
	b __cancel
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
  • 其中最重要的命令就是 svc 0,通过这条指令切换到 svc 模式(svc 替代了以前的 swi 指令,是 arm 提供的系统调用指令),进入到软件中断处理函数( SWI handler )。

问题

那可能有人会问了,操作系统有抽象层,那硬件有没有抽象层,规定处理器内核与外设的接口,统一了内核访问外设寄存器的方法,从而简化了软件的开发,提高重用度,降低软硬件接口开发成本。有的,就是CMSIS( Cortex Microcontroller Software Interface Standard)缩写,中文为Cortex系列微控制器软件接口标准。此标准是ARM公司,芯片供应商以及软件供应商共同制定的,包含以下组件:

  • CMSIS-CORE:提供与 Cortex-M0、Cortex-M3、Cortex-M4、SC000 和 SC300 处理器与外围寄存器之间的接口
  • CMSIS-DSP:包含以定点(分数 q7、q15、q31)和单精度浮点(32 位)实现的 60 多种函数的 DSP 库
  • CMSIS-RTOS API:用于线程控制、资源和时间管理的实时操作系统的标准化编程接口
  • CMSIS-SVD:包含完整微控制器系统(包括外设)的程序员视图的系统视图描述 XML 文件 此标准可进行全面扩展,以确保适用于所有 Cortex-M 处理器系列微控制器。其中包括所有设备:从最小的 8 KB 设备,直至带有精密通信外设(例如以太网或 USB)的设备。(内核外设功能的内存要求小于 1 KB 代码,低于 10 字节 RAM)。

百文说内核 | 抓住主脉络

  • 百文相当于摸出内核的肌肉和器官系统,让人开始丰满有立体感,因是直接从注释源码起步,在加注释过程中,每每有心得处就整理,慢慢形成了以下文章。内容立足源码,常以生活场景打比方尽可能多的将内核知识点置入某种场景,具有画面感,容易理解记忆。说别人能听得懂的话很重要! 百篇博客绝不是百度教条式的在说一堆诘屈聱牙的概念,那没什么意思。更希望让内核变得栩栩如生,倍感亲切。
  • 与代码需不断debug一样,文章内容会存在不少错漏之处,请多包涵,但会反复修正,持续更新,v**.xx 代表文章序号和修改的次数,精雕细琢,言简意赅,力求打造精品内容。
  • 百文在 < 鸿蒙研究站 | 开源中国 | 博客园 | 51cto | csdn | 知乎 | 掘金 > 站点发布,百篇博客系列目录如下。

按功能模块:

基础知识 进程管理 任务管理 内存管理
双向链表
内核概念
源码结构
地址空间
计时单位
优雅的宏
钩子框架
位图管理
POSIX
main函数
调度故事
进程控制块
进程空间
线性区
红黑树
进程管理
Fork进程
进程回收
Shell编辑
Shell解析
任务控制块
并发并行
就绪队列
调度机制
任务管理
用栈方式
软件定时器
控制台
远程登录
协议栈
内存规则
物理内存
内存概念
虚实映射
页表管理
静态分配
TLFS算法
内存池管理
原子操作
圆整对齐
通讯机制 文件系统 硬件架构 内核汇编
通讯总览
自旋锁
互斥锁
快锁使用
快锁实现
读写锁
信号量
事件机制
信号生产
信号消费
消息队列
消息封装
消息映射
共享内存
文件概念
文件故事
索引节点
VFS
文件句柄
根文件系统
挂载机制
管道文件
文件映射
写时拷贝
芯片模式
ARM架构
指令集
协处理器
工作模式
寄存器
多核管理
中断概念
中断管理
编码方式
汇编基础
汇编传参
链接脚本
内核启动
进程切换
任务切换
中断切换
异常接管
缺页中断
编译运行 调测工具
编译过程
编译构建
GN语法
忍者无敌
ELF格式
ELF解析
静态链接
重定位
动态链接
进程映像
应用启动
系统调用
VDSO
模块监控
日志跟踪
系统安全
测试用例

百万注源码 | 处处扣细节

  • 百万汉字注解内核目的是要看清楚其毛细血管,细胞结构,等于在拿放大镜看内核。内核并不神秘,带着问题去源码中找答案是很容易上瘾的,你会发现很多文章对一些问题的解读是错误的,或者说不深刻难以自圆其说,你会慢慢形成自己新的解读,而新的解读又会碰到新的问题,如此层层递进,滚滚向前,拿着放大镜根本不愿意放手。

  • < gitee | github | coding | gitcode > 四大码仓推送 | 同步官方源码。

关注不迷路 | 代码即人生

期间不断得到小伙伴的支持,有学生,有职场新人,也有老江湖,在此一并感谢,大家的支持是前进的动力。尤其每次收到学生的赞助很感慨,后生可敬。 >> 查看捐助名单

据说喜欢 点赞 + 分享 的,后来都成了大神。😃