流程图地址:?https://gitee.com/lwleen/liteos
水平有限, 仅供参考? ? 一定要以实际的开源代码为准.
系统调用(软中断?SVC管理模式)
概述:将runtask寄存器完整的保存下来 系统调用处理 跳转到信号处理函数
示例: sys_call3(__NR_execve, "/bin/init", 0, 0) -------引发一个SVC异常
传入参数----- R7中是调用号__NR_execve R0 R1 R2 R3是参数
_osExceptSwiHdl: @此函数是内核函数, SVC管理模式异常,使用内核堆栈---SVC堆栈
SRSFD #CPSR_SVC_MODE! @ CPSR_SVC_MODE = 0x13 保存 CPSR PC 入SVC的堆栈
STMFD SP!, {R0-R3, R12, LR} @将R0-R3 R12和 LR 入栈
STMFD SP, {R13, R14}^ @入栈用户应用的R13 R14(ULR USP)
SUB SP, SP, #(4 * 4) @修改位置,SP指向 -> reserved2
STR R7, [SP, #0] @将R7中调用号保存到reserved2
@--------- TaskContext 结构体填充一半了----------------------
#ifdef LOSCFG_KERNEL_SYSCALL
LDR R3, [SP, #(11 * 4)] @赋值R3 = regCPSR值
AND R1, R3, #CPSR_MASK_MODE @R3与后,值存到R1
CMP R1, #CPSR_USER_MODE
BNE _osKernelSVCHandler @(ARM处于特权模式)跳转 sp->reserved2
@判断 此时 ARM 处于USER用户模式
CMP R7, #119 @ 119 == 系统调用号 __NR_sigreturn
BNE _osIsSyscall @R7中的调用号 != 119 sp->reserved2
MOV R0, SP
@-------传参数 R0 = SP sp->reserved2
BLX OsRestorSignalContext @@@@@
@-------返回参数 R0 = OsCurrTaskGet()->sig.sigContext
MOV SP, R0 @堆栈 SP -> sig.sigContext
B _osSyscallReturn
_osIsSyscall: @R7中的调用号不是119 sp->reserved2
STMFD SP!, {R4-R11} @入栈R4-R11
PUSH_FPU_REGS R1 @保存浮点寄存器FPU
@--------- TaskContext 结构体填充完成----------------------
MOV R0, SP @R0指向结构体TaskContext地址
MOV FP, #0
CPSIE I @开中断
@--------传参R0指向结构体TaskContext地址
BLX OsArmA32SyscallHandle @系统调用入口
@--------传参R0里保存有系统调用返回值
CPSID I @关中断
POP_FPU_REGS R1 @弹出浮点寄存器
LDMFD SP!, {R4-R11} @出栈恢复R4-R11寄存器
MOV R0, SP @赋值R0 = SP ->reserved2
SUB SP, SP, #(12 * 4) @栈顶增加空间sizeof(TaskContext)/2
MOV R1, SP @ R1 = new SP
@----传参 R0 =SP ->reserved2 R1 =new SP ------------
BLX OsSaveSignalContext @@@@@
@-------返回参数 R0 = new SP 里面PC = sigHandler 信号处理函数
MOV SP, R0 @堆栈 SP -> new SP
_osSyscallReturn: @系统调用结束,下面是堆栈 SP -> new SP 的情况
LDR R7, [SP, #0] @赋值R7 = [SP->reserved2]里调用号
ADD SP, SP, #(2 * 4) @SP + 2
LDMFD SP, {R13, R14}^ @恢复用户的 R13 R14(USP ULR)
ADD SP, SP, #(2 * 4) @SP + 2
LDMFD SP!, {R0-R3, R12, LR} @恢复 R0-R3 R12 LR
RFEIA SP! @弹出恢复PC CPSR 返回运行的是信号处理函数sigHandle
@信号处理完成后 再次发起系统调用 __NR_sigreturn
@这个系统调用__NR_sigreturn会恢复原应用运行
_osKernelSVCHandler:
#endif @ARM处于特权模式 sp->reserved2
MOV R0, #0 @ R0 = 0
STR R0, [SP, #0] @ sp->reserved2 赋值 0
STR R0, [SP, #4] @ sp->reserved1 赋值 0
STMFD SP!, {R4-R11} @入栈保存R4-R11
MOV R0, #OS_EXCEPT_SWI @ R0 放入参数 OS_EXCEPT_SWI
@传参数 R0 = OS_EXCEPT_SWI
B _osExceptDispatch @程序跳转
@调用 OsExcHandleEntry() 异常模式处理 打印系统信息
系统信号相关函数
信号处理函数 在当前进程中 UINTPTR sigHandler = OsCurrProcessGet()->sigHandler()
信号控制块 在当前线程中 sig_cb *sigcb = OsCurrTaskGet()->sig
@-----传入参数 sp->reserved2
//这个函数由系统调用为__NR_sigreturn 时执行一次
VOID *OsRestorSignalContext(VOID *sp){ @@@@@
如果 sigcb->count == 1 否则就错误
sigcb->count = 0
process->sigShare = 0
return sigcb->sigContext
//用R0返回参数 = OsCurrTaskGet()->sig.sigContext
}
@----传入参数 R0 =SP ->reserved2 R1 =new SP
VOID *OsSaveSignalContext(VOID *sp, VOID *newSp){ @@@@@
如果 sigcb->count == 0 否则退出
sigcb->sigContext = sp //保存 SP
OsInitSignalContext(){
复制 SP内容 到 new SP
如图所示
}
sigcb->count++
//用R0返回参数 = new SP
}
通用中断(IRQ 切换到?SVC)
概述: 调用中断处理函数 处理任务停止信号 处理核间调度
示例: 核间中断
OsIrqHandler: @此函数由中断异常模式执行
SUB LR, LR, #4 @记录译码指令地址,以防切换过程丢失指令
SRSFD #0x13! @保存 CPSR PC 入SVC的堆栈
CPSID i, #0x13 @关中断 切换到SVC 模式
STMFD SP!, {R0-R3, R12, LR} @将R0-R3 R12和 LR 入栈
STMFD SP, {R13, R14}^ @入栈用户应用的R13 R14(ULR USP)
SUB SP, SP, #(4 * 4) @修改位置,SP指向 ->reserved2
STR R4, [SP, #0] @R4中的值保存到reserved2
@---- IrqContext 结构体填充完成--保存runtask的寄存器-------
PUSH_FPU_REGS R0 @保存浮点寄存器
MOV R4, SP @保存SP->IrqContex 指针到R4
@下条指令处理多核CPU
EXC_SP_SET __svc_stack_top,OS_EXC_SVC_STACK_SIZE,R1,R2
BLX HalIrqHandler @通用中断处理入口
MOV SP, R4 @从R4恢复 SP->IrqContex 指针
BLX OsTaskProcSignal
BLX OsSchedIrqEndCheckNeedSched
POP_FPU_REGS R0 @恢复浮点寄存器
LDR R4, [SP, #0] @赋值R4=[SP->reserved2]里的值
#ifdef LOSCFG_KERNEL_VM
LDR R3, [SP, #(11 * 4)] @赋值R3 = regCPSR里的值
AND R1, R3, #CPSR_MASK_MODE
CMP R1, #CPSR_USER_MODE @判断是否是用户模式
BNE 1f @特权模式跳转 堆栈sp->reserved2
@判断 这里 (ARM处于用户模式)
MOV R0, SP @赋值 R0 = SP 指针
STR R7, [SP, #0] @将 R7 里的值保存到 [SP->reserved2]
SUB SP, SP, #(12 * 4) @栈顶增加空间 sizeof(IrqContext)
MOV R1, SP
@----传入参数 R0 =SP ->reserved2 R1 =new SP
BLX OsSaveSignalContext @@@@
@-------返回参数 R0 = new SP 里面PC = sigHandler 信号处理函数
MOV SP, R0 @堆栈 SP -> new SP
1:
#endif @下面是 堆栈 SP -> new SP 的情况
ADD SP, SP, #(2 * 4) @ SP +2
LDMFD SP, {R13, R14}^ @恢复用户的 R13 R14(USP ULR)
ADD SP, SP, #(2 * 4) @ SP +2
LDMFD SP!, {R0-R3, R12, LR} @恢复 R0-R3 R12 LR
RFEIA SP! @弹出恢复PC CPSR 返回运行的是信号处理函数sigHandle
@信号处理完成后 再次发起系统调用 __NR_sigreturn
@这个系统调用__NR_sigreturn会恢复原应用运行
滴答中断(IRQ)----核间中断-----调度----相关函数
触发调度过程:
滴答中断处理函数OsTickHandler , 检查 OsPercpuGet()->taskSortLink 如果有到时的任务到时, 调用
LOS_MpSchedule(OS_MP_CPU_ALL){
HalIrqSendIpi(target, LOS_MP_IPI_SCHEDULE){
写gic控制器的 GICD_SGIR 寄存器
触发核间中断 LOS_MP_IPI_SCHEDULE = 1 为中断号
}
}
----------------------------------
核间中断处理过程
----------------------------------
进入中断异常总入口 OsIrqHandler:
1 HalIrqHandler查询向量表g_hwiForm[]找到LOS_MP_IPI_SCHEDULE的处理函数, 调用
VOID OsMpScheduleHandler(VOID){
OsPercpuGet()->schedFlag = INT_PEND_RESCH; //CPU私有变量调度标志
}
2 调用
VOID OsTaskProcSignal(VOID){
LosTaskCB *runTask = OsCurrTaskGet();
检查 runTask->signal 标志
SIGNAL_KILL 结束当前运行任务
SIGNAL_SUSPEND 要求任务挂起停止
SIGNAL_AFFI 更换CPU 亲和度
}
3 调用 (处理核间调度)
VOID OsSchedIrqEndCheckNeedSched(VOID){
处理当前任务的时间片 LosTaskCB *runTask = OsCurrTaskGet()
如果 OsPercpuGet()->schedFlag == INT_PEND_RESCH
将runTask 加入调度器里的就绪链表
查找最高优先级任务 LosTaskCB *newTask = OsGetTopTask()
如果 runTask != newTask
OsSchedTaskSwicth(){
OsTaskSchedule(newTask,runTask) 汇编代码:切换任务上下文
}
}
调度---切换任务堆栈
概述: 将runtask的寄存器其压入堆栈. 弹出恢复newtask堆栈值后运行
LosTaskCB 结构体定义时, 第一个成员就是堆栈指针 VOID *stackPointer
传入参数为LosTaskCB ---- R0 = newtask R1 = runtask 每个寄存器值4字节
OsTaskSchedule:
MRS R2, CPSR @将CPSR内容存入 R2
STMFD SP!, {R2} @将CPSR压入 run task 的栈堆
STMFD SP!, {LR} @将LR压入
STMFD SP!, {LR} @将LR压入
STMFD SP!, {R12} @将R12压入
SUB SP, SP, #(8 * 4) @栈顶增加8个寄存器空间 SP -8
STMFD SP!, {R4-R11} @将R4-R11入栈
PUSH_FPU_REGS R2 @入栈fpu寄存器
@---- TaskContext 结构体填充完成--保存runtask的寄存器-------------------
STR SP, [R1] @保存堆栈指针 SP 到 runtask ->stackPointer
OsTaskContextLoad: @切换到新任务 下面开始加载新SP 并弹出内容
CLREX @清除ldrex指令的标记
LDR SP, [R0] @加载堆栈 SP = new task ->stackPointer
POP_FPU_REGS R2 @恢复 new task 的fpu浮点寄存器
LDMFD SP!, {R4-R11} @恢复 new task 的R4 - R11
LDR R3, [SP, #(11 * 4)] @赋值R3 = new task堆栈中的CPSR
AND R0, R3, #CPSR_MASK_MODE
CMP R0, #CPSR_USER_MODE
BNE OsKernelTaskLoad @判断new task为内核任务 此时SP->reserved2
@判断 新任务newtask 是用户模式(ARM处于USER模式)
@下面为 new task 为新任务 此时SP->reserved2
MVN R2, #CPSR_INT_DISABLE @取反后放入R2
@此时R3 = new task堆栈中的CPSR
AND R3, R3, R2 @R3中为CPSR ,与操作后放入R3
STR R3, [SP, #(11 * 4)] @处理后的CPSR值重新保存到 new task 堆栈
#ifdef LOSCFG_KERNEL_SMP
BL OsSchedToUserReleaseLock @调用C函数
#endif @此时SP->reserved2
ADD SP, SP, #(2 * 4) @SP跳过 reserved 这两个寄存器
LDMFD SP, {R13, R14}^ @恢复USP ULR但SP指针未改变(带!才会改变指针)
ADD SP, SP, #(2 * 4) @SP跳过 R13 R14 (USP ULR)这两个寄存器
LDMFD SP!, {R0-R3, R12, LR} @弹出恢复 R0-R3 R12 LR
RFEIA SP! @弹出恢复PC CPSR 即返回运行(new task)
@ 上面 new task 所有寄存器已从新堆栈中弹出恢复
OsKernelTaskLoad: @判断 new task 为内核任务(ARM处于特权模式)此时SP->reserved2
ADD SP, SP, #(4 * 4) @跳过堆栈顶4个寄存器
LDMFD SP!, {R0-R3, R12, LR} @恢复 R0-R3 R12 LR
RFEIA SP! @弹出恢复PC CPSR 即返回运行(new task)
流程图内容
?
|