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