use core::arch::asm;
use hyperlight_common::vmem;
use hyperlight_guest::prim_alloc::alloc_phys_pages;
#[derive(Copy, Clone)]
struct GuestMappingOperations {
scratch_base_gpa: u64,
scratch_base_gva: u64,
}
impl GuestMappingOperations {
fn new() -> Self {
Self {
scratch_base_gpa: hyperlight_guest::layout::scratch_base_gpa(),
scratch_base_gva: hyperlight_guest::layout::scratch_base_gva(),
}
}
fn try_phys_to_virt(&self, addr: u64) -> Option<*mut u8> {
if addr >= self.scratch_base_gpa {
Some((self.scratch_base_gva + (addr - self.scratch_base_gpa)) as *mut u8)
} else {
None
}
}
fn phys_to_virt(&self, addr: u64) -> *mut u8 {
self.try_phys_to_virt(addr)
.expect("phys_to_virt encountered snapshot non-PT page")
}
}
impl core::convert::AsRef<GuestMappingOperations> for GuestMappingOperations {
fn as_ref(&self) -> &Self {
self
}
}
impl vmem::TableReadOps for GuestMappingOperations {
type TableAddr = u64;
fn entry_addr(addr: u64, offset: u64) -> u64 {
addr + offset
}
unsafe fn read_entry(&self, addr: u64) -> u64 {
let addr = self.phys_to_virt(addr);
let ret: u64;
unsafe {
asm!("mov {}, qword ptr [{}]", out(reg) ret, in(reg) addr);
}
ret
}
fn to_phys(addr: u64) -> u64 {
addr
}
fn from_phys(addr: u64) -> u64 {
addr
}
fn root_table(&self) -> u64 {
let pml4_base: u64;
unsafe {
asm!("mov {}, cr3", out(reg) pml4_base);
}
pml4_base & !0xfff
}
}
impl vmem::TableOps for GuestMappingOperations {
type TableMovability = vmem::MayMoveTable;
unsafe fn alloc_table(&self) -> u64 {
let page_addr = unsafe { alloc_phys_pages(1) };
unsafe {
self.phys_to_virt(page_addr)
.write_bytes(0u8, vmem::PAGE_TABLE_SIZE)
};
page_addr
}
unsafe fn write_entry(&self, addr: u64, entry: u64) -> Option<u64> {
let addr = self.phys_to_virt(addr);
unsafe {
asm!("mov qword ptr [{}], {}", in(reg) addr, in(reg) entry);
}
None
}
unsafe fn update_root(&self, new_root: u64) {
unsafe {
core::arch::asm!("mov cr3, {}", in(reg) <Self as vmem::TableReadOps>::to_phys(new_root));
}
}
}
pub unsafe fn map_region(phys_base: u64, virt_base: *mut u8, len: u64, kind: vmem::MappingKind) {
unsafe {
vmem::map(
&GuestMappingOperations::new(),
vmem::Mapping {
phys_base,
virt_base: virt_base as u64,
len,
kind,
},
);
}
}
pub fn virt_to_phys(gva: vmem::VirtAddr) -> impl Iterator<Item = vmem::Mapping> {
unsafe { vmem::virt_to_phys::<_>(GuestMappingOperations::new(), gva, 1) }
}
pub fn phys_to_virt(gpa: vmem::PhysAddr) -> Option<*mut u8> {
GuestMappingOperations::new().try_phys_to_virt(gpa)
}
pub mod barrier {
#[inline(always)]
pub fn first_valid_same_ctx() {
unsafe {
core::arch::asm!("
mov rax, cr0
mov cr0, rax
", out("rax") _);
}
}
}