Reference implementation

The following code shows a reference implementation of how to recognize stack overflow in a user-defined Memory Management trap handler. As the stack overflow is a non-recoverable error, the overflowing task is suspended and true is returned to signal that the trap was handled correctly. A user must keep in mind that suspending a task may influence the application’s behavior, so the proper design patterns should be used.

It is not possible to call all the API functions in trap handlers, but only those with the _Hnd suffix. This means that PxSysInfoGetTaskInfo() cannot be used to get the task base and end addresses. But there is a PXROS-HR internal symbol called _PxRuntask, which is an internal task structure. This structure contains a pointer to the task control block that is offset (TCB_OFFSET) by 11 words. The task control block is also an internal structure, and it contains stack information. The start address of the stack is offset (STACK_BASE_OFFSET) by 63 words. As far as the structures are internal, it is not possible to provide detailed information.

The stack overflow is recognized in two cases:

  1. Hardware MSTKERR was generated

  2. The fault address is within the task stack guard memory area

Code 1. Reference implementation of user-defined MM fault handler
/* Prevent compiler warnings */
#define NOT_USED(x)         ((void)(x))

/* MSTKERR bit in MemManage Fault Status Register */
#define MSTKERR             (1 << 4)

/* PXROS-HR internal symbol */
extern unsigned int * _PxRuntask;

/* Offset in the internal PXROS-HR structure to get stack base and end addresses */
#define STACK_START_OFFSET  (63)

/* Offset in the internal PXROS-HR structure to get task control block (TCB) */
#define TCB_OFFSET          (11)


PxBool_t Trap_MemManage(PxUInt_t trap_number, PxUInt_t user_argument, PxUInt_t task_id,
                        PxUInt_t fault_status_register, PxUInt_t fault_address,
                        PxSavedRegsPtr_t saved_registers)
{
    /* Prevent compiler warnings */
    NOT_USED(trap_number); NOT_USED(user_argument); NOT_USED(saved_registers);

    /* Get TCB from _PxRuntask structure by offset */
    unsigned int * task_control_block = (unsigned int *) *(_PxRuntask + TCB_OFFSET);

    /* Get stack start from task control block by offsets */
    unsigned int stack_start = *(task_control_block + STACK_START_OFFSET);

    /* Stack overflow */
    if (((stack_start <= fault_address)
          && (fault_address <= stack_start + PX_TASK_STACK_GUARD_SIZE))
        || (fault_status_register & MSTKERR))
    {
        /* Stack overflow occurred, kernel cannot recover from this error, do safe system
         * shutdown or restart */
        PxPanic();
    }

    /* Regular MM fault occurred */

    /* Space for user's MM handler implementation */

    /* This handler does not handle regular MM faults */
    return false;
}