提交 7e7f09da 编写于 作者: 鸿蒙内核源码分析's avatar 鸿蒙内核源码分析

对虚拟内存/物理内存模块更详细的注解

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    鸿蒙研究站 | http://weharmonyos.com (国内)
              | https://weharmony.github.io (国外)
    oschina | https://my.oschina.net/weharmony
    博客园 | https://www.cnblogs.com/weharmony/
    知乎 | https://www.zhihu.com/people/weharmonyos
    csdn | https://blog.csdn.net/kuangyufei
    51cto | https://harmonyos.51cto.com/column/34
    掘金 | https://juejin.cn/user/756888642000808
    公众号 | 鸿蒙研究站 (weharmonyos)
上级 ca112dfe
...@@ -11,11 +11,10 @@ ...@@ -11,11 +11,10 @@
* 因为内核代码本身并不太多,都是浓缩的精华,精读是让各个知识点高频出现,不孤立成点状记忆,没有足够连接点的知识点是很容易忘的,点点成线,线面成体,连接越多,记得越牢,如此短时间内容易结成一张高浓度,高密度的系统化知识网,训练大脑肌肉记忆,驻入大脑直觉区,想抹都抹不掉,终生携带,随时调取。跟骑单车一样,一旦学会,即便多年不骑,照样跨上就走,游刃有余。 * 因为内核代码本身并不太多,都是浓缩的精华,精读是让各个知识点高频出现,不孤立成点状记忆,没有足够连接点的知识点是很容易忘的,点点成线,线面成体,连接越多,记得越牢,如此短时间内容易结成一张高浓度,高密度的系统化知识网,训练大脑肌肉记忆,驻入大脑直觉区,想抹都抹不掉,终生携带,随时调取。跟骑单车一样,一旦学会,即便多年不骑,照样跨上就走,游刃有余。
### 热爱是所有的理由和答案 ### 热爱是所有的理由和答案
* 因大学时阅读 `linux 2.6` 内核痛并快乐的经历,一直有个心愿,如何让更多对内核感兴趣的朋友减少阅读时间,加速对计算机系统级的理解,而不至于过早的放弃。但因过程种种,多年一直没有行动,基本要放弃这件事了。恰逢 `2020/9/10` 鸿蒙正式开源,重新激活了多年的心愿,就有那么点如黄河之水一发不可收拾了。 * 因大学时阅读 `linux 2.6` 内核痛并快乐的经历,一直有个心愿,如何让更多对内核感兴趣的朋友减少阅读时间,加速对计算机系统级的理解,而不至于过早的放弃。但因过程种种,多年一直没有行动,基本要放弃这件事了。恰逢 `2020/9/10` 鸿蒙正式开源,重新激活了多年的心愿,就有那么点如黄河之水一发不可收拾了。
* 目前对内核源码的注解已完成了 `70%` ,对内核源码的博客分析已完成了`70+篇`每天都很充实,很兴奋,连做梦内核代码都在鱼贯而入。如此疯狂地做一件事还是当年谈恋爱的时候, 只因热爱, 热爱是所有的理由和答案。 :P * 目前对内核源码的注解已完成了 `80%` ,对内核源码的博客分析已完成了`70+篇`, 已持续一年有余, 占用了所有的空闲时间, 但每天都很充实,很兴奋,连做梦内核代码都在鱼贯而入。如此疯狂地做一件事还是当年谈恋爱的时候, 只因热爱, 热爱是所有的理由和答案。 :P
### (〃・ิ‿・ิ)ゞ鸿蒙内核开发者 ### (〃・ิ‿・ิ)ゞ鸿蒙内核开发者
* 感谢开放原子开源基金会,致敬鸿蒙内核开发者提供了如此优秀的源码,一了多年的夙愿,津津乐道于此。精读内核源码加注并整理成档是件很有挑战的事,时间上要以月甚至年为单位,但正因为很难才值得去做! 干困难事,方有所得;专注聚焦,必有所获。 * 感谢开放原子开源基金会,致敬鸿蒙内核开发者提供了如此优秀的源码,一了多年的夙愿,津津乐道于此。精读内核源码加注并整理成档是件很有挑战的事,时间上是以年为单位,但正因为很难才值得去做! 干困难事,方有所得;专注聚焦,必有所获。
* 从内核一行行的代码中能深深感受到开发者各中艰辛与坚持,及鸿蒙生态对未来的价值,这些是张嘴就来的网络喷子们永远不能体会到的。可以毫不夸张的说鸿蒙内核源码可作为大学: C语言,数据结构,操作系统,汇编语言,计算机系统结构,计算机组成原理 六门课程的教学项目。如此宝库,不深入研究实在是暴殄天物,于心不忍,注者坚信鸿蒙大势所趋,未来可期,其必定成功,也必然成功,誓做其坚定的追随者和传播者。 * 从内核一行行的代码中能深深感受到开发者各中艰辛与坚持,及鸿蒙生态对未来的价值,这些是张嘴就来的网络喷子们永远不能体会到的。可以毫不夸张的说鸿蒙内核源码可作为大学: C语言,数据结构,操作系统,汇编语言,计算机系统结构,计算机组成原理 六门课程的教学项目。如此宝库,不深入研究实在是暴殄天物,于心不忍,注者坚信鸿蒙大势所趋,未来可期,其必定成功,也必然成功,誓做其坚定的追随者和传播者。
### 同步历史 ### 同步历史
注解鸿蒙内核仓库与官方源码按月保持同步. 注解鸿蒙内核仓库与官方源码按月保持同步.
* `2021/11/12` -- 加入epoll支持,对shell模块有较大调整,微调process,task,更正单词拼写错误 * `2021/11/12` -- 加入epoll支持,对shell模块有较大调整,微调process,task,更正单词拼写错误
...@@ -111,7 +110,7 @@ ...@@ -111,7 +110,7 @@
# zzz 的想法源于微信中名称为AAA的那帮朋友,你的微信里应该也有他们熟悉的身影吧 :|P # zzz 的想法源于微信中名称为AAA的那帮朋友,你的微信里应该也有他们熟悉的身影吧 :|P
``` ```
### 鸿蒙研究站 | [weharmonyos.com](http://weharmonyos.com) ### 鸿蒙研究站 | [weharmonyos.com](http://weharmonyos.com) | 每天死磕一点点
聚焦于做一个专注而靠谱的技术站, 分成四部分内容 聚焦于做一个专注而靠谱的技术站, 分成四部分内容
......
...@@ -50,7 +50,7 @@ ...@@ -50,7 +50,7 @@
./trace dump 0 ./trace dump 0
@endverbatim @endverbatim
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-22 * @date 2021-11-22
*/ */
/* /*
......
...@@ -26,7 +26,7 @@ ...@@ -26,7 +26,7 @@
* *
* \n * \n
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-16 * @date 2021-11-16
* *
* @history * @history
......
...@@ -32,7 +32,7 @@ ...@@ -32,7 +32,7 @@
* @endverbatim * @endverbatim
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-17 * @date 2021-11-17
* *
* @history * @history
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
这是每分每秒都在发生的事情。 这是每分每秒都在发生的事情。
* @endverbatim * @endverbatim
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-16 * @date 2021-11-16
* *
* @history * @history
......
...@@ -45,7 +45,7 @@ ...@@ -45,7 +45,7 @@
@endverbatim @endverbatim
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-20 * @date 2021-11-20
*/ */
/* /*
......
...@@ -98,7 +98,7 @@ ...@@ -98,7 +98,7 @@
* @endverbatim * @endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/44/vector.png * @image html https://gitee.com/weharmonyos/resources/raw/master/44/vector.png
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-16 * @date 2021-11-16
* *
* @history * @history
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* @verbatim * @verbatim
* @endverbatim * @endverbatim
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-18 * @date 2021-11-18
* *
* @history * @history
......
/*!
* @file time.c
* @brief
* @link
@verbatim
@endverbatim
* @version
* @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-25
*/
/* /*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
...@@ -132,9 +142,9 @@ STATIC INT32 g_adjDirection; /* 1, speed up; 0, slow down; | 调整方向(加 ...@@ -132,9 +142,9 @@ STATIC INT32 g_adjDirection; /* 1, speed up; 0, slow down; | 调整方向(加
STATIC const long long g_adjPacement = (((LOSCFG_BASE_CORE_ADJ_PER_SECOND * SCHED_CLOCK_INTETRVAL_TICKS) / STATIC const long long g_adjPacement = (((LOSCFG_BASE_CORE_ADJ_PER_SECOND * SCHED_CLOCK_INTETRVAL_TICKS) /
LOSCFG_BASE_CORE_TICK_PER_SECOND) * OS_SYS_NS_PER_US); LOSCFG_BASE_CORE_TICK_PER_SECOND) * OS_SYS_NS_PER_US);
/* accumulative time delta from continuous modify, such as adjtime | 连续修改的累积时间增量,例如 adjtime */ /* accumulative time delta from continuous modify, such as adjtime | 运行时间,来自连续修改的累积时间增量,例如 adjtime */
STATIC struct timespec64 g_accDeltaFromAdj; STATIC struct timespec64 g_accDeltaFromAdj;
/* accumulative time delta from discontinuous modify, such as settimeofday | 来自不连续修改的累积时间增量,例如 settimeofday*/ /* accumulative time delta from discontinuous modify, such as settimeofday | 实时时间,来自不连续修改的累积时间增量,例如 日历时间 settimeofday*/
STATIC struct timespec64 g_accDeltaFromSet; STATIC struct timespec64 g_accDeltaFromSet;
VOID OsAdjTime(VOID) VOID OsAdjTime(VOID)
...@@ -241,24 +251,25 @@ int adjtime(const struct timeval *delta, struct timeval *oldDelta) ...@@ -241,24 +251,25 @@ int adjtime(const struct timeval *delta, struct timeval *oldDelta)
LOS_SpinUnlockRestore(&g_timeSpin, intSave); LOS_SpinUnlockRestore(&g_timeSpin, intSave);
return 0; return 0;
} }
/// 增加指定时间
STATIC INLINE struct timespec64 OsTimeSpecAdd(const struct timespec64 t1, const struct timespec64 t2) STATIC INLINE struct timespec64 OsTimeSpecAdd(const struct timespec64 t1, const struct timespec64 t2)
{ {
struct timespec64 ret = {0}; struct timespec64 ret = {0};
ret.tv_sec = t1.tv_sec + t2.tv_sec; ret.tv_sec = t1.tv_sec + t2.tv_sec;
ret.tv_nsec = t1.tv_nsec + t2.tv_nsec; ret.tv_nsec = t1.tv_nsec + t2.tv_nsec;
if (ret.tv_nsec >= OS_SYS_NS_PER_SECOND) { //用于校正精度
ret.tv_sec += 1; if (ret.tv_nsec >= OS_SYS_NS_PER_SECOND) {//超过1秒时的计算
ret.tv_nsec -= OS_SYS_NS_PER_SECOND; ret.tv_sec += 1; //秒数加一
} else if (ret.tv_nsec < 0L) { ret.tv_nsec -= OS_SYS_NS_PER_SECOND;//剩余纳秒数
ret.tv_sec -= 1; } else if (ret.tv_nsec < 0L) {//介于 0 - 1秒之间的纳秒数
ret.tv_nsec += OS_SYS_NS_PER_SECOND; ret.tv_sec -= 1; //秒数减一
ret.tv_nsec += OS_SYS_NS_PER_SECOND;//纳秒数增加
} }
return ret; return ret;
} }
/// 减少指定时间
STATIC INLINE struct timespec64 OsTimeSpecSub(const struct timespec64 t1, const struct timespec64 t2) STATIC INLINE struct timespec64 OsTimeSpecSub(const struct timespec64 t1, const struct timespec64 t2)
{ {
struct timespec64 ret = {0}; struct timespec64 ret = {0};
...@@ -281,7 +292,7 @@ STATIC VOID OsGetHwTime(struct timespec64 *hwTime) ...@@ -281,7 +292,7 @@ STATIC VOID OsGetHwTime(struct timespec64 *hwTime)
hwTime->tv_sec = nowNsec / OS_SYS_NS_PER_SECOND;//当前秒数 hwTime->tv_sec = nowNsec / OS_SYS_NS_PER_SECOND;//当前秒数
hwTime->tv_nsec = nowNsec - hwTime->tv_sec * OS_SYS_NS_PER_SECOND;// @note_thinking 为啥要这样做? 不应该是直接 nowNsec ? hwTime->tv_nsec = nowNsec - hwTime->tv_sec * OS_SYS_NS_PER_SECOND;// @note_thinking 为啥要这样做? 不应该是直接 nowNsec ?
} }
/// 设置日历
STATIC INT32 OsSetTimeOfDay(const struct timeval64 *tv, const struct timezone *tz) STATIC INT32 OsSetTimeOfDay(const struct timeval64 *tv, const struct timezone *tz)
{ {
UINT32 intSave; UINT32 intSave;
...@@ -341,7 +352,7 @@ int settimeofday64(const struct timeval64 *tv, const struct timezone *tz) ...@@ -341,7 +352,7 @@ int settimeofday64(const struct timeval64 *tv, const struct timezone *tz)
return OsSetTimeOfDay(tv, tz); return OsSetTimeOfDay(tv, tz);
} }
#endif #endif
/// 设置本地秒数
int setlocalseconds(int seconds) int setlocalseconds(int seconds)
{ {
struct timeval tv = {0}; struct timeval tv = {0};
...@@ -351,7 +362,7 @@ int setlocalseconds(int seconds) ...@@ -351,7 +362,7 @@ int setlocalseconds(int seconds)
return settimeofday(&tv, NULL); return settimeofday(&tv, NULL);
} }
/// 获取日历时间
STATIC INT32 OsGetTimeOfDay(struct timeval64 *tv, struct timezone *tz) STATIC INT32 OsGetTimeOfDay(struct timeval64 *tv, struct timezone *tz)
{ {
UINT32 intSave; UINT32 intSave;
...@@ -387,6 +398,24 @@ int gettimeofday64(struct timeval64 *tv, struct timezone *tz) ...@@ -387,6 +398,24 @@ int gettimeofday64(struct timeval64 *tv, struct timezone *tz)
} }
#endif #endif
/*!
* @brief gettimeofday
@verbatim
gettimeofday 函数是一个符合 POSIX 标准的函数,它可以检索当前时间,精度达到纳秒级
struct timeval{
long int tv_sec; // 秒数
long int tv_usec; // 微秒数
}
其中time_t和suseconds_t都是long int类型。在32位下为4个字节,能够表示的最大正整数是2147483647,
而这个表示的时间最大能到2038-01-19 03:14:07,超过了之后就变为-2147483648,这就是linux2038年的问题。
而64位系统下的time_t类型即long类型长度为8个字节,可以用到几千亿年,这么长的时间完全不用担心溢出的问题。
@endverbatim
* @param tv
* @param tz
* @return
*
* @see
*/
int gettimeofday(struct timeval *tv, struct timezone *tz) int gettimeofday(struct timeval *tv, struct timezone *tz)
{ {
struct timeval64 stTimeVal64 = {0}; struct timeval64 stTimeVal64 = {0};
...@@ -1115,7 +1144,7 @@ int getitimer(int which, struct itimerval *value) ...@@ -1115,7 +1144,7 @@ int getitimer(int which, struct itimerval *value)
} }
#ifdef LOSCFG_KERNEL_VDSO #ifdef LOSCFG_KERNEL_VDSO
// /// 将最新的时间刷进数据页
VOID OsVdsoTimeGet(VdsoDataPage *vdsoDataPage) VOID OsVdsoTimeGet(VdsoDataPage *vdsoDataPage)
{ {
UINT32 intSave; UINT32 intSave;
......
...@@ -120,7 +120,7 @@ struct VmMapRegion { ...@@ -120,7 +120,7 @@ struct VmMapRegion {
struct Vnode *vnode; struct Vnode *vnode;
const LosVmFileOps *vmFOps;///< 文件处理各操作接口 const LosVmFileOps *vmFOps;///< 文件处理各操作接口
} rf; } rf;
struct VmRegionAnon {//匿名映射可理解为就是物理内存 struct VmRegionAnon {//匿名映射可理解为与物理内存的映射
LOS_DL_LIST node; /**< region LosVmPage list | 线性区虚拟页链表*/ LOS_DL_LIST node; /**< region LosVmPage list | 线性区虚拟页链表*/
} ra; } ra;
struct VmRegionDev {//设备映射 struct VmRegionDev {//设备映射
...@@ -160,7 +160,7 @@ typedef struct VmSpace { ...@@ -160,7 +160,7 @@ typedef struct VmSpace {
#define VM_MAP_REGION_FLAG_UNCACHED_DEVICE (2<<0) /* only exists on some arches, otherwise UNCACHED */ #define VM_MAP_REGION_FLAG_UNCACHED_DEVICE (2<<0) /* only exists on some arches, otherwise UNCACHED */
#define VM_MAP_REGION_FLAG_STRONGLY_ORDERED (3<<0) /* only exists on some arches, otherwise UNCACHED */ #define VM_MAP_REGION_FLAG_STRONGLY_ORDERED (3<<0) /* only exists on some arches, otherwise UNCACHED */
#define VM_MAP_REGION_FLAG_CACHE_MASK (3<<0) ///< 缓冲区掩码 #define VM_MAP_REGION_FLAG_CACHE_MASK (3<<0) ///< 缓冲区掩码
#define VM_MAP_REGION_FLAG_PERM_USER (1<<2) ///< 用户区 #define VM_MAP_REGION_FLAG_PERM_USER (1<<2) ///< 用户空间
#define VM_MAP_REGION_FLAG_PERM_READ (1<<3) ///< 可读取区 #define VM_MAP_REGION_FLAG_PERM_READ (1<<3) ///< 可读取区
#define VM_MAP_REGION_FLAG_PERM_WRITE (1<<4) ///< 可写入区 #define VM_MAP_REGION_FLAG_PERM_WRITE (1<<4) ///< 可写入区
#define VM_MAP_REGION_FLAG_PERM_EXECUTE (1<<5) ///< 可被执行区 #define VM_MAP_REGION_FLAG_PERM_EXECUTE (1<<5) ///< 可被执行区
...@@ -196,13 +196,13 @@ STATIC INLINE UINT32 OsCvtProtFlagsToRegionFlags(unsigned long prot, unsigned lo ...@@ -196,13 +196,13 @@ STATIC INLINE UINT32 OsCvtProtFlagsToRegionFlags(unsigned long prot, unsigned lo
return regionFlags; return regionFlags;
} }
///是否为内核空间 /// 是否为内核空间的地址
STATIC INLINE BOOL LOS_IsKernelAddress(VADDR_T vaddr) STATIC INLINE BOOL LOS_IsKernelAddress(VADDR_T vaddr)
{ {
return ((vaddr >= (VADDR_T)KERNEL_ASPACE_BASE) && return ((vaddr >= (VADDR_T)KERNEL_ASPACE_BASE) &&
(vaddr <= ((VADDR_T)KERNEL_ASPACE_BASE + ((VADDR_T)KERNEL_ASPACE_SIZE - 1)))); (vaddr <= ((VADDR_T)KERNEL_ASPACE_BASE + ((VADDR_T)KERNEL_ASPACE_SIZE - 1))));
} }
/// 给定范围是否在内核空间中 /// 给定地址范围是否都在内核空间中
STATIC INLINE BOOL LOS_IsKernelAddressRange(VADDR_T vaddr, size_t len) STATIC INLINE BOOL LOS_IsKernelAddressRange(VADDR_T vaddr, size_t len)
{ {
return (vaddr + len > vaddr) && LOS_IsKernelAddress(vaddr) && (LOS_IsKernelAddress(vaddr + len - 1)); return (vaddr + len > vaddr) && LOS_IsKernelAddress(vaddr) && (LOS_IsKernelAddress(vaddr + len - 1));
...@@ -212,7 +212,7 @@ STATIC INLINE VADDR_T LOS_RegionEndAddr(LosVmMapRegion *region) ...@@ -212,7 +212,7 @@ STATIC INLINE VADDR_T LOS_RegionEndAddr(LosVmMapRegion *region)
{ {
return (region->range.base + region->range.size - 1); return (region->range.base + region->range.size - 1);
} }
/// 线性区大小 /// 获取线性区大小
STATIC INLINE size_t LOS_RegionSize(VADDR_T start, VADDR_T end) STATIC INLINE size_t LOS_RegionSize(VADDR_T start, VADDR_T end)
{ {
return (end - start + 1); return (end - start + 1);
...@@ -270,7 +270,7 @@ STATIC INLINE BOOL LOS_IsUserAddressRange(VADDR_T vaddr, size_t len) ...@@ -270,7 +270,7 @@ STATIC INLINE BOOL LOS_IsUserAddressRange(VADDR_T vaddr, size_t len)
return (vaddr + len > vaddr) && LOS_IsUserAddress(vaddr) && (LOS_IsUserAddress(vaddr + len - 1)); return (vaddr + len > vaddr) && LOS_IsUserAddress(vaddr) && (LOS_IsUserAddress(vaddr + len - 1));
} }
//是否是一个动态分配的地址 //是否是一个动态分配的地址(通过vmalloc申请的)
STATIC INLINE BOOL LOS_IsVmallocAddress(VADDR_T vaddr) STATIC INLINE BOOL LOS_IsVmallocAddress(VADDR_T vaddr)
{ {
return ((vaddr >= VMALLOC_START) && return ((vaddr >= VMALLOC_START) &&
......
...@@ -48,7 +48,7 @@ ...@@ -48,7 +48,7 @@
\n LiteOS-M内核作为实时操作系统需要保证任务调度的实时性,尽量避免任务的长时间阻塞,因此在获得互斥锁之后,应该尽快释放互斥锁。 \n LiteOS-M内核作为实时操作系统需要保证任务调度的实时性,尽量避免任务的长时间阻塞,因此在获得互斥锁之后,应该尽快释放互斥锁。
\n 持有互斥锁的过程中,不得再调用LOS_TaskPriSet等接口更改持有互斥锁任务的优先级。 \n 持有互斥锁的过程中,不得再调用LOS_TaskPriSet等接口更改持有互斥锁任务的优先级。
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-18 * @date 2021-11-18
*/ */
/* /*
......
...@@ -41,7 +41,7 @@ ...@@ -41,7 +41,7 @@
* @image html https://gitee.com/weharmonyos/resources/raw/master/29/sem_run.png * @image html https://gitee.com/weharmonyos/resources/raw/master/29/sem_run.png
* @attention 由于中断不能被阻塞,因此不能在中断中使用阻塞模式申请信号量。 * @attention 由于中断不能被阻塞,因此不能在中断中使用阻塞模式申请信号量。
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-18 * @date 2021-11-18
*/ */
/* /*
......
...@@ -43,7 +43,7 @@ ...@@ -43,7 +43,7 @@
@endverbatim @endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/11/2.png * @image html https://gitee.com/weharmonyos/resources/raw/master/11/2.png
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-19 * @date 2021-11-19
*/ */
/* /*
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
SGI共有16个,硬件中断号分别为ID0~ID15。它通常用于多核间通讯。 SGI共有16个,硬件中断号分别为ID0~ID15。它通常用于多核间通讯。
* @endverbatim * @endverbatim
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-18 * @date 2021-11-18
* *
* @history * @history
......
/*!
* @file los_vm_map.c
* @brief 虚拟内存管理
* @link vm http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-memory-virtual.html @endlink
@verbatim
基本概念
虚拟内存管理是计算机系统管理内存的一种技术。每个进程都有连续的虚拟地址空间,虚拟地址空间的大小由CPU的位数决定,
32位的硬件平台可以提供的最大的寻址空间为0-4GiB。整个4GiB空间分成两部分,LiteOS-A内核占据3GiB的高地址空间,
1GiB的低地址空间留给进程使用。各个进程空间的虚拟地址空间是独立的,代码、数据互不影响。
系统将虚拟内存分割为称为虚拟页的内存块,大小一般为4KiB或64KiB,LiteOS-A内核默认的页的大小是4KiB,
根据需要可以对MMU(Memory Management Units)进行配置。虚拟内存管理操作的最小单位就是一个页,
LiteOS-A内核中一个虚拟地址区间region包含地址连续的多个虚拟页,也可只有一个页。同样,物理内存也会按照页大小进行分割,
分割后的每个内存块称为页帧。虚拟地址空间划分:内核态占高地址3GiB(0x40000000 ~ 0xFFFFFFFF),
用户态占低地址1GiB(0x01000000 ~ 0x3F000000),具体见下表,详细可以查看或配置los_vm_zone.h。
内核态地址规划:
Zone名称 描述 属性
----------------------------------------------------------------------------
DMA zone 供IO设备的DMA使用。 Uncache
Normal zone 加载内核代码段、数据段、堆和栈的地址区间。 Cache
high mem zone可以分配连续的虚拟内存,但其所映射的物理内存不一定连续。Cache
用户态地址规划:
Zone名称 描述 属性
----------------------------------------------------------------------------
代码段 用户态代码段地址区间。 Cache
堆 用户态堆地址区间。 Cache
栈 用户态栈地址区间。 Cache
共享库 用于加载用户态共享库的地址区间,包括mmap所映射的区间。 Cache
运行机制
虚拟内存管理中,虚拟地址空间是连续的,但是其映射的物理内存并不一定是连续的,如下图所示。
可执行程序加载运行,CPU访问虚拟地址空间的代码或数据时存在两种情况:
1. CPU访问的虚拟地址所在的页,如V0,已经与具体的物理页P0做映射,CPU通过找到进程对应的页表条目(详见虚实映射),
根据页表条目中的物理地址信息访问物理内存中的内容并返回。
2. CPU访问的虚拟地址所在的页,如V2,没有与具体的物理页做映射,系统会触发缺页异常,系统申请一个物理页,
并把相应的信息拷贝到物理页中,并且把物理页的起始地址更新到页表条目中。此时CPU重新执行访问虚拟内存的指令
便能够访问到具体的代码或数据。
@endverbatim
* @version
* @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-25
*/
/* /*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
...@@ -51,17 +99,21 @@ ...@@ -51,17 +99,21 @@
#ifdef LOSCFG_KERNEL_VM #ifdef LOSCFG_KERNEL_VM
#define VM_MAP_WASTE_MEM_LEVEL (PAGE_SIZE >> 2) // 浪费内存等级(1K) #define VM_MAP_WASTE_MEM_LEVEL (PAGE_SIZE >> 2) ///< 浪费内存大小(1K)
LosMux g_vmSpaceListMux; //用于锁g_vmSpaceList的互斥量 LosMux g_vmSpaceListMux; ///< 用于锁g_vmSpaceList的互斥量
LOS_DL_LIST_HEAD(g_vmSpaceList); //初始化全局虚拟空间节点,所有虚拟空间都挂到此节点上. LOS_DL_LIST_HEAD(g_vmSpaceList); ///< 初始化全局虚拟空间节点,所有虚拟空间都挂到此节点上.
LosVmSpace g_kVmSpace; //内核空间地址 LosVmSpace g_kVmSpace; ///< 内核空间地址
LosVmSpace g_vMallocSpace; //内核堆空间地址 LosVmSpace g_vMallocSpace; ///< 内核堆空间地址
//通过虚拟地址获取所属空间地址
/************************************************************
* 获取进程空间系列接口
************************************************************/
/// 获取当前进程空间结构体指针
LosVmSpace *LOS_CurrSpaceGet(VOID) LosVmSpace *LOS_CurrSpaceGet(VOID)
{ {
return OsCurrProcessGet()->vmSpace; return OsCurrProcessGet()->vmSpace;
} }
/// 获取虚拟地址对应的进程空间结构体指针
LosVmSpace *LOS_SpaceGet(VADDR_T vaddr) LosVmSpace *LOS_SpaceGet(VADDR_T vaddr)
{ {
if (LOS_IsKernelAddress(vaddr)) { //是否为内核空间 if (LOS_IsKernelAddress(vaddr)) { //是否为内核空间
...@@ -79,7 +131,7 @@ LosVmSpace *LOS_GetKVmSpace(VOID) ...@@ -79,7 +131,7 @@ LosVmSpace *LOS_GetKVmSpace(VOID)
{ {
return &g_kVmSpace; return &g_kVmSpace;
} }
///获取虚拟空间双循环链表 g_vmSpaceList中存放的是 g_kVmSpace, g_vMallocSpace,所有用户进程空间(每个用户进程独有一个) ///获取进程空间链表指针 g_vmSpaceList中挂的是进程空间 g_kVmSpace, g_vMallocSpace,所有用户进程的空间(独有一个进程空间)
LOS_DL_LIST *LOS_GetVmSpaceList(VOID) LOS_DL_LIST *LOS_GetVmSpaceList(VOID)
{ {
return &g_vmSpaceList; return &g_vmSpaceList;
...@@ -89,6 +141,10 @@ LosVmSpace *LOS_GetVmallocSpace(VOID) ...@@ -89,6 +141,10 @@ LosVmSpace *LOS_GetVmallocSpace(VOID)
{ {
return &g_vMallocSpace; return &g_vMallocSpace;
} }
/************************************************************
* 虚拟地址区间region相关的操作
************************************************************/
///释放挂在红黑树上节点,等于释放了线性区 ///释放挂在红黑树上节点,等于释放了线性区
ULONG_T OsRegionRbFreeFn(LosRbNode *pstNode) ULONG_T OsRegionRbFreeFn(LosRbNode *pstNode)
{ {
...@@ -354,7 +410,7 @@ LosVmMapRegion *OsFindRegion(LosRbTree *regionRbTree, VADDR_T vaddr, size_t len) ...@@ -354,7 +410,7 @@ LosVmMapRegion *OsFindRegion(LosRbTree *regionRbTree, VADDR_T vaddr, size_t len)
} }
return regionRst; return regionRst;
} }
/// 查找线性区 /// 查找线性区 根据起始地址在进程空间内查找是否存在
LosVmMapRegion *LOS_RegionFind(LosVmSpace *vmSpace, VADDR_T addr) LosVmMapRegion *LOS_RegionFind(LosVmSpace *vmSpace, VADDR_T addr)
{ {
LosVmMapRegion *region = NULL; LosVmMapRegion *region = NULL;
...@@ -365,7 +421,7 @@ LosVmMapRegion *LOS_RegionFind(LosVmSpace *vmSpace, VADDR_T addr) ...@@ -365,7 +421,7 @@ LosVmMapRegion *LOS_RegionFind(LosVmSpace *vmSpace, VADDR_T addr)
return region; return region;
} }
/// 查找线性区范围 /// 查找线性区 根据地址区间在进程空间内查找是否存在
LosVmMapRegion *LOS_RegionRangeFind(LosVmSpace *vmSpace, VADDR_T addr, size_t len) LosVmMapRegion *LOS_RegionRangeFind(LosVmSpace *vmSpace, VADDR_T addr, size_t len)
{ {
LosVmMapRegion *region = NULL; LosVmMapRegion *region = NULL;
...@@ -490,7 +546,7 @@ LosVmMapRegion *OsCreateRegion(VADDR_T vaddr, size_t len, UINT32 regionFlags, un ...@@ -490,7 +546,7 @@ LosVmMapRegion *OsCreateRegion(VADDR_T vaddr, size_t len, UINT32 regionFlags, un
region->shmid = -1; //默认线性区为不共享,无共享资源ID region->shmid = -1; //默认线性区为不共享,无共享资源ID
return region; return region;
} }
///通过虚拟地址查询物理地址 ///通过虚拟地址查询映射的物理地址
PADDR_T LOS_PaddrQuery(VOID *vaddr) PADDR_T LOS_PaddrQuery(VOID *vaddr)
{ {
PADDR_T paddr = 0; PADDR_T paddr = 0;
...@@ -498,7 +554,7 @@ PADDR_T LOS_PaddrQuery(VOID *vaddr) ...@@ -498,7 +554,7 @@ PADDR_T LOS_PaddrQuery(VOID *vaddr)
LosVmSpace *space = NULL; LosVmSpace *space = NULL;
LosArchMmu *archMmu = NULL; LosArchMmu *archMmu = NULL;
//先取出对应空间的mmu //先取出对应空间的mmu
if (LOS_IsKernelAddress((VADDR_T)(UINTPTR)vaddr)) {//是否内核空间地址 if (LOS_IsKernelAddress((VADDR_T)(UINTPTR)vaddr)) {//是否内核空间地址
archMmu = &g_kVmSpace.archMmu; archMmu = &g_kVmSpace.archMmu;
} else if (LOS_IsUserAddress((VADDR_T)(UINTPTR)vaddr)) {//是否为用户空间地址 } else if (LOS_IsUserAddress((VADDR_T)(UINTPTR)vaddr)) {//是否为用户空间地址
space = OsCurrProcessGet()->vmSpace; space = OsCurrProcessGet()->vmSpace;
...@@ -963,7 +1019,7 @@ BOOL LOS_IsRangeInSpace(const LosVmSpace *space, VADDR_T vaddr, size_t size) ...@@ -963,7 +1019,7 @@ BOOL LOS_IsRangeInSpace(const LosVmSpace *space, VADDR_T vaddr, size_t size)
} }
return TRUE; return TRUE;
} }
/// 在进程空间中预留一块内存空间
STATUS_T LOS_VmSpaceReserve(LosVmSpace *space, size_t size, VADDR_T vaddr) STATUS_T LOS_VmSpaceReserve(LosVmSpace *space, size_t size, VADDR_T vaddr)
{ {
UINT32 regionFlags = 0; UINT32 regionFlags = 0;
...@@ -984,7 +1040,7 @@ STATUS_T LOS_VmSpaceReserve(LosVmSpace *space, size_t size, VADDR_T vaddr) ...@@ -984,7 +1040,7 @@ STATUS_T LOS_VmSpaceReserve(LosVmSpace *space, size_t size, VADDR_T vaddr)
return region ? LOS_OK : LOS_ERRNO_VM_NO_MEMORY; return region ? LOS_OK : LOS_ERRNO_VM_NO_MEMORY;
} }
///实现从虚拟地址到物理地址的映射 ///实现从虚拟地址到物理地址的映射,将指定长度的物理地址区间与虚拟地址区间做映射,需提前申请物理地址区间
STATUS_T LOS_VaddrToPaddrMmap(LosVmSpace *space, VADDR_T vaddr, PADDR_T paddr, size_t len, UINT32 flags) STATUS_T LOS_VaddrToPaddrMmap(LosVmSpace *space, VADDR_T vaddr, PADDR_T paddr, size_t len, UINT32 flags)
{ {
STATUS_T ret; STATUS_T ret;
...@@ -1145,7 +1201,7 @@ PADDR_T LOS_PaddrQuery(VOID *vaddr) ...@@ -1145,7 +1201,7 @@ PADDR_T LOS_PaddrQuery(VOID *vaddr)
return (PADDR_T)VMM_TO_DMA_ADDR((VADDR_T)vaddr); return (PADDR_T)VMM_TO_DMA_ADDR((VADDR_T)vaddr);
} }
#endif #endif
///内核空间内存分配 ///内核空间内存分配,申请小于16KiB的内存则通过堆内存池获取,否则申请多个连续物理页
VOID *LOS_KernelMalloc(UINT32 size) VOID *LOS_KernelMalloc(UINT32 size)
{ {
VOID *ptr = NULL; VOID *ptr = NULL;
...@@ -1161,7 +1217,7 @@ VOID *LOS_KernelMalloc(UINT32 size) ...@@ -1161,7 +1217,7 @@ VOID *LOS_KernelMalloc(UINT32 size)
return ptr; return ptr;
} }
/// 申请具有对齐属性的内存,申请规则:申请小于16KiB的内存则通过堆内存池获取,否则申请多个连续物理页
VOID *LOS_KernelMallocAlign(UINT32 size, UINT32 boundary) VOID *LOS_KernelMallocAlign(UINT32 size, UINT32 boundary)
{ {
VOID *ptr = NULL; VOID *ptr = NULL;
...@@ -1177,7 +1233,7 @@ VOID *LOS_KernelMallocAlign(UINT32 size, UINT32 boundary) ...@@ -1177,7 +1233,7 @@ VOID *LOS_KernelMallocAlign(UINT32 size, UINT32 boundary)
return ptr; return ptr;
} }
/// 重新分配内核内存空间
VOID *LOS_KernelRealloc(VOID *ptr, UINT32 size) VOID *LOS_KernelRealloc(VOID *ptr, UINT32 size)
{ {
VOID *tmpPtr = NULL; VOID *tmpPtr = NULL;
......
/*!
* @file los_vm_phys.c
* @brief 物理内存管理 - 段页式管理
* @link physical http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-basic-memory-physical.html @endlink
@verbatim
基本概念
物理内存是计算机上最重要的资源之一,指的是实际的内存设备提供的、可以通过CPU总线直接进行寻址的内存空间,
其主要作用是为操作系统及程序提供临时存储空间。LiteOS-A内核管理物理内存是通过分页实现的,除了内核堆占用的一部分内存外,
其余可用内存均以4KiB为单位划分成页帧,内存分配和内存回收便是以页帧为单位进行操作。内核采用伙伴算法管理空闲页面,
可以降低一定的内存碎片率,提高内存分配和释放的效率,但是一个很小的块往往也会阻塞一个大块的合并,导致不能分配较大的内存块。
运行机制
LiteOS-A内核的物理内存使用分布视图,主要由内核镜像、内核堆及物理页组成。内核堆部分见堆内存管理一节。
-----------------------------------------------------
kernel.bin | heap | page frames
(内核镜像) | (内核堆) | (物理页框)
-----------------------------------------------------
伙伴算法把所有空闲页帧分成9个内存块组,每组中内存块包含2的幂次方个页帧,例如:第0组的内存块包含2的0次方个页帧,
即1个页帧;第8组的内存块包含2的8次方个页帧,即256个页帧。相同大小的内存块挂在同一个链表上进行管理。
申请内存
系统申请12KiB内存,即3个页帧时,9个内存块组中索引为3的链表挂着一块大小为8个页帧的内存块满足要求,分配出12KiB内存后还剩余20KiB内存,
即5个页帧,将5个页帧分成2的幂次方之和,即4跟1,尝试查找伙伴进行合并。4个页帧的内存块没有伙伴则直接插到索引为2的链表上,
继续查找1个页帧的内存块是否有伙伴,索引为0的链表上此时有1个,如果两个内存块地址连续则进行合并,并将内存块挂到索引为1的链表上,否则不做处理。
释放内存
系统释放12KiB内存,即3个页帧,将3个页帧分成2的幂次方之和,即2跟1,尝试查找伙伴进行合并,索引为1的链表上有1个内存块,
若地址连续则合并,并将合并后的内存块挂到索引为2的链表上,索引为0的链表上此时也有1个,如果地址连续则进行合并,
并将合并后的内存块挂到索引为1的链表上,此时继续判断是否有伙伴,重复上述操作。
@endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/17/malloc_phy.png
* @image html https://gitee.com/weharmonyos/resources/raw/master/17/free_phy.png
* @version
* @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-25
*/
/* /*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved. * Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved. * Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
...@@ -38,9 +73,7 @@ ...@@ -38,9 +73,7 @@
#ifdef LOSCFG_KERNEL_VM #ifdef LOSCFG_KERNEL_VM
/**
* @brief 鸿蒙物理内存采用段页式管理
*/
#define ONE_PAGE 1 #define ONE_PAGE 1
/* Physical memory area array */ /* Physical memory area array */
...@@ -58,7 +91,7 @@ LosVmPhysSeg *OsGVmPhysSegGet() ...@@ -58,7 +91,7 @@ LosVmPhysSeg *OsGVmPhysSegGet()
{ {
return g_vmPhysSeg; return g_vmPhysSeg;
} }
///初始化Lru置换链表 /// 初始化Lru置换链表
STATIC VOID OsVmPhysLruInit(struct VmPhysSeg *seg) STATIC VOID OsVmPhysLruInit(struct VmPhysSeg *seg)
{ {
INT32 i; INT32 i;
...@@ -72,7 +105,7 @@ STATIC VOID OsVmPhysLruInit(struct VmPhysSeg *seg) ...@@ -72,7 +105,7 @@ STATIC VOID OsVmPhysLruInit(struct VmPhysSeg *seg)
} }
LOS_SpinUnlockRestore(&seg->lruLock, intSave); LOS_SpinUnlockRestore(&seg->lruLock, intSave);
} }
///创建物理段,由区划分转成段管理 /// 创建物理段,由区划分转成段管理
STATIC INT32 OsVmPhysSegCreate(paddr_t start, size_t size) STATIC INT32 OsVmPhysSegCreate(paddr_t start, size_t size)
{ {
struct VmPhysSeg *seg = NULL; struct VmPhysSeg *seg = NULL;
...@@ -90,7 +123,7 @@ STATIC INT32 OsVmPhysSegCreate(paddr_t start, size_t size) ...@@ -90,7 +123,7 @@ STATIC INT32 OsVmPhysSegCreate(paddr_t start, size_t size)
return 0; return 0;
} }
///添加物理段 /// 添加物理段
VOID OsVmPhysSegAdd(VOID) VOID OsVmPhysSegAdd(VOID)
{ {
INT32 i, ret; INT32 i, ret;
...@@ -197,11 +230,9 @@ STATIC VOID OsVmPhysFreeListDelUnsafe(LosVmPage *page) ...@@ -197,11 +230,9 @@ STATIC VOID OsVmPhysFreeListDelUnsafe(LosVmPage *page)
/** /**
* @brief 本函数很像卖猪肉的,拿一大块肉剁,先把多余的放回到小块肉堆里去. * @brief 本函数很像卖猪肉的,拿一大块肉剁,先把多余的放回到小块肉堆里去.
oldOrder:原本要买 2^2肉
newOrder:却找到个 2^8肉块
* @param page * @param page
* @param oldOrder * @param oldOrder 原本要买 2^2肉
* @param newOrder * @param newOrder 却找到个 2^8肉块
* @return STATIC * @return STATIC
*/ */
STATIC VOID OsVmPhysPagesSpiltUnsafe(LosVmPage *page, UINT8 oldOrder, UINT8 newOrder) STATIC VOID OsVmPhysPagesSpiltUnsafe(LosVmPage *page, UINT8 oldOrder, UINT8 newOrder)
...@@ -311,7 +342,7 @@ STATIC LosVmPage *OsVmPhysLargeAlloc(struct VmPhysSeg *seg, size_t nPages) ...@@ -311,7 +342,7 @@ STATIC LosVmPage *OsVmPhysLargeAlloc(struct VmPhysSeg *seg, size_t nPages)
return NULL; return NULL;
} }
/// 申请物理页并挂在对应的链表上
STATIC LosVmPage *OsVmPhysPagesAlloc(struct VmPhysSeg *seg, size_t nPages) STATIC LosVmPage *OsVmPhysPagesAlloc(struct VmPhysSeg *seg, size_t nPages)
{ {
struct VmFreeList *list = NULL; struct VmFreeList *list = NULL;
...@@ -348,7 +379,7 @@ DONE: ...@@ -348,7 +379,7 @@ DONE:
return page; return page;
} }
///释放物理页框,所谓释放物理页就是把页挂到空闲链表中 /// 释放物理页框,所谓释放物理页就是把页挂到空闲链表中
VOID OsVmPhysPagesFree(LosVmPage *page, UINT8 order) VOID OsVmPhysPagesFree(LosVmPage *page, UINT8 order)
{ {
paddr_t pa; paddr_t pa;
...@@ -403,11 +434,13 @@ VOID OsVmPhysPagesFreeContiguous(LosVmPage *page, size_t nPages) ...@@ -403,11 +434,13 @@ VOID OsVmPhysPagesFreeContiguous(LosVmPage *page, size_t nPages)
} }
} }
/** /*!
* @brief 获取一定数量的页框 LosVmPage实体是放在全局大数组中的, * @brief OsVmPhysPagesGet 获取一定数量的页框 LosVmPage实体是放在全局大数组中的,
LosVmPage->nPages 标记了分配页数 * LosVmPage->nPages 标记了分配页数
* @param nPages * @param nPages
* @return STATIC* * @return
*
* @see
*/ */
STATIC LosVmPage *OsVmPhysPagesGet(size_t nPages) STATIC LosVmPage *OsVmPhysPagesGet(size_t nPages)
{ {
...@@ -447,7 +480,7 @@ VOID *LOS_PhysPagesAllocContiguous(size_t nPages) ...@@ -447,7 +480,7 @@ VOID *LOS_PhysPagesAllocContiguous(size_t nPages)
return OsVmPageToVaddr(page);//通过物理页找虚拟地址 return OsVmPageToVaddr(page);//通过物理页找虚拟地址
} }
///释放连续的物理页 /// 释放多页地址连续的物理内存
VOID LOS_PhysPagesFreeContiguous(VOID *ptr, size_t nPages) VOID LOS_PhysPagesFreeContiguous(VOID *ptr, size_t nPages)
{ {
UINT32 intSave; UINT32 intSave;
...@@ -473,7 +506,7 @@ VOID LOS_PhysPagesFreeContiguous(VOID *ptr, size_t nPages) ...@@ -473,7 +506,7 @@ VOID LOS_PhysPagesFreeContiguous(VOID *ptr, size_t nPages)
LOS_SpinUnlockRestore(&seg->freeListLock, intSave); LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
} }
/// 通过物理地址获取内核虚拟地址,内核静态映射,减少虚实地址的转换 /// 通过物理地址获取内核虚拟地址
VADDR_T *LOS_PaddrToKVaddr(PADDR_T paddr) VADDR_T *LOS_PaddrToKVaddr(PADDR_T paddr)
{ {
struct VmPhysSeg *seg = NULL; struct VmPhysSeg *seg = NULL;
...@@ -488,7 +521,7 @@ VADDR_T *LOS_PaddrToKVaddr(PADDR_T paddr) ...@@ -488,7 +521,7 @@ VADDR_T *LOS_PaddrToKVaddr(PADDR_T paddr)
//内核 //内核
return (VADDR_T *)(UINTPTR)(paddr - SYS_MEM_BASE + KERNEL_ASPACE_BASE);// return (VADDR_T *)(UINTPTR)(paddr - SYS_MEM_BASE + KERNEL_ASPACE_BASE);//
} }
///释放物理页框 ///释放一个物理页框
VOID LOS_PhysPageFree(LosVmPage *page) VOID LOS_PhysPageFree(LosVmPage *page)
{ {
UINT32 intSave; UINT32 intSave;
...@@ -508,7 +541,7 @@ VOID LOS_PhysPageFree(LosVmPage *page) ...@@ -508,7 +541,7 @@ VOID LOS_PhysPageFree(LosVmPage *page)
LOS_SpinUnlockRestore(&seg->freeListLock, intSave); LOS_SpinUnlockRestore(&seg->freeListLock, intSave);
} }
} }
///供外部调用 /// 申请一个物理页
LosVmPage *LOS_PhysPageAlloc(VOID) LosVmPage *LOS_PhysPageAlloc(VOID)
{ {
return OsVmPhysPagesGet(ONE_PAGE);//分配一页物理页 return OsVmPhysPagesGet(ONE_PAGE);//分配一页物理页
......
...@@ -76,7 +76,7 @@ ...@@ -76,7 +76,7 @@
* @image html https://gitee.com/weharmonyos/resources/raw/master/27/mux.png * @image html https://gitee.com/weharmonyos/resources/raw/master/27/mux.png
* @attention * @attention
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-21 * @date 2021-11-21
*/ */
......
...@@ -33,7 +33,7 @@ ...@@ -33,7 +33,7 @@
至此,程序将在不断地缺页中断中执行。 至此,程序将在不断地缺页中断中执行。
@endverbatim @endverbatim
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-19 * @date 2021-11-19
*/ */
/* /*
......
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
@endverbatim @endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/80/trace.png * @image html https://gitee.com/weharmonyos/resources/raw/master/80/trace.png
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-20 * @date 2021-11-20
*/ */
/* /*
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
Trace提供2种工作模式,离线模式和在线模式。此处为离线模式下的实现 Trace提供2种工作模式,离线模式和在线模式。此处为离线模式下的实现
@endverbatim @endverbatim
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-22 * @date 2021-11-22
*/ */
/* /*
......
...@@ -13,7 +13,7 @@ ...@@ -13,7 +13,7 @@
本文件为 在线模式 本文件为 在线模式
@endverbatim @endverbatim
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-22 * @date 2021-11-22
*/ */
/* /*
......
...@@ -42,9 +42,9 @@ extern "C" { ...@@ -42,9 +42,9 @@ extern "C" {
typedef struct {//Vdso数据页结构体 typedef struct {//Vdso数据页结构体
/* Timeval */ /* Timeval */
INT64 realTimeSec; ///< INT64 realTimeSec; ///< 单位秒: 系统实时时间
INT64 realTimeNsec; ///< INT64 realTimeNsec; ///< 单位纳秒: 系统实时时间
INT64 monoTimeSec; ///< INT64 monoTimeSec; ///< 系统运行时间,从系统启动时开始计时,速度更快精度更低,系统休眠时不再计时
INT64 monoTimeNsec; ///< INT64 monoTimeNsec; ///<
/* lock DataPage 0:Unlock State 1:Lock State */ /* lock DataPage 0:Unlock State 1:Lock State */
UINT64 lockCount;///< 数据页被锁数量 UINT64 lockCount;///< 数据页被锁数量
......
...@@ -105,14 +105,26 @@ UINT32 OsVdsoInit(VOID) ...@@ -105,14 +105,26 @@ UINT32 OsVdsoInit(VOID)
} }
LOS_MODULE_INIT(OsVdsoInit, LOS_INIT_LEVEL_KMOD_EXTENDED);//注册vdso模块 LOS_MODULE_INIT(OsVdsoInit, LOS_INIT_LEVEL_KMOD_EXTENDED);//注册vdso模块
/// 映射,这里先通过内核地址找到 vdso的物理地址,再将物理地址映射到进程的线性区.
/// 结论是每个进程都可以拥有自己的 vdso区,映射到同一个块物理地址. /*!
* @brief OsVdsoMap 映射,这里先通过内核地址找到 vdso的物理地址,再将物理地址映射到进程的线性区.
* \n 结论是每个进程都可以拥有自己的 vdso区,映射到同一个块物理地址.
*
* @param flag
* @param len 映射长度
* @param paddr 物理地址
* @param space 进程空间
* @param vaddr 虚拟地址
* @return
*
* @see
*/
STATIC INT32 OsVdsoMap(LosVmSpace *space, size_t len, PADDR_T paddr, VADDR_T vaddr, UINT32 flag) STATIC INT32 OsVdsoMap(LosVmSpace *space, size_t len, PADDR_T paddr, VADDR_T vaddr, UINT32 flag)
{ {
STATUS_T ret; STATUS_T ret;
while (len > 0) { while (len > 0) {
ret = LOS_ArchMmuMap(&(space->archMmu), vaddr, paddr, 1, flag); ret = LOS_ArchMmuMap(&(space->archMmu), vaddr, paddr, 1, flag);//建立虚实映射关系
if (ret != 1) { if (ret != 1) {
PRINT_ERR("VDSO Load Failed! : LOS_ArchMmuMap!\n"); PRINT_ERR("VDSO Load Failed! : LOS_ArchMmuMap!\n");
return LOS_NOK; return LOS_NOK;
...@@ -136,7 +148,7 @@ vaddr_t OsVdsoLoad(const LosProcessCB *processCB) ...@@ -136,7 +148,7 @@ vaddr_t OsVdsoLoad(const LosProcessCB *processCB)
{ {
INT32 ret = -1; INT32 ret = -1;
LosVmMapRegion *vdsoRegion = NULL; LosVmMapRegion *vdsoRegion = NULL;
UINT32 flag = VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_EXECUTE; UINT32 flag = VM_MAP_REGION_FLAG_PERM_USER | VM_MAP_REGION_FLAG_PERM_READ | VM_MAP_REGION_FLAG_PERM_EXECUTE; //用户空间区,可读,可执行,但不可写
//用户区,可读可执行 //用户区,可读可执行
if ((processCB == NULL) || (processCB->vmSpace == NULL)) { if ((processCB == NULL) || (processCB->vmSpace == NULL)) {
return 0; return 0;
......
...@@ -34,7 +34,7 @@ ...@@ -34,7 +34,7 @@
#include "sys/time.h" #include "sys/time.h"
#include "los_typedef.h" #include "los_typedef.h"
#include "los_vdso_datapage.h" #include "los_vdso_datapage.h"
/// 通过vdso获取大致的实时时间
STATIC INT32 VdsoGetRealtimeCoarse(struct timespec *ts, const VdsoDataPage *usrVdsoDataPage) STATIC INT32 VdsoGetRealtimeCoarse(struct timespec *ts, const VdsoDataPage *usrVdsoDataPage)
{ {
do { do {
...@@ -45,7 +45,7 @@ STATIC INT32 VdsoGetRealtimeCoarse(struct timespec *ts, const VdsoDataPage *usrV ...@@ -45,7 +45,7 @@ STATIC INT32 VdsoGetRealtimeCoarse(struct timespec *ts, const VdsoDataPage *usrV
} }
} while (1); } while (1);
} }
/// 通过vdso获取大致的运行时间
STATIC INT32 VdsoGetMonotimeCoarse(struct timespec *ts, const VdsoDataPage *usrVdsoDataPage) STATIC INT32 VdsoGetMonotimeCoarse(struct timespec *ts, const VdsoDataPage *usrVdsoDataPage)
{ {
do { do {
...@@ -56,7 +56,7 @@ STATIC INT32 VdsoGetMonotimeCoarse(struct timespec *ts, const VdsoDataPage *usrV ...@@ -56,7 +56,7 @@ STATIC INT32 VdsoGetMonotimeCoarse(struct timespec *ts, const VdsoDataPage *usrV
} }
} while (1); } while (1);
} }
/// 开始vdso
STATIC size_t LocVdsoStart(size_t vdsoStart, const CHAR *elfHead, const size_t len) STATIC size_t LocVdsoStart(size_t vdsoStart, const CHAR *elfHead, const size_t len)
{ {
CHAR *head = NULL; CHAR *head = NULL;
......
...@@ -21,7 +21,7 @@ ...@@ -21,7 +21,7 @@
若需要新增系统调用接口,详见开发指导。内核向用户态提供的系统调用接口清单详见kernel/liteos_a/syscall/syscall_lookup.h, 若需要新增系统调用接口,详见开发指导。内核向用户态提供的系统调用接口清单详见kernel/liteos_a/syscall/syscall_lookup.h,
内核相应的系统调用对接函数清单详见kernel/liteos_a/syscall/los_syscall.h。 内核相应的系统调用对接函数清单详见kernel/liteos_a/syscall/los_syscall.h。
* @version * @version
* @author weharmonyos.com * @author weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
* @date 2021-11-19 * @date 2021-11-19
*/ */
/* /*
......
git add -A git add -A
git commit -m ' 注解 dmesg模块,环形buf记录内核日志 git commit -m ' 对虚拟内存/物理内存模块更详细的注解
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码 百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
鸿蒙研究站 | http://weharmonyos.com (国内) 鸿蒙研究站 | http://weharmonyos.com (国内)
| https://weharmony.github.io (国外) | https://weharmony.github.io (国外)
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册