host_mem.rs 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. use super::{vcpu::Vcpu, vm};
  2. use crate::{
  3. kdebug,
  4. mm::{kernel_mapper::KernelMapper, page::PageFlags, VirtAddr},
  5. syscall::SystemError,
  6. };
  7. /*
  8. * Address types:
  9. *
  10. * gva - guest virtual address
  11. * gpa - guest physical address
  12. * gfn - guest frame number
  13. * hva - host virtual address
  14. * hpa - host physical address
  15. * hfn - host frame number
  16. */
  17. pub const KVM_USER_MEM_SLOTS: u32 = 16;
  18. pub const KVM_PRIVATE_MEM_SLOTS: u32 = 3;
  19. pub const KVM_MEM_SLOTS_NUM: u32 = KVM_USER_MEM_SLOTS + KVM_PRIVATE_MEM_SLOTS;
  20. pub const KVM_ADDRESS_SPACE_NUM: usize = 2;
  21. pub const KVM_MEM_LOG_DIRTY_PAGES: u32 = 1 << 0;
  22. pub const KVM_MEM_READONLY: u32 = 1 << 1;
  23. pub const KVM_MEM_MAX_NR_PAGES: u32 = (1 << 31) - 1;
  24. /*
  25. * The bit 16 ~ bit 31 of kvm_memory_region::flags are internally used
  26. * in kvm, other bits are visible for userspace which are defined in
  27. * include/linux/kvm_h.
  28. */
  29. pub const KVM_MEMSLOT_INVALID: u32 = 1 << 16;
  30. // pub const KVM_MEMSLOT_INCOHERENT:u32 = 1 << 17;
  31. // pub const KVM_PERMILLE_MMU_PAGES: u32 = 20; // the proportion of MMU pages required per thousand (out of 1000) memory pages.
  32. // pub const KVM_MIN_ALLOC_MMU_PAGES: u32 = 64;
  33. pub const PAGE_SHIFT: u32 = 12;
  34. pub const PAGE_SIZE: u32 = 1 << PAGE_SHIFT;
  35. pub const PAGE_MASK: u32 = !(PAGE_SIZE - 1);
  36. #[repr(C)]
  37. /// 通过这个结构可以将虚拟机的物理地址对应到用户进程的虚拟地址
  38. /// 用来表示虚拟机的一段物理内存
  39. pub struct KvmUserspaceMemoryRegion {
  40. pub slot: u32, // 要在哪个slot上注册内存区间
  41. // flags有两个取值,KVM_MEM_LOG_DIRTY_PAGES和KVM_MEM_READONLY,用来指示kvm针对这段内存应该做的事情。
  42. // KVM_MEM_LOG_DIRTY_PAGES用来开启内存脏页,KVM_MEM_READONLY用来开启内存只读。
  43. pub flags: u32,
  44. pub guest_phys_addr: u64, // 虚机内存区间起始物理地址
  45. pub memory_size: u64, // 虚机内存区间大小
  46. pub userspace_addr: u64, // 虚机内存区间对应的主机虚拟地址
  47. }
  48. #[derive(Default, Clone, Copy, Debug)]
  49. pub struct KvmMemorySlot {
  50. pub base_gfn: u64, // 虚机内存区间起始物理页框号
  51. pub npages: u64, // 虚机内存区间页数,即内存区间的大小
  52. pub userspace_addr: u64, // 虚机内存区间对应的主机虚拟地址
  53. pub flags: u32, // 虚机内存区间属性
  54. pub id: u16, // 虚机内存区间id
  55. // 用来记录虚机内存区间的脏页信息,每个bit对应一个页,如果bit为1,表示对应的页是脏页,如果bit为0,表示对应的页是干净页。
  56. // pub dirty_bitmap: *mut u8,
  57. // unsigned long *rmap[KVM_NR_PAGE_SIZES]; 反向映射相关的结构, 创建EPT页表项时就记录GPA对应的页表项地址(GPA-->页表项地址),暂时不需要
  58. }
  59. #[derive(Default, Clone, Copy, Debug)]
  60. pub struct KvmMemorySlots {
  61. pub memslots: [KvmMemorySlot; KVM_MEM_SLOTS_NUM as usize], // 虚机内存区间数组
  62. pub used_slots: u32, // 已经使用的slot数量
  63. }
  64. #[derive(PartialEq, Eq, Debug)]
  65. pub enum KvmMemoryChange {
  66. Create,
  67. Delete,
  68. Move,
  69. FlagsOnly,
  70. }
  71. impl Default for KvmUserspaceMemoryRegion {
  72. fn default() -> KvmUserspaceMemoryRegion {
  73. KvmUserspaceMemoryRegion {
  74. slot: 0,
  75. flags: 0,
  76. guest_phys_addr: 0,
  77. memory_size: 0,
  78. userspace_addr: 0,
  79. }
  80. }
  81. }
  82. pub fn kvm_vcpu_memslots(_vcpu: &mut dyn Vcpu) -> KvmMemorySlots {
  83. let kvm = vm(0).unwrap();
  84. let as_id = 0;
  85. return kvm.memslots[as_id];
  86. }
  87. fn __gfn_to_memslot(slots: KvmMemorySlots, gfn: u64) -> Option<KvmMemorySlot> {
  88. kdebug!("__gfn_to_memslot");
  89. // TODO: 使用二分查找的方式优化
  90. for i in 0..slots.used_slots {
  91. let memslot = slots.memslots[i as usize];
  92. if gfn >= memslot.base_gfn && gfn < memslot.base_gfn + memslot.npages {
  93. return Some(memslot);
  94. }
  95. }
  96. return None;
  97. }
  98. fn __gfn_to_hva(slot: KvmMemorySlot, gfn: u64) -> u64 {
  99. return slot.userspace_addr + (gfn - slot.base_gfn) * (PAGE_SIZE as u64);
  100. }
  101. fn __gfn_to_hva_many(
  102. slot: Option<KvmMemorySlot>,
  103. gfn: u64,
  104. nr_pages: Option<&mut u64>,
  105. write: bool,
  106. ) -> Result<u64, SystemError> {
  107. kdebug!("__gfn_to_hva_many");
  108. if slot.is_none() {
  109. return Err(SystemError::KVM_HVA_ERR_BAD);
  110. }
  111. let slot = slot.unwrap();
  112. if slot.flags & KVM_MEMSLOT_INVALID != 0 || (slot.flags & KVM_MEM_READONLY != 0) && write {
  113. return Err(SystemError::KVM_HVA_ERR_BAD);
  114. }
  115. if nr_pages.is_some() {
  116. let nr_pages = nr_pages.unwrap();
  117. *nr_pages = slot.npages - (gfn - slot.base_gfn);
  118. }
  119. return Ok(__gfn_to_hva(slot, gfn));
  120. }
  121. /* From Linux kernel
  122. * Pin guest page in memory and return its pfn.
  123. * @addr: host virtual address which maps memory to the guest
  124. * @atomic: whether this function can sleep
  125. * @async: whether this function need to wait IO complete if the
  126. * host page is not in the memory
  127. * @write_fault: whether we should get a writable host page
  128. * @writable: whether it allows to map a writable host page for !@write_fault
  129. *
  130. * The function will map a writable host page for these two cases:
  131. * 1): @write_fault = true
  132. * 2): @write_fault = false && @writable, @writable will tell the caller
  133. * whether the mapping is writable.
  134. */
  135. // 计算 HVA 对应的 pfn,同时确保该物理页在内存中
  136. // host端虚拟地址到物理地址的转换,有两种方式,hva_to_pfn_fast、hva_to_pfn_slow
  137. // 正确性待验证
  138. fn hva_to_pfn(addr: u64, _atomic: bool, _writable: &mut bool) -> Result<u64, SystemError> {
  139. kdebug!("hva_to_pfn");
  140. unsafe {
  141. let raw = addr as *const i32;
  142. kdebug!("raw={:x}", *raw);
  143. }
  144. // let hpa = MMArch::virt_2_phys(VirtAddr::new(addr)).unwrap().data() as u64;
  145. let hva = VirtAddr::new(addr as usize);
  146. let mut mapper = KernelMapper::lock();
  147. let mapper = mapper.as_mut().unwrap();
  148. if let Some((hpa, _)) = mapper.translate(hva) {
  149. return Ok(hpa.data() as u64 >> PAGE_SHIFT);
  150. }
  151. unsafe {
  152. mapper.map(hva, PageFlags::mmio_flags());
  153. }
  154. let (hpa, _) = mapper.translate(hva).unwrap();
  155. return Ok(hpa.data() as u64 >> PAGE_SHIFT);
  156. }
  157. pub fn __gfn_to_pfn(
  158. slot: Option<KvmMemorySlot>,
  159. gfn: u64,
  160. atomic: bool,
  161. write: bool,
  162. writable: &mut bool,
  163. ) -> Result<u64, SystemError> {
  164. kdebug!("__gfn_to_pfn");
  165. let mut nr_pages = 0;
  166. let addr = __gfn_to_hva_many(slot, gfn, Some(&mut nr_pages), write)?;
  167. let pfn = hva_to_pfn(addr, atomic, writable)?;
  168. kdebug!("hva={}, pfn={}", addr, pfn);
  169. return Ok(pfn);
  170. }
  171. pub fn kvm_vcpu_gfn_to_memslot(vcpu: &mut dyn Vcpu, gfn: u64) -> Option<KvmMemorySlot> {
  172. return __gfn_to_memslot(kvm_vcpu_memslots(vcpu), gfn);
  173. }