xref: /DragonOS/kernel/src/virt/kvm/host_mem.rs (revision cf7f801e1d50ee5b04cb728e4251a57f4183bfbc)
12eab6dd7S曾俊 use log::debug;
291e9d4abSLoGin use system_error::SystemError;
391e9d4abSLoGin 
440314b30SXiaoye Zheng use super::{vcpu::Vcpu, vm};
5*cf7f801eSMemoryShore use crate::mm::{kernel_mapper::KernelMapper, page::EntryFlags, VirtAddr};
640314b30SXiaoye Zheng 
740314b30SXiaoye Zheng /*
840314b30SXiaoye Zheng  * Address types:
940314b30SXiaoye Zheng  *
1040314b30SXiaoye Zheng  *  gva - guest virtual address
1140314b30SXiaoye Zheng  *  gpa - guest physical address
1240314b30SXiaoye Zheng  *  gfn - guest frame number
1340314b30SXiaoye Zheng  *  hva - host virtual address
1440314b30SXiaoye Zheng  *  hpa - host physical address
1540314b30SXiaoye Zheng  *  hfn - host frame number
1640314b30SXiaoye Zheng  */
1740314b30SXiaoye Zheng pub const KVM_USER_MEM_SLOTS: u32 = 16;
1840314b30SXiaoye Zheng pub const KVM_PRIVATE_MEM_SLOTS: u32 = 3;
1940314b30SXiaoye Zheng pub const KVM_MEM_SLOTS_NUM: u32 = KVM_USER_MEM_SLOTS + KVM_PRIVATE_MEM_SLOTS;
2040314b30SXiaoye Zheng pub const KVM_ADDRESS_SPACE_NUM: usize = 2;
2140314b30SXiaoye Zheng 
2240314b30SXiaoye Zheng pub const KVM_MEM_LOG_DIRTY_PAGES: u32 = 1 << 0;
2340314b30SXiaoye Zheng pub const KVM_MEM_READONLY: u32 = 1 << 1;
2440314b30SXiaoye Zheng pub const KVM_MEM_MAX_NR_PAGES: u32 = (1 << 31) - 1;
2540314b30SXiaoye Zheng 
2640314b30SXiaoye Zheng /*
2740314b30SXiaoye Zheng  * The bit 16 ~ bit 31 of kvm_memory_region::flags are internally used
2840314b30SXiaoye Zheng  * in kvm, other bits are visible for userspace which are defined in
2940314b30SXiaoye Zheng  * include/linux/kvm_h.
3040314b30SXiaoye Zheng  */
3140314b30SXiaoye Zheng pub const KVM_MEMSLOT_INVALID: u32 = 1 << 16;
3240314b30SXiaoye Zheng // pub const  KVM_MEMSLOT_INCOHERENT:u32 = 1 << 17;
3340314b30SXiaoye Zheng 
3440314b30SXiaoye Zheng // pub const KVM_PERMILLE_MMU_PAGES: u32 = 20; //  the proportion of MMU pages required per thousand (out of 1000) memory pages.
3540314b30SXiaoye Zheng // pub const KVM_MIN_ALLOC_MMU_PAGES: u32 = 64;
3640314b30SXiaoye Zheng 
3740314b30SXiaoye Zheng pub const PAGE_SHIFT: u32 = 12;
3840314b30SXiaoye Zheng pub const PAGE_SIZE: u32 = 1 << PAGE_SHIFT;
3940314b30SXiaoye Zheng pub const PAGE_MASK: u32 = !(PAGE_SIZE - 1);
4040314b30SXiaoye Zheng 
4140314b30SXiaoye Zheng /// 通过这个结构可以将虚拟机的物理地址对应到用户进程的虚拟地址
4240314b30SXiaoye Zheng /// 用来表示虚拟机的一段物理内存
43840045afSLoGin #[repr(C)]
44840045afSLoGin #[derive(Default)]
4540314b30SXiaoye Zheng pub struct KvmUserspaceMemoryRegion {
4640314b30SXiaoye Zheng     pub slot: u32, // 要在哪个slot上注册内存区间
4740314b30SXiaoye Zheng     // flags有两个取值,KVM_MEM_LOG_DIRTY_PAGES和KVM_MEM_READONLY,用来指示kvm针对这段内存应该做的事情。
4840314b30SXiaoye Zheng     // KVM_MEM_LOG_DIRTY_PAGES用来开启内存脏页,KVM_MEM_READONLY用来开启内存只读。
4940314b30SXiaoye Zheng     pub flags: u32,
5040314b30SXiaoye Zheng     pub guest_phys_addr: u64, // 虚机内存区间起始物理地址
5140314b30SXiaoye Zheng     pub memory_size: u64,     // 虚机内存区间大小
5240314b30SXiaoye Zheng     pub userspace_addr: u64,  // 虚机内存区间对应的主机虚拟地址
5340314b30SXiaoye Zheng }
5440314b30SXiaoye Zheng 
5540314b30SXiaoye Zheng #[derive(Default, Clone, Copy, Debug)]
5640314b30SXiaoye Zheng pub struct KvmMemorySlot {
5740314b30SXiaoye Zheng     pub base_gfn: u64,       // 虚机内存区间起始物理页框号
5840314b30SXiaoye Zheng     pub npages: u64,         // 虚机内存区间页数,即内存区间的大小
5940314b30SXiaoye Zheng     pub userspace_addr: u64, // 虚机内存区间对应的主机虚拟地址
6040314b30SXiaoye Zheng     pub flags: u32,          // 虚机内存区间属性
6140314b30SXiaoye Zheng     pub id: u16,             // 虚机内存区间id
6240314b30SXiaoye Zheng                              // 用来记录虚机内存区间的脏页信息,每个bit对应一个页,如果bit为1,表示对应的页是脏页,如果bit为0,表示对应的页是干净页。
6340314b30SXiaoye Zheng                              // pub dirty_bitmap: *mut u8,
6440314b30SXiaoye Zheng                              // unsigned long *rmap[KVM_NR_PAGE_SIZES]; 反向映射相关的结构, 创建EPT页表项时就记录GPA对应的页表项地址(GPA-->页表项地址),暂时不需要
6540314b30SXiaoye Zheng }
6640314b30SXiaoye Zheng 
6740314b30SXiaoye Zheng #[derive(Default, Clone, Copy, Debug)]
6840314b30SXiaoye Zheng pub struct KvmMemorySlots {
6940314b30SXiaoye Zheng     pub memslots: [KvmMemorySlot; KVM_MEM_SLOTS_NUM as usize], // 虚机内存区间数组
7040314b30SXiaoye Zheng     pub used_slots: u32,                                       // 已经使用的slot数量
7140314b30SXiaoye Zheng }
7240314b30SXiaoye Zheng 
7340314b30SXiaoye Zheng #[derive(PartialEq, Eq, Debug)]
7440314b30SXiaoye Zheng pub enum KvmMemoryChange {
7540314b30SXiaoye Zheng     Create,
7640314b30SXiaoye Zheng     Delete,
7740314b30SXiaoye Zheng     Move,
7840314b30SXiaoye Zheng     FlagsOnly,
7940314b30SXiaoye Zheng }
8040314b30SXiaoye Zheng 
kvm_vcpu_memslots(_vcpu: &mut dyn Vcpu) -> KvmMemorySlots8140314b30SXiaoye Zheng pub fn kvm_vcpu_memslots(_vcpu: &mut dyn Vcpu) -> KvmMemorySlots {
8240314b30SXiaoye Zheng     let kvm = vm(0).unwrap();
8340314b30SXiaoye Zheng     let as_id = 0;
8440314b30SXiaoye Zheng     return kvm.memslots[as_id];
8540314b30SXiaoye Zheng }
8640314b30SXiaoye Zheng 
__gfn_to_memslot(slots: KvmMemorySlots, gfn: u64) -> Option<KvmMemorySlot>8740314b30SXiaoye Zheng fn __gfn_to_memslot(slots: KvmMemorySlots, gfn: u64) -> Option<KvmMemorySlot> {
882eab6dd7S曾俊     debug!("__gfn_to_memslot");
8940314b30SXiaoye Zheng     // TODO: 使用二分查找的方式优化
9040314b30SXiaoye Zheng     for i in 0..slots.used_slots {
9140314b30SXiaoye Zheng         let memslot = slots.memslots[i as usize];
9240314b30SXiaoye Zheng         if gfn >= memslot.base_gfn && gfn < memslot.base_gfn + memslot.npages {
9340314b30SXiaoye Zheng             return Some(memslot);
9440314b30SXiaoye Zheng         }
9540314b30SXiaoye Zheng     }
9640314b30SXiaoye Zheng     return None;
9740314b30SXiaoye Zheng }
9840314b30SXiaoye Zheng 
__gfn_to_hva(slot: KvmMemorySlot, gfn: u64) -> u649940314b30SXiaoye Zheng fn __gfn_to_hva(slot: KvmMemorySlot, gfn: u64) -> u64 {
10040314b30SXiaoye Zheng     return slot.userspace_addr + (gfn - slot.base_gfn) * (PAGE_SIZE as u64);
10140314b30SXiaoye Zheng }
__gfn_to_hva_many( slot: Option<KvmMemorySlot>, gfn: u64, nr_pages: Option<&mut u64>, write: bool, ) -> Result<u64, SystemError>10240314b30SXiaoye Zheng fn __gfn_to_hva_many(
10340314b30SXiaoye Zheng     slot: Option<KvmMemorySlot>,
10440314b30SXiaoye Zheng     gfn: u64,
10540314b30SXiaoye Zheng     nr_pages: Option<&mut u64>,
10640314b30SXiaoye Zheng     write: bool,
10740314b30SXiaoye Zheng ) -> Result<u64, SystemError> {
1082eab6dd7S曾俊     debug!("__gfn_to_hva_many");
10940314b30SXiaoye Zheng     if slot.is_none() {
11040314b30SXiaoye Zheng         return Err(SystemError::KVM_HVA_ERR_BAD);
11140314b30SXiaoye Zheng     }
11240314b30SXiaoye Zheng     let slot = slot.unwrap();
11340314b30SXiaoye Zheng     if slot.flags & KVM_MEMSLOT_INVALID != 0 || (slot.flags & KVM_MEM_READONLY != 0) && write {
11440314b30SXiaoye Zheng         return Err(SystemError::KVM_HVA_ERR_BAD);
11540314b30SXiaoye Zheng     }
11640314b30SXiaoye Zheng 
117840045afSLoGin     if let Some(nr_pages) = nr_pages {
11840314b30SXiaoye Zheng         *nr_pages = slot.npages - (gfn - slot.base_gfn);
11940314b30SXiaoye Zheng     }
120840045afSLoGin 
12140314b30SXiaoye Zheng     return Ok(__gfn_to_hva(slot, gfn));
12240314b30SXiaoye Zheng }
12340314b30SXiaoye Zheng 
12440314b30SXiaoye Zheng /* From Linux kernel
12540314b30SXiaoye Zheng  * Pin guest page in memory and return its pfn.
12640314b30SXiaoye Zheng  * @addr: host virtual address which maps memory to the guest
12740314b30SXiaoye Zheng  * @atomic: whether this function can sleep
12840314b30SXiaoye Zheng  * @async: whether this function need to wait IO complete if the
12940314b30SXiaoye Zheng  *         host page is not in the memory
13040314b30SXiaoye Zheng  * @write_fault: whether we should get a writable host page
13140314b30SXiaoye Zheng  * @writable: whether it allows to map a writable host page for !@write_fault
13240314b30SXiaoye Zheng  *
13340314b30SXiaoye Zheng  * The function will map a writable host page for these two cases:
13440314b30SXiaoye Zheng  * 1): @write_fault = true
13540314b30SXiaoye Zheng  * 2): @write_fault = false && @writable, @writable will tell the caller
13640314b30SXiaoye Zheng  *     whether the mapping is writable.
13740314b30SXiaoye Zheng  */
13840314b30SXiaoye Zheng // 计算 HVA 对应的 pfn,同时确保该物理页在内存中
13940314b30SXiaoye Zheng // host端虚拟地址到物理地址的转换,有两种方式,hva_to_pfn_fast、hva_to_pfn_slow
14040314b30SXiaoye Zheng // 正确性待验证
hva_to_pfn(addr: u64, _atomic: bool, _writable: &mut bool) -> Result<u64, SystemError>14140314b30SXiaoye Zheng fn hva_to_pfn(addr: u64, _atomic: bool, _writable: &mut bool) -> Result<u64, SystemError> {
1422eab6dd7S曾俊     debug!("hva_to_pfn");
14340314b30SXiaoye Zheng     unsafe {
14440314b30SXiaoye Zheng         let raw = addr as *const i32;
1452eab6dd7S曾俊         debug!("raw={:x}", *raw);
14640314b30SXiaoye Zheng     }
14740314b30SXiaoye Zheng     // let hpa = MMArch::virt_2_phys(VirtAddr::new(addr)).unwrap().data() as u64;
14840314b30SXiaoye Zheng     let hva = VirtAddr::new(addr as usize);
14940314b30SXiaoye Zheng     let mut mapper = KernelMapper::lock();
15040314b30SXiaoye Zheng     let mapper = mapper.as_mut().unwrap();
15140314b30SXiaoye Zheng     if let Some((hpa, _)) = mapper.translate(hva) {
15240314b30SXiaoye Zheng         return Ok(hpa.data() as u64 >> PAGE_SHIFT);
15340314b30SXiaoye Zheng     }
15440314b30SXiaoye Zheng     unsafe {
155*cf7f801eSMemoryShore         mapper.map(hva, EntryFlags::mmio_flags());
15640314b30SXiaoye Zheng     }
15740314b30SXiaoye Zheng     let (hpa, _) = mapper.translate(hva).unwrap();
15840314b30SXiaoye Zheng     return Ok(hpa.data() as u64 >> PAGE_SHIFT);
15940314b30SXiaoye Zheng }
16040314b30SXiaoye Zheng 
__gfn_to_pfn( slot: Option<KvmMemorySlot>, gfn: u64, atomic: bool, write: bool, writable: &mut bool, ) -> Result<u64, SystemError>16140314b30SXiaoye Zheng pub fn __gfn_to_pfn(
16240314b30SXiaoye Zheng     slot: Option<KvmMemorySlot>,
16340314b30SXiaoye Zheng     gfn: u64,
16440314b30SXiaoye Zheng     atomic: bool,
16540314b30SXiaoye Zheng     write: bool,
16640314b30SXiaoye Zheng     writable: &mut bool,
16740314b30SXiaoye Zheng ) -> Result<u64, SystemError> {
1682eab6dd7S曾俊     debug!("__gfn_to_pfn");
16940314b30SXiaoye Zheng     let mut nr_pages = 0;
17040314b30SXiaoye Zheng     let addr = __gfn_to_hva_many(slot, gfn, Some(&mut nr_pages), write)?;
17140314b30SXiaoye Zheng     let pfn = hva_to_pfn(addr, atomic, writable)?;
1722eab6dd7S曾俊     debug!("hva={}, pfn={}", addr, pfn);
17340314b30SXiaoye Zheng     return Ok(pfn);
17440314b30SXiaoye Zheng }
17540314b30SXiaoye Zheng 
kvm_vcpu_gfn_to_memslot(vcpu: &mut dyn Vcpu, gfn: u64) -> Option<KvmMemorySlot>17640314b30SXiaoye Zheng pub fn kvm_vcpu_gfn_to_memslot(vcpu: &mut dyn Vcpu, gfn: u64) -> Option<KvmMemorySlot> {
17740314b30SXiaoye Zheng     return __gfn_to_memslot(kvm_vcpu_memslots(vcpu), gfn);
17840314b30SXiaoye Zheng }
179