Skip to main content Privilege Levels, Exceptions, and System Calls: How CPUs Enter Controlled Paths | IoT Worker

Privilege Levels, Exceptions, and System Calls: How CPUs Enter Controlled Paths

An application calling read() looks like a normal function call. Illegal instructions, page faults, interrupts, and system calls can also look like “the CPU jumped to another handler.”

But these paths are not normal function calls.

A normal function call stays in the same privilege level and address space. The caller knows the callee address, passes arguments according to the ABI, and returns when the callee finishes. Exceptions and system calls are different: current code cannot freely choose a high-privilege entry. The CPU must switch state according to architectural rules, transfer execution to a controlled entry, and allow the kernel, firmware, or exception handler to decide what happens next.

The safest first model is this: privilege levels limit what code can do; exception entry is the CPU-approved controlled path for crossing protection boundaries or handling special events; a system call is a user-triggered exception that requests kernel service.

low-privilege code
-> syscall / trap / exception / interrupt
-> CPU saves state required for return
-> CPU switches to a controlled entry and higher-privilege context
-> kernel / firmware / handler checks and handles the event
-> controlled return to the previous execution state

The exact instructions and registers differ across ARM, RISC-V, and x86, but this path is stable.

Privilege Levels Decide Who Can Do What

A CPU does not give every piece of code the same power.

Applications usually cannot directly modify page tables, disable interrupts, access arbitrary physical addresses, write device registers, or change scheduler state. Kernels, exception handlers, hypervisors, secure firmware, or machine firmware may have higher privileges.

Privilege boundaries protect resources such as:

  • memory mappings and page tables
  • peripheral registers
  • interrupt control
  • task scheduling and CPU state
  • security keys, boot policy, and isolated environments
  • virtualization and multiple-system isolation

ARM and RISC-V use different names. ARM Cortex-M commonly has Thread mode and Handler mode. AArch64 has EL0, EL1, EL2, and EL3. RISC-V has U mode, S mode, and M mode. The names differ, but the common rule is this: low-privilege code cannot perform high-privilege actions arbitrarily. It can only request higher-level handling through architecture-approved entries.

A Normal Jump Cannot Cross the Protection Boundary

If a user program could jump directly to any kernel address, isolation would collapse.

So a CPU does not treat “jump to an address” and “gain kernel privilege” as the same operation. Normal branch, call, and jump instructions execute under the current privilege. Entering a higher-privilege path requires an architectural exception, trap, system call, interrupt, or return mechanism.

This has two important consequences.

First, the entry address is not chosen freely by the user program. System calls can only enter a preconfigured entry. Exceptions and interrupts enter through a vector table, exception-vector base, or trap vector.

Second, high-privilege code cannot trust parameters from low-privilege code. User registers, user pointers, system-call numbers, lengths, and flags are requests, not trusted facts. The kernel must re-check permissions, addresses, and object state.

That is why a system call is heavier and more controlled than a normal function call.

Exception Entry Must Save Enough State to Return

When an exception occurs, the CPU is executing some instruction in some context. After handling, the system may return to the same place, terminate the task, schedule another one, or enter error handling.

Exception entry therefore has to solve several problems:

  • record the program counter or return address before the exception
  • record the previous status register or privilege state
  • record the exception cause
  • switch to the contracted entry address
  • switch to a usable stack or exception context
  • limit or adjust interrupt enable, priority, and return rules

Some state is saved automatically by hardware. Some must be saved by entry assembly or kernel code. Architectures differ greatly, but the goal is the same: the handler must know why it was entered and must be able to return safely or terminate safely.

If the return address, status register, stack, or exception cause is corrupted, the system may fail exception return, repeat the same fault, run at the wrong privilege level, or crash immediately after the handler returns.

A System Call Is a User-Triggered Exception

A system call can be understood as a user-triggered controlled exception.

User space enters the kernel through a dedicated instruction. ARM/AArch64 commonly uses svc, RISC-V commonly uses ecall, and x86 has syscall, sysenter, or older interrupt-gate mechanisms. The instructions differ, but the role is similar: current code asks the CPU to enter a preconfigured higher-privilege entry.

After entry, the kernel usually sees:

  • system-call number
  • argument registers
  • current task or thread
  • user return address
  • user status
  • current address space

The kernel then dispatches and checks the request: whether the system-call number exists, whether argument addresses are user-accessible, whether a file descriptor is valid, whether the process has permission, whether the call may block, and whether a signal interrupted it.

So a system call is not a direct user-space call into a kernel function. User space places a request in agreed registers, enters through exception entry, and lets the kernel decide which path is allowed to run.

Exceptions Are Not Always Errors

Many people hear “exception” and think only of faults. In practice, exception entry carries multiple event types.

Common examples include:

  • system call: user space actively requests kernel service
  • page fault: a virtual page is missing or permission is insufficient
  • illegal instruction: the current CPU or privilege level cannot execute it
  • unaligned access: disallowed on some platforms or configurations
  • debug exception: breakpoint, single-step, or watchpoint
  • interrupt: a peripheral, timer, or IPI needs CPU attention
  • secure or virtualization trap: a lower-level operation is intercepted by a higher layer

These events use similar entry mechanisms, but their semantics differ. A page fault may be repaired and return to user space. An illegal instruction may signal or terminate the task. A timer interrupt may trigger scheduling. A system call may block. A secure monitor or hypervisor may intercept sensitive operations.

So after seeing that the CPU entered an exception, check the cause, source privilege, entry type, and OS handling policy.

Return Is Controlled Too

After exception handling finishes, a normal function return is not enough.

The return path must restore:

  • previous program counter
  • previous status register and privilege level
  • required general-purpose registers
  • stack state
  • address space or task context
  • interrupt enable and priority state

Architectures usually provide a dedicated exception-return, eret, sret, mret, or similar mechanism. These do more than jump to an address. They restore privilege, state, and exception context.

That is why exception-return bugs are hard to debug. Missing saved state, stack corruption, wrong return status, or returning to the wrong privilege level can crash the system after the handler “finished.”

The Common Model Across ARM and RISC-V

ARM and RISC-V differ greatly in register names, mode names, and entry details, but the common model comes first.

For ARM/AArch64, watch:

  • current Exception Level or mode
  • exception-vector base
  • saved return address and status register
  • entry type such as svc, interrupt, abort, or fault
  • eret or exception-return mechanism

For RISC-V, watch:

  • current U/S/M mode
  • trap vector
  • cause of ecall, interrupt, or exception
  • epc, status, tval, and related state registers
  • sret, mret, and return mechanisms
  • whether SBI or machine firmware participates

Do not begin by memorizing complete register tables. First ask: which privilege did it come from, why did it enter, where is the entry, where is the return address, who checks the parameters, and which privilege will it return to?

Evidence to Debug This Layer

Privilege and exception problems usually require state evidence, not just source code.

Useful evidence includes:

  • current privilege level or mode
  • exception cause
  • PC or return address at exception time
  • accessed address or instruction at exception time
  • status-register interrupt enable, privilege, and return-state bits
  • whether the current stack is correct
  • whether system-call number and argument registers match the ABI
  • whether the vector table or trap vector points to the expected entry
  • whether the return path restores the correct address and privilege

For example, a user process faulting when accessing a peripheral register may not mean the address is wrong; the access may simply be disallowed. A system call returning EFAULT may not mean the driver is broken; a user pointer may be inaccessible. Repeated exceptions at the same address may mean the handler did not fix the cause, or the return state did not advance.

What to Remember

Privilege levels, exceptions, and system calls solve one underlying problem: low-privilege code cannot freely perform high-privilege actions, but the system must still allow service requests, hardware responses, and error handling.

A normal function call jumps within the current privilege. Exception entry is the CPU-approved controlled path: save required state, switch to a contracted entry, let higher-privilege code or a dedicated handler run, then use a controlled return to restore execution.

With that model, system calls, interrupts, page faults, illegal instructions, debug breakpoints, and secure traps stop being unrelated concepts. They are different reasons for the CPU to enter controlled paths. The differences are who triggered them, which privilege they came from, who handles them, and whether execution can return.