mirror of
https://github.com/cloud-hypervisor/cloud-hypervisor.git
synced 2026-08-05 02:19:16 +00:00
vmm: trim qualified paths
Import the modules used in the crate instead of spelling the full paths at every use site, and drop the now-unnecessary crate-level Signed-off-by: Henry Hrvoje Tonkovac <htonkovac@gmail.com> Assisted-by: Claude:Opus-4.8
This commit is contained in:
committed by
Sebastien Boeuf
parent
0caa3ee73f
commit
025e782e50
@@ -11,9 +11,11 @@ use acpi_tables::sdt::GenericAddress;
|
||||
use acpi_tables::sdt::Sdt;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use arch::DeviceType;
|
||||
use arch::NumaNodes;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use arch::aarch64::DeviceInfoForFdt;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use arch::x86_64;
|
||||
use arch::{NumaNodes, layout};
|
||||
use bitflags::bitflags;
|
||||
use log::{info, warn};
|
||||
use pci::PciBdf;
|
||||
@@ -25,6 +27,8 @@ use crate::cpu::CpuManager;
|
||||
use crate::device_manager::DeviceManager;
|
||||
use crate::memory_manager::MemoryManager;
|
||||
use crate::pci_segment::PciSegment;
|
||||
#[cfg(feature = "fw_cfg")]
|
||||
use crate::vm;
|
||||
use crate::{GuestMemoryMmap, GuestRegionMmap};
|
||||
|
||||
/* Values for Type in APIC sub-headers */
|
||||
@@ -371,9 +375,9 @@ fn create_srat_table(
|
||||
|
||||
// Check the MemoryAffinity structure is the right size as expected by
|
||||
// the ACPI specification.
|
||||
assert_eq!(std::mem::size_of::<MemoryAffinity>(), 40);
|
||||
assert_eq!(size_of::<MemoryAffinity>(), 40);
|
||||
// Confirm struct size matches ACPI 6.6 spec
|
||||
assert_eq!(std::mem::size_of::<GenericInitiatorAffinity>(), 32);
|
||||
assert_eq!(size_of::<GenericInitiatorAffinity>(), 32);
|
||||
for (node_id, node) in numa_nodes.iter() {
|
||||
let proximity_domain = *node_id;
|
||||
|
||||
@@ -395,7 +399,7 @@ fn create_srat_table(
|
||||
|
||||
for cpu in &node.cpus {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let x2apic_id = arch::x86_64::get_x2apic_id(*cpu, topology);
|
||||
let x2apic_id = x86_64::get_x2apic_id(*cpu, topology);
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
let x2apic_id = *cpu;
|
||||
|
||||
@@ -698,7 +702,7 @@ fn create_iort_table(pci_segments: &[PciSegment]) -> Sdt {
|
||||
// - N x PCI Root Complex Node (N = number of pci segments)
|
||||
let num_nodes = (1 + pci_segments.len()) as u32;
|
||||
// First node is the ITS Group Node located right after the IORT Body Base
|
||||
let offset_its_node = iort.len() + std::mem::size_of::<IortBodyBase>();
|
||||
let offset_its_node = iort.len() + size_of::<IortBodyBase>();
|
||||
assert!(align_to_8_bytes(offset_its_node) == 0); // Ensure the ITS node is 8-byte aligned
|
||||
iort.append(IortBodyBase {
|
||||
num_nodes,
|
||||
@@ -714,8 +718,7 @@ fn create_iort_table(pci_segments: &[PciSegment]) -> Sdt {
|
||||
// `translation_id` field of the `GisIts`` structure in the MADT table.
|
||||
let its_id_array = [0u32; 1];
|
||||
let its_count = its_id_array.len();
|
||||
let its_group_node_size =
|
||||
std::mem::size_of::<IortItsGroupBase>() + its_count * std::mem::size_of::<u32>();
|
||||
let its_group_node_size = size_of::<IortItsGroupBase>() + its_count * size_of::<u32>();
|
||||
let padding = align_to_8_bytes(iort.len() + its_group_node_size);
|
||||
iort.append(IortItsGroupBase {
|
||||
common: IortNodeCommon {
|
||||
@@ -741,8 +744,8 @@ fn create_iort_table(pci_segments: &[PciSegment]) -> Sdt {
|
||||
// Currently contains a single mapping that maps all device IDs
|
||||
// in the segment to the ITS Group Node.
|
||||
let num_id_mappings = 1;
|
||||
let node_size = std::mem::size_of::<IortPciRootComplexBase>()
|
||||
+ num_id_mappings * std::mem::size_of::<IortIdMapping>();
|
||||
let node_size =
|
||||
size_of::<IortPciRootComplexBase>() + num_id_mappings * size_of::<IortIdMapping>();
|
||||
let padding = align_to_8_bytes(iort.len() + node_size);
|
||||
iort.append(IortPciRootComplexBase {
|
||||
common: IortNodeCommon {
|
||||
@@ -752,7 +755,7 @@ fn create_iort_table(pci_segments: &[PciSegment]) -> Sdt {
|
||||
node_id: segment.id as u32, // todo to avoid conflict with ITS node IDs
|
||||
num_id_mappings: num_id_mappings as u32,
|
||||
// ID mapping array starts right after `IortPciRootComplexBase`
|
||||
id_mappings_array_offset: std::mem::size_of::<IortPciRootComplexBase>() as u32,
|
||||
id_mappings_array_offset: size_of::<IortPciRootComplexBase>() as u32,
|
||||
},
|
||||
mem_access_props: IortMemoryAccessProperties {
|
||||
cca: 1, // Fully coherent device
|
||||
@@ -915,7 +918,7 @@ fn create_acpi_tables_internal(
|
||||
.get_device_info()
|
||||
.clone()
|
||||
.contains_key(&(DeviceType::Serial, DeviceType::Serial.to_string()));
|
||||
let serial_device_addr = arch::layout::LEGACY_SERIAL_MAPPED_IO_START.raw_value();
|
||||
let serial_device_addr = layout::LEGACY_SERIAL_MAPPED_IO_START.raw_value();
|
||||
let serial_device_irq = if is_serial_on {
|
||||
device_manager
|
||||
.get_device_info()
|
||||
@@ -1024,7 +1027,7 @@ pub fn create_acpi_tables_for_fw_cfg(
|
||||
memory_manager: &MemoryManager,
|
||||
numa_nodes: &NumaNodes,
|
||||
tpm_enabled: bool,
|
||||
) -> Result<(), crate::vm::Error> {
|
||||
) -> Result<(), vm::Error> {
|
||||
let dsdt_offset = GuestAddress(0);
|
||||
let (rsdp, table_bytes, xsdt_table_pointers) = create_acpi_tables_internal(
|
||||
dsdt_offset,
|
||||
@@ -1071,7 +1074,7 @@ pub fn create_acpi_tables_for_fw_cfg(
|
||||
.lock()
|
||||
.unwrap()
|
||||
.add_acpi(rsdp, table_bytes, checksums, pointer_offsets)
|
||||
.map_err(crate::vm::Error::CreatingAcpiTables)
|
||||
.map_err(vm::Error::CreatingAcpiTables)
|
||||
}
|
||||
|
||||
pub fn create_acpi_tables(
|
||||
@@ -1085,7 +1088,7 @@ pub fn create_acpi_tables(
|
||||
trace_scoped!("create_acpi_tables");
|
||||
|
||||
let start_time = Instant::now();
|
||||
let rsdp_addr = arch::layout::RSDP_POINTER;
|
||||
let rsdp_addr = layout::RSDP_POINTER;
|
||||
let dsdt_addr = rsdp_addr.checked_add(Rsdp::len() as u64).unwrap();
|
||||
|
||||
let (rsdp, tables_bytes, _xsdt_table_pointers) = create_acpi_tables_internal(
|
||||
@@ -1165,13 +1168,15 @@ pub fn create_acpi_tables_tdx(
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::slice;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_generic_initiator_affinity_size() {
|
||||
// ACPI spec requires Generic Initiator Affinity Structure to be exactly 32 bytes
|
||||
assert_eq!(
|
||||
std::mem::size_of::<GenericInitiatorAffinity>(),
|
||||
size_of::<GenericInitiatorAffinity>(),
|
||||
32,
|
||||
"GenericInitiatorAffinity must be exactly 32 bytes per ACPI 6.6 spec"
|
||||
);
|
||||
@@ -1266,9 +1271,9 @@ mod tests {
|
||||
// there is no internal padding, making every byte within it
|
||||
// safe to read. Casting to `u8` satisfies alignment requirements.
|
||||
let bytes = unsafe {
|
||||
std::slice::from_raw_parts(
|
||||
slice::from_raw_parts(
|
||||
(&raw const gi).cast::<u8>(),
|
||||
std::mem::size_of::<GenericInitiatorAffinity>(),
|
||||
size_of::<GenericInitiatorAffinity>(),
|
||||
)
|
||||
};
|
||||
|
||||
|
||||
@@ -5,17 +5,17 @@
|
||||
use std::panic::AssertUnwindSafe;
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::thread;
|
||||
use std::{fmt, panic, thread};
|
||||
|
||||
use futures::channel::oneshot;
|
||||
use futures::{FutureExt, executor};
|
||||
use futures::{FutureExt, executor, future, lock};
|
||||
use log::{error, warn};
|
||||
use seccompiler::{SeccompAction, apply_filter};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
use zbus::connection::Builder;
|
||||
use zbus::fdo::{self, Result};
|
||||
use zbus::interface;
|
||||
use zbus::zvariant::Optional;
|
||||
use zbus::{interface, object_server};
|
||||
|
||||
use super::{ApiAction, ApiRequest};
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
@@ -40,10 +40,10 @@ pub struct DBusApiOptions {
|
||||
|
||||
pub struct DBusApi {
|
||||
api_notifier: EventFd,
|
||||
api_sender: futures::lock::Mutex<Sender<ApiRequest>>,
|
||||
api_sender: lock::Mutex<Sender<ApiRequest>>,
|
||||
}
|
||||
|
||||
fn api_error(error: impl std::fmt::Debug + std::fmt::Display) -> fdo::Error {
|
||||
fn api_error(error: impl fmt::Debug + fmt::Display) -> fdo::Error {
|
||||
fdo::Error::Failed(format!("{error}"))
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ impl DBusApi {
|
||||
pub fn new(api_notifier: EventFd, api_sender: Sender<ApiRequest>) -> Self {
|
||||
Self {
|
||||
api_notifier,
|
||||
api_sender: futures::lock::Mutex::new(api_sender),
|
||||
api_sender: lock::Mutex::new(api_sender),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,10 +313,8 @@ impl DBusApi {
|
||||
|
||||
// implementation of this function is provided by the `#[zbus(signal)]` macro call
|
||||
#[zbus(signal)]
|
||||
async fn event(
|
||||
ctxt: &zbus::object_server::SignalEmitter<'_>,
|
||||
event: Arc<String>,
|
||||
) -> zbus::Result<()>;
|
||||
async fn event(ctxt: &object_server::SignalEmitter<'_>, event: Arc<String>)
|
||||
-> zbus::Result<()>;
|
||||
}
|
||||
|
||||
pub fn start_dbus_thread(
|
||||
@@ -371,10 +369,10 @@ pub fn start_dbus_thread(
|
||||
})?;
|
||||
}
|
||||
|
||||
std::panic::catch_unwind(AssertUnwindSafe(move || {
|
||||
panic::catch_unwind(AssertUnwindSafe(move || {
|
||||
executor::block_on(async move {
|
||||
let recv_shutdown = recv_shutdown.fuse();
|
||||
let executor_tick = futures::future::Fuse::terminated();
|
||||
let executor_tick = future::Fuse::terminated();
|
||||
futures::pin_mut!(recv_shutdown, executor_tick);
|
||||
executor_tick.set(connection.executor().tick().fuse());
|
||||
|
||||
|
||||
@@ -35,11 +35,13 @@
|
||||
//! [special HTTP library]: https://github.com/firecracker-microvm/micro-http
|
||||
|
||||
use std::fs::File;
|
||||
use std::result;
|
||||
use std::sync::mpsc::Sender;
|
||||
|
||||
use micro_http::{Body, Method, Request, Response, StatusCode, Version};
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
use crate::api;
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
use crate::api::VmCoredump;
|
||||
use crate::api::http::http_endpoint::fds_helper::{attach_fds_to_cfg, attach_fds_to_cfgs};
|
||||
@@ -327,7 +329,7 @@ impl EndpointHandler for VmCreate {
|
||||
}
|
||||
}
|
||||
|
||||
match crate::api::VmCreate
|
||||
match api::VmCreate
|
||||
.send(api_notifier, api_sender, vm_config)
|
||||
.map_err(HttpError::ApiError)
|
||||
{
|
||||
@@ -350,7 +352,7 @@ pub trait GetHandler {
|
||||
&'static self,
|
||||
_api_notifier: EventFd,
|
||||
_api_sender: Sender<ApiRequest>,
|
||||
) -> std::result::Result<Option<Body>, HttpError> {
|
||||
) -> result::Result<Option<Body>, HttpError> {
|
||||
Err(HttpError::BadRequest)
|
||||
}
|
||||
}
|
||||
@@ -362,7 +364,7 @@ pub trait PutHandler {
|
||||
_api_sender: Sender<ApiRequest>,
|
||||
_body: &Option<Body>,
|
||||
_files: Vec<File>,
|
||||
) -> std::result::Result<Option<Body>, HttpError> {
|
||||
) -> result::Result<Option<Body>, HttpError> {
|
||||
Err(HttpError::BadRequest)
|
||||
}
|
||||
}
|
||||
@@ -503,7 +505,7 @@ impl PutHandler for VmAddNet {
|
||||
api_sender: Sender<ApiRequest>,
|
||||
body: &Option<Body>,
|
||||
files: Vec<File>,
|
||||
) -> std::result::Result<Option<Body>, HttpError> {
|
||||
) -> result::Result<Option<Body>, HttpError> {
|
||||
if let Some(body) = body {
|
||||
let mut net_cfg: NetConfig = serde_json::from_slice(body.raw())?;
|
||||
attach_fds_to_cfg(files, &mut net_cfg)?;
|
||||
@@ -525,7 +527,7 @@ impl PutHandler for VmResize {
|
||||
api_sender: Sender<ApiRequest>,
|
||||
body: &Option<Body>,
|
||||
_files: Vec<File>,
|
||||
) -> std::result::Result<Option<Body>, HttpError> {
|
||||
) -> result::Result<Option<Body>, HttpError> {
|
||||
if let Some(body) = body {
|
||||
self.send(
|
||||
api_notifier,
|
||||
@@ -555,7 +557,7 @@ impl PutHandler for VmRestore {
|
||||
api_sender: Sender<ApiRequest>,
|
||||
body: &Option<Body>,
|
||||
files: Vec<File>,
|
||||
) -> std::result::Result<Option<Body>, HttpError> {
|
||||
) -> result::Result<Option<Body>, HttpError> {
|
||||
if let Some(body) = body {
|
||||
let mut restore_cfg: RestoreConfig = serde_json::from_slice(body.raw())?;
|
||||
|
||||
@@ -593,7 +595,7 @@ impl EndpointHandler for VmActionHandler {
|
||||
api_sender: Sender<ApiRequest>,
|
||||
body: &Option<Body>,
|
||||
files: Vec<File>,
|
||||
) -> std::result::Result<Option<Body>, HttpError> {
|
||||
) -> result::Result<Option<Body>, HttpError> {
|
||||
PutHandler::handle_request(self.action, api_notifier, api_sender, body, files)
|
||||
}
|
||||
|
||||
@@ -602,7 +604,7 @@ impl EndpointHandler for VmActionHandler {
|
||||
api_notifier: EventFd,
|
||||
api_sender: Sender<ApiRequest>,
|
||||
_body: &Option<Body>,
|
||||
) -> std::result::Result<Option<Body>, HttpError> {
|
||||
) -> result::Result<Option<Body>, HttpError> {
|
||||
GetHandler::handle_request(self.action, api_notifier, api_sender)
|
||||
}
|
||||
}
|
||||
@@ -618,7 +620,7 @@ impl EndpointHandler for VmInfo {
|
||||
api_sender: Sender<ApiRequest>,
|
||||
) -> Response {
|
||||
match req.method() {
|
||||
Method::Get => match crate::api::VmInfo
|
||||
Method::Get => match api::VmInfo
|
||||
.send(api_notifier, api_sender, ())
|
||||
.map_err(HttpError::ApiError)
|
||||
{
|
||||
@@ -647,7 +649,7 @@ impl EndpointHandler for VmmPing {
|
||||
api_sender: Sender<ApiRequest>,
|
||||
) -> Response {
|
||||
match req.method() {
|
||||
Method::Get => match crate::api::VmmPing
|
||||
Method::Get => match api::VmmPing
|
||||
.send(api_notifier, api_sender, ())
|
||||
.map_err(HttpError::ApiError)
|
||||
{
|
||||
@@ -678,7 +680,7 @@ impl EndpointHandler for VmmShutdown {
|
||||
) -> Response {
|
||||
match req.method() {
|
||||
Method::Put => {
|
||||
match crate::api::VmmShutdown
|
||||
match api::VmmShutdown
|
||||
.send(api_notifier, api_sender, ())
|
||||
.map_err(HttpError::ApiError)
|
||||
{
|
||||
|
||||
@@ -12,7 +12,7 @@ use std::panic::AssertUnwindSafe;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::LazyLock;
|
||||
use std::sync::mpsc::Sender;
|
||||
use std::thread;
|
||||
use std::{fs, iter, panic, result, thread};
|
||||
|
||||
use block::fcntl::{LockError, LockGranularity, LockType, try_acquire_lock};
|
||||
use log::{error, info};
|
||||
@@ -104,7 +104,7 @@ pub fn error_response(error: HttpError) -> Response {
|
||||
|
||||
let error: &dyn Error = &error;
|
||||
// Write the Display::display() output all errors (from top to root).
|
||||
let error_messages = std::iter::successors(Some(error), |sub_error| {
|
||||
let error_messages = iter::successors(Some(error), |sub_error| {
|
||||
// Dereference necessary to mitigate rustc compiler bug.
|
||||
// See <https://github.com/rust-lang/rust/issues/141673>
|
||||
(*sub_error).source()
|
||||
@@ -167,7 +167,7 @@ pub trait EndpointHandler {
|
||||
_api_sender: Sender<ApiRequest>,
|
||||
_body: &Option<Body>,
|
||||
_files: Vec<File>,
|
||||
) -> std::result::Result<Option<Body>, HttpError> {
|
||||
) -> result::Result<Option<Body>, HttpError> {
|
||||
Err(HttpError::BadRequest)
|
||||
}
|
||||
|
||||
@@ -176,7 +176,7 @@ pub trait EndpointHandler {
|
||||
_api_notifier: EventFd,
|
||||
_api_sender: Sender<ApiRequest>,
|
||||
_body: &Option<Body>,
|
||||
) -> std::result::Result<Option<Body>, HttpError> {
|
||||
) -> result::Result<Option<Body>, HttpError> {
|
||||
Err(HttpError::BadRequest)
|
||||
}
|
||||
}
|
||||
@@ -385,7 +385,7 @@ fn start_http_thread(
|
||||
})?;
|
||||
}
|
||||
|
||||
std::panic::catch_unwind(AssertUnwindSafe(move || {
|
||||
panic::catch_unwind(AssertUnwindSafe(move || {
|
||||
server.start_server().unwrap();
|
||||
loop {
|
||||
match server.requests() {
|
||||
@@ -456,7 +456,7 @@ pub fn start_http_path_thread(
|
||||
let lock = acquire_api_socket_lock(&socket_path)?;
|
||||
// We hold the lock, so any socket at this path is stale from a crashed
|
||||
// run: remove it before bind. Ignore errors (it is usually not present).
|
||||
let _ = std::fs::remove_file(&socket_path);
|
||||
let _ = fs::remove_file(&socket_path);
|
||||
|
||||
let socket_fd = UnixListener::bind(socket_path).map_err(VmmError::CreateApiServerSocket)?;
|
||||
// SAFETY: Valid FD just opened
|
||||
|
||||
@@ -1925,7 +1925,7 @@ impl ApiAction for VmNmi {
|
||||
mod unit_tests {
|
||||
use std::path::PathBuf;
|
||||
use std::time::{SystemTime, UNIX_EPOCH};
|
||||
use std::{fs, process};
|
||||
use std::{env, fs, process};
|
||||
|
||||
use super::*;
|
||||
|
||||
@@ -1939,7 +1939,7 @@ mod unit_tests {
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.unwrap()
|
||||
.as_nanos();
|
||||
let path = std::env::temp_dir().join(format!(
|
||||
let path = env::temp_dir().join(format!(
|
||||
"cloud-hypervisor-api-{name}-{}-{unique}",
|
||||
process::id()
|
||||
));
|
||||
|
||||
@@ -25,7 +25,7 @@ use virtio_bindings::virtio_blk::VIRTIO_BLK_ID_BYTES;
|
||||
use virtio_bindings::virtio_ids::*;
|
||||
use virtio_devices::block::MINIMUM_BLOCK_QUEUE_SIZE;
|
||||
use virtio_devices::vhost_user::VIRTIO_FS_TAG_LEN;
|
||||
use virtio_devices::{RateLimiterConfig, TokenBucketConfig};
|
||||
use virtio_devices::{RateLimiterConfig, TokenBucketConfig, net, vhost_user};
|
||||
|
||||
use crate::landlock::LandlockAccess;
|
||||
use crate::vm_config::*;
|
||||
@@ -432,7 +432,7 @@ pub enum ValidationError {
|
||||
InvalidSharedMemoryWithMergeable,
|
||||
}
|
||||
|
||||
type ValidationResult<T> = std::result::Result<T, ValidationError>;
|
||||
type ValidationResult<T> = result::Result<T, ValidationError>;
|
||||
|
||||
pub fn add_to_config<T>(items: &mut Option<Vec<T>>, item: T) {
|
||||
if let Some(items) = items {
|
||||
@@ -637,7 +637,7 @@ pub enum ParseHotplugMethodError {
|
||||
impl FromStr for HotplugMethod {
|
||||
type Err = ParseHotplugMethodError;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
fn from_str(s: &str) -> result::Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"acpi" => Ok(HotplugMethod::Acpi),
|
||||
"virtio-mem" => Ok(HotplugMethod::VirtioMem),
|
||||
@@ -653,7 +653,7 @@ pub enum ParseCoreSchedulingError {
|
||||
impl FromStr for CoreScheduling {
|
||||
type Err = ParseCoreSchedulingError;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
fn from_str(s: &str) -> result::Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"vm" => Ok(CoreScheduling::Vm),
|
||||
"vcpu" => Ok(CoreScheduling::Vcpu),
|
||||
@@ -670,7 +670,7 @@ pub enum CpuTopologyParseError {
|
||||
impl FromStr for CpuTopology {
|
||||
type Err = CpuTopologyParseError;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
fn from_str(s: &str) -> result::Result<Self, Self::Err> {
|
||||
let parts: Vec<&str> = s.split(':').collect();
|
||||
|
||||
if parts.len() != 4 {
|
||||
@@ -1655,7 +1655,7 @@ pub enum ParseVhostModeError {
|
||||
impl FromStr for VhostMode {
|
||||
type Err = ParseVhostModeError;
|
||||
|
||||
fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
|
||||
fn from_str(s: &str) -> result::Result<Self, Self::Err> {
|
||||
match s.to_lowercase().as_str() {
|
||||
"client" => Ok(VhostMode::Client),
|
||||
"server" => Ok(VhostMode::Server),
|
||||
@@ -1863,7 +1863,7 @@ impl NetConfig {
|
||||
}
|
||||
|
||||
if let Some(mtu) = self.mtu
|
||||
&& mtu < virtio_devices::net::MIN_MTU
|
||||
&& mtu < net::MIN_MTU
|
||||
{
|
||||
return Err(ValidationError::InvalidMtu(mtu));
|
||||
}
|
||||
@@ -2122,7 +2122,7 @@ impl FsConfig {
|
||||
parser.parse(fs).map_err(Error::ParseFileSystem)?;
|
||||
|
||||
let tag = parser.get("tag").ok_or(Error::ParseFsTagMissing)?;
|
||||
if tag.len() > virtio_devices::vhost_user::VIRTIO_FS_TAG_LEN {
|
||||
if tag.len() > vhost_user::VIRTIO_FS_TAG_LEN {
|
||||
return Err(Error::ParseFsTagTooLong);
|
||||
}
|
||||
let socket = PathBuf::from(parser.get("socket").ok_or(Error::ParseFsSockMissing)?);
|
||||
@@ -2223,7 +2223,7 @@ impl FwCfgConfig {
|
||||
items,
|
||||
})
|
||||
}
|
||||
pub fn validate(&self, payload: &PayloadConfig) -> std::result::Result<(), PayloadConfigError> {
|
||||
pub fn validate(&self, payload: &PayloadConfig) -> result::Result<(), PayloadConfigError> {
|
||||
if self.kernel && payload.kernel.is_none() {
|
||||
return Err(PayloadConfigError::FwCfgMissingKernel);
|
||||
} else if self.cmdline && payload.cmdline.is_none() {
|
||||
@@ -2736,9 +2736,7 @@ pub struct RestoredNetConfig {
|
||||
pub fds: Option<Vec<i32>>,
|
||||
}
|
||||
|
||||
fn deserialize_restorednetconfig_fds<'de, D>(
|
||||
d: D,
|
||||
) -> std::result::Result<Option<Vec<i32>>, D::Error>
|
||||
fn deserialize_restorednetconfig_fds<'de, D>(d: D) -> result::Result<Option<Vec<i32>>, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
|
||||
@@ -21,6 +21,7 @@ use std::{io, result};
|
||||
|
||||
use libc::{TCSANOW, cfmakeraw, isatty, tcgetattr, tcsetattr, termios};
|
||||
use thiserror::Error;
|
||||
use vmm_sys_util::errno;
|
||||
|
||||
use crate::Vmm;
|
||||
use crate::sigwinch_listener::listen_for_sigwinch_on_tty;
|
||||
@@ -42,15 +43,15 @@ pub enum ConsoleDeviceError {
|
||||
|
||||
/// Error setting pty raw mode
|
||||
#[error("Error setting pty raw mode")]
|
||||
SetPtyRaw(#[source] vmm_sys_util::errno::Error),
|
||||
SetPtyRaw(#[source] errno::Error),
|
||||
|
||||
/// Cannot duplicate file descriptor
|
||||
#[error("Cannot duplicate file descriptor")]
|
||||
DupFd(#[source] vmm_sys_util::errno::Error),
|
||||
DupFd(#[source] errno::Error),
|
||||
|
||||
/// Error starting sigwinch listener
|
||||
#[error("Error starting sigwinch listener")]
|
||||
StartSigwinchListener(#[source] std::io::Error),
|
||||
StartSigwinchListener(#[source] io::Error),
|
||||
}
|
||||
|
||||
type ConsoleDeviceResult<T> = result::Result<T, ConsoleDeviceError>;
|
||||
@@ -77,7 +78,7 @@ fn modify_mode<F: FnOnce(&mut termios)>(
|
||||
fd: RawFd,
|
||||
f: F,
|
||||
original_termios_opt: &mut Option<termios>,
|
||||
) -> vmm_sys_util::errno::Result<()> {
|
||||
) -> errno::Result<()> {
|
||||
// SAFETY: safe because we check the return value of isatty.
|
||||
if unsafe { isatty(fd) } != 1 {
|
||||
return Ok(());
|
||||
@@ -89,7 +90,7 @@ fn modify_mode<F: FnOnce(&mut termios)>(
|
||||
// SAFETY: see above
|
||||
let ret = unsafe { tcgetattr(fd, &raw mut termios) };
|
||||
if ret < 0 {
|
||||
return vmm_sys_util::errno::errno_result();
|
||||
return errno::errno_result();
|
||||
}
|
||||
if original_termios_opt.is_none() {
|
||||
original_termios_opt.replace(termios);
|
||||
@@ -100,7 +101,7 @@ fn modify_mode<F: FnOnce(&mut termios)>(
|
||||
// the return result.
|
||||
let ret = unsafe { tcsetattr(fd, TCSANOW, &raw const termios) };
|
||||
if ret < 0 {
|
||||
return vmm_sys_util::errno::errno_result();
|
||||
return errno::errno_result();
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@@ -155,7 +156,7 @@ fn create_pty() -> io::Result<(File, File, PathBuf)> {
|
||||
)
|
||||
};
|
||||
if sub_fd == -1 {
|
||||
return vmm_sys_util::errno::errno_result().map_err(|e| e.into());
|
||||
return errno::errno_result().map_err(|e| e.into());
|
||||
}
|
||||
|
||||
let proc_path = PathBuf::from(format!("/proc/self/fd/{sub_fd}"));
|
||||
@@ -165,11 +166,11 @@ fn create_pty() -> io::Result<(File, File, PathBuf)> {
|
||||
Ok((main, unsafe { File::from_raw_fd(sub_fd) }, path))
|
||||
}
|
||||
|
||||
fn dup_stdout() -> vmm_sys_util::errno::Result<File> {
|
||||
fn dup_stdout() -> errno::Result<File> {
|
||||
// SAFETY: FFI call to dup. Trivially safe.
|
||||
let stdout = unsafe { libc::dup(libc::STDOUT_FILENO) };
|
||||
if stdout == -1 {
|
||||
return vmm_sys_util::errno::errno_result();
|
||||
return errno::errno_result();
|
||||
}
|
||||
// SAFETY: stdout is valid and owned solely by us.
|
||||
Ok(unsafe { File::from_raw_fd(stdout) })
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
use std::fs::File;
|
||||
use std::io::Write;
|
||||
use std::{collections, io, result};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use hypervisor::arch::x86::{DescriptorTable, SegmentRegister};
|
||||
@@ -20,7 +21,7 @@ pub struct CoredumpMemoryRegion {
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct CoredumpMemoryRegions {
|
||||
pub ram_maps: std::collections::BTreeMap<u64, CoredumpMemoryRegion>,
|
||||
pub ram_maps: collections::BTreeMap<u64, CoredumpMemoryRegion>,
|
||||
}
|
||||
|
||||
/// Platform information
|
||||
@@ -39,7 +40,7 @@ pub enum GuestDebuggableError {
|
||||
#[error("coredump")]
|
||||
Coredump(#[source] anyhow::Error),
|
||||
#[error("coredump file")]
|
||||
CoredumpFile(#[source] std::io::Error),
|
||||
CoredumpFile(#[source] io::Error),
|
||||
#[error("Failed to pause")]
|
||||
Pause(#[source] vm_migration::MigratableError),
|
||||
#[error("Failed to resume")]
|
||||
@@ -47,10 +48,7 @@ pub enum GuestDebuggableError {
|
||||
}
|
||||
|
||||
pub trait GuestDebuggable: vm_migration::Pausable {
|
||||
fn coredump(
|
||||
&mut self,
|
||||
_destination_url: &str,
|
||||
) -> std::result::Result<(), GuestDebuggableError> {
|
||||
fn coredump(&mut self, _destination_url: &str) -> result::Result<(), GuestDebuggableError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -194,10 +192,7 @@ const EV_CURRENT: u8 = 1;
|
||||
const EM_X86_64: u16 = 62;
|
||||
|
||||
pub trait Elf64Writable {
|
||||
fn write_header(
|
||||
&mut self,
|
||||
dump_state: &DumpState,
|
||||
) -> std::result::Result<(), GuestDebuggableError> {
|
||||
fn write_header(&mut self, dump_state: &DumpState) -> result::Result<(), GuestDebuggableError> {
|
||||
let e_ident = [
|
||||
elf::ELFMAG0 as u8, // magic
|
||||
elf::ELFMAG1,
|
||||
@@ -216,8 +211,8 @@ pub trait Elf64Writable {
|
||||
0,
|
||||
0,
|
||||
];
|
||||
let elf64_ehdr_size = std::mem::size_of::<elf::Elf64_Ehdr>();
|
||||
let elf64_phdr_size = std::mem::size_of::<elf::Elf64_Phdr>();
|
||||
let elf64_ehdr_size = size_of::<elf::Elf64_Ehdr>();
|
||||
let elf64_phdr_size = size_of::<elf::Elf64_Phdr>();
|
||||
let mut elf64_ehdr = elf::Elf64_Ehdr {
|
||||
e_ident,
|
||||
e_type: ET_CORE,
|
||||
@@ -234,7 +229,7 @@ pub trait Elf64Writable {
|
||||
e_shnum: 0,
|
||||
e_shstrndx: 0,
|
||||
};
|
||||
elf64_ehdr.e_ehsize = std::mem::size_of_val(&elf64_ehdr) as u16;
|
||||
elf64_ehdr.e_ehsize = size_of_val(&elf64_ehdr) as u16;
|
||||
|
||||
let mut coredump_file = dump_state.file.as_ref().unwrap();
|
||||
let bytes: &[u8] = elf64_ehdr.as_slice();
|
||||
@@ -245,10 +240,7 @@ pub trait Elf64Writable {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_note(
|
||||
&mut self,
|
||||
dump_state: &DumpState,
|
||||
) -> std::result::Result<(), GuestDebuggableError> {
|
||||
fn write_note(&mut self, dump_state: &DumpState) -> result::Result<(), GuestDebuggableError> {
|
||||
let begin = dump_state.mem_offset - dump_state.elf_note_size as u64;
|
||||
let elf64_phdr = elf::Elf64_Phdr {
|
||||
p_type: elf::PT_NOTE,
|
||||
@@ -277,7 +269,7 @@ pub trait Elf64Writable {
|
||||
length: u64,
|
||||
virt_addr: u64,
|
||||
dump_state: &DumpState,
|
||||
) -> std::result::Result<(), GuestDebuggableError> {
|
||||
) -> result::Result<(), GuestDebuggableError> {
|
||||
let elf64_load = elf::Elf64_Phdr {
|
||||
p_type: elf::PT_LOAD,
|
||||
p_flags: 0,
|
||||
@@ -298,10 +290,7 @@ pub trait Elf64Writable {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn write_loads(
|
||||
&mut self,
|
||||
dump_state: &DumpState,
|
||||
) -> std::result::Result<(), GuestDebuggableError> {
|
||||
fn write_loads(&mut self, dump_state: &DumpState) -> result::Result<(), GuestDebuggableError> {
|
||||
let mem_info = dump_state.mem_info.as_ref().unwrap();
|
||||
|
||||
for (gpa, load) in &mem_info.ram_maps {
|
||||
@@ -316,9 +305,9 @@ pub trait Elf64Writable {
|
||||
}
|
||||
|
||||
fn get_note_size(&self, desc_type: NoteDescType, nr_cpus: u32) -> u32 {
|
||||
let note_head_size = std::mem::size_of::<elf::Elf64_Nhdr>() as u32;
|
||||
let elf_desc_size = std::mem::size_of::<X86_64ElfPrStatus>() as u32;
|
||||
let cpu_state_desc_size = std::mem::size_of::<CpuState>() as u32;
|
||||
let note_head_size = size_of::<elf::Elf64_Nhdr>() as u32;
|
||||
let elf_desc_size = size_of::<X86_64ElfPrStatus>() as u32;
|
||||
let cpu_state_desc_size = size_of::<CpuState>() as u32;
|
||||
|
||||
let elf_note_size = self.elf_note_size(note_head_size, COREDUMP_NAME_SIZE, elf_desc_size);
|
||||
let vmm_note_size =
|
||||
@@ -336,14 +325,14 @@ pub trait CpuElf64Writable {
|
||||
fn cpu_write_elf64_note(
|
||||
&mut self,
|
||||
_dump_state: &DumpState,
|
||||
) -> std::result::Result<(), GuestDebuggableError> {
|
||||
) -> result::Result<(), GuestDebuggableError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn cpu_write_vmm_note(
|
||||
&mut self,
|
||||
_dump_state: &DumpState,
|
||||
) -> std::result::Result<(), GuestDebuggableError> {
|
||||
) -> result::Result<(), GuestDebuggableError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
109
vmm/src/cpu.rs
109
vmm/src/cpu.rs
@@ -14,19 +14,20 @@
|
||||
use std::collections::BTreeMap;
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
use std::io::Write;
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
use std::mem::size_of;
|
||||
use std::mem::zeroed;
|
||||
use std::os::unix::thread::JoinHandleExt;
|
||||
use std::sync::atomic::{AtomicBool, AtomicI32, Ordering};
|
||||
use std::sync::{Arc, Barrier, Mutex};
|
||||
use std::{cmp, io, result, thread};
|
||||
use std::{any, cmp, hint, io, panic, result, thread, time};
|
||||
|
||||
use acpi_tables::sdt::Sdt;
|
||||
use acpi_tables::{Aml, aml};
|
||||
use anyhow::anyhow;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use arch::x86_64;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use arch::x86_64::get_x2apic_id;
|
||||
use arch::{EntryPoint, NumaNodes};
|
||||
use arch::{EntryPoint, NumaNodes, layout};
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use devices::gic::Gic;
|
||||
use devices::interrupt_controller::InterruptController;
|
||||
@@ -54,7 +55,11 @@ use hypervisor::arch::x86::SpecialRegisters;
|
||||
use hypervisor::arch::x86::msr_index;
|
||||
#[cfg(feature = "tdx")]
|
||||
use hypervisor::kvm::{TdxExitDetails, TdxExitStatus};
|
||||
#[cfg(feature = "mshv")]
|
||||
use hypervisor::mshv;
|
||||
use hypervisor::{CpuState, HypervisorCpuError, VmExit, VmOps};
|
||||
#[cfg(feature = "sev_snp")]
|
||||
use igvm::snp_defs;
|
||||
use libc::{c_void, siginfo_t};
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
use linux_loader::elf::Elf64_Nhdr;
|
||||
@@ -76,6 +81,8 @@ use vmm_sys_util::eventfd::EventFd;
|
||||
use vmm_sys_util::signal::{SIGRTMIN, register_signal_handler};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes};
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::acpi;
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
use crate::coredump::{
|
||||
COREDUMP_NAME_SIZE, CpuElf64Writable, CpuSegment, CpuState as DumpCpusState, DumpState,
|
||||
@@ -84,6 +91,8 @@ use crate::coredump::{
|
||||
};
|
||||
#[cfg(feature = "guest_debug")]
|
||||
use crate::gdb::{Debuggable, DebuggableError, get_raw_tid};
|
||||
#[cfg(all(feature = "sev_snp", feature = "mshv"))]
|
||||
use crate::igvm::HV_PAGE_SIZE;
|
||||
use crate::seccomp_filters::{Thread, get_seccomp_filter};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use crate::vm::physical_bits;
|
||||
@@ -156,7 +165,7 @@ pub enum Error {
|
||||
VcpuSetGicrBaseAddr(#[source] hypervisor::HypervisorCpuError),
|
||||
|
||||
#[error("Failed to join on vCPU threads: {0:?}")]
|
||||
ThreadCleanup(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
|
||||
ThreadCleanup(Box<dyn any::Any + Send>),
|
||||
|
||||
#[error("Timeout when waiting for signal to be acknowledged")]
|
||||
SignalAcknowledgeTimeout,
|
||||
@@ -639,7 +648,7 @@ impl Vcpu {
|
||||
///
|
||||
/// Note that the state of the VCPU and associated VM must be setup first for this to do
|
||||
/// anything useful.
|
||||
pub fn run(&mut self) -> std::result::Result<VmExit, HypervisorCpuError> {
|
||||
pub fn run(&mut self) -> result::Result<VmExit, HypervisorCpuError> {
|
||||
self.vcpu.run()
|
||||
}
|
||||
|
||||
@@ -656,7 +665,7 @@ impl Vcpu {
|
||||
}
|
||||
|
||||
#[cfg(feature = "sev_snp")]
|
||||
pub fn setup_sev_snp_regs(&self, vmsa: igvm::snp_defs::SevVmsa) -> Result<()> {
|
||||
pub fn setup_sev_snp_regs(&self, vmsa: snp_defs::SevVmsa) -> Result<()> {
|
||||
self.vcpu
|
||||
.setup_sev_snp_regs(vmsa)
|
||||
.map_err(Error::SetupSevSnpRegs)
|
||||
@@ -671,8 +680,8 @@ impl Vcpu {
|
||||
base_redist_addr: u64,
|
||||
redist_size: u64,
|
||||
) -> Result<()> {
|
||||
let gicr_base = base_redist_addr + (arch::layout::GIC_V3_REDIST_SIZE * self.id as u64);
|
||||
assert!(gicr_base + arch::layout::GIC_V3_REDIST_SIZE <= base_redist_addr + redist_size);
|
||||
let gicr_base = base_redist_addr + (layout::GIC_V3_REDIST_SIZE * self.id as u64);
|
||||
assert!(gicr_base + layout::GIC_V3_REDIST_SIZE <= base_redist_addr + redist_size);
|
||||
self.vcpu
|
||||
.set_gic_redistributor_addr(gicr_base)
|
||||
.map_err(Error::VcpuSetGicrBaseAddr)?;
|
||||
@@ -686,7 +695,7 @@ impl Snapshottable for Vcpu {
|
||||
self.id.to_string()
|
||||
}
|
||||
|
||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||
fn snapshot(&mut self) -> result::Result<Snapshot, MigratableError> {
|
||||
let saved_state = self
|
||||
.vcpu
|
||||
.state()
|
||||
@@ -819,7 +828,7 @@ impl VcpuState {
|
||||
}
|
||||
// This is more effective than thread::yield_now() at
|
||||
// avoiding a priority inversion with the vCPU thread
|
||||
thread::sleep(std::time::Duration::from_millis(1));
|
||||
thread::sleep(time::Duration::from_millis(1));
|
||||
count += 1;
|
||||
if count >= 1000 {
|
||||
return Err(Error::SignalAcknowledgeTimeout);
|
||||
@@ -979,7 +988,7 @@ impl CpuManager {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let topology = self.get_vcpu_topology();
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
let x2apic_id = arch::x86_64::get_x2apic_id(cpu_id, topology);
|
||||
let x2apic_id = x86_64::get_x2apic_id(cpu_id, topology);
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||
let x2apic_id = cpu_id;
|
||||
|
||||
@@ -1034,9 +1043,7 @@ impl CpuManager {
|
||||
&& self.hypervisor.hypervisor_type() == hypervisor::HypervisorType::Mshv
|
||||
{
|
||||
if let Some((kernel_entry_point, _)) = boot_setup {
|
||||
vcpu.set_sev_control_register(
|
||||
kernel_entry_point.entry_addr.0 / crate::igvm::HV_PAGE_SIZE,
|
||||
)?;
|
||||
vcpu.set_sev_control_register(kernel_entry_point.entry_addr.0 / HV_PAGE_SIZE)?;
|
||||
}
|
||||
|
||||
// Traditional way to configure vcpu doesn't work for SEV-SNP guests.
|
||||
@@ -1200,7 +1207,7 @@ impl CpuManager {
|
||||
// Prepare the CPU set the current vCPU is expected to run onto.
|
||||
let cpuset = self.affinity.get(&vcpu_id).map(|host_cpus| {
|
||||
// SAFETY: all zeros is a valid pattern
|
||||
let mut cpuset: libc::cpu_set_t = unsafe { std::mem::zeroed() };
|
||||
let mut cpuset: libc::cpu_set_t = unsafe { zeroed() };
|
||||
// SAFETY: FFI call, trivially safe
|
||||
unsafe { libc::CPU_ZERO(&mut cpuset) };
|
||||
for host_cpu in host_cpus {
|
||||
@@ -1237,7 +1244,7 @@ impl CpuManager {
|
||||
let ret = unsafe {
|
||||
libc::sched_setaffinity(
|
||||
0,
|
||||
std::mem::size_of::<libc::cpu_set_t>(),
|
||||
size_of::<libc::cpu_set_t>(),
|
||||
cpuset,
|
||||
)
|
||||
};
|
||||
@@ -1290,7 +1297,7 @@ impl CpuManager {
|
||||
match CoreSchedulingLeader::try_from(v) {
|
||||
Ok(CoreSchedulingLeader::Error) => return,
|
||||
Ok(CoreSchedulingLeader::Initial |
|
||||
CoreSchedulingLeader::Elected) => std::hint::spin_loop(),
|
||||
CoreSchedulingLeader::Elected) => hint::spin_loop(),
|
||||
Err(()) => break v,
|
||||
}
|
||||
};
|
||||
@@ -1328,7 +1335,7 @@ impl CpuManager {
|
||||
// Block until all CPUs are ready.
|
||||
vcpu_thread_barrier.wait();
|
||||
|
||||
std::panic::catch_unwind(move || {
|
||||
panic::catch_unwind(move || {
|
||||
loop {
|
||||
// If we are being told to pause, we park the thread
|
||||
// until the pause boolean is toggled.
|
||||
@@ -1563,7 +1570,7 @@ impl CpuManager {
|
||||
|
||||
#[cfg(feature = "mshv")]
|
||||
pub fn set_processors_per_socket_property(&self) -> Result<()> {
|
||||
if let Some(mshv_vm) = self.vm.as_any().downcast_ref::<hypervisor::mshv::MshvVm>() {
|
||||
if let Some(mshv_vm) = self.vm.as_any().downcast_ref::<mshv::MshvVm>() {
|
||||
let threads_per_core = if let Some(ref topology) = self.config.topology {
|
||||
topology.threads_per_core as u64
|
||||
} else {
|
||||
@@ -1572,7 +1579,7 @@ impl CpuManager {
|
||||
|
||||
mshv_vm
|
||||
.set_partition_property(
|
||||
hypervisor::mshv::HV_PARTITION_PROPERTY_PROCESSORS_PER_SOCKET,
|
||||
mshv::HV_PARTITION_PROPERTY_PROCESSORS_PER_SOCKET,
|
||||
threads_per_core,
|
||||
)
|
||||
.map_err(Error::SetPartitionProperty)?;
|
||||
@@ -1752,7 +1759,7 @@ impl CpuManager {
|
||||
let mut madt = Sdt::new(*b"APIC", 44, 5, *b"CLOUDH", *b"CHMADT ", 1);
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
{
|
||||
madt.write(36, arch::layout::APIC_START.0);
|
||||
madt.write(36, layout::APIC_START.0);
|
||||
|
||||
for cpu in 0..self.config.max_vcpus {
|
||||
let x2apic_id = get_x2apic_id(cpu, self.get_vcpu_topology());
|
||||
@@ -1776,7 +1783,7 @@ impl CpuManager {
|
||||
r#type: acpi::ACPI_APIC_IO,
|
||||
length: 12,
|
||||
ioapic_id: 0,
|
||||
apic_address: arch::layout::IOAPIC_START.0 as u32,
|
||||
apic_address: layout::IOAPIC_START.0 as u32,
|
||||
gsi_base: 0,
|
||||
..Default::default()
|
||||
});
|
||||
@@ -2163,7 +2170,7 @@ impl CpuManager {
|
||||
let pa_range = extract_bits_64_without_offset!(id_aa64mmfr0_el1, 4);
|
||||
// The IPA size in TCR_BL1 and PA Range in ID_AA64MMFR0_EL1 should match.
|
||||
// To be safe, we use the minimum value if they are different.
|
||||
let pa_range = std::cmp::min(tcr_ips, pa_range);
|
||||
let pa_range = cmp::min(tcr_ips, pa_range);
|
||||
// PA size in bits
|
||||
let pa_size = match pa_range {
|
||||
0 => 32,
|
||||
@@ -2320,10 +2327,10 @@ const MADT_CPU_ONLINE_CAPABLE_FLAG: usize = 1;
|
||||
impl Cpu {
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn generate_mat(&self) -> Vec<u8> {
|
||||
let x2apic_id = arch::x86_64::get_x2apic_id(self.cpu_id, self.topology);
|
||||
let x2apic_id = x86_64::get_x2apic_id(self.cpu_id, self.topology);
|
||||
|
||||
LocalX2Apic {
|
||||
r#type: crate::acpi::ACPI_X2APIC_PROCESSOR,
|
||||
r#type: acpi::ACPI_X2APIC_PROCESSOR,
|
||||
length: 16,
|
||||
processor_id: self.cpu_id,
|
||||
apic_id: x2apic_id,
|
||||
@@ -2650,7 +2657,7 @@ impl Aml for CpuManager {
|
||||
}
|
||||
|
||||
impl Pausable for CpuManager {
|
||||
fn pause(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
fn pause(&mut self) -> result::Result<(), MigratableError> {
|
||||
// Tell the vCPUs to pause themselves next time they exit
|
||||
self.vcpus_pause_signalled.store(true, Ordering::SeqCst);
|
||||
|
||||
@@ -2676,7 +2683,7 @@ impl Pausable for CpuManager {
|
||||
// wait for vCPU to update state
|
||||
while !state.paused.load(Ordering::SeqCst) {
|
||||
// To avoid a priority inversion with the vCPU thread
|
||||
thread::sleep(std::time::Duration::from_millis(1));
|
||||
thread::sleep(time::Duration::from_millis(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2684,7 +2691,7 @@ impl Pausable for CpuManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn resume(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
fn resume(&mut self) -> result::Result<(), MigratableError> {
|
||||
// Ensure that vCPUs keep running after being unpark() in
|
||||
// their run vCPU loop.
|
||||
self.vcpus_pause_signalled.store(false, Ordering::SeqCst);
|
||||
@@ -2704,7 +2711,7 @@ impl Pausable for CpuManager {
|
||||
// wait for vCPU to update state
|
||||
while state.paused.load(Ordering::SeqCst) {
|
||||
// To avoid a priority inversion with the vCPU thread
|
||||
thread::sleep(std::time::Duration::from_millis(1));
|
||||
thread::sleep(time::Duration::from_millis(1));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2717,7 +2724,7 @@ impl Snapshottable for CpuManager {
|
||||
CPU_MANAGER_SNAPSHOT_ID.to_string()
|
||||
}
|
||||
|
||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||
fn snapshot(&mut self) -> result::Result<Snapshot, MigratableError> {
|
||||
let mut cpu_manager_snapshot = Snapshot::default();
|
||||
|
||||
// The CpuManager snapshot is a collection of all vCPUs snapshots.
|
||||
@@ -2741,7 +2748,7 @@ impl Debuggable for CpuManager {
|
||||
cpu_id: usize,
|
||||
addrs: &[GuestAddress],
|
||||
singlestep: bool,
|
||||
) -> std::result::Result<(), DebuggableError> {
|
||||
) -> result::Result<(), DebuggableError> {
|
||||
self.vcpus[cpu_id]
|
||||
.lock()
|
||||
.unwrap()
|
||||
@@ -2750,16 +2757,16 @@ impl Debuggable for CpuManager {
|
||||
.map_err(DebuggableError::SetDebug)
|
||||
}
|
||||
|
||||
fn debug_pause(&mut self) -> std::result::Result<(), DebuggableError> {
|
||||
fn debug_pause(&mut self) -> result::Result<(), DebuggableError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn debug_resume(&mut self) -> std::result::Result<(), DebuggableError> {
|
||||
fn debug_resume(&mut self) -> result::Result<(), DebuggableError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn read_regs(&self, cpu_id: usize) -> std::result::Result<CoreRegs, DebuggableError> {
|
||||
fn read_regs(&self, cpu_id: usize) -> result::Result<CoreRegs, DebuggableError> {
|
||||
// General registers: RAX, RBX, RCX, RDX, RSI, RDI, RBP, RSP, r8-r15
|
||||
let gregs = self
|
||||
.get_regs(cpu_id as u8)
|
||||
@@ -2813,7 +2820,7 @@ impl Debuggable for CpuManager {
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn read_regs(&self, cpu_id: usize) -> std::result::Result<CoreRegs, DebuggableError> {
|
||||
fn read_regs(&self, cpu_id: usize) -> result::Result<CoreRegs, DebuggableError> {
|
||||
let gregs = self
|
||||
.get_regs(cpu_id as u8)
|
||||
.map_err(DebuggableError::ReadRegs)?;
|
||||
@@ -2826,11 +2833,7 @@ impl Debuggable for CpuManager {
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
fn write_regs(
|
||||
&self,
|
||||
cpu_id: usize,
|
||||
regs: &CoreRegs,
|
||||
) -> std::result::Result<(), DebuggableError> {
|
||||
fn write_regs(&self, cpu_id: usize, regs: &CoreRegs) -> result::Result<(), DebuggableError> {
|
||||
let orig_gregs = self
|
||||
.get_regs(cpu_id as u8)
|
||||
.map_err(DebuggableError::ReadRegs)?;
|
||||
@@ -2879,11 +2882,7 @@ impl Debuggable for CpuManager {
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
fn write_regs(
|
||||
&self,
|
||||
cpu_id: usize,
|
||||
regs: &CoreRegs,
|
||||
) -> std::result::Result<(), DebuggableError> {
|
||||
fn write_regs(&self, cpu_id: usize, regs: &CoreRegs) -> result::Result<(), DebuggableError> {
|
||||
let mut gregs = self
|
||||
.get_regs(cpu_id as u8)
|
||||
.map_err(DebuggableError::ReadRegs)?;
|
||||
@@ -2904,7 +2903,7 @@ impl Debuggable for CpuManager {
|
||||
cpu_id: usize,
|
||||
vaddr: GuestAddress,
|
||||
len: usize,
|
||||
) -> std::result::Result<Vec<u8>, DebuggableError> {
|
||||
) -> result::Result<Vec<u8>, DebuggableError> {
|
||||
let mut buf = vec![0; len];
|
||||
let mut total_read = 0_u64;
|
||||
|
||||
@@ -2916,7 +2915,7 @@ impl Debuggable for CpuManager {
|
||||
Err(e) => return Err(DebuggableError::TranslateGva(e)),
|
||||
};
|
||||
let psize = arch::PAGE_SIZE as u64;
|
||||
let read_len = std::cmp::min(len as u64 - total_read, psize - (paddr & (psize - 1)));
|
||||
let read_len = cmp::min(len as u64 - total_read, psize - (paddr & (psize - 1)));
|
||||
guest_memory
|
||||
.memory()
|
||||
.read(
|
||||
@@ -2935,7 +2934,7 @@ impl Debuggable for CpuManager {
|
||||
cpu_id: usize,
|
||||
vaddr: &GuestAddress,
|
||||
data: &[u8],
|
||||
) -> std::result::Result<(), DebuggableError> {
|
||||
) -> result::Result<(), DebuggableError> {
|
||||
let mut total_written = 0_u64;
|
||||
|
||||
while total_written < data.len() as u64 {
|
||||
@@ -2946,7 +2945,7 @@ impl Debuggable for CpuManager {
|
||||
Err(e) => return Err(DebuggableError::TranslateGva(e)),
|
||||
};
|
||||
let psize = arch::PAGE_SIZE as u64;
|
||||
let write_len = std::cmp::min(
|
||||
let write_len = cmp::min(
|
||||
data.len() as u64 - total_written,
|
||||
psize - (paddr & (psize - 1)),
|
||||
);
|
||||
@@ -2975,7 +2974,7 @@ impl CpuElf64Writable for CpuManager {
|
||||
fn cpu_write_elf64_note(
|
||||
&mut self,
|
||||
dump_state: &DumpState,
|
||||
) -> std::result::Result<(), GuestDebuggableError> {
|
||||
) -> result::Result<(), GuestDebuggableError> {
|
||||
let mut coredump_file = dump_state.file.as_ref().unwrap();
|
||||
for vcpu in &self.vcpus {
|
||||
let note_size = self.get_note_size(NoteDescType::Elf, 1);
|
||||
@@ -3083,7 +3082,7 @@ impl CpuElf64Writable for CpuManager {
|
||||
fn cpu_write_vmm_note(
|
||||
&mut self,
|
||||
dump_state: &DumpState,
|
||||
) -> std::result::Result<(), GuestDebuggableError> {
|
||||
) -> result::Result<(), GuestDebuggableError> {
|
||||
let mut coredump_file = dump_state.file.as_ref().unwrap();
|
||||
for vcpu in &self.vcpus {
|
||||
let note_size = self.get_note_size(NoteDescType::Vmm, 1);
|
||||
@@ -3349,6 +3348,7 @@ impl BusDevice for AcpiCpuHotplugController {
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
#[cfg(test)]
|
||||
mod unit_tests {
|
||||
use arch::layout;
|
||||
use arch::layout::{BOOT_STACK_POINTER, ZERO_PAGE_START};
|
||||
use arch::x86_64::interrupts::*;
|
||||
use arch::x86_64::regs::*;
|
||||
@@ -3448,7 +3448,7 @@ mod unit_tests {
|
||||
|
||||
let mut expected_regs: StandardRegisters = vcpu.create_standard_regs();
|
||||
expected_regs.set_rflags(0x0000000000000002u64);
|
||||
expected_regs.set_rbx(arch::layout::PVH_INFO_START.0);
|
||||
expected_regs.set_rbx(layout::PVH_INFO_START.0);
|
||||
expected_regs.set_rip(1);
|
||||
|
||||
setup_regs(
|
||||
@@ -3511,6 +3511,7 @@ mod unit_tests {
|
||||
KVM_REG_ARM_CORE, KVM_REG_ARM64, KVM_REG_ARM64_SYSREG, KVM_REG_SIZE_U64, user_pt_regs,
|
||||
};
|
||||
use hypervisor::{HypervisorCpuError, HypervisorVmConfig};
|
||||
use vmm_sys_util::errno;
|
||||
|
||||
#[test]
|
||||
fn test_setup_regs() {
|
||||
@@ -3564,7 +3565,7 @@ mod unit_tests {
|
||||
fn hypervisor_cpu_error_to_raw_os_error(error: &anyhow::Error) -> libc::c_int {
|
||||
let cause = error.chain().next().expect("should have root cause");
|
||||
cause
|
||||
.downcast_ref::<vmm_sys_util::errno::Error>()
|
||||
.downcast_ref::<errno::Error>()
|
||||
.unwrap_or_else(|| panic!("should be io::Error but is: {cause:?}"))
|
||||
.errno() as libc::c_int
|
||||
}
|
||||
|
||||
@@ -9,7 +9,11 @@
|
||||
// SPDX-License-Identifier: Apache-2.0 AND BSD-3-Clause
|
||||
//
|
||||
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use std::cmp;
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
||||
#[cfg(feature = "sev_snp")]
|
||||
use std::fmt;
|
||||
#[cfg(feature = "kvm")]
|
||||
use std::fs;
|
||||
use std::fs::{File, OpenOptions};
|
||||
@@ -20,10 +24,10 @@ use std::os::unix::io::{AsRawFd, FromRawFd};
|
||||
#[cfg(not(target_arch = "riscv64"))]
|
||||
use std::path::Path;
|
||||
use std::path::PathBuf;
|
||||
use std::result;
|
||||
use std::sync::{Arc, Mutex};
|
||||
#[cfg(not(target_arch = "riscv64"))]
|
||||
use std::time::Instant;
|
||||
use std::{iter, path, result, sync};
|
||||
|
||||
use acpi_tables::sdt::GenericAddress;
|
||||
use acpi_tables::{Aml, aml};
|
||||
@@ -62,8 +66,8 @@ use devices::legacy::{
|
||||
fw_cfg::{PORT_FW_CFG_BASE, PORT_FW_CFG_WIDTH},
|
||||
};
|
||||
#[cfg(feature = "pvmemcontrol")]
|
||||
use devices::pvmemcontrol::{PvmemcontrolBusDevice, PvmemcontrolPciDevice};
|
||||
use devices::{AcpiNotificationFlags, interrupt_controller};
|
||||
use devices::pvmemcontrol::{self, PvmemcontrolBusDevice, PvmemcontrolPciDevice};
|
||||
use devices::{AcpiNotificationFlags, acpi, interrupt_controller, legacy, pvpanic, tpm};
|
||||
use event_monitor::event;
|
||||
use hypervisor::IoEventAddress;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
@@ -79,6 +83,7 @@ use pci::{
|
||||
DeviceRelocation, MmioRegion, PciBarConfiguration, PciBarRegionType, PciBdf, PciDevice,
|
||||
VfioDmaMapping, VfioPciDevice, VfioUserDmaMapping, VfioUserPciDevice, VfioUserPciDeviceError,
|
||||
};
|
||||
use rate_limiter::group;
|
||||
use rate_limiter::group::RateLimiterGroup;
|
||||
use seccompiler::SeccompAction;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -87,10 +92,12 @@ use tracer::trace_scoped;
|
||||
#[cfg(feature = "kvm")]
|
||||
use vfio_ioctls::VfioIommufd;
|
||||
use vfio_ioctls::{VfioContainer, VfioDevice, VfioDeviceFd, VfioOps};
|
||||
use virtio_devices::block::Error as VirtioBlockError;
|
||||
use virtio_devices::transport::{VirtioPciDevice, VirtioPciDeviceActivator, VirtioTransport};
|
||||
use virtio_devices::vhost_user::VhostUserConfig;
|
||||
use virtio_devices::{
|
||||
AccessPlatformMapping, Block, Endpoint, IommuMapping, VdpaDmaMapping, VirtioMemMappingSource,
|
||||
balloon, mem, net, transport, vdpa, vhost_user, vsock,
|
||||
};
|
||||
use vm_allocator::{AddressAllocator, InterruptAllocError, SystemAllocator};
|
||||
use vm_device::dma_mapping::ExternalDmaMapping;
|
||||
@@ -101,7 +108,9 @@ use vm_device::{Bus, BusDevice, BusDeviceSync, Resource, UserspaceMapping};
|
||||
#[cfg(feature = "ivshmem")]
|
||||
use vm_memory::bitmap::AtomicBitmap;
|
||||
use vm_memory::guest_memory::FileOffset;
|
||||
use vm_memory::{Address, GuestAddress, GuestMemoryRegion, GuestUsize, MmapRegion, VolatileMemory};
|
||||
use vm_memory::{
|
||||
Address, GuestAddress, GuestMemoryRegion, GuestUsize, MmapRegion, VolatileMemory, mmap,
|
||||
};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use vm_memory::{GuestAddressSpace, GuestMemory};
|
||||
use vm_migration::protocol::MemoryRangeTable;
|
||||
@@ -110,6 +119,7 @@ use vm_migration::{
|
||||
snapshot_from_id, state_from_id,
|
||||
};
|
||||
use vm_virtio::{AccessPlatform, VirtioDeviceType};
|
||||
use vmm_sys_util::errno;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
use crate::console_devices::{ConsoleDeviceError, ConsoleInfo, ConsoleTransport};
|
||||
@@ -177,7 +187,7 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Cannot create vhost-user-net device
|
||||
#[error("Cannot create vhost-user-net device")]
|
||||
CreateVhostUserNet(#[source] virtio_devices::vhost_user::Error),
|
||||
CreateVhostUserNet(#[source] vhost_user::Error),
|
||||
|
||||
/// Cannot create virtio-blk device
|
||||
#[error("Cannot create virtio-blk device")]
|
||||
@@ -185,7 +195,7 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Cannot create virtio-net device
|
||||
#[error("Cannot create virtio-net device")]
|
||||
CreateVirtioNet(#[source] virtio_devices::net::Error),
|
||||
CreateVirtioNet(#[source] net::Error),
|
||||
|
||||
/// Cannot create virtio-console device
|
||||
#[error("Cannot create virtio-console device")]
|
||||
@@ -201,11 +211,11 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Cannot create generic vhost-user device
|
||||
#[error("Cannot create generic vhost-user device")]
|
||||
CreateGenericVhostUser(#[source] virtio_devices::vhost_user::Error),
|
||||
CreateGenericVhostUser(#[source] vhost_user::Error),
|
||||
|
||||
/// Cannot create virtio-fs device
|
||||
#[error("Cannot create virtio-fs device")]
|
||||
CreateVirtioFs(#[source] virtio_devices::vhost_user::Error),
|
||||
CreateVirtioFs(#[source] vhost_user::Error),
|
||||
|
||||
/// Virtio-fs device was created without a socket.
|
||||
#[error("Virtio-fs device was created without a socket")]
|
||||
@@ -217,7 +227,7 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Cannot create vhost-user-blk device
|
||||
#[error("Cannot create vhost-user-blk device")]
|
||||
CreateVhostUserBlk(#[source] virtio_devices::vhost_user::Error),
|
||||
CreateVhostUserBlk(#[source] vhost_user::Error),
|
||||
|
||||
/// Cannot create virtio-pmem device
|
||||
#[error("Cannot create virtio-pmem device")]
|
||||
@@ -225,7 +235,7 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Cannot create vDPA device
|
||||
#[error("Cannot create vdpa device")]
|
||||
CreateVdpa(#[source] virtio_devices::vdpa::Error),
|
||||
CreateVdpa(#[source] vdpa::Error),
|
||||
|
||||
/// Cannot create virtio-vsock device
|
||||
#[error("Cannot create virtio-vsock device")]
|
||||
@@ -245,7 +255,7 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Cannot create virtio-vsock backend
|
||||
#[error("Cannot create virtio-vsock backend")]
|
||||
CreateVsockBackend(#[source] virtio_devices::vsock::VsockUnixError),
|
||||
CreateVsockBackend(#[source] vsock::VsockUnixError),
|
||||
|
||||
/// Cannot create virtio-iommu device
|
||||
#[error("Cannot create virtio-iommu device")]
|
||||
@@ -282,7 +292,7 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Cannot configure the IRQ.
|
||||
#[error("Cannot configure the IRQ")]
|
||||
Irq(#[source] vmm_sys_util::errno::Error),
|
||||
Irq(#[source] errno::Error),
|
||||
|
||||
/// Cannot allocate PCI BARs
|
||||
#[error("Cannot allocate PCI BARs")]
|
||||
@@ -302,7 +312,7 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Cannot create virtio device
|
||||
#[error("Cannot create virtio device")]
|
||||
VirtioDevice(#[source] virtio_devices::transport::VirtioPciDeviceError),
|
||||
VirtioDevice(#[source] transport::VirtioPciDeviceError),
|
||||
|
||||
/// Cannot add PCI device
|
||||
#[error("Cannot add PCI device")]
|
||||
@@ -363,7 +373,7 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Error getting pty peer
|
||||
#[error("Error getting pty peer")]
|
||||
GetPtyPeer(#[source] vmm_sys_util::errno::Error),
|
||||
GetPtyPeer(#[source] errno::Error),
|
||||
|
||||
/// Cannot create iommufd
|
||||
#[cfg(feature = "kvm")]
|
||||
@@ -440,7 +450,7 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Failed to create a new MmapRegion instance.
|
||||
#[error("Failed to create a new MmapRegion instance")]
|
||||
NewMmapRegion(#[source] vm_memory::mmap::MmapRegionError),
|
||||
NewMmapRegion(#[source] mmap::MmapRegionError),
|
||||
|
||||
/// Failed to clone a File.
|
||||
#[error("Failed to clone a File")]
|
||||
@@ -560,7 +570,7 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Failed to resize virtio-balloon
|
||||
#[error("Failed to resize virtio-balloon")]
|
||||
VirtioBalloonResize(#[source] virtio_devices::balloon::Error),
|
||||
VirtioBalloonResize(#[source] balloon::Error),
|
||||
|
||||
/// Missing virtio-balloon, can't proceed as expected.
|
||||
#[error("Missing virtio-balloon, can't proceed as expected")]
|
||||
@@ -577,18 +587,18 @@ pub enum DeviceManagerError {
|
||||
/// Failed to do AArch64 GPIO power button notification
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[error("Failed to do AArch64 GPIO power button notification")]
|
||||
AArch64PowerButtonNotification(#[source] devices::legacy::GpioDeviceError),
|
||||
AArch64PowerButtonNotification(#[source] legacy::GpioDeviceError),
|
||||
|
||||
/// Failed to set O_DIRECT flag to file descriptor
|
||||
#[error("Failed to set O_DIRECT flag to file descriptor")]
|
||||
SetDirectIo,
|
||||
/// Failed to add DMA mapping handler to virtio-mem device.
|
||||
#[error("Failed to add DMA mapping handler to virtio-mem device")]
|
||||
AddDmaMappingHandlerVirtioMem(#[source] virtio_devices::mem::Error),
|
||||
AddDmaMappingHandlerVirtioMem(#[source] mem::Error),
|
||||
|
||||
/// Failed to remove DMA mapping handler from virtio-mem device.
|
||||
#[error("Failed to remove DMA mapping handler from virtio-mem device")]
|
||||
RemoveDmaMappingHandlerVirtioMem(#[source] virtio_devices::mem::Error),
|
||||
RemoveDmaMappingHandlerVirtioMem(#[source] mem::Error),
|
||||
|
||||
/// Failed to create vfio-user client
|
||||
#[error("Failed to create vfio-user client")]
|
||||
@@ -616,15 +626,15 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Cannot duplicate file descriptor
|
||||
#[error("Cannot duplicate file descriptor")]
|
||||
DupFd(#[source] vmm_sys_util::errno::Error),
|
||||
DupFd(#[source] errno::Error),
|
||||
|
||||
/// Failed to DMA map virtio device.
|
||||
#[error("Failed to DMA map virtio device")]
|
||||
VirtioDmaMap(#[source] std::io::Error),
|
||||
VirtioDmaMap(#[source] io::Error),
|
||||
|
||||
/// Failed to DMA unmap virtio device.
|
||||
#[error("Failed to DMA unmap virtio device")]
|
||||
VirtioDmaUnmap(#[source] std::io::Error),
|
||||
VirtioDmaUnmap(#[source] io::Error),
|
||||
|
||||
/// Cannot hotplug device behind vIOMMU
|
||||
#[error("Cannot hotplug device behind vIOMMU")]
|
||||
@@ -640,7 +650,7 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// vfio-user socket path already in use by another user device.
|
||||
#[error("vfio-user socket path already in use: {0:?}")]
|
||||
UserDeviceSocketInUse(std::path::PathBuf),
|
||||
UserDeviceSocketInUse(path::PathBuf),
|
||||
|
||||
/// Failed retrieving device state from snapshot
|
||||
#[error("Failed retrieving device state from snapshot")]
|
||||
@@ -648,7 +658,7 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Cannot create a PvPanic device
|
||||
#[error("Cannot create a PvPanic device")]
|
||||
PvPanicCreate(#[source] devices::pvpanic::PvPanicError),
|
||||
PvPanicCreate(#[source] pvpanic::PvPanicError),
|
||||
|
||||
#[cfg(feature = "ivshmem")]
|
||||
/// Cannot create a ivshmem device
|
||||
@@ -657,11 +667,11 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Cannot create a RateLimiterGroup
|
||||
#[error("Cannot create a RateLimiterGroup")]
|
||||
RateLimiterGroupCreate(#[source] rate_limiter::group::Error),
|
||||
RateLimiterGroupCreate(#[source] group::Error),
|
||||
|
||||
/// Cannot start sigwinch listener
|
||||
#[error("Cannot start sigwinch listener")]
|
||||
StartSigwinchListener(#[source] std::io::Error),
|
||||
StartSigwinchListener(#[source] io::Error),
|
||||
|
||||
// Invalid console info
|
||||
#[error("Invalid console info")]
|
||||
@@ -673,7 +683,7 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Cannot lock images of all block devices.
|
||||
#[error("Cannot lock images of all block devices")]
|
||||
DiskLockError(#[source] virtio_devices::block::Error),
|
||||
DiskLockError(#[source] VirtioBlockError),
|
||||
|
||||
#[cfg(feature = "fw_cfg")]
|
||||
/// Error adding fw_cfg to bus.
|
||||
@@ -682,7 +692,7 @@ pub enum DeviceManagerError {
|
||||
|
||||
/// Disk resizing failed.
|
||||
#[error("Disk resize error")]
|
||||
DiskResize(#[source] virtio_devices::block::Error),
|
||||
DiskResize(#[source] VirtioBlockError),
|
||||
|
||||
/// Disk image type does not match expected type.
|
||||
#[error(
|
||||
@@ -737,7 +747,7 @@ impl DeviceRelocation for AddressManager {
|
||||
len: u64,
|
||||
pci_dev: &mut dyn PciDevice,
|
||||
region_type: PciBarRegionType,
|
||||
) -> std::result::Result<(), std::io::Error> {
|
||||
) -> result::Result<(), io::Error> {
|
||||
match region_type {
|
||||
PciBarRegionType::IoRegion => {
|
||||
let mut sys_allocator = self.allocator.lock().unwrap();
|
||||
@@ -974,8 +984,8 @@ struct SevSnpPageAccessProxy {
|
||||
}
|
||||
|
||||
#[cfg(feature = "sev_snp")]
|
||||
impl std::fmt::Debug for SevSnpPageAccessProxy {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
impl fmt::Debug for SevSnpPageAccessProxy {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "SNP Page access proxy")
|
||||
}
|
||||
}
|
||||
@@ -989,11 +999,11 @@ impl SevSnpPageAccessProxy {
|
||||
|
||||
#[cfg(feature = "sev_snp")]
|
||||
impl AccessPlatform for SevSnpPageAccessProxy {
|
||||
fn translate_gpa(&self, base: u64, _size: u64) -> std::result::Result<u64, std::io::Error> {
|
||||
fn translate_gpa(&self, base: u64, _size: u64) -> result::Result<u64, io::Error> {
|
||||
Ok(base)
|
||||
}
|
||||
|
||||
fn translate_gva(&self, base: u64, size: u64) -> std::result::Result<u64, std::io::Error> {
|
||||
fn translate_gva(&self, base: u64, size: u64) -> result::Result<u64, io::Error> {
|
||||
self.vm
|
||||
.gain_page_access(base, size as u32)
|
||||
.map_err(io::Error::other)?;
|
||||
@@ -1126,7 +1136,7 @@ pub struct DeviceManager {
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
// GPIO device for AArch64
|
||||
gpio_device: Option<Arc<Mutex<devices::legacy::Gpio>>>,
|
||||
gpio_device: Option<Arc<Mutex<legacy::Gpio>>>,
|
||||
|
||||
#[cfg(feature = "pvmemcontrol")]
|
||||
pvmemcontrol_devices: Option<(
|
||||
@@ -1251,8 +1261,7 @@ impl DeviceManager {
|
||||
};
|
||||
|
||||
let mut mmio32_aperture_weights: Vec<u32> =
|
||||
std::iter::repeat_n(DEFAULT_PCI_SEGMENT_APERTURE_WEIGHT, num_pci_segments.into())
|
||||
.collect();
|
||||
iter::repeat_n(DEFAULT_PCI_SEGMENT_APERTURE_WEIGHT, num_pci_segments.into()).collect();
|
||||
if let Some(pci_segments) = &config.lock().unwrap().pci_segments {
|
||||
for pci_segment in pci_segments.iter() {
|
||||
mmio32_aperture_weights[pci_segment.pci_segment as usize] =
|
||||
@@ -1272,8 +1281,7 @@ impl DeviceManager {
|
||||
);
|
||||
|
||||
let mut mmio64_aperture_weights: Vec<u32> =
|
||||
std::iter::repeat_n(DEFAULT_PCI_SEGMENT_APERTURE_WEIGHT, num_pci_segments.into())
|
||||
.collect();
|
||||
iter::repeat_n(DEFAULT_PCI_SEGMENT_APERTURE_WEIGHT, num_pci_segments.into()).collect();
|
||||
if let Some(pci_segments) = &config.lock().unwrap().pci_segments {
|
||||
for pci_segment in pci_segments.iter() {
|
||||
mmio64_aperture_weights[pci_segment.pci_segment as usize] =
|
||||
@@ -1586,7 +1594,7 @@ impl DeviceManager {
|
||||
|
||||
#[cfg(feature = "fw_cfg")]
|
||||
pub fn create_fw_cfg_device(&mut self) -> Result<(), DeviceManagerError> {
|
||||
let fw_cfg = Arc::new(Mutex::new(devices::legacy::FwCfg::new(
|
||||
let fw_cfg = Arc::new(Mutex::new(legacy::FwCfg::new(
|
||||
self.memory_manager.lock().as_ref().unwrap().guest_memory(),
|
||||
)));
|
||||
|
||||
@@ -1986,11 +1994,7 @@ impl DeviceManager {
|
||||
.allocator
|
||||
.lock()
|
||||
.unwrap()
|
||||
.allocate_platform_mmio_addresses(
|
||||
None,
|
||||
devices::acpi::GED_DEVICE_ACPI_SIZE as u64,
|
||||
None,
|
||||
)
|
||||
.allocate_platform_mmio_addresses(None, acpi::GED_DEVICE_ACPI_SIZE as u64, None)
|
||||
.ok_or(DeviceManagerError::AllocateMmioAddress)?;
|
||||
let ged_device = Arc::new(Mutex::new(devices::AcpiGedDevice::new(
|
||||
interrupt_group,
|
||||
@@ -2002,7 +2006,7 @@ impl DeviceManager {
|
||||
.insert(
|
||||
ged_device.clone(),
|
||||
ged_address.0,
|
||||
devices::acpi::GED_DEVICE_ACPI_SIZE as u64,
|
||||
acpi::GED_DEVICE_ACPI_SIZE as u64,
|
||||
)
|
||||
.map_err(DeviceManagerError::BusError)?;
|
||||
self.bus_devices
|
||||
@@ -2045,7 +2049,7 @@ impl DeviceManager {
|
||||
.vcpus_kill_signalled()
|
||||
.clone();
|
||||
// Add a shutdown device (i8042)
|
||||
let i8042 = Arc::new(Mutex::new(devices::legacy::I8042Device::new(
|
||||
let i8042 = Arc::new(Mutex::new(legacy::I8042Device::new(
|
||||
reset_evt.try_clone().unwrap(),
|
||||
vcpus_kill_signalled.clone(),
|
||||
)));
|
||||
@@ -2068,10 +2072,10 @@ impl DeviceManager {
|
||||
.last_addr()
|
||||
.0
|
||||
+ 1;
|
||||
let mem_below_4g = std::cmp::min(arch::layout::MEM_32BIT_RESERVED_START.0, mem_size);
|
||||
let mem_above_4g = mem_size.saturating_sub(arch::layout::RAM_64BIT_START.0);
|
||||
let mem_below_4g = cmp::min(layout::MEM_32BIT_RESERVED_START.0, mem_size);
|
||||
let mem_above_4g = mem_size.saturating_sub(layout::RAM_64BIT_START.0);
|
||||
|
||||
let cmos = Arc::new(Mutex::new(devices::legacy::Cmos::new(
|
||||
let cmos = Arc::new(Mutex::new(legacy::Cmos::new(
|
||||
mem_below_4g,
|
||||
mem_above_4g,
|
||||
reset_evt,
|
||||
@@ -2086,7 +2090,7 @@ impl DeviceManager {
|
||||
.insert(cmos, 0x70, 0x2)
|
||||
.map_err(DeviceManagerError::BusError)?;
|
||||
|
||||
let fwdebug = Arc::new(Mutex::new(devices::legacy::FwDebugDevice::new()));
|
||||
let fwdebug = Arc::new(Mutex::new(legacy::FwDebugDevice::new()));
|
||||
|
||||
self.bus_devices
|
||||
.push(Arc::clone(&fwdebug) as Arc<dyn BusDeviceSync>);
|
||||
@@ -2098,7 +2102,7 @@ impl DeviceManager {
|
||||
}
|
||||
|
||||
// 0x80 debug port
|
||||
let debug_port = Arc::new(Mutex::new(devices::legacy::DebugPort::new(self.timestamp)));
|
||||
let debug_port = Arc::new(Mutex::new(legacy::DebugPort::new(self.timestamp)));
|
||||
self.bus_devices
|
||||
.push(Arc::clone(&debug_port) as Arc<dyn BusDeviceSync>);
|
||||
self.address_manager
|
||||
@@ -2124,12 +2128,12 @@ impl DeviceManager {
|
||||
.allocate_irq()
|
||||
.unwrap();
|
||||
|
||||
let rtc_device = Arc::new(Mutex::new(devices::legacy::Rtc::new()));
|
||||
let rtc_device = Arc::new(Mutex::new(legacy::Rtc::new()));
|
||||
|
||||
self.bus_devices
|
||||
.push(Arc::clone(&rtc_device) as Arc<dyn BusDeviceSync>);
|
||||
|
||||
let addr = arch::layout::LEGACY_RTC_MAPPED_IO_START;
|
||||
let addr = layout::LEGACY_RTC_MAPPED_IO_START;
|
||||
|
||||
self.address_manager
|
||||
.mmio_bus
|
||||
@@ -2161,7 +2165,7 @@ impl DeviceManager {
|
||||
})
|
||||
.map_err(DeviceManagerError::CreateInterruptGroup)?;
|
||||
|
||||
let gpio_device = Arc::new(Mutex::new(devices::legacy::Gpio::new(
|
||||
let gpio_device = Arc::new(Mutex::new(legacy::Gpio::new(
|
||||
id.clone(),
|
||||
interrupt_group,
|
||||
state_from_id(snapshot, id.as_str()).map_err(DeviceManagerError::RestoreGetState)?,
|
||||
@@ -2170,7 +2174,7 @@ impl DeviceManager {
|
||||
self.bus_devices
|
||||
.push(Arc::clone(&gpio_device) as Arc<dyn BusDeviceSync>);
|
||||
|
||||
let addr = arch::layout::LEGACY_GPIO_MAPPED_IO_START;
|
||||
let addr = layout::LEGACY_GPIO_MAPPED_IO_START;
|
||||
|
||||
self.address_manager
|
||||
.mmio_bus
|
||||
@@ -2316,7 +2320,7 @@ impl DeviceManager {
|
||||
})
|
||||
.map_err(DeviceManagerError::CreateInterruptGroup)?;
|
||||
|
||||
let serial = Arc::new(Mutex::new(devices::legacy::Pl011::new(
|
||||
let serial = Arc::new(Mutex::new(legacy::Pl011::new(
|
||||
id.clone(),
|
||||
interrupt_group,
|
||||
serial_writer,
|
||||
@@ -2327,7 +2331,7 @@ impl DeviceManager {
|
||||
self.bus_devices
|
||||
.push(Arc::clone(&serial) as Arc<dyn BusDeviceSync>);
|
||||
|
||||
let addr = arch::layout::LEGACY_SERIAL_MAPPED_IO_START;
|
||||
let addr = layout::LEGACY_SERIAL_MAPPED_IO_START;
|
||||
|
||||
self.address_manager
|
||||
.mmio_bus
|
||||
@@ -2444,8 +2448,7 @@ impl DeviceManager {
|
||||
// SAFETY: FFI call to dup. Trivially safe.
|
||||
let stdin = unsafe { libc::dup(libc::STDIN_FILENO) };
|
||||
if stdin == -1 {
|
||||
return vmm_sys_util::errno::errno_result()
|
||||
.map_err(DeviceManagerError::DupFd);
|
||||
return errno::errno_result().map_err(DeviceManagerError::DupFd);
|
||||
}
|
||||
// SAFETY: stdin is valid and owned solely by us.
|
||||
let stdin = unsafe { File::from_raw_fd(stdin) };
|
||||
@@ -2591,12 +2594,9 @@ impl DeviceManager {
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "riscv64"))]
|
||||
fn add_tpm_device(
|
||||
&mut self,
|
||||
tpm_path: &Path,
|
||||
) -> DeviceManagerResult<Arc<Mutex<devices::tpm::Tpm>>> {
|
||||
fn add_tpm_device(&mut self, tpm_path: &Path) -> DeviceManagerResult<Arc<Mutex<tpm::Tpm>>> {
|
||||
// Create TPM Device
|
||||
let tpm = devices::tpm::Tpm::new(tpm_path).map_err(|e| {
|
||||
let tpm = tpm::Tpm::new(tpm_path).map_err(|e| {
|
||||
DeviceManagerError::CreateTpmDevice(anyhow!("Failed to create TPM Device : {e:?}"))
|
||||
})?;
|
||||
let tpm = Arc::new(Mutex::new(tpm));
|
||||
@@ -2604,11 +2604,7 @@ impl DeviceManager {
|
||||
// Add TPM Device to mmio
|
||||
self.address_manager
|
||||
.mmio_bus
|
||||
.insert(
|
||||
tpm.clone(),
|
||||
arch::layout::TPM_START.0,
|
||||
arch::layout::TPM_SIZE,
|
||||
)
|
||||
.insert(tpm.clone(), layout::TPM_START.0, layout::TPM_SIZE)
|
||||
.map_err(DeviceManagerError::BusError)?;
|
||||
|
||||
Ok(tpm)
|
||||
@@ -2715,7 +2711,7 @@ impl DeviceManager {
|
||||
queue_size: disk_cfg.queue_size,
|
||||
};
|
||||
let vhost_user_block = Arc::new(Mutex::new(
|
||||
match virtio_devices::vhost_user::Blk::new(
|
||||
match vhost_user::Blk::new(
|
||||
id.clone(),
|
||||
vu_cfg,
|
||||
self.seccomp_action.clone(),
|
||||
@@ -2945,7 +2941,7 @@ impl DeviceManager {
|
||||
VhostMode::Server => true,
|
||||
};
|
||||
let vhost_user_net = Arc::new(Mutex::new(
|
||||
match virtio_devices::vhost_user::Net::new(
|
||||
match vhost_user::Net::new(
|
||||
id.clone(),
|
||||
net_cfg.mac,
|
||||
net_cfg.mtu,
|
||||
@@ -3204,7 +3200,7 @@ impl DeviceManager {
|
||||
|
||||
if let Some(generic_vhost_user_socket) = generic_vhost_user_cfg.socket.to_str() {
|
||||
let generic_vhost_user_device = Arc::new(Mutex::new(
|
||||
virtio_devices::vhost_user::GenericVhostUser::new(
|
||||
vhost_user::GenericVhostUser::new(
|
||||
id.clone(),
|
||||
generic_vhost_user_socket,
|
||||
generic_vhost_user_cfg.queue_sizes.clone(),
|
||||
@@ -3274,7 +3270,7 @@ impl DeviceManager {
|
||||
|
||||
if let Some(fs_socket) = fs_cfg.socket.to_str() {
|
||||
let virtio_fs_device = Arc::new(Mutex::new(
|
||||
virtio_devices::vhost_user::Fs::new(
|
||||
vhost_user::Fs::new(
|
||||
id.clone(),
|
||||
fs_socket,
|
||||
&fs_cfg.tag,
|
||||
@@ -3527,9 +3523,8 @@ impl DeviceManager {
|
||||
.socket
|
||||
.to_str()
|
||||
.ok_or(DeviceManagerError::CreateVsockConvertPath)?;
|
||||
let backend =
|
||||
virtio_devices::vsock::VsockUnixBackend::new(vsock_cfg.cid, socket_path.to_string())
|
||||
.map_err(DeviceManagerError::CreateVsockBackend)?;
|
||||
let backend = vsock::VsockUnixBackend::new(vsock_cfg.cid, socket_path.to_string())
|
||||
.map_err(DeviceManagerError::CreateVsockBackend)?;
|
||||
|
||||
let vsock_device = Arc::new(Mutex::new(
|
||||
virtio_devices::Vsock::new(
|
||||
@@ -3651,7 +3646,7 @@ impl DeviceManager {
|
||||
|
||||
info!("Creating pvmemcontrol device: id = {id}");
|
||||
let (pvmemcontrol_pci_device, pvmemcontrol_bus_device) =
|
||||
devices::pvmemcontrol::PvmemcontrolDevice::make_device(
|
||||
pvmemcontrol::PvmemcontrolDevice::make_device(
|
||||
id.clone(),
|
||||
self.memory_manager.lock().unwrap().guest_memory(),
|
||||
);
|
||||
@@ -5843,7 +5838,7 @@ impl Aml for DeviceManager {
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
&aml::Memory32Fixed::new(
|
||||
true,
|
||||
arch::layout::LEGACY_SERIAL_MAPPED_IO_START.raw_value() as u32,
|
||||
layout::LEGACY_SERIAL_MAPPED_IO_START.raw_value() as u32,
|
||||
MMIO_LEN as u32,
|
||||
),
|
||||
]),
|
||||
@@ -5939,7 +5934,7 @@ impl Snapshottable for DeviceManager {
|
||||
DEVICE_MANAGER_SNAPSHOT_ID.to_string()
|
||||
}
|
||||
|
||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||
fn snapshot(&mut self) -> result::Result<Snapshot, MigratableError> {
|
||||
let mut snapshot = Snapshot::from_data(SnapshotData::new_from_state(&self.state())?);
|
||||
|
||||
// We aggregate all devices snapshots.
|
||||
@@ -5957,7 +5952,7 @@ impl Snapshottable for DeviceManager {
|
||||
impl Transportable for DeviceManager {}
|
||||
|
||||
impl Migratable for DeviceManager {
|
||||
fn start_dirty_log(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
fn start_dirty_log(&mut self) -> result::Result<(), MigratableError> {
|
||||
for (_, device_node) in self.device_tree.lock().unwrap().iter() {
|
||||
if let Some(migratable) = &device_node.migratable {
|
||||
migratable.lock().unwrap().start_dirty_log()?;
|
||||
@@ -5966,7 +5961,7 @@ impl Migratable for DeviceManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stop_dirty_log(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
fn stop_dirty_log(&mut self) -> result::Result<(), MigratableError> {
|
||||
for (_, device_node) in self.device_tree.lock().unwrap().iter() {
|
||||
if let Some(migratable) = &device_node.migratable {
|
||||
migratable.lock().unwrap().stop_dirty_log()?;
|
||||
@@ -5975,7 +5970,7 @@ impl Migratable for DeviceManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn dirty_log(&mut self) -> std::result::Result<MemoryRangeTable, MigratableError> {
|
||||
fn dirty_log(&mut self) -> result::Result<MemoryRangeTable, MigratableError> {
|
||||
let mut tables = Vec::new();
|
||||
for (_, device_node) in self.device_tree.lock().unwrap().iter() {
|
||||
if let Some(migratable) = &device_node.migratable {
|
||||
@@ -5985,7 +5980,7 @@ impl Migratable for DeviceManager {
|
||||
Ok(MemoryRangeTable::new_from_tables(tables))
|
||||
}
|
||||
|
||||
fn start_migration(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
fn start_migration(&mut self) -> result::Result<(), MigratableError> {
|
||||
for (_, device_node) in self.device_tree.lock().unwrap().iter() {
|
||||
if let Some(migratable) = &device_node.migratable {
|
||||
migratable.lock().unwrap().start_migration()?;
|
||||
@@ -5994,7 +5989,7 @@ impl Migratable for DeviceManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
fn complete_migration(&mut self) -> result::Result<(), MigratableError> {
|
||||
for (_, device_node) in self.device_tree.lock().unwrap().iter() {
|
||||
if let Some(migratable) = &device_node.migratable {
|
||||
migratable.lock().unwrap().complete_migration()?;
|
||||
@@ -6064,7 +6059,7 @@ impl BusDevice for DeviceManager {
|
||||
debug!("PCI_HP_REG_R: base 0x{base:x}, offset 0x{offset:x}, data {data:?}");
|
||||
}
|
||||
|
||||
fn write(&mut self, base: u64, offset: u64, data: &[u8]) -> Option<Arc<std::sync::Barrier>> {
|
||||
fn write(&mut self, base: u64, offset: u64, data: &[u8]) -> Option<Arc<sync::Barrier>> {
|
||||
match offset {
|
||||
B0EJ_FIELD_OFFSET => {
|
||||
if data.len() != B0EJ_FIELD_SIZE {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::collections::{HashMap, hash_map};
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use pci::PciBdf;
|
||||
@@ -75,7 +75,7 @@ impl DeviceTree {
|
||||
pub fn remove(&mut self, k: &str) -> Option<DeviceNode> {
|
||||
self.0.remove(k)
|
||||
}
|
||||
pub fn iter(&self) -> std::collections::hash_map::Iter<'_, String, DeviceNode> {
|
||||
pub fn iter(&self) -> hash_map::Iter<'_, String, DeviceNode> {
|
||||
self.0.iter()
|
||||
}
|
||||
pub fn breadth_first_traversal(&self) -> BftIter<'_> {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
|
||||
use std::os::unix::net::UnixListener;
|
||||
use std::sync::mpsc;
|
||||
use std::{cmp, io, path, result};
|
||||
|
||||
use gdbstub::arch::Arch;
|
||||
use gdbstub::common::{Signal, Tid};
|
||||
@@ -32,8 +33,9 @@ use gdbstub_arch::x86::reg::X86_64CoreRegs as CoreRegs;
|
||||
use log::{error, info};
|
||||
use thiserror::Error;
|
||||
use vm_memory::{GuestAddress, GuestMemoryAtomic, GuestMemoryError};
|
||||
use vmm_sys_util::eventfd;
|
||||
|
||||
use crate::GuestMemoryMmap;
|
||||
use crate::{GuestMemoryMmap, cpu, vm};
|
||||
|
||||
type ArchUsize = u64;
|
||||
|
||||
@@ -46,15 +48,15 @@ pub enum DebuggableError {
|
||||
#[error("Resuming failed")]
|
||||
Resume(#[source] vm_migration::MigratableError),
|
||||
#[error("Reading registers failed")]
|
||||
ReadRegs(#[source] crate::cpu::Error),
|
||||
ReadRegs(#[source] cpu::Error),
|
||||
#[error("Writing registers failed")]
|
||||
WriteRegs(#[source] crate::cpu::Error),
|
||||
WriteRegs(#[source] cpu::Error),
|
||||
#[error("Reading memory failed")]
|
||||
ReadMem(#[source] GuestMemoryError),
|
||||
#[error("Writing memory failed")]
|
||||
WriteMem(#[source] GuestMemoryError),
|
||||
#[error("Translating GVA failed")]
|
||||
TranslateGva(#[source] crate::cpu::Error),
|
||||
TranslateGva(#[source] cpu::Error),
|
||||
#[error("The lock is poisened")]
|
||||
PoisonedState,
|
||||
}
|
||||
@@ -66,45 +68,41 @@ pub trait Debuggable: vm_migration::Pausable {
|
||||
addrs: &[GuestAddress],
|
||||
singlestep: bool,
|
||||
) -> Result<(), DebuggableError>;
|
||||
fn debug_pause(&mut self) -> std::result::Result<(), DebuggableError>;
|
||||
fn debug_resume(&mut self) -> std::result::Result<(), DebuggableError>;
|
||||
fn read_regs(&self, cpu_id: usize) -> std::result::Result<CoreRegs, DebuggableError>;
|
||||
fn write_regs(
|
||||
&self,
|
||||
cpu_id: usize,
|
||||
regs: &CoreRegs,
|
||||
) -> std::result::Result<(), DebuggableError>;
|
||||
fn debug_pause(&mut self) -> result::Result<(), DebuggableError>;
|
||||
fn debug_resume(&mut self) -> result::Result<(), DebuggableError>;
|
||||
fn read_regs(&self, cpu_id: usize) -> result::Result<CoreRegs, DebuggableError>;
|
||||
fn write_regs(&self, cpu_id: usize, regs: &CoreRegs) -> result::Result<(), DebuggableError>;
|
||||
fn read_mem(
|
||||
&self,
|
||||
guest_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
cpu_id: usize,
|
||||
vaddr: GuestAddress,
|
||||
len: usize,
|
||||
) -> std::result::Result<Vec<u8>, DebuggableError>;
|
||||
) -> result::Result<Vec<u8>, DebuggableError>;
|
||||
fn write_mem(
|
||||
&self,
|
||||
guest_memory: &GuestMemoryAtomic<GuestMemoryMmap>,
|
||||
cpu_id: usize,
|
||||
vaddr: &GuestAddress,
|
||||
data: &[u8],
|
||||
) -> std::result::Result<(), DebuggableError>;
|
||||
) -> result::Result<(), DebuggableError>;
|
||||
fn active_vcpus(&self) -> usize;
|
||||
}
|
||||
|
||||
#[derive(Error, Debug)]
|
||||
pub enum Error {
|
||||
#[error("VM failed")]
|
||||
Vm(#[source] crate::vm::Error),
|
||||
Vm(#[source] vm::Error),
|
||||
#[error("GDB request failed")]
|
||||
GdbRequest,
|
||||
#[error("GDB couldn't be notified")]
|
||||
GdbResponseNotify(#[source] std::io::Error),
|
||||
GdbResponseNotify(#[source] io::Error),
|
||||
#[error("GDB response failed")]
|
||||
GdbResponse(#[source] mpsc::RecvError),
|
||||
#[error("GDB response timeout")]
|
||||
GdbResponseTimeout(#[source] mpsc::RecvTimeoutError),
|
||||
}
|
||||
type GdbResult<T> = std::result::Result<T, Error>;
|
||||
type GdbResult<T> = result::Result<T, Error>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct GdbRequest {
|
||||
@@ -126,7 +124,7 @@ pub enum GdbRequestPayload {
|
||||
ActiveVcpus,
|
||||
}
|
||||
|
||||
pub type GdbResponse = std::result::Result<GdbResponsePayload, Error>;
|
||||
pub type GdbResponse = result::Result<GdbResponsePayload, Error>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum GdbResponsePayload {
|
||||
@@ -138,8 +136,8 @@ pub enum GdbResponsePayload {
|
||||
|
||||
pub struct GdbStub {
|
||||
gdb_sender: mpsc::Sender<GdbRequest>,
|
||||
gdb_event: vmm_sys_util::eventfd::EventFd,
|
||||
vm_event: vmm_sys_util::eventfd::EventFd,
|
||||
gdb_event: eventfd::EventFd,
|
||||
vm_event: eventfd::EventFd,
|
||||
hw_breakpoints: Vec<GuestAddress>,
|
||||
single_step: bool,
|
||||
}
|
||||
@@ -147,8 +145,8 @@ pub struct GdbStub {
|
||||
impl GdbStub {
|
||||
pub fn new(
|
||||
gdb_sender: mpsc::Sender<GdbRequest>,
|
||||
gdb_event: vmm_sys_util::eventfd::EventFd,
|
||||
vm_event: vmm_sys_util::eventfd::EventFd,
|
||||
gdb_event: eventfd::EventFd,
|
||||
vm_event: eventfd::EventFd,
|
||||
hw_breakpoints: usize,
|
||||
) -> Self {
|
||||
Self {
|
||||
@@ -165,7 +163,7 @@ impl GdbStub {
|
||||
payload: GdbRequestPayload,
|
||||
cpu_id: usize,
|
||||
) -> GdbResult<GdbResponsePayload> {
|
||||
let (response_sender, response_receiver) = std::sync::mpsc::channel();
|
||||
let (response_sender, response_receiver) = mpsc::channel();
|
||||
let request = GdbRequest {
|
||||
sender: response_sender,
|
||||
payload,
|
||||
@@ -265,7 +263,7 @@ impl MultiThreadBase for GdbStub {
|
||||
for (dst, v) in data.iter_mut().zip(r.iter()) {
|
||||
*dst = *v;
|
||||
}
|
||||
Ok(std::cmp::min(data.len(), r.len()))
|
||||
Ok(cmp::min(data.len(), r.len()))
|
||||
}
|
||||
Ok(s) => {
|
||||
error!("Unexpected response for ReadMem: {s:?}");
|
||||
@@ -445,7 +443,7 @@ enum GdbEventLoop {}
|
||||
|
||||
impl run_blocking::BlockingEventLoop for GdbEventLoop {
|
||||
type Target = GdbStub;
|
||||
type Connection = Box<dyn ConnectionExt<Error = std::io::Error>>;
|
||||
type Connection = Box<dyn ConnectionExt<Error = io::Error>>;
|
||||
type StopReason = MultiThreadStopReason<ArchUsize>;
|
||||
|
||||
fn wait_for_stop_reason(
|
||||
@@ -478,7 +476,7 @@ impl run_blocking::BlockingEventLoop for GdbEventLoop {
|
||||
return Ok(run_blocking::Event::TargetStopped(stop_reason));
|
||||
}
|
||||
Err(e) => {
|
||||
if e.kind() != std::io::ErrorKind::WouldBlock {
|
||||
if e.kind() != io::ErrorKind::WouldBlock {
|
||||
return Err(run_blocking::WaitForStopReasonError::Connection(e));
|
||||
}
|
||||
}
|
||||
@@ -506,7 +504,7 @@ impl run_blocking::BlockingEventLoop for GdbEventLoop {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn gdb_thread(mut gdbstub: GdbStub, path: &std::path::Path) {
|
||||
pub fn gdb_thread(mut gdbstub: GdbStub, path: &path::Path) {
|
||||
let listener = match UnixListener::bind(path) {
|
||||
Ok(s) => s,
|
||||
Err(e) => {
|
||||
@@ -525,7 +523,7 @@ pub fn gdb_thread(mut gdbstub: GdbStub, path: &std::path::Path) {
|
||||
};
|
||||
info!("GDB connected from {addr:?}");
|
||||
|
||||
let connection: Box<dyn ConnectionExt<Error = std::io::Error>> = Box::new(stream);
|
||||
let connection: Box<dyn ConnectionExt<Error = io::Error>> = Box::new(stream);
|
||||
let gdb = gdbstub::stub::GdbStub::new(connection);
|
||||
|
||||
match gdb.run_blocking::<GdbEventLoop>(&mut gdbstub) {
|
||||
|
||||
@@ -2,10 +2,15 @@
|
||||
//
|
||||
// Copyright © 2023, Microsoft Corporation
|
||||
//
|
||||
#[cfg(all(feature = "kvm", feature = "sev_snp"))]
|
||||
use std::cmp;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::CString;
|
||||
#[cfg(feature = "kvm")]
|
||||
use std::iter;
|
||||
use std::mem::size_of;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{ffi, io};
|
||||
|
||||
use hypervisor::HypervisorType;
|
||||
#[cfg(feature = "sev_snp")]
|
||||
@@ -31,15 +36,18 @@ use vm_memory::Bytes;
|
||||
use vm_memory::{GuestAddress, GuestAddressSpace, GuestMemory};
|
||||
#[cfg(all(feature = "kvm", feature = "sev_snp"))]
|
||||
use vm_migration::Snapshottable;
|
||||
#[cfg(all(feature = "kvm", feature = "sev_snp", feature = "fw_cfg"))]
|
||||
use vmm_sys_util::errno;
|
||||
use zerocopy::IntoBytes;
|
||||
#[cfg(all(feature = "kvm", feature = "sev_snp"))]
|
||||
use zerocopy::{FromBytes, FromZeros};
|
||||
|
||||
#[cfg(feature = "sev_snp")]
|
||||
use crate::GuestMemoryMmap;
|
||||
use crate::cpu;
|
||||
use crate::cpu::CpuManager;
|
||||
use crate::igvm::loader::Loader;
|
||||
use crate::igvm::{BootPageAcceptance, HV_PAGE_SIZE, IgvmLoadedInfo, StartupMemoryType};
|
||||
use crate::igvm::{BootPageAcceptance, HV_PAGE_SIZE, IgvmLoadedInfo, StartupMemoryType, loader};
|
||||
use crate::memory_manager::{Error as MemoryManagerError, MemoryManager};
|
||||
#[cfg(all(feature = "kvm", feature = "sev_snp", feature = "fw_cfg"))]
|
||||
use crate::sev::{MeasuredBootInfo, SEV_HASH_BLOCK_ADDRESS, SEV_HASH_BLOCK_SIZE};
|
||||
@@ -77,9 +85,9 @@ pub struct SnpCpuidInfo {
|
||||
#[derive(Debug, Error)]
|
||||
pub enum Error {
|
||||
#[error("command line is not a valid C string")]
|
||||
InvalidCommandLine(#[source] std::ffi::NulError),
|
||||
InvalidCommandLine(#[source] ffi::NulError),
|
||||
#[error("failed to read igvm file")]
|
||||
Igvm(#[source] std::io::Error),
|
||||
Igvm(#[source] io::Error),
|
||||
#[error("invalid igvm file")]
|
||||
InvalidIgvmFile(#[source] igvm::Error),
|
||||
#[error("multiple SNP ID blocks in IGVM file")]
|
||||
@@ -87,7 +95,7 @@ pub enum Error {
|
||||
#[error("invalid guest memory map")]
|
||||
InvalidGuestMemmap(#[source] arch::Error),
|
||||
#[error("loader error")]
|
||||
Loader(#[source] crate::igvm::loader::Error),
|
||||
Loader(#[source] loader::Error),
|
||||
#[error("parameter too large for parameter area")]
|
||||
ParameterTooLarge,
|
||||
#[error("Error importing isolated pages")]
|
||||
@@ -101,10 +109,10 @@ pub enum Error {
|
||||
#[error("IGVM file not provided")]
|
||||
MissingIgvm,
|
||||
#[error("Error applying VMSA to vCPU registers: {0}")]
|
||||
SetVmsa(#[source] crate::cpu::Error),
|
||||
SetVmsa(#[source] cpu::Error),
|
||||
#[cfg(all(feature = "kvm", feature = "sev_snp", feature = "fw_cfg"))]
|
||||
#[error("Error building SEV-SNP measured boot hash block")]
|
||||
MeasuredBoot(#[source] vmm_sys_util::errno::Error),
|
||||
MeasuredBoot(#[source] errno::Error),
|
||||
#[cfg(all(feature = "kvm", feature = "sev_snp", feature = "fw_cfg"))]
|
||||
#[error(
|
||||
"igvmfile inserts unmeasured parameter area [0x{region_start:x}, 0x{region_end:x}) over SEV-SNP kernel hashes region [0x{hash_start:x}, 0x{hash_end:x})"
|
||||
@@ -441,7 +449,7 @@ pub fn load_igvm(
|
||||
let mut new_cp = SnpCpuidInfo::new_zeroed();
|
||||
|
||||
let entries = cpu_manager.lock().unwrap().common_cpuid();
|
||||
let cp_count = std::cmp::min(SNP_CPUID_LIMIT as usize, entries.len());
|
||||
let cp_count = cmp::min(SNP_CPUID_LIMIT as usize, entries.len());
|
||||
// TODO: Filter cpuid rather than truncate
|
||||
for (i, entry) in entries.iter().enumerate().take(cp_count) {
|
||||
new_cp.entries[i].eax_in = entry.function;
|
||||
@@ -857,7 +865,7 @@ pub fn load_igvm(
|
||||
// https://elixir.bootlin.com/linux/v6.11/source/arch/x86/kvm/svm/sev.c#L2322
|
||||
let mut updated_cp = SnpCpuidInfo::new_zeroed();
|
||||
let _ = guest_memory.read(updated_cp.as_mut_bytes(), GuestAddress(group[0].gpa));
|
||||
for (set, got) in std::iter::zip(new_cp.entries.iter(), updated_cp.entries.iter()) {
|
||||
for (set, got) in iter::zip(new_cp.entries.iter(), updated_cp.entries.iter()) {
|
||||
if set != got {
|
||||
error!("Set cpuid fn: {set:#x?}, but firmware expects: {got:#x?}");
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
|
||||
pub mod igvm_loader;
|
||||
mod loader;
|
||||
use std::fs;
|
||||
use std::path::Path;
|
||||
|
||||
use igvm::snp_defs::SevVmsa;
|
||||
@@ -35,7 +36,7 @@ use igvm_defs::IGVM_VHS_SNP_ID_BLOCK;
|
||||
use zerocopy::FromZeros;
|
||||
|
||||
pub fn parse_igvm(igvm_path: &Path) -> Result<IgvmFile, igvm_loader::Error> {
|
||||
let file_contents = std::fs::read(igvm_path).map_err(igvm_loader::Error::Igvm)?;
|
||||
let file_contents = fs::read(igvm_path).map_err(igvm_loader::Error::Igvm)?;
|
||||
IgvmFile::new_from_binary(&file_contents, Some(IsolationType::Snp))
|
||||
.map_err(igvm_loader::Error::InvalidIgvmFile)
|
||||
}
|
||||
|
||||
@@ -5,11 +5,13 @@
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io;
|
||||
use std::mem::replace;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
use devices::interrupt_controller::InterruptController;
|
||||
use hypervisor::IrqRoutingEntry;
|
||||
use vm_allocator::SystemAllocator;
|
||||
use vm_device::interrupt;
|
||||
use vm_device::interrupt::{
|
||||
InterruptIndex, InterruptManager, InterruptSourceConfig, InterruptSourceGroup,
|
||||
LegacyIrqGroupConfig, MsiIrqGroupConfig,
|
||||
@@ -17,7 +19,7 @@ use vm_device::interrupt::{
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
/// Reuse std::io::Result to simplify interoperability among crates.
|
||||
type Result<T> = std::io::Result<T>;
|
||||
type Result<T> = io::Result<T>;
|
||||
|
||||
/// Per-interrupt routing state for an MSI/MSI-X vector.
|
||||
///
|
||||
@@ -125,7 +127,7 @@ impl InterruptRoute {
|
||||
}
|
||||
|
||||
fn set_notifier(&mut self, eventfd: Option<EventFd>, vm: &dyn hypervisor::Vm) -> Result<()> {
|
||||
let old_irqfd = core::mem::replace(&mut self.irq_fd, eventfd);
|
||||
let old_irqfd = replace(&mut self.irq_fd, eventfd);
|
||||
if self.registered {
|
||||
// A registered route must have a GSI allocated, since enable()
|
||||
// only sets registered=true after using a valid GSI.
|
||||
@@ -434,7 +436,7 @@ impl InterruptManager for MsiInterruptManager {
|
||||
fn create_group_mut(
|
||||
&self,
|
||||
config: Self::GroupConfig,
|
||||
) -> vm_device::interrupt::Result<Arc<Mutex<dyn InterruptSourceGroup>>> {
|
||||
) -> interrupt::Result<Arc<Mutex<dyn InterruptSourceGroup>>> {
|
||||
let r = self.create_group_raw(config)?;
|
||||
Ok(Arc::new(Mutex::new(r)))
|
||||
}
|
||||
|
||||
@@ -3,9 +3,6 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
//
|
||||
|
||||
// TODO: Trim qualified paths in this crate, then drop this expectation.
|
||||
#![expect(clippy::absolute_paths)]
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::fs::File;
|
||||
use std::io::{Read, Write, stdout};
|
||||
@@ -13,10 +10,12 @@ use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||
use std::panic::AssertUnwindSafe;
|
||||
#[cfg(feature = "guest_debug")]
|
||||
use std::path::PathBuf;
|
||||
#[cfg(feature = "guest_debug")]
|
||||
use std::sync::mpsc;
|
||||
use std::sync::mpsc::{Receiver, RecvError, SendError, Sender, channel};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::{Duration, Instant};
|
||||
use std::{io, mem, result, thread};
|
||||
use std::{any, io, mem, panic, path, process, result, thread};
|
||||
|
||||
use anyhow::{Context, anyhow};
|
||||
#[cfg(feature = "dbus_api")]
|
||||
@@ -26,6 +25,8 @@ use api::http::HttpApiHandle;
|
||||
use arch::x86_64::MAX_SUPPORTED_CPUS_LEGACY;
|
||||
use console_devices::{ConsoleInfo, pre_create_console_devices};
|
||||
use event_monitor::event;
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
use hypervisor::arch::x86;
|
||||
use landlock::LandlockError;
|
||||
use libc::{EFD_NONBLOCK, SIGINT, SIGTERM, TCSANOW, tcsetattr, termios};
|
||||
use log::{debug, error, info, trace, warn};
|
||||
@@ -202,7 +203,7 @@ pub enum Error {
|
||||
|
||||
/// The API server socket is already in use by another running instance
|
||||
#[error("API socket {0:?} is already in use by another running instance")]
|
||||
ApiSocketInUse(std::path::PathBuf),
|
||||
ApiSocketInUse(path::PathBuf),
|
||||
|
||||
#[cfg(feature = "guest_debug")]
|
||||
#[error("Failed to start the GDB thread")]
|
||||
@@ -222,7 +223,7 @@ pub enum Error {
|
||||
SignalHandlerSpawn(#[source] io::Error),
|
||||
|
||||
#[error("Failed to join on threads: {0:?}")]
|
||||
ThreadCleanup(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
|
||||
ThreadCleanup(Box<dyn any::Any + Send>),
|
||||
|
||||
/// Cannot create Landlock object
|
||||
#[error("Error creating landlock object")]
|
||||
@@ -347,7 +348,7 @@ pub struct PciDeviceInfo {
|
||||
}
|
||||
|
||||
impl Serialize for PciDeviceInfo {
|
||||
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
|
||||
fn serialize<S>(&self, serializer: S) -> result::Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
@@ -423,7 +424,7 @@ pub fn start_event_monitor_thread(
|
||||
})?;
|
||||
}
|
||||
|
||||
std::panic::catch_unwind(AssertUnwindSafe(move || {
|
||||
panic::catch_unwind(AssertUnwindSafe(move || {
|
||||
while let Ok(event) = monitor.rx.recv() {
|
||||
let event = Arc::new(event);
|
||||
|
||||
@@ -469,7 +470,7 @@ pub fn start_vmm_thread(
|
||||
#[cfg(feature = "guest_debug")]
|
||||
let gdb_hw_breakpoints = hypervisor.get_guest_debug_hw_bps();
|
||||
#[cfg(feature = "guest_debug")]
|
||||
let (gdb_sender, gdb_receiver) = std::sync::mpsc::channel();
|
||||
let (gdb_sender, gdb_receiver) = mpsc::channel();
|
||||
#[cfg(feature = "guest_debug")]
|
||||
let gdb_debug_event = debug_event.try_clone().map_err(Error::EventFdClone)?;
|
||||
#[cfg(feature = "guest_debug")]
|
||||
@@ -593,7 +594,7 @@ where
|
||||
pub struct VmMigrationConfig {
|
||||
vm_config: Arc<Mutex<VmConfig>>,
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
common_cpuid: Vec<hypervisor::arch::x86::CpuIdEntry>,
|
||||
common_cpuid: Vec<x86::CpuIdEntry>,
|
||||
memory_manager_data: MemoryManagerSnapshotData,
|
||||
}
|
||||
|
||||
@@ -780,7 +781,7 @@ impl Vmm {
|
||||
warn!("Failed to lock original termios");
|
||||
}
|
||||
|
||||
std::process::exit(1);
|
||||
process::exit(1);
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
@@ -826,7 +827,7 @@ impl Vmm {
|
||||
}
|
||||
}
|
||||
|
||||
std::panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
Vmm::signal_handler(signals, original_termios_opt.as_ref(), &exit_evt);
|
||||
}))
|
||||
.map_err(|_| {
|
||||
@@ -918,7 +919,7 @@ impl Vmm {
|
||||
/// Try to receive a file descriptor from a socket. Returns the slot number and the file descriptor.
|
||||
fn vm_receive_memory_fd(
|
||||
socket: &mut SocketStream,
|
||||
) -> std::result::Result<(u32, File), MigratableError> {
|
||||
) -> result::Result<(u32, File), MigratableError> {
|
||||
if let SocketStream::Unix(unix_socket) = socket {
|
||||
let mut buf = [0u8; 4];
|
||||
let (_, file) = unix_socket.recv_with_fd(&mut buf).map_err(|e| {
|
||||
@@ -945,7 +946,7 @@ impl Vmm {
|
||||
state: ReceiveMigrationState,
|
||||
req: &Request,
|
||||
receive_data_migration: &VmReceiveMigrationData,
|
||||
) -> std::result::Result<ReceiveMigrationState, MigratableError> {
|
||||
) -> result::Result<ReceiveMigrationState, MigratableError> {
|
||||
use ReceiveMigrationState::*;
|
||||
|
||||
let invalid_command = |state: &str, cmd: Command| {
|
||||
@@ -958,7 +959,7 @@ impl Vmm {
|
||||
let mut configure_vm =
|
||||
|socket: &mut SocketStream,
|
||||
memory_files: HashMap<u32, File>|
|
||||
-> std::result::Result<ReceiveMigrationConfiguredData, MigratableError> {
|
||||
-> result::Result<ReceiveMigrationConfiguredData, MigratableError> {
|
||||
let shared_backing = !memory_files.is_empty();
|
||||
let memory_manager = self.vm_receive_config(req, socket, memory_files, mode)?;
|
||||
let guest_memory = memory_manager.lock().unwrap().guest_memory();
|
||||
@@ -982,7 +983,7 @@ impl Vmm {
|
||||
|
||||
let recv_memory_fd = |socket: &mut SocketStream,
|
||||
mut memory_files: Vec<(u32, File)>|
|
||||
-> std::result::Result<Vec<(u32, File)>, MigratableError> {
|
||||
-> result::Result<Vec<(u32, File)>, MigratableError> {
|
||||
let (slot, file) = Self::vm_receive_memory_fd(socket)?;
|
||||
|
||||
memory_files.push((slot, file));
|
||||
@@ -1083,7 +1084,7 @@ impl Vmm {
|
||||
socket: &mut SocketStream,
|
||||
mut config_data: ReceiveMigrationConfiguredData,
|
||||
receive_data_migration: &VmReceiveMigrationData,
|
||||
) -> std::result::Result<ReceiveMigrationState, MigratableError> {
|
||||
) -> result::Result<ReceiveMigrationState, MigratableError> {
|
||||
let state_receive_begin = Instant::now();
|
||||
|
||||
// Serve faults before restore so accesses during restore resolve on demand.
|
||||
@@ -1136,7 +1137,7 @@ impl Vmm {
|
||||
socket: &mut T,
|
||||
existing_memory_files: HashMap<u32, File>,
|
||||
mode: MigrationMode,
|
||||
) -> std::result::Result<Arc<Mutex<MemoryManager>>, MigratableError>
|
||||
) -> result::Result<Arc<Mutex<MemoryManager>>, MigratableError>
|
||||
where
|
||||
T: Read,
|
||||
{
|
||||
@@ -1243,7 +1244,7 @@ impl Vmm {
|
||||
req: &Request,
|
||||
socket: &mut T,
|
||||
mm: Arc<Mutex<MemoryManager>>,
|
||||
) -> std::result::Result<
|
||||
) -> result::Result<
|
||||
(
|
||||
Duration, /* state receive + deserialize */
|
||||
Duration, /* restoring */
|
||||
@@ -1836,7 +1837,7 @@ impl Vmm {
|
||||
fn vm_check_cpuid_compatibility(
|
||||
&self,
|
||||
src_vm_config: &Arc<Mutex<VmConfig>>,
|
||||
src_vm_cpuid: &[hypervisor::arch::x86::CpuIdEntry],
|
||||
src_vm_cpuid: &[x86::CpuIdEntry],
|
||||
) -> result::Result<(), MigratableError> {
|
||||
#[cfg(feature = "tdx")]
|
||||
if src_vm_config.lock().unwrap().is_tdx_enabled() {
|
||||
@@ -1889,7 +1890,7 @@ impl Vmm {
|
||||
vm_config: Arc<Mutex<VmConfig>>,
|
||||
prefault: bool,
|
||||
memory_restore_mode: MemoryRestoreMode,
|
||||
) -> std::result::Result<(), VmError> {
|
||||
) -> result::Result<(), VmError> {
|
||||
match &self.vm {
|
||||
VmOwnership::Owned(_) => Err(VmError::VmAlreadyCreated),
|
||||
VmOwnership::Migration { .. } => Err(VmError::VmMigrating),
|
||||
@@ -2509,7 +2510,7 @@ impl RequestHandler for Vmm {
|
||||
VmmPingResponse {
|
||||
build_version,
|
||||
version,
|
||||
pid: std::process::id() as i64,
|
||||
pid: process::id() as i64,
|
||||
features: feature_list(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use std::collections::BTreeMap;
|
||||
use std::collections::HashMap;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{self, Seek, SeekFrom};
|
||||
use std::mem::{MaybeUninit, zeroed};
|
||||
use std::num::NonZeroUsize;
|
||||
use std::ops::{BitAnd, Not, Sub};
|
||||
use std::os::fd::{AsFd, OwnedFd};
|
||||
@@ -16,11 +17,11 @@ use std::path::{Path, PathBuf};
|
||||
use std::sync::atomic::{AtomicU32, Ordering};
|
||||
use std::sync::mpsc::{self, Receiver, SyncSender};
|
||||
use std::sync::{Arc, Barrier, Mutex};
|
||||
use std::{ffi, result, thread};
|
||||
use std::{cmp, ffi, panic, result, thread, time};
|
||||
|
||||
use acpi_tables::{Aml, aml};
|
||||
use anyhow::anyhow;
|
||||
use arch::RegionType;
|
||||
use arch::{RegionType, layout};
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use devices::ioapic;
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||
@@ -31,6 +32,7 @@ use serde::{Deserialize, Serialize};
|
||||
use thiserror::Error;
|
||||
use tracer::trace_scoped;
|
||||
use virtio_devices::BlocksState;
|
||||
use virtio_devices::mem::Error as VirtioMemError;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use vm_allocator::GsiApic;
|
||||
use vm_allocator::{AddressAllocator, MemorySlotAllocator, SystemAllocator};
|
||||
@@ -62,7 +64,7 @@ use crate::uffd::{
|
||||
UffdRange,
|
||||
};
|
||||
use crate::vm_config::{HotplugMethod, MemoryConfig, MemoryZoneConfig};
|
||||
use crate::{GuestMemoryMmap, GuestRegionMmap, MEMORY_MANAGER_SNAPSHOT_ID};
|
||||
use crate::{GuestMemoryMmap, GuestRegionMmap, MEMORY_MANAGER_SNAPSHOT_ID, userfaultfd};
|
||||
|
||||
struct UffdHandler {
|
||||
stop_event: EventFd,
|
||||
@@ -297,7 +299,7 @@ pub enum Error {
|
||||
|
||||
/// Failed to virtio-mem resize
|
||||
#[error("Failed to virtio-mem resize")]
|
||||
VirtioMemResizeFail(#[source] virtio_devices::mem::Error),
|
||||
VirtioMemResizeFail(#[source] VirtioMemError),
|
||||
|
||||
/// Cannot restore VM
|
||||
#[error("Cannot restore VM")]
|
||||
@@ -314,7 +316,7 @@ pub enum Error {
|
||||
/// Failed creating a new MmapRegion instance.
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
#[error("Failed creating a new MmapRegion instance")]
|
||||
NewMmapRegion(#[source] vm_memory::mmap::MmapRegionError),
|
||||
NewMmapRegion(#[source] MmapRegionError),
|
||||
|
||||
/// No memory zones found.
|
||||
#[error("No memory zones found")]
|
||||
@@ -448,14 +450,12 @@ fn mmio_address_space_size(phys_bits: u8) -> u64 {
|
||||
// See: https://github.com/torvalds/linux/blob/v6.3/fs/hugetlbfs/inode.c#L1169
|
||||
fn statfs_get_bsize(path: &str) -> Result<u64, Error> {
|
||||
let path = ffi::CString::new(path).map_err(Error::InvalidMemoryPath)?;
|
||||
let mut buf = std::mem::MaybeUninit::<libc::statfs>::uninit();
|
||||
let mut buf = MaybeUninit::<libc::statfs>::uninit();
|
||||
|
||||
// SAFETY: FFI call with a valid path and buffer
|
||||
let ret = unsafe { libc::statfs(path.as_ptr(), buf.as_mut_ptr()) };
|
||||
if ret != 0 {
|
||||
return Err(Error::GetFileSystemBlockSize(
|
||||
std::io::Error::last_os_error(),
|
||||
));
|
||||
return Err(Error::GetFileSystemBlockSize(io::Error::last_os_error()));
|
||||
}
|
||||
|
||||
// SAFETY: `buf` is valid at this point
|
||||
@@ -494,7 +494,7 @@ fn memory_zone_get_align_size(zone: &MemoryZoneConfig) -> Result<u64, Error> {
|
||||
pathbuf.to_str().ok_or(Error::InvalidMemoryParameters)
|
||||
})?;
|
||||
|
||||
let align_size = std::cmp::max(page_size, statfs_get_bsize(path)?);
|
||||
let align_size = cmp::max(page_size, statfs_get_bsize(path)?);
|
||||
|
||||
Ok(align_size)
|
||||
}
|
||||
@@ -1009,8 +1009,8 @@ impl MemoryManager {
|
||||
}
|
||||
})?;
|
||||
|
||||
if ioctls & crate::userfaultfd::UFFD_API_RANGE_IOCTLS_BASIC
|
||||
!= crate::userfaultfd::UFFD_API_RANGE_IOCTLS_BASIC
|
||||
if ioctls & userfaultfd::UFFD_API_RANGE_IOCTLS_BASIC
|
||||
!= userfaultfd::UFFD_API_RANGE_IOCTLS_BASIC
|
||||
{
|
||||
return Err(UffdError::MissingIoctlSupport {
|
||||
addr: host_addr,
|
||||
@@ -1059,7 +1059,7 @@ impl MemoryManager {
|
||||
let handle = thread::Builder::new()
|
||||
.name("uffd-handler".to_string())
|
||||
.spawn(move || {
|
||||
std::panic::catch_unwind(std::panic::AssertUnwindSafe(move || {
|
||||
panic::catch_unwind(panic::AssertUnwindSafe(move || {
|
||||
let result = Self::uffd_handler_loop(
|
||||
uffd_fd,
|
||||
thread_stop_event,
|
||||
@@ -1106,10 +1106,10 @@ impl MemoryManager {
|
||||
fn required_uffd_features(&self) -> u64 {
|
||||
let mut features = 0u64;
|
||||
if self.memory_zones.values().any(|z| z.shared || !z.hugepages) {
|
||||
features |= crate::userfaultfd::UFFD_FEATURE_MISSING_SHMEM;
|
||||
features |= userfaultfd::UFFD_FEATURE_MISSING_SHMEM;
|
||||
}
|
||||
if self.memory_zones.values().any(|z| z.hugepages) {
|
||||
features |= crate::userfaultfd::UFFD_FEATURE_MISSING_HUGETLBFS;
|
||||
features |= userfaultfd::UFFD_FEATURE_MISSING_HUGETLBFS;
|
||||
}
|
||||
features
|
||||
}
|
||||
@@ -1166,7 +1166,7 @@ impl MemoryManager {
|
||||
// means prefault was given up due to an error (natural completion
|
||||
// returns from the function instead).
|
||||
let mut prefault_cursor: Option<(usize, u64)> = (!ranges.is_empty()).then_some((0, 0));
|
||||
let prefault_start = std::time::Instant::now();
|
||||
let prefault_start = time::Instant::now();
|
||||
|
||||
const EVENT_STOP: u64 = 0;
|
||||
const EVENT_UFFD: u64 = 1;
|
||||
@@ -1230,13 +1230,13 @@ impl MemoryManager {
|
||||
|
||||
if got_uffd_data {
|
||||
// SAFETY: UffdMsg is a plain repr(C) struct, safe to zero-init.
|
||||
let mut msg: uffd::UffdMsg = unsafe { std::mem::zeroed() };
|
||||
let mut msg: uffd::UffdMsg = unsafe { zeroed() };
|
||||
// SAFETY: reading a uffd_msg-sized struct from the valid uffd fd.
|
||||
let n = unsafe {
|
||||
libc::read(
|
||||
uffd_raw_fd,
|
||||
(&raw mut msg).cast(),
|
||||
std::mem::size_of::<uffd::UffdMsg>(),
|
||||
size_of::<uffd::UffdMsg>(),
|
||||
)
|
||||
};
|
||||
if n < 0 {
|
||||
@@ -1250,14 +1250,14 @@ impl MemoryManager {
|
||||
info!("UFFD handler: EOF on fd, exiting");
|
||||
return Ok(());
|
||||
}
|
||||
if n as usize != std::mem::size_of::<uffd::UffdMsg>() {
|
||||
if n as usize != size_of::<uffd::UffdMsg>() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::UnexpectedEof,
|
||||
"Short read from userfaultfd",
|
||||
));
|
||||
}
|
||||
|
||||
if msg.event != crate::userfaultfd::UFFD_EVENT_PAGEFAULT {
|
||||
if msg.event != userfaultfd::UFFD_EVENT_PAGEFAULT {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1566,11 +1566,11 @@ impl MemoryManager {
|
||||
// 4 MiB memory is mapped to simulate the flash.
|
||||
let uefi_mem_slot = self.allocate_memory_slot();
|
||||
let uefi_region = GuestRegionMmap::new(
|
||||
MmapRegion::new(arch::layout::UEFI_SIZE as usize).unwrap(),
|
||||
arch::layout::UEFI_START,
|
||||
MmapRegion::new(layout::UEFI_SIZE as usize).unwrap(),
|
||||
layout::UEFI_START,
|
||||
)
|
||||
.unwrap();
|
||||
const _: () = assert!(core::mem::size_of::<usize>() == core::mem::size_of::<u64>());
|
||||
const _: () = assert!(size_of::<usize>() == size_of::<u64>());
|
||||
|
||||
// SAFETY: guaranteed by GuestRegionMmap
|
||||
unsafe {
|
||||
@@ -2092,8 +2092,7 @@ impl MemoryManager {
|
||||
// over mmap_sem between thread stack allocation and page faulting.
|
||||
barrier.wait();
|
||||
let pages = pages_per_thread + if i < remainder { 1 } else { 0 };
|
||||
let offset =
|
||||
page_size * ((i * pages_per_thread) + std::cmp::min(i, remainder));
|
||||
let offset = page_size * ((i * pages_per_thread) + cmp::min(i, remainder));
|
||||
// SAFETY: FFI call with correct arguments
|
||||
let ret = unsafe {
|
||||
let addr = r.as_ptr().add(offset);
|
||||
@@ -2186,7 +2185,7 @@ impl MemoryManager {
|
||||
.map_or(Ok("/dev/hugepages"), |pathbuf| {
|
||||
pathbuf.to_str().ok_or(Error::InvalidMemoryParameters)
|
||||
})?;
|
||||
let align_size = std::cmp::max(page_size, statfs_get_bsize(path)?);
|
||||
let align_size = cmp::max(page_size, statfs_get_bsize(path)?);
|
||||
Ok(align_size)
|
||||
}
|
||||
}
|
||||
@@ -2199,17 +2198,14 @@ impl MemoryManager {
|
||||
// SAFETY: FFI call. Trivially safe.
|
||||
let procs = unsafe { libc::sysconf(_SC_NPROCESSORS_ONLN) };
|
||||
if procs > 0 {
|
||||
n = std::cmp::min(procs as usize, MAX_PREFAULT_THREAD_COUNT);
|
||||
n = cmp::min(procs as usize, MAX_PREFAULT_THREAD_COUNT);
|
||||
}
|
||||
|
||||
// Do not create more threads than pages being allocated.
|
||||
n = std::cmp::min(n, num_pages);
|
||||
n = cmp::min(n, num_pages);
|
||||
|
||||
// Do not create threads to allocate less than 64 MiB of memory.
|
||||
n = std::cmp::min(
|
||||
n,
|
||||
std::cmp::max(1, page_size * num_pages / (64 * (1 << 26))),
|
||||
);
|
||||
n = cmp::min(n, cmp::max(1, page_size * num_pages / (64 * (1 << 26))));
|
||||
|
||||
n
|
||||
}
|
||||
@@ -2245,8 +2241,8 @@ impl MemoryManager {
|
||||
.ok_or(Error::GuestAddressOverFlow)?;
|
||||
|
||||
#[cfg(not(target_arch = "riscv64"))]
|
||||
if mem_end < arch::layout::MEM_32BIT_RESERVED_START {
|
||||
return Ok(arch::layout::RAM_64BIT_START);
|
||||
if mem_end < layout::MEM_32BIT_RESERVED_START {
|
||||
return Ok(layout::RAM_64BIT_START);
|
||||
}
|
||||
|
||||
Ok(start_addr)
|
||||
@@ -2614,7 +2610,7 @@ impl MemoryManager {
|
||||
}
|
||||
|
||||
pub fn is_hardlink(f: &File) -> bool {
|
||||
let mut stat = std::mem::MaybeUninit::<libc::stat>::uninit();
|
||||
let mut stat = MaybeUninit::<libc::stat>::uninit();
|
||||
// SAFETY: FFI call with correct arguments
|
||||
let ret = unsafe { libc::fstat(f.as_raw_fd(), stat.as_mut_ptr()) };
|
||||
if ret != 0 {
|
||||
@@ -2650,7 +2646,7 @@ impl MemoryManager {
|
||||
pub fn memory_range_table(
|
||||
&self,
|
||||
snapshot: bool,
|
||||
) -> std::result::Result<MemoryRangeTable, MigratableError> {
|
||||
) -> result::Result<MemoryRangeTable, MigratableError> {
|
||||
let mut table = MemoryRangeTable::default();
|
||||
|
||||
for memory_zone in self.memory_zones.values() {
|
||||
@@ -2755,7 +2751,7 @@ impl MemoryManager {
|
||||
pub fn coredump_iterate_save_mem(
|
||||
&mut self,
|
||||
dump_state: &DumpState,
|
||||
) -> std::result::Result<(), GuestDebuggableError> {
|
||||
) -> result::Result<(), GuestDebuggableError> {
|
||||
let snapshot_memory_ranges = self
|
||||
.memory_range_table(false)
|
||||
.map_err(|e| GuestDebuggableError::Coredump(e.into()))?;
|
||||
@@ -3283,7 +3279,7 @@ impl Migratable for MemoryManager {
|
||||
// Also, reset the dirty bitmap logged by the vmm.
|
||||
// Just before we do a bulk copy we want to start/clear the dirty log so that
|
||||
// pages touched during our bulk copy are tracked.
|
||||
fn start_dirty_log(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
fn start_dirty_log(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.vm.start_dirty_log().map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!("Error starting VM dirty log {e}"))
|
||||
})?;
|
||||
@@ -3295,7 +3291,7 @@ impl Migratable for MemoryManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn stop_dirty_log(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
fn stop_dirty_log(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.vm.stop_dirty_log().map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!("Error stopping VM dirty log {e}"))
|
||||
})?;
|
||||
@@ -3305,7 +3301,7 @@ impl Migratable for MemoryManager {
|
||||
|
||||
// Generate a table for the pages that are dirty. The dirty pages are collapsed
|
||||
// together in the table if they are contiguous.
|
||||
fn dirty_log(&mut self) -> std::result::Result<MemoryRangeTable, MigratableError> {
|
||||
fn dirty_log(&mut self) -> result::Result<MemoryRangeTable, MigratableError> {
|
||||
let mut table = MemoryRangeTable::default();
|
||||
for r in &self.guest_ram_mappings {
|
||||
let vm_dirty_bitmap = self.vm.get_dirty_log(r.slot, r.gpa, r.size).map_err(|e| {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::path::PathBuf;
|
||||
use std::result;
|
||||
|
||||
use anyhow::anyhow;
|
||||
use vm_migration::{MigratableError, Snapshot};
|
||||
@@ -20,7 +21,7 @@ pub(crate) mod worker;
|
||||
pub const SNAPSHOT_STATE_FILE: &str = "state.json";
|
||||
pub const SNAPSHOT_CONFIG_FILE: &str = "config.json";
|
||||
|
||||
pub fn url_to_path(url: &str) -> std::result::Result<PathBuf, MigratableError> {
|
||||
pub fn url_to_path(url: &str) -> result::Result<PathBuf, MigratableError> {
|
||||
let path: PathBuf = url
|
||||
.strip_prefix("file://")
|
||||
.ok_or_else(|| {
|
||||
@@ -38,7 +39,7 @@ pub fn url_to_path(url: &str) -> std::result::Result<PathBuf, MigratableError> {
|
||||
}
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
pub fn url_to_file(url: &str) -> std::result::Result<PathBuf, GuestDebuggableError> {
|
||||
pub fn url_to_file(url: &str) -> result::Result<PathBuf, GuestDebuggableError> {
|
||||
let file: PathBuf = url
|
||||
.strip_prefix("file://")
|
||||
.ok_or_else(|| {
|
||||
@@ -49,7 +50,7 @@ pub fn url_to_file(url: &str) -> std::result::Result<PathBuf, GuestDebuggableErr
|
||||
Ok(file)
|
||||
}
|
||||
|
||||
pub fn recv_vm_config(source_url: &str) -> std::result::Result<VmConfig, MigratableError> {
|
||||
pub fn recv_vm_config(source_url: &str) -> result::Result<VmConfig, MigratableError> {
|
||||
let mut vm_config_path = url_to_path(source_url)?;
|
||||
|
||||
vm_config_path.push(SNAPSHOT_CONFIG_FILE);
|
||||
@@ -65,7 +66,7 @@ pub fn recv_vm_config(source_url: &str) -> std::result::Result<VmConfig, Migrata
|
||||
serde_json::from_slice(&bytes).map_err(|e| MigratableError::MigrateReceive(e.into()))
|
||||
}
|
||||
|
||||
pub fn recv_vm_state(source_url: &str) -> std::result::Result<Snapshot, MigratableError> {
|
||||
pub fn recv_vm_state(source_url: &str) -> result::Result<Snapshot, MigratableError> {
|
||||
let mut vm_state_path = url_to_path(source_url)?;
|
||||
|
||||
vm_state_path.push(SNAPSHOT_STATE_FILE);
|
||||
@@ -81,7 +82,7 @@ pub fn recv_vm_state(source_url: &str) -> std::result::Result<Snapshot, Migratab
|
||||
serde_json::from_slice(&bytes).map_err(|e| MigratableError::MigrateReceive(e.into()))
|
||||
}
|
||||
|
||||
pub fn get_vm_snapshot(snapshot: &Snapshot) -> std::result::Result<VmSnapshot, MigratableError> {
|
||||
pub fn get_vm_snapshot(snapshot: &Snapshot) -> result::Result<VmSnapshot, MigratableError> {
|
||||
if let Some(snapshot_data) = snapshot.snapshot_data.as_ref() {
|
||||
return snapshot_data.to_state();
|
||||
}
|
||||
|
||||
@@ -12,12 +12,12 @@
|
||||
//! (rendezvous-channel). If spawning fails, the VM is returned to the caller in
|
||||
//! [`MigrationWorkerSpawnError`].
|
||||
|
||||
use std::fmt::{Debug, Formatter};
|
||||
use std::fmt::{self, Debug, Formatter};
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
use std::sync::Arc;
|
||||
use std::sync::mpsc::Receiver;
|
||||
use std::thread;
|
||||
use std::sync::mpsc::{self, Receiver};
|
||||
use std::thread::JoinHandle;
|
||||
use std::{io, thread};
|
||||
|
||||
use event_monitor::event;
|
||||
use log::warn;
|
||||
@@ -32,12 +32,12 @@ use crate::vm::{Vm, VmState};
|
||||
#[derive(thiserror::Error)]
|
||||
#[error("Migration worker could not be spawned: {spawn_error}")]
|
||||
pub struct MigrationWorkerSpawnError {
|
||||
pub spawn_error: std::io::Error,
|
||||
pub spawn_error: io::Error,
|
||||
pub vm: Vm,
|
||||
}
|
||||
|
||||
impl Debug for MigrationWorkerSpawnError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("MigrationWorkerSpawnError")
|
||||
.field("spawn_error", &self.spawn_error)
|
||||
.field("vm", &"<VM>")
|
||||
@@ -121,7 +121,7 @@ impl MigrationWorker {
|
||||
initial_vm_state: VmState,
|
||||
seccomp_action: SeccompAction,
|
||||
) -> Result<MigrationWorkerHandle, MigrationWorkerSpawnError> {
|
||||
let (vm_sender, vm_receiver) = std::sync::mpsc::sync_channel(0);
|
||||
let (vm_sender, vm_receiver) = mpsc::sync_channel(0);
|
||||
let worker = MigrationWorker {
|
||||
vm_receiver,
|
||||
check_migration_evt,
|
||||
|
||||
@@ -554,6 +554,7 @@ impl Aml for PciSegment {
|
||||
|
||||
#[cfg(test)]
|
||||
mod unit_tests {
|
||||
use std::io;
|
||||
use std::result::Result;
|
||||
|
||||
use vm_memory::GuestAddress;
|
||||
@@ -570,7 +571,7 @@ mod unit_tests {
|
||||
_len: u64,
|
||||
_pci_dev: &mut dyn pci::PciDevice,
|
||||
_region_type: pci::PciBarRegionType,
|
||||
) -> Result<(), std::io::Error> {
|
||||
) -> Result<(), io::Error> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
use std::env::consts;
|
||||
|
||||
use hypervisor::HypervisorType;
|
||||
use libc::{
|
||||
BLKIOMIN, BLKIOOPT, BLKPBSZGET, BLKSSZGET, FIOCLEX, FIONBIO, SIOCGIFFLAGS, SIOCGIFHWADDR,
|
||||
@@ -1151,7 +1153,7 @@ pub fn get_seccomp_filter(
|
||||
.collect(),
|
||||
SeccompAction::Log,
|
||||
SeccompAction::Allow,
|
||||
std::env::consts::ARCH.try_into().unwrap(),
|
||||
consts::ARCH.try_into().unwrap(),
|
||||
)
|
||||
.and_then(|filter| filter.try_into())
|
||||
.map_err(Error::Backend),
|
||||
@@ -1162,7 +1164,7 @@ pub fn get_seccomp_filter(
|
||||
.collect(),
|
||||
SeccompAction::Trap,
|
||||
SeccompAction::Allow,
|
||||
std::env::consts::ARCH.try_into().unwrap(),
|
||||
consts::ARCH.try_into().unwrap(),
|
||||
)
|
||||
.and_then(|filter| filter.try_into())
|
||||
.map_err(Error::Backend),
|
||||
|
||||
@@ -13,7 +13,7 @@ use std::panic::AssertUnwindSafe;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::{io, result, thread};
|
||||
use std::{fs, io, panic, result, thread, time};
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use devices::legacy::Pl011;
|
||||
@@ -24,6 +24,7 @@ use log::{error, info, warn};
|
||||
use seccompiler::{SeccompAction, apply_filter};
|
||||
use serial_buffer::SerialBuffer;
|
||||
use thiserror::Error;
|
||||
use vmm_sys_util::errno;
|
||||
use vmm_sys_util::eventfd::EventFd;
|
||||
|
||||
use crate::console_devices::ConsoleTransport;
|
||||
@@ -45,7 +46,7 @@ pub enum Error {
|
||||
|
||||
/// Cannot queue input to the serial device.
|
||||
#[error("Error queuing input to the serial device")]
|
||||
QueueInput(#[source] vmm_sys_util::errno::Error),
|
||||
QueueInput(#[source] errno::Error),
|
||||
|
||||
/// Cannot flush output on the serial buffer.
|
||||
#[error("Error flushing serial device's output buffer")]
|
||||
@@ -199,7 +200,7 @@ impl SerialManager {
|
||||
// SAFETY: STDIN_FILENO is a valid fd
|
||||
let fd = unsafe { libc::dup(libc::STDIN_FILENO) };
|
||||
if fd == -1 {
|
||||
return Err(Error::DupFd(std::io::Error::last_os_error()));
|
||||
return Err(Error::DupFd(io::Error::last_os_error()));
|
||||
}
|
||||
// SAFETY: fd is valid and owned by us
|
||||
let stdin_clone = unsafe { File::from_raw_fd(fd) };
|
||||
@@ -211,7 +212,7 @@ impl SerialManager {
|
||||
};
|
||||
|
||||
if ret < 0 {
|
||||
return Err(Error::SetNonBlocking(std::io::Error::last_os_error()));
|
||||
return Err(Error::SetNonBlocking(io::Error::last_os_error()));
|
||||
}
|
||||
|
||||
transport = ConsoleTransport::Tty(Arc::new(stdin_clone));
|
||||
@@ -352,7 +353,7 @@ impl SerialManager {
|
||||
let thread = thread::Builder::new()
|
||||
.name("serial-manager".to_string())
|
||||
.spawn(move || {
|
||||
std::panic::catch_unwind(AssertUnwindSafe(move || {
|
||||
panic::catch_unwind(AssertUnwindSafe(move || {
|
||||
// Apply seccomp filter for serial manager thread.
|
||||
if !seccomp_filter.is_empty() {
|
||||
apply_filter(&seccomp_filter).map_err(Error::ApplySeccompFilter)?;
|
||||
@@ -503,7 +504,7 @@ impl SerialManager {
|
||||
// It's really important to sleep here as this will prevent
|
||||
// the current thread from consuming 100% of the CPU cycles
|
||||
// when waiting for someone to connect to the PTY.
|
||||
std::thread::sleep(std::time::Duration::from_millis(500));
|
||||
thread::sleep(time::Duration::from_millis(500));
|
||||
} else {
|
||||
// If the EPOLLHUP flag is not up on the associated event, we
|
||||
// can assume the other end of the PTY is connected and therefore
|
||||
@@ -538,7 +539,7 @@ impl Drop for SerialManager {
|
||||
handle.join().ok();
|
||||
}
|
||||
if let Some(socket_console) = self.socket_console.as_ref() {
|
||||
std::fs::remove_file(&socket_console.path)
|
||||
fs::remove_file(&socket_console.path)
|
||||
.map_err(Error::RemoveUnixSocket)
|
||||
.ok();
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ use std::ffi::CString;
|
||||
use std::fs::File;
|
||||
use std::io::{self, Cursor, Read, Seek, SeekFrom};
|
||||
use std::os::unix::fs::FileExt;
|
||||
use std::result;
|
||||
|
||||
use linux_loader::bootparam::boot_params;
|
||||
use sha2::{Digest, Sha256};
|
||||
@@ -16,7 +17,7 @@ use vm_memory::ByteValued;
|
||||
use vmm_sys_util::errno;
|
||||
use zerocopy::{Immutable, IntoBytes};
|
||||
|
||||
pub(crate) type Result<T> = std::result::Result<T, errno::Error>;
|
||||
pub(crate) type Result<T> = result::Result<T, errno::Error>;
|
||||
|
||||
// https://github.com/tianocore/edk2/blob/f98662c5e35b6ab60f46ee4350fa0e6eab0497cf/OvmfPkg/Include/Fdf/MemFd.fdf.inc#L89-L93
|
||||
pub const SEV_HASH_BLOCK_ADDRESS: u64 = 0x10c00;
|
||||
@@ -182,6 +183,7 @@ impl MeasuredBootInfo {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::cmp;
|
||||
use std::io::Write;
|
||||
|
||||
use super::*;
|
||||
@@ -196,7 +198,7 @@ mod tests {
|
||||
let effective_sects = if setup_sects == 0 { 4 } else { setup_sects };
|
||||
let setup_len = (usize::from(effective_sects) + 1) * 512;
|
||||
let header_size = size_of::<boot_params>();
|
||||
let file_len = std::cmp::max(setup_len, header_size) + kernel_payload.len();
|
||||
let file_len = cmp::max(setup_len, header_size) + kernel_payload.len();
|
||||
|
||||
let mut buf = vec![0u8; file_len];
|
||||
let bp = boot_params::from_mut_slice(&mut buf[..header_size]).unwrap();
|
||||
@@ -329,7 +331,7 @@ mod tests {
|
||||
let effective_sects = if setup_sects == 0 { 4 } else { setup_sects };
|
||||
let setup_len = (usize::from(effective_sects) + 1) * 512;
|
||||
let header_size = size_of::<boot_params>();
|
||||
let file_len = std::cmp::max(setup_len, header_size) + kernel_payload.len();
|
||||
let file_len = cmp::max(setup_len, header_size) + kernel_payload.len();
|
||||
|
||||
let mut buf = vec![0u8; file_len];
|
||||
let bp = boot_params::from_mut_slice(&mut buf[..header_size]).unwrap();
|
||||
|
||||
@@ -269,7 +269,7 @@ pub fn start_sigwinch_listener(seccomp_filter: BpfProgramRef, tty_sub: File) ->
|
||||
pub fn listen_for_sigwinch_on_tty(
|
||||
pty_sub: File,
|
||||
seccomp_action: &SeccompAction,
|
||||
) -> std::io::Result<File> {
|
||||
) -> io::Result<File> {
|
||||
let seccomp_filter = get_seccomp_filter(seccomp_action, Thread::PtyForeground, None).unwrap();
|
||||
|
||||
let console_resize_pipe = start_sigwinch_listener(&seccomp_filter, pty_sub)?;
|
||||
|
||||
@@ -154,26 +154,23 @@ mod unit_tests {
|
||||
use std::io::Write;
|
||||
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd};
|
||||
use std::os::unix::fs::FileExt;
|
||||
use std::{fs, io};
|
||||
|
||||
use super::{next_data_extent, write_region_sparse};
|
||||
|
||||
fn make_memfd(size: u64) -> std::fs::File {
|
||||
fn make_memfd(size: u64) -> fs::File {
|
||||
// SAFETY: memfd_create is a self-contained syscall; we own the
|
||||
// returned fd.
|
||||
let fd = unsafe { libc::syscall(libc::SYS_memfd_create, c"sparse-test".as_ptr(), 0u32) };
|
||||
assert!(fd >= 0, "memfd_create failed");
|
||||
// SAFETY: memfd_create returned a valid fd that we now own; wrap it
|
||||
// in File so it is closed on drop.
|
||||
let f = unsafe { std::fs::File::from_raw_fd(fd as i32) };
|
||||
let f = unsafe { fs::File::from_raw_fd(fd as i32) };
|
||||
f.set_len(size).unwrap();
|
||||
f
|
||||
}
|
||||
|
||||
fn collect_extents(
|
||||
fd: BorrowedFd<'_>,
|
||||
start: u64,
|
||||
end: u64,
|
||||
) -> std::io::Result<Vec<(u64, u64)>> {
|
||||
fn collect_extents(fd: BorrowedFd<'_>, start: u64, end: u64) -> io::Result<Vec<(u64, u64)>> {
|
||||
let mut out = Vec::new();
|
||||
let mut cursor = start;
|
||||
while let Some((off, len)) = next_data_extent(fd, cursor, end)? {
|
||||
@@ -190,7 +187,7 @@ mod unit_tests {
|
||||
/// not portable. `fallocate(PUNCH_HOLE)` is the explicit "deallocate
|
||||
/// these pages" syscall and is honored on every Linux filesystem we
|
||||
/// run tests on (tmpfs, ext4, xfs, btrfs).
|
||||
fn punch_hole(f: &std::fs::File, off: u64, len: u64) {
|
||||
fn punch_hole(f: &fs::File, off: u64, len: u64) {
|
||||
// SAFETY: FFI call; f is a valid open fd for the duration of the
|
||||
// call.
|
||||
let r = unsafe {
|
||||
@@ -205,7 +202,7 @@ mod unit_tests {
|
||||
r,
|
||||
0,
|
||||
"fallocate PUNCH_HOLE off={off} len={len}: {}",
|
||||
std::io::Error::last_os_error(),
|
||||
io::Error::last_os_error(),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -213,7 +210,7 @@ mod unit_tests {
|
||||
/// len, byte)` data extent, then punch every gap into a real hole.
|
||||
/// The resulting `SEEK_DATA`/`SEEK_HOLE` extents match `data` exactly,
|
||||
/// regardless of folio/THP allocation policy on the backing FS.
|
||||
fn sparse_layout(f: &std::fs::File, total: u64, data: &[(u64, u64, u8)]) {
|
||||
fn sparse_layout(f: &fs::File, total: u64, data: &[(u64, u64, u8)]) {
|
||||
f.set_len(total).unwrap();
|
||||
for &(off, len, byte) in data {
|
||||
f.write_all_at(&vec![byte; len as usize], off).unwrap();
|
||||
@@ -296,7 +293,7 @@ mod unit_tests {
|
||||
let used = write_region_sparse(&src, 0, &dst, 0, 4096 * 16).unwrap();
|
||||
assert!(used);
|
||||
|
||||
let buf = std::fs::read(tmp.path()).unwrap();
|
||||
let buf = fs::read(tmp.path()).unwrap();
|
||||
assert!(buf[..4096 * 3].iter().all(|&b| b == 0xFE));
|
||||
assert!(buf[4096 * 3..4096 * 5].iter().all(|&b| b == 0x42));
|
||||
assert!(buf[4096 * 5..].iter().all(|&b| b == 0xFE));
|
||||
@@ -316,7 +313,7 @@ mod unit_tests {
|
||||
let _ = write_region_sparse(&src_a, 0, &dst, 0, 4096 * 16).unwrap();
|
||||
let _ = write_region_sparse(&src_b, 0, &dst, 4096 * 16, 4096 * 16).unwrap();
|
||||
|
||||
let buf = std::fs::read(tmp.path()).unwrap();
|
||||
let buf = fs::read(tmp.path()).unwrap();
|
||||
assert!(buf[..4096].iter().all(|&b| b == 0));
|
||||
assert!(buf[4096..4096 * 3].iter().all(|&b| b == 0xAA));
|
||||
assert!(buf[4096 * 3..4096 * 16].iter().all(|&b| b == 0));
|
||||
@@ -337,7 +334,7 @@ mod unit_tests {
|
||||
let used = write_region_sparse(&src, 4096 * 16, &dst, 0, 4096 * 16).unwrap();
|
||||
assert!(used);
|
||||
|
||||
let buf = std::fs::read(tmp.path()).unwrap();
|
||||
let buf = fs::read(tmp.path()).unwrap();
|
||||
assert!(buf[..4096 * 4].iter().all(|&b| b == 0));
|
||||
assert!(buf[4096 * 4..4096 * 6].iter().all(|&b| b == 0x77));
|
||||
assert!(buf[4096 * 6..].iter().all(|&b| b == 0));
|
||||
@@ -387,7 +384,7 @@ mod unit_tests {
|
||||
}
|
||||
|
||||
// Verify content matches a dense read.
|
||||
let dense = std::fs::read(tmp.path()).unwrap();
|
||||
let dense = fs::read(tmp.path()).unwrap();
|
||||
assert_eq!(restored, dense);
|
||||
|
||||
// Verify the actual data landed in the right places.
|
||||
|
||||
186
vmm/src/vm.rs
186
vmm/src/vm.rs
@@ -12,6 +12,8 @@
|
||||
//
|
||||
|
||||
use std::collections::{BTreeMap, BTreeSet, HashMap};
|
||||
#[cfg(feature = "fw_cfg")]
|
||||
use std::ffi;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{self, Seek, SeekFrom, Write};
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
@@ -22,22 +24,30 @@ use std::os::unix::net::UnixStream;
|
||||
use std::sync::{Arc, Mutex};
|
||||
#[cfg(not(target_arch = "riscv64"))]
|
||||
use std::time::Instant;
|
||||
use std::{cmp, result, str, thread};
|
||||
use std::{any, cmp, result, str, thread};
|
||||
|
||||
use anyhow::anyhow;
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||
use arch::PciSpaceInfo;
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
use arch::aarch64;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use arch::layout::{KVM_IDENTITY_MAP_START, KVM_TSS_START};
|
||||
#[cfg(not(target_arch = "x86_64"))]
|
||||
use arch::uefi;
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
use arch::x86_64::MAX_SUPPORTED_CPUS_LEGACY;
|
||||
#[cfg(feature = "tdx")]
|
||||
use arch::x86_64::tdx;
|
||||
#[cfg(feature = "tdx")]
|
||||
use arch::x86_64::tdx::TdvfSection;
|
||||
use arch::{EntryPoint, NumaNode, NumaNodes, get_host_cpu_phys_bits};
|
||||
use arch::{EntryPoint, NumaNode, NumaNodes, get_host_cpu_phys_bits, layout};
|
||||
use devices::AcpiNotificationFlags;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use devices::interrupt_controller;
|
||||
#[cfg(feature = "fw_cfg")]
|
||||
use devices::legacy::fw_cfg;
|
||||
#[cfg(feature = "fw_cfg")]
|
||||
use devices::legacy::fw_cfg::FwCfgItem;
|
||||
use event_monitor::event;
|
||||
#[cfg(all(target_arch = "aarch64", feature = "guest_debug"))]
|
||||
@@ -46,6 +56,8 @@ use gdbstub_arch::aarch64::reg::AArch64CoreRegs as CoreRegs;
|
||||
use gdbstub_arch::x86::reg::X86_64CoreRegs as CoreRegs;
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
use hypervisor::arch::aarch64::regs::AARCH64_PMU_IRQ;
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
use hypervisor::arch::x86;
|
||||
#[cfg(all(feature = "kvm", feature = "sev_snp"))]
|
||||
use hypervisor::kvm::{
|
||||
BOOTLOADER_SIZE, BOOTLOADER_START, KVM_VMSA_PAGE_ADDRESS, KVM_VMSA_PAGE_SIZE,
|
||||
@@ -56,6 +68,8 @@ use igvm::IgvmFile;
|
||||
#[cfg(feature = "sev_snp")]
|
||||
use igvm_defs::SnpPolicy;
|
||||
use libc::{SIGWINCH, termios};
|
||||
#[cfg(feature = "tdx")]
|
||||
use linux_loader::bootparam;
|
||||
use linux_loader::cmdline::Cmdline;
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
use linux_loader::elf;
|
||||
@@ -66,6 +80,7 @@ use linux_loader::loader::bzimage::BzImage;
|
||||
use linux_loader::loader::elf::PvhBootCapability::PvhEntryPresent;
|
||||
#[cfg(any(target_arch = "aarch64", target_arch = "riscv64"))]
|
||||
use linux_loader::loader::pe::Error::InvalidImageMagicNumber;
|
||||
use linux_loader::{cmdline, loader};
|
||||
use log::{error, info, warn};
|
||||
use seccompiler::SeccompAction;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -95,8 +110,10 @@ use crate::device_tree::DeviceTree;
|
||||
#[cfg(feature = "guest_debug")]
|
||||
use crate::gdb::{Debuggable, DebuggableError, GdbRequestPayload, GdbResponsePayload};
|
||||
#[cfg(feature = "igvm")]
|
||||
use crate::igvm::igvm_loader;
|
||||
use crate::igvm::{igvm_loader, parse_igvm};
|
||||
use crate::landlock::LandlockError;
|
||||
#[cfg(feature = "tdx")]
|
||||
use crate::memory_manager;
|
||||
use crate::memory_manager::{
|
||||
Error as MemoryManagerError, MemoryManager, MemoryManagerSnapshotData,
|
||||
};
|
||||
@@ -113,7 +130,7 @@ use crate::vm_config::{
|
||||
};
|
||||
use crate::{
|
||||
CPU_MANAGER_SNAPSHOT_ID, DEVICE_MANAGER_SNAPSHOT_ID, GuestMemoryMmap,
|
||||
MEMORY_MANAGER_SNAPSHOT_ID, PciDeviceInfo, cpu,
|
||||
MEMORY_MANAGER_SNAPSHOT_ID, PciDeviceInfo, acpi, cpu,
|
||||
};
|
||||
|
||||
/// Errors associated with VM management
|
||||
@@ -126,18 +143,18 @@ pub enum Error {
|
||||
InitramfsFile(#[source] io::Error),
|
||||
|
||||
#[error("Cannot load the kernel into memory")]
|
||||
KernelLoad(#[source] linux_loader::loader::Error),
|
||||
KernelLoad(#[source] loader::Error),
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[error("Cannot load the UEFI binary in memory")]
|
||||
UefiLoad(#[source] arch::aarch64::uefi::Error),
|
||||
UefiLoad(#[source] aarch64::uefi::Error),
|
||||
|
||||
#[cfg(target_arch = "riscv64")]
|
||||
#[error("Cannot load the UEFI binary in memory")]
|
||||
UefiLoad(#[source] arch::riscv64::uefi::Error),
|
||||
|
||||
#[error("Cannot load the initramfs into memory")]
|
||||
InitramfsLoad(#[source] std::io::Error),
|
||||
InitramfsLoad(#[source] io::Error),
|
||||
|
||||
#[error("Cannot determine initramfs load address")]
|
||||
InitramfsAddress(#[source] arch::Error),
|
||||
@@ -146,16 +163,16 @@ pub enum Error {
|
||||
InitramfsRead(#[source] vm_memory::GuestMemoryError),
|
||||
|
||||
#[error("Cannot load the kernel command line in memory")]
|
||||
LoadCmdLine(#[source] linux_loader::loader::Error),
|
||||
LoadCmdLine(#[source] loader::Error),
|
||||
|
||||
#[error("Failed to apply landlock config during vm_create")]
|
||||
ApplyLandlock(#[source] LandlockError),
|
||||
|
||||
#[error("Cannot modify the kernel command line")]
|
||||
CmdLineInsertStr(#[source] linux_loader::cmdline::Error),
|
||||
CmdLineInsertStr(#[source] cmdline::Error),
|
||||
|
||||
#[error("Cannot create the kernel command line")]
|
||||
CmdLineCreate(#[source] linux_loader::cmdline::Error),
|
||||
CmdLineCreate(#[source] cmdline::Error),
|
||||
|
||||
#[error("Cannot configure system")]
|
||||
ConfigureSystem(#[source] arch::Error),
|
||||
@@ -177,7 +194,7 @@ pub enum Error {
|
||||
SignalHandlerSpawn(#[source] io::Error),
|
||||
|
||||
#[error("Failed to join on threads: {0:?}")]
|
||||
ThreadCleanup(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
|
||||
ThreadCleanup(Box<dyn any::Any + Send>),
|
||||
|
||||
#[error("VM config is missing")]
|
||||
VmMissingConfig,
|
||||
@@ -225,7 +242,7 @@ pub enum Error {
|
||||
MemoryManager(#[source] MemoryManagerError),
|
||||
|
||||
#[error("Eventfd write error")]
|
||||
EventfdError(#[source] std::io::Error),
|
||||
EventfdError(#[source] io::Error),
|
||||
|
||||
#[error("Cannot snapshot VM")]
|
||||
Snapshot(#[source] MigratableError),
|
||||
@@ -276,7 +293,7 @@ pub enum Error {
|
||||
AllocateFirmwareMemory(#[source] MemoryManagerError),
|
||||
|
||||
#[error("Error manipulating firmware file")]
|
||||
FirmwareFile(#[source] std::io::Error),
|
||||
FirmwareFile(#[source] io::Error),
|
||||
|
||||
#[error("Firmware too big")]
|
||||
FirmwareTooLarge,
|
||||
@@ -290,23 +307,23 @@ pub enum Error {
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
#[error("Error performing I/O on TDX firmware file")]
|
||||
LoadTdvf(#[source] std::io::Error),
|
||||
LoadTdvf(#[source] io::Error),
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
#[error("Error performing I/O on the TDX payload file")]
|
||||
LoadPayload(#[source] std::io::Error),
|
||||
LoadPayload(#[source] io::Error),
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
#[error("Error parsing TDVF")]
|
||||
ParseTdvf(#[source] arch::x86_64::tdx::TdvfError),
|
||||
ParseTdvf(#[source] tdx::TdvfError),
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
#[error("Error populating TDX HOB")]
|
||||
PopulateHob(#[source] arch::x86_64::tdx::TdvfError),
|
||||
PopulateHob(#[source] tdx::TdvfError),
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
#[error("Error allocating TDVF memory")]
|
||||
AllocatingTdvfMemory(#[source] crate::memory_manager::Error),
|
||||
AllocatingTdvfMemory(#[source] memory_manager::Error),
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
#[error("Error enabling TDX VM")]
|
||||
@@ -333,10 +350,10 @@ pub enum Error {
|
||||
Debug(#[source] DebuggableError),
|
||||
|
||||
#[error("Error spawning kernel loading thread")]
|
||||
KernelLoadThreadSpawn(#[source] std::io::Error),
|
||||
KernelLoadThreadSpawn(#[source] io::Error),
|
||||
|
||||
#[error("Error joining kernel loading thread")]
|
||||
KernelLoadThreadJoin(std::boxed::Box<dyn std::any::Any + std::marker::Send>),
|
||||
KernelLoadThreadJoin(Box<dyn any::Any + Send>),
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
#[error("Error coredumping VM")]
|
||||
@@ -1187,7 +1204,7 @@ impl Vm {
|
||||
.map_err(Error::MissingFwCfgKernelFile)?;
|
||||
kernel_option = kernel;
|
||||
}
|
||||
let mut cmdline_option: Option<std::ffi::CString> = None;
|
||||
let mut cmdline_option: Option<ffi::CString> = None;
|
||||
if fw_cfg_config.cmdline {
|
||||
let cmdline = Vm::generate_cmdline(
|
||||
config.lock().unwrap().payload.as_ref().unwrap(),
|
||||
@@ -1220,9 +1237,9 @@ impl Vm {
|
||||
for fw_cfg_item in fw_cfg_items.item_list.clone() {
|
||||
let content = match (fw_cfg_item.string, fw_cfg_item.file) {
|
||||
(Some(string_val), None) => {
|
||||
devices::legacy::fw_cfg::FwCfgContent::Bytes(string_val.into_bytes())
|
||||
fw_cfg::FwCfgContent::Bytes(string_val.into_bytes())
|
||||
}
|
||||
(None, Some(file_path)) => devices::legacy::fw_cfg::FwCfgContent::File(
|
||||
(None, Some(file_path)) => fw_cfg::FwCfgContent::File(
|
||||
0,
|
||||
File::open(file_path).map_err(Error::AddingFwCfgItem)?,
|
||||
),
|
||||
@@ -1370,7 +1387,7 @@ impl Vm {
|
||||
.payload
|
||||
.as_ref()
|
||||
.and_then(|p| p.igvm.as_ref())
|
||||
.map(|igvm_path| crate::igvm::parse_igvm(igvm_path))
|
||||
.map(|igvm_path| parse_igvm(igvm_path))
|
||||
.transpose()
|
||||
.map_err(Error::IgvmLoad)?
|
||||
};
|
||||
@@ -1516,10 +1533,9 @@ impl Vm {
|
||||
.map_err(Error::MemoryManager)?;
|
||||
let uefi_flash = memory_manager.uefi_flash();
|
||||
let mem = uefi_flash.memory();
|
||||
arch::uefi::load_uefi(mem.deref(), arch::layout::UEFI_START, &mut firmware)
|
||||
.map_err(Error::UefiLoad)?;
|
||||
uefi::load_uefi(mem.deref(), layout::UEFI_START, &mut firmware).map_err(Error::UefiLoad)?;
|
||||
Ok(EntryPoint {
|
||||
entry_addr: arch::layout::UEFI_START,
|
||||
entry_addr: layout::UEFI_START,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1533,9 +1549,9 @@ impl Vm {
|
||||
let mem = guest_memory.memory();
|
||||
let alignment = 0x20_0000;
|
||||
// round up
|
||||
let aligned_kernel_addr = arch::layout::KERNEL_START.0.div_ceil(alignment) * alignment;
|
||||
let aligned_kernel_addr = layout::KERNEL_START.0.div_ceil(alignment) * alignment;
|
||||
let entry_addr = {
|
||||
match linux_loader::loader::pe::PE::load(
|
||||
match loader::pe::PE::load(
|
||||
mem.deref(),
|
||||
Some(GuestAddress(aligned_kernel_addr)),
|
||||
&mut kernel,
|
||||
@@ -1545,9 +1561,9 @@ impl Vm {
|
||||
// Try to load the binary as kernel PE file at first.
|
||||
// If failed, retry to load it as UEFI binary.
|
||||
// As the UEFI binary is formatless, it must be the last option to try.
|
||||
Err(linux_loader::loader::Error::Pe(InvalidImageMagicNumber)) => {
|
||||
Err(loader::Error::Pe(InvalidImageMagicNumber)) => {
|
||||
Self::load_firmware(&kernel, memory_manager)?;
|
||||
arch::layout::UEFI_START
|
||||
layout::UEFI_START
|
||||
}
|
||||
Err(e) => {
|
||||
return Err(Error::KernelLoad(e));
|
||||
@@ -1632,25 +1648,16 @@ impl Vm {
|
||||
};
|
||||
|
||||
// Try ELF binary with PVH boot.
|
||||
let entry_addr = linux_loader::loader::elf::Elf::load(
|
||||
mem.deref(),
|
||||
None,
|
||||
&mut kernel,
|
||||
Some(arch::layout::HIGH_RAM_START),
|
||||
)
|
||||
// Try loading kernel as bzImage.
|
||||
.or_else(|_| {
|
||||
BzImage::load(
|
||||
mem.deref(),
|
||||
None,
|
||||
&mut kernel,
|
||||
Some(arch::layout::HIGH_RAM_START),
|
||||
)
|
||||
})
|
||||
.map_err(Error::KernelLoad)?;
|
||||
let entry_addr =
|
||||
loader::elf::Elf::load(mem.deref(), None, &mut kernel, Some(layout::HIGH_RAM_START))
|
||||
// Try loading kernel as bzImage.
|
||||
.or_else(|_| {
|
||||
BzImage::load(mem.deref(), None, &mut kernel, Some(layout::HIGH_RAM_START))
|
||||
})
|
||||
.map_err(Error::KernelLoad)?;
|
||||
|
||||
if let Some(cmdline) = cmdline {
|
||||
linux_loader::loader::load_cmdline(mem.deref(), arch::layout::CMDLINE_START, &cmdline)
|
||||
loader::load_cmdline(mem.deref(), layout::CMDLINE_START, &cmdline)
|
||||
.map_err(Error::LoadCmdLine)?;
|
||||
}
|
||||
|
||||
@@ -1799,7 +1806,7 @@ impl Vm {
|
||||
#[cfg(feature = "igvm")]
|
||||
let cpu_manager = cpu_manager.clone();
|
||||
|
||||
std::thread::Builder::new()
|
||||
thread::Builder::new()
|
||||
.name("payload_loader".into())
|
||||
.spawn(move || {
|
||||
Self::load_payload(
|
||||
@@ -1845,8 +1852,8 @@ impl Vm {
|
||||
|
||||
arch::configure_system(
|
||||
&mem,
|
||||
arch::layout::CMDLINE_START,
|
||||
arch::layout::CMDLINE_MAX_SIZE,
|
||||
layout::CMDLINE_START,
|
||||
layout::CMDLINE_MAX_SIZE,
|
||||
&initramfs_config,
|
||||
boot_vcpus,
|
||||
entry_addr.setup_header,
|
||||
@@ -1914,9 +1921,7 @@ impl Vm {
|
||||
.unwrap()
|
||||
.get_vgic()
|
||||
.map_err(|_| {
|
||||
Error::ConfigureSystem(arch::Error::PlatformSpecific(
|
||||
arch::aarch64::Error::SetupGic,
|
||||
))
|
||||
Error::ConfigureSystem(arch::Error::PlatformSpecific(aarch64::Error::SetupGic))
|
||||
})?;
|
||||
|
||||
// PMU interrupt sticks to PPI, so need to be added by 16 to get real irq number.
|
||||
@@ -1926,9 +1931,7 @@ impl Vm {
|
||||
.unwrap()
|
||||
.init_pmu(AARCH64_PMU_IRQ + 16)
|
||||
.map_err(|_| {
|
||||
Error::ConfigureSystem(arch::Error::PlatformSpecific(
|
||||
arch::aarch64::Error::VcpuInitPmu,
|
||||
))
|
||||
Error::ConfigureSystem(arch::Error::PlatformSpecific(aarch64::Error::VcpuInitPmu))
|
||||
})?;
|
||||
|
||||
arch::configure_system(
|
||||
@@ -2467,7 +2470,7 @@ impl Vm {
|
||||
if section.address <= next_start_addr {
|
||||
(section.address, section.size, false)
|
||||
} else {
|
||||
let last_addr = std::cmp::min(section.address - 1, region_end);
|
||||
let last_addr = cmp::min(section.address - 1, region_end);
|
||||
(next_start_addr, last_addr - next_start_addr + 1, true)
|
||||
}
|
||||
} else {
|
||||
@@ -2583,7 +2586,7 @@ impl Vm {
|
||||
.seek(SeekFrom::Start(0x1f1))
|
||||
.map_err(Error::LoadPayload)?;
|
||||
|
||||
let mut payload_header = linux_loader::bootparam::setup_header::default();
|
||||
let mut payload_header = bootparam::setup_header::default();
|
||||
payload_file
|
||||
.read_volatile(&mut payload_header.as_bytes())
|
||||
.unwrap();
|
||||
@@ -2646,9 +2649,8 @@ impl Vm {
|
||||
// MMIO regions
|
||||
hob.add_mmio_resource(
|
||||
&mem,
|
||||
arch::layout::MEM_32BIT_DEVICES_START.raw_value(),
|
||||
arch::layout::APIC_START.raw_value()
|
||||
- arch::layout::MEM_32BIT_DEVICES_START.raw_value(),
|
||||
layout::MEM_32BIT_DEVICES_START.raw_value(),
|
||||
layout::APIC_START.raw_value() - layout::MEM_32BIT_DEVICES_START.raw_value(),
|
||||
)
|
||||
.map_err(Error::PopulateHob)?;
|
||||
let start_of_device_area = self
|
||||
@@ -2672,7 +2674,7 @@ impl Vm {
|
||||
|
||||
// Loop over the ACPI tables and copy them to the HOB.
|
||||
|
||||
for acpi_table in crate::acpi::create_acpi_tables_tdx(
|
||||
for acpi_table in acpi::create_acpi_tables_tdx(
|
||||
&self.device_manager.lock().unwrap(),
|
||||
&self.cpu_manager.lock().unwrap(),
|
||||
&self.memory_manager.lock().unwrap(),
|
||||
@@ -2733,7 +2735,7 @@ impl Vm {
|
||||
}
|
||||
let mem = self.memory_manager.lock().unwrap().guest_memory().memory();
|
||||
let tpm_enabled = self.config.lock().unwrap().tpm.is_some();
|
||||
let rsdp_addr = crate::acpi::create_acpi_tables(
|
||||
let rsdp_addr = acpi::create_acpi_tables(
|
||||
&mem,
|
||||
&self.device_manager.lock().unwrap(),
|
||||
&self.cpu_manager.lock().unwrap(),
|
||||
@@ -2820,7 +2822,7 @@ impl Vm {
|
||||
|
||||
if fw_cfg_config.acpi_tables {
|
||||
let tpm_enabled = self.config.lock().unwrap().tpm.is_some();
|
||||
crate::acpi::create_acpi_tables_for_fw_cfg(
|
||||
acpi::create_acpi_tables_for_fw_cfg(
|
||||
&self.device_manager.lock().unwrap(),
|
||||
&self.cpu_manager.lock().unwrap(),
|
||||
&self.memory_manager.lock().unwrap(),
|
||||
@@ -3009,7 +3011,7 @@ impl Vm {
|
||||
pub fn send_memory_fds(
|
||||
&mut self,
|
||||
socket: &mut UnixStream,
|
||||
) -> std::result::Result<(), MigratableError> {
|
||||
) -> result::Result<(), MigratableError> {
|
||||
for (slot, fd) in self
|
||||
.memory_manager
|
||||
.lock()
|
||||
@@ -3017,7 +3019,7 @@ impl Vm {
|
||||
.memory_slot_fds()
|
||||
.drain()
|
||||
{
|
||||
Request::memory_fd(std::mem::size_of_val(&slot) as u64)
|
||||
Request::memory_fd(size_of_val(&slot) as u64)
|
||||
.write_to(socket)
|
||||
.map_err(|e| {
|
||||
MigratableError::MigrateSend(anyhow!("Error sending memory fd request: {e}"))
|
||||
@@ -3037,7 +3039,7 @@ impl Vm {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn memory_range_table(&self) -> std::result::Result<MemoryRangeTable, MigratableError> {
|
||||
pub fn memory_range_table(&self) -> result::Result<MemoryRangeTable, MigratableError> {
|
||||
self.memory_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
@@ -3156,7 +3158,7 @@ impl Vm {
|
||||
fn get_dump_state(
|
||||
&mut self,
|
||||
destination_url: &str,
|
||||
) -> std::result::Result<DumpState, GuestDebuggableError> {
|
||||
) -> result::Result<DumpState, GuestDebuggableError> {
|
||||
let nr_cpus = self.config.lock().unwrap().cpus.boot_vcpus;
|
||||
let elf_note_size = self.get_note_size(NoteDescType::ElfAndVmm, nr_cpus) as isize;
|
||||
let mut elf_phdr_num = 1;
|
||||
@@ -3211,7 +3213,7 @@ impl Vm {
|
||||
|
||||
/// Capture the guest clock for a same-host resume (mode `SameHostResume`).
|
||||
/// `None` if the VM is not booted or the backend has no guest clock.
|
||||
fn capture_guest_clock(&self) -> std::result::Result<Option<SavedClock>, MigratableError> {
|
||||
fn capture_guest_clock(&self) -> result::Result<Option<SavedClock>, MigratableError> {
|
||||
let Some(boot_vcpu) = self.cpu_manager.lock().unwrap().boot_vcpu() else {
|
||||
return Ok(None);
|
||||
};
|
||||
@@ -3227,7 +3229,7 @@ impl Vm {
|
||||
}
|
||||
|
||||
/// Re-establish the guest clock before the vCPUs resume. No-op if none captured.
|
||||
fn restore_guest_clock(&self) -> std::result::Result<(), MigratableError> {
|
||||
fn restore_guest_clock(&self) -> result::Result<(), MigratableError> {
|
||||
let Some(saved) = &self.saved_clock else {
|
||||
return Ok(());
|
||||
};
|
||||
@@ -3242,7 +3244,7 @@ impl Vm {
|
||||
}
|
||||
|
||||
impl Pausable for Vm {
|
||||
fn pause(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
fn pause(&mut self) -> result::Result<(), MigratableError> {
|
||||
event!("vm", "pausing");
|
||||
let new_state = VmState::Paused;
|
||||
self.state
|
||||
@@ -3272,7 +3274,7 @@ impl Pausable for Vm {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn resume(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
fn resume(&mut self) -> result::Result<(), MigratableError> {
|
||||
event!("vm", "resuming");
|
||||
let current_state = self.get_state();
|
||||
let new_state = VmState::Running;
|
||||
@@ -3305,7 +3307,7 @@ pub struct VmSnapshot {
|
||||
#[serde(default, skip_serializing_if = "Option::is_none")]
|
||||
pub clock: Option<hypervisor::ClockState>,
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
pub common_cpuid: Vec<hypervisor::arch::x86::CpuIdEntry>,
|
||||
pub common_cpuid: Vec<x86::CpuIdEntry>,
|
||||
}
|
||||
|
||||
pub const VM_SNAPSHOT_ID: &str = "vm";
|
||||
@@ -3314,7 +3316,7 @@ impl Snapshottable for Vm {
|
||||
VM_SNAPSHOT_ID.to_string()
|
||||
}
|
||||
|
||||
fn snapshot(&mut self) -> std::result::Result<Snapshot, MigratableError> {
|
||||
fn snapshot(&mut self) -> result::Result<Snapshot, MigratableError> {
|
||||
event!("vm", "snapshotting");
|
||||
|
||||
#[cfg(feature = "tdx")]
|
||||
@@ -3397,7 +3399,7 @@ impl Transportable for Vm {
|
||||
&self,
|
||||
snapshot: &Snapshot,
|
||||
destination_url: &str,
|
||||
) -> std::result::Result<(), MigratableError> {
|
||||
) -> result::Result<(), MigratableError> {
|
||||
let mut snapshot_config_path = url_to_path(destination_url)?;
|
||||
snapshot_config_path.push(SNAPSHOT_CONFIG_FILE);
|
||||
|
||||
@@ -3453,29 +3455,29 @@ impl Transportable for Vm {
|
||||
}
|
||||
|
||||
impl Migratable for Vm {
|
||||
fn start_dirty_log(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
fn start_dirty_log(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.memory_manager.lock().unwrap().start_dirty_log()?;
|
||||
self.device_manager.lock().unwrap().start_dirty_log()
|
||||
}
|
||||
|
||||
fn stop_dirty_log(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
fn stop_dirty_log(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.memory_manager.lock().unwrap().stop_dirty_log()?;
|
||||
self.device_manager.lock().unwrap().stop_dirty_log()
|
||||
}
|
||||
|
||||
fn dirty_log(&mut self) -> std::result::Result<MemoryRangeTable, MigratableError> {
|
||||
fn dirty_log(&mut self) -> result::Result<MemoryRangeTable, MigratableError> {
|
||||
Ok(MemoryRangeTable::new_from_tables(vec![
|
||||
self.memory_manager.lock().unwrap().dirty_log()?,
|
||||
self.device_manager.lock().unwrap().dirty_log()?,
|
||||
]))
|
||||
}
|
||||
|
||||
fn start_migration(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
fn start_migration(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.memory_manager.lock().unwrap().start_migration()?;
|
||||
self.device_manager.lock().unwrap().start_migration()
|
||||
}
|
||||
|
||||
fn complete_migration(&mut self) -> std::result::Result<(), MigratableError> {
|
||||
fn complete_migration(&mut self) -> result::Result<(), MigratableError> {
|
||||
self.memory_manager.lock().unwrap().complete_migration()?;
|
||||
self.device_manager.lock().unwrap().complete_migration()
|
||||
}
|
||||
@@ -3488,14 +3490,14 @@ impl Debuggable for Vm {
|
||||
cpu_id: usize,
|
||||
addrs: &[GuestAddress],
|
||||
singlestep: bool,
|
||||
) -> std::result::Result<(), DebuggableError> {
|
||||
) -> result::Result<(), DebuggableError> {
|
||||
self.cpu_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
.set_guest_debug(cpu_id, addrs, singlestep)
|
||||
}
|
||||
|
||||
fn debug_pause(&mut self) -> std::result::Result<(), DebuggableError> {
|
||||
fn debug_pause(&mut self) -> result::Result<(), DebuggableError> {
|
||||
if self.state == VmState::Running {
|
||||
self.pause().map_err(DebuggableError::Pause)?;
|
||||
}
|
||||
@@ -3504,7 +3506,7 @@ impl Debuggable for Vm {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn debug_resume(&mut self) -> std::result::Result<(), DebuggableError> {
|
||||
fn debug_resume(&mut self) -> result::Result<(), DebuggableError> {
|
||||
if self.state == VmState::BreakPoint {
|
||||
self.resume().map_err(DebuggableError::Pause)?;
|
||||
}
|
||||
@@ -3512,15 +3514,11 @@ impl Debuggable for Vm {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn read_regs(&self, cpu_id: usize) -> std::result::Result<CoreRegs, DebuggableError> {
|
||||
fn read_regs(&self, cpu_id: usize) -> result::Result<CoreRegs, DebuggableError> {
|
||||
self.cpu_manager.lock().unwrap().read_regs(cpu_id)
|
||||
}
|
||||
|
||||
fn write_regs(
|
||||
&self,
|
||||
cpu_id: usize,
|
||||
regs: &CoreRegs,
|
||||
) -> std::result::Result<(), DebuggableError> {
|
||||
fn write_regs(&self, cpu_id: usize, regs: &CoreRegs) -> result::Result<(), DebuggableError> {
|
||||
self.cpu_manager.lock().unwrap().write_regs(cpu_id, regs)
|
||||
}
|
||||
|
||||
@@ -3530,7 +3528,7 @@ impl Debuggable for Vm {
|
||||
cpu_id: usize,
|
||||
vaddr: GuestAddress,
|
||||
len: usize,
|
||||
) -> std::result::Result<Vec<u8>, DebuggableError> {
|
||||
) -> result::Result<Vec<u8>, DebuggableError> {
|
||||
self.cpu_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
@@ -3543,7 +3541,7 @@ impl Debuggable for Vm {
|
||||
cpu_id: usize,
|
||||
vaddr: &GuestAddress,
|
||||
data: &[u8],
|
||||
) -> std::result::Result<(), DebuggableError> {
|
||||
) -> result::Result<(), DebuggableError> {
|
||||
self.cpu_manager
|
||||
.lock()
|
||||
.unwrap()
|
||||
@@ -3569,7 +3567,7 @@ impl Elf64Writable for Vm {}
|
||||
|
||||
#[cfg(all(target_arch = "x86_64", feature = "guest_debug"))]
|
||||
impl GuestDebuggable for Vm {
|
||||
fn coredump(&mut self, destination_url: &str) -> std::result::Result<(), GuestDebuggableError> {
|
||||
fn coredump(&mut self, destination_url: &str) -> result::Result<(), GuestDebuggableError> {
|
||||
event!("vm", "coredumping");
|
||||
|
||||
let mut resume = false;
|
||||
@@ -3986,7 +3984,7 @@ mod unit_tests {
|
||||
let regions = vec![(layout::RAM_START, (layout::FDT_MAX_SIZE + 0x1000) as usize)];
|
||||
let mem = GuestMemoryMmap::from_ranges(®ions).expect("Cannot initialize memory");
|
||||
|
||||
let dev_info: HashMap<(DeviceType, std::string::String), MmioDeviceInfo> = [
|
||||
let dev_info: HashMap<(DeviceType, String), MmioDeviceInfo> = [
|
||||
(
|
||||
(DeviceType::Serial, DeviceType::Serial.to_string()),
|
||||
MmioDeviceInfo {
|
||||
|
||||
@@ -10,8 +10,12 @@ use std::str::FromStr;
|
||||
use std::{fs, result};
|
||||
|
||||
use arch::CpuProfile;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use arch::x86_64;
|
||||
use block::ImageType;
|
||||
pub use block::fcntl::LockGranularityChoice;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use devices::debug_console;
|
||||
use log::{debug, warn};
|
||||
use net_util::MacAddr;
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -170,7 +174,7 @@ pub struct PlatformConfig {
|
||||
impl PlatformConfig {
|
||||
/// Returns `None` if no SMBIOS-relevant platform fields are set, otherwise
|
||||
/// `Some` with a [`SmbiosConfig`] built from the populated fields.
|
||||
pub fn smbios_config(&self) -> Option<arch::x86_64::SmbiosConfig> {
|
||||
pub fn smbios_config(&self) -> Option<x86_64::SmbiosConfig> {
|
||||
let has_system = [
|
||||
&self.system_serial_number,
|
||||
&self.system_uuid,
|
||||
@@ -183,7 +187,7 @@ impl PlatformConfig {
|
||||
.iter()
|
||||
.any(|v| v.is_some());
|
||||
|
||||
let system = has_system.then_some(arch::x86_64::SmbiosSystem {
|
||||
let system = has_system.then_some(x86_64::SmbiosSystem {
|
||||
manufacturer: self.system_manufacturer.clone(),
|
||||
product_name: self.system_product_name.clone(),
|
||||
version: self.system_version.clone(),
|
||||
@@ -193,14 +197,14 @@ impl PlatformConfig {
|
||||
family: self.system_family.clone(),
|
||||
});
|
||||
|
||||
let chassis =
|
||||
self.chassis_asset_tag
|
||||
.clone()
|
||||
.map(|asset_tag| arch::x86_64::SmbiosChassisConfig {
|
||||
asset_tag: Some(asset_tag),
|
||||
});
|
||||
let chassis = self
|
||||
.chassis_asset_tag
|
||||
.clone()
|
||||
.map(|asset_tag| x86_64::SmbiosChassisConfig {
|
||||
asset_tag: Some(asset_tag),
|
||||
});
|
||||
|
||||
let smbios = arch::x86_64::SmbiosConfig {
|
||||
let smbios = x86_64::SmbiosConfig {
|
||||
system,
|
||||
chassis,
|
||||
oem_strings: self.oem_strings.clone().unwrap_or_default(),
|
||||
@@ -753,7 +757,7 @@ impl Default for DebugConsoleConfig {
|
||||
Self {
|
||||
file: None,
|
||||
mode: ConsoleOutputMode::Off,
|
||||
iobase: Some(devices::debug_console::DEFAULT_PORT as u16),
|
||||
iobase: Some(debug_console::DEFAULT_PORT as u16),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1317,7 +1321,7 @@ impl VmConfig {
|
||||
#[cfg(all(feature = "kvm", target_arch = "x86_64"))]
|
||||
pub(crate) fn max_apic_id(&self) -> u32 {
|
||||
if let Some(topology) = &self.cpus.topology {
|
||||
arch::x86_64::get_max_x2apic_id((
|
||||
x86_64::get_max_x2apic_id((
|
||||
topology.threads_per_core,
|
||||
topology.cores_per_die,
|
||||
topology.dies_per_package,
|
||||
|
||||
Reference in New Issue
Block a user