Cortex Authority Manual – OS Support Features

Shadow Stack Pointer

The shadow stack pointer mechanism is crucial for the implementation of operating systems in ARM Cortex-M series processors. The Main Stack Pointer (MSP) and Process Stack Pointer (PSP) are used in different scenarios:

  • Main Stack Pointer (MSP): The default stack pointer used for the operating system kernel and interrupt handling. In handler mode, MSP is always used.

  • Process Stack Pointer (PSP): Used for application tasks. When bit[1] (SPSEL) of the CONTROL register is set to 1, PSP is used in thread mode.

Each time the operating system performs a context switch, the PSP is updated to save the stack state of the current task and switch to the stack of the next task.

SysTick Timer

The SysTick timer is a 24-bit down counter used to provide a periodic time base for the operating system. Its main features include:

  • Accessible only in privileged mode.

  • Used to generate periodic interrupts, suitable for the operating system’s clock ticks.

  • Simple configuration, suitable for the timing needs of embedded real-time operating systems.

SVC (Supervisor Call) and PendSV (Pendable System Call) Exceptions

SVC and PendSV are key exception types that support operating system functionality in ARM Cortex-M series processors:

  • SVC (Supervisor Call): Used for application tasks to request operating system services. When an application task needs to access system resources or perform privileged operations, it can trigger the SVC exception to call operating system services.

  • PendSV: Used for context switching in the operating system. It has the lowest priority, ensuring that context switching occurs after all other interrupt handling is completed.

SVC Exception Handling

SVC exception handling is divided into assembly and C language parts:

  1. Assembly Handling:

  • Check the value of the Link Register (LR) to determine whether the stack used is MSP or PSP.

  • Extract the starting address of the stack frame and pass it to the C language handling part.

  • C Language Handling:

    • Extract the pushed Program Counter (PC) value from the stack frame to obtain the SVC instruction number.

    • Execute the corresponding operating system service based on the SVC number.

    Example code:

    // Assembly part
    _asm void SVC_Handler(void){
        TST LR, #4        ; Test the 2nd bit of EXC_RETURN
        ITE EQ
        MRSEQ R0, MSP    ; If 0, the stack used is MSP, copy to R0
        MRSNE R0, PSP    ; If 1, the stack used is PSP, copy to R0
        B SVC_Handler_C
        ALIGN 4
    }
    // C language part
    void SVC_Handler_C(unsigned int *svc_args){
        unsigned int svc_number;
        svc_number = ((char *)svc_args[6])[-2]; // Get the SVC instruction number
        switch (svc_number)    {
            case 0: svc_args[0] = svc_args[0] + svc_args[1]; // Addition
                break;
            case 1: svc_args[0] = svc_args[0] - svc_args[1]; // Subtraction
                break;
            case 2: svc_args[0] = svc_args[0] + 1; // Increment
                break;
            default: // Unknown SVC request
                break;
        }
    }

    PendSV Exception Handling

    PendSV exceptions are used to delay context switching, ensuring that context switching occurs after all other interrupt handling is completed. Its priority is lower than SVC and normal interrupts, but higher than SysTick.

    The workflow of PendSV is as follows:

    1. When Task A calls SVC for a task switch, the operating system prepares for context switching and suspends the PendSV exception.

    2. When the CPU exits SVC, it immediately enters PendSV and performs context switching.

    3. After PendSV completes, the program returns to thread mode and executes Task B.

    4. When an interrupt occurs and enters the interrupt handler, the SysTick exception is generated.

    5. The OS performs important operations and suspends the PendSV exception to prepare for context switching.

    6. When the SysTick exception exits, it returns to the interrupt service routine.

    7. After the interrupt service routine ends, PendSV begins executing the actual context switching operation.

    8. When PendSV completes, the program returns to thread mode and continues executing Task A.

    Exclusive Access and Embedded OS

    The exclusive access mechanism is used to ensure the atomicity of semaphore and mutex (MUTEX) operations. The decrement operation of the counting variable of the semaphore needs to be guaranteed atomicity through exclusive access instructions.

    Example code:

    // Using exclusive access instructions for semaphore decrement operation
    void semaphore_wait(volatile int *semaphore){
        while (1)    {
            int expected = *semaphore;
            int desired = expected - 1;
            if (__atomic_compare_exchange_n(semaphore, &expected, desired, 0, __ATOMIC_ACQUIRE, __ATOMIC_RELAXED))
            {
                break;
            }
        }
    }

    Leave a Comment