mirror of
				https://github.com/edera-dev/krata.git
				synced 2025-11-04 07:39:39 +00:00 
			
		
		
		
	feat(xen): update xenclient and xenplatform to the latest structure (#433)
This commit is contained in:
		@ -8,16 +8,9 @@ use crate::{
 | 
			
		||||
    error::{Error, Result},
 | 
			
		||||
    mem::PhysicalPages,
 | 
			
		||||
    sys::XEN_PAGE_SHIFT,
 | 
			
		||||
    ImageLoader, PlatformKernelConfig, PlatformResourcesConfig,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
pub struct BootSetup<I: BootImageLoader, P: BootSetupPlatform> {
 | 
			
		||||
    pub call: XenCall,
 | 
			
		||||
    pub domid: u32,
 | 
			
		||||
    pub platform: P,
 | 
			
		||||
    pub image_loader: I,
 | 
			
		||||
    pub dtb: Option<Vec<u8>>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Default, Clone)]
 | 
			
		||||
pub struct DomainSegment {
 | 
			
		||||
    pub vstart: u64,
 | 
			
		||||
@ -42,7 +35,7 @@ pub struct BootDomain {
 | 
			
		||||
    pub phys: PhysicalPages,
 | 
			
		||||
    pub store_evtchn: u32,
 | 
			
		||||
    pub store_mfn: u64,
 | 
			
		||||
    pub initrd_segment: DomainSegment,
 | 
			
		||||
    pub initrd_segment: Option<DomainSegment>,
 | 
			
		||||
    pub console_evtchn: u32,
 | 
			
		||||
    pub console_mfn: u64,
 | 
			
		||||
    pub cmdline: String,
 | 
			
		||||
@ -142,129 +135,8 @@ impl BootDomain {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<I: BootImageLoader, P: BootSetupPlatform> BootSetup<I, P> {
 | 
			
		||||
    pub fn new(
 | 
			
		||||
        call: XenCall,
 | 
			
		||||
        domid: u32,
 | 
			
		||||
        platform: P,
 | 
			
		||||
        image_loader: I,
 | 
			
		||||
        dtb: Option<Vec<u8>>,
 | 
			
		||||
    ) -> BootSetup<I, P> {
 | 
			
		||||
        BootSetup {
 | 
			
		||||
            call,
 | 
			
		||||
            domid,
 | 
			
		||||
            platform,
 | 
			
		||||
            image_loader,
 | 
			
		||||
            dtb,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn initialize(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        initrd: &[u8],
 | 
			
		||||
        target_mem_mb: u64,
 | 
			
		||||
        max_mem_mb: u64,
 | 
			
		||||
        max_vcpus: u32,
 | 
			
		||||
        cmdline: &str,
 | 
			
		||||
    ) -> Result<BootDomain> {
 | 
			
		||||
        let target_pages = target_mem_mb << (20 - self.platform.page_shift());
 | 
			
		||||
        let total_pages = max_mem_mb << (20 - self.platform.page_shift());
 | 
			
		||||
        let image_info = self.image_loader.parse(self.platform.hvm()).await?;
 | 
			
		||||
        let mut domain = BootDomain {
 | 
			
		||||
            domid: self.domid,
 | 
			
		||||
            call: self.call.clone(),
 | 
			
		||||
            virt_alloc_end: 0,
 | 
			
		||||
            virt_pgtab_end: 0,
 | 
			
		||||
            pfn_alloc_end: 0,
 | 
			
		||||
            total_pages,
 | 
			
		||||
            target_pages,
 | 
			
		||||
            page_size: self.platform.page_size(),
 | 
			
		||||
            image_info,
 | 
			
		||||
            console_evtchn: 0,
 | 
			
		||||
            console_mfn: 0,
 | 
			
		||||
            max_vcpus,
 | 
			
		||||
            phys: PhysicalPages::new(self.call.clone(), self.domid, self.platform.page_shift()),
 | 
			
		||||
            initrd_segment: DomainSegment::default(),
 | 
			
		||||
            store_evtchn: 0,
 | 
			
		||||
            store_mfn: 0,
 | 
			
		||||
            cmdline: cmdline.to_string(),
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        self.platform.initialize_early(&mut domain).await?;
 | 
			
		||||
 | 
			
		||||
        let mut initrd_segment = if !domain.image_info.unmapped_initrd {
 | 
			
		||||
            Some(domain.alloc_module(initrd).await?)
 | 
			
		||||
        } else {
 | 
			
		||||
            None
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let mut kernel_segment = if self.platform.needs_early_kernel() {
 | 
			
		||||
            Some(self.load_kernel_segment(&mut domain).await?)
 | 
			
		||||
        } else {
 | 
			
		||||
            None
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        self.platform.initialize_memory(&mut domain).await?;
 | 
			
		||||
        domain.virt_alloc_end = domain.image_info.virt_base;
 | 
			
		||||
 | 
			
		||||
        if kernel_segment.is_none() {
 | 
			
		||||
            kernel_segment = Some(self.load_kernel_segment(&mut domain).await?);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if domain.image_info.unmapped_initrd {
 | 
			
		||||
            initrd_segment = Some(domain.alloc_module(initrd).await?);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        domain.initrd_segment =
 | 
			
		||||
            initrd_segment.ok_or(Error::MemorySetupFailed("initrd_segment missing"))?;
 | 
			
		||||
 | 
			
		||||
        self.platform.alloc_magic_pages(&mut domain).await?;
 | 
			
		||||
 | 
			
		||||
        domain.store_evtchn = self.call.evtchn_alloc_unbound(self.domid, 0).await?;
 | 
			
		||||
 | 
			
		||||
        let _kernel_segment =
 | 
			
		||||
            kernel_segment.ok_or(Error::MemorySetupFailed("kernel_segment missing"))?;
 | 
			
		||||
 | 
			
		||||
        Ok(domain)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn boot(&mut self, domain: &mut BootDomain) -> Result<()> {
 | 
			
		||||
        let domain_info = self.call.get_domain_info(self.domid).await?;
 | 
			
		||||
        let shared_info_frame = domain_info.shared_info_frame;
 | 
			
		||||
        self.platform.setup_page_tables(domain).await?;
 | 
			
		||||
        self.platform
 | 
			
		||||
            .setup_start_info(domain, shared_info_frame)
 | 
			
		||||
            .await?;
 | 
			
		||||
        self.platform.setup_hypercall_page(domain).await?;
 | 
			
		||||
        self.platform.bootlate(domain).await?;
 | 
			
		||||
        self.platform
 | 
			
		||||
            .setup_shared_info(domain, shared_info_frame)
 | 
			
		||||
            .await?;
 | 
			
		||||
        self.platform.vcpu(domain).await?;
 | 
			
		||||
        domain.phys.unmap_all()?;
 | 
			
		||||
        self.platform.gnttab_seed(domain).await?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn load_kernel_segment(&mut self, domain: &mut BootDomain) -> Result<DomainSegment> {
 | 
			
		||||
        let kernel_segment = domain
 | 
			
		||||
            .alloc_segment(
 | 
			
		||||
                domain.image_info.virt_kstart,
 | 
			
		||||
                domain.image_info.virt_kend - domain.image_info.virt_kstart,
 | 
			
		||||
            )
 | 
			
		||||
            .await?;
 | 
			
		||||
        let kernel_segment_ptr = kernel_segment.addr as *mut u8;
 | 
			
		||||
        let kernel_segment_slice =
 | 
			
		||||
            unsafe { slice::from_raw_parts_mut(kernel_segment_ptr, kernel_segment.size as usize) };
 | 
			
		||||
        self.image_loader
 | 
			
		||||
            .load(&domain.image_info, kernel_segment_slice)
 | 
			
		||||
            .await?;
 | 
			
		||||
        Ok(kernel_segment)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[async_trait::async_trait]
 | 
			
		||||
pub trait BootSetupPlatform: Clone {
 | 
			
		||||
pub trait BootSetupPlatform {
 | 
			
		||||
    fn create_domain(&self, enable_iommu: bool) -> CreateDomain;
 | 
			
		||||
    fn page_size(&self) -> u64;
 | 
			
		||||
    fn page_shift(&self) -> u64;
 | 
			
		||||
@ -304,6 +176,135 @@ pub trait BootSetupPlatform: Clone {
 | 
			
		||||
    async fn vcpu(&mut self, domain: &mut BootDomain) -> Result<()>;
 | 
			
		||||
 | 
			
		||||
    async fn setup_hypercall_page(&mut self, domain: &mut BootDomain) -> Result<()>;
 | 
			
		||||
 | 
			
		||||
    async fn initialize_internal(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        domid: u32,
 | 
			
		||||
        call: XenCall,
 | 
			
		||||
        image_loader: &ImageLoader,
 | 
			
		||||
        domain: &mut BootDomain,
 | 
			
		||||
        kernel: &PlatformKernelConfig,
 | 
			
		||||
    ) -> Result<()> {
 | 
			
		||||
        self.initialize_early(domain).await?;
 | 
			
		||||
 | 
			
		||||
        let mut initrd_segment = if !domain.image_info.unmapped_initrd && kernel.initrd.is_some() {
 | 
			
		||||
            Some(domain.alloc_module(kernel.initrd.as_ref().unwrap()).await?)
 | 
			
		||||
        } else {
 | 
			
		||||
            None
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        let mut kernel_segment = if self.needs_early_kernel() {
 | 
			
		||||
            Some(self.load_kernel_segment(image_loader, domain).await?)
 | 
			
		||||
        } else {
 | 
			
		||||
            None
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        self.initialize_memory(domain).await?;
 | 
			
		||||
        domain.virt_alloc_end = domain.image_info.virt_base;
 | 
			
		||||
 | 
			
		||||
        if kernel_segment.is_none() {
 | 
			
		||||
            kernel_segment = Some(self.load_kernel_segment(image_loader, domain).await?);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if domain.image_info.unmapped_initrd && kernel.initrd.is_some() {
 | 
			
		||||
            initrd_segment = Some(domain.alloc_module(kernel.initrd.as_ref().unwrap()).await?);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        domain.initrd_segment = initrd_segment;
 | 
			
		||||
        self.alloc_magic_pages(domain).await?;
 | 
			
		||||
        domain.store_evtchn = call.evtchn_alloc_unbound(domid, 0).await?;
 | 
			
		||||
        let _kernel_segment =
 | 
			
		||||
            kernel_segment.ok_or(Error::MemorySetupFailed("kernel_segment missing"))?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[allow(clippy::too_many_arguments)]
 | 
			
		||||
    async fn initialize(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        domid: u32,
 | 
			
		||||
        call: XenCall,
 | 
			
		||||
        image_loader: &ImageLoader,
 | 
			
		||||
        kernel: &PlatformKernelConfig,
 | 
			
		||||
        resources: &PlatformResourcesConfig,
 | 
			
		||||
    ) -> Result<BootDomain> {
 | 
			
		||||
        let target_pages = resources.assigned_memory_mb << (20 - self.page_shift());
 | 
			
		||||
        let total_pages = resources.max_memory_mb << (20 - self.page_shift());
 | 
			
		||||
        let image_info = image_loader.parse(self.hvm()).await?;
 | 
			
		||||
        let mut domain = BootDomain {
 | 
			
		||||
            domid,
 | 
			
		||||
            call: call.clone(),
 | 
			
		||||
            virt_alloc_end: 0,
 | 
			
		||||
            virt_pgtab_end: 0,
 | 
			
		||||
            pfn_alloc_end: 0,
 | 
			
		||||
            total_pages,
 | 
			
		||||
            target_pages,
 | 
			
		||||
            page_size: self.page_size(),
 | 
			
		||||
            image_info,
 | 
			
		||||
            console_evtchn: 0,
 | 
			
		||||
            console_mfn: 0,
 | 
			
		||||
            max_vcpus: resources.max_vcpus,
 | 
			
		||||
            phys: PhysicalPages::new(call.clone(), domid, self.page_shift()),
 | 
			
		||||
            initrd_segment: None,
 | 
			
		||||
            store_evtchn: 0,
 | 
			
		||||
            store_mfn: 0,
 | 
			
		||||
            cmdline: kernel.cmdline.clone(),
 | 
			
		||||
        };
 | 
			
		||||
        match self
 | 
			
		||||
            .initialize_internal(domid, call, image_loader, &mut domain, kernel)
 | 
			
		||||
            .await
 | 
			
		||||
        {
 | 
			
		||||
            Ok(_) => Ok(domain),
 | 
			
		||||
            Err(error) => {
 | 
			
		||||
                domain.phys.unmap_all()?;
 | 
			
		||||
                Err(error)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn boot_internal(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        call: XenCall,
 | 
			
		||||
        domid: u32,
 | 
			
		||||
        domain: &mut BootDomain,
 | 
			
		||||
    ) -> Result<()> {
 | 
			
		||||
        let domain_info = call.get_domain_info(domid).await?;
 | 
			
		||||
        let shared_info_frame = domain_info.shared_info_frame;
 | 
			
		||||
        self.setup_page_tables(domain).await?;
 | 
			
		||||
        self.setup_start_info(domain, shared_info_frame).await?;
 | 
			
		||||
        self.setup_hypercall_page(domain).await?;
 | 
			
		||||
        self.bootlate(domain).await?;
 | 
			
		||||
        self.setup_shared_info(domain, shared_info_frame).await?;
 | 
			
		||||
        self.vcpu(domain).await?;
 | 
			
		||||
        self.gnttab_seed(domain).await?;
 | 
			
		||||
        domain.phys.unmap_all()?;
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn boot(&mut self, domid: u32, call: XenCall, domain: &mut BootDomain) -> Result<()> {
 | 
			
		||||
        let result = self.boot_internal(call, domid, domain).await;
 | 
			
		||||
        domain.phys.unmap_all()?;
 | 
			
		||||
        result
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn load_kernel_segment(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        image_loader: &ImageLoader,
 | 
			
		||||
        domain: &mut BootDomain,
 | 
			
		||||
    ) -> Result<DomainSegment> {
 | 
			
		||||
        let kernel_segment = domain
 | 
			
		||||
            .alloc_segment(
 | 
			
		||||
                domain.image_info.virt_kstart,
 | 
			
		||||
                domain.image_info.virt_kend - domain.image_info.virt_kstart,
 | 
			
		||||
            )
 | 
			
		||||
            .await?;
 | 
			
		||||
        let kernel_segment_ptr = kernel_segment.addr as *mut u8;
 | 
			
		||||
        let kernel_segment_slice =
 | 
			
		||||
            unsafe { slice::from_raw_parts_mut(kernel_segment_ptr, kernel_segment.size as usize) };
 | 
			
		||||
        image_loader
 | 
			
		||||
            .load(&domain.image_info, kernel_segment_slice)
 | 
			
		||||
            .await?;
 | 
			
		||||
        Ok(kernel_segment)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[async_trait::async_trait]
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,10 @@
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
    boot::{BootSetup, BootSetupPlatform},
 | 
			
		||||
    elfloader::ElfImageLoader,
 | 
			
		||||
    boot::BootDomain, elfloader::ElfImageLoader, error::Error, ImageLoader, RuntimePlatform,
 | 
			
		||||
    RuntimePlatformType,
 | 
			
		||||
};
 | 
			
		||||
use log::warn;
 | 
			
		||||
use uuid::Uuid;
 | 
			
		||||
use xencall::XenCall;
 | 
			
		||||
 | 
			
		||||
@ -11,42 +12,92 @@ use crate::error::Result;
 | 
			
		||||
 | 
			
		||||
pub const XEN_EXTRA_MEMORY_KB: u64 = 2048;
 | 
			
		||||
 | 
			
		||||
pub struct BaseDomainManager<P: BootSetupPlatform> {
 | 
			
		||||
pub struct PlatformDomainManager {
 | 
			
		||||
    call: XenCall,
 | 
			
		||||
    pub platform: Arc<P>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl<P: BootSetupPlatform> BaseDomainManager<P> {
 | 
			
		||||
    pub async fn new(call: XenCall, platform: P) -> Result<BaseDomainManager<P>> {
 | 
			
		||||
        Ok(BaseDomainManager {
 | 
			
		||||
            call,
 | 
			
		||||
            platform: Arc::new(platform),
 | 
			
		||||
        })
 | 
			
		||||
impl PlatformDomainManager {
 | 
			
		||||
    pub async fn new(call: XenCall) -> Result<PlatformDomainManager> {
 | 
			
		||||
        Ok(PlatformDomainManager { call })
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn create(&self, config: BaseDomainConfig) -> Result<CreatedDomain> {
 | 
			
		||||
        let mut domain = self.platform.create_domain(config.enable_iommu);
 | 
			
		||||
    fn max_memory_kb(resources: &PlatformResourcesConfig) -> u64 {
 | 
			
		||||
        (resources.max_memory_mb * 1024) + XEN_EXTRA_MEMORY_KB
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn create_base_domain(
 | 
			
		||||
        &self,
 | 
			
		||||
        config: &PlatformDomainConfig,
 | 
			
		||||
        platform: &RuntimePlatform,
 | 
			
		||||
    ) -> Result<u32> {
 | 
			
		||||
        let mut domain = platform.create_domain(config.options.iommu);
 | 
			
		||||
        domain.handle = config.uuid.into_bytes();
 | 
			
		||||
        domain.max_vcpus = config.max_vcpus;
 | 
			
		||||
        domain.max_vcpus = config.resources.max_vcpus;
 | 
			
		||||
        let domid = self.call.create_domain(domain).await?;
 | 
			
		||||
        self.call.set_max_vcpus(domid, config.max_vcpus).await?;
 | 
			
		||||
        Ok(domid)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn configure_domain_resources(
 | 
			
		||||
        &self,
 | 
			
		||||
        domid: u32,
 | 
			
		||||
        config: &PlatformDomainConfig,
 | 
			
		||||
    ) -> Result<()> {
 | 
			
		||||
        self.call
 | 
			
		||||
            .set_max_mem(domid, (config.max_mem_mb * 1024) + XEN_EXTRA_MEMORY_KB)
 | 
			
		||||
            .set_max_vcpus(domid, config.resources.max_vcpus)
 | 
			
		||||
            .await?;
 | 
			
		||||
        let loader = ElfImageLoader::load_file_kernel(&config.kernel)?;
 | 
			
		||||
        let platform = (*self.platform).clone();
 | 
			
		||||
        let mut boot = BootSetup::new(self.call.clone(), domid, platform, loader, None);
 | 
			
		||||
        let mut domain = boot
 | 
			
		||||
            .initialize(
 | 
			
		||||
                &config.initrd,
 | 
			
		||||
                config.target_mem_mb,
 | 
			
		||||
                config.max_mem_mb,
 | 
			
		||||
                config.max_vcpus,
 | 
			
		||||
                &config.cmdline,
 | 
			
		||||
        self.call
 | 
			
		||||
            .set_max_mem(
 | 
			
		||||
                domid,
 | 
			
		||||
                PlatformDomainManager::max_memory_kb(&config.resources),
 | 
			
		||||
            )
 | 
			
		||||
            .await?;
 | 
			
		||||
        boot.boot(&mut domain).await?;
 | 
			
		||||
        Ok(CreatedDomain {
 | 
			
		||||
        Ok(())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn create_internal(
 | 
			
		||||
        &self,
 | 
			
		||||
        domid: u32,
 | 
			
		||||
        config: &PlatformDomainConfig,
 | 
			
		||||
        mut platform: RuntimePlatform,
 | 
			
		||||
    ) -> Result<BootDomain> {
 | 
			
		||||
        self.configure_domain_resources(domid, config).await?;
 | 
			
		||||
        let kernel = config.kernel.clone();
 | 
			
		||||
        let loader = tokio::task::spawn_blocking(move || match kernel.format {
 | 
			
		||||
            KernelFormat::ElfCompressed => ElfImageLoader::load(kernel.data),
 | 
			
		||||
            KernelFormat::ElfUncompressed => Ok(ElfImageLoader::new(kernel.data)),
 | 
			
		||||
        })
 | 
			
		||||
        .await
 | 
			
		||||
        .map_err(Error::AsyncJoinError)??;
 | 
			
		||||
        let loader = ImageLoader::Elf(loader);
 | 
			
		||||
        let mut domain = platform
 | 
			
		||||
            .initialize(
 | 
			
		||||
                domid,
 | 
			
		||||
                self.call.clone(),
 | 
			
		||||
                &loader,
 | 
			
		||||
                &config.kernel,
 | 
			
		||||
                &config.resources,
 | 
			
		||||
            )
 | 
			
		||||
            .await?;
 | 
			
		||||
        platform.boot(domid, self.call.clone(), &mut domain).await?;
 | 
			
		||||
        Ok(domain)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn create(&self, config: PlatformDomainConfig) -> Result<PlatformDomainInfo> {
 | 
			
		||||
        let platform = config.platform.create();
 | 
			
		||||
        let domid = self.create_base_domain(&config, &platform).await?;
 | 
			
		||||
        let domain = match self.create_internal(domid, &config, platform).await {
 | 
			
		||||
            Ok(domain) => domain,
 | 
			
		||||
            Err(error) => {
 | 
			
		||||
                if let Err(destroy_fail) = self.call.destroy_domain(domid).await {
 | 
			
		||||
                    warn!(
 | 
			
		||||
                        "failed to destroy failed domain {}: {}",
 | 
			
		||||
                        domid, destroy_fail
 | 
			
		||||
                    );
 | 
			
		||||
                }
 | 
			
		||||
                return Err(error);
 | 
			
		||||
            }
 | 
			
		||||
        };
 | 
			
		||||
        Ok(PlatformDomainInfo {
 | 
			
		||||
            domid,
 | 
			
		||||
            store_evtchn: domain.store_evtchn,
 | 
			
		||||
            store_mfn: domain.store_mfn,
 | 
			
		||||
@ -62,21 +113,43 @@ impl<P: BootSetupPlatform> BaseDomainManager<P> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub struct BaseDomainConfig {
 | 
			
		||||
pub struct PlatformDomainConfig {
 | 
			
		||||
    pub uuid: Uuid,
 | 
			
		||||
    pub owner_domid: u32,
 | 
			
		||||
    pub max_vcpus: u32,
 | 
			
		||||
    pub target_vcpus: u32,
 | 
			
		||||
    pub max_mem_mb: u64,
 | 
			
		||||
    pub target_mem_mb: u64,
 | 
			
		||||
    pub kernel: Vec<u8>,
 | 
			
		||||
    pub initrd: Vec<u8>,
 | 
			
		||||
    pub cmdline: String,
 | 
			
		||||
    pub enable_iommu: bool,
 | 
			
		||||
    pub platform: RuntimePlatformType,
 | 
			
		||||
    pub resources: PlatformResourcesConfig,
 | 
			
		||||
    pub kernel: PlatformKernelConfig,
 | 
			
		||||
    pub options: PlatformOptions,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub struct CreatedDomain {
 | 
			
		||||
pub struct PlatformKernelConfig {
 | 
			
		||||
    pub data: Arc<Vec<u8>>,
 | 
			
		||||
    pub format: KernelFormat,
 | 
			
		||||
    pub initrd: Option<Arc<Vec<u8>>>,
 | 
			
		||||
    pub cmdline: String,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub struct PlatformResourcesConfig {
 | 
			
		||||
    pub max_vcpus: u32,
 | 
			
		||||
    pub assigned_vcpus: u32,
 | 
			
		||||
    pub max_memory_mb: u64,
 | 
			
		||||
    pub assigned_memory_mb: u64,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub struct PlatformOptions {
 | 
			
		||||
    pub iommu: bool,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub enum KernelFormat {
 | 
			
		||||
    ElfUncompressed,
 | 
			
		||||
    ElfCompressed,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug)]
 | 
			
		||||
pub struct PlatformDomainInfo {
 | 
			
		||||
    pub domid: u32,
 | 
			
		||||
    pub store_evtchn: u32,
 | 
			
		||||
    pub store_mfn: u64,
 | 
			
		||||
 | 
			
		||||
@ -19,6 +19,12 @@ use std::mem::size_of;
 | 
			
		||||
use std::sync::Arc;
 | 
			
		||||
use xz2::bufread::XzDecoder;
 | 
			
		||||
 | 
			
		||||
const ELF_MAGIC: &[u8] = &[
 | 
			
		||||
    0x7f, 0x45, 0x4c, 0x46, 0x02, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
 | 
			
		||||
];
 | 
			
		||||
const GZIP_MAGIC: &[u8] = &[0x1f, 0x8b];
 | 
			
		||||
const XZ_MAGIC: &[u8] = &[0xfd, 0x37, 0x7a, 0x58];
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub struct ElfImageLoader {
 | 
			
		||||
    data: Arc<Vec<u8>>,
 | 
			
		||||
@ -60,22 +66,40 @@ fn xen_note_value_as_u64(endian: AnyEndian, value: &[u8]) -> Option<u64> {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ElfImageLoader {
 | 
			
		||||
    pub fn new(data: Vec<u8>) -> ElfImageLoader {
 | 
			
		||||
        ElfImageLoader {
 | 
			
		||||
            data: Arc::new(data),
 | 
			
		||||
        }
 | 
			
		||||
    pub fn new(data: Arc<Vec<u8>>) -> ElfImageLoader {
 | 
			
		||||
        ElfImageLoader { data }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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))
 | 
			
		||||
        Ok(ElfImageLoader::new(Arc::new(image)))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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))
 | 
			
		||||
        Ok(ElfImageLoader::new(Arc::new(image)))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn load(data: Arc<Vec<u8>>) -> Result<ElfImageLoader> {
 | 
			
		||||
        if data.len() >= 16 && find_iter(&data[0..15], ELF_MAGIC).next().is_some() {
 | 
			
		||||
            return Ok(ElfImageLoader::new(data));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for start in find_iter(&data, GZIP_MAGIC) {
 | 
			
		||||
            if let Ok(elf) = ElfImageLoader::load_gz(&data[start..]) {
 | 
			
		||||
                return Ok(elf);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for start in find_iter(&data, XZ_MAGIC) {
 | 
			
		||||
            if let Ok(elf) = ElfImageLoader::load_xz(&data[start..]) {
 | 
			
		||||
                return Ok(elf);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Err(Error::ElfCompressionUnknown)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn read_one_stream(read: &mut dyn Read) -> Result<Vec<u8>> {
 | 
			
		||||
@ -101,36 +125,11 @@ impl ElfImageLoader {
 | 
			
		||||
        Ok(result)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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> {
 | 
			
		||||
        let file = std::fs::read(path)?;
 | 
			
		||||
        ElfImageLoader::load_xz(file.as_slice())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn load_file_kernel(data: &[u8]) -> Result<ElfImageLoader> {
 | 
			
		||||
        for start in find_iter(data, &[0x1f, 0x8b]) {
 | 
			
		||||
            if let Ok(elf) = ElfImageLoader::load_gz(&data[start..]) {
 | 
			
		||||
                return Ok(elf);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        for start in find_iter(data, &[0xfd, 0x37, 0x7a, 0x58]) {
 | 
			
		||||
            if let Ok(elf) = ElfImageLoader::load_xz(&data[start..]) {
 | 
			
		||||
                return Ok(elf);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        Err(Error::ElfCompressionUnknown)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn parse_sync(&self, hvm: bool) -> Result<BootImageInfo> {
 | 
			
		||||
        let elf = ElfBytes::<AnyEndian>::minimal_parse(self.data.as_slice())?;
 | 
			
		||||
        let headers = elf.section_headers().ok_or(Error::ElfInvalidImage)?;
 | 
			
		||||
        let mut linux_notes: HashMap<u64, Vec<u8>> = HashMap::new();
 | 
			
		||||
        let headers = elf
 | 
			
		||||
            .section_headers()
 | 
			
		||||
            .ok_or(Error::ElfInvalidImage("section headers missing"))?;
 | 
			
		||||
        let mut xen_notes: HashMap<u64, ElfNoteValue> = HashMap::new();
 | 
			
		||||
 | 
			
		||||
        for header in headers {
 | 
			
		||||
@ -140,62 +139,55 @@ impl ElfImageLoader {
 | 
			
		||||
 | 
			
		||||
            let notes = elf.section_data_as_notes(&header)?;
 | 
			
		||||
            for note in notes {
 | 
			
		||||
                if let Note::Unknown(note) = note {
 | 
			
		||||
                    if note.name == "Linux" {
 | 
			
		||||
                        linux_notes.insert(note.n_type, note.desc.to_vec());
 | 
			
		||||
                    }
 | 
			
		||||
                let Note::Unknown(note) = note else {
 | 
			
		||||
                    continue;
 | 
			
		||||
                };
 | 
			
		||||
 | 
			
		||||
                    if note.name == "Xen" {
 | 
			
		||||
                        for typ in XEN_ELFNOTE_TYPES {
 | 
			
		||||
                            if typ.id != note.n_type {
 | 
			
		||||
                                continue;
 | 
			
		||||
                            }
 | 
			
		||||
 | 
			
		||||
                            let value = if !typ.is_string {
 | 
			
		||||
                                xen_note_value_as_u64(elf.ehdr.endianness, note.desc).unwrap_or(0)
 | 
			
		||||
                            } else {
 | 
			
		||||
                                0
 | 
			
		||||
                            };
 | 
			
		||||
 | 
			
		||||
                            xen_notes.insert(typ.id, ElfNoteValue { value });
 | 
			
		||||
                if note.name == "Xen" {
 | 
			
		||||
                    for typ in XEN_ELFNOTE_TYPES {
 | 
			
		||||
                        if typ.id != note.n_type {
 | 
			
		||||
                            continue;
 | 
			
		||||
                        }
 | 
			
		||||
                        continue;
 | 
			
		||||
 | 
			
		||||
                        let value = if !typ.is_string {
 | 
			
		||||
                            xen_note_value_as_u64(elf.ehdr.endianness, note.desc).unwrap_or(0)
 | 
			
		||||
                        } else {
 | 
			
		||||
                            0
 | 
			
		||||
                        };
 | 
			
		||||
 | 
			
		||||
                        xen_notes.insert(typ.id, ElfNoteValue { value });
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if linux_notes.is_empty() {
 | 
			
		||||
            return Err(Error::ElfInvalidImage);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if xen_notes.is_empty() {
 | 
			
		||||
            return Err(Error::ElfXenSupportMissing);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let paddr_offset = xen_notes
 | 
			
		||||
            .get(&XEN_ELFNOTE_PADDR_OFFSET)
 | 
			
		||||
            .ok_or(Error::ElfInvalidImage)?
 | 
			
		||||
            .ok_or(Error::ElfXenNoteMissing("PADDR_OFFSET"))?
 | 
			
		||||
            .value;
 | 
			
		||||
        let virt_base = xen_notes
 | 
			
		||||
            .get(&XEN_ELFNOTE_VIRT_BASE)
 | 
			
		||||
            .ok_or(Error::ElfInvalidImage)?
 | 
			
		||||
            .ok_or(Error::ElfXenNoteMissing("VIRT_BASE"))?
 | 
			
		||||
            .value;
 | 
			
		||||
        let entry = xen_notes
 | 
			
		||||
            .get(&XEN_ELFNOTE_ENTRY)
 | 
			
		||||
            .ok_or(Error::ElfInvalidImage)?
 | 
			
		||||
            .ok_or(Error::ElfXenNoteMissing("ENTRY"))?
 | 
			
		||||
            .value;
 | 
			
		||||
        let virt_hypercall = xen_notes
 | 
			
		||||
            .get(&XEN_ELFNOTE_HYPERCALL_PAGE)
 | 
			
		||||
            .ok_or(Error::ElfInvalidImage)?
 | 
			
		||||
            .ok_or(Error::ElfXenNoteMissing("HYPERCALL_PAGE"))?
 | 
			
		||||
            .value;
 | 
			
		||||
        let init_p2m = xen_notes
 | 
			
		||||
            .get(&XEN_ELFNOTE_INIT_P2M)
 | 
			
		||||
            .ok_or(Error::ElfInvalidImage)?
 | 
			
		||||
            .ok_or(Error::ElfXenNoteMissing("INIT_P2M"))?
 | 
			
		||||
            .value;
 | 
			
		||||
        let mod_start_pfn = xen_notes
 | 
			
		||||
            .get(&XEN_ELFNOTE_MOD_START_PFN)
 | 
			
		||||
            .ok_or(Error::ElfInvalidImage)?
 | 
			
		||||
            .ok_or(Error::ElfXenNoteMissing("MOD_START_PFN"))?
 | 
			
		||||
            .value;
 | 
			
		||||
 | 
			
		||||
        let phys32_entry = xen_notes.get(&XEN_ELFNOTE_PHYS32_ENTRY).map(|x| x.value);
 | 
			
		||||
@ -203,7 +195,9 @@ impl ElfImageLoader {
 | 
			
		||||
        let mut start: u64 = u64::MAX;
 | 
			
		||||
        let mut end: u64 = 0;
 | 
			
		||||
 | 
			
		||||
        let segments = elf.segments().ok_or(Error::ElfInvalidImage)?;
 | 
			
		||||
        let segments = elf
 | 
			
		||||
            .segments()
 | 
			
		||||
            .ok_or(Error::ElfInvalidImage("segments missing"))?;
 | 
			
		||||
 | 
			
		||||
        for header in segments {
 | 
			
		||||
            if (header.p_type != PT_LOAD) || (header.p_flags & (PF_R | PF_W | PF_X)) == 0 {
 | 
			
		||||
@ -221,7 +215,9 @@ impl ElfImageLoader {
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if paddr_offset != u64::MAX && virt_base == u64::MAX {
 | 
			
		||||
            return Err(Error::ElfInvalidImage);
 | 
			
		||||
            return Err(Error::ElfInvalidImage(
 | 
			
		||||
                "paddr_offset specified, but virt_base is not specified",
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let virt_offset = virt_base - paddr_offset;
 | 
			
		||||
@ -247,8 +243,13 @@ impl ElfImageLoader {
 | 
			
		||||
        };
 | 
			
		||||
        Ok(image_info)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn into_elf_bytes(self) -> Arc<Vec<u8>> {
 | 
			
		||||
        self.data
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug)]
 | 
			
		||||
struct ElfNoteValue {
 | 
			
		||||
    value: u64,
 | 
			
		||||
}
 | 
			
		||||
@ -262,7 +263,9 @@ impl BootImageLoader for ElfImageLoader {
 | 
			
		||||
 | 
			
		||||
    async 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(Error::ElfInvalidImage)?;
 | 
			
		||||
        let segments = elf
 | 
			
		||||
            .segments()
 | 
			
		||||
            .ok_or(Error::ElfInvalidImage("segments missing"))?;
 | 
			
		||||
 | 
			
		||||
        debug!(
 | 
			
		||||
            "load dst={:#x} segments={}",
 | 
			
		||||
 | 
			
		||||
@ -28,10 +28,14 @@ pub enum Error {
 | 
			
		||||
    PopulatePhysmapFailed(usize, usize, usize),
 | 
			
		||||
    #[error("unknown elf compression method")]
 | 
			
		||||
    ElfCompressionUnknown,
 | 
			
		||||
    #[error("expected elf image format not found")]
 | 
			
		||||
    ElfInvalidImage,
 | 
			
		||||
    #[error("elf image format invalid: {0}")]
 | 
			
		||||
    ElfInvalidImage(&'static str),
 | 
			
		||||
    #[error("elf linux image not found")]
 | 
			
		||||
    ElfNotLinux,
 | 
			
		||||
    #[error("provided elf image does not contain xen support")]
 | 
			
		||||
    ElfXenSupportMissing,
 | 
			
		||||
    #[error("provided elf image does not contain xen note {0}")]
 | 
			
		||||
    ElfXenNoteMissing(&'static str),
 | 
			
		||||
    #[error("regex error: {0}")]
 | 
			
		||||
    RegexError(#[from] regex::Error),
 | 
			
		||||
    #[error("error: {0}")]
 | 
			
		||||
 | 
			
		||||
@ -4,9 +4,104 @@ pub mod error;
 | 
			
		||||
pub mod mem;
 | 
			
		||||
pub mod sys;
 | 
			
		||||
 | 
			
		||||
use boot::{BootDomain, BootImageInfo, BootImageLoader, BootSetupPlatform};
 | 
			
		||||
use domain::{PlatformKernelConfig, PlatformResourcesConfig};
 | 
			
		||||
use elfloader::ElfImageLoader;
 | 
			
		||||
use error::Result;
 | 
			
		||||
use unsupported::UnsupportedPlatform;
 | 
			
		||||
use xencall::{sys::CreateDomain, XenCall};
 | 
			
		||||
 | 
			
		||||
use crate::error::Error;
 | 
			
		||||
 | 
			
		||||
pub mod domain;
 | 
			
		||||
pub mod unsupported;
 | 
			
		||||
#[cfg(target_arch = "x86_64")]
 | 
			
		||||
pub mod x86pv;
 | 
			
		||||
 | 
			
		||||
#[derive(Clone)]
 | 
			
		||||
pub enum ImageLoader {
 | 
			
		||||
    Elf(ElfImageLoader),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl ImageLoader {
 | 
			
		||||
    async fn parse(&self, hvm: bool) -> Result<BootImageInfo> {
 | 
			
		||||
        match self {
 | 
			
		||||
            ImageLoader::Elf(elf) => elf.parse(hvm).await,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    async fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<()> {
 | 
			
		||||
        match self {
 | 
			
		||||
            ImageLoader::Elf(elf) => elf.load(image_info, dst).await,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Clone, Debug, PartialEq, PartialOrd, Eq, Ord)]
 | 
			
		||||
pub enum RuntimePlatformType {
 | 
			
		||||
    Unsupported,
 | 
			
		||||
    #[cfg(target_arch = "x86_64")]
 | 
			
		||||
    Pv,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl RuntimePlatformType {
 | 
			
		||||
    pub fn create(&self) -> RuntimePlatform {
 | 
			
		||||
        match self {
 | 
			
		||||
            RuntimePlatformType::Unsupported => {
 | 
			
		||||
                RuntimePlatform::Unsupported(UnsupportedPlatform::new())
 | 
			
		||||
            }
 | 
			
		||||
            #[cfg(target_arch = "x86_64")]
 | 
			
		||||
            RuntimePlatformType::Pv => RuntimePlatform::Pv(x86pv::X86PvPlatform::new()),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[allow(clippy::large_enum_variant)]
 | 
			
		||||
pub enum RuntimePlatform {
 | 
			
		||||
    Unsupported(UnsupportedPlatform),
 | 
			
		||||
    #[cfg(target_arch = "x86_64")]
 | 
			
		||||
    Pv(x86pv::X86PvPlatform),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl RuntimePlatform {
 | 
			
		||||
    #[allow(clippy::too_many_arguments)]
 | 
			
		||||
    pub async fn initialize(
 | 
			
		||||
        &mut self,
 | 
			
		||||
        domid: u32,
 | 
			
		||||
        call: XenCall,
 | 
			
		||||
        image_loader: &ImageLoader,
 | 
			
		||||
        kernel: &PlatformKernelConfig,
 | 
			
		||||
        resources: &PlatformResourcesConfig,
 | 
			
		||||
    ) -> Result<BootDomain> {
 | 
			
		||||
        match self {
 | 
			
		||||
            RuntimePlatform::Unsupported(unsupported) => {
 | 
			
		||||
                unsupported
 | 
			
		||||
                    .initialize(domid, call, image_loader, kernel, resources)
 | 
			
		||||
                    .await
 | 
			
		||||
            }
 | 
			
		||||
            #[cfg(target_arch = "x86_64")]
 | 
			
		||||
            RuntimePlatform::Pv(pv) => {
 | 
			
		||||
                pv.initialize(domid, call, image_loader, kernel, resources)
 | 
			
		||||
                    .await
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub async fn boot(&mut self, domid: u32, call: XenCall, domain: &mut BootDomain) -> Result<()> {
 | 
			
		||||
        match self {
 | 
			
		||||
            RuntimePlatform::Unsupported(unsupported) => {
 | 
			
		||||
                unsupported.boot(domid, call, domain).await
 | 
			
		||||
            }
 | 
			
		||||
            #[cfg(target_arch = "x86_64")]
 | 
			
		||||
            RuntimePlatform::Pv(pv) => pv.boot(domid, call, domain).await,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn create_domain(&self, enable_iommu: bool) -> CreateDomain {
 | 
			
		||||
        match self {
 | 
			
		||||
            RuntimePlatform::Unsupported(unsupported) => unsupported.create_domain(enable_iommu),
 | 
			
		||||
            #[cfg(target_arch = "x86_64")]
 | 
			
		||||
            RuntimePlatform::Pv(pv) => pv.create_domain(enable_iommu),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -9,8 +9,8 @@ use log::{debug, trace};
 | 
			
		||||
use nix::errno::Errno;
 | 
			
		||||
use slice_copy::copy;
 | 
			
		||||
use xencall::sys::{
 | 
			
		||||
    x8664VcpuGuestContext, CreateDomain, E820Entry, VcpuGuestContextAny, E820_MAX, E820_RAM,
 | 
			
		||||
    E820_UNUSABLE, MMUEXT_PIN_L4_TABLE, XEN_DOMCTL_CDF_IOMMU,
 | 
			
		||||
    x8664VcpuGuestContext, CreateDomain, VcpuGuestContextAny, MMUEXT_PIN_L4_TABLE,
 | 
			
		||||
    XEN_DOMCTL_CDF_IOMMU,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
use crate::{
 | 
			
		||||
@ -282,52 +282,6 @@ impl X86PvPlatform {
 | 
			
		||||
        self.table.mappings[m] = map;
 | 
			
		||||
        Ok(m)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fn e820_sanitize(
 | 
			
		||||
        &self,
 | 
			
		||||
        mut source: Vec<E820Entry>,
 | 
			
		||||
        map_limit_kb: u64,
 | 
			
		||||
    ) -> Result<Vec<E820Entry>> {
 | 
			
		||||
        let mut e820 = vec![E820Entry::default(); E820_MAX as usize];
 | 
			
		||||
 | 
			
		||||
        for entry in &mut source {
 | 
			
		||||
            if entry.addr > 0x100000 {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // entries under 1MB should be removed.
 | 
			
		||||
            entry.typ = 0;
 | 
			
		||||
            entry.size = 0;
 | 
			
		||||
            entry.addr = u64::MAX;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        let mut lowest = u64::MAX;
 | 
			
		||||
        let mut highest = 0;
 | 
			
		||||
 | 
			
		||||
        for entry in &source {
 | 
			
		||||
            if entry.typ == E820_RAM || entry.typ == E820_UNUSABLE || entry.typ == 0 {
 | 
			
		||||
                continue;
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            lowest = if entry.addr < lowest {
 | 
			
		||||
                entry.addr
 | 
			
		||||
            } else {
 | 
			
		||||
                lowest
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            highest = if entry.addr + entry.size > highest {
 | 
			
		||||
                entry.addr + entry.size
 | 
			
		||||
            } else {
 | 
			
		||||
                highest
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        e820[0].addr = 0;
 | 
			
		||||
        e820[0].size = map_limit_kb << 10;
 | 
			
		||||
        e820[0].typ = E820_RAM;
 | 
			
		||||
 | 
			
		||||
        Ok(e820)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[async_trait::async_trait]
 | 
			
		||||
@ -690,8 +644,10 @@ impl BootSetupPlatform for X86PvPlatform {
 | 
			
		||||
            (*info).store_mfn = domain.phys.p2m[xenstore_segment.pfn as usize];
 | 
			
		||||
            (*info).console.mfn = domain.console_mfn;
 | 
			
		||||
            (*info).console.evtchn = domain.console_evtchn;
 | 
			
		||||
            (*info).mod_start = domain.initrd_segment.vstart;
 | 
			
		||||
            (*info).mod_len = domain.initrd_segment.size;
 | 
			
		||||
            if let Some(ref initrd_segment) = domain.initrd_segment {
 | 
			
		||||
                (*info).mod_start = initrd_segment.vstart;
 | 
			
		||||
                (*info).mod_len = initrd_segment.size;
 | 
			
		||||
            }
 | 
			
		||||
            for (i, c) in domain.cmdline.chars().enumerate() {
 | 
			
		||||
                (*info).cmdline[i] = c as c_char;
 | 
			
		||||
            }
 | 
			
		||||
@ -715,12 +671,6 @@ impl BootSetupPlatform for X86PvPlatform {
 | 
			
		||||
        domain.phys.unmap(pg_pfn)?;
 | 
			
		||||
        domain.phys.unmap(p2m_segment.pfn)?;
 | 
			
		||||
 | 
			
		||||
        let map = domain.call.get_memory_map(E820_MAX).await?;
 | 
			
		||||
        let mem_mb = domain.total_pages >> (20 - self.page_shift());
 | 
			
		||||
        let mem_kb = mem_mb * 1024;
 | 
			
		||||
        let e820 = self.e820_sanitize(map, mem_kb)?;
 | 
			
		||||
        domain.call.set_memory_map(domain.domid, e820).await?;
 | 
			
		||||
 | 
			
		||||
        domain
 | 
			
		||||
            .call
 | 
			
		||||
            .mmuext(domain.domid, MMUEXT_PIN_L4_TABLE, pg_mfn, 0)
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user