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}