2024-01-10 16:07:57 -08:00
|
|
|
use crate::sys::XEN_PAGE_SHIFT;
|
|
|
|
use crate::XenClientError;
|
|
|
|
|
2024-01-11 23:54:44 -08:00
|
|
|
use crate::x86::X86_PAGE_SHIFT;
|
2024-01-10 16:07:57 -08:00
|
|
|
use xencall::sys::MmapEntry;
|
|
|
|
use xencall::XenCall;
|
|
|
|
|
|
|
|
pub struct PhysicalPage {
|
|
|
|
pfn: u64,
|
|
|
|
ptr: u64,
|
2024-01-10 19:18:48 -08:00
|
|
|
count: u64,
|
2024-01-10 16:07:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct PhysicalPages<'a> {
|
|
|
|
domid: u32,
|
2024-01-11 17:23:09 -08:00
|
|
|
pub(crate) p2m: Vec<u64>,
|
2024-01-10 16:07:57 -08:00
|
|
|
call: &'a XenCall,
|
|
|
|
pages: Vec<PhysicalPage>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl PhysicalPages<'_> {
|
|
|
|
pub fn new(call: &XenCall, domid: u32) -> PhysicalPages {
|
|
|
|
PhysicalPages {
|
|
|
|
domid,
|
|
|
|
p2m: Vec::new(),
|
|
|
|
call,
|
|
|
|
pages: Vec::new(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn load_p2m(&mut self, p2m: Vec<u64>) {
|
|
|
|
self.p2m = p2m;
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:23:09 -08:00
|
|
|
pub fn p2m_size(&mut self) -> u64 {
|
|
|
|
self.p2m.len() as u64
|
|
|
|
}
|
|
|
|
|
2024-01-10 16:07:57 -08:00
|
|
|
pub fn pfn_to_ptr(&mut self, pfn: u64, count: u64) -> Result<u64, XenClientError> {
|
|
|
|
for page in &self.pages {
|
2024-01-10 19:18:48 -08:00
|
|
|
if pfn >= page.pfn + page.count {
|
2024-01-10 16:07:57 -08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if count > 0 {
|
|
|
|
if (pfn + count) <= page.pfn {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-01-10 19:18:48 -08:00
|
|
|
if pfn < page.pfn || (pfn + count) > page.pfn + page.count {
|
2024-01-10 16:07:57 -08:00
|
|
|
return Err(XenClientError::new("request overlaps allocated block"));
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if pfn < page.pfn {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-01-10 19:18:48 -08:00
|
|
|
if pfn >= page.pfn + page.count {
|
2024-01-10 16:07:57 -08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-11 23:54:44 -08:00
|
|
|
return Ok(page.ptr + ((pfn - page.pfn) << X86_PAGE_SHIFT));
|
2024-01-10 16:07:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
if count == 0 {
|
|
|
|
return Err(XenClientError::new(
|
|
|
|
"allocation is only allowed when a size is given",
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
self.pfn_alloc(pfn, count)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn pfn_alloc(&mut self, pfn: u64, count: u64) -> Result<u64, XenClientError> {
|
|
|
|
let mut entries = vec![MmapEntry::default(); count as usize];
|
2024-01-15 16:25:06 -08:00
|
|
|
for (i, entry) in entries.iter_mut().enumerate() {
|
|
|
|
entry.mfn = self.p2m[pfn as usize + i];
|
2024-01-10 16:07:57 -08:00
|
|
|
}
|
|
|
|
let chunk_size = 1 << XEN_PAGE_SHIFT;
|
|
|
|
let num_per_entry = chunk_size >> XEN_PAGE_SHIFT;
|
2024-01-15 16:25:06 -08:00
|
|
|
let num = num_per_entry * count as usize;
|
|
|
|
let mut pfns = vec![u64::MAX; num];
|
|
|
|
for i in 0..count as usize {
|
2024-01-10 16:07:57 -08:00
|
|
|
for j in 0..num_per_entry {
|
|
|
|
pfns[i * num_per_entry + j] = entries[i].mfn + j as u64;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-15 16:25:06 -08:00
|
|
|
let actual_mmap_len = (num as u64) << XEN_PAGE_SHIFT;
|
2024-01-10 16:07:57 -08:00
|
|
|
let addr = self
|
|
|
|
.call
|
2024-01-15 16:25:06 -08:00
|
|
|
.mmap(0, actual_mmap_len)
|
2024-01-10 16:07:57 -08:00
|
|
|
.ok_or(XenClientError::new("failed to mmap address"))?;
|
2024-01-15 16:25:06 -08:00
|
|
|
let result = self.call.mmap_batch(self.domid, num as u64, addr, pfns)?;
|
|
|
|
if result != 0 {
|
|
|
|
return Err(XenClientError::new("mmap_batch call failed"));
|
|
|
|
}
|
2024-01-10 16:07:57 -08:00
|
|
|
let page = PhysicalPage {
|
|
|
|
pfn,
|
|
|
|
ptr: addr,
|
2024-01-10 19:18:48 -08:00
|
|
|
count,
|
2024-01-10 16:07:57 -08:00
|
|
|
};
|
|
|
|
self.pages.push(page);
|
|
|
|
Ok(addr)
|
|
|
|
}
|
|
|
|
}
|