提交 e3534707 编写于 作者: 鸿蒙内核源码分析'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)
上级 01fd6b85
......@@ -231,6 +231,7 @@
### 关注不迷路.代码即人生
<img src="https://gitee.com/weharmonyos/resources/raw/master/common/so1so.png" alt="图片替换文本" width="855px" height="312px" align="bottom" />
![](https://gitee.com/weharmonyos/resources/raw/master/common/so1so.png)
**QQ群 790015635 | 入群密码 666 | 存放重要文档资料**
......@@ -47,10 +47,27 @@ extern "C" {
#endif /* __cplusplus */
#endif /* __cplusplus */
/*!
* @brief 内存屏障(英语:Memory barrier),也称内存栅栏,内存栅障,屏障指令等,是一类同步屏障指令,
\n 它使得 CPU 或编译器在对内存进行操作的时候, 严格按照一定的顺序来执行, 也就是说在memory barrier 之前的指令
\n 和memory barrier之后的指令不会由于系统优化等原因而导致乱序。
\n 大多数现代计算机为了提高性能而采取乱序执行,这使得内存屏障成为必须。
\n 语义上,内存屏障之前的所有写操作都要写入内存;内存屏障之后的读操作都可以获得同步屏障之前的写操作的结果。
\n 因此,对于敏感的程序块,写操作之后、读操作之前可以插入内存屏障。
*
* @param index
* @return
*
* @see
*/
// https://community.arm.com/arm-community-blogs/b/architectures-and-processors-blog/posts/memory-access-ordering---an-introduction
/* ARM System Registers */
#define DSB __asm__ volatile("dsb" ::: "memory")
#define DMB __asm__ volatile("dmb" ::: "memory")
#define ISB __asm__ volatile("isb" ::: "memory")
#define DSB __asm__ volatile("dsb" ::: "memory") ///< Data Synchronization Barrier(DSB) 数据同步隔离。DSB 比 DMB 管得更宽, DSB 屏障之后的所有得指令不可越过屏障乱序执行
#define DMB __asm__ volatile("dmb" ::: "memory") ///< Data Memory Barrier(DMB) 数据存储器隔离。保证该指令前的所有内存访问结束,而该指令之后引起的内存访问只能在该指令执行结束后开始,其它数据处理指令等可以越过 DMB 屏障乱序执行
#define ISB __asm__ volatile("isb" ::: "memory") ///< Instruction Synchronization Barrier(ISB) 指令同步隔离。ISB 比 DSB 管的更宽, ISB 屏障之前的指令保证执行完,屏障之后的指令直接flush 掉再重新从 Memroy 中取指
#define WFI __asm__ volatile("wfi" ::: "memory")
#define BARRIER __asm__ volatile("":::"memory")
#define WFE __asm__ volatile("wfe" ::: "memory")
......@@ -225,7 +242,7 @@ STATIC INLINE UINT32 ArchIntLock(VOID)
: :"memory");
return intSave;
}
/// 打开当前处理器所有中断响应
STATIC INLINE UINT32 ArchIntUnlock(VOID)
{
UINT32 intSave;
......@@ -239,7 +256,7 @@ STATIC INLINE UINT32 ArchIntUnlock(VOID)
}
#endif
/// 恢复到使用LOS_IntLock关闭所有中断之前的状态
STATIC INLINE VOID ArchIntRestore(UINT32 intSave)
{
__asm__ __volatile__(
......@@ -250,7 +267,7 @@ STATIC INLINE VOID ArchIntRestore(UINT32 intSave)
}
#define PSR_I_BIT 0x00000080U
/// 关闭当前处理器所有中断响应
STATIC INLINE UINT32 OsIntLocked(VOID)
{
UINT32 intSave;
......
......@@ -4,13 +4,23 @@
* @link
* @verbatim
基本概念
中断是指出现需要时,CPU暂停执行当前程序,转而执行新程序的过程。即在程序运行过程中,
出现了一个必须由CPU立即处理的事务。此时,CPU暂时中止当前程序的执行转而处理这个事务,
这个过程就叫做中断。
外设可以在没有CPU介入的情况下完成一定的工作,但某些情况下也需要CPU为其执行一定的工作。
通过中断机制,在外设不需要CPU介入时,CPU可以执行其它任务,而当外设需要CPU时,将通过产生
中断信号使CPU立即中断当前任务来响应中断请求。这样可以使CPU避免把大量时间耗费在等待、
查询外设状态的操作上,大大提高系统实时性以及执行效率。
中断是指出现需要时,CPU暂停执行当前程序,转而执行新程序的过程。即在程序运行过程中,
出现了一个必须由CPU立即处理的事务。此时,CPU暂时中止当前程序的执行转而处理这个事务,
这个过程就叫做中断。通过中断机制,可以使CPU避免把大量时间耗费在等待、查询外设状态的操作上,
大大提高系统实时性以及执行效率。
异常处理是操作系统对运行期间发生的异常情况(芯片硬件异常)进行处理的一系列动作,
例如虚拟内存缺页异常、打印异常发生时函数的调用栈信息、CPU现场信息、任务的堆栈情况等。
外设可以在没有CPU介入的情况下完成一定的工作,但某些情况下也需要CPU为其执行一定的工作。
通过中断机制,在外设不需要CPU介入时,CPU可以执行其它任务,而当外设需要CPU时,产生一个中断信号,
该信号连接至中断控制器。中断控制器是一方面接收其它外设中断引脚的输入,另一方面它会发出中断信号给CPU。
可以通过对中断控制器编程来打开和关闭中断源、设置中断源的优先级和触发方式。
常用的中断控制器有VIC(Vector Interrupt Controller)和GIC(General Interrupt Controller)。
在ARM Cortex-A7中使用的中断控制器是GIC。CPU收到中断控制器发送的中断信号后,中断当前任务来响应中断请求。
异常处理就是可以打断CPU正常运行流程的一些事情,如未定义指令异常、试图修改只读的数据异常、不对齐的地址访问异常等。
当异常发生时,CPU暂停当前的程序,先处理异常事件,然后再继续执行被异常打断的程序。
中断特性:
中断共享,且可配置。
......@@ -82,8 +92,11 @@
中断处理程序耗时不能过长,否则会影响CPU对中断的及时响应。
中断响应过程中不能执行引起调度的函数。
中断恢复LOS_IntRestore()的入参必须是与之对应的LOS_IntLock()的返回值(即关中断之前的CPSR值)。
Cortex-M系列处理器中0-15中断为内部使用,Cortex-A7中0-31中断为内部使用,因此不建议用户去申请和创建。
Cortex-M系列处理器中0-15中断为内部使用,Cortex-A7中0-31中断为内部使用,因此不建议用户去申请和创建。
以ARMv7-a架构为例,中断和异常处理的入口为中断向量表,中断向量表包含各个中断和异常处理的入口函数。
* @endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/44/vector.png
* @version
* @author weharmonyos.com
* @date 2021-11-16
......@@ -166,7 +179,7 @@ CHAR *OsGetHwiFormName(UINT32 index)//获取某个中断的名称
{
return g_hwiFormName[index];
}
/// 获取系统支持的最大中断数
UINT32 LOS_GetSystemHwiMaximum(VOID)
{
return OS_HWI_MAX_NUM;
......
......@@ -250,22 +250,22 @@ typedef VOID (*HWI_PROC_FUNC)(VOID);
#define IRQF_SHARED 0x8000U //IRQF_SHARED-允许在多个设备之间共享irq
typedef struct tagHwiHandleForm {
HWI_PROC_FUNC pfnHook; //中断处理函数
HWI_ARG_T uwParam; //中断处理函数参数
struct tagHwiHandleForm *pstNext; //节点,指向下一个中断,用于共享中断的情况
HWI_PROC_FUNC pfnHook; ///< 中断处理函数
HWI_ARG_T uwParam; ///< 中断处理函数参数
struct tagHwiHandleForm *pstNext; ///< 节点,指向下一个中断,用于共享中断的情况
} HwiHandleForm;
typedef struct tagIrqParam { //中断参数
int swIrq; // 软件中断
VOID *pDevId; // 设备ID
const CHAR *pName; //名称
int swIrq; ///< 软件中断
VOID *pDevId; ///< 设备ID
const CHAR *pName; ///< 名称
} HwiIrqParam;
extern HwiHandleForm g_hwiForm[OS_HWI_MAX_NUM];//中断注册表
/**
* @ingroup los_hwi
* @brief Disable all interrupts.
* @brief Disable all interrupts. | 关闭当前处理器所有中断响应
*
* @par Description:
* <ul>
......@@ -282,7 +282,7 @@ extern HwiHandleForm g_hwiForm[OS_HWI_MAX_NUM];//中断注册表
* @par Dependency:
* <ul><li>los_hwi.h: the header file that contains the API declaration.</li></ul>
* @see LOS_IntRestore
*/ //关闭当前处理器所有中断响应
*/
STATIC INLINE UINT32 LOS_IntLock(VOID)
{//此API用于禁用CPSR中的所有IRQ和FIQ中断。CPSR:程序状态寄存器(current program status register)
return ArchIntLock();
......@@ -290,7 +290,7 @@ STATIC INLINE UINT32 LOS_IntLock(VOID)
/**
* @ingroup los_hwi
* @brief Enable all interrupts.
* @brief Enable all interrupts. | 打开当前处理器所有中断响应
*
* @par Description:
* <ul>
......@@ -307,7 +307,7 @@ STATIC INLINE UINT32 LOS_IntLock(VOID)
* @par Dependency:
* <ul><li>los_hwi.h: the header file that contains the API declaration.</li></ul>
* @see LOS_IntLock
*/ //打开当前处理器所有中断响应
*/
STATIC INLINE UINT32 LOS_IntUnLock(VOID)
{//此API用于启用CPSR中的所有IRQ和FIQ中断。
return ArchIntUnlock();
......@@ -315,7 +315,7 @@ STATIC INLINE UINT32 LOS_IntUnLock(VOID)
/**
* @ingroup los_hwi
* @brief Restore interrupts.
* @brief Restore interrupts. | 恢复到使用LOS_IntLock关闭所有中断之前的状态
*
* @par Description:
* <ul>
......@@ -333,7 +333,7 @@ STATIC INLINE UINT32 LOS_IntUnLock(VOID)
* @par Dependency:
* <ul><li>los_hwi.h: the header file that contains the API declaration.</li></ul>
* @see LOS_IntLock
*/ //恢复到使用LOS_IntLock关闭所有中断之前的状态
*/
STATIC INLINE VOID LOS_IntRestore(UINT32 intSave)
{//只有在禁用所有中断之后才能调用此API,并且输入参数值应为LOS_IntLock返回的值。
ArchIntRestore(intSave);
......
/*!
* @file los_memory.c
* @brief
* @link
@verbatim
基本概念
内存管理模块管理系统的内存资源,它是操作系统的核心模块之一,主要包括内存的初始化、分配以及释放。
OpenHarmony LiteOS-A的堆内存管理提供内存初始化、分配、释放等功能。在系统运行过程中,堆内存管理
模块通过对内存的申请/释放来管理用户和OS对内存的使用,使内存的利用率和使用效率达到最优,同时最大限度地解决系统的内存碎片问题。
运行机制
堆内存管理,即在内存资源充足的情况下,根据用户需求,从系统配置的一块比较大的连续内存
(内存池,也是堆内存)中分配任意大小的内存块。当用户不需要该内存块时,又可以释放回系统供下一次使用。
与静态内存相比,动态内存管理的优点是按需分配,缺点是内存池中容易出现碎片。
OpenHarmony LiteOS-A堆内存在TLSF算法的基础上,对区间的划分进行了优化,获得更优的性能,降低了碎片率。
动态内存核心算法框图如下:
@endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/11/1.png
* @image html https://gitee.com/weharmonyos/resources/raw/master/11/2.png
* @version
* @author weharmonyos.com
* @date 2021-11-19
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......@@ -852,7 +875,7 @@ STATIC UINT32 OsMemPoolDelete(VOID *pool)
return ret;
}
#endif
/// 初始化一块指定的动态内存池,大小为size
UINT32 LOS_MemInit(VOID *pool, UINT32 size)
{
if ((pool == NULL) || (size <= OS_MEM_MIN_POOL_SIZE)) {
......@@ -876,6 +899,7 @@ UINT32 LOS_MemInit(VOID *pool, UINT32 size)
}
#ifdef LOSCFG_MEM_MUL_POOL
/// 删除指定内存池
UINT32 LOS_MemDeInit(VOID *pool)
{
if (pool == NULL) {
......@@ -905,7 +929,7 @@ UINT32 LOS_MemPoolList(VOID)
return index;
}
#endif
/// 从指定动态内存池中申请size长度的内存
STATIC INLINE VOID *OsMemAlloc(struct OsMemPoolHead *pool, UINT32 size, UINT32 intSave)
{
struct OsMemNodeHead *allocNode = NULL;
......@@ -953,7 +977,7 @@ retry:
#endif
return OsMemCreateUsedNode((VOID *)allocNode);
}
/// 从指定动态内存池中申请size长度的内存
VOID *LOS_MemAlloc(VOID *pool, UINT32 size)
{
if ((pool == NULL) || (size == 0)) {
......@@ -980,7 +1004,7 @@ VOID *LOS_MemAlloc(VOID *pool, UINT32 size)
OsHookCall(LOS_HOOK_TYPE_MEM_ALLOC, pool, ptr, size);
return ptr;
}
/// 从指定动态内存池中申请长度为size且地址按boundary字节对齐的内存
VOID *LOS_MemAllocAlign(VOID *pool, UINT32 size, UINT32 boundary)
{
UINT32 gapSize;
......@@ -1179,7 +1203,7 @@ STATIC INLINE UINT32 OsMemFree(struct OsMemPoolHead *pool, struct OsMemNodeHead
return ret;
}
/// 释放从指定动态内存中申请的内存
UINT32 LOS_MemFree(VOID *pool, VOID *ptr)
{
if ((pool == NULL) || (ptr == NULL) || !OS_MEM_IS_ALIGNED(pool, sizeof(VOID *)) ||
......@@ -1306,7 +1330,7 @@ STATIC INLINE VOID *OsMemRealloc(struct OsMemPoolHead *pool, const VOID *ptr,
}
return tmpPtr;
}
/// 按size大小重新分配内存块,并将原内存块内容拷贝到新内存块。如果新内存块申请成功,则释放原内存块
VOID *LOS_MemRealloc(VOID *pool, VOID *ptr, UINT32 size)
{
if ((pool == NULL) || OS_MEM_NODE_GET_USED_FLAG(size) || OS_MEM_NODE_GET_ALIGNED_FLAG(size)) {
......
......@@ -130,10 +130,16 @@ ULONG_T OsRegionRbCmpKeyFn(const VOID *pNodeKeyA, const VOID *pNodeKeyB)
}
return RB_EQUAL;
}
/*!
初始化虚拟空间,必须提供L1表的虚拟内存地址
VADDR_T *virtTtb:L1表的地址,TTB表地址
*/
* @brief OsVmSpaceInitCommon 初始化虚拟空间,必须提供L1表的虚拟内存地址
*
* @param virtTtb L1表的地址,TTB表地址
* @param vmSpace
* @return
*
* @see
*/
STATIC BOOL OsVmSpaceInitCommon(LosVmSpace *vmSpace, VADDR_T *virtTtb)
{
LOS_RbInitTree(&vmSpace->regionRbTree, OsRegionRbCmpKeyFn, OsRegionRbFreeFn, OsRegionRbGetKeyFn);//初始化虚拟存储空间-以红黑树组织方式
......@@ -191,7 +197,16 @@ VOID OsKSpaceInit(VOID)
OsKernVmSpaceInit(&g_kVmSpace, OsGFirstTableGet());
OsVMallocSpaceInit(&g_vMallocSpace, OsGFirstTableGet());
}
BOOL OsUserVmSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)//用户空间的TTB表是动态申请得来,每个进程有属于自己的L1,L2表
/*!
* @brief OsUserVmSpaceInit 用户空间的TTB表是动态申请得来,每个进程有属于自己的L1,L2表
* 初始化用户进程虚拟空间,主要划分数据区,堆区,映射区和创建mmu
* @param virtTtb
* @param vmSpace
* @return
*
* @see
*/
BOOL OsUserVmSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)
{
vmSpace->base = USER_ASPACE_BASE;//用户空间基地址
vmSpace->size = USER_ASPACE_SIZE;//用户空间大小
......@@ -206,24 +221,24 @@ BOOL OsUserVmSpaceInit(LosVmSpace *vmSpace, VADDR_T *virtTtb)//用户空间的TT
#endif
return OsVmSpaceInitCommon(vmSpace, virtTtb);
}
///创建用户进程空间
/// 创建用户进程空间
LosVmSpace *OsCreateUserVmSpace(VOID)
{
BOOL retVal = FALSE;
LosVmSpace *space = LOS_MemAlloc(m_aucSysMem0, sizeof(LosVmSpace));
LosVmSpace *space = LOS_MemAlloc(m_aucSysMem0, sizeof(LosVmSpace));//在内核空间申请用户进程空间
if (space == NULL) {
return NULL;
}
VADDR_T *ttb = LOS_PhysPagesAllocContiguous(1);
if (ttb == NULL) {
VADDR_T *ttb = LOS_PhysPagesAllocContiguous(1);//分配一个物理页用于存放虚实内存映射关系, 即:L1表
if (ttb == NULL) {//若连映射页都没有,剩下的也别玩了.
(VOID)LOS_MemFree(m_aucSysMem0, space);
return NULL;
}
(VOID)memset_s(ttb, PAGE_SIZE, 0, PAGE_SIZE);
retVal = OsUserVmSpaceInit(space, ttb);
retVal = OsUserVmSpaceInit(space, ttb);//初始化用户空间,mmu
LosVmPage *vmPage = OsVmVaddrToPage(ttb);
if ((retVal == FALSE) || (vmPage == NULL)) {
(VOID)LOS_MemFree(m_aucSysMem0, space);
......@@ -268,9 +283,9 @@ STATUS_T LOS_VmSpaceClone(LosVmSpace *oldVmSpace, LosVmSpace *newVmSpace)
}
//空间克隆的主体实现是:线性区重新一个个分配物理内存,重新映射.
/* search the region list */
newVmSpace->mapBase = oldVmSpace->mapBase;
newVmSpace->heapBase = oldVmSpace->heapBase;
newVmSpace->heapNow = oldVmSpace->heapNow;
newVmSpace->mapBase = oldVmSpace->mapBase; //复制映射区基址
newVmSpace->heapBase = oldVmSpace->heapBase; //复制堆区基址
newVmSpace->heapNow = oldVmSpace->heapNow; //复制堆区当前使用到哪了
(VOID)LOS_MuxAcquire(&oldVmSpace->regionMux);
RB_SCAN_SAFE(&oldVmSpace->regionRbTree, pstRbNode, pstRbNodeNext)//红黑树循环开始
oldRegion = (LosVmMapRegion *)pstRbNode;
......@@ -339,18 +354,18 @@ LosVmMapRegion *OsFindRegion(LosRbTree *regionRbTree, VADDR_T vaddr, size_t len)
}
return regionRst;
}
/// 查找线性区
LosVmMapRegion *LOS_RegionFind(LosVmSpace *vmSpace, VADDR_T addr)
{
LosVmMapRegion *region = NULL;
(VOID)LOS_MuxAcquire(&vmSpace->regionMux);
(VOID)LOS_MuxAcquire(&vmSpace->regionMux);//因进程空间是隔离的,所以此处只会涉及到任务(线程)之间的竞争,故使用互斥锁,而自旋锁则用于CPU核间的竞争
region = OsFindRegion(&vmSpace->regionRbTree, addr, 1);
(VOID)LOS_MuxRelease(&vmSpace->regionMux);
return region;
}
/// 查找线性区范围
LosVmMapRegion *LOS_RegionRangeFind(LosVmSpace *vmSpace, VADDR_T addr, size_t len)
{
LosVmMapRegion *region = NULL;
......@@ -361,7 +376,7 @@ LosVmMapRegion *LOS_RegionRangeFind(LosVmSpace *vmSpace, VADDR_T addr, size_t le
return region;
}
/// 分配线性区
VADDR_T OsAllocRange(LosVmSpace *vmSpace, size_t len)
{
LosVmMapRegion *curRegion = NULL;
......
/*!
* @file los_exec_elf.c
* @brief
* @link
@verbatim
基本概念
OpenHarmony系统的动态加载与链接机制主要是由内核加载器以及动态链接器构成,内核加载器用于加载应用程序以及动态链接器,
动态链接器用于加载应用程序所依赖的共享库,并对应用程序和共享库进行符号重定位。与静态链接相比,动态链接是将应用程序
与动态库推迟到运行时再进行链接的一种机制。
动态链接的优势
1. 多个应用程序可以共享一份代码,最小加载单元为页,相对静态链接可以节约磁盘和内存空间。
2. 共享库升级时,理论上将旧版本的共享库覆盖即可(共享库中的接口向下兼容),无需重新链接。
3. 加载地址可以进行随机化处理,防止攻击,保证安全性。
运行机制
@endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/51/1.png
@verbatim
1. 内核将应用程序ELF文件的PT_LOAD段信息映射至进程空间。对于ET_EXEC类型的文件,根据PT_LOAD段中p_vaddr进行固定地址映射;
对于ET_DYN类型(位置无关的可执行程序,通过编译选项“-fPIE”得到)的文件,内核通过mmap接口选择base基址进行映射(load_addr = base + p_vaddr)。
2. 若应用程序是静态链接的(静态链接不支持编译选项“-fPIE”),设置堆栈信息后跳转至应用程序ELF文件中e_entry指定的地址并运行;
若程序是动态链接的,应用程序ELF文件中会有PT_INTERP段,保存动态链接器的路径信息(ET_DYN类型)。musl的动态链接器是libc-musl.so的一部分,
libc-musl.so的入口即动态链接器的入口。内核通过mmap接口选择base基址进行映射,设置堆栈信息后跳转至base + e_entry(该e_entry为动态链接器的入口)
地址并运行动态链接器。
3. 动态链接器自举并查找应用程序依赖的所有共享库并对导入符号进行重定位,最后跳转至应用程序的e_entry(或base + e_entry),开始运行应用程序。
@endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/51/2.png
@verbatim
1. 加载器与链接器调用mmap映射PT_LOAD段;
2. 内核调用map_pages接口查找并映射pagecache已有的缓存;
3. 程序执行时,内存若无所需代码或数据时触发缺页中断,将elf文件内容读入内存,并将该内存块加入pagecache;
4. 将已读入文件内容的内存块与虚拟地址区间做映射;
5. 程序继续执行;
至此,程序将在不断地缺页中断中执行。
@endverbatim
* @version
* @author weharmonyos.com
* @date 2021-11-19
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......@@ -113,7 +151,17 @@ STATIC INT32 OsCopyUserParam(ELFLoadInfo *loadInfo, const CHAR *fileName, CHAR *
loadInfo->fileName = kfileName;//文件名指向内核空间
return LOS_OK;
}
////运行用户态进程 ELF格式,运行在内核态
/*!
* @brief LOS_DoExecveFile
* 根据fileName执行一个新的用户程序 LOS_DoExecveFile接口一般由用户通过execve系列接口利用系统调用机制调用创建新的进程,内核不能直接调用该接口启动新进程。
* @param argv 程序执行所需的参数序列,以NULL结尾。无需参数时填入NULL。
* @param envp 程序执行所需的新的环境变量序列,以NULL结尾。无需新的环境变量时填入NULL。
* @param fileName 二进制可执行文件名,可以是路径名。
* @return
*
* @see
*/
INT32 LOS_DoExecveFile(const CHAR *fileName, CHAR * const *argv, CHAR * const *envp)
{
ELFLoadInfo loadInfo = { 0 };
......@@ -122,18 +170,18 @@ INT32 LOS_DoExecveFile(const CHAR *fileName, CHAR * const *argv, CHAR * const *e
#ifdef LOSCFG_SHELL
CHAR buf[PATH_MAX + 1] = { 0 };
#endif
//先判断参数地址是否来自用户空间
//先判断参数地址是否来自用户空间,此处必须要来自用户空间,内核是不能直接调用本函数
if ((fileName == NULL) || ((argv != NULL) && !LOS_IsUserAddress((VADDR_T)(UINTPTR)argv)) ||
((envp != NULL) && !LOS_IsUserAddress((VADDR_T)(UINTPTR)envp))) {
return -EINVAL;
}
ret = OsCopyUserParam(&loadInfo, fileName, kfileName, PATH_MAX);//确保拷贝至内核空间
ret = OsCopyUserParam(&loadInfo, fileName, kfileName, PATH_MAX);//拷贝用户空间数据至内核空间
if (ret != LOS_OK) {
return ret;
}
#ifdef LOSCFG_SHELL
if (OsGetRealPath(kfileName, buf, (PATH_MAX + 1)) != LOS_OK) {
if (OsGetRealPath(kfileName, buf, (PATH_MAX + 1)) != LOS_OK) {//获取绝对路径
return -ENOENT;
}
if (buf[0] != '\0') {
......@@ -141,7 +189,7 @@ INT32 LOS_DoExecveFile(const CHAR *fileName, CHAR * const *argv, CHAR * const *e
}
#endif
loadInfo.newSpace = OsCreateUserVmSpace();
loadInfo.newSpace = OsCreateUserVmSpace();//创建一个用户空间,用于开启新的进程
if (loadInfo.newSpace == NULL) {
PRINT_ERR("%s %d, failed to allocate new vm space\n", __FUNCTION__, __LINE__);
return -ENOMEM;
......
/*!
* @file los_syscall.c
* @brief
* @link kernel-small-bundles-system http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/kernel-small-bundles-system.html @endlink
@verbatim
OpenHarmony LiteOS-A实现了用户态与内核态的区分隔离,用户态程序不能直接访问内核资源,
而系统调用则为用户态程序提供了一种访问内核资源、与内核进行交互的通道。
新增系统调用的典型开发流程如下:
1. 在LibC库中确定并添加新增的系统调用号。
2. 在LibC库中新增用户态的函数接口声明及实现。
3. 在内核系统调用头文件中确定并添加新增的系统调用号及对应内核处理函数的声明。
4. 在内核中新增该系统调用对应的内核处理函数。
如图所示,用户程序通过调用System API(系统API,通常是系统提供的POSIX接口)进行内核资源访问与交互请求,POSIX接口内部会触发SVC/SWI异常,
完成系统从用户态到内核态的切换,然后对接到内核的Syscall Handler(系统调用统一处理接口)进行参数解析,最终分发至具体的内核处理函数。
@endverbatim
* @image html https://gitee.com/weharmonyos/resources/raw/master/37/sys_call.png
* @attention 系统调用提供基础的用户态程序与内核的交互功能,不建议开发者直接使用系统调用接口,推荐使用内核提供的对外POSIX接口,
若需要新增系统调用接口,详见开发指导。内核向用户态提供的系统调用接口清单详见kernel/liteos_a/syscall/syscall_lookup.h,
内核相应的系统调用对接函数清单详见kernel/liteos_a/syscall/los_syscall.h。
* @version
* @author weharmonyos.com
* @date 2021-11-19
*/
/*
* Copyright (c) 2013-2019 Huawei Technologies Co., Ltd. All rights reserved.
* Copyright (c) 2020-2021 Huawei Device Co., Ltd. All rights reserved.
......
git add -A
git commit -m ' 注解钩子函数的宏实现
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.
先完成此消息的编辑!
想要评论请 注册