fix L4 page table pinning

This commit is contained in:
Alex Zenla 2024-01-16 19:25:38 -08:00
parent 044795db0f
commit 0d68db8523
No known key found for this signature in database
GPG Key ID: 067B238899B51269
2 changed files with 35 additions and 32 deletions

View File

@ -9,7 +9,7 @@ use crate::x86::{
X86_PGTABLE_LEVEL_SHIFT, X86_VIRT_MASK, X86_PGTABLE_LEVEL_SHIFT, X86_VIRT_MASK,
}; };
use crate::XenClientError; use crate::XenClientError;
use libc::{c_char}; use libc::c_char;
use log::{debug, trace}; use log::{debug, trace};
use slice_copy::copy; use slice_copy::copy;
use std::cmp::{max, min}; use std::cmp::{max, min};
@ -290,23 +290,20 @@ impl BootSetup<'_> {
} }
pub fn boot(&mut self, state: &mut BootState, cmdline: &str) -> Result<(), XenClientError> { pub fn boot(&mut self, state: &mut BootState, cmdline: &str) -> Result<(), XenClientError> {
self.setup_page_tables(state)?;
self.setup_start_info(state, cmdline)?;
self.setup_hypercall_page(&state.image_info)?;
self.phys.unmap_all()?;
let pg_pfn = state.page_table_segment.pfn;
let pg_mfn = self.phys.p2m[pg_pfn as usize];
debug!( debug!(
"domain info: {:?}", "domain info: {:?}",
self.domctl.get_domain_info(self.domid)? self.domctl.get_domain_info(self.domid)?
); );
let page_frame_info = self.domctl.get_page_frame_info(self.domid, &[pg_pfn])?; self.setup_page_tables(state)?;
debug!("pgtable page frame info: {:#x}", page_frame_info[0]); self.setup_start_info(state, cmdline)?;
debug!("pinning l4 table: pfn={:#x} mfn={:#x}", pg_pfn, pg_mfn); self.setup_hypercall_page(&state.image_info)?;
let pg_pfn = state.page_table_segment.pfn;
self.phys.unmap(pg_pfn)?;
self.phys.unmap(state.p2m_segment.pfn)?;
let pg_mfn = self.phys.p2m[pg_pfn as usize];
self.memctl self.memctl
.mmuext(self.domid, MMUEXT_PIN_L4_TABLE, pg_mfn, 0)?; .mmuext(self.domid, MMUEXT_PIN_L4_TABLE, pg_mfn, 0)?;
debug!("pinned l4 table: {:#x}", state.page_table_segment.pfn);
// self.setup_shared_info()?; // self.setup_shared_info()?;
let mut vcpu = VcpuGuestContext::default(); let mut vcpu = VcpuGuestContext::default();
@ -348,7 +345,7 @@ impl BootSetup<'_> {
let map1 = &state.page_table.mappings[m1]; let map1 = &state.page_table.mappings[m1];
let from = map1.levels[l].from; let from = map1.levels[l].from;
let to = map1.levels[l].to; let to = map1.levels[l].to;
let pg = self.phys.pfn_to_ptr(map1.levels[l].pfn, 0)? as *mut u64; let pg_ptr = self.phys.pfn_to_ptr(map1.levels[l].pfn, 0)? as *mut u64;
for m2 in 0usize..state.page_table.mappings_count { for m2 in 0usize..state.page_table.mappings_count {
let map2 = &state.page_table.mappings[m2]; let map2 = &state.page_table.mappings[m2];
let lvl = if l > 0 { let lvl = if l > 0 {
@ -376,18 +373,13 @@ impl BootSetup<'_> {
"BootSetup setup_page_tables lvl={} map_1={} map_2={} pfn={:#x} p_s={:#x} p_e={:#x}", "BootSetup setup_page_tables lvl={} map_1={} map_2={} pfn={:#x} p_s={:#x} p_e={:#x}",
l, m1, m2, pfn, p_s, p_e l, m1, m2, pfn, p_s, p_e
); );
let pg = unsafe { slice::from_raw_parts_mut(pg_ptr, (p_e + 1) as usize) };
for p in p_s..p_e + 1 { for p in p_s..p_e + 1 {
let prot = self.get_pg_prot(l, pfn, &state.page_table); let prot = self.get_pg_prot(l, pfn, &state.page_table);
let pfn_paddr = self.phys.p2m[pfn as usize] << X86_PAGE_SHIFT; let pfn_paddr = self.phys.p2m[pfn as usize] << X86_PAGE_SHIFT;
let value = pfn_paddr | prot; let value = pfn_paddr | prot;
// debug!( pg[p as usize] = value;
// "pgtable pfn: {:#x}, p: {:#x}, pfn_paddr: {:#x}, value: {:#x}, prot: {:#x}",
// pfn, p, pfn_paddr, value, prot
// );
unsafe {
*pg.add(p as usize) = value;
}
pfn += 1; pfn += 1;
} }
} }
@ -426,10 +418,11 @@ impl BootSetup<'_> {
return prot; return prot;
} }
for map in &table.mappings { for m in 0..table.mappings_count {
let map = &table.mappings[m];
let pfn_s = map.levels[(X86_PGTABLE_LEVELS - 1) as usize].pfn; let pfn_s = map.levels[(X86_PGTABLE_LEVELS - 1) as usize].pfn;
let pfn_e = map.area.pgtables as u64 + pfn_s; let pfn_e = map.area.pgtables as u64 + pfn_s;
if pfn > pfn_s && pfn < pfn_e { if pfn >= pfn_s && pfn < pfn_e {
return prot & !BootSetup::PAGE_RW; return prot & !BootSetup::PAGE_RW;
} }
} }

View File

@ -96,6 +96,7 @@ impl PhysicalPages<'_> {
.call .call
.mmap(0, actual_mmap_len) .mmap(0, actual_mmap_len)
.ok_or(XenClientError::new("failed to mmap address"))?; .ok_or(XenClientError::new("failed to mmap address"))?;
debug!("mapped {:#x} foreign bytes at {:#x}", actual_mmap_len, addr);
let result = self.call.mmap_batch(self.domid, num as u64, addr, pfns)?; let result = self.call.mmap_batch(self.domid, num as u64, addr, pfns)?;
if result != 0 { if result != 0 {
return Err(XenClientError::new("mmap_batch call failed")); return Err(XenClientError::new("mmap_batch call failed"));
@ -130,16 +131,25 @@ impl PhysicalPages<'_> {
} }
pub fn unmap(&mut self, pfn: u64) -> Result<(), XenClientError> { pub fn unmap(&mut self, pfn: u64) -> Result<(), XenClientError> {
let mut page: Option<(usize, &PhysicalPage)> = None; let page = self.pages.iter().find(|x| x.pfn == pfn);
for (i, item) in self.pages.iter().enumerate() {
if pfn >= item.pfn && pfn < (item.pfn + item.count) {
break;
}
page = Some((i, item));
}
if page.is_none() { if page.is_none() {
return Err(XenClientError::new("failed to unmap pfn")); return Err(XenClientError::new("unable to find page to unmap"));
}
let page = page.unwrap();
unsafe {
let err = munmap(
page.ptr as *mut c_void,
(page.count << X86_PAGE_SHIFT) as usize,
);
debug!(
"unmapped {:#x} foreign bytes at {:#x}",
(page.count << X86_PAGE_SHIFT) as usize,
page.ptr
);
if err != 0 {
return Err(XenClientError::new("failed to munmap page"));
}
} }
Ok(()) Ok(())
} }