Skip to main content

axvm_types/
lib.rs

1// Copyright 2025 The Axvisor Team
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Shared base types for AxVM and virtualization capability components.
16//!
17//! This crate intentionally contains only small value types and aliases. It is
18//! not a host capability API and must not depend on any OS-specific crate.
19
20#![no_std]
21
22extern crate alloc;
23
24use alloc::{string::String, vec::Vec};
25use core::fmt::{Display, Formatter};
26
27use ax_memory_addr::{AddrRange, PhysAddr, VirtAddr, def_usize_addr, def_usize_addr_formatter};
28
29/// Virtual machine identifier.
30pub type VMId = usize;
31
32/// Virtual CPU identifier within a VM.
33pub type VCpuId = usize;
34
35/// Interrupt vector number injected into a guest.
36pub type InterruptVector = u8;
37
38/// The maximum number of virtual CPUs supported in a virtual machine.
39pub const MAX_VCPU_NUM: usize = 64;
40
41/// A set of virtual CPUs.
42pub type VCpuSet = ax_cpumask::CpuMask<MAX_VCPU_NUM>;
43
44/// Host virtual address.
45pub type HostVirtAddr = VirtAddr;
46
47/// Host physical address.
48pub type HostPhysAddr = PhysAddr;
49
50def_usize_addr! {
51    /// Guest virtual address.
52    pub type GuestVirtAddr;
53
54    /// Guest physical address.
55    pub type GuestPhysAddr;
56}
57
58def_usize_addr_formatter! {
59    GuestVirtAddr = "GVA:{}";
60    GuestPhysAddr = "GPA:{}";
61}
62
63/// Guest virtual address range.
64pub type GuestVirtAddrRange = AddrRange<GuestVirtAddr>;
65
66/// Guest physical address range.
67pub type GuestPhysAddrRange = AddrRange<GuestPhysAddr>;
68
69/// Common AxVM result type.
70pub type AxVmResult<T = ()> = ax_errno::AxResult<T>;
71
72/// Common AxVM error type.
73pub type AxVmError = ax_errno::AxError;
74
75/// A part of `AxVMConfig`, which represents guest VM type.
76#[derive(Default, Clone, Copy, PartialEq, Eq, Debug)]
77pub enum VMType {
78    /// Host VM, used for boot from Linux like Jailhouse do, named "type1.5".
79    VMTHostVM = 0,
80    /// Guest RTOS, generally a simple guest OS with most of the resource passthrough.
81    #[default]
82    VMTRTOS   = 1,
83    /// Guest Linux, generally a full-featured guest OS with complicated device emulation requirements.
84    VMTLinux  = 2,
85}
86
87impl From<usize> for VMType {
88    fn from(value: usize) -> Self {
89        match value {
90            0 => Self::VMTHostVM,
91            1 => Self::VMTRTOS,
92            2 => Self::VMTLinux,
93            _ => Self::default(),
94        }
95    }
96}
97
98impl From<VMType> for usize {
99    fn from(value: VMType) -> Self {
100        value as usize
101    }
102}
103
104/// The type of memory mapping used for VM memory regions.
105#[derive(Debug, Default, Clone, PartialEq, Eq)]
106#[repr(u8)]
107pub enum VmMemMappingType {
108    /// The memory region is allocated by the VM monitor.
109    #[default]
110    MapAlloc     = 0,
111    /// The memory region is identical to the host physical memory region.
112    MapIdentical = 1,
113    /// The memory region is reserved memory for the guest OS.
114    MapReserved  = 2,
115}
116
117/// Configuration for a virtual machine memory region.
118#[derive(Debug, Default, Clone)]
119pub struct VmMemConfig {
120    /// The start address of the memory region in GPA (Guest Physical Address).
121    pub gpa: usize,
122    /// The size of the memory region in bytes.
123    pub size: usize,
124    /// The mappings flags of the memory region.
125    pub flags: usize,
126    /// The type of memory mapping.
127    pub map_type: VmMemMappingType,
128}
129
130/// A part of `AxVMConfig`, which represents the configuration of an emulated device for a virtual machine.
131#[derive(Debug, Default, Clone)]
132pub struct EmulatedDeviceConfig {
133    /// The name of the device.
134    pub name: String,
135    /// The base GPA (Guest Physical Address) of the device.
136    pub base_gpa: usize,
137    /// The address length of the device.
138    pub length: usize,
139    /// The IRQ (Interrupt Request) ID of the device.
140    pub irq_id: usize,
141    /// The type of emulated device.
142    pub emu_type: EmulatedDeviceType,
143    /// The config list of the device.
144    pub cfg_list: Vec<usize>,
145}
146
147/// A part of `AxVMConfig`, which represents the configuration of a pass-through device for a virtual machine.
148#[derive(Debug, Default, Clone, PartialEq)]
149pub struct PassThroughDeviceConfig {
150    /// The name of the device.
151    pub name: String,
152    /// The base GPA (Guest Physical Address) of the device.
153    pub base_gpa: usize,
154    /// The base HPA (Host Physical Address) of the device.
155    pub base_hpa: usize,
156    /// The address length of the device.
157    pub length: usize,
158    /// The IRQ (Interrupt Request) ID of the device.
159    pub irq_id: usize,
160}
161
162/// A part of `AxVMConfig`, which represents the configuration of a pass-through address for a virtual machine.
163#[derive(Debug, Default, Clone, PartialEq)]
164pub struct PassThroughAddressConfig {
165    /// The base GPA (Guest Physical Address).
166    pub base_gpa: usize,
167    /// The address length.
168    pub length: usize,
169}
170
171/// Describes how a guest VM should enter its boot image.
172#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
173pub enum VMBootProtocol {
174    /// Enter the configured kernel entry directly without a firmware image.
175    #[default]
176    Direct,
177    /// Use the legacy x86 axvm-bios/multiboot trampoline.
178    Multiboot,
179    /// Load an external UEFI firmware image and enter it without multiboot patching.
180    Uefi,
181}
182
183/// Specifies how the VM should handle interrupts and interrupt controllers.
184#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
185pub enum VMInterruptMode {
186    /// The VM will not handle interrupts, and the guest OS should not use interrupts.
187    #[default]
188    NoIrq,
189    /// The VM will use the emulated interrupt controller to handle interrupts.
190    Emulated,
191    /// The VM will use the passthrough interrupt controller (including GPPT) to handle interrupts.
192    Passthrough,
193}
194
195/// The type of emulated device.
196///
197/// Allocation scheme:
198/// - 0x00 - 0x1F: Special devices, and abstract device types that does not specify a concrete
199///   interface or implementation. The device objects created from these types depend on the target
200///   architecture and the specific implementation of the hypervisor.
201/// - 0x20 - 0x7F: Concrete emulated device types.
202///   - 0x20 - 0x2F: Interrupt controller devices.
203///   - 0x30 - 0x3F: Reserved for future use.
204/// - 0x80 - 0xDF: Reserved for future use.
205/// - 0xE0 - 0xEF: Virtio devices.
206/// - 0xF0 - 0xFF: Reserved for future use.
207#[derive(Debug, Default, Copy, Clone, PartialEq, Eq)]
208#[repr(u8)]
209pub enum EmulatedDeviceType {
210    // Special devices and abstract device types.
211    /// Dummy device type.
212    #[default]
213    Dummy               = 0x0,
214    /// Interrupt controller device, e.g. vGICv2 in aarch64, vLAPIC in x86.
215    InterruptController = 0x1,
216    /// Console (serial) device.
217    Console             = 0x2,
218    /// An emulated device that provides Inter-VM Communication (IVC) channel.
219    ///
220    /// This device is used for communication between different VMs,
221    /// the corresponding memory region of this device should be marked as `Reserved` in
222    /// device tree or ACPI table.
223    IVCChannel          = 0xA,
224
225    // Arch-specific interrupt controller devices.
226    // 0x20 - 0x22: GPPT (GIC Partial Passthrough) devices.
227    /// ARM GIC Partial Passthrough Redistributor device.
228    GPPTRedistributor   = 0x20,
229    /// ARM GIC Partial Passthrough Distributor device.
230    GPPTDistributor     = 0x21,
231    /// ARM GIC Partial Passthrough Interrupt Translation Service device.
232    GPPTITS             = 0x22,
233
234    // 0x23 - 0x24: x86 platform devices.
235    /// x86 virtual IO APIC device.
236    X86IoApic           = 0x23,
237    /// x86 virtual PIT/8254 timer device.
238    X86Pit              = 0x24,
239
240    // 0x30: PPPT (PLIC Partial Passthrough) devices.
241    /// RISC-V PLIC Partial Passthrough Global device.
242    PPPTGlobal          = 0x30,
243
244    // Virtio devices.
245    /// Virtio block device.
246    VirtioBlk           = 0xE1,
247    /// Virtio net device.
248    VirtioNet           = 0xE2,
249    /// Virtio console device.
250    VirtioConsole       = 0xE3,
251    // Following are some other emulated devices that are not currently used and removed from the enum temporarily.
252    // /// IOMMU device.
253    // IOMMU = 0x6,
254    // /// Interrupt ICC SRE device.
255    // ICCSRE = 0x7,
256    // /// Interrupt ICC SGIR device.
257    // SGIR = 0x8,
258    // /// Interrupt controller GICR device.
259    // GICR = 0x9,
260}
261
262impl Display for EmulatedDeviceType {
263    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
264        match self {
265            EmulatedDeviceType::Console => write!(f, "console"),
266            EmulatedDeviceType::InterruptController => write!(f, "interrupt controller"),
267            EmulatedDeviceType::GPPTRedistributor => {
268                write!(f, "gic partial passthrough redistributor")
269            }
270            EmulatedDeviceType::GPPTDistributor => write!(f, "gic partial passthrough distributor"),
271            EmulatedDeviceType::GPPTITS => write!(f, "gic partial passthrough its"),
272            EmulatedDeviceType::X86IoApic => write!(f, "x86 io apic"),
273            EmulatedDeviceType::X86Pit => write!(f, "x86 pit"),
274            EmulatedDeviceType::PPPTGlobal => write!(f, "plic partial passthrough global"),
275            // EmulatedDeviceType::IOMMU => write!(f, "iommu"),
276            // EmulatedDeviceType::ICCSRE => write!(f, "interrupt icc sre"),
277            // EmulatedDeviceType::SGIR => write!(f, "interrupt icc sgir"),
278            // EmulatedDeviceType::GICR => write!(f, "interrupt controller gicr"),
279            EmulatedDeviceType::IVCChannel => write!(f, "ivc channel"),
280            EmulatedDeviceType::Dummy => write!(f, "meta device"),
281            EmulatedDeviceType::VirtioBlk => write!(f, "virtio block"),
282            EmulatedDeviceType::VirtioNet => write!(f, "virtio net"),
283            EmulatedDeviceType::VirtioConsole => write!(f, "virtio console"),
284        }
285    }
286}
287
288impl EmulatedDeviceType {
289    /// All known emulated device types.
290    pub const ALL: [Self; 13] = [
291        EmulatedDeviceType::Dummy,
292        EmulatedDeviceType::InterruptController,
293        EmulatedDeviceType::Console,
294        EmulatedDeviceType::IVCChannel,
295        EmulatedDeviceType::GPPTRedistributor,
296        EmulatedDeviceType::GPPTDistributor,
297        EmulatedDeviceType::GPPTITS,
298        EmulatedDeviceType::X86IoApic,
299        EmulatedDeviceType::X86Pit,
300        EmulatedDeviceType::PPPTGlobal,
301        EmulatedDeviceType::VirtioBlk,
302        EmulatedDeviceType::VirtioNet,
303        EmulatedDeviceType::VirtioConsole,
304    ];
305
306    /// Returns all known emulated device types.
307    pub const fn all() -> &'static [Self] {
308        &Self::ALL
309    }
310
311    /// Returns true if the device is removable.
312    pub fn removable(&self) -> bool {
313        matches!(
314            *self,
315            EmulatedDeviceType::InterruptController
316                // | EmulatedDeviceType::SGIR
317                // | EmulatedDeviceType::ICCSRE
318                | EmulatedDeviceType::GPPTRedistributor
319                | EmulatedDeviceType::X86IoApic
320                | EmulatedDeviceType::X86Pit
321                | EmulatedDeviceType::VirtioBlk
322                | EmulatedDeviceType::VirtioNet
323                // | EmulatedDeviceType::GICR
324                | EmulatedDeviceType::VirtioConsole
325        )
326    }
327
328    /// Converts a `usize` value to an `EmulatedDeviceType`.
329    pub const fn from_usize(value: usize) -> Option<Self> {
330        match value {
331            0x0 => Some(EmulatedDeviceType::Dummy),
332            0x1 => Some(EmulatedDeviceType::InterruptController),
333            0x2 => Some(EmulatedDeviceType::Console),
334            0xA => Some(EmulatedDeviceType::IVCChannel),
335            0x20 => Some(EmulatedDeviceType::GPPTRedistributor),
336            0x21 => Some(EmulatedDeviceType::GPPTDistributor),
337            0x22 => Some(EmulatedDeviceType::GPPTITS),
338            0x23 => Some(EmulatedDeviceType::X86IoApic),
339            0x24 => Some(EmulatedDeviceType::X86Pit),
340            0x30 => Some(EmulatedDeviceType::PPPTGlobal),
341            0xE1 => Some(EmulatedDeviceType::VirtioBlk),
342            0xE2 => Some(EmulatedDeviceType::VirtioNet),
343            0xE3 => Some(EmulatedDeviceType::VirtioConsole),
344            // 0x6 => EmulatedDeviceType::IOMMU,
345            // 0x7 => EmulatedDeviceType::ICCSRE,
346            // 0x8 => EmulatedDeviceType::SGIR,
347            // 0x9 => EmulatedDeviceType::GICR,
348            _ => None,
349        }
350    }
351}
352
353#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
354impl ax_page_table_multiarch::riscv::SvVirtAddr for GuestPhysAddr {
355    /// Flushes the TLB for the entire address space.
356    ///
357    /// `hfence.vvma` does not access host memory.
358    fn flush_tlb(_vaddr: Option<Self>) {
359        unsafe {
360            core::arch::asm!("hfence.vvma", options(nostack, nomem, preserves_flags));
361        }
362    }
363}