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