User Space Support

Relevant source files

This document covers the user space support functionality provided by the axcpu library, which enables transitions from kernel mode to user mode across supported architectures. This feature allows operating systems built on axcpu to execute user programs in unprivileged mode while maintaining proper isolation and control.

For architecture-specific trap handling that occurs when transitioning back from user space, see the trap handling sections for each architecture (2.2, 3.2, 4.2). For general context management during task switching, see the context management sections (2.1, 3.1, 4.1, 5.1).

Architecture Support Overview

The user space support is implemented through the uspace feature and provides a consistent interface across multiple architectures. Each supported architecture implements the functionality through a dedicated uspace.rs module that provides the UspaceContext structure and associated methods.

flowchart TD
subgraph subGraph3["User Space Support Architecture"]
    USPACE_FEAT["uspace feature flag"]
    subgraph subGraph2["Common Interface"]
        EMPTY["empty()"]
        NEW["new()"]
        FROM["from()"]
        GET_IP["get_ip()"]
        GET_SP["get_sp()"]
        SET_IP["set_ip()"]
        SET_SP["set_sp()"]
        SET_RETVAL["set_retval()"]
    end
    subgraph subGraph1["Core Components"]
        USPACE_CTX["UspaceContext struct"]
        TRAP_FRAME["TrapFrame wrapper"]
        ENTER_USPACE["enter_uspace() method"]
    end
    subgraph subGraph0["Architecture Implementations"]
        RISCV_USPACE["src/riscv/uspace.rsUspaceContext"]
        AARCH64_USPACE["src/aarch64/uspace.rsUspaceContext"]
        LOONGARCH64_USPACE["src/loongarch64/uspace.rsUspaceContext"]
    end
end

AARCH64_USPACE --> USPACE_CTX
LOONGARCH64_USPACE --> USPACE_CTX
RISCV_USPACE --> USPACE_CTX
USPACE_CTX --> EMPTY
USPACE_CTX --> ENTER_USPACE
USPACE_CTX --> FROM
USPACE_CTX --> GET_IP
USPACE_CTX --> GET_SP
USPACE_CTX --> NEW
USPACE_CTX --> SET_IP
USPACE_CTX --> SET_RETVAL
USPACE_CTX --> SET_SP
USPACE_CTX --> TRAP_FRAME
USPACE_FEAT --> AARCH64_USPACE
USPACE_FEAT --> LOONGARCH64_USPACE
USPACE_FEAT --> RISCV_USPACE

Sources: src/riscv/uspace.rs(L1 - L104)  src/aarch64/uspace.rs(L1 - L113)  src/loongarch64/uspace.rs(L1 - L98) 

UspaceContext Structure

The UspaceContext is implemented as a wrapper around the architecture-specific TrapFrame structure. This design provides a unified interface while leveraging the existing trap frame infrastructure for context management.

ArchitectureUspaceContext DefinitionUnderlying TrapFrame
RISC-Vpub struct UspaceContext(TrapFrame)ContainsGeneralRegisters,sepc,sstatus
AArch64pub struct UspaceContext(TrapFrame)Contains register arrayr[31],usp,elr,spsr
LoongArch64pub struct UspaceContext(TrapFrame)Contains registers,era,prmd

Sources: src/riscv/uspace.rs(L8)  src/aarch64/uspace.rs(L8)  src/loongarch64/uspace.rs(L8) 

Context Creation and Management

Each architecture provides consistent methods for creating and manipulating user space contexts:

Context Creation Methods

flowchart TD
subgraph subGraph1["Implementation Details"]
    EMPTY_ZERO["All registers zeroed"]
    NEW_SETUP["Entry point + stack + argument configured"]
    FROM_COPY["Copy from existing TrapFrame"]
end
subgraph subGraph0["UspaceContext Creation"]
    EMPTY["UspaceContext::empty()"]
    NEW["UspaceContext::new(entry, ustack_top, arg0)"]
    FROM["UspaceContext::from(trap_frame)"]
end

EMPTY --> EMPTY_ZERO
FROM --> FROM_COPY
NEW --> NEW_SETUP

Sources: src/riscv/uspace.rs(L12 - L35)  src/aarch64/uspace.rs(L12 - L38)  src/loongarch64/uspace.rs(L12 - L32) 

The new() method performs architecture-specific initialization:

Context Access Methods

All architectures provide consistent getter and setter methods:

MethodPurposeRISC-VAArch64LoongArch64
get_ip()Get instruction pointerself.0.sepcself.0.elrself.0.era
get_sp()Get stack pointerself.0.regs.spself.0.uspself.0.regs.sp
set_ip()Set instruction pointerself.0.sepc = pcself.0.elr = pcself.0.era = pc
set_sp()Set stack pointerself.0.regs.sp = spself.0.usp = spself.0.regs.sp = sp
set_retval()Set return valueself.0.regs.a0 = a0self.0.r[0] = r0self.0.regs.a0 = a0

Sources: src/riscv/uspace.rs(L37 - L61)  src/aarch64/uspace.rs(L40 - L63)  src/loongarch64/uspace.rs(L34 - L57) 

User Space Entry Process

The enter_uspace() method performs the critical transition from kernel mode to user mode. This is an unsafe operation that fundamentally changes the processor's execution context.

flowchart TD
subgraph subGraph1["Architecture-Specific Details"]
    RISCV_IMPL["RISC-V: sscratch, sepc, sret"]
    AARCH64_IMPL["AArch64: sp_el0, elr_el1, spsr_el1, eret"]
    LOONGARCH64_IMPL["LoongArch64: era, PRMD, ertn"]
end
subgraph subGraph0["enter_uspace() Flow"]
    START["enter_uspace(kstack_top)"]
    DISABLE_IRQ["Disable interrupts"]
    SETUP_KERNEL_STACK["Setup kernel stack for trap handling"]
    CONFIGURE_ARCH["Architecture-specific register setup"]
    RESTORE_CONTEXT["Restore user context from TrapFrame"]
    SWITCH_MODE["Switch to user mode"]
    USER_EXEC["Execute user code"]
    TRAP_RETURN["[On trap/syscall] Return to kernel"]
end

CONFIGURE_ARCH --> AARCH64_IMPL
CONFIGURE_ARCH --> LOONGARCH64_IMPL
CONFIGURE_ARCH --> RESTORE_CONTEXT
CONFIGURE_ARCH --> RISCV_IMPL
DISABLE_IRQ --> SETUP_KERNEL_STACK
RESTORE_CONTEXT --> SWITCH_MODE
SETUP_KERNEL_STACK --> CONFIGURE_ARCH
START --> DISABLE_IRQ
SWITCH_MODE --> USER_EXEC
USER_EXEC --> TRAP_RETURN

Sources: src/riscv/uspace.rs(L72 - L102)  src/aarch64/uspace.rs(L75 - L111)  src/loongarch64/uspace.rs(L69 - L96) 

Architecture-Specific Entry Implementation

Each architecture implements the final transition using inline assembly:

RISC-V Implementation:

AArch64 Implementation:

LoongArch64 Implementation:

Cross-Architecture Design Patterns

The user space support demonstrates several consistent design patterns across architectures:

Trap Frame Reuse

All implementations leverage the existing TrapFrame structure rather than defining separate user context formats. This provides consistency with the trap handling infrastructure and ensures that user contexts contain all necessary state for exception handling.

Kernel Stack Management

Each architecture properly configures the kernel stack pointer to handle subsequent traps or system calls from user mode:

Register State Initialization

The new() method in each architecture sets appropriate processor state flags for user mode execution, ensuring proper privilege levels and interrupt handling configuration.

Sources: src/riscv/uspace.rs(L1 - L104)  src/aarch64/uspace.rs(L1 - L113)  src/loongarch64/uspace.rs(L1 - L98)