Device Operations Interface
Relevant source files
Purpose and Scope
This document covers the Device Operations Interface implementation in the arm_vgic crate, which provides the integration layer between the Virtual Generic Interrupt Controller (VGIC) and the ArceOS device framework. The interface enables the hypervisor to expose the virtual GIC as a memory-mapped device to guest virtual machines.
For details about the core VGIC controller functionality, see Virtual GIC Controller (Vgic). For information about the CPU interface components, see CPU Interface (Vgicc).
BaseDeviceOps Trait Implementation
The VGIC integrates with the ArceOS device framework through the BaseDeviceOps trait implementation. This trait provides the standard interface for emulated devices within the hypervisor ecosystem.
Device Operations Structure
flowchart TD
subgraph subGraph3["VGIC Core Methods"]
Read8["handle_read8()"]
Read16["handle_read16()"]
Read32["handle_read32()"]
Write8["handle_write8()"]
Write16["handle_write16()"]
Write32["handle_write32()"]
end
subgraph subGraph2["VGIC Implementation"]
VgicStruct["VgicMain Controller"]
DevOpsImpl["impl BaseDeviceOps for Vgic"]
subgraph subGraph1["Trait Methods"]
EmuType["emu_type()→ EmuDeviceTGicdV2"]
AddrRange["address_range()→ 0x800_0000-0x800_FFFF"]
HandleRead["handle_read()→ Width Dispatch"]
HandleWrite["handle_write()→ Width Dispatch"]
end
end
subgraph subGraph0["ArceOS Device Framework"]
BaseDeviceOps["BaseDeviceOpsTrait"]
EmuDeviceType["EmuDeviceTypeEnum"]
GuestPhysAddr["GuestPhysAddrAddress Type"]
end
BaseDeviceOps --> DevOpsImpl
DevOpsImpl --> AddrRange
DevOpsImpl --> EmuType
DevOpsImpl --> HandleRead
DevOpsImpl --> HandleWrite
HandleRead --> Read16
HandleRead --> Read32
HandleRead --> Read8
HandleWrite --> Write16
HandleWrite --> Write32
HandleWrite --> Write8
VgicStruct --> DevOpsImpl
Sources: src/devops_impl.rs(L1 - L99) src/vgic.rs(L32 - L34)
Device Type and Address Mapping
The VGIC device is identified as EmuDeviceTGicdV2, indicating it emulates a Generic Interrupt Controller Distributor version 2. The device occupies a 64KB memory region in the guest physical address space.
| Property | Value | Description |
|---|---|---|
| Device Type | EmuDeviceTGicdV2 | GICv2 Distributor Emulation |
| Base Address | 0x800_0000 | Guest physical start address |
| Size | 0x10000(64KB) | Total address space |
| Address Mask | 0xfff | 4KB page alignment |
Address Range Implementation
flowchart TD
subgraph subGraph2["Register Space"]
RegisterOffset["Register OffsetWithin 4KB page"]
VGICDRegs["VGICD RegistersControl, Enable, Priority, etc."]
end
subgraph subGraph1["Address Processing"]
AddrRange["address_range()Returns: 0x800_0000-0x800_FFFF"]
AddrMask["Address Maskingaddr & 0xfff"]
end
subgraph subGraph0["Guest VM Memory Access"]
GuestAccess["Guest Memory Access0x800_0000 + offset"]
end
AddrMask --> RegisterOffset
AddrRange --> AddrMask
GuestAccess --> AddrRange
RegisterOffset --> VGICDRegs
Sources: src/devops_impl.rs(L29 - L31) src/devops_impl.rs(L47) src/devops_impl.rs(L79)
Read Operation Handling
The handle_read method provides width-based dispatching for memory read operations. The implementation supports 8-bit, 16-bit, and 32-bit read operations.
Read Operation Flow
flowchart TD
subgraph subGraph2["VGIC Read Handlers"]
HandleRead8["handle_read8(addr)Returns: AxResult"]
HandleRead16["handle_read16(addr)Returns: AxResult"]
HandleRead32["handle_read32(addr)Returns: AxResult"]
end
subgraph subGraph1["Width Dispatch"]
WidthMatch["match width"]
Width1["width == 18-bit read"]
Width2["width == 216-bit read"]
Width4["width == 432-bit read"]
WidthOther["_ => Ok(0)Unsupported width"]
end
subgraph subGraph0["Read Entry Point"]
HandleRead["handle_read()Parameters: addr, width"]
AddrMask["addr = addr.as_usize() & 0xfff"]
end
AddrMask --> WidthMatch
HandleRead --> AddrMask
Width1 --> HandleRead8
Width2 --> HandleRead16
Width4 --> HandleRead32
WidthMatch --> Width1
WidthMatch --> Width2
WidthMatch --> Width4
WidthMatch --> WidthOther
Sources: src/devops_impl.rs(L45 - L66) src/vgic.rs(L56 - L66)
Write Operation Handling
The handle_write method manages memory write operations with similar width-based dispatching. Write operations modify the virtual GIC state and may trigger hardware GIC operations.
Write Operation Dispatch and Register Handling
flowchart TD
subgraph subGraph3["State Management"]
MutexLock["vgic_inner.lock()"]
CtrlrUpdate["vgic_inner.ctrlr = val & 0b11"]
IRQLoop["Loop: SGI_ID_MAX..SPI_ID_MAX"]
GicInterface["GicInterface::set_enable()GicInterface::set_priority()"]
end
subgraph subGraph2["Register Address Matching"]
AddrMatch["match addr"]
VGICD_CTLR["VGICD_CTLRControl Register"]
VGICD_ISENABLER["VGICD_ISENABLER_*Enable Registers"]
UnknownAddr["_ => error!()"]
end
subgraph subGraph1["Width Dispatch"]
WriteMatch["match width"]
WriteWidth1["width == 1handle_write8()"]
WriteWidth2["width == 2handle_write16()"]
WriteWidth4["width == 4handle_write32()"]
end
subgraph subGraph0["Write Entry Point"]
HandleWrite["handle_write()Parameters: addr, width, val"]
WriteMask["addr = addr.as_usize() & 0xfff"]
end
AddrMatch --> UnknownAddr
AddrMatch --> VGICD_CTLR
AddrMatch --> VGICD_ISENABLER
CtrlrUpdate --> IRQLoop
HandleWrite --> WriteMask
IRQLoop --> GicInterface
MutexLock --> CtrlrUpdate
VGICD_CTLR --> MutexLock
WriteMask --> WriteMatch
WriteMatch --> WriteWidth1
WriteMatch --> WriteWidth2
WriteMatch --> WriteWidth4
WriteWidth1 --> AddrMatch
WriteWidth2 --> AddrMatch
WriteWidth4 --> AddrMatch
Sources: src/devops_impl.rs(L77 - L98) src/vgic.rs(L68 - L133)
Integration with VGIC Core
The device operations interface serves as the bridge between guest VM memory accesses and the internal VGIC state management. Key integration points include:
Core Integration Components
| Component | Purpose | Implementation |
|---|---|---|
| VgicInner | Protected state storage | Mutex-wrapped internal state |
| Register handlers | Address-specific logic | Match-based dispatch in write methods |
| Hardware interface | Physical GIC operations | arm_gicv2::GicInterfacecalls |
| Error handling | Operation validation | AxResult |
State Synchronization
The interface ensures thread-safe access to the VGIC state through mutex protection. Write operations that modify interrupt enable states trigger corresponding operations on the physical GIC hardware.
flowchart TD
subgraph subGraph2["Hardware Interface"]
GicSetEnable["GicInterface::set_enable()"]
GicSetPriority["GicInterface::set_priority()"]
PhysicalGIC["Physical GIC Hardware"]
end
subgraph subGraph1["VGIC Processing"]
DevOpsWrite["handle_write()"]
StateUpdate["VgicInner Updateused_irq[] modification"]
MutexProtection["Mutex"]
end
subgraph subGraph0["Guest Operation"]
GuestWrite["Guest WriteEnable Interrupt"]
end
DevOpsWrite --> MutexProtection
GicSetEnable --> PhysicalGIC
GicSetPriority --> PhysicalGIC
GuestWrite --> DevOpsWrite
MutexProtection --> StateUpdate
StateUpdate --> GicSetEnable
StateUpdate --> GicSetPriority