1 use crate::arch::kvm::vmx::vcpu::VmxVcpu; 2 use crate::arch::KVMArch; 3 use crate::arch::MMArch; 4 use crate::libs::mutex::Mutex; 5 use crate::mm::MemoryManagementArch; 6 use alloc::sync::Arc; 7 use alloc::vec::Vec; 8 use log::debug; 9 use system_error::SystemError; 10 11 // use super::HOST_STACK_SIZE; 12 use super::host_mem::{ 13 KvmMemoryChange, KvmMemorySlot, KvmMemorySlots, KvmUserspaceMemoryRegion, 14 KVM_ADDRESS_SPACE_NUM, KVM_MEM_LOG_DIRTY_PAGES, KVM_MEM_MAX_NR_PAGES, KVM_MEM_READONLY, 15 KVM_MEM_SLOTS_NUM, KVM_USER_MEM_SLOTS, PAGE_SHIFT, 16 }; 17 18 #[derive(Debug, Clone)] 19 pub struct Vm { 20 pub id: usize, 21 // vcpu config 22 pub nr_vcpus: u32, /* Number of cpus to run */ 23 pub vcpu: Vec<Arc<Mutex<VmxVcpu>>>, 24 // memory config 25 pub nr_mem_slots: u32, /* Number of memory slots in each address space */ 26 pub memslots: [KvmMemorySlots; KVM_ADDRESS_SPACE_NUM], 27 #[allow(dead_code)] 28 // arch related config 29 pub arch: KVMArch, 30 } 31 32 impl Vm { new(id: usize) -> Result<Self, SystemError>33 pub fn new(id: usize) -> Result<Self, SystemError> { 34 let vcpu = Vec::new(); 35 // Allocate stack for vm-exit handlers and fill it with garbage data 36 let instance = Self { 37 id, 38 nr_vcpus: 0, 39 vcpu, 40 nr_mem_slots: KVM_MEM_SLOTS_NUM, 41 memslots: [KvmMemorySlots::default(); KVM_ADDRESS_SPACE_NUM], 42 arch: Default::default(), 43 }; 44 Ok(instance) 45 } 46 47 /// Allocate some memory and give it an address in the guest physical address space. set_user_memory_region( &mut self, mem: &KvmUserspaceMemoryRegion, ) -> Result<(), SystemError>48 pub fn set_user_memory_region( 49 &mut self, 50 mem: &KvmUserspaceMemoryRegion, 51 ) -> Result<(), SystemError> { 52 debug!("set_user_memory_region"); 53 let id: u16 = mem.slot as u16; // slot id 54 let as_id = mem.slot >> 16; // address space id 55 debug!("id={}, as_id={}", id, as_id); 56 57 // 检查slot是否合法 58 if mem.slot as usize >= self.nr_mem_slots as usize { 59 return Err(SystemError::EINVAL); 60 } 61 // 检查flags是否合法 62 self.check_memory_region_flag(mem)?; 63 // 内存大小和地址必须是页对齐的 64 if (mem.memory_size & (MMArch::PAGE_SIZE - 1) as u64) != 0 65 || (mem.guest_phys_addr & (MMArch::PAGE_SIZE - 1) as u64) != 0 66 { 67 return Err(SystemError::EINVAL); 68 } 69 // 检查地址空间是否合法 70 if as_id >= (KVM_ADDRESS_SPACE_NUM as u32) || id >= KVM_MEM_SLOTS_NUM as u16 { 71 return Err(SystemError::EINVAL); 72 } 73 // if mem.memory_size < 0 { 74 // return Err(SystemError::EINVAL); 75 // } 76 let slot = &self.memslots[as_id as usize].memslots[id as usize]; 77 let base_gfn = mem.guest_phys_addr >> PAGE_SHIFT; 78 let npages = mem.memory_size >> PAGE_SHIFT; 79 if npages > KVM_MEM_MAX_NR_PAGES as u64 { 80 return Err(SystemError::EINVAL); 81 } 82 let change: KvmMemoryChange; 83 84 let old_slot = slot; 85 let mut new_slot = KvmMemorySlot { 86 base_gfn, // 虚机内存区间起始物理页框号 87 npages, // 虚机内存区间页数,即内存区间的大小 88 // dirty_bitmap: old_slot.dirty_bitmap, 89 userspace_addr: mem.userspace_addr, // 虚机内存区间对应的主机虚拟地址 90 flags: mem.flags, // 虚机内存区间属性 91 id, // 虚机内存区间id 92 }; 93 94 // 判断新memoryslot的类型 95 if npages != 0 { 96 //映射内存有大小,不是删除内存条 97 if old_slot.npages == 0 { 98 //内存槽号没有虚拟内存条,意味内存新创建 99 change = KvmMemoryChange::Create; 100 } else { 101 //修改已存在的内存,表示修改标志或者平移映射地址 102 // 检查内存条是否可以修改 103 if mem.userspace_addr != old_slot.userspace_addr 104 || npages != old_slot.npages 105 || (new_slot.flags ^ old_slot.flags & KVM_MEM_READONLY) != 0 106 { 107 return Err(SystemError::EINVAL); 108 } 109 if new_slot.base_gfn != old_slot.base_gfn { 110 //guest地址不同,内存条平移 111 change = KvmMemoryChange::Move; 112 } else if new_slot.flags != old_slot.flags { 113 //内存条标志不同,修改标志 114 change = KvmMemoryChange::FlagsOnly; 115 } else { 116 return Ok(()); 117 } 118 } 119 } else { 120 if old_slot.npages == 0 { 121 //内存槽号没有虚拟内存条,不可以删除 122 return Err(SystemError::EINVAL); 123 } 124 //申请插入的内存为0,而内存槽上有内存,意味删除 125 change = KvmMemoryChange::Delete; 126 new_slot.base_gfn = 0; 127 new_slot.flags = 0; 128 } 129 130 if change == KvmMemoryChange::Create || change == KvmMemoryChange::Move { 131 // 检查内存区域是否重叠 132 for i in 0..KVM_MEM_SLOTS_NUM { 133 let memslot = &self.memslots[as_id as usize].memslots[i as usize]; 134 if memslot.id == id || memslot.id as u32 >= KVM_USER_MEM_SLOTS { 135 continue; 136 } 137 // 当前已有的slot与new在guest物理地址上有交集 138 if !(base_gfn + npages <= memslot.base_gfn 139 || memslot.base_gfn + memslot.npages <= base_gfn) 140 { 141 return Err(SystemError::EEXIST); 142 } 143 } 144 } 145 146 if (new_slot.flags & KVM_MEM_LOG_DIRTY_PAGES) == 0 { 147 // new_slot.dirty_bitmap = 0; 148 } 149 150 // 根据flags的值,决定是否创建内存脏页 151 // if (new_slot.flags & KVM_MEM_LOG_DIRTY_PAGES)!=0 && new_slot.dirty_bitmap == 0 { 152 // let type_size = core::mem::size_of::<u64>() as u64; 153 // let dirty_bytes = 2 * ((new_slot.npages+type_size-1) / type_size) / 8; 154 // new_slot.dirty_bitmap = Box::new(vec![0; dirty_bytes as u8]); 155 // } 156 if change == KvmMemoryChange::Create { 157 new_slot.userspace_addr = mem.userspace_addr; 158 let mut memslots = self.memslots[as_id as usize].memslots; 159 memslots[id as usize] = new_slot; 160 self.memslots[as_id as usize].memslots = memslots; 161 self.memslots[as_id as usize].used_slots += 1; 162 // KVMArch::kvm_arch_create_memslot(&mut new_slot, npages); 163 // KVMArch::kvm_arch_commit_memory_region(mem, &new_slot, old_slot, change); 164 } 165 // TODO--KvmMemoryChange::Delete & Move 166 Ok(()) 167 } 168 check_memory_region_flag(&self, mem: &KvmUserspaceMemoryRegion) -> Result<(), SystemError>169 fn check_memory_region_flag(&self, mem: &KvmUserspaceMemoryRegion) -> Result<(), SystemError> { 170 let valid_flags = KVM_MEM_LOG_DIRTY_PAGES; 171 // 除了valid_flags之外的flags被置1了,就返回错误 172 if mem.flags & !valid_flags != 0 { 173 return Err(SystemError::EINVAL); 174 } 175 Ok(()) 176 } 177 } 178