Master Exception For System Level Services in Arm Cortex Processor (2025)
,

Master Exception For System Level Services in Arm Cortex Processor (2025)

Exception For System Level Services in Arm Cortex Processor : When you’re working with ARM Cortex processors, especially in embedded systems, you’ll hear a lot about exceptions. But what are they, and how do they help your system run more smoothly — especially at the system level?

Let’s break it down simply. 😊

Exception For System Level Services in Arm Cortex Processor

What is an Exception?

An exception is a special kind of signal that tells the processor to stop what it’s doing and do something more important first. Think of it like this:

“Hey CPU, pause your current work. There’s something urgent to handle!”

This could be an interrupt from hardware, a system fault, or even a software request like a system call.

Why Are Exceptions Important in ARM Cortex?

ARM Cortex-M processors are designed for embedded and real-time systems. Exceptions allow the processor to respond quickly to:

  • 🔌 Hardware interrupts (like GPIO or Timer events)
  • 🧱 Faults (like trying to access invalid memory)
  • 🧬 System-level services (like context switching in an RTOS)

They help keep the system responsive, safe, and organized.

Types of Exceptions in Cortex-M

There are two main categories:

1. System Exceptions (Predefined by ARM)

These are built into the Cortex-M core itself. Examples:

  • Reset – Triggered when the system starts or restarts.
  • NMI (Non-Maskable Interrupt) – High-priority interrupt that can’t be disabled.
  • HardFault – Happens when something goes very wrong (e.g., divide by zero).
  • SVCall (Supervisor Call) – Used by the OS to switch between user/system mode.
  • PendSV – Used for context switching in RTOS (e.g., FreeRTOS).
  • SysTick – A system timer interrupt, often used for OS ticks.

2. External Interrupts (IRQs)

These come from outside peripherals — like buttons, UART, I2C, etc.

System-Level Services Using Exceptions

Here’s how exceptions help in system-level operations like OS scheduling:

SVCall (Supervisor Call)

When a user app needs the OS to perform a system-level task (like memory allocation), it can make a supervisor call. This triggers the SVCall exception.

Think of it like:

“Hey OS, please do something privileged for me.”

PendSV (Pendable Service Call)

The RTOS uses this to perform context switches. When it’s time to switch tasks, the OS sets PendSV as “pending”. When the CPU is ready, it runs the PendSV handler to switch tasks.

SysTick (System Timer)

This fires at regular intervals (e.g., every 1ms). It’s often used to keep track of time and schedule tasks in real-time operating systems.

Simple Real-World Use Case

Let’s say you’re building a smart fan with FreeRTOS running on a Cortex-M4:

  1. SysTick triggers every 1ms and updates the system tick.
  2. Based on tick count, the OS decides to switch to another task.
  3. It sets the PendSV exception.
  4. The processor runs the PendSV handler, which saves the current task context and switches to the next.
  5. A user app asks for memory — it triggers SVCall to request memory allocation from the kernel.

All these system-level services run smoothly using exceptions!

Bonus: What Happens on Errors?

If your program does something wrong, the processor triggers:

  • HardFault
  • MemManage Fault
  • BusFault
  • UsageFault

These exceptions protect your system and help with debugging.

Summary

ExceptionPurpose
ResetSystem starts
NMIHigh-priority external signal
HardFaultSerious error handling
SVCallRequest system-level services
PendSVContext switching in RTOS
SysTickSystem timekeeping

ARM Cortex-Mx processors, focusing on SVC and PendSV:

Exceptions for System-Level Services (Cortex-Mx)

The ARM Cortex-Mx processors support various exceptions, but two key system-level service exceptions used in operating systems are:

1. SVC (Supervisor Call) Exception

  • Purpose: Used to request privileged operations or access to system-level services from a less privileged task.
  • When Used: A user-mode application or thread generates an SVC exception using the SVC instruction.
  • Common Use Case:
    • Requesting services from the OS kernel such as:
      • Accessing peripherals
      • Managing device drivers
      • Allocating memory
  • Why Needed: Ensures that only authorized and controlled code (OS) can access critical system resources.

📌 Example:
User task calls SVC 0x01 → triggers an SVC exception → OS handler processes it → returns result to user task.

2. PendSV (Pendable Service Call) Exception

  • Purpose: Designed specifically for context switching between tasks in an OS.
  • When Used: When a context switch is required, the OS sets the PendSV interrupt to pending.
  • Pendable: It is a low-priority, software-triggered exception that can be delayed until no higher-priority exceptions are active.
  • Common Use Case:
    • Task switching in RTOS (e.g., switching from Task A to Task B)
  • Why Needed: Ensures context switching doesn’t interfere with high-priority interrupts or exceptions.

📌 Example:
Task A finishes → OS schedules Task B → PendSV is triggered → saves Task A context & restores Task B context.

Summary Table

ExceptionPurposeTrigger SourceUse Case in OS
SVCRequest system servicesSVC instructionAccessing device drivers, memory
PendSVPerform context switchingSoftwareSwitching between tasks

What is SVC (Supervisor Call)?

SVC is a special instruction in the Thumb Instruction Set Architecture (ISA) of ARM Cortex-M processors.

  • When a CPU executes SVC, it causes a special exception called the SVC exception.
  • This transfers control from user code (unprivileged mode) to kernel code (privileged mode).
  • It’s like raising your hand to ask the operating system (OS) to do something you’re not allowed to do directly.

Why Do We Use SVC?

In embedded systems or RTOS, we often run:

  • User tasks in unprivileged mode (to protect the system)
  • Kernel code in privileged mode (can access hardware, critical memory, etc.)

Since user code cannot access critical resources (like hardware registers or memory-mapped peripherals) directly, it uses SVC to request the OS to do so on its behalf.

Example Uses:

  • Creating/deleting tasks
  • Accessing hardware (GPIO, UART)
  • Requesting memory allocation
  • Starting/stopping timers

How SVC Works — Step by Step:

Let’s break it down:

1. The User Code Issues an SVC Instruction

__asm("SVC #0");   // Inline Assembly — calls SVC with number 0
  • The #0 is the SVC number — a value used to indicate which service you’re requesting (like a function ID).
  • This instruction triggers the SVC exception.

2. Processor Automatically Saves Context

When the SVC is executed:

  • The processor switches to handler mode (privileged mode).
  • It pushes some registers (R0–R3, R12, LR, PC, xPSR) onto the stack to save the current context.
  • This is similar to how interrupts are handled.

3. Processor Jumps to the SVC Handler

The processor now jumps to the address of the SVC handler, defined in the vector table:

void SVC_Handler(void) {
   // Kernel code handles the request here
}

4. The SVC Handler Decodes the Request

The handler checks the SVC number used in the instruction to determine what service is requested.

How to extract the SVC number:

Because the number is embedded in the instruction (not passed in R0–R3), the handler must read the instruction that caused the exception:

void SVC_Handler(void) {
    uint32_t *stack_ptr;
    uint8_t svc_number;

    // Get stack pointer (usually MSP or PSP depending on context)
    __asm("TST lr, #4\n"
          "ITE EQ\n"
          "MRSEQ %0, MSP\n"
          "MRSNE %0, PSP\n"
          : "=r" (stack_ptr));

    // Find the instruction that caused the SVC
    uint16_t *svc_instr_addr = ((uint16_t*)stack_ptr[6]) - 1;
    uint16_t svc_instr = *svc_instr_addr;

    // Extract the SVC number (last 8 bits)
    svc_number = (uint8_t)(svc_instr & 0xFF);

    switch (svc_number) {
        case 0:
            // Handle SVC #0 request
            break;
        case 1:
            // Handle SVC #1 request
            break;
        // and so on...
    }
}

5. Kernel Code Executes the Requested Service

  • After identifying the request (like start a task, turn on LED), the kernel performs the task in privileged mode.

6. Return to User Code

  • Once the handler completes, the context is restored, and execution resumes at the next instruction after SVC.

Key Points

ConceptExplanation
SVC InstructionCauses a software exception (like a controlled interrupt)
Used ByUnprivileged user code to request services from kernel
SVC NumberA number (0–255) passed with the SVC instruction to indicate what service is needed
Handler NameSVC_Handler() — OS or firmware must implement this
Privilege EscalationSwitches temporarily from user mode to privileged mode
SecurityEnsures user tasks don’t access critical resources directly

Analogy

Think of it like this:

  • You are in a library (user task), and you need access to a restricted book (privileged resource).
  • You cannot go to the restricted section.
  • So, you ring a bell (SVC instruction) with a code number saying which book you want.
  • The librarian (SVC handler) checks your request and fetches the book on your behalf.

When Is It Used in RTOS?

  • Thread switching or task management
  • Requesting kernel services from user apps
  • Accessing hardware securely
  • System calls in embedded systems without a full-fledged OS

Summary

SVC is a software interrupt used to safely access system-level services
✅ Switches from unprivileged user mode to privileged kernel mode
✅ The SVC handler reads the SVC number and executes the requested action
✅ Helps in security, task isolation, and controlled hardware access

The SVC (Supervisor Call) exception is a mechanism used in ARM Cortex-M processors to transition from unprivileged to privileged mode or to request OS services (like system calls) from the application layer. There are two methods to trigger an SVC exception:

1. Direct Execution of the SVC Instruction

This is the standard and most efficient way to trigger an SVC exception.

How it works:

  • The CPU executes an SVC instruction with an immediate value (which usually indicates the specific service requested).
  • This causes the processor to immediately enter the SVC handler, switching to Handler mode.

Example:

SVC #0x04   ; Assembly instruction to trigger SVC exception with immediate value 0x04

In C (using inline assembly or CMSIS):

__asm("SVC #0x04");

Use Cases:

  • Used in RTOS for system calls
  • Switching from Thread mode (unprivileged) to Handler mode (privileged)

Advantages:

  • Low latency
  • Immediate and deterministic triggering
  • Directly supported by the CPU instruction set

2. Setting the Exception Pending Bit in SHCSR (System Handler Control and State Register)

This is a less common and non-standard method used mainly for testing or simulation.

How it works:

  • The System Handler Control and State Register (SHCSR) contains a bit for SVC pending (SVCALLPENDED).
  • Manually setting this bit to 1 via software tricks the processor into thinking an SVC is pending.
  • When conditions allow, the SVC handler will be called.

Example:

#define SCB_SHCSR (*((volatile uint32_t*)0xE000ED24))
SCB_SHCSR |= (1 << 15);  // Set SVCALLPENDED bit manually
  • Bit 15 in SHCSR is SVCALLPENDED.

Important Notes:

  • This does not immediately trigger the SVC handler.
  • The exception must be enabled, and priority levels must allow it to be serviced.
  • Not a common practice — typically used in test environments, fault injection, or debugging.

Summary Table:

MethodDescriptionEfficiencyUse CaseNotes
SVC #immDirect instruction✅ HighSystem calls, privilege switchStandard and efficient
SHCSR bitSet pending bit❌ LowTesting, debugUncommon and delayed execution

What is SVC?

  • SVC is an instruction used in ARM Cortex-M to request a privileged system service.
  • The syntax is: SVC #<number> Example: SVC #0x20 ; Here, 0x20 is the SVC number

Goal

When an SVC instruction is executed, it causes a SVC exception, and the processor jumps to the SVC_Handler.
Your task is to:

  1. Get the address of the SVC instruction that caused the exception.
  2. Read the SVC opcode at that address.
  3. Extract the SVC number from that opcode.

What Happens During SVC?

  1. The CPU runs a line like SVC #0x05.
  2. This triggers an SVC exception.
  3. The CPU automatically saves some context (like registers) on the stack — this includes the Program Counter (PC) where it stopped, i.e., the instruction after the SVC.

Step-by-Step Breakdown

Step 1: Understand Stack Frame Format

When an exception like SVC occurs, ARM Cortex-M pushes the following registers onto the stack in this order:

OffsetRegister
0x00R0
0x04R1
0x08R2
0x0CR3
0x10R12
0x14LR
0x18PC (🟢 Points to next instruction after SVC)
0x1CxPSR

Step 2: Get the Stack Pointer in the Handler

void SVC_Handler(void)
{
    __asm volatile
    (
        "TST lr, #4 \n"               // Test bit 2 of LR to know which stack (MSP or PSP)
        "ITE EQ \n"
        "MRSEQ r0, MSP \n"           // If 0: Main Stack Pointer
        "MRSNE r0, PSP \n"           // If 1: Process Stack Pointer
        "B SVC_Handler_C \n"         // Branch to C handler and pass r0
    );
}

Step 3: In C, Extract the SVC Number

Here is the C function that receives the stack frame pointer:

void SVC_Handler_C(uint32_t *stack_frame)
{
    // PC is at offset 6 (index 6), because each register is 4 bytes
    uint32_t return_address = stack_frame[6];

    // SVC instruction is at (return_address - 2)
    // because PC points to instruction AFTER SVC
    uint16_t *svc_instruction_address = (uint16_t *)(return_address - 2);

    uint8_t svc_number = (uint8_t)(*svc_instruction_address & 0xFF); // SVC number is in the lower byte

    // Now you can use svc_number for your logic
}

Why return_address - 2?

  • On Thumb instruction set (which Cortex-M uses), SVC is a 16-bit instruction.
  • The saved PC points to the next instruction, so subtract 2 to get the SVC instruction itself.

Example

Suppose user code runs:

SVC #0x23

Then in the handler:

  • PC = address after SVC = 0x08000102
  • SVC instruction is at 0x08000100
  • At that memory: 0xDF23
    • 0xDF is opcode for SVC
    • 0x23 is the SVC number
  • Extract using: uint8_t svc_number = *svc_instruction_address & 0xFF; // svc_number = 0x23

Final Summary

StepAction
1Determine active stack (MSP/PSP) in assembly
2Pass stack frame pointer to C function
3Extract PC from stack (offset 6)
4Subtract 2 to get SVC instruction address
5Read 16-bit value, extract lower byte for SVC number

Full Example: Execute SVC, extract number, increment by 4 and return

#include <stdio.h>
#include <stdint.h>

uint32_t svc_result = 0;

void SVC_Handler_Main(uint32_t *stack_frame);

__attribute__((naked)) void SVC_Handler(void) {
    __asm volatile (
        "TST lr, #4 \n"             // Test bit 2 of LR to find stack pointer (MSP or PSP)
        "ITE EQ \n"
        "MRSEQ r0, MSP \n"          // If 0, use MSP
        "MRSNE r0, PSP \n"          // Else, use PSP
        "B SVC_Handler_Main \n"     // Branch to handler in C
    );
}

// This function is called with the pointer to the stack frame
void SVC_Handler_Main(uint32_t *stack_frame) {
    // Stack frame: R0, R1, R2, R3, R12, LR, PC, xPSR
    uint16_t *pc_ptr = (uint16_t *)stack_frame[6]; // PC points to next instruction after SVC
    uint8_t svc_number = ((uint8_t *)pc_ptr)[-1];  // SVC immediate is 1 byte before PC

    printf("SVC number: %d\n", svc_number);

    svc_result = svc_number + 4;
}

uint32_t call_svc(uint8_t svc_num) {
    __asm volatile (
        "mov r0, %[num]     \n"   // Move svc_num to r0 (optional for general use)
        "svc %[immediate]   \n"   // Trigger SVC
        :
        : [num] "r" (svc_num), [immediate] "I" (0x05) // SVC #5 hardcoded for demo
        : "r0"
    );
    return svc_result;
}

int main(void) {
    printf("Calling SVC now...\n");
    uint32_t result = call_svc(5);
    printf("Returned value from SVC handler: %u\n", result);
    return 0;
}

Explanation:

  • SVC_Handler: Naked function with inline assembly that determines which stack pointer was used (MSP or PSP), then passes stack pointer to SVC_Handler_Main.
  • SVC_Handler_Main: Extracts SVC number from instruction that caused the exception (using PC - 1), prints it, increments by 4, and stores in svc_result.
  • call_svc(5): Executes the svc #0x5 instruction and later returns the modified result from the handler.

Output:

Calling SVC now...
SVC number: 5
Returned value from SVC handler: 9

Leave a Reply

Your email address will not be published. Required fields are marked *