diff --git a/arch/arm/arm/src/los_dispatch.S b/arch/arm/arm/src/los_dispatch.S index 1056ad16d8ccd5c5c707ea0aa5e72531ab568a73..6c56620b9f74b6caf441ff4fb25729c74c9e6456 100644 --- a/arch/arm/arm/src/los_dispatch.S +++ b/arch/arm/arm/src/los_dispatch.S @@ -42,28 +42,28 @@ .global OsIrqHandler /*硬中断处理*/ .global ArchSpinUnlock /*自旋锁解锁*/ .global OsSchedToUserSpinUnlock /*尚未实现*/ - + /* @note_why 为何要重新定义OS_TASK_STATUS_RUNNING? */ .equ OS_TASK_STATUS_RUNNING, 0x0010U /* .equ用于把常量值设置为可以在文本段中使用的符号 #define OS_TASK_STATUS_RUNNING 0x0010U */ .equ OS_PERCPU_STRUCT_SIZE, 0x28U .equ OS_PERCPU_TASK_LOCK_OFFSET, 0x14U .fpu vfpv4 /* .fpu @note_why 尚未知这句话的含义 */ /* 此宏用于对齐和不对齐8字节边界上的堆栈以符合ABI */ /* macros to align and unalign the stack on 8 byte boundary for ABI compliance */ -.macro STACK_ALIGN, reg /* 汇编带参数的宏定义*/ - MOV \reg, sp +.macro STACK_ALIGN, reg /* 栈对齐*/ + MOV \reg, sp TST SP, #4 SUBEQ SP, #4 PUSH { \reg } .endm -.macro STACK_RESTORE, reg /*汇编带参数的宏定义*/ - POP { \reg } @ - MOV sp, \reg +.macro STACK_RESTORE, reg /*栈恢复*/ + POP { \reg } + MOV sp, \reg .endm - -/* macros to save and restore fpu regs */ -.macro PUSH_FPU_REGS reg1 /* 汇编宏定义,类似于 #define PUSH_FPU_REGS(reg1) ... */ -#if !defined(LOSCFG_ARCH_FPU_DISABLE) +/* FPU(floating-point processor unit)浮点运算单元*/ +/* macros to save and restore fpu regs */ +.macro PUSH_FPU_REGS reg1 /* 保存fpu寄存器 */ +#if !defined(LOSCFG_ARCH_FPU_DISABLE) @FPU使能 VMRS \reg1, FPEXC PUSH {\reg1} VMRS \reg1, FPSCR @@ -75,7 +75,7 @@ #endif .endm -.macro POP_FPU_REGS reg1 +.macro POP_FPU_REGS reg1 /* 恢复fpu寄存器 */ #if !defined(LOSCFG_ARCH_FPU_DISABLE) VPOP {D0-D15} #if defined(LOSCFG_ARCH_FPU_VFP_D32) @@ -94,12 +94,12 @@ OsStartToRun: MSR CPSR_c, #(CPSR_INT_DISABLE | CPSR_SVC_MODE) @禁止中断并切到管理模式 LDRH R1, [R0, #4] @将存储器地址为R0+4 的低16位数据读入寄存器R1,并将R1 的高16 位清零 - ORR R1, #OS_TASK_STATUS_RUNNING - STRH R1, [R0, #4] + ORR R1, #OS_TASK_STATUS_RUNNING @或指令 R1=R1|OS_TASK_STATUS_RUNNING + STRH R1, [R0, #4] @将寄存器R1中的低16位写入以R0+4地址的存储器中 /* R0 is new task, save it on tpidrprw */ - MCR p15, 0, R0, c13, c0, 4 - ISB + MCR p15, 0, R0, c13, c0, 4 @ C5=C4=R0 + ISB @指令同步屏障,清除流水线并且确保在新指令执行时,之前的指令都已经执行完毕。 VPUSH {S0} /* fpu */ VPOP {S0} @@ -149,15 +149,15 @@ OsTaskContextLoad: MOV R4, R0 @R4=R0 说明R4也记录了CPSR内容,这个内容将用于 OsKernelTaskLoad中保存到SPSR AND R0, R0, #CPSR_MASK_MODE @R0 =R0&CPSR_MASK_MODE ,目的是清除高16位 CMP R0, #CPSR_USER_MODE @比较R0是否为用户模式 - BNE OsKernelTaskLoad @不相等则跳转到OsKernelTaskLoad执行 + BNE OsKernelTaskLoad @不相等则跳转到OsKernelTaskLoad执行,return回去了 #ifdef LOSCFG_KERNEL_SMP #ifdef LOSCFG_KERNEL_SMP_LOCKDEP /* 8 bytes stack align */ - SUB SP, SP, #4 - LDR R0, =g_taskSpin - BL OsLockDepCheckOut - ADD SP, SP, #4 + SUB SP, SP, #4 @sp = sp -4 + LDR R0, =g_taskSpin @R0 = g_taskSpin + BL OsLockDepCheckOut @带链接的跳转指令。指令将下一条指令的地址拷贝到R14(即LR)链接寄存器中,然后跳转到指定地址运行程序 + ADD SP, SP, #4 @sp=sp+4 #endif /* R0 = &g_taskSpin.rawLock */ LDR R0, =g_taskSpin @@ -181,12 +181,12 @@ OsTaskContextLoad: ADD SP, SP, #(2 * 4) LDMFD SP!, {PC}^ -OsKernelTaskLoad: @内核任务的加载 - MSR SPSR_cxsf, R4 @将R4保存到程序状态保存寄存器32位 +OsKernelTaskLoad: @内核任务的加载 + MSR SPSR_cxsf, R4 @将R4保存到程序状态保存寄存器32位 /* restore r0-r12, lr */ - LDMFD SP!, {R0-R12} @出栈,依次保存到 R0-R12,其实就是恢复现场 - ADD SP, SP, #4 @sp=SP+4 - LDMFD SP!, {LR, PC}^ @返回地址赋给pc指针 + LDMFD SP!, {R0-R12} @出栈,依次保存到 R0-R12,其实就是恢复现场 + ADD SP, SP, #4 @sp=SP+4 + LDMFD SP!, {LR, PC}^ @返回地址赋给pc指针 OsIrqHandler: SUB LR, LR, #4 diff --git a/arch/arm/arm/src/los_exc.c b/arch/arm/arm/src/los_exc.c index ef4ea396ca4c765e1bd930d3321fbdb22ff5f3a7..d22b5917e5453b141e7e47059f5a5d76f55158b1 100644 --- a/arch/arm/arm/src/los_exc.c +++ b/arch/arm/arm/src/los_exc.c @@ -285,14 +285,14 @@ STATIC VOID OsExcType(UINT32 excType, ExcContext *excBufAddr, UINT32 far, UINT32 } STATIC const CHAR *g_excTypeString[] = {//异常类型的字符说明,在鸿蒙内核中什么才算是异常? 看这里 - "reset", //重置命令 - "undefined instruction", //未定义的指令 - "software interrupt", //软中断,比如定时器 - "prefetch abort", //取指异常 - "data abort", //数据异常 - "fiq", //快中断异常 - "address abort", //地址异常 - "irq" //中断异常 + "reset", //复位异常源 - SVC模式(Supervisor保护模式) + "undefined instruction", //未定义指令异常源- und模式 + "software interrupt", //软中断异常源 - SVC模式 + "prefetch abort", //取指异常源 - abort模式 + "data abort", //数据异常源 - abort模式 + "fiq", //快中断异常源 - FIQ模式 + "address abort", //地址异常源 - abort模式 + "irq" //中断异常源 - IRQ模式 }; //打印系统信息 STATIC VOID OsExcSysInfo(UINT32 excType, const ExcContext *excBufAddr) @@ -705,7 +705,7 @@ VOID BackTrace(UINT32 regFP)//fp:R11寄存器 BackTraceSub(regFP); } -//异常处理模块的初始化 +//异常接管模块的初始化 VOID OsExcInit(VOID) { OsExcStackInfoReg(g_excStack, sizeof(g_excStack) / sizeof(g_excStack[0]));//异常模式下注册内核栈信息 diff --git a/arch/arm/arm/src/startup/reset_vector_up.S b/arch/arm/arm/src/startup/reset_vector_up.S index 00c14d95cb18fceaba12105a3e4c7dfff3988935..42d0eeafee70b110249589aa25432ee6880b0431 100644 --- a/arch/arm/arm/src/startup/reset_vector_up.S +++ b/arch/arm/arm/src/startup/reset_vector_up.S @@ -36,6 +36,10 @@ #include "los_mmu_descriptor_v6.h" #undef ASSEMBLY +/****************************************************************************** +单CPU下异常向量表 + +******************************************************************************/ .global __exc_stack_top .global __irq_stack_top @@ -68,16 +72,16 @@ .fpu vfpv4 .arm - +/* 设置异常模式栈的SP 参数1为栈底, 参数2为栈大小 r11 存放的是 cpu id */ /* param0 is stack bottom, param1 is stack size, r11 hold cpu id */ .macro EXC_SP_SET param0, param1 - ldr r1, =\param0 - mov r0, \param1 - bl sp_set + ldr r1, =\param0 @r1 = 栈底 + mov r0, \param1 @r0 = 栈大小 + bl sp_set @跳到设置SP处 .endm /* param0 is stack top, param1 is stack size, param2 is magic num */ -.macro STACK_MAGIC_SET param0, param1, param2 +.macro STACK_MAGIC_SET param0, param1, param2 @设置栈魔法数字 ldr r0, =\param0 mov r1, \param1 ldr r2, =\param2 @@ -332,12 +336,12 @@ cpu_start: /* 启动CPU */ /* * set sp for current cpu * r1 is stack bottom, r0 is stack size, r11 hold cpu id - */ + */@设置当前CPU的SP, r1为栈底, r0为栈大小 r11 为 cpu id sp_set: - mul r3, r0, r11 - sub r2, r1, r3 - mov sp, r2 - bx lr /* set sp */ + mul r3, r0, r11 @r3=r0*r11 先计算偏移量 + sub r2, r1, r3 @r2=r1-r3 如此得到r2为cpu的SP位置,从这里可以看出 栈底地址是要高于栈顶的 + mov sp, r2 @sp = r2 设置栈指针位置,SP默认指向了栈底 + bx lr /* set sp */ @跳回去继续执行 /* * r4: page table base address @@ -468,6 +472,6 @@ __svc_stack: .space OS_EXC_SVC_STACK_SIZE * CORE_NUM __svc_stack_top: -__exc_stack: +__exc_stack: .space OS_EXC_STACK_SIZE * CORE_NUM __exc_stack_top: diff --git a/kernel/base/misc/los_stackinfo.c b/kernel/base/misc/los_stackinfo.c index 94a722d4028875abf9d0ba69ef6fc0c4d6c51278..418be0d15dfe2332411cde1cbfb97b2a98d585ca 100644 --- a/kernel/base/misc/los_stackinfo.c +++ b/kernel/base/misc/los_stackinfo.c @@ -1,146 +1,146 @@ -/* - * Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved. - * Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without modification, - * are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright notice, this list of - * conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright notice, this list - * of conditions and the following disclaimer in the documentation and/or other materials - * provided with the distribution. - * - * 3. Neither the name of the copyright holder nor the names of its contributors may be used - * to endorse or promote products derived from this software without specific prior written - * permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, - * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR - * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR - * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, - * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; - * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, - * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR - * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#include "los_stackinfo_pri.h" -#include "los_printf_pri.h" -#include "los_config.h" -#ifdef LOSCFG_SHELL -#include "shcmd.h" -#include "shell.h" -#endif - -const StackInfo *g_stackInfo = NULL; -UINT32 g_stackNum; -//获取栈的吃水线 -UINT32 OsStackWaterLineGet(const UINTPTR *stackBottom, const UINTPTR *stackTop, UINT32 *peakUsed) -{ - UINT32 size; - const UINTPTR *tmp = NULL; - if (*stackTop == OS_STACK_MAGIC_WORD) {//栈顶值是否等于 magic 0xCCCCCCCC - tmp = stackTop + 1; - while ((tmp < stackBottom) && (*tmp == OS_STACK_INIT)) {//记录从栈顶到栈低有多少个连续的 0xCACACACA - tmp++; - } - size = (UINT32)((UINTPTR)stackBottom - (UINTPTR)tmp);//剩余多少非0xCACACACA的栈空间 - *peakUsed = (size == 0) ? size : (size + sizeof(CHAR *));//得出高峰用值,还剩多少可用 - return LOS_OK; - } else { - *peakUsed = OS_INVALID_WATERLINE;//栈溢出了 - return LOS_NOK; - } -} -//异常情况下的栈检查,主要就是检查栈顶值有没有被改写 -VOID OsExcStackCheck(VOID) -{ - UINT32 index; - UINT32 cpuid; - UINTPTR *stackTop = NULL; - - if (g_stackInfo == NULL) { - return; - } - for (index = 0; index < g_stackNum; index++) { - for (cpuid = 0; cpuid < LOSCFG_KERNEL_CORE_NUM; cpuid++) { - stackTop = (UINTPTR *)((UINTPTR)g_stackInfo[index].stackTop + cpuid * g_stackInfo[index].stackSize); - if (*stackTop != OS_STACK_MAGIC_WORD) {// 只要栈顶内容不是 0xCCCCCCCCC 就是溢出了. - PRINT_ERR("cpu:%u %s overflow , magic word changed to 0x%x\n", - LOSCFG_KERNEL_CORE_NUM - 1 - cpuid, g_stackInfo[index].stackName, *stackTop); - } - } - } -} -//打印栈的信息 把每个CPU的栈信息打印出来 -VOID OsExcStackInfo(VOID) -{ - UINT32 index; - UINT32 cpuid; - UINT32 size; - UINTPTR *stackTop = NULL; - UINTPTR *stack = NULL; - - if (g_stackInfo == NULL) { - return; - } - - PrintExcInfo("\n stack name cpu id stack addr total size used size\n" - " ---------- ------ --------- -------- --------\n"); - for (index = 0; index < g_stackNum; index++) { - for (cpuid = 0; cpuid < LOSCFG_KERNEL_CORE_NUM; cpuid++) {//可以看出 各个CPU的栈是紧挨的的 - stackTop = (UINTPTR *)((UINTPTR)g_stackInfo[index].stackTop + cpuid * g_stackInfo[index].stackSize); - stack = (UINTPTR *)((UINTPTR)stackTop + g_stackInfo[index].stackSize); - (VOID)OsStackWaterLineGet(stack, stackTop, &size);//获取吃水线, 鸿蒙用WaterLine 这个词用的很妙 - - PrintExcInfo("%11s %-5d %-10p 0x%-8x 0x%-4x\n", g_stackInfo[index].stackName, - LOSCFG_KERNEL_CORE_NUM - 1 - cpuid, stackTop, g_stackInfo[index].stackSize, size); - } - } - - OsExcStackCheck();//发生异常时栈检查 -} -/*************************************************************************************** @note_pic - OsExcStackInfo 各个CPU栈布局图,其他栈也是一样,CPU各核硬件栈都是紧挨着 - __undef_stack(SMP) -+-------------------+ <--- cpu1 top -| | -| CPU core1 | -| | -+--------------------<--- cpu2 top -| | -| cpu core 2 | -| | -+--------------------<--- cpu3 top -| | -| cpu core 3 | -| | -+--------------------<--- cpu4 top -| | -| cpu core 4 | -| | -+-------------------+ -******************************************************************************************/ - -//注册栈信息 -VOID OsExcStackInfoReg(const StackInfo *stackInfo, UINT32 stackNum) -{ - g_stackInfo = stackInfo; //g_excStack - g_stackNum = stackNum; -} -//task栈的初始化,设置固定的值. 0xcccccccc 和 0xcacacaca -VOID OsStackInit(VOID *stacktop, UINT32 stacksize) -{ - /* initialize the task stack, write magic num to stack top */ - (VOID)memset_s(stacktop, stacksize, (INT32)OS_STACK_INIT, stacksize);//清一色填 0xCACACACA - *((UINTPTR *)stacktop) = OS_STACK_MAGIC_WORD;//0xCCCCCCCCC 中文就是"烫烫烫烫" 这几个字懂点计算机的人都不会陌生了. -} - -#ifdef LOSCFG_SHELL_CMD_DEBUG -SHELLCMD_ENTRY(stack_shellcmd, CMD_TYPE_EX, "stack", 1, (CmdCallBackFunc)OsExcStackInfo);//采用shell命令静态注册方式 -#endif +/* + * Copyright (c) 2013-2019, Huawei Technologies Co., Ltd. All rights reserved. + * Copyright (c) 2020, Huawei Device Co., Ltd. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without modification, + * are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, this list + * of conditions and the following disclaimer in the documentation and/or other materials + * provided with the distribution. + * + * 3. Neither the name of the copyright holder nor the names of its contributors may be used + * to endorse or promote products derived from this software without specific prior written + * permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, + * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; + * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR + * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "los_stackinfo_pri.h" +#include "los_printf_pri.h" +#include "los_config.h" +#ifdef LOSCFG_SHELL +#include "shcmd.h" +#include "shell.h" +#endif + +const StackInfo *g_stackInfo = NULL; //CPU所有工作模式的栈信息 +UINT32 g_stackNum; //CPU所有工作模式的栈数量 +//获取栈的吃水线 +UINT32 OsStackWaterLineGet(const UINTPTR *stackBottom, const UINTPTR *stackTop, UINT32 *peakUsed) +{ + UINT32 size; + const UINTPTR *tmp = NULL; + if (*stackTop == OS_STACK_MAGIC_WORD) {//栈顶值是否等于 magic 0xCCCCCCCC + tmp = stackTop + 1; + while ((tmp < stackBottom) && (*tmp == OS_STACK_INIT)) {//记录从栈顶到栈低有多少个连续的 0xCACACACA + tmp++; + } + size = (UINT32)((UINTPTR)stackBottom - (UINTPTR)tmp);//剩余多少非0xCACACACA的栈空间 + *peakUsed = (size == 0) ? size : (size + sizeof(CHAR *));//得出高峰用值,还剩多少可用 + return LOS_OK; + } else { + *peakUsed = OS_INVALID_WATERLINE;//栈溢出了 + return LOS_NOK; + } +} +//异常情况下的栈检查,主要就是检查栈顶值有没有被改写 +VOID OsExcStackCheck(VOID) +{ + UINT32 index; + UINT32 cpuid; + UINTPTR *stackTop = NULL; + + if (g_stackInfo == NULL) { + return; + } + for (index = 0; index < g_stackNum; index++) { + for (cpuid = 0; cpuid < LOSCFG_KERNEL_CORE_NUM; cpuid++) { + stackTop = (UINTPTR *)((UINTPTR)g_stackInfo[index].stackTop + cpuid * g_stackInfo[index].stackSize); + if (*stackTop != OS_STACK_MAGIC_WORD) {// 只要栈顶内容不是 0xCCCCCCCCC 就是溢出了. + PRINT_ERR("cpu:%u %s overflow , magic word changed to 0x%x\n", + LOSCFG_KERNEL_CORE_NUM - 1 - cpuid, g_stackInfo[index].stackName, *stackTop); + } + } + } +} +//打印栈的信息 把每个CPU的栈信息打印出来 +VOID OsExcStackInfo(VOID) +{ + UINT32 index; + UINT32 cpuid; + UINT32 size; + UINTPTR *stackTop = NULL; + UINTPTR *stack = NULL; + + if (g_stackInfo == NULL) { + return; + } + + PrintExcInfo("\n stack name cpu id stack addr total size used size\n" + " ---------- ------ --------- -------- --------\n"); + for (index = 0; index < g_stackNum; index++) { + for (cpuid = 0; cpuid < LOSCFG_KERNEL_CORE_NUM; cpuid++) {//可以看出 各个CPU的栈是紧挨的的 + stackTop = (UINTPTR *)((UINTPTR)g_stackInfo[index].stackTop + cpuid * g_stackInfo[index].stackSize); + stack = (UINTPTR *)((UINTPTR)stackTop + g_stackInfo[index].stackSize); + (VOID)OsStackWaterLineGet(stack, stackTop, &size);//获取吃水线, 鸿蒙用WaterLine 这个词用的很妙 + + PrintExcInfo("%11s %-5d %-10p 0x%-8x 0x%-4x\n", g_stackInfo[index].stackName, + LOSCFG_KERNEL_CORE_NUM - 1 - cpuid, stackTop, g_stackInfo[index].stackSize, size); + } + } + + OsExcStackCheck();//发生异常时栈检查 +} +/*************************************************************************************** @note_pic + OsExcStackInfo 各个CPU栈布局图,其他栈也是一样,CPU各核硬件栈都是紧挨着 + __undef_stack(SMP) ++-------------------+ <--- cpu1 top +| | +| CPU core1 | +| | ++--------------------<--- cpu2 top +| | +| cpu core 2 | +| | ++--------------------<--- cpu3 top +| | +| cpu core 3 | +| | ++--------------------<--- cpu4 top +| | +| cpu core 4 | +| | ++-------------------+ +******************************************************************************************/ + +//注册栈信息 +VOID OsExcStackInfoReg(const StackInfo *stackInfo, UINT32 stackNum) +{ + g_stackInfo = stackInfo; //全局变量指向g_excStack + g_stackNum = stackNum; +} +//task栈的初始化,设置固定的值. 0xcccccccc 和 0xcacacaca +VOID OsStackInit(VOID *stacktop, UINT32 stacksize) +{ + /* initialize the task stack, write magic num to stack top */ + (VOID)memset_s(stacktop, stacksize, (INT32)OS_STACK_INIT, stacksize);//清一色填 0xCACACACA + *((UINTPTR *)stacktop) = OS_STACK_MAGIC_WORD;//0xCCCCCCCCC 中文就是"烫烫烫烫" 这几个字懂点计算机的人都不会陌生了. +} + +#ifdef LOSCFG_SHELL_CMD_DEBUG +SHELLCMD_ENTRY(stack_shellcmd, CMD_TYPE_EX, "stack", 1, (CmdCallBackFunc)OsExcStackInfo);//采用shell命令静态注册方式 +#endif diff --git a/zzz/git/push.sh b/zzz/git/push.sh index 9e90c4be968f8f53a19531229053e16105bebb14..d7ee1df41941622a6be36ea8310390eaab952f9b 100644 --- a/zzz/git/push.sh +++ b/zzz/git/push.sh @@ -1,5 +1,5 @@ git add -A -git commit -m '注解汇编代码,原来它们竟如此可爱,爱了爱了. +git commit -m 'CPU有哪几种工作模式?每种模式都有独立堆栈,如何用汇编初始化这些栈? 搜索 @note_pic 可查看绘制的全部字符图 搜索 @note_why 是尚未看明白的地方,有看明白的,请Pull Request完善 搜索 @note_thinking 是一些的思考和建议