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