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