1use std::sync::Arc;
2
3use crate::{
4 boot::BootDomain, elfloader::ElfImageLoader, error::Error, ImageLoader, RuntimePlatform,
5 RuntimePlatformType,
6};
7use log::warn;
8use uuid::Uuid;
9use xencall::XenCall;
10
11use crate::error::Result;
12
13pub const XEN_EXTRA_MEMORY_KB: u64 = 2048;
14
15pub struct PlatformDomainManager {
16 call: XenCall,
17}
18
19impl PlatformDomainManager {
20 pub async fn new(call: XenCall) -> Result<PlatformDomainManager> {
21 Ok(PlatformDomainManager { call })
22 }
23
24 fn max_memory_kb(resources: &PlatformResourcesConfig) -> u64 {
25 (resources.max_memory_mb * 1024) + XEN_EXTRA_MEMORY_KB
26 }
27
28 async fn create_base_domain(
29 &self,
30 config: &PlatformDomainConfig,
31 platform: &RuntimePlatform,
32 ) -> Result<u32> {
33 let mut domain = platform.create_domain(config.options.iommu);
34 domain.handle = config.uuid.into_bytes();
35 domain.max_vcpus = config.resources.max_vcpus;
36 let domid = self.call.create_domain(domain).await?;
37 Ok(domid)
38 }
39
40 async fn configure_domain_resources(
41 &self,
42 domid: u32,
43 config: &PlatformDomainConfig,
44 ) -> Result<()> {
45 self.call
46 .set_max_vcpus(domid, config.resources.max_vcpus)
47 .await?;
48 self.call
49 .set_max_mem(
50 domid,
51 PlatformDomainManager::max_memory_kb(&config.resources),
52 )
53 .await?;
54 Ok(())
55 }
56
57 async fn create_internal(
58 &self,
59 domid: u32,
60 config: &PlatformDomainConfig,
61 mut platform: RuntimePlatform,
62 ) -> Result<BootDomain> {
63 self.configure_domain_resources(domid, config).await?;
64 let kernel = config.kernel.clone();
65 let loader = tokio::task::spawn_blocking(move || match kernel.format {
66 KernelFormat::ElfCompressed => ElfImageLoader::load(kernel.data),
67 KernelFormat::ElfUncompressed => Ok(ElfImageLoader::new(kernel.data)),
68 })
69 .await
70 .map_err(Error::AsyncJoinError)??;
71 let loader = ImageLoader::Elf(loader);
72 let mut domain = platform
73 .initialize(
74 domid,
75 self.call.clone(),
76 &loader,
77 &config.kernel,
78 &config.resources,
79 )
80 .await?;
81 platform.boot(domid, self.call.clone(), &mut domain).await?;
82 Ok(domain)
83 }
84
85 pub async fn create(&self, config: PlatformDomainConfig) -> Result<PlatformDomainInfo> {
86 let platform = config.platform.create();
87 let domid = self.create_base_domain(&config, &platform).await?;
88 let domain = match self.create_internal(domid, &config, platform).await {
89 Ok(domain) => domain,
90 Err(error) => {
91 if let Err(destroy_fail) = self.call.destroy_domain(domid).await {
92 warn!(
93 "failed to destroy failed domain {}: {}",
94 domid, destroy_fail
95 );
96 }
97 return Err(error);
98 }
99 };
100 Ok(PlatformDomainInfo {
101 domid,
102 store_evtchn: domain.store_evtchn,
103 store_mfn: domain.store_mfn,
104 console_evtchn: domain.console_evtchn,
105 console_mfn: domain.console_mfn,
106 })
107 }
108
109 pub async fn destroy(&self, domid: u32) -> Result<()> {
110 self.call.destroy_domain(domid).await?;
111 Ok(())
112 }
113}
114
115#[derive(Clone, Debug)]
116pub struct PlatformDomainConfig {
117 pub uuid: Uuid,
118 pub platform: RuntimePlatformType,
119 pub resources: PlatformResourcesConfig,
120 pub kernel: PlatformKernelConfig,
121 pub options: PlatformOptions,
122}
123
124#[derive(Clone, Debug)]
125pub struct PlatformKernelConfig {
126 pub data: Arc<Vec<u8>>,
127 pub format: KernelFormat,
128 pub initrd: Option<Arc<Vec<u8>>>,
129 pub cmdline: String,
130}
131
132#[derive(Clone, Debug)]
133pub struct PlatformResourcesConfig {
134 pub max_vcpus: u32,
135 pub assigned_vcpus: u32,
136 pub max_memory_mb: u64,
137 pub assigned_memory_mb: u64,
138}
139
140#[derive(Clone, Debug)]
141pub struct PlatformOptions {
142 pub iommu: bool,
143}
144
145#[derive(Clone, Debug)]
146pub enum KernelFormat {
147 ElfUncompressed,
148 ElfCompressed,
149}
150
151#[derive(Clone, Debug)]
152pub struct PlatformDomainInfo {
153 pub domid: u32,
154 pub store_evtchn: u32,
155 pub store_mfn: u64,
156 pub console_evtchn: u32,
157 pub console_mfn: u64,
158}