System Architecture

Relevant source files

Purpose and Scope

This document provides a comprehensive overview of the arm_vgic crate's system architecture, detailing how it implements a Virtual Generic Interrupt Controller (VGIC) for ARM systems within the ArceOS hypervisor ecosystem. The architecture encompasses the virtualization of ARM GICv2 hardware, memory-mapped register emulation, and integration with the hypervisor's device framework.

For detailed information about individual components and their APIs, see Core Components. For dependency analysis and integration patterns, see Dependencies and Integration.

Virtualization Stack Positioning

The arm_vgic crate operates as a critical virtualization layer between guest operating systems and physical ARM GIC hardware. The architecture follows a clean separation of concerns across multiple abstraction levels.

Hypervisor Stack Architecture

flowchart TD
subgraph PhysicalHW["Physical Hardware"]
    ARMCores["ARM CPU Cores"]
    PhysicalGIC["Physical GIC Hardware"]
    MemorySystem["Memory Subsystem"]
end
subgraph ArceOSHypervisor["ArceOS Hypervisor Layer"]
    subgraph HardwareAbstraction["Hardware Abstraction"]
        ArmGicV2["arm_gicv2::GicInterface"]
        MemoryAddr["memory_addr"]
    end
    subgraph FrameworkLayer["Framework Layer"]
        BaseDeviceOps["BaseDeviceOps"]
        AxDeviceBase["axdevice_base"]
        AxAddrSpace["axaddrspace"]
    end
    subgraph DeviceEmulation["Device Emulation Layer"]
        VgicController["Vgic"]
        VgicInner["VgicInner"]
        VgiccState["Vgicc"]
    end
end
subgraph GuestVM["Guest Virtual Machine"]
    GuestOS["Guest OS Kernel"]
    GuestDrivers["Device Drivers"]
    GuestHandlers["Interrupt Handlers"]
end

ArmGicV2 --> PhysicalGIC
ArmGicV2 --> VgicController
BaseDeviceOps --> AxDeviceBase
GuestDrivers --> VgicController
GuestHandlers --> VgicController
MemoryAddr --> MemorySystem
PhysicalGIC --> ArmGicV2
VgicController --> AxAddrSpace
VgicController --> BaseDeviceOps
VgicController --> GuestHandlers
VgicController --> VgicInner
VgicInner --> VgiccState

Sources: src/vgic.rs(L32 - L34)  src/devops_impl.rs(L10)  src/vgicc.rs(L3) 

The Vgic struct serves as the primary interface between guest VMs and the physical interrupt controller, implementing memory-mapped register emulation at the standardized ARM GIC address space of 0x800_0000 to 0x800_FFFF.

Core Architecture Components

The system architecture is built around four primary components that work together to provide complete interrupt controller virtualization.

Component Relationship Architecture

flowchart TD
subgraph ExternalDeps["External Dependencies"]
    SpinMutex["spin::Mutex"]
    ArmGicV2Interface["arm_gicv2::GicInterface"]
    AxDeviceBase["axdevice_base"]
end
subgraph CoreImplementation["Core Implementation"]
    subgraph DevOpsModule["devops_impl.rs"]
        BaseDeviceOpsImpl["BaseDeviceOps impl"]
        EmuType["emu_type()"]
        AddressRange["address_range()"]
        HandleRead["handle_read()"]
        HandleWrite["handle_write()"]
    end
    subgraph ConstsModule["consts.rs"]
        SGI_ID_MAX["SGI_ID_MAX"]
        PPI_ID_MAX["PPI_ID_MAX"]
        SPI_ID_MAX["SPI_ID_MAX"]
        VGICD_CTLR["VGICD_CTLR"]
        VGICD_ISENABLER_SGI_PPI["VGICD_ISENABLER_SGI_PPI"]
        VGICD_ISENABLER_SPI["VGICD_ISENABLER_SPI"]
    end
    subgraph VgiccModule["vgicc.rs"]
        VgiccStruct["Vgicc"]
        PendingLR["pending_lr[SPI_ID_MAX]"]
        SavedLR["saved_lr[GICD_LR_NUM]"]
        SavedRegs["saved_elsr0, saved_apr, saved_hcr"]
    end
    subgraph VgicModule["vgic.rs"]
        VgicStruct["Vgic"]
        VgicInnerStruct["VgicInner"]
        HandleRead8["handle_read8"]
        HandleRead16["handle_read16"]
        HandleRead32["handle_read32"]
        HandleWrite8["handle_write8"]
        HandleWrite16["handle_write16"]
        HandleWrite32["handle_write32"]
    end
end
subgraph PublicAPI["Public API Layer"]
    LibRS["lib.rs"]
    VgicExport["pub use vgic::Vgic"]
end

BaseDeviceOpsImpl --> AxDeviceBase
BaseDeviceOpsImpl --> HandleRead
BaseDeviceOpsImpl --> HandleWrite
HandleRead --> HandleRead16
HandleRead --> HandleRead32
HandleRead --> HandleRead8
HandleRead8 --> VGICD_CTLR
HandleWrite --> HandleWrite16
HandleWrite --> HandleWrite32
HandleWrite --> HandleWrite8
HandleWrite8 --> ArmGicV2Interface
HandleWrite8 --> SGI_ID_MAX
HandleWrite8 --> SPI_ID_MAX
HandleWrite8 --> VGICD_CTLR
HandleWrite8 --> VGICD_ISENABLER_SGI_PPI
LibRS --> VgicExport
VgicExport --> VgicStruct
VgicInnerStruct --> VgiccStruct
VgicStruct --> SpinMutex
VgicStruct --> VgicInnerStruct
VgiccStruct --> PendingLR
VgiccStruct --> SavedLR
VgiccStruct --> SavedRegs

Sources: src/vgic.rs(L15 - L30)  src/vgicc.rs(L3 - L14)  src/consts.rs(L1 - L19)  src/devops_impl.rs(L10 - L99) 

Memory Layout and Address Handling

The VGIC implements a memory-mapped interface that emulates the standard ARM GICv2 distributor registers. The address decoding and dispatch mechanism ensures proper isolation and functionality.

Address Space and Register Layout

Address RangeRegister CategoryHandler Functions
0x800_0000 + 0x000Control Register (VGICD_CTLR)handle_write8/16/32
0x800_0000 + 0x100-0x104Interrupt Set Enable (VGICD_ISENABLER)handle_write8/16/32
0x800_0000 + 0x180-0x184Interrupt Clear Enable (VGICD_ICENABLER)handle_write8/16/32
0x800_0000 + 0x200Interrupt Set Pending (VGICD_ISPENDR)handle_write8/16/32

Sources: src/consts.rs(L7 - L18)  src/devops_impl.rs(L29 - L31)  src/devops_impl.rs(L47) 

The address range spans 64KB (0x10000 bytes) starting at 0x800_0000, with address masking applied using addr & 0xfff to ensure proper alignment within the 4KB register space.

Data Flow Architecture

The system processes guest memory accesses through a well-defined pipeline that maintains virtualization transparency while interfacing with physical hardware.

Memory Access Processing Pipeline

flowchart TD
subgraph PhysicalInterface["Physical Interface"]
    GicInterface["arm_gicv2::GicInterface"]
    SetEnable["set_enable(irq, bool)"]
    SetPriority["set_priority(irq, u8)"]
end
subgraph StateManagement["State Management"]
    UsedIRQ["used_irq[SPI_ID_MAX/32]"]
    PTOV["ptov[SPI_ID_MAX]"]
    VTOP["vtop[SPI_ID_MAX]"]
    GICDRegs["gicd_* register arrays"]
end
subgraph RegisterHandling["Register Handling"]
    CTLRHandler["VGICD_CTLR Handler"]
    ENABLERHandler["ISENABLER/ICENABLER"]
    PENDRHandler["ISPENDR/ICPENDR"]
    MutexLock["VgicInner Mutex Lock"]
end
subgraph AddressProcessing["Address Processing"]
    AddrDecode["Address DecodingGuestPhysAddr"]
    AddrMask["Address Maskingaddr & 0xfff"]
    WidthDispatch["Width Dispatch1/2/4 bytes"]
end
subgraph GuestAccess["Guest Memory Access"]
    VMRead["VM Read Operation"]
    VMWrite["VM Write Operation"]
end

AddrDecode --> AddrMask
AddrMask --> WidthDispatch
CTLRHandler --> GicInterface
CTLRHandler --> MutexLock
ENABLERHandler --> MutexLock
GicInterface --> SetEnable
GicInterface --> SetPriority
MutexLock --> GICDRegs
MutexLock --> PTOV
MutexLock --> UsedIRQ
MutexLock --> VTOP
VMRead --> AddrDecode
VMWrite --> AddrDecode
WidthDispatch --> CTLRHandler
WidthDispatch --> ENABLERHandler
WidthDispatch --> PENDRHandler

Sources: src/devops_impl.rs(L45 - L66)  src/devops_impl.rs(L77 - L98)  src/vgic.rs(L68 - L133)  src/vgic.rs(L15 - L30) 

The data flow ensures thread-safe access through mutex protection of the VgicInner state, while maintaining efficient dispatch based on access width and register offset. Physical GIC operations are performed only when necessary, such as during control register updates that enable or disable interrupt groups.

Thread Safety and Concurrency

The architecture employs a mutex-protected inner state design to ensure thread-safe operation across multiple CPU cores accessing the virtual interrupt controller simultaneously.

The VgicInner struct src/vgic.rs(L15 - L30)  contains all mutable state protected by a spin::Mutex src/vgic.rs(L33)  including interrupt tracking arrays, virtual-to-physical mapping tables, and register state. This design allows multiple guest CPUs to safely access the VGIC while maintaining consistency of the virtualized interrupt controller state.

Sources: src/vgic.rs(L32 - L53)  src/vgic.rs(L76)  src/devops_impl.rs(L1 - L8)