#![cfg_attr(not(feature = "std"), no_std)]
extern crate alloc;
#[macro_use]
extern crate log;
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt::{Display, Formatter};
use enumerable::Enumerable;
use serde_repr::{Deserialize_repr, Serialize_repr};
use axerrno::AxResult;
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Default, Clone, Copy, PartialEq, Eq, Debug, serde::Serialize, serde::Deserialize)]
pub enum VMType {
VMTHostVM = 0,
#[default]
VMTRTOS = 1,
VMTLinux = 2,
}
impl From<usize> for VMType {
fn from(value: usize) -> Self {
match value {
0 => Self::VMTHostVM,
1 => Self::VMTRTOS,
2 => Self::VMTLinux,
_ => {
warn!("Unknown VmType value: {}, default to VMTRTOS", value);
Self::default()
}
}
}
}
impl From<VMType> for usize {
fn from(value: VMType) -> Self {
value as usize
}
}
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Debug, Clone, PartialEq, Eq, serde_repr::Serialize_repr, serde_repr::Deserialize_repr)]
#[repr(u8)]
pub enum VmMemMappingType {
MapAlloc = 0,
MapIdentical = 1,
MapReserved = 2,
}
impl Default for VmMemMappingType {
fn default() -> Self {
Self::MapAlloc
}
}
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
pub struct VmMemConfig {
pub gpa: usize,
pub size: usize,
pub flags: usize,
pub map_type: VmMemMappingType,
}
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(
Debug, Default, Copy, Clone, PartialEq, Eq, Serialize_repr, Deserialize_repr, Enumerable,
)]
#[repr(u8)]
pub enum EmulatedDeviceType {
#[default]
Dummy = 0x0,
InterruptController = 0x1,
Console = 0x2,
IVCChannel = 0xA,
GPPTRedistributor = 0x20,
GPPTDistributor = 0x21,
GPPTITS = 0x22,
PPPTGlobal = 0x30,
VirtioBlk = 0xE1,
VirtioNet = 0xE2,
VirtioConsole = 0xE3,
}
impl Display for EmulatedDeviceType {
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
match self {
EmulatedDeviceType::Console => write!(f, "console"),
EmulatedDeviceType::InterruptController => write!(f, "interrupt controller"),
EmulatedDeviceType::GPPTRedistributor => {
write!(f, "gic partial passthrough redistributor")
}
EmulatedDeviceType::GPPTDistributor => write!(f, "gic partial passthrough distributor"),
EmulatedDeviceType::GPPTITS => write!(f, "gic partial passthrough its"),
EmulatedDeviceType::PPPTGlobal => write!(f, "plic partial passthrough global"),
EmulatedDeviceType::IVCChannel => write!(f, "ivc channel"),
EmulatedDeviceType::Dummy => write!(f, "meta device"),
EmulatedDeviceType::VirtioBlk => write!(f, "virtio block"),
EmulatedDeviceType::VirtioNet => write!(f, "virtio net"),
EmulatedDeviceType::VirtioConsole => write!(f, "virtio console"),
}
}
}
impl EmulatedDeviceType {
pub fn removable(&self) -> bool {
matches!(
*self,
EmulatedDeviceType::InterruptController
| EmulatedDeviceType::GPPTRedistributor
| EmulatedDeviceType::VirtioBlk
| EmulatedDeviceType::VirtioNet
| EmulatedDeviceType::VirtioConsole
)
}
pub fn from_usize(value: usize) -> EmulatedDeviceType {
match value {
0x0 => EmulatedDeviceType::Dummy,
0x1 => EmulatedDeviceType::InterruptController,
0x2 => EmulatedDeviceType::Console,
0xA => EmulatedDeviceType::IVCChannel,
0x20 => EmulatedDeviceType::GPPTRedistributor,
0x21 => EmulatedDeviceType::GPPTDistributor,
0x22 => EmulatedDeviceType::GPPTITS,
0x30 => EmulatedDeviceType::PPPTGlobal,
0xE1 => EmulatedDeviceType::VirtioBlk,
0xE2 => EmulatedDeviceType::VirtioNet,
0xE3 => EmulatedDeviceType::VirtioConsole,
_ => {
warn!("Unknown emulated device type value: {value}, default to Meta");
EmulatedDeviceType::Dummy
}
}
}
}
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
pub struct EmulatedDeviceConfig {
pub name: String,
pub base_gpa: usize,
pub length: usize,
pub irq_id: usize,
pub emu_type: EmulatedDeviceType,
pub cfg_list: Vec<usize>,
}
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Debug, Default, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct PassThroughDeviceConfig {
pub name: String,
#[serde(default)]
pub base_gpa: usize,
#[serde(default)]
pub base_hpa: usize,
#[serde(default)]
pub length: usize,
#[serde(default)]
pub irq_id: usize,
}
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Debug, Default, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct PassThroughAddressConfig {
#[serde(default)]
pub base_gpa: usize,
#[serde(default)]
pub length: usize,
}
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
pub struct VMBaseConfig {
pub id: usize,
pub name: String,
pub vm_type: usize,
pub cpu_num: usize,
pub phys_cpu_ids: Option<Vec<usize>>,
pub phys_cpu_sets: Option<Vec<usize>>,
}
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
pub struct VMKernelConfig {
pub entry_point: usize,
pub kernel_path: String,
pub kernel_load_addr: usize,
pub bios_path: Option<String>,
pub bios_load_addr: Option<usize>,
pub dtb_path: Option<String>,
pub dtb_load_addr: Option<usize>,
pub ramdisk_path: Option<String>,
pub ramdisk_load_addr: Option<usize>,
pub image_location: Option<String>,
pub cmdline: Option<String>,
pub disk_path: Option<String>,
pub memory_regions: Vec<VmMemConfig>,
}
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
pub enum VMInterruptMode {
#[serde(rename = "no_irq", alias = "no", alias = "none")]
#[default]
NoIrq,
#[serde(rename = "emu", alias = "emulated")]
Emulated,
#[serde(rename = "passthrough", alias = "pt")]
Passthrough,
}
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
pub struct VMDevicesConfig {
pub emu_devices: Vec<EmulatedDeviceConfig>,
pub passthrough_devices: Vec<PassThroughDeviceConfig>,
#[serde(default)]
pub interrupt_mode: VMInterruptMode,
#[serde(default)]
pub excluded_devices: Vec<Vec<String>>,
#[serde(default)]
pub passthrough_addresses: Vec<PassThroughAddressConfig>,
}
#[cfg_attr(feature = "std", derive(schemars::JsonSchema))]
#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
pub struct AxVMCrateConfig {
pub base: VMBaseConfig,
pub kernel: VMKernelConfig,
pub devices: VMDevicesConfig,
}
impl AxVMCrateConfig {
pub fn from_toml(raw_cfg_str: &str) -> AxResult<Self> {
let config: AxVMCrateConfig = toml::from_str(raw_cfg_str).map_err(|err| {
warn!("Config TOML parse error {:?}", err.message());
axerrno::ax_err_type!(InvalidInput, alloc::format!("Error details {err:?}"))
})?;
Ok(config)
}
}
#[cfg(test)]
mod test;