mirror of
				https://github.com/edera-dev/krata.git
				synced 2025-11-03 07:19:37 +00:00 
			
		
		
		
	xenclient: move error to it's own mod
This commit is contained in:
		@ -5,6 +5,7 @@ edition = "2021"
 | 
			
		||||
resolver = "2"
 | 
			
		||||
 | 
			
		||||
[dependencies]
 | 
			
		||||
thiserror = { workspace = true }
 | 
			
		||||
libc = { workspace = true }
 | 
			
		||||
elf = { workspace = true }
 | 
			
		||||
flate2 = { workspace = true }
 | 
			
		||||
 | 
			
		||||
@ -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<String> = env::args().collect();
 | 
			
		||||
 | 
			
		||||
@ -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<BootImageInfo, XenClientError>;
 | 
			
		||||
    fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<(), XenClientError>;
 | 
			
		||||
    fn parse(&self) -> Result<BootImageInfo>;
 | 
			
		||||
    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<BootState, XenClientError> {
 | 
			
		||||
    ) -> Result<BootState> {
 | 
			
		||||
        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<DomainSegment, XenClientError> {
 | 
			
		||||
    ) -> Result<DomainSegment> {
 | 
			
		||||
        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<DomainSegment, XenClientError> {
 | 
			
		||||
    ) -> Result<DomainSegment> {
 | 
			
		||||
        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<DomainSegment, XenClientError> {
 | 
			
		||||
    fn alloc_page(&mut self, arch: &mut dyn ArchBootSetup) -> Result<DomainSegment> {
 | 
			
		||||
        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<DomainSegment, XenClientError> {
 | 
			
		||||
    ) -> Result<DomainSegment> {
 | 
			
		||||
        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<DomainSegment, XenClientError>;
 | 
			
		||||
    ) -> Result<DomainSegment>;
 | 
			
		||||
 | 
			
		||||
    fn alloc_page_tables(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        setup: &mut BootSetup,
 | 
			
		||||
        image_info: &BootImageInfo,
 | 
			
		||||
    ) -> Result<DomainSegment, XenClientError>;
 | 
			
		||||
    ) -> Result<DomainSegment>;
 | 
			
		||||
 | 
			
		||||
    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<()>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -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<ParseError> for XenClientError {
 | 
			
		||||
impl From<ParseError> for Error {
 | 
			
		||||
    fn from(value: ParseError) -> Self {
 | 
			
		||||
        XenClientError::new(value.to_string().as_str())
 | 
			
		||||
        Error::new(value.to_string().as_str())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<FromVecWithNulError> for XenClientError {
 | 
			
		||||
impl From<FromVecWithNulError> for Error {
 | 
			
		||||
    fn from(value: FromVecWithNulError) -> Self {
 | 
			
		||||
        XenClientError::new(value.to_string().as_str())
 | 
			
		||||
        Error::new(value.to_string().as_str())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<IntoStringError> for XenClientError {
 | 
			
		||||
impl From<IntoStringError> 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<ElfImageLoader, XenClientError> {
 | 
			
		||||
    pub fn load_file(path: &str) -> Result<ElfImageLoader> {
 | 
			
		||||
        let data = std::fs::read(path)?;
 | 
			
		||||
        Ok(ElfImageLoader::new(data))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn load_gz(data: &[u8]) -> Result<ElfImageLoader, XenClientError> {
 | 
			
		||||
    pub fn load_gz(data: &[u8]) -> Result<ElfImageLoader> {
 | 
			
		||||
        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<ElfImageLoader, XenClientError> {
 | 
			
		||||
    pub fn load_xz(data: &[u8]) -> Result<ElfImageLoader> {
 | 
			
		||||
        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<Vec<u8>, XenClientError> {
 | 
			
		||||
    fn read_one_stream(read: &mut dyn Read) -> Result<Vec<u8>> {
 | 
			
		||||
        let mut result: Vec<u8> = 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<ElfImageLoader, XenClientError> {
 | 
			
		||||
    pub fn load_file_gz(path: &str) -> Result<ElfImageLoader> {
 | 
			
		||||
        let file = std::fs::read(path)?;
 | 
			
		||||
        ElfImageLoader::load_gz(file.as_slice())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn load_file_xz(path: &str) -> Result<ElfImageLoader, XenClientError> {
 | 
			
		||||
    pub fn load_file_xz(path: &str) -> Result<ElfImageLoader> {
 | 
			
		||||
        let file = std::fs::read(path)?;
 | 
			
		||||
        ElfImageLoader::load_xz(file.as_slice())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn load_file_kernel(path: &str) -> Result<ElfImageLoader, XenClientError> {
 | 
			
		||||
    pub fn load_file_kernel(path: &str) -> Result<ElfImageLoader> {
 | 
			
		||||
        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<BootImageInfo, XenClientError> {
 | 
			
		||||
    fn parse(&self) -> Result<BootImageInfo> {
 | 
			
		||||
        let elf = ElfBytes::<AnyEndian>::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<u64, Vec<u8>> = 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::<AnyEndian>::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.",
 | 
			
		||||
        ))?;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										60
									
								
								xen/xenclient/src/error.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								xen/xenclient/src/error.rs
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,60 @@
 | 
			
		||||
use std::fmt::{Display, Formatter};
 | 
			
		||||
use std::string::FromUtf8Error;
 | 
			
		||||
use xencall::XenCallError;
 | 
			
		||||
 | 
			
		||||
pub type Result<T> = std::result::Result<T, Error>;
 | 
			
		||||
 | 
			
		||||
#[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<std::io::Error> for Error {
 | 
			
		||||
    fn from(value: std::io::Error) -> Self {
 | 
			
		||||
        Error::new(value.to_string().as_str())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<xenstore::error::Error> for Error {
 | 
			
		||||
    fn from(value: xenstore::error::Error) -> Self {
 | 
			
		||||
        Error::new(value.to_string().as_str())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<XenCallError> for Error {
 | 
			
		||||
    fn from(value: XenCallError) -> Self {
 | 
			
		||||
        Error::new(value.to_string().as_str())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<FromUtf8Error> for Error {
 | 
			
		||||
    fn from(value: FromUtf8Error) -> Self {
 | 
			
		||||
        Error::new(value.to_string().as_str())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<xenevtchn::error::Error> for Error {
 | 
			
		||||
    fn from(value: xenevtchn::error::Error) -> Self {
 | 
			
		||||
        Error::new(value.to_string().as_str())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -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<std::io::Error> for XenClientError {
 | 
			
		||||
    fn from(value: std::io::Error) -> Self {
 | 
			
		||||
        XenClientError::new(value.to_string().as_str())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<xenstore::error::Error> for XenClientError {
 | 
			
		||||
    fn from(value: xenstore::error::Error) -> Self {
 | 
			
		||||
        XenClientError::new(value.to_string().as_str())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<XenCallError> for XenClientError {
 | 
			
		||||
    fn from(value: XenCallError) -> Self {
 | 
			
		||||
        XenClientError::new(value.to_string().as_str())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<FromUtf8Error> for XenClientError {
 | 
			
		||||
    fn from(value: FromUtf8Error) -> Self {
 | 
			
		||||
        XenClientError::new(value.to_string().as_str())
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl From<xenevtchn::error::Error> 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<XenClient, XenClientError> {
 | 
			
		||||
    pub fn open() -> Result<XenClient> {
 | 
			
		||||
        let store = XsdClient::open()?;
 | 
			
		||||
        let call = XenCall::open()?;
 | 
			
		||||
        Ok(XenClient { store, call })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn create(&mut self, config: &DomainConfig) -> Result<u32, XenClientError> {
 | 
			
		||||
    pub fn create(&mut self, config: &DomainConfig) -> Result<u32> {
 | 
			
		||||
        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<String> = 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)?;
 | 
			
		||||
 | 
			
		||||
@ -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<u64, XenClientError> {
 | 
			
		||||
    pub fn pfn_to_ptr(&mut self, pfn: u64, count: u64) -> Result<u64> {
 | 
			
		||||
        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<u64, XenClientError> {
 | 
			
		||||
    fn pfn_alloc(&mut self, pfn: u64, count: u64) -> Result<u64> {
 | 
			
		||||
        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<u64, XenClientError> {
 | 
			
		||||
    pub fn map_foreign_pages(&mut self, mfn: u64, size: u64) -> Result<u64> {
 | 
			
		||||
        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);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@ -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<usize, XenClientError> {
 | 
			
		||||
    ) -> Result<usize> {
 | 
			
		||||
        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<DomainSegment, XenClientError> {
 | 
			
		||||
    ) -> Result<DomainSegment> {
 | 
			
		||||
        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<DomainSegment, XenClientError> {
 | 
			
		||||
    ) -> Result<DomainSegment> {
 | 
			
		||||
        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<VmemRange> = 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();
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user