xref: /DragonOS/kernel/src/virt/kvm/vm.rs (revision 01c18c64b14b4ebabd98fa92c587c26874275eb1)
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 {
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.
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 
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