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 Range | Register Category | Handler Functions |
---|---|---|
0x800_0000 + 0x000 | Control Register (VGICD_CTLR) | handle_write8/16/32 |
0x800_0000 + 0x100-0x104 | Interrupt Set Enable (VGICD_ISENABLER) | handle_write8/16/32 |
0x800_0000 + 0x180-0x184 | Interrupt Clear Enable (VGICD_ICENABLER) | handle_write8/16/32 |
0x800_0000 + 0x200 | Interrupt 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)