diff --git a/xen/xenclient/Cargo.toml b/xen/xenclient/Cargo.toml index 001aff6..dc1c493 100644 --- a/xen/xenclient/Cargo.toml +++ b/xen/xenclient/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" resolver = "2" [dependencies] +thiserror = { workspace = true } libc = { workspace = true } elf = { workspace = true } flate2 = { workspace = true } diff --git a/xen/xenclient/examples/boot.rs b/xen/xenclient/examples/boot.rs index 8929c84..9edffe8 100644 --- a/xen/xenclient/examples/boot.rs +++ b/xen/xenclient/examples/boot.rs @@ -1,7 +1,8 @@ use std::{env, process}; -use xenclient::{DomainConfig, XenClient, XenClientError}; +use xenclient::error::Result; +use xenclient::{DomainConfig, XenClient}; -fn main() -> Result<(), XenClientError> { +fn main() -> Result<()> { env_logger::init(); let args: Vec = env::args().collect(); diff --git a/xen/xenclient/src/boot.rs b/xen/xenclient/src/boot.rs index 8dd9bf2..f7860a4 100644 --- a/xen/xenclient/src/boot.rs +++ b/xen/xenclient/src/boot.rs @@ -1,6 +1,7 @@ +use crate::error::Result; use crate::mem::PhysicalPages; use crate::sys::{GrantEntry, XEN_PAGE_SHIFT}; -use crate::XenClientError; +use crate::Error; use libc::munmap; use log::debug; use slice_copy::copy; @@ -10,8 +11,8 @@ use std::slice; use xencall::XenCall; pub trait BootImageLoader { - fn parse(&self) -> Result; - fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<(), XenClientError>; + fn parse(&self) -> Result; + fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<()>; } pub const XEN_UNSET_ADDR: u64 = -1i64 as u64; @@ -77,11 +78,7 @@ impl BootSetup<'_> { } } - fn initialize_memory( - &mut self, - arch: &mut dyn ArchBootSetup, - total_pages: u64, - ) -> Result<(), XenClientError> { + fn initialize_memory(&mut self, arch: &mut dyn ArchBootSetup, total_pages: u64) -> Result<()> { self.call.set_address_size(self.domid, 64)?; arch.meminit(self, total_pages)?; Ok(()) @@ -94,7 +91,7 @@ impl BootSetup<'_> { initrd: &[u8], max_vcpus: u32, mem_mb: u64, - ) -> Result { + ) -> Result { debug!( "BootSetup initialize max_vcpus={:?} mem_mb={:?}", max_vcpus, mem_mb @@ -164,7 +161,7 @@ impl BootSetup<'_> { arch: &mut dyn ArchBootSetup, state: &mut BootState, cmdline: &str, - ) -> Result<(), XenClientError> { + ) -> Result<()> { let domain_info = self.call.get_domain_info(self.domid)?; let shared_info_frame = domain_info.shared_info_frame; state.shared_info_frame = shared_info_frame; @@ -179,13 +176,13 @@ impl BootSetup<'_> { Ok(()) } - fn gnttab_seed(&mut self, state: &mut BootState) -> Result<(), XenClientError> { + fn gnttab_seed(&mut self, state: &mut BootState) -> Result<()> { let console_gfn = self.phys.p2m[state.console_segment.pfn as usize]; let xenstore_gfn = self.phys.p2m[state.xenstore_segment.pfn as usize]; let addr = self .call .mmap(0, 1 << XEN_PAGE_SHIFT) - .ok_or(XenClientError::new("failed to mmap for resource"))?; + .ok_or(Error::new("failed to mmap for resource"))?; self.call.map_resource(self.domid, 1, 0, 0, 1, addr)?; let entries = unsafe { slice::from_raw_parts_mut(addr as *mut GrantEntry, 2) }; entries[0].flags = 1 << 0; @@ -197,7 +194,7 @@ impl BootSetup<'_> { unsafe { let result = munmap(addr as *mut c_void, 1 << XEN_PAGE_SHIFT); if result != 0 { - return Err(XenClientError::new("failed to unmap resource")); + return Err(Error::new("failed to unmap resource")); } } Ok(()) @@ -208,7 +205,7 @@ impl BootSetup<'_> { arch: &mut dyn ArchBootSetup, image_loader: &dyn BootImageLoader, image_info: &BootImageInfo, - ) -> Result { + ) -> Result { let kernel_segment = self.alloc_segment( arch, image_info.virt_kstart, @@ -234,7 +231,7 @@ impl BootSetup<'_> { arch: &mut dyn ArchBootSetup, start: u64, size: u64, - ) -> Result { + ) -> Result { if start > 0 { self.alloc_padding_pages(arch, start)?; } @@ -268,10 +265,7 @@ impl BootSetup<'_> { Ok(segment) } - fn alloc_page( - &mut self, - arch: &mut dyn ArchBootSetup, - ) -> Result { + fn alloc_page(&mut self, arch: &mut dyn ArchBootSetup) -> Result { let start = self.virt_alloc_end; let pfn = self.pfn_alloc_end; @@ -291,26 +285,22 @@ impl BootSetup<'_> { &mut self, arch: &mut dyn ArchBootSetup, buffer: &[u8], - ) -> Result { + ) -> Result { let segment = self.alloc_segment(arch, 0, buffer.len() as u64)?; let slice = unsafe { slice::from_raw_parts_mut(segment.addr as *mut u8, buffer.len()) }; copy(slice, buffer); Ok(segment) } - fn alloc_padding_pages( - &mut self, - arch: &mut dyn ArchBootSetup, - boundary: u64, - ) -> Result<(), XenClientError> { + fn alloc_padding_pages(&mut self, arch: &mut dyn ArchBootSetup, boundary: u64) -> Result<()> { if (boundary & (arch.page_size() - 1)) != 0 { - return Err(XenClientError::new( + return Err(Error::new( format!("segment boundary isn't page aligned: {:#x}", boundary).as_str(), )); } if boundary < self.virt_alloc_end { - return Err(XenClientError::new( + return Err(Error::new( format!("segment boundary too low: {:#x})", boundary).as_str(), )); } @@ -319,16 +309,12 @@ impl BootSetup<'_> { Ok(()) } - fn chk_alloc_pages( - &mut self, - arch: &mut dyn ArchBootSetup, - pages: u64, - ) -> Result<(), XenClientError> { + fn chk_alloc_pages(&mut self, arch: &mut dyn ArchBootSetup, pages: u64) -> Result<()> { if pages > self.total_pages || self.pfn_alloc_end > self.total_pages || pages > self.total_pages - self.pfn_alloc_end { - return Err(XenClientError::new( + return Err(Error::new( format!( "segment too large: pages={} total_pages={} pfn_alloc_end={}", pages, self.total_pages, self.pfn_alloc_end @@ -351,44 +337,32 @@ pub trait ArchBootSetup { &mut self, setup: &mut BootSetup, image_info: &BootImageInfo, - ) -> Result; + ) -> Result; fn alloc_page_tables( &mut self, setup: &mut BootSetup, image_info: &BootImageInfo, - ) -> Result; + ) -> Result; - fn setup_page_tables( - &mut self, - setup: &mut BootSetup, - state: &mut BootState, - ) -> Result<(), XenClientError>; + fn setup_page_tables(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()>; fn setup_start_info( &mut self, setup: &mut BootSetup, state: &BootState, cmdline: &str, - ) -> Result<(), XenClientError>; + ) -> Result<()>; - fn setup_shared_info( - &mut self, - setup: &mut BootSetup, - shared_info_frame: u64, - ) -> Result<(), XenClientError>; + fn setup_shared_info(&mut self, setup: &mut BootSetup, shared_info_frame: u64) -> Result<()>; fn setup_hypercall_page( &mut self, setup: &mut BootSetup, image_info: &BootImageInfo, - ) -> Result<(), XenClientError>; + ) -> Result<()>; - fn meminit(&mut self, setup: &mut BootSetup, total_pages: u64) -> Result<(), XenClientError>; - fn bootlate( - &mut self, - setup: &mut BootSetup, - state: &mut BootState, - ) -> Result<(), XenClientError>; - fn vcpu(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<(), XenClientError>; + fn meminit(&mut self, setup: &mut BootSetup, total_pages: u64) -> Result<()>; + fn bootlate(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()>; + fn vcpu(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()>; } diff --git a/xen/xenclient/src/elfloader.rs b/xen/xenclient/src/elfloader.rs index e7c5b6e..900f52c 100644 --- a/xen/xenclient/src/elfloader.rs +++ b/xen/xenclient/src/elfloader.rs @@ -1,9 +1,10 @@ use crate::boot::{BootImageInfo, BootImageLoader, XEN_UNSET_ADDR}; +use crate::error::Result; use crate::sys::{ XEN_ELFNOTE_ENTRY, XEN_ELFNOTE_HYPERCALL_PAGE, XEN_ELFNOTE_INIT_P2M, XEN_ELFNOTE_MOD_START_PFN, XEN_ELFNOTE_PADDR_OFFSET, XEN_ELFNOTE_TYPES, XEN_ELFNOTE_VIRT_BASE, }; -use crate::XenClientError; +use crate::Error; use elf::abi::{PF_R, PF_W, PF_X, PT_LOAD, SHT_NOTE}; use elf::endian::AnyEndian; use elf::note::Note; @@ -18,21 +19,21 @@ use std::io::{BufReader, Read}; use std::mem::size_of; use xz2::bufread::XzDecoder; -impl From for XenClientError { +impl From for Error { fn from(value: ParseError) -> Self { - XenClientError::new(value.to_string().as_str()) + Error::new(value.to_string().as_str()) } } -impl From for XenClientError { +impl From for Error { fn from(value: FromVecWithNulError) -> Self { - XenClientError::new(value.to_string().as_str()) + Error::new(value.to_string().as_str()) } } -impl From for XenClientError { +impl From for Error { fn from(value: IntoStringError) -> Self { - XenClientError::new(value.to_string().as_str()) + Error::new(value.to_string().as_str()) } } @@ -80,24 +81,24 @@ impl ElfImageLoader { ElfImageLoader { data } } - pub fn load_file(path: &str) -> Result { + pub fn load_file(path: &str) -> Result { let data = std::fs::read(path)?; Ok(ElfImageLoader::new(data)) } - pub fn load_gz(data: &[u8]) -> Result { + pub fn load_gz(data: &[u8]) -> Result { let buff = BufReader::new(data); let image = ElfImageLoader::read_one_stream(&mut GzDecoder::new(buff))?; Ok(ElfImageLoader::new(image)) } - pub fn load_xz(data: &[u8]) -> Result { + pub fn load_xz(data: &[u8]) -> Result { let buff = BufReader::new(data); let image = ElfImageLoader::read_one_stream(&mut XzDecoder::new(buff))?; Ok(ElfImageLoader::new(image)) } - fn read_one_stream(read: &mut dyn Read) -> Result, XenClientError> { + fn read_one_stream(read: &mut dyn Read) -> Result> { let mut result: Vec = Vec::new(); let mut buffer = [0u8; 8192]; @@ -113,24 +114,24 @@ impl ElfImageLoader { if !result.is_empty() { break; } - return Err(XenClientError::from(error)); + return Err(Error::from(error)); } } } Ok(result) } - pub fn load_file_gz(path: &str) -> Result { + pub fn load_file_gz(path: &str) -> Result { let file = std::fs::read(path)?; ElfImageLoader::load_gz(file.as_slice()) } - pub fn load_file_xz(path: &str) -> Result { + pub fn load_file_xz(path: &str) -> Result { let file = std::fs::read(path)?; ElfImageLoader::load_xz(file.as_slice()) } - pub fn load_file_kernel(path: &str) -> Result { + pub fn load_file_kernel(path: &str) -> Result { let file = std::fs::read(path)?; for start in find_iter(file.as_slice(), &[0x1f, 0x8b]) { @@ -145,7 +146,7 @@ impl ElfImageLoader { } } - Err(XenClientError::new( + Err(Error::new( "Unable to parse kernel image: unknown compression type", )) } @@ -156,9 +157,9 @@ struct ElfNoteValue { } impl BootImageLoader for ElfImageLoader { - fn parse(&self) -> Result { + fn parse(&self) -> Result { let elf = ElfBytes::::minimal_parse(self.data.as_slice())?; - let headers = elf.section_headers().ok_or(XenClientError::new( + let headers = elf.section_headers().ok_or(Error::new( "Unable to parse kernel image: section headers not found.", ))?; let mut linux_notes: HashMap> = HashMap::new(); @@ -197,56 +198,44 @@ impl BootImageLoader for ElfImageLoader { } if linux_notes.is_empty() { - return Err(XenClientError::new( + return Err(Error::new( "Provided kernel does not appear to be a Linux kernel image.", )); } if xen_notes.is_empty() { - return Err(XenClientError::new( - "Provided kernel does not have Xen support.", - )); + return Err(Error::new("Provided kernel does not have Xen support.")); } let paddr_offset = xen_notes .get(&XEN_ELFNOTE_PADDR_OFFSET) - .ok_or(XenClientError::new( - "Unable to find paddr_offset note in kernel.", - ))? + .ok_or(Error::new("Unable to find paddr_offset note in kernel."))? .value; let virt_base = xen_notes .get(&XEN_ELFNOTE_VIRT_BASE) - .ok_or(XenClientError::new( - "Unable to find virt_base note in kernel.", - ))? + .ok_or(Error::new("Unable to find virt_base note in kernel."))? .value; let entry = xen_notes .get(&XEN_ELFNOTE_ENTRY) - .ok_or(XenClientError::new("Unable to find entry note in kernel."))? + .ok_or(Error::new("Unable to find entry note in kernel."))? .value; let virt_hypercall = xen_notes .get(&XEN_ELFNOTE_HYPERCALL_PAGE) - .ok_or(XenClientError::new( - "Unable to find hypercall_page note in kernel.", - ))? + .ok_or(Error::new("Unable to find hypercall_page note in kernel."))? .value; let init_p2m = xen_notes .get(&XEN_ELFNOTE_INIT_P2M) - .ok_or(XenClientError::new( - "Unable to find init_p2m note in kernel.", - ))? + .ok_or(Error::new("Unable to find init_p2m note in kernel."))? .value; let mod_start_pfn = xen_notes .get(&XEN_ELFNOTE_MOD_START_PFN) - .ok_or(XenClientError::new( - "Unable to find mod_start_pfn note in kernel.", - ))? + .ok_or(Error::new("Unable to find mod_start_pfn note in kernel."))? .value; let mut start: u64 = u64::MAX; let mut end: u64 = 0; - let segments = elf.segments().ok_or(XenClientError::new( + let segments = elf.segments().ok_or(Error::new( "Unable to parse kernel image: segments not found.", ))?; @@ -266,7 +255,7 @@ impl BootImageLoader for ElfImageLoader { } if paddr_offset != XEN_UNSET_ADDR && virt_base == XEN_UNSET_ADDR { - return Err(XenClientError::new( + return Err(Error::new( "Unable to load kernel image: paddr_offset set but virt_base is unset.", )); } @@ -289,9 +278,9 @@ impl BootImageLoader for ElfImageLoader { Ok(image_info) } - fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<(), XenClientError> { + fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<()> { let elf = ElfBytes::::minimal_parse(self.data.as_slice())?; - let segments = elf.segments().ok_or(XenClientError::new( + let segments = elf.segments().ok_or(Error::new( "Unable to parse kernel image: segments not found.", ))?; diff --git a/xen/xenclient/src/error.rs b/xen/xenclient/src/error.rs new file mode 100644 index 0000000..5020bd7 --- /dev/null +++ b/xen/xenclient/src/error.rs @@ -0,0 +1,60 @@ +use std::fmt::{Display, Formatter}; +use std::string::FromUtf8Error; +use xencall::XenCallError; + +pub type Result = std::result::Result; + +#[derive(Debug)] +pub struct Error { + message: String, +} + +impl Error { + pub fn new(msg: &str) -> Error { + Error { + message: msg.to_string(), + } + } +} + +impl Display for Error { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.message) + } +} + +impl std::error::Error for Error { + fn description(&self) -> &str { + &self.message + } +} + +impl From for Error { + fn from(value: std::io::Error) -> Self { + Error::new(value.to_string().as_str()) + } +} + +impl From for Error { + fn from(value: xenstore::error::Error) -> Self { + Error::new(value.to_string().as_str()) + } +} + +impl From for Error { + fn from(value: XenCallError) -> Self { + Error::new(value.to_string().as_str()) + } +} + +impl From for Error { + fn from(value: FromUtf8Error) -> Self { + Error::new(value.to_string().as_str()) + } +} + +impl From for Error { + fn from(value: xenevtchn::error::Error) -> Self { + Error::new(value.to_string().as_str()) + } +} diff --git a/xen/xenclient/src/lib.rs b/xen/xenclient/src/lib.rs index c3dc8c2..79c9141 100644 --- a/xen/xenclient/src/lib.rs +++ b/xen/xenclient/src/lib.rs @@ -1,24 +1,24 @@ pub mod boot; pub mod elfloader; +pub mod error; pub mod mem; pub mod sys; -mod x86; +pub mod x86; use crate::boot::BootSetup; use crate::elfloader::ElfImageLoader; +use crate::error::{Error, Result}; use crate::x86::X86BootSetup; use log::{trace, warn}; -use std::error::Error; -use std::fmt::{Display, Formatter}; + use std::fs::{read, File, OpenOptions}; use std::path::PathBuf; use std::str::FromStr; -use std::string::FromUtf8Error; use std::thread; use std::time::Duration; use uuid::Uuid; use xencall::sys::CreateDomain; -use xencall::{XenCall, XenCallError}; +use xencall::XenCall; use xenstore::client::{ XsPermission, XsdClient, XsdInterface, XS_PERM_NONE, XS_PERM_READ, XS_PERM_READ_WRITE, }; @@ -28,61 +28,6 @@ pub struct XenClient { call: XenCall, } -#[derive(Debug)] -pub struct XenClientError { - message: String, -} - -impl XenClientError { - pub fn new(msg: &str) -> XenClientError { - XenClientError { - message: msg.to_string(), - } - } -} - -impl Display for XenClientError { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - write!(f, "{}", self.message) - } -} - -impl Error for XenClientError { - fn description(&self) -> &str { - &self.message - } -} - -impl From for XenClientError { - fn from(value: std::io::Error) -> Self { - XenClientError::new(value.to_string().as_str()) - } -} - -impl From for XenClientError { - fn from(value: xenstore::error::Error) -> Self { - XenClientError::new(value.to_string().as_str()) - } -} - -impl From for XenClientError { - fn from(value: XenCallError) -> Self { - XenClientError::new(value.to_string().as_str()) - } -} - -impl From for XenClientError { - fn from(value: FromUtf8Error) -> Self { - XenClientError::new(value.to_string().as_str()) - } -} - -impl From for XenClientError { - fn from(value: xenevtchn::error::Error) -> Self { - XenClientError::new(value.to_string().as_str()) - } -} - #[derive(Debug)] pub struct BlockDeviceRef { pub path: String, @@ -118,13 +63,13 @@ pub struct DomainConfig<'a> { } impl XenClient { - pub fn open() -> Result { + pub fn open() -> Result { let store = XsdClient::open()?; let call = XenCall::open()?; Ok(XenClient { store, call }) } - pub fn create(&mut self, config: &DomainConfig) -> Result { + pub fn create(&mut self, config: &DomainConfig) -> Result { let domain = CreateDomain { max_vcpus: config.max_vcpus, ..Default::default() @@ -141,7 +86,7 @@ impl XenClient { } } - pub fn destroy(&mut self, domid: u32) -> Result<(), XenClientError> { + pub fn destroy(&mut self, domid: u32) -> Result<()> { if let Err(err) = self.destroy_store(domid) { warn!("failed to destroy store for domain {}: {}", domid, err); } @@ -149,13 +94,11 @@ impl XenClient { Ok(()) } - fn destroy_store(&mut self, domid: u32) -> Result<(), XenClientError> { + fn destroy_store(&mut self, domid: u32) -> Result<()> { let dom_path = self.store.get_domain_path(domid)?; let vm_path = self.store.read_string(&format!("{}/vm", dom_path))?; if vm_path.is_empty() { - return Err(XenClientError::new( - "cannot destroy domain that doesn't exist", - )); + return Err(Error::new("cannot destroy domain that doesn't exist")); } let mut backend_paths: Vec = Vec::new(); @@ -220,10 +163,10 @@ impl XenClient { let path = PathBuf::from(path); let parent = path .parent() - .ok_or(XenClientError::new("unable to get parent of backend path"))?; + .ok_or(Error::new("unable to get parent of backend path"))?; tx.rm(parent .to_str() - .ok_or(XenClientError::new("unable to convert parent to string"))?)?; + .ok_or(Error::new("unable to convert parent to string"))?)?; } tx.rm(&vm_path)?; tx.rm(&dom_path)?; @@ -231,12 +174,7 @@ impl XenClient { Ok(()) } - fn init( - &mut self, - domid: u32, - domain: &CreateDomain, - config: &DomainConfig, - ) -> Result<(), XenClientError> { + fn init(&mut self, domid: u32, domain: &CreateDomain, config: &DomainConfig) -> Result<()> { trace!( "XenClient init domid={} domain={:?} config={:?}", domid, @@ -398,7 +336,7 @@ impl XenClient { .store .introduce_domain(domid, xenstore_mfn, xenstore_evtchn)? { - return Err(XenClientError::new("failed to introduce domain")); + return Err(Error::new("failed to introduce domain")); } self.console_device_add( &dom_path, @@ -440,7 +378,7 @@ impl XenClient { domid: u32, index: usize, disk: &DomainDisk, - ) -> Result<(), XenClientError> { + ) -> Result<()> { let id = (202 << 8) | (index << 4) as u64; let backend_items: Vec<(&str, String)> = vec![ ("frontend-id", domid.to_string()), @@ -491,7 +429,7 @@ impl XenClient { domid: u32, port: u32, mfn: u64, - ) -> Result<(), XenClientError> { + ) -> Result<()> { let backend_entries = vec![ ("frontend-id", domid.to_string()), ("online", "1".to_string()), @@ -530,7 +468,7 @@ impl XenClient { domid: u32, index: usize, filesystem: &DomainFilesystem, - ) -> Result<(), XenClientError> { + ) -> Result<()> { let id = 90 + index as u64; let backend_items: Vec<(&str, String)> = vec![ ("frontend-id", domid.to_string()), @@ -570,7 +508,7 @@ impl XenClient { domid: u32, frontend_items: Vec<(&str, String)>, backend_items: Vec<(&str, String)>, - ) -> Result<(), XenClientError> { + ) -> Result<()> { let console_zero = typ == "console" && id == 0; let frontend_path = if console_zero { @@ -624,7 +562,7 @@ impl XenClient { Ok(()) } - pub fn open_console(&mut self, domid: u32) -> Result<(File, File), XenClientError> { + pub fn open_console(&mut self, domid: u32) -> Result<(File, File)> { let dom_path = self.store.get_domain_path(domid)?; let console_tty_path = format!("{}/console/tty", dom_path); let tty = self @@ -632,10 +570,7 @@ impl XenClient { .read_string_optional(&console_tty_path)? .unwrap_or("".to_string()); if tty.is_empty() { - return Err(XenClientError::new(&format!( - "domain {} does not have a tty", - domid - ))); + return Err(Error::new(&format!("domain {} does not have a tty", domid))); } let read = OpenOptions::new().read(true).write(false).open(&tty)?; let write = OpenOptions::new().read(false).write(true).open(&tty)?; diff --git a/xen/xenclient/src/mem.rs b/xen/xenclient/src/mem.rs index a425872..355dcf0 100644 --- a/xen/xenclient/src/mem.rs +++ b/xen/xenclient/src/mem.rs @@ -1,5 +1,6 @@ +use crate::error::Result; use crate::sys::{XEN_PAGE_SHIFT, XEN_PAGE_SIZE}; -use crate::XenClientError; +use crate::Error; use libc::munmap; use log::debug; use std::ffi::c_void; @@ -40,7 +41,7 @@ impl PhysicalPages<'_> { self.p2m.len() as u64 } - pub fn pfn_to_ptr(&mut self, pfn: u64, count: u64) -> Result { + pub fn pfn_to_ptr(&mut self, pfn: u64, count: u64) -> Result { for page in &self.pages { if pfn >= page.pfn + page.count { continue; @@ -52,7 +53,7 @@ impl PhysicalPages<'_> { } if pfn < page.pfn || (pfn + count) > page.pfn + page.count { - return Err(XenClientError::new("request overlaps allocated block")); + return Err(Error::new("request overlaps allocated block")); } } else { if pfn < page.pfn { @@ -68,7 +69,7 @@ impl PhysicalPages<'_> { } if count == 0 { - return Err(XenClientError::new( + return Err(Error::new( "allocation is only allowed when a size is given", )); } @@ -76,7 +77,7 @@ impl PhysicalPages<'_> { self.pfn_alloc(pfn, count) } - fn pfn_alloc(&mut self, pfn: u64, count: u64) -> Result { + fn pfn_alloc(&mut self, pfn: u64, count: u64) -> Result { let mut entries = vec![MmapEntry::default(); count as usize]; for (i, entry) in entries.iter_mut().enumerate() { entry.mfn = self.p2m[pfn as usize + i]; @@ -95,11 +96,11 @@ impl PhysicalPages<'_> { let addr = self .call .mmap(0, actual_mmap_len) - .ok_or(XenClientError::new("failed to mmap address"))?; + .ok_or(Error::new("failed to mmap address"))?; debug!("mapped {:#x} foreign bytes at {:#x}", actual_mmap_len, addr); let result = self.call.mmap_batch(self.domid, num as u64, addr, pfns)?; if result != 0 { - return Err(XenClientError::new("mmap_batch call failed")); + return Err(Error::new("mmap_batch call failed")); } let page = PhysicalPage { pfn, @@ -114,7 +115,7 @@ impl PhysicalPages<'_> { Ok(addr) } - pub fn map_foreign_pages(&mut self, mfn: u64, size: u64) -> Result { + pub fn map_foreign_pages(&mut self, mfn: u64, size: u64) -> Result { let num = ((size + XEN_PAGE_SIZE - 1) >> XEN_PAGE_SHIFT) as usize; let mut pfns = vec![u64::MAX; num]; for (i, item) in pfns.iter_mut().enumerate().take(num) { @@ -125,11 +126,11 @@ impl PhysicalPages<'_> { let addr = self .call .mmap(0, actual_mmap_len) - .ok_or(XenClientError::new("failed to mmap address"))?; + .ok_or(Error::new("failed to mmap address"))?; debug!("mapped {:#x} foreign bytes at {:#x}", actual_mmap_len, addr); let result = self.call.mmap_batch(self.domid, num as u64, addr, pfns)?; if result != 0 { - return Err(XenClientError::new("mmap_batch call failed")); + return Err(Error::new("mmap_batch call failed")); } let page = PhysicalPage { pfn: u64::MAX, @@ -144,7 +145,7 @@ impl PhysicalPages<'_> { Ok(addr) } - pub fn unmap_all(&mut self) -> Result<(), XenClientError> { + pub fn unmap_all(&mut self) -> Result<()> { for page in &self.pages { unsafe { let err = munmap( @@ -152,7 +153,7 @@ impl PhysicalPages<'_> { (page.count << X86_PAGE_SHIFT) as usize, ); if err != 0 { - return Err(XenClientError::new("failed to munmap all pages")); + return Err(Error::new("failed to munmap all pages")); } } } @@ -160,10 +161,10 @@ impl PhysicalPages<'_> { Ok(()) } - pub fn unmap(&mut self, pfn: u64) -> Result<(), XenClientError> { + pub fn unmap(&mut self, pfn: u64) -> Result<()> { let page = self.pages.iter().enumerate().find(|(_, x)| x.pfn == pfn); if page.is_none() { - return Err(XenClientError::new("unable to find page to unmap")); + return Err(Error::new("unable to find page to unmap")); } let (i, page) = page.unwrap(); @@ -178,7 +179,7 @@ impl PhysicalPages<'_> { page.ptr ); if err != 0 { - return Err(XenClientError::new("failed to munmap page")); + return Err(Error::new("failed to munmap page")); } self.pages.remove(i); } diff --git a/xen/xenclient/src/x86.rs b/xen/xenclient/src/x86.rs index 13d6313..c164c2c 100644 --- a/xen/xenclient/src/x86.rs +++ b/xen/xenclient/src/x86.rs @@ -1,11 +1,12 @@ use crate::boot::{ ArchBootSetup, BootImageInfo, BootSetup, BootState, DomainSegment, XEN_UNSET_ADDR, }; +use crate::error::Result; use crate::sys::{ SUPERPAGE_2MB_NR_PFNS, SUPERPAGE_2MB_SHIFT, SUPERPAGE_BATCH_SIZE, VGCF_IN_KERNEL, VGCF_ONLINE, XEN_PAGE_SHIFT, }; -use crate::XenClientError; +use crate::Error; use libc::c_char; use log::{debug, trace}; use slice_copy::copy; @@ -139,6 +140,12 @@ struct VmemRange { _nid: u32, } +impl Default for X86BootSetup { + fn default() -> Self { + Self::new() + } +} + impl X86BootSetup { pub fn new() -> X86BootSetup { X86BootSetup { @@ -193,22 +200,22 @@ impl X86BootSetup { from: u64, to: u64, pfn: u64, - ) -> Result { + ) -> Result { debug!("counting pgtables from={} to={} pfn={}", from, to, pfn); if self.table.mappings_count == X86_PAGE_TABLE_MAX_MAPPINGS { - return Err(XenClientError::new("too many mappings")); + return Err(Error::new("too many mappings")); } let m = self.table.mappings_count; let pfn_end = pfn + ((to - from) >> X86_PAGE_SHIFT); if pfn_end >= setup.phys.p2m_size() { - return Err(XenClientError::new("not enough memory for initial mapping")); + return Err(Error::new("not enough memory for initial mapping")); } for idx in 0..self.table.mappings_count { if from < self.table.mappings[idx].area.to && to > self.table.mappings[idx].area.from { - return Err(XenClientError::new("overlapping mappings")); + return Err(Error::new("overlapping mappings")); } } let mut map = PageTableMapping::default(); @@ -284,7 +291,7 @@ impl ArchBootSetup for X86BootSetup { &mut self, setup: &mut BootSetup, image_info: &BootImageInfo, - ) -> Result { + ) -> Result { let mut p2m_alloc_size = ((setup.phys.p2m_size() * 8) + X86_PAGE_SIZE - 1) & !(X86_PAGE_SIZE - 1); let from = image_info.virt_p2m_base; @@ -310,7 +317,7 @@ impl ArchBootSetup for X86BootSetup { &mut self, setup: &mut BootSetup, image_info: &BootImageInfo, - ) -> Result { + ) -> Result { let mut extra_pages = 1; extra_pages += (512 * 1024) / X86_PAGE_SIZE; let mut pages = extra_pages; @@ -341,11 +348,7 @@ impl ArchBootSetup for X86BootSetup { Ok(segment) } - fn setup_page_tables( - &mut self, - setup: &mut BootSetup, - state: &mut BootState, - ) -> Result<(), XenClientError> { + fn setup_page_tables(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()> { let p2m_guest = unsafe { slice::from_raw_parts_mut( state.p2m_segment.addr as *mut u64, @@ -407,7 +410,7 @@ impl ArchBootSetup for X86BootSetup { setup: &mut BootSetup, state: &BootState, cmdline: &str, - ) -> Result<(), XenClientError> { + ) -> Result<()> { let ptr = setup.phys.pfn_to_ptr(state.start_info_segment.pfn, 1)?; let byte_slice = unsafe { slice::from_raw_parts_mut(ptr as *mut u8, X86_PAGE_SIZE as usize) }; @@ -441,11 +444,7 @@ impl ArchBootSetup for X86BootSetup { Ok(()) } - fn setup_shared_info( - &mut self, - setup: &mut BootSetup, - shared_info_frame: u64, - ) -> Result<(), XenClientError> { + fn setup_shared_info(&mut self, setup: &mut BootSetup, shared_info_frame: u64) -> Result<()> { let info = setup .phys .map_foreign_pages(shared_info_frame, X86_PAGE_SIZE)? @@ -466,7 +465,7 @@ impl ArchBootSetup for X86BootSetup { &mut self, setup: &mut BootSetup, image_info: &BootImageInfo, - ) -> Result<(), XenClientError> { + ) -> Result<()> { if image_info.virt_hypercall == XEN_UNSET_ADDR { return Ok(()); } @@ -477,7 +476,7 @@ impl ArchBootSetup for X86BootSetup { Ok(()) } - fn meminit(&mut self, setup: &mut BootSetup, total_pages: u64) -> Result<(), XenClientError> { + fn meminit(&mut self, setup: &mut BootSetup, total_pages: u64) -> Result<()> { setup.call.claim_pages(setup.domid, total_pages)?; let mut vmemranges: Vec = Vec::new(); let stub = VmemRange { @@ -495,9 +494,7 @@ impl ArchBootSetup for X86BootSetup { } if total != total_pages { - return Err(XenClientError::new( - "page count mismatch while calculating pages", - )); + return Err(Error::new("page count mismatch while calculating pages")); } setup.total_pages = total; @@ -564,7 +561,7 @@ impl ArchBootSetup for X86BootSetup { .populate_physmap(setup.domid, allocsz, 0, 0, input_extent_starts)?; if result.len() != allocsz as usize { - return Err(XenClientError::new( + return Err(Error::new( format!( "failed to populate physmap: wanted={} received={} input_extents={}", allocsz, @@ -589,11 +586,7 @@ impl ArchBootSetup for X86BootSetup { Ok(()) } - fn bootlate( - &mut self, - setup: &mut BootSetup, - state: &mut BootState, - ) -> Result<(), XenClientError> { + fn bootlate(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()> { let pg_pfn = state.page_table_segment.pfn; let pg_mfn = setup.phys.p2m[pg_pfn as usize]; setup.phys.unmap(pg_pfn)?; @@ -604,7 +597,7 @@ impl ArchBootSetup for X86BootSetup { Ok(()) } - fn vcpu(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<(), XenClientError> { + fn vcpu(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()> { let pg_pfn = state.page_table_segment.pfn; let pg_mfn = setup.phys.p2m[pg_pfn as usize]; let mut vcpu = VcpuGuestContext::default();