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