Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion os/axvisor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ spin = { workspace = true }
ax-crate-interface = { workspace = true }

[target.'cfg(any(not(any(windows, unix)), target_env = "musl"))'.dependencies]
anyhow.workspace = true
log = "0.4"

# System dependent modules provided by ArceOS.
Expand All @@ -73,7 +74,6 @@ ax-hal = { workspace = true, features = ["paging", "irq", "smp", "hv"] }
axvm = { workspace = true, default-features = false }
axvmconfig = { workspace = true, default-features = false }
# System independent crates provided by ArceOS
ax-errno = { workspace = true }
ax-driver.workspace = true
axplat-dyn.workspace = true

Expand Down
54 changes: 36 additions & 18 deletions os/axvisor/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use alloc::format;
#[cfg(all(
feature = "fs",
any(target_arch = "x86_64", target_arch = "loongarch64")
))]
use core::sync::atomic::{AtomicBool, Ordering};

use ax_errno::{AxResult, ax_err_type};
use anyhow::{Context, Result, anyhow, bail};
#[cfg(all(feature = "fs", target_arch = "x86_64"))]
use axvm::InterruptTriggerMode;
use axvm::{
Expand All @@ -33,6 +32,8 @@ use axvm::{
VMImageConfig,
},
};
#[cfg(feature = "fs")]
use axvm::{AxVmError, AxVmResult};
use axvmconfig::{AxVMCrateConfig, VMType};

#[cfg(all(
Expand Down Expand Up @@ -99,15 +100,16 @@ pub fn init_guest_vms() {
for raw_cfg_str in gvm_raw_configs {
debug!("Initializing guest VM with config: {:#?}", raw_cfg_str);
if let Err(e) = init_guest_vm(&raw_cfg_str) {
error!("Failed to initialize guest VM: {e:?}");
error!("Failed to initialize guest VM: {e:#}");
}
}
}

pub fn init_guest_vm(raw_cfg: &str) -> AxResult<usize> {
pub fn init_guest_vm(raw_cfg: &str) -> Result<usize> {
let image_provider = AxvisorBootImageProvider;
let vm_create_config = AxVMCrateConfig::from_toml(raw_cfg)
.map_err(|e| ax_err_type!(InvalidData, format!("Failed to resolve VM config: {e:?}")))?;
.map_err(|error| anyhow!("parse VM TOML configuration: {error}"))?;
let configured_vm_id = vm_create_config.base.id;

#[cfg(all(
feature = "fs",
Expand All @@ -123,7 +125,8 @@ pub fn init_guest_vm(raw_cfg: &str) -> AxResult<usize> {
}

let mut vm_config = build_axvm_config(&vm_create_config);
let prepared_boot = prepare_guest_boot(&mut vm_config, vm_create_config, &image_provider)?;
let prepared_boot = prepare_guest_boot(&mut vm_config, vm_create_config, &image_provider)
.with_context(|| format!("prepare boot resources for VM[{configured_vm_id}]"))?;
let prepared_config = prepared_boot.config();

sync_axvm_config_from_crate_config(&mut vm_config, prepared_config);
Expand All @@ -134,26 +137,26 @@ pub fn init_guest_vm(raw_cfg: &str) -> AxResult<usize> {
info!("Creating VM[{}] {:?}", vm_config.id(), vm_config.name());

// Create VM.
let vm = AxVM::new(vm_config)
.map_err(|e| ax_err_type!(InvalidData, format!("Failed to create VM: {e:?}")))?;
let vm = AxVM::new(vm_config).with_context(|| format!("create VM[{configured_vm_id}]"))?;
let vm_id = vm.id();

let memory_layout = vm.prepare_memory_layout()?;
let memory_layout = vm
.prepare_memory_layout()
.with_context(|| format!("prepare memory layout for VM[{vm_id}]"))?;
let main_mem = memory_layout.main_memory().clone();

// Load corresponding images for VM.
info!("VM[{}] created success, loading images...", vm.id());

prepared_boot.load_images(main_mem, vm.clone(), &image_provider)?;
prepared_boot
.load_images(main_mem, vm.clone(), &image_provider)
.with_context(|| format!("load boot images for VM[{vm_id}]"))?;

vm.prepare()
.map_err(|e| ax_err_type!(InvalidData, format!("VM[{}] setup failed: {e:?}", vm.id())))?;
.with_context(|| format!("prepare devices and vCPUs for VM[{vm_id}]"))?;

if !axvm::register_vm(vm) {
return Err(ax_err_type!(
AlreadyExists,
format!("VM[{vm_id}] already exists")
));
bail!("register VM[{vm_id}]: a VM with this ID already exists");
}
#[cfg(target_arch = "loongarch64")]
crate::manager::register_loongarch_passthrough_irq_routes(vm_id);
Expand Down Expand Up @@ -363,18 +366,33 @@ impl BootImageProvider for AxvisorBootImageProvider {
}

#[cfg(feature = "fs")]
fn read_file(&self, file_name: &str) -> AxResult<alloc::vec::Vec<u8>> {
fn read_file(&self, file_name: &str) -> AxVmResult<alloc::vec::Vec<u8>> {
crate::manager::AxvmManager::read_file(file_name)
.map_err(|error| boot_file_error("read guest image file", file_name, error))
}

#[cfg(feature = "fs")]
fn read_file_exact(&self, file_name: &str, read_size: usize) -> AxResult<alloc::vec::Vec<u8>> {
fn read_file_exact(
&self,
file_name: &str,
read_size: usize,
) -> AxVmResult<alloc::vec::Vec<u8>> {
crate::manager::AxvmManager::read_file_exact(file_name, read_size)
.map_err(|error| boot_file_error("read guest image file", file_name, error))
}

#[cfg(feature = "fs")]
fn file_size(&self, file_name: &str) -> AxResult<usize> {
fn file_size(&self, file_name: &str) -> AxVmResult<usize> {
crate::manager::AxvmManager::file_size(file_name)
.map_err(|error| boot_file_error("inspect guest image file", file_name, error))
}
}

#[cfg(feature = "fs")]
fn boot_file_error(operation: &'static str, file_name: &str, error: anyhow::Error) -> AxVmError {
AxVmError::Boot {
operation,
detail: format!("`{file_name}`: {error:#}"),
}
}

Expand Down
3 changes: 2 additions & 1 deletion os/axvisor/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ fn main() {
banner::print_logo();

info!("Starting virtualization...");
let manager = manager::AxvmManager::new().expect("failed to initialize AxVM manager");
let manager = manager::AxvmManager::new()
.unwrap_or_else(|error| panic!("failed to initialize AxVM manager: {error:#}"));

manager.init_default_vms();
manager.start_default_vms();
Expand Down
70 changes: 26 additions & 44 deletions os/axvisor/src/manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ use alloc::vec::Vec;
#[cfg(feature = "fs")]
use alloc::{string::String, vec, vec::Vec};

use ax_errno::AxResult;
#[cfg(feature = "fs")]
use anyhow::anyhow;
use anyhow::{Context, Result};
use axvm::{AxVMRef, AxvmRuntime, VMId};

/// AxVM top-level manager.
Expand All @@ -21,9 +23,9 @@ pub struct AxvmManager {

impl AxvmManager {
/// Initialize the AxVM runtime services.
pub fn new() -> AxResult<Self> {
pub fn new() -> Result<Self> {
Ok(Self {
runtime: AxvmRuntime::new()?,
runtime: AxvmRuntime::new().context("initialize AxVM runtime")?,
})
}

Expand All @@ -40,28 +42,28 @@ impl AxvmManager {
}

/// Create one VM from a TOML config string.
pub fn create_vm_from_toml(raw_cfg: &str) -> AxResult<VMId> {
crate::config::init_guest_vm(raw_cfg)
pub fn create_vm_from_toml(raw_cfg: &str) -> Result<VMId> {
crate::config::init_guest_vm(raw_cfg).context("create VM from TOML configuration")
}

/// Start a VM by ID.
pub fn start_vm(vm_id: VMId) -> AxResult {
AxvmRuntime::start_vm(vm_id)
pub fn start_vm(vm_id: VMId) -> Result<()> {
AxvmRuntime::start_vm(vm_id).with_context(|| format!("start VM[{vm_id}]"))
}

/// Stop a VM by ID.
pub fn stop_vm(vm_id: VMId) -> AxResult {
AxvmRuntime::stop_vm(vm_id)
pub fn stop_vm(vm_id: VMId) -> Result<()> {
AxvmRuntime::stop_vm(vm_id).with_context(|| format!("stop VM[{vm_id}]"))
}

/// Resume a VM by ID.
pub fn resume_vm(vm_id: VMId) -> AxResult {
AxvmRuntime::resume_vm(vm_id)
pub fn resume_vm(vm_id: VMId) -> Result<()> {
AxvmRuntime::resume_vm(vm_id).with_context(|| format!("resume VM[{vm_id}]"))
}

/// Reset a VM by ID.
pub fn reset_vm(vm_id: VMId) -> AxResult {
AxvmRuntime::reset_vm(vm_id)
pub fn reset_vm(vm_id: VMId) -> Result<()> {
AxvmRuntime::reset_vm(vm_id).with_context(|| format!("reset VM[{vm_id}]"))
}

/// Remove a VM by ID.
Expand Down Expand Up @@ -145,7 +147,7 @@ impl AxvmManager {
let file_size = match Self::file_size(path_str) {
Ok(file_size) => file_size,
Err(e) => {
error!("Failed to get config file {} metadata: {:?}", path_str, e);
error!("Failed to get config file {path_str} metadata: {e:#}");
continue;
}
};
Expand All @@ -159,7 +161,7 @@ impl AxvmManager {
let buffer = match Self::read_file_exact(path_str, file_size) {
Ok(buffer) => buffer,
Err(e) => {
error!("Failed to read file {}: {:?}", path_str, e);
error!("Failed to read file {path_str}: {e:#}");
continue;
}
};
Expand All @@ -174,53 +176,33 @@ impl AxvmManager {
}

#[cfg(feature = "fs")]
fn open_file(file_name: &str) -> AxResult<ax_std::fs::File> {
ax_std::fs::File::open(file_name).map_err(|err| {
ax_errno::ax_err_type!(
NotFound,
alloc::format!(
"Failed to open {}, err {:?}, please check your disk.img",
file_name,
err
)
)
})
fn open_file(file_name: &str) -> Result<ax_std::fs::File> {
ax_std::fs::File::open(file_name)
.map_err(|error| anyhow!("open guest image file `{file_name}`: {error}"))
}

#[cfg(feature = "fs")]
pub fn file_size(file_name: &str) -> AxResult<usize> {
pub fn file_size(file_name: &str) -> Result<usize> {
Self::open_file(file_name)?
.metadata()
.map_err(|err| {
ax_errno::ax_err_type!(
Io,
alloc::format!(
"Failed to get metadate of file {}, err {:?}",
file_name,
err
)
)
})
.map_err(|error| anyhow!("read metadata for guest image file `{file_name}`: {error}"))
.map(|metadata| metadata.size() as usize)
}

#[cfg(feature = "fs")]
pub fn read_file_exact(file_name: &str, read_size: usize) -> AxResult<Vec<u8>> {
pub fn read_file_exact(file_name: &str, read_size: usize) -> Result<Vec<u8>> {
use ax_std::io::Read;

let mut file = Self::open_file(file_name)?;
let mut buffer = vec![0u8; read_size];
file.read_exact(&mut buffer).map_err(|err| {
ax_errno::ax_err_type!(
Io,
alloc::format!("Failed in reading from file {}, err {:?}", file_name, err)
)
file.read_exact(&mut buffer).map_err(|error| {
anyhow!("read {read_size} bytes from guest image file `{file_name}`: {error}")
})?;
Ok(buffer)
}

#[cfg(feature = "fs")]
pub fn read_file(file_name: &str) -> AxResult<Vec<u8>> {
pub fn read_file(file_name: &str) -> Result<Vec<u8>> {
let size = Self::file_size(file_name)?;
Self::read_file_exact(file_name, size)
}
Expand Down
Loading