更新日期: 2022/06/01 来源: https://gitee.com/weharmony/kernel_liteos_a_note
los_exc.c 文件参考

异常接管主文件 更多...

浏览源代码.

函数

VOID OsExcHook (UINT32 excType, ExcContext *excBufAddr, UINT32 far, UINT32 fsr)
 由注册后回调,发送异常情况下会回调这里执行,见于 OsUndefIncExcHandleEntry, OsExcHandleEntry ==函数 更多...
 
STATIC SPIN_LOCK_INIT (g_excSerializerSpin)
 
UINT32 OsGetSystemStatus (VOID)
 获取系统状态 更多...
 
STATIC INT32 OsDecodeFS (UINT32 bitsFS)
 
STATIC INT32 OsDecodeInstructionFSR (UINT32 regIFSR)
 
STATIC INT32 OsDecodeDataFSR (UINT32 regDFSR)
 
UINT32 OsArmSharedPageFault (UINT32 excType, ExcContext *frame, UINT32 far, UINT32 fsr)
 共享页缺失异常 更多...
 
STATIC VOID OsExcType (UINT32 excType, ExcContext *excBufAddr, UINT32 far, UINT32 fsr)
 异常类型 更多...
 
STATIC VADDR_T OsGetTextRegionBase (LosVmMapRegion *region, LosProcessCB *runProcess)
 
STATIC VOID OsExcSysInfo (UINT32 excType, const ExcContext *excBufAddr)
 打印异常系统信息 更多...
 
STATIC VOID OsExcRegsInfo (const ExcContext *excBufAddr)
 异常情况下打印各寄存器的信息 更多...
 
LITE_OS_SEC_TEXT_INIT UINT32 LOS_ExcRegHook (EXC_PROC_FUNC excHook)
 注册异常处理钩子 更多...
 
EXC_PROC_FUNC OsExcRegHookGet (VOID)
 获取hook函数 更多...
 
STATIC VOID OsDumpExcVaddrRegion (LosVmSpace *space, LosVmMapRegion *region)
 dump 虚拟空间下异常虚拟地址线性区 更多...
 
STATIC VOID OsDumpProcessUsedMemRegion (LosProcessCB *runProcess, LosVmSpace *runspace, UINT16 vmmFlags)
 dump 进程使用的内存线性区 更多...
 
STATIC VOID OsDumpProcessUsedMemNode (UINT16 vmmFlags)
 dump 进程使用的内存节点 更多...
 
VOID OsDumpContextMem (const ExcContext *excBufAddr)
 dump 上下文内存,注意内核异常不能简单的映射理解为应用的异常,异常对内核来说是一个很常见操作,
比如任务的切换对内核来说就是一个异常处理 更多...
 
STATIC VOID OsExcRestore (VOID)
 异常恢复,继续执行 更多...
 
STATIC VOID OsUserExcHandle (ExcContext *excBufAddr)
 用户态异常处理函数 更多...
 
STATIC INLINE BOOL IsValidFP (UINTPTR regFP, UINTPTR start, UINTPTR end, vaddr_t *vaddr)
 此函数用于验证fp或验证检查开始和结束范围 更多...
 
STATIC INLINE BOOL FindSuitableStack (UINTPTR regFP, UINTPTR *start, UINTPTR *end, vaddr_t *vaddr)
 找到一个合适的栈 更多...
 
BOOL OsGetUsrIpInfo (UINTPTR ip, IpInfo *info)
 
UINT32 BackTraceGet (UINTPTR regFP, IpInfo *callChain, UINT32 maxDepth)
 
VOID BackTraceSub (UINTPTR regFP)
 
VOID BackTrace (UINT32 regFP)
 打印调用栈信息 更多...
 
VOID OsExcInit (VOID)
 异常接管模块的初始化 更多...
 
VOID OsCallStackInfo (VOID)
 打印调用栈信息 更多...
 
VOID OsTaskBackTrace (UINT32 taskID)
 Kernel task backtrace function. 更多...
 
VOID OsBackTrace (VOID)
 Kernel backtrace function. 更多...
 
VOID OsUndefIncExcHandleEntry (ExcContext *excBufAddr)
 未定义的异常处理函数,由汇编调用 见于 los_hw_exc.s 更多...
 
VOID OsPrefetchAbortExcHandleEntry (ExcContext *excBufAddr)
 预取指令异常处理函数,由汇编调用 见于 los_hw_exc.s 更多...
 
VOID OsDataAbortExcHandleEntry (ExcContext *excBufAddr)
 数据中止异常处理函数,由汇编调用 见于 los_hw_exc.s 更多...
 
STATIC VOID WaitAllCpuStop (UINT32 cpuid)
 等待所有CPU停止 更多...
 
STATIC VOID OsWaitOtherCoresHandleExcEnd (UINT32 currCpuid)
 
STATIC VOID OsCheckAllCpuStatus (VOID)
 检查所有CPU的状态 更多...
 
STATIC VOID OsCheckCpuStatus (VOID)
 
LITE_OS_SEC_TEXT VOID STATIC OsExcPriorDisposal (ExcContext *excBufAddr)
 执行期间的优先处理 excBufAddr为CPU异常上下文, 更多...
 
LITE_OS_SEC_TEXT_INIT STATIC VOID OsPrintExcHead (UINT32 far)
 异常信息头部打印 更多...
 
STATIC VOID OsSysStateSave (UINT32 *intCount, UINT32 *lockCount)
 
STATIC VOID OsSysStateRestore (UINT32 intCount, UINT32 lockCount)
 
LITE_OS_SEC_TEXT_INIT VOID OsExcHandleEntry (UINT32 excType, ExcContext *excBufAddr, UINT32 far, UINT32 fsr)
 
 __attribute__ ((noinline))
 可变参数,输出到控制台 更多...
 
VOID __stack_chk_fail (VOID)
 
VOID LOS_RecordLR (UINTPTR *LR, UINT32 LRSize, UINT32 recordCount, UINT32 jumpCount)
 record LR function. 更多...
 

变量

STATIC UINTPTR g_minAddr
 
STATIC UINTPTR g_maxAddr
 
STATIC UINT32 g_currHandleExcCpuid = INVALID_CPUID
 
UINT32 g_curNestCount [LOSCFG_KERNEL_CORE_NUM] = {0}
 记录当前嵌套异常的数量 更多...
 
BOOL g_excFromUserMode [LOSCFG_KERNEL_CORE_NUM]
 记录CPU core 异常来自用户态还是内核态 TRUE为用户态,默认为内核态 更多...
 
STATIC EXC_PROC_FUNC g_excHook = (EXC_PROC_FUNC)OsExcHook
 全局异常处理钩子 更多...
 
STATIC UINT32 g_currHandleExcPID = OS_INVALID_VALUE
 
STATIC UINT32 g_nextExcWaitCpu = INVALID_CPUID
 
STATIC const StackInfo g_excStack []
 
STATIC const CHARg_excTypeString []
 
USED UINT32 __stack_chk_guard = 0xd00a0dff
 

详细描述

异常接管主文件

基本概念 
    异常接管是操作系统对运行期间发生的异常情况(芯片硬件异常)进行处理的一系列动作,
    例如打印异常发生时当前函数的调用栈信息、CPU现场信息、任务的堆栈情况等。

    异常接管作为一种调测手段,可以在系统发生异常时给用户提供有用的异常信息,譬如异常类型、
    发生异常时的系统状态等,方便用户定位分析问题。

    异常接管,在系统发生异常时的处理动作为:显示异常发生时正在运行的任务信息 
    (包括任务名、任务号、堆栈大小等),以及CPU现场等信息。 

运作机制 
    每个函数都有自己的栈空间,称为栈帧。调用函数时,会创建子函数的栈帧, 
    同时将函数入参、局部变量、寄存器入栈。栈帧从高地址向低地址生长。 
    
    以ARM32 CPU架构为例,每个栈帧中都会保存PC、LR、SP和FP寄存器的历史值。 
    ARM处理器中的R13被用作SP 

堆栈分析 
    LR寄存器(Link Register),链接寄存器,指向函数的返回地址。 
    R11:可以用作通用寄存器,在开启特定编译选项时可以用作帧指针寄存器FP,用来实现栈回溯功能。 
    GNU编译器(gcc)默认将R11作为存储变量的通用寄存器,因而默认情况下无法使用FP的栈回溯功能。 
       为支持调用栈解析功能,需要在编译参数中添加-fno-omit-frame-pointer选项,提示编译器将R11作为FP使用。 
    FP寄存器(Frame Point),帧指针寄存器,指向当前函数的父函数的栈帧起始地址。利用该寄存器可以得到父函数的栈帧, 
       从栈帧中获取父函数的FP,就可以得到祖父函数的栈帧,以此类推,可以追溯程序调用栈,得到函数间的调用关系。 
    当系统发生异常时,系统打印异常函数的栈帧中保存的寄存器内容,以及父函数、祖父函数的 
       栈帧中的LR、FP寄存器内容,用户就可以据此追溯函数间的调用关系,定位异常原因。 
    异常接管对系统运行期间发生的芯片硬件异常进行处理,不同芯片的异常类型存在差异,具体异常类型可以查看芯片手册。  
    
异常接管一般的定位步骤如下: 
    打开编译后生成的镜像反汇编(asm)文件。 
    搜索PC指针(指向当前正在执行的指令)在asm中的位置,找到发生异常的函数。 
    根据LR值查找异常函数的父函数。 
    重复步骤3,得到函数间的调用关系,找到异常原因。 

注意事项 
    要查看调用栈信息,必须添加编译选项宏-fno-omit-frame-pointer支持stack frame,否则编译时FP寄存器是关闭的。 

参考 
    http://weharmonyos.com/openharmony/zh-cn/device-dev/kernel/%E7%94%A8%E6%88%B7%E6%80%81%E5%BC%82%E5%B8%B8%E4%BF%A1%E6%81%AF%E8%AF%B4%E6%98%8E.html
版本
作者
weharmonyos.com | 鸿蒙研究站 | 每天死磕一点点
日期
2021-11-20

在文件 los_exc.c 中定义.

函数说明

◆ __attribute__()

__attribute__ ( (noinline)  )

可变参数,输出到控制台

异常信息的输出

在文件 los_exc.c1333 行定义.

1334{
1335 va_list ap;
1336 va_start(ap, fmt);
1337 OsVprintf(fmt, ap, EXC_OUTPUT);
1338 va_end(ap);
1339 __asm__ __volatile__("swi 0"); //触发断异常
1340 while (1) {}
1341}
VOID OsVprintf(const CHAR *fmt, va_list ap, OutputType type)
printf由 print 和 format 两个单词构成,格式化输出函数, 一般用于向标准输出设备按规定格式输出信息
Definition: los_printf.c:138
@ EXC_OUTPUT
Definition: los_printf.h:108
函数调用图:

◆ __stack_chk_fail()

VOID __stack_chk_fail ( VOID  )

在文件 los_exc.c1346 行定义.

1347{
1348 /* __builtin_return_address is a builtin function, building in gcc */
1349 LOS_Panic("stack-protector: Kernel stack is corrupted in: %p\n",
1350 __builtin_return_address(0));
1351}
NORETURN VOID LOS_Panic(const CHAR *fmt,...)
Kernel panic function.
函数调用图:

◆ BackTrace()

VOID BackTrace ( UINT32  regFP)

打印调用栈信息

在文件 los_exc.c930 行定义.

931{
932 PrintExcInfo("*******backtrace begin*******\n");
933
934 BackTraceSub(regFP);
935}
VOID BackTraceSub(UINTPTR regFP)
Definition: los_exc.c:925
VOID PrintExcInfo(const CHAR *fmt,...)
打印异常信息
Definition: los_printf.c:263
函数调用图:
这是这个函数的调用关系图:

◆ BackTraceGet()

UINT32 BackTraceGet ( UINTPTR  regFP,
IpInfo callChain,
UINT32  maxDepth 
)

在文件 los_exc.c850 行定义.

851{
852 UINTPTR tmpFP, backLR;
853 UINTPTR stackStart, stackEnd;
854 UINTPTR backFP = regFP;
855 UINT32 count = 0;
856 BOOL ret;
857 VADDR_T kvaddr;
858
859 if (FindSuitableStack(regFP, &stackStart, &stackEnd, &kvaddr) == FALSE) {
860 if (callChain == NULL) {
861 PrintExcInfo("traceback error fp = 0x%x\n", regFP);
862 }
863 return 0;
864 }
865
866 /*
867 * Check whether it is the leaf function.
868 * Generally, the frame pointer points to the address of link register, while in the leaf function,
869 * there's no function call, and compiler will not store the link register, but the frame pointer
870 * will still be stored and updated. In that case we needs to find the right position of frame pointer.
871 */
872 tmpFP = *(UINTPTR *)(UINTPTR)kvaddr;
873 if (IsValidFP(tmpFP, stackStart, stackEnd, NULL) == TRUE) {
874 backFP = tmpFP;
875 if (callChain == NULL) {
876 PrintExcInfo("traceback fp fixed, trace using fp = 0x%x\n", backFP);
877 }
878 }
879
880 while (IsValidFP(backFP, stackStart, stackEnd, &kvaddr) == TRUE) {
881 tmpFP = backFP;
882#ifdef LOSCFG_COMPILER_CLANG_LLVM
883 backFP = *(UINTPTR *)(UINTPTR)kvaddr;
884 if (IsValidFP(tmpFP + POINTER_SIZE, stackStart, stackEnd, &kvaddr) == FALSE) {
885 if (callChain == NULL) {
886 PrintExcInfo("traceback backLR check failed, backLP: 0x%x\n", tmpFP + POINTER_SIZE);
887 }
888 return 0;
889 }
890 backLR = *(UINTPTR *)(UINTPTR)kvaddr;
891#else
892 backLR = *(UINTPTR *)(UINTPTR)kvaddr;
893 if (IsValidFP(tmpFP - POINTER_SIZE, stackStart, stackEnd, &kvaddr) == FALSE) {
894 if (callChain == NULL) {
895 PrintExcInfo("traceback backFP check failed, backFP: 0x%x\n", tmpFP - POINTER_SIZE);
896 }
897 return 0;
898 }
899 backFP = *(UINTPTR *)(UINTPTR)kvaddr;
900#endif
901 IpInfo info = {0};
902 ret = OsGetUsrIpInfo((VADDR_T)backLR, &info);
903 if (callChain == NULL) {
904 PrintExcInfo("traceback %u -- lr = 0x%x fp = 0x%x ", count, backLR, backFP);
905 if (ret) {
906#ifdef LOSCFG_KERNEL_VM
907 PrintExcInfo("lr in %s --> 0x%x\n", info.f_path, info.ip);
908#else
909 PrintExcInfo("\n");
910#endif
911 } else {
912 PrintExcInfo("\n");
913 }
914 } else {
915 (VOID)memcpy_s(&callChain[count], sizeof(IpInfo), &info, sizeof(IpInfo));
916 }
917 count++;
918 if ((count == maxDepth) || (backFP == tmpFP)) {
919 break;
920 }
921 }
922 return count;
923}
BOOL OsGetUsrIpInfo(UINTPTR ip, IpInfo *info)
Definition: los_exc.c:804
STATIC INLINE BOOL IsValidFP(UINTPTR regFP, UINTPTR start, UINTPTR end, vaddr_t *vaddr)
此函数用于验证fp或验证检查开始和结束范围
Definition: los_exc.c:716
STATIC INLINE BOOL FindSuitableStack(UINTPTR regFP, UINTPTR *start, UINTPTR *end, vaddr_t *vaddr)
找到一个合适的栈
Definition: los_exc.c:747
unsigned long VADDR_T
Definition: los_typedef.h:208
unsigned long UINTPTR
Definition: los_typedef.h:68
unsigned int UINT32
Definition: los_typedef.h:57
size_t BOOL
Definition: los_typedef.h:88
UINTPTR ip
Definition: los_exc_pri.h:51
CHAR f_path[REGION_PATH_MAX]
Definition: los_exc_pri.h:53
函数调用图:
这是这个函数的调用关系图:

◆ BackTraceSub()

VOID BackTraceSub ( UINTPTR  regFP)

在文件 los_exc.c925 行定义.

926{
927 (VOID) BackTraceGet(regFP, NULL, OS_MAX_BACKTRACE);
928}
UINT32 BackTraceGet(UINTPTR regFP, IpInfo *callChain, UINT32 maxDepth)
Definition: los_exc.c:850
函数调用图:
这是这个函数的调用关系图:

◆ FindSuitableStack()

STATIC INLINE BOOL FindSuitableStack ( UINTPTR  regFP,
UINTPTR start,
UINTPTR end,
vaddr_t vaddr 
)

找到一个合适的栈

在文件 los_exc.c747 行定义.

748{
749 UINT32 index, stackStart, stackEnd;
750 BOOL found = FALSE;
751 LosTaskCB *taskCB = NULL;
752 const StackInfo *stack = NULL;
753 vaddr_t kvaddr;
754
755#ifdef LOSCFG_KERNEL_VM
756 if (g_excFromUserMode[ArchCurrCpuid()] == TRUE) {//当前CPU在用户态执行发生异常
757 taskCB = OsCurrTaskGet();
758 stackStart = taskCB->userMapBase; //用户态栈基地址,即用户态栈顶
759 stackEnd = taskCB->userMapBase + taskCB->userMapSize; //用户态栈结束地址
760 if (IsValidFP(regFP, stackStart, stackEnd, &kvaddr) == TRUE) {
761 found = TRUE;
762 goto FOUND;
763 }
764 return found;
765 }
766#endif
767
768 /* Search in the task stacks | 找任务的内核态栈*/
769 for (index = 0; index < g_taskMaxNum; index++) {
770 taskCB = &g_taskCBArray[index];
771 if (OsTaskIsUnused(taskCB)) {
772 continue;
773 }
774
775 stackStart = taskCB->topOfStack; //内核态栈顶
776 stackEnd = taskCB->topOfStack + taskCB->stackSize; //内核态栈底
777 if (IsValidFP(regFP, stackStart, stackEnd, &kvaddr) == TRUE) {
778 found = TRUE;
779 goto FOUND;
780 }
781 }
782
783 /* Search in the exc stacks */ //从异常栈中找
784 for (index = 0; index < sizeof(g_excStack) / sizeof(StackInfo); index++) {
785 stack = &g_excStack[index];
786 stackStart = (UINTPTR)stack->stackTop;
787 stackEnd = stackStart + LOSCFG_KERNEL_CORE_NUM * stack->stackSize;
788 if (IsValidFP(regFP, stackStart, stackEnd, &kvaddr) == TRUE) {
789 found = TRUE;
790 goto FOUND;
791 }
792 }
793
794FOUND:
795 if (found == TRUE) {
796 *start = stackStart;
797 *end = stackEnd;
798 *vaddr = kvaddr;
799 }
800
801 return found;
802}
LITE_OS_SEC_BSS UINT32 g_taskMaxNum
任务最大数量 默认128个
Definition: los_task.c:150
LITE_OS_SEC_BSS LosTaskCB * g_taskCBArray
外部变量 任务池 默认128个
Definition: los_task.c:147
BOOL g_excFromUserMode[LOSCFG_KERNEL_CORE_NUM]
记录CPU core 异常来自用户态还是内核态 TRUE为用户态,默认为内核态
Definition: los_exc.c:129
STATIC const StackInfo g_excStack[]
Definition: los_exc.c:176
STATIC INLINE UINT32 ArchCurrCpuid(VOID)
Definition: los_hw_cpu.h:168
STATIC INLINE LosTaskCB * OsCurrTaskGet(VOID)
STATIC INLINE BOOL OsTaskIsUnused(const LosTaskCB *taskCB)
任务是否在使用
Definition: los_task_pri.h:255
unsigned long vaddr_t
Definition: los_typedef.h:206
UINT32 stackSize
栈大小
VOID * stackTop
栈顶
UINT32 stackSize
UINTPTR userMapBase
用户空间的栈顶位置,内存来自用户空间,和topOfStack有本质的区别.
UINTPTR topOfStack
UINT32 userMapSize
if(tv==NULL)
Definition: time.c:430
函数调用图:
这是这个函数的调用关系图:

◆ IsValidFP()

STATIC INLINE BOOL IsValidFP ( UINTPTR  regFP,
UINTPTR  start,
UINTPTR  end,
vaddr_t vaddr 
)

此函数用于验证fp或验证检查开始和结束范围

在文件 los_exc.c716 行定义.

717{
718 VADDR_T kvaddr = regFP;
719
720 if (!((regFP > start) && (regFP < end) && IS_ALIGNED(regFP, sizeof(CHAR *)))) {
721 return FALSE;
722 }
723
724#ifdef LOSCFG_KERNEL_VM
725 PADDR_T paddr;
726 if (g_excFromUserMode[ArchCurrCpuid()] == TRUE) {
727 LosProcessCB *runProcess = OsCurrProcessGet();
728 LosVmSpace *runspace = runProcess->vmSpace;
729 if (runspace == NULL) {
730 return FALSE;
731 }
732
733 if (LOS_ArchMmuQuery(&runspace->archMmu, regFP, &paddr, NULL) != LOS_OK) {
734 return FALSE;
735 }
736
737 kvaddr = (PADDR_T)(UINTPTR)LOS_PaddrToKVaddr(paddr);
738 }
739#endif
740 if (vaddr != NULL) {
741 *vaddr = kvaddr;
742 }
743
744 return TRUE;
745}
STATUS_T LOS_ArchMmuQuery(const LosArchMmu *archMmu, VADDR_T vaddr, PADDR_T *paddr, UINT32 *flags)
LOS_ArchMmuQuery 获取进程空间虚拟地址对应的物理地址以及映射属性。 本函数是内核高频函数,通过MMU查询虚拟地址是否映射过,带走映射的物理地址和权限
Definition: los_arch_mmu.c:569
STATIC INLINE LosProcessCB * OsCurrProcessGet(VOID)
unsigned long PADDR_T
Definition: los_typedef.h:207
char CHAR
Definition: los_typedef.h:63
VADDR_T * LOS_PaddrToKVaddr(PADDR_T paddr)
通过物理地址获取内核虚拟地址
Definition: los_vm_phys.c:688
LosVmSpace * vmSpace
虚拟空间,每个进程都有一个属于自己的虚拟内存地址空间
Definition: los_vm_map.h:146
LosArchMmu archMmu
Definition: los_vm_map.h:157
函数调用图:
这是这个函数的调用关系图:

◆ OsArmSharedPageFault()

UINT32 OsArmSharedPageFault ( UINT32  excType,
ExcContext frame,
UINT32  far,
UINT32  fsr 
)

共享页缺失异常

参数
excType
frame
far异常状态寄存器(Fault Status Register -FAR)
fsr异常地址寄存器(Fault Address Register -FSR)
返回
UINT32

在文件 los_exc.c261 行定义.

262{
263 BOOL instructionFault = FALSE;
264 UINT32 pfFlags = 0;
265 UINT32 fsrFlag;
266 BOOL write = FALSE;
267 UINT32 ret;
268
269 PRINT_INFO("page fault entry!!!\n");
270 if (OsGetSystemStatus() == OS_SYSTEM_EXC_CURR_CPU) {
271 return LOS_ERRNO_VM_NOT_FOUND;
272 }
273#if defined(LOSCFG_KERNEL_SMP) && defined(LOSCFG_DEBUG_VERSION)
274 BOOL irqEnable = !(LOS_SpinHeld(&g_taskSpin) && OsSchedIsLock());
275 if (irqEnable) {
277 } else {
278 PrintExcInfo("[ERR][%s] may be held scheduler lock when entering [%s] on cpu [%u]\n",
279 OsCurrTaskGet()->taskName, __FUNCTION__, ArchCurrCpuid());
280 }
281#else
283#endif
284 if (excType == OS_EXCEPT_PREFETCH_ABORT) {
285 instructionFault = TRUE;
286 } else {
287 write = !!BIT_GET(fsr, WNR_BIT);
288 }
289
290 fsrFlag = ((BIT_GET(fsr, FSR_FLAG_OFFSET_BIT) ? 0b10000 : 0) | BITS_GET(fsr, FSR_BITS_BEGIN_BIT, 0));
291 switch (fsrFlag) {
292 case 0b00101:
293 /* translation fault */
294 case 0b00111:
295 /* translation fault */
296 case 0b01101:
297 /* permission fault */
298 case 0b01111: {
299 /* permission fault */
300 BOOL user = (frame->regCPSR & CPSR_MODE_MASK) == CPSR_MODE_USR;
301 pfFlags |= write ? VM_MAP_PF_FLAG_WRITE : 0;
302 pfFlags |= user ? VM_MAP_PF_FLAG_USER : 0;
303 pfFlags |= instructionFault ? VM_MAP_PF_FLAG_INSTRUCTION : 0;
304 pfFlags |= VM_MAP_PF_FLAG_NOT_PRESENT;
305 OsSigIntLock();
306 ret = OsVmPageFaultHandler(far, pfFlags, frame);
308 break;
309 }
310 default:
311 OsArmWriteTlbimvaais(ROUNDDOWN(far, PAGE_SIZE));
312 ret = LOS_OK;
313 break;
314 }
315#if defined(LOSCFG_KERNEL_SMP) && defined(LOSCFG_DEBUG_VERSION)
316 if (irqEnable) {
318 }
319#else
321#endif
322 return ret;
323}
STATIC INLINE VOID OsArmWriteTlbimvaais(UINT32 val)
Definition: arm.h:527
UINT32 OsGetSystemStatus(VOID)
获取系统状态
Definition: los_exc.c:181
STATIC INLINE VOID ArchIrqDisable(VOID)
Definition: los_hw_cpu.h:214
STATIC INLINE VOID ArchIrqEnable(VOID)
Definition: los_hw_cpu.h:223
STATIC INLINE BOOL OsSchedIsLock(VOID)
VOID OsSigIntUnlock(VOID)
Definition: los_signal.c:712
VOID OsSigIntLock(VOID)
Definition: los_signal.c:704
BOOL LOS_SpinHeld(const SPIN_LOCK_S *lock)
Definition: los_spinlock.c:45
SPIN_LOCK_S g_taskSpin
STATUS_T OsVmPageFaultHandler(VADDR_T vaddr, UINT32 flags, ExcContext *frame)
Definition: los_vm_fault.c:352
UINT32 regCPSR
Definition: los_exc.h:88
函数调用图:

◆ OsCallStackInfo()

VOID OsCallStackInfo ( VOID  )

打印调用栈信息

在文件 los_exc.c974 行定义.

975{
976 UINT32 count = 0;
977 LosTaskCB *runTask = OsCurrTaskGet();
978 UINTPTR stackBottom = runTask->topOfStack + runTask->stackSize; //内核态的 栈底 = 栈顶 + 大小
979 UINT32 *stackPointer = (UINT32 *)stackBottom;
980
981 PrintExcInfo("runTask->stackPointer = 0x%x\n"
982 "runTask->topOfStack = 0x%x\n"
983 "text_start:0x%x,text_end:0x%x\n",
984 stackPointer, runTask->topOfStack, &__text_start, &__text_end);
985 //打印OS_MAX_BACKTRACE多一条栈信息,注意stack中存放的是函数调用地址和指令的地址
986 while ((stackPointer > (UINT32 *)runTask->topOfStack) && (count < OS_MAX_BACKTRACE)) {
987 if ((*stackPointer > (UINTPTR)(&__text_start)) && //正常情况下 sp的内容都是文本段的内容
988 (*stackPointer < (UINTPTR)(&__text_end)) &&
989 IS_ALIGNED((*stackPointer), POINTER_SIZE)) { //sp的内容是否对齐, sp指向指令的地址
990 if ((*(stackPointer - 1) > (UINT32)runTask->topOfStack) &&
991 (*(stackPointer - 1) < stackBottom) && //@note_why 这里为什么要对 stackPointer - 1 进行判断
992 IS_ALIGNED((*(stackPointer - 1)), POINTER_SIZE)) {
993 count++;
994 PrintExcInfo("traceback %u -- lr = 0x%x\n", count, *stackPointer);
995 }
996 }
997 stackPointer--;
998 }
999 PRINTK("\n");
1000}
macro EXC_SP_SET stackBottom
Definition: asm.h:50
CHAR __text_end
代码区结束地址
CHAR __text_start
代码区开始地址
函数调用图:
这是这个函数的调用关系图:

◆ OsCheckAllCpuStatus()

STATIC VOID OsCheckAllCpuStatus ( VOID  )

检查所有CPU的状态

在文件 los_exc.c1139 行定义.

1140{
1141 UINT32 currCpuid = ArchCurrCpuid();
1142 UINT32 ret, target;
1143
1145 LOCKDEP_CLEAR_LOCKS();
1146
1147 LOS_SpinLock(&g_excSerializerSpin);
1148 /* Only the current CPU anomaly */
1149 if (g_currHandleExcCpuid == INVALID_CPUID) {
1150 g_currHandleExcCpuid = currCpuid;
1152 LOS_SpinUnlock(&g_excSerializerSpin);
1153#ifndef LOSCFG_SAVE_EXCINFO
1154 if (g_excFromUserMode[currCpuid] == FALSE) {
1155 target = (UINT32)(OS_MP_CPU_ALL & ~CPUID_TO_AFFI_MASK(currCpuid));
1157 }
1158#endif
1159 } else if (g_excFromUserMode[currCpuid] == TRUE) {
1160 /* Both cores raise exceptions, and the current core is a user-mode exception.
1161 * Both cores are abnormal and come from the same process
1162 */
1163 if (OsCurrProcessGet()->processID == g_currHandleExcPID) {
1164 LOS_SpinUnlock(&g_excSerializerSpin);
1165 OsExcRestore();
1166 ret = LOS_TaskDelete(OsCurrTaskGet()->taskID);
1167 LOS_Panic("%s supend task :%u failed: 0x%x\n", __FUNCTION__, OsCurrTaskGet()->taskID, ret);
1168 }
1169 LOS_SpinUnlock(&g_excSerializerSpin);
1170
1172 } else {
1173 if ((g_currHandleExcCpuid < LOSCFG_KERNEL_CORE_NUM) && (g_excFromUserMode[g_currHandleExcCpuid] == TRUE)) {
1174 g_currHandleExcCpuid = currCpuid;
1175 LOS_SpinUnlock(&g_excSerializerSpin);
1176 target = (UINT32)(OS_MP_CPU_ALL & ~CPUID_TO_AFFI_MASK(currCpuid));
1178 } else {
1179 LOS_SpinUnlock(&g_excSerializerSpin);
1180 while (1) {}
1181 }
1182 }
1183#ifndef LOSCFG_SAVE_EXCINFO
1184 /* use halt ipi to stop other active cores */
1185 if (g_excFromUserMode[ArchCurrCpuid()] == FALSE) {
1186 WaitAllCpuStop(currCpuid);
1187 }
1188#endif
1189}
VOID HalIrqSendIpi(UINT32 target, UINT32 ipi)
Definition: gic_v2.c:58
LITE_OS_SEC_TEXT_INIT UINT32 LOS_TaskDelete(UINT32 taskID)
Delete a task.
Definition: los_task.c:968
STATIC UINT32 g_currHandleExcCpuid
Definition: los_exc.c:126
STATIC VOID WaitAllCpuStop(UINT32 cpuid)
等待所有CPU停止
Definition: los_exc.c:1099
STATIC VOID OsExcRestore(VOID)
异常恢复,继续执行
Definition: los_exc.c:638
STATIC VOID OsWaitOtherCoresHandleExcEnd(UINT32 currCpuid)
Definition: los_exc.c:1120
STATIC UINT32 g_currHandleExcPID
Definition: los_exc.c:133
@ LOS_MP_IPI_HALT
!< 调度CPU
Definition: los_mp.h:52
@ CPU_EXC
cpu in the exc | CPU处于异常状态
STATIC INLINE VOID OsCpuStatusSet(ExcFlag flag)
VOID LOS_SpinLock(SPIN_LOCK_S *lock)
Definition: los_spinlock.c:50
VOID LOS_SpinUnlock(SPIN_LOCK_S *lock)
Definition: los_spinlock.c:84
UINT32 processID
函数调用图:
这是这个函数的调用关系图:

◆ OsCheckCpuStatus()

STATIC VOID OsCheckCpuStatus ( VOID  )

在文件 los_exc.c1192 行定义.

1193{
1194#ifdef LOSCFG_KERNEL_SMP
1196#else
1198#endif
1199}
STATIC VOID OsCheckAllCpuStatus(VOID)
检查所有CPU的状态
Definition: los_exc.c:1139
函数调用图:
这是这个函数的调用关系图:

◆ OsDataAbortExcHandleEntry()

VOID OsDataAbortExcHandleEntry ( ExcContext excBufAddr)

数据中止异常处理函数,由汇编调用 见于 los_hw_exc.s

在文件 los_exc.c1073 行定义.

1074{
1075 UINT32 far;
1076 UINT32 fsr;
1077
1078 excBufAddr->PC -= 8; /* lr in data abort is pc + 8 */
1079
1080 if (gdbhw_hook(excBufAddr, OS_EXCEPT_DATA_ABORT)) {
1081 return;
1082 }
1083
1084 if (g_excHook != NULL) {
1085 far = OsArmReadDfar();
1086 fsr = OsArmReadDfsr();
1087 g_excHook(OS_EXCEPT_DATA_ABORT, excBufAddr, far, fsr); ////回调函数,详见: OsExcHook
1088 }
1089 while (1) {}
1090}
STATIC INLINE UINT32 OsArmReadDfar(VOID)
Definition: arm.h:169
STATIC INLINE UINT32 OsArmReadDfsr(VOID)
Definition: arm.h:143
STATIC EXC_PROC_FUNC g_excHook
全局异常处理钩子
Definition: los_exc.c:130
UINT32 PC
Definition: los_exc.h:87
函数调用图:

◆ OsDecodeDataFSR()

STATIC INT32 OsDecodeDataFSR ( UINT32  regDFSR)

在文件 los_exc.c231 行定义.

232{
233 INT32 ret = 0;
234 UINT32 bitWnR = GET_WNR(regDFSR); /* WnR bit[11] */
235 UINT32 bitsFS = GET_FS(regDFSR); /* FS bits[4]+[3:0] */
236
237 if (bitWnR) {
238 PrintExcInfo("Abort caused by a write instruction. ");
239 } else {
240 PrintExcInfo("Abort caused by a read instruction. ");
241 }
242
243 if (bitsFS == 0x01) { /* 0b00001 */
244 PrintExcInfo("Alignment fault.\n");
245 return ret;
246 }
247 ret = OsDecodeFS(bitsFS);
248 return ret;
249}
STATIC INT32 OsDecodeFS(UINT32 bitsFS)
Definition: los_exc.c:197
signed int INT32
Definition: los_typedef.h:60
函数调用图:
这是这个函数的调用关系图:

◆ OsDecodeFS()

STATIC INT32 OsDecodeFS ( UINT32  bitsFS)

在文件 los_exc.c197 行定义.

198{
199 switch (bitsFS) {
200 case 0x05: /* 0b00101 */
201 case 0x07: /* 0b00111 */
202 PrintExcInfo("Translation fault, %s\n", (bitsFS & 0x2) ? "page" : "section");
203 break;
204 case 0x09: /* 0b01001 */
205 case 0x0b: /* 0b01011 */
206 PrintExcInfo("Domain fault, %s\n", (bitsFS & 0x2) ? "page" : "section");
207 break;
208 case 0x0d: /* 0b01101 */
209 case 0x0f: /* 0b01111 */
210 PrintExcInfo("Permission fault, %s\n", (bitsFS & 0x2) ? "page" : "section");
211 break;
212 default:
213 PrintExcInfo("Unknown fault! FS:0x%x. "
214 "Check IFSR and DFSR in ARM Architecture Reference Manual.\n",
215 bitsFS);
216 break;
217 }
218
219 return LOS_OK;
220}
函数调用图:
这是这个函数的调用关系图:

◆ OsDecodeInstructionFSR()

STATIC INT32 OsDecodeInstructionFSR ( UINT32  regIFSR)

在文件 los_exc.c222 行定义.

223{
224 INT32 ret;
225 UINT32 bitsFS = GET_FS(regIFSR); /* FS bits[4]+[3:0] */
226
227 ret = OsDecodeFS(bitsFS);
228 return ret;
229}
函数调用图:
这是这个函数的调用关系图:

◆ OsDumpContextMem()

VOID OsDumpContextMem ( const ExcContext excBufAddr)

dump 上下文内存,注意内核异常不能简单的映射理解为应用的异常,异常对内核来说是一个很常见操作,
比如任务的切换对内核来说就是一个异常处理

打印异常上下文

参数
excBufAddr
返回
VOID

在文件 los_exc.c608 行定义.

609{
610 UINT32 count = 0;
611 const UINT32 *excReg = NULL;
612 if (g_excFromUserMode[ArchCurrCpuid()] == TRUE) {
613 return;
614 }
615
616 for (excReg = &(excBufAddr->R0); count < COM_REGS; excReg++, count++) {
617 if (IS_VALID_ADDR(*excReg)) {
618 PrintExcInfo("\ndump mem around R%u:%p", count, (*excReg));
619 OsDumpMemByte(DUMPSIZE, ((*excReg) - (DUMPSIZE >> 1)));
620 }
621 }
622 for (excReg = &(excBufAddr->R4); count < DUMPREGS; excReg++, count++) {
623 if (IS_VALID_ADDR(*excReg)) {
624 PrintExcInfo("\ndump mem around R%u:%p", count, (*excReg));
625 OsDumpMemByte(DUMPSIZE, ((*excReg) - (DUMPSIZE >> 1)));
626 }
627 }
628 if (IS_VALID_ADDR(excBufAddr->R12)) {
629 PrintExcInfo("\ndump mem around R12:%p", excBufAddr->R12);
630 OsDumpMemByte(DUMPSIZE, (excBufAddr->R12 - (DUMPSIZE >> 1)));
631 }
632 if (IS_VALID_ADDR(excBufAddr->SP)) {
633 PrintExcInfo("\ndump mem around SP:%p", excBufAddr->SP);
634 OsDumpMemByte(DUMPSIZE, (excBufAddr->SP - (DUMPSIZE >> 1)));
635 }
636}
VOID OsDumpMemByte(size_t length, UINTPTR addr)
UINT64 SP
Definition: los_exc.h:62
UINT32 R4
Definition: los_exc.h:68
UINT32 R0
Definition: los_exc.h:81
UINT32 R12
Definition: los_exc.h:85
函数调用图:
这是这个函数的调用关系图:

◆ OsDumpExcVaddrRegion()

STATIC VOID OsDumpExcVaddrRegion ( LosVmSpace space,
LosVmMapRegion region 
)

dump 虚拟空间下异常虚拟地址线性区

在文件 los_exc.c515 行定义.

516{
517 INT32 i, numPages, pageCount;
518 paddr_t addr, oldAddr, startVaddr, startPaddr;
519 vaddr_t pageBase;
520 BOOL mmuFlag = FALSE;
521
522 numPages = region->range.size >> PAGE_SHIFT;
523 mmuFlag = TRUE;
524 for (pageCount = 0, startPaddr = 0, startVaddr = 0, i = 0; i < numPages; i++) {
525 pageBase = region->range.base + i * PAGE_SIZE;
526 addr = 0;
527 if (LOS_ArchMmuQuery(&space->archMmu, pageBase, &addr, NULL) != LOS_OK) {
528 if (startPaddr == 0) {
529 continue;
530 }
531 } else if (startPaddr == 0) {
532 startVaddr = pageBase;
533 startPaddr = addr;
534 oldAddr = addr;
535 pageCount++;
536 if (numPages > 1) {
537 continue;
538 }
539 } else if (addr == (oldAddr + PAGE_SIZE)) {
540 pageCount++;
541 oldAddr = addr;
542 if (i < (numPages - 1)) {
543 continue;
544 }
545 }
546 if (mmuFlag == TRUE) {
547 PrintExcInfo(" uvaddr kvaddr mapped size\n");
548 mmuFlag = FALSE;
549 }
550 PrintExcInfo(" 0x%08x 0x%08x 0x%08x\n",
551 startVaddr, LOS_PaddrToKVaddr(startPaddr), (UINT32)pageCount << PAGE_SHIFT);
552 pageCount = 0;
553 startPaddr = 0;
554 }
555}
unsigned long paddr_t
Definition: los_typedef.h:209
UINT32 size
Definition: los_vm_map.h:85
VADDR_T base
Definition: los_vm_map.h:84
LosVmMapRange range
Definition: los_vm_map.h:123
函数调用图:
这是这个函数的调用关系图:

◆ OsDumpProcessUsedMemNode()

STATIC VOID OsDumpProcessUsedMemNode ( UINT16  vmmFlags)

dump 进程使用的内存节点

在文件 los_exc.c576 行定义.

577{
578 LosProcessCB *runProcess = NULL;
579 LosVmSpace *runspace = NULL;
580
581 runProcess = OsCurrProcessGet();
582 if (runProcess == NULL) {
583 return;
584 }
585
586 if (!OsProcessIsUserMode(runProcess)) {
587 return;
588 }
589
590 PrintExcInfo("\n ******Current process %u vmm regions: ******\n", runProcess->processID);
591
592 runspace = runProcess->vmSpace;
593 if (!runspace) {
594 return;
595 }
596
597 OsDumpProcessUsedMemRegion(runProcess, runspace, vmmFlags);
598 return;
599}
STATIC VOID OsDumpProcessUsedMemRegion(LosProcessCB *runProcess, LosVmSpace *runspace, UINT16 vmmFlags)
dump 进程使用的内存线性区
Definition: los_exc.c:557
STATIC INLINE BOOL OsProcessIsUserMode(const LosProcessCB *processCB)
函数调用图:
这是这个函数的调用关系图:

◆ OsDumpProcessUsedMemRegion()

STATIC VOID OsDumpProcessUsedMemRegion ( LosProcessCB runProcess,
LosVmSpace runspace,
UINT16  vmmFlags 
)

dump 进程使用的内存线性区

在文件 los_exc.c557 行定义.

558{
559 LosVmMapRegion *region = NULL;
560 LosRbNode *pstRbNodeTemp = NULL;
561 LosRbNode *pstRbNodeNext = NULL;
562 UINT32 count = 0;
563
564 /* search the region list */
565 RB_SCAN_SAFE(&runspace->regionRbTree, pstRbNodeTemp, pstRbNodeNext)
566 region = (LosVmMapRegion *)pstRbNodeTemp;
567 PrintExcInfo("%3u -> regionBase: 0x%08x regionSize: 0x%08x\n", count, region->range.base, region->range.size);
568 if (vmmFlags == OS_EXC_VMM_ALL_REGION) {
569 OsDumpExcVaddrRegion(runspace, region);
570 }
571 count++;
572 (VOID) OsRegionOverlapCheckUnlock(runspace, region);
573 RB_SCAN_SAFE_END(&space->regionRbTree, pstRbNodeTemp, pstRbNodeNext)
574}
STATIC VOID OsDumpExcVaddrRegion(LosVmSpace *space, LosVmMapRegion *region)
dump 虚拟空间下异常虚拟地址线性区
Definition: los_exc.c:515
INT32 OsRegionOverlapCheckUnlock(LosVmSpace *space, LosVmMapRegion *region)
Definition: los_vm_dump.c:85
LosRbTree regionRbTree
Definition: los_vm_map.h:148
函数调用图:
这是这个函数的调用关系图:

◆ OsExcHandleEntry()

LITE_OS_SEC_TEXT_INIT VOID OsExcHandleEntry ( UINT32  excType,
ExcContext excBufAddr,
UINT32  far,
UINT32  fsr 
)

在文件 los_exc.c1269 行定义.

1270{ //异常信息处理入口
1271#ifdef LOSCFG_SAVE_EXCINFO
1272 UINT32 intCount;
1273 UINT32 lockCount;
1274#endif
1275 /* Task scheduling is not allowed during exception handling */
1276 OsSchedLock();
1277
1279
1280 OsExcPriorDisposal(excBufAddr);
1281
1282 OsPrintExcHead(far); //打印异常信息头部信息 ##################excFrom: User!####################
1283
1284#ifdef LOSCFG_KERNEL_SMP
1285 OsAllCpuStatusOutput(); //打印各CPU core的状态
1286#endif
1287
1288#ifdef LOSCFG_SAVE_EXCINFO
1289 log_read_write_fn func = GetExcInfoRW(); //获取异常信息读写函数,用于打印异常信息栈
1290#endif
1291
1292 if (g_excHook != NULL) {//全局异常钩子函数
1293 if (g_curNestCount[ArchCurrCpuid()] == 1) {//说明只有一个异常
1294#ifdef LOSCFG_SAVE_EXCINFO
1295 if (func != NULL) {
1296#ifndef LOSCFG_BLACKBOX
1297 SetExcInfoIndex(0);
1298#endif
1299 OsSysStateSave(&intCount, &lockCount);
1301 OsSysStateRestore(intCount, lockCount);
1302 }
1303#endif
1304 g_excHook(excType, excBufAddr, far, fsr);
1305 } else { //说明出现了异常嵌套的情况
1306 OsCallStackInfo(); //打印栈内容
1307 }
1308
1309#ifdef LOSCFG_SAVE_EXCINFO
1310 if (func != NULL) {
1311 PrintExcInfo("Be sure flash space bigger than GetExcInfoIndex():0x%x\n", GetExcInfoIndex());
1312 OsSysStateSave(&intCount, &lockCount);
1314 OsSysStateRestore(intCount, lockCount);
1315 }
1316#endif
1317 }
1318
1319#ifdef LOSCFG_SHELL_CMD_DEBUG
1320 SystemRebootFunc rebootHook = OsGetRebootHook();
1321 if ((OsSystemExcIsReset() == TRUE) && (rebootHook != NULL)) {
1322 LOS_Mdelay(3000); /* 3000: System dead, delay 3 seconds after system restart */
1323 rebootHook();
1324 }
1325#endif
1326
1327#ifdef LOSCFG_BLACKBOX
1328 BBoxNotifyError(EVENT_PANIC, MODULE_SYSTEM, "Crash in kernel", 1);
1329#endif
1330 while (1) {}
1331}
VOID(* log_read_write_fn)(UINT32 startAddr, UINT32 space, UINT32 rwFlag, CHAR *buf)
define the type of functions for reading or writing exception information.
Definition: los_config.h:435
LITE_OS_SEC_TEXT_MINOR VOID LOS_Mdelay(UINT32 msecs)
以ms为单位的忙等,但可以被优先级更高的任务抢占
Definition: los_hw_tick.c:73
int BBoxNotifyError(const char event[EVENT_MAX_LEN], const char module[MODULE_MAX_LEN], const char errorDesc[ERROR_DESC_MAX_LEN], int needSysReset)
SystemRebootFunc OsGetRebootHook(VOID)
获取系统重启钩子函数
Definition: los_config.c:63
VOID(* SystemRebootFunc)(VOID)
Definition: los_config.h:475
VOID OsCallStackInfo(VOID)
打印调用栈信息
Definition: los_exc.c:974
STATIC VOID OsSysStateRestore(UINT32 intCount, UINT32 lockCount)
Definition: los_exc.c:1257
LITE_OS_SEC_TEXT VOID STATIC OsExcPriorDisposal(ExcContext *excBufAddr)
执行期间的优先处理 excBufAddr为CPU异常上下文,
Definition: los_exc.c:1201
STATIC VOID OsSysStateSave(UINT32 *intCount, UINT32 *lockCount)
Definition: los_exc.c:1249
UINT32 g_curNestCount[LOSCFG_KERNEL_CORE_NUM]
记录当前嵌套异常的数量
Definition: los_exc.c:128
LITE_OS_SEC_TEXT_INIT STATIC VOID OsPrintExcHead(UINT32 far)
异常信息头部打印
Definition: los_exc.c:1223
BOOL OsSystemExcIsReset(VOID)
UINT32 GetExcInfoIndex(VOID)
获取异常信息索引位
Definition: los_excinfo.c:74
CHAR * GetExcInfoBuf(VOID)
获取异常信息的缓存
Definition: los_excinfo.c:64
UINT32 GetRecordAddr(VOID)
Definition: los_excinfo.c:84
UINT32 GetRecordSpace(VOID)
Definition: los_excinfo.c:94
log_read_write_fn GetExcInfoRW(VOID)
获取异常信息读写函数
Definition: los_excinfo.c:54
VOID OsRecordExcInfoTime(VOID)
记录异常信息产生的时间
Definition: los_excinfo.c:149
VOID SetExcInfoIndex(UINT32 index)
设置异常信息索引位
Definition: los_excinfo.c:69
VOID OsAllCpuStatusOutput(VOID)
Definition: los_percpu.c:38
STATIC INLINE VOID OsSchedLock(VOID)
函数调用图:

◆ OsExcHook()

VOID OsExcHook ( UINT32  excType,
ExcContext excBufAddr,
UINT32  far,
UINT32  fsr 
)

由注册后回调,发送异常情况下会回调这里执行,见于 OsUndefIncExcHandleEntry, OsExcHandleEntry ==函数

在文件 los_exc.c942 行定义.

943{ //参考文档 https://gitee.com/openharmony/docs/blob/master/kernel/%E7%94%A8%E6%88%B7%E6%80%81%E5%BC%82%E5%B8%B8%E4%BF%A1%E6%81%AF%E8%AF%B4%E6%98%8E.md
944 OsExcType(excType, excBufAddr, far, fsr); //1.打印异常的类型
945 OsExcSysInfo(excType, excBufAddr); //2.打印异常的基本信息
946 OsExcRegsInfo(excBufAddr); //3.打印异常的寄存器信息
947
948 BackTrace(excBufAddr->R11); //4.打印调用栈信息,
949
950 (VOID) OsShellCmdTskInfoGet(OS_ALL_TASK_MASK, NULL, OS_PROCESS_INFO_ALL); //打印进程线程基本信息 相当于执行下 shell task -a 命令
951
952#ifndef LOSCFG_DEBUG_VERSION //打开debug开关
953 if (g_excFromUserMode[ArchCurrCpuid()] != TRUE) {
954#endif
955#ifdef LOSCFG_KERNEL_VM
956 OsDumpProcessUsedMemNode(OS_EXC_VMM_NO_REGION);
957#endif
958 OsExcStackInfo(); // 打印任务栈的信息
959#ifndef LOSCFG_DEBUG_VERSION
960 }
961#endif
962
963 OsDumpContextMem(excBufAddr); // 打印上下文
964
965 (VOID) OsShellCmdMemCheck(0, NULL); //检查内存,相当于执行 shell memcheck 命令
966
967#ifdef LOSCFG_COREDUMP
968 LOS_CoreDumpV2(excType, excBufAddr);
969#endif
970
971 OsUserExcHandle(excBufAddr); //用户态下异常的处理
972}
STATIC VOID OsUserExcHandle(ExcContext *excBufAddr)
用户态异常处理函数
Definition: los_exc.c:651
VOID OsDumpContextMem(const ExcContext *excBufAddr)
dump 上下文内存,注意内核异常不能简单的映射理解为应用的异常,异常对内核来说是一个很常见操作, 比如任务的切换对内核来说就是一个异常处理
Definition: los_exc.c:608
VOID BackTrace(UINT32 regFP)
打印调用栈信息
Definition: los_exc.c:930
STATIC VOID OsExcType(UINT32 excType, ExcContext *excBufAddr, UINT32 far, UINT32 fsr)
异常类型
Definition: los_exc.c:326
STATIC VOID OsDumpProcessUsedMemNode(UINT16 vmmFlags)
dump 进程使用的内存节点
Definition: los_exc.c:576
STATIC VOID OsExcSysInfo(UINT32 excType, const ExcContext *excBufAddr)
打印异常系统信息
Definition: los_exc.c:401
STATIC VOID OsExcRegsInfo(const ExcContext *excBufAddr)
异常情况下打印各寄存器的信息
Definition: los_exc.c:471
UINT32 OsShellCmdMemCheck(INT32 argc, const CHAR *argv[])
VOID OsExcStackInfo(VOID)
打印栈的信息 把每个CPU的栈信息打印出来
UINT32 OsShellCmdTskInfoGet(UINT32 taskID, VOID *seqfile, UINT16 flag)
UINT32 R11
Definition: los_exc.h:75
函数调用图:

◆ OsExcInit()

VOID OsExcInit ( VOID  )

异常接管模块的初始化

在文件 los_exc.c937 行定义.

938{
939 OsExcStackInfoReg(g_excStack, sizeof(g_excStack) / sizeof(g_excStack[0])); //异常模式下注册内核栈信息
940}
VOID OsExcStackInfoReg(const StackInfo *stackInfo, UINT32 stackNum)
注册栈信息
函数调用图:
这是这个函数的调用关系图:

◆ OsExcPriorDisposal()

LITE_OS_SEC_TEXT VOID STATIC OsExcPriorDisposal ( ExcContext excBufAddr)

执行期间的优先处理 excBufAddr为CPU异常上下文,

在文件 los_exc.c1201 行定义.

1202{
1203 if ((excBufAddr->regCPSR & CPSR_MASK_MODE) == CPSR_USER_MODE) { //用户模式下,访问地址不能出用户空间
1204 g_minAddr = USER_ASPACE_BASE; //可访问地址范围的开始地址,
1205 g_maxAddr = USER_ASPACE_BASE + USER_ASPACE_SIZE; //地址范围的结束地址,就是用户空间
1206 g_excFromUserMode[ArchCurrCpuid()] = TRUE; //当前CPU执行切到用户态
1207 } else {
1208 g_minAddr = KERNEL_ASPACE_BASE; //可访问地址范围的开始地址
1209 g_maxAddr = KERNEL_ASPACE_BASE + KERNEL_ASPACE_SIZE; //可访问地址范围的结束地址
1210 g_excFromUserMode[ArchCurrCpuid()] = FALSE; //当前CPU执行切到内核态
1211 }
1212
1214
1215#ifdef LOSCFG_KERNEL_SMP
1216#ifdef LOSCFG_FS_VFS
1217 /* Wait for the end of the Console task to avoid multicore printing code */
1218 OsWaitConsoleSendTaskPend(OsCurrTaskGet()->taskID); //等待控制台任务结束,以避免多核打印代码
1219#endif
1220#endif
1221}
VOID OsWaitConsoleSendTaskPend(UINT32 taskID)
Definition: console.c:1633
STATIC UINTPTR g_maxAddr
Definition: los_exc.c:125
STATIC UINTPTR g_minAddr
Definition: los_exc.c:124
STATIC VOID OsCheckCpuStatus(VOID)
Definition: los_exc.c:1192
函数调用图:
这是这个函数的调用关系图:

◆ OsExcRegHookGet()

EXC_PROC_FUNC OsExcRegHookGet ( VOID  )

获取hook函数

在文件 los_exc.c509 行定义.

510{
511 return g_excHook;
512}

◆ OsExcRegsInfo()

STATIC VOID OsExcRegsInfo ( const ExcContext excBufAddr)

异常情况下打印各寄存器的信息

参数
excBufAddr
返回
STATIC

在文件 los_exc.c471 行定义.

472{
473 /*
474 * Split register information into two parts:
475 * Ensure printing does not rely on memory modules.
476 */
477 //将寄存器信息分为两部分:确保打印不依赖内存模块。
478 PrintExcInfo("R0 = 0x%x\n"
479 "R1 = 0x%x\n"
480 "R2 = 0x%x\n"
481 "R3 = 0x%x\n"
482 "R4 = 0x%x\n"
483 "R5 = 0x%x\n"
484 "R6 = 0x%x\n",
485 excBufAddr->R0, excBufAddr->R1, excBufAddr->R2, excBufAddr->R3,
486 excBufAddr->R4, excBufAddr->R5, excBufAddr->R6);
487 PrintExcInfo("R7 = 0x%x\n"
488 "R8 = 0x%x\n"
489 "R9 = 0x%x\n"
490 "R10 = 0x%x\n"
491 "R11 = 0x%x\n"
492 "R12 = 0x%x\n"
493 "CPSR = 0x%x\n",
494 excBufAddr->R7, excBufAddr->R8, excBufAddr->R9, excBufAddr->R10,
495 excBufAddr->R11, excBufAddr->R12, excBufAddr->regCPSR);
496}
UINT32 R1
Definition: los_exc.h:82
UINT32 R9
Definition: los_exc.h:73
UINT32 R3
Definition: los_exc.h:84
UINT32 R7
Definition: los_exc.h:71
UINT32 R10
Definition: los_exc.h:74
UINT32 R5
Definition: los_exc.h:69
UINT32 R8
Definition: los_exc.h:72
UINT32 R6
Definition: los_exc.h:70
UINT32 R2
Definition: los_exc.h:83
函数调用图:
这是这个函数的调用关系图:

◆ OsExcRestore()

STATIC VOID OsExcRestore ( VOID  )

异常恢复,继续执行

在文件 los_exc.c638 行定义.

639{
640 UINT32 currCpuid = ArchCurrCpuid();
641
642 g_excFromUserMode[currCpuid] = FALSE;
643 g_intCount[currCpuid] = 0;
644 g_curNestCount[currCpuid] = 0;
645#ifdef LOSCFG_KERNEL_SMP
647#endif
649}
size_t g_intCount[LOSCFG_KERNEL_CORE_NUM]
记录每个CPUcore的中断数量
Definition: los_hwi.c:153
@ CPU_RUNNING
cpu is running | CPU正在运行状态
STATIC INLINE VOID OsSchedLockSet(UINT32 count)
函数调用图:
这是这个函数的调用关系图:

◆ OsExcSysInfo()

STATIC VOID OsExcSysInfo ( UINT32  excType,
const ExcContext excBufAddr 
)

打印异常系统信息

参数
excType
excBufAddr
返回
STATIC

在文件 los_exc.c401 行定义.

402{
403 LosTaskCB *runTask = OsCurrTaskGet(); //获取当前任务
404 LosProcessCB *runProcess = OsCurrProcessGet(); //获取当前进程
405
406 PrintExcInfo("excType: %s\n"
407 "processName = %s\n"
408 "processID = %u\n"
409#ifdef LOSCFG_KERNEL_VM
410 "process aspace = 0x%08x -> 0x%08x\n"
411#endif
412 "taskName = %s\n"
413 "taskID = %u\n",
414 g_excTypeString[excType],
415 runProcess->processName,
416 runProcess->processID,
417#ifdef LOSCFG_KERNEL_VM
418 runProcess->vmSpace->base,
419 runProcess->vmSpace->base + runProcess->vmSpace->size,
420#endif
421 runTask->taskName,
422 runTask->taskID);
423 //这里可以看出一个任务有两个运行栈空间
424#ifdef LOSCFG_KERNEL_VM
425 if (OsProcessIsUserMode(runProcess)) { //用户态栈空间,对于栈而言,栈底的地址要小于栈顶的地址
426 PrintExcInfo("task user stack = 0x%08x -> 0x%08x\n", //用户态栈空间由用户空间提供
427 runTask->userMapBase, runTask->userMapBase + runTask->userMapSize);
428 } else
429#endif
430 {
431 PrintExcInfo("task kernel stack = 0x%08x -> 0x%08x\n", //
432 runTask->topOfStack, runTask->topOfStack + runTask->stackSize);
433 }
434
435 PrintExcInfo("pc = 0x%x ", excBufAddr->PC);
436#ifdef LOSCFG_KERNEL_VM
437 LosVmMapRegion *region = NULL;
438 if (g_excFromUserMode[ArchCurrCpuid()] == TRUE) { //当前CPU处于用户模式
439 if (LOS_IsUserAddress((vaddr_t)excBufAddr->PC)) { //pc寄存器处于用户空间
440 region = LOS_RegionFind(runProcess->vmSpace, (VADDR_T)excBufAddr->PC); //找到所在线性区
441 if (region != NULL) {
442 PrintExcInfo("in %s ---> 0x%x", OsGetRegionNameOrFilePath(region),
443 (VADDR_T)excBufAddr->PC - OsGetTextRegionBase(region, runProcess));
444 }
445 }
446
447 PrintExcInfo("\nulr = 0x%x ", excBufAddr->ULR); //打印用户模式下程序的返回地址
448 region = LOS_RegionFind(runProcess->vmSpace, (VADDR_T)excBufAddr->ULR); //通过返回地址找到线性区
449 if (region != NULL) {
450 PrintExcInfo("in %s ---> 0x%x", OsGetRegionNameOrFilePath(region),
451 (VADDR_T)excBufAddr->ULR - OsGetTextRegionBase(region, runProcess));
452 }
453 PrintExcInfo("\nusp = 0x%x", excBufAddr->USP); //打印用户模式下栈指针
454 } else
455#endif
456 {
457 PrintExcInfo("\nklr = 0x%x\n" //注意:只有一个内核空间和内核堆空间,而每个用户进程就有自己独立的用户空间。
458 "ksp = 0x%x\n", //用户空间的虚拟地址范围是一样的,只是映射到不同的物理内存页。
459 excBufAddr->LR, //直接打印程序的返回地址
460 excBufAddr->SP); //直接打印栈指针
461 }
462
463 PrintExcInfo("\nfp = 0x%x\n", excBufAddr->R11);
464}
STATIC const CHAR * g_excTypeString[]
Definition: los_exc.c:346
STATIC VADDR_T OsGetTextRegionBase(LosVmMapRegion *region, LosProcessCB *runProcess)
Definition: los_exc.c:359
const CHAR * OsGetRegionNameOrFilePath(LosVmMapRegion *region)
Definition: los_vm_dump.c:57
STATIC INLINE BOOL LOS_IsUserAddress(VADDR_T vaddr)
虚拟地址是否在用户空间
Definition: los_vm_map.h:275
LosVmMapRegion * LOS_RegionFind(LosVmSpace *vmSpace, VADDR_T addr)
查找线性区 根据起始地址在进程空间内查找是否存在
Definition: los_vm_map.c:414
UINT32 ULR
Definition: los_exc.h:80
UINT64 LR
Definition: los_exc.h:61
UINT32 USP
Definition: los_exc.h:79
CHAR processName[OS_PCB_NAME_LEN]
UINT32 taskID
CHAR taskName[OS_TCB_NAME_LEN]
VADDR_T base
Definition: los_vm_map.h:150
UINT32 size
Definition: los_vm_map.h:151
函数调用图:
这是这个函数的调用关系图:

◆ OsExcType()

STATIC VOID OsExcType ( UINT32  excType,
ExcContext excBufAddr,
UINT32  far,
UINT32  fsr 
)

异常类型

在文件 los_exc.c326 行定义.

327{
328 /* undefinited exception handling or software interrupt | 未定义的异常处理或软件中断 */
329 if ((excType == OS_EXCEPT_UNDEF_INSTR) || (excType == OS_EXCEPT_SWI)) {
330 if ((excBufAddr->regCPSR & INSTR_SET_MASK) == 0) { /* work status: ARM */
331 excBufAddr->PC = excBufAddr->PC - ARM_INSTR_LEN;
332 } else if ((excBufAddr->regCPSR & INSTR_SET_MASK) == 0x20) { /* work status: Thumb */
333 excBufAddr->PC = excBufAddr->PC - THUMB_INSTR_LEN;
334 }
335 }
336
337 if (excType == OS_EXCEPT_PREFETCH_ABORT) { //取指异常
338 PrintExcInfo("prefetch_abort fault fsr:0x%x, far:0x%0+8x\n", fsr, far);
339 (VOID) OsDecodeInstructionFSR(fsr);
340 } else if (excType == OS_EXCEPT_DATA_ABORT) { // 数据异常
341 PrintExcInfo("data_abort fsr:0x%x, far:0x%0+8x\n", fsr, far);
342 (VOID) OsDecodeDataFSR(fsr);
343 }
344}
STATIC INT32 OsDecodeDataFSR(UINT32 regDFSR)
Definition: los_exc.c:231
STATIC INT32 OsDecodeInstructionFSR(UINT32 regIFSR)
Definition: los_exc.c:222
函数调用图:
这是这个函数的调用关系图:

◆ OsGetSystemStatus()

UINT32 OsGetSystemStatus ( VOID  )

获取系统状态

在文件 los_exc.c181 行定义.

182{
183 UINT32 flag;
184 UINT32 cpuid = g_currHandleExcCpuid; //全局变量 当前执行CPU ID
185
186 if (cpuid == INVALID_CPUID) { //当前CPU处于空闲状态的情况
187 flag = OS_SYSTEM_NORMAL;
188 } else if (cpuid == ArchCurrCpuid()) { //碰到了正在执行此处代码的CPU core
189 flag = OS_SYSTEM_EXC_CURR_CPU; //当前CPU
190 } else {
191 flag = OS_SYSTEM_EXC_OTHER_CPU; //其他CPU
192 }
193
194 return flag;
195}
函数调用图:
这是这个函数的调用关系图:

◆ OsGetTextRegionBase()

STATIC VADDR_T OsGetTextRegionBase ( LosVmMapRegion region,
LosProcessCB runProcess 
)

在文件 los_exc.c359 行定义.

360{
361 struct Vnode *curVnode = NULL;
362 struct Vnode *lastVnode = NULL;
363 LosVmMapRegion *curRegion = NULL;
364 LosVmMapRegion *lastRegion = NULL;
365
366 if ((region == NULL) || (runProcess == NULL)) {
367 return 0;
368 }
369
370 if (!LOS_IsRegionFileValid(region)) {
371 return region->range.base;
372 }
373
374 lastRegion = region;
375 do {
376 curRegion = lastRegion;
377 lastRegion = LOS_RegionFind(runProcess->vmSpace, curRegion->range.base - 1);
378 if ((lastRegion == NULL) || !LOS_IsRegionFileValid(lastRegion)) {
379 goto DONE;
380 }
381 curVnode = curRegion->unTypeData.rf.vnode;
382 lastVnode = lastRegion->unTypeData.rf.vnode;
383 } while (curVnode == lastVnode);
384
385DONE:
386#ifdef LOSCFG_KERNEL_DYNLOAD
387 if (curRegion->range.base == EXEC_MMAP_BASE) {
388 return 0;
389 }
390#endif
391 return curRegion->range.base;
392}
BOOL LOS_IsRegionFileValid(LosVmMapRegion *region)
映射类型为文件的线性区是否有效
Definition: los_vm_map.c:512
struct VmMapRegion::@4::VmRegionFile rf
union VmMapRegion::@4 unTypeData
vnode并不包含文件名,因为 vnode和文件名是 1:N 的关系
Definition: vnode.h:164
函数调用图:
这是这个函数的调用关系图:

◆ OsGetUsrIpInfo()

BOOL OsGetUsrIpInfo ( UINTPTR  ip,
IpInfo info 
)

在文件 los_exc.c804 行定义.

805{
806 if (info == NULL) {
807 return FALSE;
808 }
809#ifdef LOSCFG_KERNEL_VM
810 BOOL ret = FALSE;
811 const CHAR *name = NULL;
812 LosVmMapRegion *region = NULL;
813 LosProcessCB *runProcess = OsCurrProcessGet();
814
815 if (LOS_IsUserAddress((VADDR_T)ip) == FALSE) {
816 info->ip = ip;
817 name = "kernel";
818 ret = FALSE;
819 goto END;
820 }
821
822 region = LOS_RegionFind(runProcess->vmSpace, (VADDR_T)ip);
823 if (region == NULL) {
824 info->ip = ip;
825 name = "invalid";
826 ret = FALSE;
827 goto END;
828 }
829
830 info->ip = ip - OsGetTextRegionBase(region, runProcess);
831 name = OsGetRegionNameOrFilePath(region);
832 ret = TRUE;
833 if (strcmp(name, "/lib/libc.so") != 0) {
834 PRINT_ERR("ip = 0x%x, %s\n", info->ip, name);
835 }
836END:
837 info->len = strlen(name);
838 if (strncpy_s(info->f_path, REGION_PATH_MAX, name, REGION_PATH_MAX - 1) != EOK) {
839 info->f_path[0] = '\0';
840 info->len = 0;
841 PRINT_ERR("copy f_path failed, %s\n", name);
842 }
843 return ret;
844#else
845 info->ip = ip;
846 return FALSE;
847#endif
848}
UINT32 len
Definition: los_exc_pri.h:52
函数调用图:
这是这个函数的调用关系图:

◆ OsPrefetchAbortExcHandleEntry()

VOID OsPrefetchAbortExcHandleEntry ( ExcContext excBufAddr)

预取指令异常处理函数,由汇编调用 见于 los_hw_exc.s

在文件 los_exc.c1053 行定义.

1054{
1055 UINT32 far;
1056 UINT32 fsr;
1057
1058 excBufAddr->PC -= 4; /* lr in prefetch abort is pc + 4 */
1059
1060 if (gdbhw_hook(excBufAddr, OS_EXCEPT_PREFETCH_ABORT)) {
1061 return;
1062 }
1063
1064 if (g_excHook != NULL) {
1065 far = OsArmReadIfar(); //far 为CP15的 C6寄存器 详见:https://blog.csdn.net/kuangyufei/article/details/108994081
1066 fsr = OsArmReadIfsr(); //fsr 为CP15的 C5寄存器
1067 g_excHook(OS_EXCEPT_PREFETCH_ABORT, excBufAddr, far, fsr); //回调函数,详见: OsExcHook
1068 }
1069 while (1) {}
1070}
STATIC INLINE UINT32 OsArmReadIfsr(VOID)
Definition: arm.h:156
STATIC INLINE UINT32 OsArmReadIfar(VOID)
Definition: arm.h:195
函数调用图:

◆ OsPrintExcHead()

LITE_OS_SEC_TEXT_INIT STATIC VOID OsPrintExcHead ( UINT32  far)

异常信息头部打印

在文件 los_exc.c1223 行定义.

1224{
1225#ifdef LOSCFG_BLACKBOX
1226#ifdef LOSCFG_SAVE_EXCINFO
1227 SetExcInfoIndex(0);
1228#endif
1229#endif
1230#ifdef LOSCFG_KERNEL_VM
1231 /* You are not allowed to add any other print information before this exception information */
1232 if (g_excFromUserMode[ArchCurrCpuid()] == TRUE) {
1233#ifdef LOSCFG_DEBUG_VERSION
1234 VADDR_T vaddr = ROUNDDOWN(far, PAGE_SIZE);
1235 LosVmSpace *space = LOS_SpaceGet(vaddr);
1236 if (space != NULL) {
1237 LOS_DumpMemRegion(vaddr);
1238 }
1239#endif
1240 PrintExcInfo("##################excFrom: User!####################\n"); //用户态异常信息说明
1241 } else
1242#endif
1243 {
1244 PrintExcInfo("##################excFrom: kernel!###################\n"); //内核态异常信息说明
1245 }
1246}
LosVmSpace * LOS_SpaceGet(VADDR_T vaddr)
获取虚拟地址对应的进程空间结构体指针
Definition: los_vm_map.c:117
VOID LOS_DumpMemRegion(VADDR_T vaddr)
输出内存线性区
函数调用图:
这是这个函数的调用关系图:

◆ OsSysStateRestore()

STATIC VOID OsSysStateRestore ( UINT32  intCount,
UINT32  lockCount 
)

在文件 los_exc.c1257 行定义.

1258{
1259 g_intCount[ArchCurrCpuid()] = intCount;
1260 OsSchedLockSet(lockCount);
1261}
函数调用图:
这是这个函数的调用关系图:

◆ OsSysStateSave()

STATIC VOID OsSysStateSave ( UINT32 intCount,
UINT32 lockCount 
)

在文件 los_exc.c1249 行定义.

1250{
1251 *intCount = g_intCount[ArchCurrCpuid()];
1252 *lockCount = OsSchedLockCountGet();
1254 OsSchedLockSet(0);
1255}
STATIC INLINE UINT32 OsSchedLockCountGet(VOID)
函数调用图:
这是这个函数的调用关系图:

◆ OsUndefIncExcHandleEntry()

VOID OsUndefIncExcHandleEntry ( ExcContext excBufAddr)

未定义的异常处理函数,由汇编调用 见于 los_hw_exc.s

在文件 los_exc.c1036 行定义.

1037{
1038 excBufAddr->PC -= 4; /* lr in undef is pc + 4 */
1039
1040 if (gdb_undef_hook(excBufAddr, OS_EXCEPT_UNDEF_INSTR)) {
1041 return;
1042 }
1043
1044 if (g_excHook != NULL) {//是否注册异常打印函数
1045 /* far, fsr are unused in exc type of OS_EXCEPT_UNDEF_INSTR */
1046 g_excHook(OS_EXCEPT_UNDEF_INSTR, excBufAddr, 0, 0); //回调函数,详见: OsExcHook
1047 }
1048 while (1) {}
1049}

◆ OsUserExcHandle()

STATIC VOID OsUserExcHandle ( ExcContext excBufAddr)

用户态异常处理函数

在文件 los_exc.c651 行定义.

652{
653 UINT32 intSave;
654 UINT32 currCpu = ArchCurrCpuid();
655 LosTaskCB *runTask = OsCurrTaskGet();
656 LosProcessCB *runProcess = OsCurrProcessGet();
657
658 if (g_excFromUserMode[ArchCurrCpuid()] == FALSE) { //内核态直接退出,不处理了.
659 return;
660 }
661
662#ifdef LOSCFG_KERNEL_SMP
663 LOS_SpinLock(&g_excSerializerSpin);
664 if (g_nextExcWaitCpu != INVALID_CPUID) {
666 g_nextExcWaitCpu = INVALID_CPUID;
667 } else {
668 g_currHandleExcCpuid = INVALID_CPUID;
669 }
670 g_currHandleExcPID = OS_INVALID_VALUE;
671 LOS_SpinUnlock(&g_excSerializerSpin);
672#else
673 g_currHandleExcCpuid = INVALID_CPUID;
674#endif
675
676#ifdef LOSCFG_KERNEL_SMP
677#ifdef LOSCFG_FS_VFS
679#endif
680#endif
681
682#ifdef LOSCFG_BLACKBOX
683 BBoxNotifyError("USER_CRASH", MODULE_SYSTEM, "Crash in user", 0);
684#endif
685 SCHEDULER_LOCK(intSave);
686#ifdef LOSCFG_SAVE_EXCINFO
688#endif
689 OsProcessExitCodeSignalSet(runProcess, SIGUSR2);
690
691 /* An exception was raised by a task that is not the current main thread during the exit process of
692 * the current process.
693 */
694 if (runProcess->processStatus & OS_PROCESS_FLAG_EXIT) {
695 SCHEDULER_UNLOCK(intSave);
696 /* Exception handling All operations should be kept prior to that operation */
697 OsExcRestore();
698 OsRunningTaskToExit(runTask, OS_PRO_EXIT_OK);
699 } else {
700 SCHEDULER_UNLOCK(intSave);
701
702 /* Exception handling All operations should be kept prior to that operation */
703 OsExcRestore();
704 /* kill user exc process */
705 LOS_Exit(OS_PRO_EXIT_OK); //进程退出
706 }
707
708 /* User mode exception handling failed , which normally does not exist */ //用户态的异常处理失败,通常情况下不会发生
709 g_curNestCount[currCpu]++;
710 g_intCount[currCpu]++;
711 PrintExcInfo("User mode exception ends unscheduled!\n");
712}
VOID OsWakeConsoleSendTask(VOID)
唤醒控制台发送任务
Definition: console.c:1658
STATIC UINT32 g_nextExcWaitCpu
Definition: los_exc.c:134
LITE_OS_SEC_TEXT VOID LOS_Exit(INT32 status)
LOS_Exit 进程退出
Definition: los_process.c:2086
STATIC INLINE VOID OsProcessExitCodeSignalSet(LosProcessCB *processCB, UINT32 signal)
设置进程退出信号(0 ~ 7)
STATIC INLINE VOID OsProcessExitCodeCoreDumpSet(LosProcessCB *processCB)
置进程退出码第七位为1
LITE_OS_SEC_TEXT VOID OsRunningTaskToExit(LosTaskCB *runTask, UINT32 status)
Definition: los_task.c:908
UINT16 processStatus
函数调用图:
这是这个函数的调用关系图:

◆ OsWaitOtherCoresHandleExcEnd()

STATIC VOID OsWaitOtherCoresHandleExcEnd ( UINT32  currCpuid)

在文件 los_exc.c1120 行定义.

1121{
1122 while (1) {
1123 LOS_SpinLock(&g_excSerializerSpin);
1124 if ((g_currHandleExcCpuid == INVALID_CPUID) || (g_currHandleExcCpuid == currCpuid)) {
1125 g_currHandleExcCpuid = currCpuid;
1127 LOS_SpinUnlock(&g_excSerializerSpin);
1128 break;
1129 }
1130
1131 if (g_nextExcWaitCpu == INVALID_CPUID) {
1132 g_nextExcWaitCpu = currCpuid;
1133 }
1134 LOS_SpinUnlock(&g_excSerializerSpin);
1135 LOS_Mdelay(EXC_WAIT_INTER);
1136 }
1137}
函数调用图:
这是这个函数的调用关系图:

◆ SPIN_LOCK_INIT()

STATIC SPIN_LOCK_INIT ( g_excSerializerSpin  )

◆ WaitAllCpuStop()

STATIC VOID WaitAllCpuStop ( UINT32  cpuid)

等待所有CPU停止

在文件 los_exc.c1099 行定义.

1100{
1101 UINT32 i;
1102 UINT32 time = 0;
1103
1104 while (time < EXC_WAIT_TIME) {
1105 for (i = 0; i < LOSCFG_KERNEL_CORE_NUM; i++) {
1106 if ((i != cpuid) && !OsCpuStatusIsHalt(i)) {
1107 LOS_Mdelay(EXC_WAIT_INTER);
1108 time += EXC_WAIT_INTER;
1109 break;
1110 }
1111 }
1112 /* Other CPUs are all haletd or in the exc. */
1113 if (i == LOSCFG_KERNEL_CORE_NUM) {
1114 break;
1115 }
1116 }
1117 return;
1118}
STATIC INLINE UINT32 OsCpuStatusIsHalt(UINT16 cpuid)
time_t time(time_t *t)
Definition: time.c:1224
函数调用图:
这是这个函数的调用关系图:

变量说明

◆ __stack_chk_guard

USED UINT32 __stack_chk_guard = 0xd00a0dff

在文件 los_exc.c1344 行定义.

◆ g_curNestCount

UINT32 g_curNestCount[LOSCFG_KERNEL_CORE_NUM] = {0}

记录当前嵌套异常的数量

在文件 los_exc.c128 行定义.

◆ g_currHandleExcCpuid

STATIC UINT32 g_currHandleExcCpuid = INVALID_CPUID

在文件 los_exc.c126 行定义.

◆ g_currHandleExcPID

STATIC UINT32 g_currHandleExcPID = OS_INVALID_VALUE

在文件 los_exc.c133 行定义.

◆ g_excFromUserMode

BOOL g_excFromUserMode[LOSCFG_KERNEL_CORE_NUM]

记录CPU core 异常来自用户态还是内核态 TRUE为用户态,默认为内核态

在文件 los_exc.c129 行定义.

◆ g_excHook

STATIC EXC_PROC_FUNC g_excHook = (EXC_PROC_FUNC)OsExcHook

全局异常处理钩子

在文件 los_exc.c130 行定义.

◆ g_excStack

STATIC const StackInfo g_excStack[]
初始值:
= {
{&__svc_stack, OS_EXC_SVC_STACK_SIZE, "svc_stack"},
{&__exc_stack, OS_EXC_STACK_SIZE, "exc_stack"}
}
UINTPTR __exc_stack
UINTPTR __svc_stack
   6种异常情况下对应的栈,每一种异常模式都有其独立的堆栈,用不同的堆栈指针来索引,
   这样当ARM进入异常模式的时候,程序就可以把一般通用寄存器压入堆栈,返回时再出栈,
   保证了各种模式下程序的状态的完整性

   用户模式,运行应用程序的普通模式。限制你的内存访问并且不能直接读取硬件设备。 
   超级用户模式(SVC 模式),主要用于 SWI(软件中断)和 OS(操作系统)。这个模式有额外的特权,
       允许你进一步控制计算机。例如,你必须进入超级用户模式来读取一个插件(podule)。
       这不能在用户模式下完成。 
   中断模式(IRQ 模式),用来处理发起中断的外设。这个模式也是有特权的。导致 IRQ 的设备有
       键盘、 VSync (在发生屏幕刷新的时候)、IOC 定时器、串行口、硬盘、软盘、等等... 
   快速中断模式(FIQ 模式),用来处理发起快速中断的外设。这个模式是有特权的。导致 FIQ 的设备有
       处理数据的软盘,串行端口。  
       
   IRQ 和 FIQ 之间的区别是对于 FIQ 你必须尽快处理你事情并离开这个模式。
   IRQ 可以被 FIQ 所中断但 IRQ 不能中断 FIQ
* 

在文件 los_exc.c176 行定义.

◆ g_excTypeString

STATIC const CHAR* g_excTypeString[]
初始值:
= {
"reset",
"undefined instruction",
"software interrupt",
"prefetch abort",
"data abort",
"fiq",
"address abort",
"irq"
}

在文件 los_exc.c346 行定义.

◆ g_maxAddr

STATIC UINTPTR g_maxAddr

在文件 los_exc.c125 行定义.

◆ g_minAddr

STATIC UINTPTR g_minAddr

在文件 los_exc.c124 行定义.

◆ g_nextExcWaitCpu

STATIC UINT32 g_nextExcWaitCpu = INVALID_CPUID

在文件 los_exc.c134 行定义.