RTOS实现Try-Catch机制,支持CM3/4/7

背景:我用的S32K3系列单片机,这芯片的RAM有ECC,就是说上电后如果你不写RAM,直接去读,就会触发ECC故障,然后进入hardfault.于是我就想实现Try Catch,想办法从Hardfault中跳出来。理论上支持CM系列,我只实现了Free RTOS的. 裸机也可以的。。包括STM32...实现代码:

核心汇编部分:

#if (configNumberOfExceptionStacks > 0)
    int xPortUpdateSignalCode(ExceptionContext_t *pxExceptionContext)
    {
        // 根据寄存器判断是哪些错误码,然后返回对应的信号。这里简单返回总线错误
        return SIGBUS;
    }

    __attribute__((naked)) HardFault_Handler(void)
    {
        __asm volatile(
            "TST     lr, #0x04 \n" //              ; if(!EXC_RETURN[2])
            "ITE     EQ \n"
            "MRSEQ   r0, msp                 \n" //; [2]=0 ==> Z=1, get fault context from handler."
            "MRSNE   r0, psp                 \n" //; [2]=1 ==> Z=0, get fault context from thread."

            /*"	tst lr, #0x10						\n"  Is the task using the FPU context?  If so, push high vfp registers. */
            /*"	it eq								\n"*/
            /*"	vstmdbeq r0!, {s16-s31}				\n"*/
            "stmdb r0!, {r4-r11,lr}			\n" 
            "push {r0} \n"

            "BL vExceptionHappened \n" // vExceptionHappened(r0); r0=异常长下文的栈结构体地址,r1=是否发生在中断

            "pop {r0} \n"
            "ldmia r0!, {r4-r11,lr}			\n"         /* Pop the core registers. */
            
            "TST     lr, #0x04 \n" //              ; if(!EXC_RETURN[2])
            "ITE     EQ \n"
            "MSREQ   msp, r0                 \n" //; [2]=0 ==> Z=1, update stack pointer to MSP."
            "MSRNE   psp, r0                 \n" //; [2]=1 ==> Z=0, update stack pointer to PSP."
            "isb \n"
            "bx lr\n");
    }
#else
void HardFault_Handler(void)
{
    while (1)
    {
    }
}
#endif

FreeRTOS.h:

#if ( configNumberOfExceptionStacks >0 )
#include 

#define	SIGHUP	1	/* hangup */
#define	SIGINT	2	/* interrupt */
#define	SIGQUIT	3	/* quit */
#define	SIGILL	4	/* illegal instruction (not reset when caught) */
#define	SIGTRAP	5	/* trace trap (not reset when caught) */
#define	SIGIOT	6	/* IOT instruction */
#define	SIGABRT 6	/* used by abort, replace SIGIOT in the future */
#define	SIGEMT	7	/* EMT instruction */
#define	SIGFPE	8	/* floating point exception */
#define	SIGKILL	9	/* kill (cannot be caught or ignored) */
#define	SIGBUS	10	/* bus error */
#define	SIGSEGV	11	/* segmentation violation */
#define	SIGSYS	12	/* bad argument to system call */
#define	SIGPIPE	13	/* write on a pipe with no one to read it */
#define	SIGALRM	14	/* alarm clock */
#define	SIGTERM	15	/* software termination signal from kill */  


#define	SIGURG	16	/* urgent condition on IO channel */
#define	SIGSTOP	17	/* sendable stop signal not from tty */
#define	SIGTSTP	18	/* stop signal from tty */
#define	SIGCONT	19	/* continue a stopped process */
#define	SIGCHLD	20	/* to parent on child stop or exit */
#define	SIGCLD	20	/* System V name for SIGCHLD */
#define	SIGTTIN	21	/* to readers pgrp upon background tty read */
#define	SIGTTOU	22	/* like TTIN for output if (tp->t_local<OSTOP) */
#define	SIGIO	23	/* input/output possible signal */
#define	SIGPOLL	SIGIO	/* System V name for SIGIO */
#define	SIGWINCH 24	/* window changed */
#define	SIGUSR1 25	/* user defined signal 1 */
#define	SIGUSR2 26	/* user defined signal 2 */

#endif

task.c修改:

PRIVILEGED_DATA TCB_t * volatile pxCurrentTCB = NULL; //原内核代码
PRIVILEGED_DATA UBaseType_t volatile xExceptionHappen = 0;//我加的


    #if ( configNUM_THREAD_LOCAL_STORAGE_POINTERS > 0 )//原内核代码
        void * pvThreadLocalStoragePointers[ configNUM_THREAD_LOCAL_STORAGE_POINTERS ];
    #endif

    //我加的
    #if ( configNumberOfExceptionStacks > 0 )
        UBaseType_t uxJmpStacksCounter;
        jmp_buf JmpStacks[configNumberOfExceptionStacks];
        volatile ExceptionContext_t    xExceptionContext;
        volatile    int     xThrowCode;
    #endif

    #if ( configGENERATE_RUN_TIME_STATS == 1 )
        configRUN_TIME_COUNTER_TYPE ulRunTimeCounter; /*< Stores the amount of time the task has spent in the Running state. */
    #endif

task.c:

#if (configNumberOfExceptionStacks >0)
inline jmp_buf *xGetJmpStackOfCurrentTask()
{
    TCB_t *self=(TCB_t *)xTaskGetCurrentTaskHandle();
    configASSERT(self!=NULL);
    return self->JmpStacks[self->uxJmpStacksCounter];
}
inline void jmp_stack_push()
{
    TCB_t *self=(TCB_t *)xTaskGetCurrentTaskHandle();
    configASSERT(self!=NULL);
	self->uxJmpStacksCounter++;
}

inline jmp_buf* jmp_stack_pop()
{
    TCB_t *self=(TCB_t *)xTaskGetCurrentTaskHandle();
    configASSERT(self!=NULL);
	return &self->JmpStacks[--self->uxJmpStacksCounter];
}

void vInternalExceptionProcess ()
{
    taskENTER_CRITICAL();
    {
        xExceptionHappen--;
    }
    taskEXIT_CRITICAL();

    TCB_t *self=(TCB_t *)xTaskGetCurrentTaskHandle();
    configASSERT(self!=NULL);
    UBaseType_t tempJmpStacksCounter=0;
    taskENTER_CRITICAL();
    {
        tempJmpStacksCounter=self->uxJmpStacksCounter;
    }
    taskEXIT_CRITICAL();
    if(tempJmpStacksCounter==0)
    {
        extern void vExceptionProcess(TaskHandle_t pxCurrentTask,volatile   ExceptionContext_t *pxExceptionContext);
        vExceptionProcess(self,&self->xExceptionContext);
    }
    else
    {
        _throw_(self->xThrowCode);//to do
    }
    while(1)
    {
        vTaskDelay(1000);
    }
}
/*

*/
void vExceptionHappened(ExceptionContext_t *pxExceptionContext)
{  

    xExceptionHappen++;
    if(xExceptionHappen>1)
    {
        while(1);//no use configASSERT
    }

    TCB_t *self=xTaskGetCurrentTaskHandle();
    configASSERT(self!=NULL);

    extern int xPortUpdateSignalCode(ExceptionContext_t *pxExceptionContext);
    self->xThrowCode=xPortUpdateSignalCode(pxExceptionContext);
    
    memcpy((ExceptionContext_t *)&self->xExceptionContext,pxExceptionContext,sizeof(ExceptionContext_t));
    
    pxExceptionContext->exception_stack_frame.pc=(BaseType_t)vInternalExceptionProcess;
}
ExceptionContext_t* xGetExceptionContext(void)   
{
    TCB_t *self=xTaskGetCurrentTaskHandle();
    configASSERT(self!=NULL);
    return &self->xExceptionContext;
}
#endif

task.h:

#if (configNumberOfExceptionStacks >0)

void jmp_stack_push() PRIVILEGED_FUNCTION;
jmp_buf* jmp_stack_pop() PRIVILEGED_FUNCTION;
jmp_buf *xGetJmpStackOfCurrentTask() PRIVILEGED_FUNCTION;
#define _try_ \
	jmp_buf *__jmp_buf= xGetJmpStackOfCurrentTask(); \
	int __jmp_result = setjmp(*__jmp_buf); \
	if (!__jmp_result) jmp_stack_push(); \
	if (!__jmp_result)

#define _catch_(x) \
	int x = __jmp_result; \
	if (!x) jmp_stack_pop(); \
	else

#define _throw_(x) longjmp(*jmp_stack_pop(), x);

void vExceptionHappened(ExceptionContext_t *pxExceptionContext);
ExceptionContext_t* xGetExceptionContext(void);   
#else

#define _try_ 
#define _catch_(x)
#define _throw_(x)
   
#endif

portmacro.h: (我用S32K自带的LIBC库的Setjmp和longJmp反汇编没有保存浮点,所以我也没保存,实际你需要保存,我try块里用不到浮点,所以没保存,如果要保存自行修改结构体和hardfault汇编哦)

 #if (configNumberOfExceptionStacks >0)
    #include "Mcal.h"
#include "core_cm7.h"
struct exception_stack_frame
{
    BaseType_t r0;
    BaseType_t r1;
    BaseType_t r2;
    BaseType_t r3;
    BaseType_t r12;
    BaseType_t lr;//这个LR是异常发生后,硬件自动入栈的LR
    BaseType_t pc;
    BaseType_t psr;
};
typedef struct stack_frame
{

    BaseType_t exc_return;//这个LR是进入异常函数后,LR的实时状态。
    /* r4 ~ r11 register */
    BaseType_t r4;
    BaseType_t r5;
    BaseType_t r6;
    BaseType_t r7;
    BaseType_t r8;
    BaseType_t r9;
    BaseType_t r10;
    BaseType_t r11;
    #if 0
    BaseType_t s16;
    BaseType_t s17;
    BaseType_t s18;
    BaseType_t s19;
    BaseType_t s20;
    BaseType_t s21;
    BaseType_t s22;
    BaseType_t s23;
    BaseType_t s24;
    BaseType_t s25;
    BaseType_t s26;
    BaseType_t s27;
    BaseType_t s28;
    BaseType_t s29;
    BaseType_t s30;
    BaseType_t s31;
    #endif
    struct exception_stack_frame exception_stack_frame;
}ExceptionContext_t;

#endif

调用:

  
  _try_
  {
    uint32_t *addr = (uint32_t *)(&__BootAppComSramStart__);
    return *addr;
  }
  _catch_(x)
  {
    return 0;
  }

你可能感兴趣的:(单片机,stm32,嵌入式硬件,arm)