1use alloc::{string::String, vec::Vec};
19
20use axaddrspace::GuestPhysAddr;
21pub use axvmconfig::{
22 AxVMCrateConfig, EmulatedDeviceConfig, PassThroughAddressConfig, PassThroughDeviceConfig,
23 VMInterruptMode, VMType, VmMemConfig, VmMemMappingType,
24};
25
26use crate::VMMemoryRegion;
27
28const BIOS_RESERVED_SIZE: usize = 2 * 1024 * 1024;
29
30#[derive(Clone, Copy, Debug, Default)]
40pub struct AxVCpuConfig {
41 pub bsp_entry: GuestPhysAddr,
44 pub ap_entry: GuestPhysAddr,
46}
47
48#[derive(Debug, Default, Clone)]
50pub struct RamdiskInfo {
51 pub load_gpa: GuestPhysAddr,
53 pub size: Option<usize>,
55}
56
57#[derive(Debug, Default, Clone)]
59pub struct VMImageConfig {
60 pub kernel_load_gpa: GuestPhysAddr,
62 pub bios_load_gpa: Option<GuestPhysAddr>,
64 pub dtb_load_gpa: Option<GuestPhysAddr>,
66 pub ramdisk: Option<RamdiskInfo>,
68}
69
70#[derive(Debug, Default)]
72pub struct AxVMConfig {
73 id: usize,
74 name: String,
75 #[allow(dead_code)]
76 vm_type: VMType,
77 pub(crate) phys_cpu_ls: PhysCpuList,
78 pub cpu_config: AxVCpuConfig,
80 pub image_config: VMImageConfig,
82 emu_devices: Vec<EmulatedDeviceConfig>,
83 pass_through_devices: Vec<PassThroughDeviceConfig>,
84 excluded_devices: Vec<Vec<String>>,
85 pass_through_addresses: Vec<PassThroughAddressConfig>,
86 spi_list: Vec<u32>,
88 interrupt_mode: VMInterruptMode,
89}
90
91impl From<AxVMCrateConfig> for AxVMConfig {
92 fn from(cfg: AxVMCrateConfig) -> Self {
93 Self {
94 id: cfg.base.id,
95 name: cfg.base.name,
96 vm_type: VMType::from(cfg.base.vm_type),
97 phys_cpu_ls: PhysCpuList {
98 cpu_num: cfg.base.cpu_num,
99 phys_cpu_ids: cfg.base.phys_cpu_ids,
100 phys_cpu_sets: cfg.base.phys_cpu_sets,
101 },
102 cpu_config: AxVCpuConfig {
103 bsp_entry: GuestPhysAddr::from(cfg.kernel.entry_point),
104 ap_entry: GuestPhysAddr::from(cfg.kernel.entry_point),
105 },
106 image_config: VMImageConfig {
107 kernel_load_gpa: GuestPhysAddr::from(cfg.kernel.kernel_load_addr),
108 bios_load_gpa: cfg.kernel.bios_load_addr.map(GuestPhysAddr::from),
109 dtb_load_gpa: cfg.kernel.dtb_load_addr.map(GuestPhysAddr::from),
110 ramdisk: cfg.kernel.ramdisk_load_addr.map(|addr| RamdiskInfo {
111 load_gpa: GuestPhysAddr::from(addr),
112 size: None,
113 }),
114 },
115 emu_devices: cfg.devices.emu_devices,
117 pass_through_devices: cfg.devices.passthrough_devices,
118 excluded_devices: cfg.devices.excluded_devices,
119 pass_through_addresses: cfg.devices.passthrough_addresses,
120 spi_list: Vec::new(),
121 interrupt_mode: cfg.devices.interrupt_mode,
122 }
123 }
124}
125
126pub fn adjusted_kernel_load_gpa(
127 main_memory: &VMMemoryRegion,
128 bios_load_gpa: Option<GuestPhysAddr>,
129) -> Option<GuestPhysAddr> {
130 if !main_memory.is_identical() {
131 return None;
132 }
133
134 let mut kernel_addr = main_memory.gpa;
135 if bios_load_gpa.is_some() {
136 kernel_addr += BIOS_RESERVED_SIZE;
137 }
138 Some(kernel_addr)
139}
140
141impl AxVMConfig {
142 pub fn id(&self) -> usize {
144 self.id
145 }
146
147 pub fn name(&self) -> String {
149 self.name.clone()
150 }
151
152 pub fn image_config(&self) -> &VMImageConfig {
154 &self.image_config
155 }
156
157 pub fn bsp_entry(&self) -> GuestPhysAddr {
159 self.cpu_config.bsp_entry
161 }
162
163 pub fn ap_entry(&self) -> GuestPhysAddr {
165 self.cpu_config.ap_entry
167 }
168
169 pub fn phys_cpu_ls_mut(&mut self) -> &mut PhysCpuList {
171 &mut self.phys_cpu_ls
172 }
173
174 pub fn excluded_devices(&self) -> &Vec<Vec<String>> {
176 &self.excluded_devices
177 }
178
179 pub fn pass_through_addresses(&self) -> &Vec<PassThroughAddressConfig> {
181 &self.pass_through_addresses
182 }
183 pub fn emu_devices(&self) -> &Vec<EmulatedDeviceConfig> {
202 &self.emu_devices
203 }
204
205 pub fn pass_through_devices(&self) -> &Vec<PassThroughDeviceConfig> {
207 &self.pass_through_devices
208 }
209
210 pub fn add_pass_through_device(&mut self, device: PassThroughDeviceConfig) {
212 self.pass_through_devices.push(device);
213 }
214
215 pub fn remove_pass_through_device(&mut self, device: PassThroughDeviceConfig) {
217 self.pass_through_devices.retain(|d| d == &device);
218 }
219
220 pub fn clear_pass_through_devices(&mut self) {
222 self.pass_through_devices.clear();
223 }
224
225 pub fn add_pass_through_spi(&mut self, spi: u32) {
227 self.spi_list.push(spi);
228 }
229
230 pub fn pass_through_spis(&self) -> &Vec<u32> {
232 &self.spi_list
233 }
234
235 pub fn interrupt_mode(&self) -> VMInterruptMode {
237 self.interrupt_mode
238 }
239
240 pub fn relocate_kernel_image(&mut self, kernel_load_gpa: GuestPhysAddr) {
243 let old_load = self.image_config.kernel_load_gpa.as_usize();
244 let new_load = kernel_load_gpa.as_usize();
245
246 let bsp_offset = self
247 .cpu_config
248 .bsp_entry
249 .as_usize()
250 .checked_sub(old_load)
251 .expect("BSP entry must not be below kernel load address");
252 let ap_offset = self
253 .cpu_config
254 .ap_entry
255 .as_usize()
256 .checked_sub(old_load)
257 .expect("AP entry must not be below kernel load address");
258
259 self.image_config.kernel_load_gpa = kernel_load_gpa;
260 self.cpu_config.bsp_entry = GuestPhysAddr::from(new_load + bsp_offset);
261 self.cpu_config.ap_entry = GuestPhysAddr::from(new_load + ap_offset);
262 }
263}
264
265#[derive(Debug, Default, Clone)]
267pub struct PhysCpuList {
268 cpu_num: usize,
269 phys_cpu_ids: Option<Vec<usize>>,
270 phys_cpu_sets: Option<Vec<usize>>,
271}
272
273impl PhysCpuList {
274 pub fn get_vcpu_affinities_pcpu_ids(&self) -> Vec<(usize, Option<usize>, usize)> {
283 let mut vcpu_pcpu_tuples = Vec::new();
284 #[cfg(target_arch = "riscv64")]
285 let mut pcpu_mask_flag = false;
286
287 if let Some(phys_cpu_ids) = &self.phys_cpu_ids
288 && self.cpu_num != phys_cpu_ids.len()
289 {
290 error!(
291 "ERROR!!!: cpu_num: {}, phys_cpu_ids: {:?}",
292 self.cpu_num, self.phys_cpu_ids
293 );
294 }
295
296 for vcpu_id in 0..self.cpu_num {
297 vcpu_pcpu_tuples.push((vcpu_id, None, vcpu_id));
298 }
299
300 #[cfg(target_arch = "riscv64")]
301 if let Some(phys_cpu_sets) = &self.phys_cpu_sets {
302 pcpu_mask_flag = true;
303 for (vcpu_id, pcpu_mask_bitmap) in phys_cpu_sets.iter().enumerate() {
304 vcpu_pcpu_tuples[vcpu_id].1 = Some(*pcpu_mask_bitmap);
305 }
306 }
307
308 #[cfg(not(target_arch = "riscv64"))]
309 if let Some(phys_cpu_sets) = &self.phys_cpu_sets {
310 for (vcpu_id, pcpu_mask_bitmap) in phys_cpu_sets.iter().enumerate() {
311 vcpu_pcpu_tuples[vcpu_id].1 = Some(*pcpu_mask_bitmap);
312 }
313 }
314
315 if let Some(phys_cpu_ids) = &self.phys_cpu_ids {
316 for (vcpu_id, phys_id) in phys_cpu_ids.iter().enumerate() {
317 vcpu_pcpu_tuples[vcpu_id].2 = *phys_id;
318 #[cfg(target_arch = "riscv64")]
319 {
320 if !pcpu_mask_flag {
321 vcpu_pcpu_tuples[vcpu_id].1 = Some(1 << (*phys_id));
323 }
324 }
325 }
326 }
327 vcpu_pcpu_tuples
328 }
329
330 pub fn cpu_num(&self) -> usize {
332 self.cpu_num
333 }
334
335 pub fn phys_cpu_ids(&self) -> &Option<Vec<usize>> {
337 &self.phys_cpu_ids
338 }
339
340 pub fn phys_cpu_sets(&self) -> &Option<Vec<usize>> {
342 &self.phys_cpu_sets
343 }
344
345 pub fn set_guest_cpu_sets(&mut self, phys_cpu_sets: Vec<usize>) {
347 self.phys_cpu_sets = Some(phys_cpu_sets);
348 }
349}