2024-01-10 16:07:57 -08:00
|
|
|
use crate::mem::PhysicalPages;
|
|
|
|
use crate::sys::{
|
|
|
|
SUPERPAGE_2MB_NR_PFNS, SUPERPAGE_2MB_SHIFT, SUPERPAGE_BATCH_SIZE, XEN_PAGE_SHIFT,
|
|
|
|
};
|
2024-01-09 22:39:32 -08:00
|
|
|
use crate::XenClientError;
|
2024-01-10 16:07:57 -08:00
|
|
|
use libc::memset;
|
2024-01-11 12:21:33 -08:00
|
|
|
use log::debug;
|
2024-01-10 16:07:57 -08:00
|
|
|
use std::ffi::c_void;
|
2024-01-10 23:28:41 -08:00
|
|
|
use std::slice;
|
2024-01-10 16:07:57 -08:00
|
|
|
use xencall::domctl::DomainControl;
|
|
|
|
use xencall::memory::MemoryControl;
|
|
|
|
use xencall::XenCall;
|
2024-01-09 22:39:32 -08:00
|
|
|
|
2024-01-10 08:57:44 -08:00
|
|
|
pub trait BootImageLoader {
|
2024-01-10 16:07:57 -08:00
|
|
|
fn parse(&self) -> Result<BootImageInfo, XenClientError>;
|
|
|
|
fn load(&self, image_info: BootImageInfo, dst: &mut [u8]) -> Result<(), XenClientError>;
|
2024-01-09 22:39:32 -08:00
|
|
|
}
|
|
|
|
|
2024-01-10 10:08:39 -08:00
|
|
|
pub const XEN_UNSET_ADDR: u64 = -1i64 as u64;
|
|
|
|
|
2024-01-10 08:57:44 -08:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct BootImageInfo {
|
|
|
|
pub virt_kstart: u64,
|
|
|
|
pub virt_kend: u64,
|
2024-01-10 10:08:39 -08:00
|
|
|
pub virt_hypercall: u64,
|
2024-01-10 16:07:57 -08:00
|
|
|
pub virt_entry: u64,
|
|
|
|
pub init_p2m: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct BootSetup<'a> {
|
|
|
|
domctl: &'a DomainControl<'a>,
|
|
|
|
memctl: &'a MemoryControl<'a>,
|
|
|
|
phys: PhysicalPages<'a>,
|
|
|
|
domid: u32,
|
|
|
|
virt_alloc_end: u64,
|
|
|
|
pfn_alloc_end: u64,
|
|
|
|
}
|
|
|
|
|
2024-01-10 22:42:26 -08:00
|
|
|
#[derive(Debug)]
|
2024-01-10 16:07:57 -08:00
|
|
|
struct DomainSegment {
|
|
|
|
_vstart: u64,
|
|
|
|
_vend: u64,
|
|
|
|
pfn: u64,
|
2024-01-10 23:28:41 -08:00
|
|
|
addr: u64,
|
|
|
|
size: u64,
|
2024-01-10 16:07:57 -08:00
|
|
|
_pages: u64,
|
|
|
|
}
|
|
|
|
|
|
|
|
struct VmemRange {
|
|
|
|
start: u64,
|
|
|
|
end: u64,
|
|
|
|
_flags: u32,
|
|
|
|
_nid: u32,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl BootSetup<'_> {
|
|
|
|
pub fn new<'a>(
|
|
|
|
call: &'a XenCall,
|
|
|
|
domctl: &'a DomainControl<'a>,
|
|
|
|
memctl: &'a MemoryControl<'a>,
|
|
|
|
domid: u32,
|
|
|
|
) -> BootSetup<'a> {
|
|
|
|
BootSetup {
|
|
|
|
domctl,
|
|
|
|
memctl,
|
|
|
|
phys: PhysicalPages::new(call, domid),
|
|
|
|
domid,
|
|
|
|
virt_alloc_end: 0,
|
|
|
|
pfn_alloc_end: 0,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-10 19:18:48 -08:00
|
|
|
fn initialize_memory(&mut self, memkb: u64) -> Result<(), XenClientError> {
|
|
|
|
let mem_mb: u64 = memkb / 1024;
|
2024-01-10 16:07:57 -08:00
|
|
|
let page_count: u64 = mem_mb << (20 - XEN_PAGE_SHIFT);
|
|
|
|
let mut vmemranges: Vec<VmemRange> = Vec::new();
|
|
|
|
let stub = VmemRange {
|
|
|
|
start: 0,
|
|
|
|
end: page_count << XEN_PAGE_SHIFT,
|
|
|
|
_flags: 0,
|
|
|
|
_nid: 0,
|
|
|
|
};
|
|
|
|
vmemranges.push(stub);
|
|
|
|
|
|
|
|
let mut p2m_size: u64 = 0;
|
|
|
|
let mut total: u64 = 0;
|
|
|
|
for range in &vmemranges {
|
|
|
|
total += (range.end - range.start) >> XEN_PAGE_SHIFT;
|
|
|
|
p2m_size = p2m_size.max(range.end >> XEN_PAGE_SHIFT);
|
|
|
|
}
|
|
|
|
|
|
|
|
if total != page_count {
|
|
|
|
return Err(XenClientError::new(
|
|
|
|
"Page count mismatch while calculating pages.",
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut p2m = vec![-1i64 as u64; p2m_size as usize];
|
|
|
|
for range in &vmemranges {
|
|
|
|
let mut extents = vec![0u64; SUPERPAGE_BATCH_SIZE as usize];
|
|
|
|
let pages = (range.end - range.start) >> XEN_PAGE_SHIFT;
|
|
|
|
let pfn_base = range.start >> XEN_PAGE_SHIFT;
|
|
|
|
|
|
|
|
for pfn in pfn_base..pfn_base + pages {
|
|
|
|
p2m[pfn as usize] = pfn;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut super_pages = pages >> SUPERPAGE_2MB_SHIFT;
|
2024-01-10 19:18:48 -08:00
|
|
|
let mut pfn_base_idx: u64 = pfn_base;
|
2024-01-10 16:07:57 -08:00
|
|
|
while super_pages > 0 {
|
|
|
|
let count = super_pages.min(SUPERPAGE_BATCH_SIZE);
|
|
|
|
super_pages -= count;
|
|
|
|
|
2024-01-10 19:18:48 -08:00
|
|
|
let mut j: usize = 0;
|
|
|
|
let mut pfn: u64 = pfn_base_idx;
|
|
|
|
loop {
|
|
|
|
if pfn >= pfn_base_idx + (count << SUPERPAGE_2MB_SHIFT) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
extents[j] = p2m[pfn as usize];
|
|
|
|
pfn += SUPERPAGE_2MB_NR_PFNS;
|
|
|
|
j += 1;
|
2024-01-10 16:07:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
let starts = self.memctl.populate_physmap(
|
|
|
|
self.domid,
|
|
|
|
count,
|
|
|
|
SUPERPAGE_2MB_SHIFT as u32,
|
|
|
|
0,
|
|
|
|
extents.as_slice(),
|
|
|
|
)?;
|
|
|
|
|
2024-01-10 19:18:48 -08:00
|
|
|
pfn = pfn_base_idx;
|
2024-01-10 16:07:57 -08:00
|
|
|
for mfn in starts {
|
|
|
|
for k in 0..SUPERPAGE_2MB_NR_PFNS {
|
|
|
|
p2m[pfn as usize] = mfn + k;
|
2024-01-10 19:18:48 -08:00
|
|
|
pfn += 1;
|
2024-01-10 16:07:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
pfn_base_idx = pfn;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut j = pfn_base_idx - pfn_base;
|
|
|
|
loop {
|
|
|
|
if j >= pages {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2024-01-10 19:18:48 -08:00
|
|
|
let allocsz = (1024 * 1024).min(pages - j);
|
|
|
|
let p2m_idx = (pfn_base + j) as usize;
|
2024-01-10 22:42:26 -08:00
|
|
|
let p2m_end_idx = p2m_idx + allocsz as usize;
|
|
|
|
let result = self.memctl.populate_physmap(
|
|
|
|
self.domid,
|
|
|
|
allocsz,
|
|
|
|
0,
|
|
|
|
0,
|
|
|
|
&p2m[p2m_idx..p2m_end_idx],
|
|
|
|
)?;
|
2024-01-10 19:18:48 -08:00
|
|
|
|
|
|
|
if result.len() != allocsz as usize {
|
|
|
|
return Err(XenClientError::new(
|
|
|
|
format!("failed to populate physmap: {:?}", result).as_str(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
p2m[p2m_idx] = result[0];
|
2024-01-10 16:07:57 -08:00
|
|
|
j += allocsz;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.phys.load_p2m(p2m);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-01-10 22:42:26 -08:00
|
|
|
fn _initialize_hypercall(&mut self, image_info: BootImageInfo) -> Result<(), XenClientError> {
|
2024-01-10 16:07:57 -08:00
|
|
|
if image_info.virt_hypercall != XEN_UNSET_ADDR {
|
|
|
|
self.domctl
|
|
|
|
.hypercall_init(self.domid, image_info.virt_hypercall)?;
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-01-10 19:18:48 -08:00
|
|
|
pub fn initialize(
|
|
|
|
&mut self,
|
2024-01-10 23:28:41 -08:00
|
|
|
image_loader: &dyn BootImageLoader,
|
2024-01-10 19:18:48 -08:00
|
|
|
memkb: u64,
|
|
|
|
) -> Result<(), XenClientError> {
|
2024-01-11 12:21:33 -08:00
|
|
|
debug!("BootSetup initialize memkb={:?}", memkb);
|
2024-01-10 23:28:41 -08:00
|
|
|
let image_info = image_loader.parse()?;
|
2024-01-11 12:21:33 -08:00
|
|
|
debug!("BootSetup initialize image_info={:?}", image_info);
|
2024-01-10 19:18:48 -08:00
|
|
|
self.domctl.set_max_mem(self.domid, memkb)?;
|
|
|
|
self.initialize_memory(memkb)?;
|
2024-01-10 22:42:26 -08:00
|
|
|
let kernel_segment = self.alloc_segment(image_info.virt_kend - image_info.virt_kstart)?;
|
2024-01-10 23:28:41 -08:00
|
|
|
let kernel_segment_ptr = kernel_segment.addr as *mut u8;
|
2024-01-11 12:21:33 -08:00
|
|
|
debug!(
|
|
|
|
"BootSetup initialize kernel_segment ptr={:#x}",
|
|
|
|
kernel_segment_ptr as u64
|
|
|
|
);
|
2024-01-10 23:28:41 -08:00
|
|
|
let slice =
|
|
|
|
unsafe { slice::from_raw_parts_mut(kernel_segment_ptr, kernel_segment.size as usize) };
|
|
|
|
image_loader.load(image_info, slice)?;
|
2024-01-10 16:07:57 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn alloc_segment(&mut self, size: u64) -> Result<DomainSegment, XenClientError> {
|
|
|
|
let page_size = 1u64 << XEN_PAGE_SHIFT;
|
|
|
|
let pages = (size + page_size - 1) / page_size;
|
|
|
|
let start = self.virt_alloc_end;
|
|
|
|
let mut segment = DomainSegment {
|
|
|
|
_vstart: start,
|
|
|
|
_vend: 0,
|
|
|
|
pfn: self.pfn_alloc_end,
|
2024-01-10 23:28:41 -08:00
|
|
|
addr: 0,
|
|
|
|
size,
|
2024-01-10 16:07:57 -08:00
|
|
|
_pages: pages,
|
|
|
|
};
|
|
|
|
let ptr = self.phys.pfn_to_ptr(segment.pfn, pages)?;
|
2024-01-10 23:28:41 -08:00
|
|
|
segment.addr = ptr;
|
2024-01-10 16:07:57 -08:00
|
|
|
unsafe {
|
|
|
|
memset(ptr as *mut c_void, 0, (pages * page_size) as usize);
|
|
|
|
}
|
|
|
|
self.virt_alloc_end += pages * page_size;
|
|
|
|
segment._vend = self.virt_alloc_end;
|
|
|
|
self.pfn_alloc_end += 1;
|
2024-01-11 12:21:33 -08:00
|
|
|
debug!("BootSetup alloc_segment size={} ptr={:#x}", size, ptr);
|
2024-01-10 16:07:57 -08:00
|
|
|
Ok(segment)
|
|
|
|
}
|
2024-01-09 22:39:32 -08:00
|
|
|
}
|