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

因同步官源,代码覆盖,部分模块需重新注解

    百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
    博客输出站点(国内):http://weharmonyos.com
    博客输出站点(国外):https://weharmony.github.io
    注解文件系统:https://gitee.com/weharmony/third_party_NuttX
    注解协议栈:https://gitee.com/weharmony/third_party_lwip
    注解编译子系统:https://gitee.com/weharmony/build_lite
上级 15c69bee
/*!
* @file los_arch_mmu.h
* @brief
*
* \n
* @link https://blog.csdn.net/kuangyufei/article/details/109032636
* \n https://blog.csdn.net/qq_38410730/article/details/81036768
* @verbatim
https://blog.csdn.net/kuangyufei/article/details/109032636
https://blog.csdn.net/qq_38410730/article/details/81036768
虚拟内存空间中的地址叫做“虚拟地址”;而实际物理内存空间中的地址叫做“实际物理地址”或“物理地址”。处理器
运算器和应用程序设计人员看到的只是虚拟内存空间和虚拟地址,而处理器片外的地址总线看到的只是物理地址空间和物理地址。
MMU是 MemoryManagementUnit 的缩写即,内存管理单元.
MMU 的作用:
1. 将虚拟地址翻译成为物理地址,然后访问实际的物理地址
2. 访问权限控制
当处理器试图访问一个虚存页面时,首先到页表中去查询该页是否已映射到物理页框中,并记录在页表中。如果在,
则MMU会把页码转换成页框码,并加上虚拟地址提供的页内偏移量形成物理地址后去访问物理内存;如果不在,
则意味着该虚存页面还没有被载入内存,这时MMU就会通知操作系统:发生了一个页面访问错误(页面错误),
接下来系统会启动所谓的“请页”机制,即调用相应的系统操作函数,判断该虚拟地址是否为有效地址。
如果是有效的地址,就从虚拟内存中将该地址指向的页面读入到内存中的一个空闲页框中,并在页表中添加上
相对应的表项,最后处理器将从发生页面错误的地方重新开始运行;如果是无效的地址,则表明进程在试图访问
一个不存在的虚拟地址,此时操作系统将终止此次访问。
* @endverbatim
*
* \n
* @version
* @author weharmonyos.com
* @date 2021-11-16
*
* @history
*
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......@@ -46,34 +80,13 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/**
* @file los_arch_mmu.h
* @brief 简介
* @details 细节
* @attention
https://blog.csdn.net/kuangyufei/article/details/109032636
https://blog.csdn.net/qq_38410730/article/details/81036768
虚拟内存空间中的地址叫做“虚拟地址”;而实际物理内存空间中的地址叫做“实际物理地址”或“物理地址”。处理器
运算器和应用程序设计人员看到的只是虚拟内存空间和虚拟地址,而处理器片外的地址总线看到的只是物理地址空间和物理地址。
MMU是 MemoryManagementUnit 的缩写即,内存管理单元.
MMU 的作用:
1. 将虚拟地址翻译成为物理地址,然后访问实际的物理地址
2. 访问权限控制
当处理器试图访问一个虚存页面时,首先到页表中去查询该页是否已映射到物理页框中,并记录在页表中。如果在,
则MMU会把页码转换成页框码,并加上虚拟地址提供的页内偏移量形成物理地址后去访问物理内存;如果不在,
则意味着该虚存页面还没有被载入内存,这时MMU就会通知操作系统:发生了一个页面访问错误(页面错误),
接下来系统会启动所谓的“请页”机制,即调用相应的系统操作函数,判断该虚拟地址是否为有效地址。
如果是有效的地址,就从虚拟内存中将该地址指向的页面读入到内存中的一个空闲页框中,并在页表中添加上
相对应的表项,最后处理器将从发生页面错误的地方重新开始运行;如果是无效的地址,则表明进程在试图访问
一个不存在的虚拟地址,此时操作系统将终止此次访问。
*/
typedef struct ArchMmu {//内存管理单元
LosMux mtx; /**< arch mmu page table entry modification mutex lock \n 对页表操作的互斥量*/
VADDR_T *virtTtb; /**< translation table base virtual addr \n 注意:这里是个指针,内核操作都用这个地址*/
PADDR_T physTtb; /**< translation table base phys addr \n 注意:这里是个值,这个值是记录给MMU使用的,MMU只认它,内核是无法使用的*/
UINT32 asid; /**< TLB asid \n 标识进程用的,由mmu分配,有了它在mmu层面才知道是哪个进程的虚拟地址*/
LOS_DL_LIST ptList; /**< page table vm page list \n L1 为表头,后面挂的是n多L2*/
LosMux mtx; /**< arch mmu page table entry modification mutex lock | 对页表操作的互斥量*/
VADDR_T *virtTtb; /**< translation table base virtual addr | 注意:这里是个指针,内核操作都用这个地址*/
PADDR_T physTtb; /**< translation table base phys addr | 注意:这里是个值,这个值是记录给MMU使用的,MMU只认它,内核是无法使用的*/
UINT32 asid; /**< TLB asid | 标识进程用的,由mmu初始化阶段申请分配,有了它在mmu层面才知道是哪个进程的虚拟地址*/
LOS_DL_LIST ptList; /**< page table vm page list | L1 为表头,后面挂的是n多L2*/
} LosArchMmu;
BOOL OsArchMmuInit(LosArchMmu *archMmu, VADDR_T *virtTtb);
......
......@@ -58,9 +58,9 @@ __attribute__((aligned(MMU_DESCRIPTOR_L1_SMALL_ENTRY_NUMBERS))) \
UINT8 *g_mmuJumpPageTable = g_tempPageTable;
#else
extern CHAR __mmu_ttlb_begin; /* defined in .ld script */
UINT8 *g_mmuJumpPageTable = (UINT8 *)&__mmu_ttlb_begin; /* temp page table, this is only used when system power up */
UINT8 *g_mmuJumpPageTable = (UINT8 *)&__mmu_ttlb_begin; /* temp page table, this is only used when system power up | 临时页表,用于系统启动阶段*/
#endif
/// 获取页表基地址
STATIC INLINE PTE_T *OsGetPte2BasePtr(PTE_T pte1)
{
PADDR_T pa = MMU_DESCRIPTOR_L1_PAGE_TABLE_ADDR(pte1);
......@@ -376,11 +376,20 @@ STATIC UINT32 OsUnmapSection(LosArchMmu *archMmu, vaddr_t *vaddr, UINT32 *count)
return MMU_DESCRIPTOR_L2_NUMBERS_PER_L1;
}
//mmu 初始化
/*!
* @brief OsArchMmuInit 初始化MMU
*
* @param archMmu
* @param virtTtb
* @return
*
* @see
*/
BOOL OsArchMmuInit(LosArchMmu *archMmu, VADDR_T *virtTtb)
{
#ifdef LOSCFG_KERNEL_VM
if (OsAllocAsid(&archMmu->asid) != LOS_OK) {//分配一个asid,ASID可用来唯一标识进程
if (OsAllocAsid(&archMmu->asid) != LOS_OK) {//分配一个asid,ASID可用来唯一标识进程空间
VM_ERR("alloc arch mmu asid failed");//地址空间标识码(address-space identifier,ASID)为CP15协处理器 C13寄存器
return FALSE;
}
......@@ -400,13 +409,17 @@ BOOL OsArchMmuInit(LosArchMmu *archMmu, VADDR_T *virtTtb)
return TRUE;
}
/**
* @brief 本函数是内核高频函数,通过MMU查询虚拟地址是否映射过,带走映射的物理地址和权限
* @param archMmu
* @param vaddr
* @param paddr
* @param flags
* @return STATUS_T
/*!
* @brief LOS_ArchMmuQuery 本函数是内核高频函数,通过MMU查询虚拟地址是否映射过,带走映射的物理地址和权限
*
* @param archMmu
* @param flags
* @param paddr
* @param vaddr
* @return
*
* @see
*/
STATUS_T LOS_ArchMmuQuery(const LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T *paddr, UINT32 *flags)
{//archMmu->virtTtb:转换表基地址
......@@ -447,7 +460,17 @@ STATUS_T LOS_ArchMmuQuery(const LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T *pad
return LOS_OK;
}
/// 解除映射关系
/*!
* @brief LOS_ArchMmuUnmap 解除映射关系
*
* @param archMmu
* @param count
* @param vaddr
* @return
*
* @see
*/
STATUS_T LOS_ArchMmuUnmap(LosArchMmu *archMmu, VADDR_T vaddr, size_t count)
{
PTE_T l1Entry;
......@@ -477,7 +500,19 @@ STATUS_T LOS_ArchMmuUnmap(LosArchMmu *archMmu, VADDR_T vaddr, size_t count)
OsArmInvalidateTlbBarrier();//TLB失效,不可用
return unmapped;
}
/// section页表格式项映射
/*!
* @brief OsMapSection section页表格式项映射
*
* @param archMmu
* @param count
* @param flags
* @param paddr
* @param vaddr
* @return
*
* @see
*/
STATIC UINT32 OsMapSection(const LosArchMmu *archMmu, UINT32 flags, VADDR_T *vaddr,
PADDR_T *paddr, UINT32 *count)
{
......@@ -762,6 +797,14 @@ STATUS_T LOS_ArchMmuMove(LosArchMmu *archMmu, VADDR_T oldVaddr, VADDR_T newVaddr
return LOS_OK;
}
/*!
* @brief LOS_ArchMmuContextSwitch 切换MMU上下文
*
* @param archMmu
* @return
*
* @see
*/
VOID LOS_ArchMmuContextSwitch(LosArchMmu *archMmu)
{
UINT32 ttbr;
......@@ -793,17 +836,25 @@ VOID LOS_ArchMmuContextSwitch(LosArchMmu *archMmu)
#endif
}
/*!
* @brief LOS_ArchMmuDestroy 销毁MMU 和 initMmu 相呼应,释放页表页
*
* @param archMmu
* @return
*
* @see
*/
STATUS_T LOS_ArchMmuDestroy(LosArchMmu *archMmu)
{
#ifdef LOSCFG_KERNEL_VM
LosVmPage *page = NULL;
/* free all of the pages allocated in archMmu->ptList */
while ((page = LOS_ListRemoveHeadType(&archMmu->ptList, LosVmPage, node)) != NULL) {
LOS_PhysPageFree(page);
LOS_PhysPageFree(page);//释放物理页
}
OsArmWriteTlbiasid(archMmu->asid);
OsFreeAsid(archMmu->asid);
OsArmWriteTlbiasid(archMmu->asid);//写TLB
OsFreeAsid(archMmu->asid);//释放asid
#endif
(VOID)LOS_MuxDestroy(&archMmu->mtx);
return LOS_OK;
......
/*!
* @file los_asid.c
* @brief
*
* \n
* @link http://weharmonyos.com/blog/14.html
* @verbatim
asid(Adress Space ID) 进程标识符,属于CP15协处理器的C13号寄存器,ASID可用来唯一标识进程,并为进程提供地址空间保护。
当TLB试图解析虚拟页号时,它确保当前运行进程的ASID与虚拟页相关的ASID相匹配。如果不匹配,那么就作为TLB失效。
除了提供地址空间保护外,ASID允许TLB同时包含多个进程的条目。如果TLB不支持独立的ASID,每次选择一个页表时(例如,上下文切换时),
TLB就必须被冲刷(flushed)或删除,以确保下一个进程不会使用错误的地址转换。
TLB页表中有一个bit来指明当前的entry是global(nG=0,所有process都可以访问)还是non-global(nG=1,only本process允许访问)。
如果是global类型,则TLB中不会tag ASID;如果是non-global类型,则TLB会tag上ASID,
且MMU在TLB中查询时需要判断这个ASID和当前进程的ASID是否一致,只有一致才证明这条entry当前process有权限访问。
看到了吗?如果每次mmu上下文切换时,把TLB全部刷新已保证TLB中全是新进程的映射表,固然是可以,但效率太低了!!!
进程的切换其实是秒级亚秒级的,地址的虚实转换是何等的频繁啊,怎么会这么现实呢,
真实的情况是TLB中有很多很多其他进程占用的物理内存的记录还在,当然他们对物理内存的使用权也还在。
所以当应用程序 new了10M内存以为是属于自己的时候,其实在内核层面根本就不属于你,还是别人在用,
只有你用了1M的那一瞬间真正1M物理内存才属于你,而且当你的进程被其他进程切换后,很大可能你用的那1M也已经不在物理内存中了,
已经被置换到硬盘上了。明白了吗?只关注应用开发的同学当然可以说这关我鸟事,给我的感觉有就行了,但想熟悉内核的同学就必须要明白,
这是每分每秒都在发生的事情。
* @endverbatim
*
* \n
* @version
* @author weharmonyos.com
* @date 2021-11-16
*
* @history
*
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......@@ -42,18 +75,18 @@
#ifdef LOSCFG_KERNEL_VM
STATIC SPIN_LOCK_INIT(g_cpuAsidLock);
STATIC UINTPTR g_asidPool[BITMAP_NUM_WORDS(1UL << MMU_ARM_ASID_BITS)];
STATIC SPIN_LOCK_INIT(g_cpuAsidLock); ///< asid专属自旋锁
STATIC UINTPTR g_asidPool[BITMAP_NUM_WORDS(1UL << MMU_ARM_ASID_BITS)]; ///< 地址空间ID池 , 2^8 = 256 个
/* allocate and free asid */
/* allocate and free asid | 分配地址空间ID */
status_t OsAllocAsid(UINT32 *asid)
{
UINT32 flags;
LOS_SpinLockSave(&g_cpuAsidLock, &flags);
UINT32 firstZeroBit = LOS_BitmapFfz(g_asidPool, 1UL << MMU_ARM_ASID_BITS);
UINT32 firstZeroBit = LOS_BitmapFfz(g_asidPool, 1UL << MMU_ARM_ASID_BITS);//找到第一个0位,即可分配位
if (firstZeroBit >= 0 && firstZeroBit < (1UL << MMU_ARM_ASID_BITS)) {
LOS_BitmapSetNBits(g_asidPool, firstZeroBit, 1);
*asid = firstZeroBit;
LOS_BitmapSetNBits(g_asidPool, firstZeroBit, 1);//设为已分配
*asid = firstZeroBit;//由参数带走
LOS_SpinUnlockRestore(&g_cpuAsidLock, flags);
return LOS_OK;
}
......@@ -62,11 +95,13 @@ status_t OsAllocAsid(UINT32 *asid)
return firstZeroBit;
}
/// 释放 asid
VOID OsFreeAsid(UINT32 asid)
{
UINT32 flags;
LOS_SpinLockSave(&g_cpuAsidLock, &flags);
LOS_BitmapClrNBits(g_asidPool, asid, 1);
LOS_BitmapClrNBits(g_asidPool, asid, 1);//清空对应位,可继续分配给其他进程
LOS_SpinUnlockRestore(&g_cpuAsidLock, flags);
}
#endif
......
/*!
* @file los_hwi.c
* @brief 硬中断主文件
* @link
* @verbatim
基本概念
中断是指出现需要时,CPU暂停执行当前程序,转而执行新程序的过程。即在程序运行过程中,
出现了一个必须由CPU立即处理的事务。此时,CPU暂时中止当前程序的执行转而处理这个事务,
这个过程就叫做中断。
外设可以在没有CPU介入的情况下完成一定的工作,但某些情况下也需要CPU为其执行一定的工作。
通过中断机制,在外设不需要CPU介入时,CPU可以执行其它任务,而当外设需要CPU时,将通过产生
中断信号使CPU立即中断当前任务来响应中断请求。这样可以使CPU避免把大量时间耗费在等待、
查询外设状态的操作上,大大提高系统实时性以及执行效率。
中断特性:
中断共享,且可配置。
中断嵌套,即高优先级的中断可抢占低优先级的中断,且可配置。
使用独立中断栈,可配置。
可配置支持的中断优先级个数。
可配置支持的中断数。
中断相关的硬件介绍
与中断相关的硬件可以划分为三类:设备、中断控制器、CPU本身。
设备
发起中断的源,当设备需要请求CPU时,产生一个中断信号,该信号连接至中断控制器。
中断控制器
中断控制器是CPU众多外设中的一个,它一方面接收其它外设中断引脚的输入,另一方面,
它会发出中断信号给CPU。可以通过对中断控制器编程来打开和关闭中断源、设置中断源
的优先级和触发方式。常用的中断控制器有VIC(Vector Interrupt Controller)和
GIC(General Interrupt Controller)。在ARM Cortex-M系列中使用的中断控制器是
NVIC(Nested Vector Interrupt Controller)。在ARM Cortex-A7中使用的中断控制器是GIC。
CPU
CPU会响应中断源的请求,中断当前正在执行的任务,转而执行中断处理程序。
中断相关概念
中断号
每个中断请求信号都会有特定的标志,使得计算机能够判断是哪个设备提出的中断请求,这个标志就是中断号。
中断请求
“紧急事件”需向CPU提出申请(发一个电脉冲信号),要求中断,及要求CPU暂停当前执行的任务,
转而处理该“紧急事件”,这一申请过程称为中断请求。
中断优先级
为使系统能够及时响应并处理所有中断,系统根据中断时间的重要性和紧迫程度,将中断源分为若干个级别,
称作中断优先级。
中断处理程序
当外设产生中断请求后,CPU暂停当前的任务,转而响应中断申请,即执行中断处理程序。产生中断的每个设备
都有相应的中断处理程序。
中断嵌套
中断嵌套也称为中断抢占,指的是正在执行一个中断处理程序时,如果有另一个优先级更高的中断源提出中断请求,
这时会暂时终止当前正在执行的优先级较低的中断源的中断处理程序,转而去处理更高优先级的中断请求,待处理完毕,
再返回到之前被中断的处理程序中继续执行。
中断触发
中断源向中断控制器发送中断信号,中断控制器对中断进行仲裁,确定优先级,将中断信号送给CPU。
中断源产生中断信号的时候,会将中断触发器置“1”,表明该中断源产生了中断,要求CPU去响应该中断。
中断触发类型
外部中断申请通过一个物理信号发送到NVIC/GIC,可以是电平触发或边沿触发。
中断向量
中断服务程序的入口地址。
中断向量表
存储中断向量的存储区,中断向量与中断号对应,中断向量在中断向量表中按照中断号顺序存储。
中断共享
当外设较少时,可以实现一个外设对应一个中断号,但为了支持更多的硬件设备,可以让多个设备共享
一个中断号,共享同一个中断号的中断处理程序形成一个链表。当外部设备产生中断申请时,系统会
遍历执行中断号对应的中断处理程序链表直到找到对应设备的中断处理程序。在遍历执行过程中,
各中断处理程序可以通过检测设备ID,判断是否是这个中断处理程序对应的设备产生的中断。
核间中断
对于多核系统,中断控制器允许一个CPU的硬件线程去中断其他CPU的硬件线程,这种方式被称为核间中断。
核间中断的实现基础是多CPU内存共享,采用核间中断可以减少某个CPU负荷过大,有效提升系统效率。
目前只有GIC中断控制器支持。
使用场景
当有中断请求产生时,CPU暂停当前的任务,转而去响应外设请求。根据需要,用户通过
中断申请,注册中断处理程序,可以指定CPU响应中断请求时所执行的具体操作。
开发流程
调用中断创建接口LOS_HwiCreate创建中断。
如果是SMP模式,调用LOS_HwiSetAffinity设置中断的亲和性,否则直接进入步骤4。
调用LOS_HwiEnable接口使能指定中断。
调用LOS_HwiTrigger接口触发指定中断(该接口通过写中断控制器的相关寄存器模拟外部中断,一般的外设设备,不需要执行这一步)。
调用LOS_HwiDisable接口屏蔽指定中断,此接口根据实际情况使用,判断是否需要屏蔽中断。
调用LOS_HwiDelete接口删除指定中断,此接口根据实际情况使用,判断是否需要删除中断。
注意事项
根据具体硬件,配置支持的最大中断数及可设置的中断优先级个数。
中断共享机制,支持不同的设备使用相同的中断号注册同一中断处理程序,但中断处理程序的入参pDevId(设备号)
必须唯一,代表不同的设备。即同一中断号,同一dev只能挂载一次;但同一中断号,同一中断处理程序,dev不同则可以重复挂载。
中断处理程序耗时不能过长,否则会影响CPU对中断的及时响应。
中断响应过程中不能执行引起调度的函数。
中断恢复LOS_IntRestore()的入参必须是与之对应的LOS_IntLock()的返回值(即关中断之前的CPSR值)。
Cortex-M系列处理器中0-15中断为内部使用,Cortex-A7中0-31中断为内部使用,因此不建议用户去申请和创建。
* @endverbatim
* @version
* @author weharmonyos.com
* @date 2021-11-16
*
* @history
*
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......@@ -38,91 +131,6 @@
#include "los_sched_pri.h"
#include "los_hook.h"
/**@file los_hwi.c
* @brief 硬中断主文件
* @details
* @attention
基本概念 \n
中断是指出现需要时,CPU暂停执行当前程序,转而执行新程序的过程。即在程序运行过程中, \n
出现了一个必须由CPU立即处理的事务。此时,CPU暂时中止当前程序的执行转而处理这个事务, \n
这个过程就叫做中断。 \n
外设可以在没有CPU介入的情况下完成一定的工作,但某些情况下也需要CPU为其执行一定的工作。 \n
通过中断机制,在外设不需要CPU介入时,CPU可以执行其它任务,而当外设需要CPU时,将通过产生 \n
中断信号使CPU立即中断当前任务来响应中断请求。这样可以使CPU避免把大量时间耗费在等待、 \n
查询外设状态的操作上,大大提高系统实时性以及执行效率。 \n
中断特性: \n
中断共享,且可配置。 \n
中断嵌套,即高优先级的中断可抢占低优先级的中断,且可配置。 \n
使用独立中断栈,可配置。 \n
可配置支持的中断优先级个数。 \n
可配置支持的中断数。 \n
中断相关的硬件介绍 \n
与中断相关的硬件可以划分为三类:设备、中断控制器、CPU本身。 \n
设备 \n
发起中断的源,当设备需要请求CPU时,产生一个中断信号,该信号连接至中断控制器。 \n
中断控制器 \n
中断控制器是CPU众多外设中的一个,它一方面接收其它外设中断引脚的输入,另一方面, \n
它会发出中断信号给CPU。可以通过对中断控制器编程来打开和关闭中断源、设置中断源 \n
的优先级和触发方式。常用的中断控制器有VIC(Vector Interrupt Controller)和 \n
GIC(General Interrupt Controller)。在ARM Cortex-M系列中使用的中断控制器是 \n
NVIC(Nested Vector Interrupt Controller)。在ARM Cortex-A7中使用的中断控制器是GIC。 \n
CPU \n
CPU会响应中断源的请求,中断当前正在执行的任务,转而执行中断处理程序。 \n
中断相关概念 \n
中断号 \n
每个中断请求信号都会有特定的标志,使得计算机能够判断是哪个设备提出的中断请求,这个标志就是中断号。 \n
中断请求 \n
“紧急事件”需向CPU提出申请(发一个电脉冲信号),要求中断,及要求CPU暂停当前执行的任务, \n
转而处理该“紧急事件”,这一申请过程称为中断请求。 \n
中断优先级 \n
为使系统能够及时响应并处理所有中断,系统根据中断时间的重要性和紧迫程度,将中断源分为若干个级别, \n
称作中断优先级。 \n
中断处理程序 \n
当外设产生中断请求后,CPU暂停当前的任务,转而响应中断申请,即执行中断处理程序。产生中断的每个设备 \n
都有相应的中断处理程序。 \n
中断嵌套 \n
中断嵌套也称为中断抢占,指的是正在执行一个中断处理程序时,如果有另一个优先级更高的中断源提出中断请求, \n
这时会暂时终止当前正在执行的优先级较低的中断源的中断处理程序,转而去处理更高优先级的中断请求,待处理完毕, \n
再返回到之前被中断的处理程序中继续执行。 \n
中断触发 \n
中断源向中断控制器发送中断信号,中断控制器对中断进行仲裁,确定优先级,将中断信号送给CPU。 \n
中断源产生中断信号的时候,会将中断触发器置“1”,表明该中断源产生了中断,要求CPU去响应该中断。 \n
中断触发类型 \n
外部中断申请通过一个物理信号发送到NVIC/GIC,可以是电平触发或边沿触发。 \n
中断向量 \n
中断服务程序的入口地址。 \n
中断向量表 \n
存储中断向量的存储区,中断向量与中断号对应,中断向量在中断向量表中按照中断号顺序存储。 \n
中断共享 \n
当外设较少时,可以实现一个外设对应一个中断号,但为了支持更多的硬件设备,可以让多个设备共享 \n
一个中断号,共享同一个中断号的中断处理程序形成一个链表。当外部设备产生中断申请时,系统会 \n
遍历执行中断号对应的中断处理程序链表直到找到对应设备的中断处理程序。在遍历执行过程中, \n
各中断处理程序可以通过检测设备ID,判断是否是这个中断处理程序对应的设备产生的中断。 \n
核间中断 \n
对于多核系统,中断控制器允许一个CPU的硬件线程去中断其他CPU的硬件线程,这种方式被称为核间中断。 \n
核间中断的实现基础是多CPU内存共享,采用核间中断可以减少某个CPU负荷过大,有效提升系统效率。 \n
目前只有GIC中断控制器支持。 \n
使用场景 \n
当有中断请求产生时,CPU暂停当前的任务,转而去响应外设请求。根据需要,用户通过 \n
中断申请,注册中断处理程序,可以指定CPU响应中断请求时所执行的具体操作。 \n
开发流程 \n
调用中断创建接口LOS_HwiCreate创建中断。 \n \n
如果是SMP模式,调用LOS_HwiSetAffinity设置中断的亲和性,否则直接进入步骤4。 \n
调用LOS_HwiEnable接口使能指定中断。 \n
调用LOS_HwiTrigger接口触发指定中断(该接口通过写中断控制器的相关寄存器模拟外部中断,一般的外设设备,不需要执行这一步)。 \n
调用LOS_HwiDisable接口屏蔽指定中断,此接口根据实际情况使用,判断是否需要屏蔽中断。 \n
调用LOS_HwiDelete接口删除指定中断,此接口根据实际情况使用,判断是否需要删除中断。 \n
注意事项 \n
根据具体硬件,配置支持的最大中断数及可设置的中断优先级个数。 \n
中断共享机制,支持不同的设备使用相同的中断号注册同一中断处理程序,但中断处理程序的入参pDevId(设备号) \n
必须唯一,代表不同的设备。即同一中断号,同一dev只能挂载一次;但同一中断号,同一中断处理程序,dev不同则可以重复挂载。 \n
中断处理程序耗时不能过长,否则会影响CPU对中断的及时响应。 \n
中断响应过程中不能执行引起调度的函数。 \n
中断恢复LOS_IntRestore()的入参必须是与之对应的LOS_IntLock()的返回值(即关中断之前的CPSR值)。 \n
Cortex-M系列处理器中0-15中断为内部使用,Cortex-A7中0-31中断为内部使用,因此不建议用户去申请和创建。 \n
*/
/* spinlock for hwi module, only available on SMP mode */
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_hwiSpin); ///< 注意全局变量 g_hwiSpin 是在宏里面定义的
......
......@@ -42,6 +42,7 @@
// /proc 下的文件描述符适配层
/*
* Template: Pid Fd [SysFd ] Name
*/ //打印系统文件描述符信息
......
......@@ -37,16 +37,16 @@
#endif
LITE_OS_SEC_DATA_INIT UINT32 g_sysClock;///< 系统时钟,是绝大部分部件工作的时钟源,也是其他所有外设的时钟的来源
LITE_OS_SEC_DATA_INIT UINT32 g_sysClock; ///< 系统时钟,是绝大部分部件工作的时钟源,也是其他所有外设的时钟的来源
LITE_OS_SEC_DATA_INIT UINT32 g_tickPerSecond;///<每秒Tick数,鸿蒙默认是每秒100次,即:10ms
LITE_OS_SEC_BSS DOUBLE g_cycle2NsScale; ///<周期转纳秒级
LITE_OS_SEC_BSS DOUBLE g_cycle2NsScale; ///<周期转纳秒级
/* spinlock for task module */
LITE_OS_SEC_BSS SPIN_LOCK_INIT(g_tickSpin); ///<节拍器自旋锁
/*
* Description : Tick interruption handler
*///节拍中断处理函数 ,鸿蒙默认10ms触发一次
* Description : Tick interruption handler | 节拍中断处理函数 ,鸿蒙默认10ms触发一次
*/
LITE_OS_SEC_TEXT VOID OsTickHandler(VOID)
{
#ifdef LOSCFG_SCHED_TICK_DEBUG
......
......@@ -80,7 +80,7 @@ typedef struct ProcessCB {
CHAR processName[OS_PCB_NAME_LEN]; /**< Process name | 进程名称 */
UINT32 processID; /**< Process ID = leader thread ID | 进程ID,由进程池分配,范围[0,64] */
UINT16 processStatus; /**< [15:4] Process Status; [3:0] The number of threads currently
running in the process | 这里设计很巧妙.用一个变量表示了两层逻辑 数量和状态,点赞!从这里也可以看出一个进程可以有多个正在运行的任务*/
running in the process | 这里设计很巧妙.用一个变量表示了两层逻辑 数量和状态,点赞! @note_good 从这里也可以看出一个进程可以有多个正在运行的任务*/
UINT16 priority; /**< Process priority | 进程优先级*/
UINT16 consoleID; /**< The console id of task belongs | 任务的控制台id归属 */
UINT16 processMode; /**< Kernel Mode:0; User Mode:1; | 模式指定为内核还是用户进程 */
......@@ -300,9 +300,12 @@ STATIC INLINE BOOL OsProcessIsDead(const LosProcessCB *processCB)//查下进程
#define OS_PROCESS_USERINIT_PRIORITY 28 ///< 用户进程默认的优先级,28级好低啊
#define OS_GET_PROCESS_STATUS(status) ((UINT16)((UINT16)(status) & OS_PROCESS_STATUS_MASK))
/// 获取进程处于运行中的任务数量
#define OS_PROCESS_GET_RUNTASK_COUNT(status) ((UINT16)(((UINT16)(status)) & OS_PROCESS_RUNTASK_COUNT_MASK))
/// 进程运行中的任务数量加1
#define OS_PROCESS_RUNTASK_COUNT_ADD(status) ((UINT16)(((UINT16)(status)) & OS_PROCESS_STATUS_MASK) | \
((OS_PROCESS_GET_RUNTASK_COUNT(status) + 1) & OS_PROCESS_RUNTASK_COUNT_MASK))
/// 进程运行中的任务数量减1
#define OS_PROCESS_RUNTASK_COUNT_DEC(status) ((UINT16)(((UINT16)(status)) & OS_PROCESS_STATUS_MASK) | \
((OS_PROCESS_GET_RUNTASK_COUNT(status) - 1) & OS_PROCESS_RUNTASK_COUNT_MASK))
......
......@@ -301,68 +301,68 @@ extern SPIN_LOCK_S g_taskSpin;//任务自旋锁
#define OS_TCB_NAME_LEN 32
typedef struct {
VOID *stackPointer; /**< Task stack pointer \n */ //内核栈指针位置(SP)
UINT16 taskStatus; /**< Task status \n */ //各种状态标签,可以拥有多种标签,按位标识
UINT16 priority; /**< Task priority \n */ //任务优先级[0:31],默认是31级
UINT16 policy; //任务的调度方式(三种 .. LOS_SCHED_RR )
UINT64 startTime; /**< The start time of each phase of task \n *///任务开始时间
UINT64 irqStartTime; /**< Interrupt start time \n *///任务中断开始时间
UINT32 irqUsedTime; /**< Interrupt consumption time \n *///任务中断恢复时间
UINT32 initTimeSlice; /**< Task init time slice \n *///任务初始的时间片
INT32 timeSlice; /**< Task remaining time slice \n *///任务剩余时间片
UINT32 waitTimes; /**< Task delay time, tick number \n *///设置任务调度延期时间
SortLinkList sortList; /**< Task sortlink node \n */ //任务排序链表节点
UINT32 stackSize; /**< Task stack size \n */ //内核态栈大小,内存来自内核空间
UINTPTR topOfStack; /**< Task stack top \n */ //内核态栈顶 bottom = top + size
UINT32 taskID; /**< Task ID \n */ //任务ID,任务池本质是一个大数组,ID就是数组的索引,默认 < 128
TSK_ENTRY_FUNC taskEntry; /**< Task entrance function \n */ //任务执行入口函数
VOID *joinRetval; /**< pthread adaption \n */ //用来存储join线程的返回值
VOID *taskMux; /**< Task-held mutex \n */ //task在等哪把锁
VOID *taskEvent; /**< Task-held event \n */ //task在等哪个事件
UINTPTR args[4]; /**< Parameter, of which the maximum number is 4 \n */ //入口函数的参数 例如 main (int argc,char *argv[])
CHAR taskName[OS_TCB_NAME_LEN]; /**< Task name \n */ //任务的名称
LOS_DL_LIST pendList; /**< Task pend node \n */ //如果任务阻塞时就通过它挂到各种阻塞情况的链表上,比如OsTaskWait时
LOS_DL_LIST threadList; /**< thread list \n */ //挂到所属进程的线程链表上
UINT32 eventMask; /**< Event mask \n */ //任务对哪些事件进行屏蔽
UINT32 eventMode; /**< Event mode \n */ //事件三种模式(LOS_WAITMODE_AND,LOS_WAITMODE_OR,LOS_WAITMODE_CLR)
UINT32 priBitMap; /**< BitMap for recording the change of task priority, //任务在执行过程中优先级会经常变化,这个变量用来记录所有曾经变化
the priority can not be greater than 31 \n */ //过的优先级,例如 ..01001011 曾经有过 0,1,3,6 优先级
VOID *stackPointer; /**< Task stack pointer | 内核栈指针位置(SP) */
UINT16 taskStatus; /**< Task status | 各种状态标签,可以拥有多种标签,按位标识 */
UINT16 priority; /**< Task priority | 任务优先级[0:31],默认是31级 */
UINT16 policy; ///< 任务的调度方式(三种 .. LOS_SCHED_RR )
UINT64 startTime; /**< The start time of each phase of task | 任务开始时间 */
UINT64 irqStartTime; /**< Interrupt start time | 任务中断开始时间 */
UINT32 irqUsedTime; /**< Interrupt consumption time | 任务中断恢复时间 */
UINT32 initTimeSlice; /**< Task init time slice | 任务初始的时间片 */
INT32 timeSlice; /**< Task remaining time slice | 任务剩余时间片 */
UINT32 waitTimes; /**< Task delay time, tick number | 设置任务调度延期时间 */
SortLinkList sortList; /**< Task sortlink node | 任务排序链表节点 */
UINT32 stackSize; /**< Task stack size | 内核态栈大小,内存来自内核空间 */
UINTPTR topOfStack; /**< Task stack top | 内核态栈顶 bottom = top + size */
UINT32 taskID; /**< Task ID | 任务ID,任务池本质是一个大数组,ID就是数组的索引,默认 < 128 */
TSK_ENTRY_FUNC taskEntry; /**< Task entrance function | 任务执行入口函数 */
VOID *joinRetval; /**< pthread adaption | 用来存储join线程的返回值 */
VOID *taskMux; /**< Task-held mutex | task在等哪把锁 */
VOID *taskEvent; /**< Task-held event | task在等哪个事件 */
UINTPTR args[4]; /**< Parameter, of which the maximum number is 4 | 入口函数的参数 例如 main (int argc,char *argv[]) */
CHAR taskName[OS_TCB_NAME_LEN]; /**< Task name | 任务的名称 */
LOS_DL_LIST pendList; /**< Task pend node | 如果任务阻塞时就通过它挂到各种阻塞情况的链表上,比如OsTaskWait时 */
LOS_DL_LIST threadList; /**< thread list | 挂到所属进程的线程链表上 */
UINT32 eventMask; /**< Event mask | 任务对哪些事件进行屏蔽 */
UINT32 eventMode; /**< Event mode | 事件三种模式(LOS_WAITMODE_AND,LOS_WAITMODE_OR,LOS_WAITMODE_CLR) */
UINT32 priBitMap; /**< BitMap for recording the change of task priority,the priority can not be greater than 31
| 任务在执行过程中优先级会经常变化,这个变量用来记录所有曾经变化过的优先级,例如 ..01001011 曾经有过 0,1,3,6 优先级 */
#ifdef LOSCFG_KERNEL_CPUP
OsCpupBase taskCpup; /**< task cpu usage \n */
OsCpupBase taskCpup; /**< task cpu usage | CPU 使用统计 */
#endif
INT32 errorNo; /**< Error Num \n */
UINT32 signal; /**< Task signal \n */ //任务信号类型,(SIGNAL_NONE,SIGNAL_KILL,SIGNAL_SUSPEND,SIGNAL_AFFI)
sig_cb sig; //信号控制块,用于异步通信,类似于 linux singal模块
INT32 errorNo; /**< Error Num | 错误序号 */
UINT32 signal; /**< Task signal | 任务信号类型,(SIGNAL_NONE,SIGNAL_KILL,SIGNAL_SUSPEND,SIGNAL_AFFI) */
sig_cb sig; ///< 信号控制块,用于异步通信,类似于 linux singal模块
#ifdef LOSCFG_KERNEL_SMP
UINT16 currCpu; /**< CPU core number of this task is running on \n */ //正在运行此任务的CPU内核号
UINT16 lastCpu; /**< CPU core number of this task is running on last time \n */ //上次运行此任务的CPU内核号
UINT16 cpuAffiMask; /**< CPU affinity mask, support up to 16 cores \n */ //CPU亲和力掩码,最多支持16核,亲和力很重要,多核情况下尽量一个任务在一个CPU核上运行,提高效率
UINT16 currCpu; /**< CPU core number of this task is running on | 正在运行此任务的CPU内核号 */
UINT16 lastCpu; /**< CPU core number of this task is running on last time | 上次运行此任务的CPU内核号 */
UINT16 cpuAffiMask; /**< CPU affinity mask, support up to 16 cores | CPU亲和力掩码,最多支持16核,亲和力很重要,多核情况下尽量一个任务在一个CPU核上运行,提高效率 */
#ifdef LOSCFG_KERNEL_SMP_TASK_SYNC
UINT32 syncSignal; /**< Synchronization for signal handling \n */ //用于CPU之间 同步信号
UINT32 syncSignal; /**< Synchronization for signal handling | 用于CPU之间 同步信号 */
#endif
#ifdef LOSCFG_KERNEL_SMP_LOCKDEP //死锁检测开关
LockDep lockDep;
#ifdef LOSCFG_KERNEL_SMP_LOCKDEP //SMP死锁检测开关
LockDep lockDep; ///< 死锁依赖检测
#endif
#endif
#ifdef LOSCFG_SCHED_DEBUG
SchedStat schedStat; /**< Schedule statistics \n */
#ifdef LOSCFG_SCHED_DEBUG //调试调度开关
SchedStat schedStat; /**< Schedule statistics | 调度统计 */
#endif
UINTPTR userArea; ///< 用户空间的堆区开始位置
UINTPTR userMapBase; ///< 用户空间的栈顶位置,内存来自用户空间,和topOfStack有本质的区别.
UINT32 userMapSize; /**< user thread stack size ,real size : userMapSize + USER_STACK_MIN_SIZE \n *///用户栈大小
UINT32 processID; /**< Which belong process \n *///所属进程ID
UINT32 userMapSize; /**< user thread stack size ,real size : userMapSize + USER_STACK_MIN_SIZE | 用户栈大小 */
UINT32 processID; /**< Which belong process | 所属进程ID */
FutexNode futex; ///< 实现快锁功能
LOS_DL_LIST joinList; /**< join list \n */ //联结链表,允许任务之间相互释放彼此
LOS_DL_LIST lockList; /**< Hold the lock list \n 该链表上挂的都是已持有的锁 */
UINTPTR waitID; /**< Wait for the PID or GID of the child process \n */
LOS_DL_LIST joinList; /**< join list | 联结链表,允许任务之间相互释放彼此 */
LOS_DL_LIST lockList; /**< Hold the lock list | 该链表上挂的都是已持有的锁 */
UINTPTR waitID; /**< Wait for the PID or GID of the child process | */
UINT16 waitFlag; /**< The type of child process that is waiting, belonging to a group or parent,
a specific child process, or any child process \n 以什么样的方式等待子进程结束(OS_TASK_WAIT_PROCESS | OS_TASK_WAIT_GID | ..) */
a specific child process, or any child process | 以什么样的方式等待子进程结束(OS_TASK_WAIT_PROCESS | OS_TASK_WAIT_GID | ..) */
#ifdef LOSCFG_KERNEL_LITEIPC
IpcTaskInfo *ipcTaskInfo;
IpcTaskInfo *ipcTaskInfo; ///< 任务IPC信息结构体
#endif
#ifdef LOSCFG_KERNEL_PERF
UINTPTR pc;
UINTPTR fp;
UINTPTR pc; ///< pc寄存器
UINTPTR fp; ///< fp寄存器
#endif
} LosTaskCB;
//LosTask结构体是给外部使用的
......@@ -372,11 +372,11 @@ typedef struct {
} LosTask;
struct ProcessSignalInfo {//进程信号描述符
siginfo_t *sigInfo; /**< Signal to be dispatched \n 要发送的信号*/
LosTaskCB *defaultTcb; /**< Default TCB \n 默认task,默认接收信号的任务. */
LosTaskCB *unblockedTcb; /**< The signal unblock on this TCB \n 信号在此TCB上解除阻塞 */
LosTaskCB *awakenedTcb; /**< This TCB was awakened \n 即 任务在等待这个信号,此信号一来任务被唤醒.*/
LosTaskCB *receivedTcb; /**< This TCB received the signal \n 如果没有屏蔽信号,任务将接收这个信号. */
siginfo_t *sigInfo; /**< Signal to be dispatched | 要发送的信号*/
LosTaskCB *defaultTcb; /**< Default TCB | 默认task,默认接收信号的任务. */
LosTaskCB *unblockedTcb; /**< The signal unblock on this TCB | 信号在此TCB上解除阻塞 */
LosTaskCB *awakenedTcb; /**< This TCB was awakened | 即 任务在等待这个信号,此信号一来任务被唤醒.*/
LosTaskCB *receivedTcb; /**< This TCB received the signal | 如果没有屏蔽信号,任务将接收这个信号. */
};
typedef int (*ForEachTaskCB)(LosTaskCB *tcb, void *arg);//回调任务函数,例如:进程被kill 9 时,通知所有任务善后处理
......@@ -401,9 +401,9 @@ extern LosTaskCB *g_taskCBArray;///< 外部变量 任务池 默认128个
* Time slice structure.
*/
typedef struct {//时间片结构体,任务轮询
LosTaskCB *task; /**< Current running task \n 当前运行着的任务*/
UINT16 time; /**< Expiration time point \n 过期时间点*/
UINT16 timeout; /**< Expiration duration \n 有效期*/
LosTaskCB *task; /**< Current running task | 当前运行着的任务*/
UINT16 time; /**< Expiration time point | 过期时间点*/
UINT16 timeout; /**< Expiration duration | 有效期*/
} OsTaskRobin;
//获取当前CPU core运行的任务
STATIC INLINE LosTaskCB *OsCurrTaskGet(VOID)
......
......@@ -60,13 +60,15 @@
#define OS_SCHED_READY_MAX 30
#define OS_TIME_SLICE_MIN (INT32)((50 * OS_SYS_NS_PER_US) / OS_NS_PER_CYCLE) /* 50us */
typedef struct {//进程调度队列
LOS_DL_LIST priQueueList[OS_PRIORITY_QUEUE_NUM];//各优先级任务调度队列,默认32级
UINT32 readyTasks[OS_PRIORITY_QUEUE_NUM];//各优先级就绪任务个数
UINT32 queueBitmap;//任务优先级调度位图
/// 调度队列
typedef struct {
LOS_DL_LIST priQueueList[OS_PRIORITY_QUEUE_NUM];///< 各优先级任务调度队列,默认32级
UINT32 readyTasks[OS_PRIORITY_QUEUE_NUM]; ///< 各优先级就绪任务数
UINT32 queueBitmap; ///< 任务优先级调度位图
} SchedQueue;
typedef struct {//调度器
/// 调度器
typedef struct {
SchedQueue queueList[OS_PRIORITY_QUEUE_NUM];//进程优先级调度队列,默认32级
UINT32 queueBitmap;//进程优先级调度位图
SchedScan taskScan;//函数指针,扫描任务
......@@ -598,24 +600,26 @@ STATIC INLINE VOID OsSchedDeTaskQueue(LosTaskCB *taskCB, LosProcessCB *processCB
processCB->processStatus &= ~OS_PROCESS_STATUS_READY;
}
}
/// 将任务从就绪队列中删除
VOID OsSchedTaskDeQueue(LosTaskCB *taskCB)
{
LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID);
LosProcessCB *processCB = OS_PCB_FROM_PID(taskCB->processID);//通过任务获取所在进程
if (taskCB->taskStatus & OS_TASK_STATUS_READY) {
OsSchedDeTaskQueue(taskCB, processCB);
if (taskCB->taskStatus & OS_TASK_STATUS_READY) {//任务处于就绪状态
OsSchedDeTaskQueue(taskCB, processCB);//从该进程的就绪任务队列中删除
}
if (processCB->processStatus & OS_PROCESS_STATUS_READY) {
if (processCB->processStatus & OS_PROCESS_STATUS_READY) { //进程处于就绪状态不能删除任务,这是为什么呢 ? @note_thinking
return;
}
/* If the current process has only the current thread running,
* the process becomes blocked after the thread leaves the scheduling queue
* 如果当前进程只有当前任务在运行,任务离开调度队列后进程设置为阻塞状态
* 注意:一个进程下的任务可能同时被多个CPU在并行运行.
*/
if (OS_PROCESS_GET_RUNTASK_COUNT(processCB->processStatus) == 1) {
processCB->processStatus |= OS_PROCESS_STATUS_PENDING;
if (OS_PROCESS_GET_RUNTASK_COUNT(processCB->processStatus) == 1) { //根据数量来这只状态,注意 processStatus 承载了两重含义
processCB->processStatus |= OS_PROCESS_STATUS_PENDING; //将进程状态设为阻塞状态
}
}
......@@ -846,7 +850,7 @@ UINT32 OsSchedInit(VOID)
#endif
return LOS_OK;
}
///获取优先级最高的任务
/// 获取就绪队列中优先级最高的任务
STATIC LosTaskCB *OsGetTopTask(VOID)
{
UINT32 priority, processPriority;
......@@ -899,7 +903,7 @@ VOID OsSchedStart(VOID)
LosProcessCB *newProcess = OS_PCB_FROM_PID(newTask->processID);//获取该任务的进程实体
newTask->taskStatus |= OS_TASK_STATUS_RUNNING;//变成运行状态,注意此时该任务还没真正的运行
newProcess->processStatus |= OS_PROCESS_STATUS_RUNNING;
newProcess->processStatus |= OS_PROCESS_STATUS_RUNNING;//processStatus 具有两重含义,将它设为正在运行状态,但注意这是在进程的角度,实际上底层还没有切到它运行.
newProcess->processStatus = OS_PROCESS_RUNTASK_COUNT_ADD(newProcess->processStatus);//当前任务的数量也增加一个
OsSchedSetStartTime(HalClockGetCycles());//设置调度开始时间
......
......@@ -54,12 +54,12 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
#define INTERP_FULL_PATH "/lib/libc.so" //解析器路径
#define INVALID_FD (-1)//无效文件描述符,用于初始值.
#define STRINGS_COUNT_MAX 256 //argv[], envp[]最大数量
#define ELF_PHDR_NUM_MAX 128 //ELF最大段数量
#define FILE_LENGTH_MAX 0x1000000 //段占用的文件大小 最大1M
#define MEM_SIZE_MAX 0x1000000 //运行时占用进程空间内存大小最大1M
#define INTERP_FULL_PATH "/lib/libc.so" ///< 解析器路径
#define INVALID_FD (-1)///< 无效文件描述符,用于初始值.
#define STRINGS_COUNT_MAX 256 ///< argv[], envp[]最大数量
#define ELF_PHDR_NUM_MAX 128 ///< ELF最大段数量
#define FILE_LENGTH_MAX 0x1000000 ///< 段占用的文件大小 最大1M
#define MEM_SIZE_MAX 0x1000000 ///< 运行时占用进程空间内存大小最大1M
#ifndef FILE_PATH_MAX
#define FILE_PATH_MAX PATH_MAX
......@@ -68,9 +68,9 @@ extern "C" {
#define FILE_PATH_MIN 2
#endif
#define USER_STACK_SIZE 0x100000 //用户空间栈大小 1M
#define USER_PARAM_BYTE_MAX 0x1000 //4K
#define USER_STACK_TOP_MAX USER_ASPACE_TOP_MAX //用户空间栈顶位置
#define USER_STACK_SIZE 0x100000 ///< 用户空间栈大小 1M
#define USER_PARAM_BYTE_MAX 0x1000 ///< 4K
#define USER_STACK_TOP_MAX USER_ASPACE_TOP_MAX ///< 用户空间栈顶位置
#define EXEC_MMAP_BASE 0x02000000 //可执行文件分配基地址
......@@ -78,13 +78,13 @@ extern "C" {
#define RANDOM_MASK ((((USER_ASPACE_TOP_MAX + GB - 1) & (-GB)) >> 3) - 1)
#endif
#define STACK_ALIGN_SIZE 0x10 //栈对齐
#define STACK_ALIGN_SIZE 0x10 ///< 栈对齐
#define RANDOM_VECTOR_SIZE 1
/* The permissions on sections in the program header. */ //对段的操作权限
#define PF_R 0x4 //只读
#define PF_W 0x2 //只写
#define PF_X 0x1 //可执行
/* The permissions on sections in the program header. | 对段的操作权限*/
#define PF_R 0x4 ///< 只读
#define PF_W 0x2 ///< 只写
#define PF_X 0x1 ///< 可执行
/**@struct
* @brief ELF信息结构体
......@@ -102,28 +102,28 @@ typedef struct {
typedef struct {
ELFInfo execInfo; ///< 可执行文件信息
ELFInfo interpInfo;///< 解析器文件信息 lib/libc.so
const CHAR *fileName;///< 文件名称
CHAR *execName;///< 程序名称
INT32 argc; ///< 参数个数
INT32 envc; ///< 环境变量个数
CHAR *const *argv; ///< 参数数组
CHAR *const *envp; ///< 环境变量数组
UINTPTR stackTop;///< 栈底位置,递减满栈下,stackTop是高地址位
const CHAR *fileName; ///< 文件名称
CHAR *execName; ///< 程序名称
INT32 argc; ///< 参数个数
INT32 envc; ///< 环境变量个数
CHAR *const *argv; ///< 参数数组
CHAR *const *envp; ///< 环境变量数组
UINTPTR stackTop; ///< 栈底位置,递减满栈下,stackTop是高地址位
UINTPTR stackTopMax;///< 栈最大上限
UINTPTR stackBase;///< 栈顶位置
UINTPTR stackBase; ///< 栈顶位置
UINTPTR stackParamBase;///< 栈参数空间,放置启动ELF时的外部参数,大小为 USER_PARAM_BYTE_MAX 4K
UINT32 stackSize;///< 栈大小
INT32 stackProt;///< LD_PT_GNU_STACK栈的权限 ,例如(RW)
UINTPTR argStart;
UINT32 stackSize; ///< 栈大小
INT32 stackProt; ///< LD_PT_GNU_STACK栈的权限 ,例如(RW)
UINTPTR argStart; ///< 开始参数位置
UINTPTR loadAddr; ///< 加载地址
UINTPTR elfEntry; ///< 装载点地址 即: _start 函数地址
UINTPTR topOfMem; ///< 虚拟空间顶部位置,loadInfo->topOfMem = loadInfo->stackTopMax - sizeof(UINTPTR);
UINTPTR oldFiles; ///< 旧空间的文件映像
LosVmSpace *newSpace;///< 新虚拟空间
LosVmSpace *oldSpace;///< 旧虚拟空间
LosVmSpace *newSpace; ///< 新虚拟空间
LosVmSpace *oldSpace; ///< 旧虚拟空间
INT32 randomDevFD;
} ELFLoadInfo;
//不超过用户空间顶部位置
/// 不超过用户空间顶部位置
STATIC INLINE BOOL OsIsBadUserAddress(VADDR_T vaddr)
{
return (vaddr >= USER_STACK_TOP_MAX);
......
git add -A
git commit -m ' 同步官源,加入epoll支持,对shell模块有较大调整,微调process,task,更正单词拼写错误
git commit -m ' 因同步官源,代码覆盖,部分模块需重新注解
百万汉字注解 + 百篇博客分析 => 挖透鸿蒙内核源码
博客输出站点(国内):http://weharmonyos.com
博客输出站点(国外):https://weharmony.github.io
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册