2024-01-10 16:07:57 -08:00
|
|
|
use crate::mem::PhysicalPages;
|
|
|
|
use crate::sys::{
|
2024-01-16 23:07:34 -08:00
|
|
|
GrantEntry, SUPERPAGE_2MB_NR_PFNS, SUPERPAGE_2MB_SHIFT, SUPERPAGE_BATCH_SIZE, VGCF_IN_KERNEL,
|
|
|
|
VGCF_ONLINE, XEN_PAGE_SHIFT,
|
2024-01-10 16:07:57 -08:00
|
|
|
};
|
2024-01-11 17:23:09 -08:00
|
|
|
use crate::x86::{
|
2024-01-15 18:50:12 -08:00
|
|
|
PageTable, PageTableMapping, SharedInfo, StartInfo, MAX_GUEST_CMDLINE, X86_GUEST_MAGIC,
|
|
|
|
X86_PAGE_SHIFT, X86_PAGE_SIZE, X86_PAGE_TABLE_MAX_MAPPINGS, X86_PGTABLE_LEVELS,
|
|
|
|
X86_PGTABLE_LEVEL_SHIFT, X86_VIRT_MASK,
|
2024-01-11 17:23:09 -08:00
|
|
|
};
|
2024-01-09 22:39:32 -08:00
|
|
|
use crate::XenClientError;
|
2024-01-16 23:07:34 -08:00
|
|
|
use libc::{c_char, munmap};
|
2024-01-12 14:57:02 -08:00
|
|
|
use log::{debug, trace};
|
|
|
|
use slice_copy::copy;
|
2024-01-11 17:23:09 -08:00
|
|
|
use std::cmp::{max, min};
|
2024-01-16 23:07:34 -08:00
|
|
|
use std::ffi::c_void;
|
2024-01-15 18:50:12 -08:00
|
|
|
use std::mem::size_of;
|
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;
|
2024-01-15 18:50:12 -08:00
|
|
|
use xencall::sys::{VcpuGuestContext, MMUEXT_PIN_L4_TABLE};
|
2024-01-10 16:07:57 -08:00
|
|
|
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>;
|
2024-01-11 17:23:09 -08:00
|
|
|
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 {
|
2024-01-11 21:10:59 -08:00
|
|
|
pub start: u64,
|
2024-01-11 17:23:09 -08:00
|
|
|
pub virt_base: u64,
|
2024-01-10 08:57:44 -08:00
|
|
|
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,
|
2024-01-12 14:57:02 -08:00
|
|
|
pub virt_p2m_base: u64,
|
2024-01-16 17:57:19 -08:00
|
|
|
pub unmapped_initrd: bool,
|
2024-01-10 16:07:57 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
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-11 17:23:09 -08:00
|
|
|
virt_pgtab_end: u64,
|
|
|
|
total_pages: u64,
|
2024-01-10 16:07:57 -08:00
|
|
|
}
|
|
|
|
|
2024-01-10 22:42:26 -08:00
|
|
|
#[derive(Debug)]
|
2024-01-11 17:23:09 -08:00
|
|
|
pub struct DomainSegment {
|
|
|
|
vstart: u64,
|
2024-01-10 16:07:57 -08:00
|
|
|
_vend: u64,
|
|
|
|
pfn: u64,
|
2024-01-10 23:28:41 -08:00
|
|
|
addr: u64,
|
|
|
|
size: u64,
|
2024-01-16 23:07:34 -08:00
|
|
|
pages: u64,
|
2024-01-10 16:07:57 -08:00
|
|
|
}
|
|
|
|
|
2024-01-14 16:00:44 -08:00
|
|
|
#[derive(Debug)]
|
2024-01-10 16:07:57 -08:00
|
|
|
struct VmemRange {
|
|
|
|
start: u64,
|
|
|
|
end: u64,
|
|
|
|
_flags: u32,
|
|
|
|
_nid: u32,
|
|
|
|
}
|
|
|
|
|
2024-01-12 02:12:29 -08:00
|
|
|
#[derive(Debug)]
|
2024-01-11 17:23:09 -08:00
|
|
|
pub struct BootState {
|
|
|
|
pub kernel_segment: DomainSegment,
|
|
|
|
pub start_info_segment: DomainSegment,
|
|
|
|
pub xenstore_segment: DomainSegment,
|
|
|
|
pub console_segment: DomainSegment,
|
|
|
|
pub boot_stack_segment: DomainSegment,
|
2024-01-12 14:57:02 -08:00
|
|
|
pub p2m_segment: DomainSegment,
|
2024-01-11 17:23:09 -08:00
|
|
|
pub page_table_segment: DomainSegment,
|
|
|
|
pub page_table: PageTable,
|
2024-01-11 21:10:59 -08:00
|
|
|
pub image_info: BootImageInfo,
|
2024-01-16 23:07:34 -08:00
|
|
|
pub shared_info_frame: u64,
|
|
|
|
pub initrd_segment: DomainSegment,
|
2024-01-17 01:41:17 -08:00
|
|
|
pub store_evtchn: u32,
|
|
|
|
pub console_evtchn: u32,
|
2024-01-11 17:23:09 -08:00
|
|
|
}
|
|
|
|
|
2024-01-10 16:07:57 -08:00
|
|
|
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-11 17:23:09 -08:00
|
|
|
virt_pgtab_end: 0,
|
|
|
|
total_pages: 0,
|
2024-01-10 16:07:57 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-15 15:00:48 -08:00
|
|
|
fn initialize_memory(&mut self, total_pages: u64) -> Result<(), XenClientError> {
|
2024-01-11 23:54:44 -08:00
|
|
|
self.domctl.set_address_size(self.domid, 64)?;
|
|
|
|
|
2024-01-10 16:07:57 -08:00
|
|
|
let mut vmemranges: Vec<VmemRange> = Vec::new();
|
|
|
|
let stub = VmemRange {
|
|
|
|
start: 0,
|
2024-01-15 15:00:48 -08:00
|
|
|
end: total_pages << XEN_PAGE_SHIFT,
|
2024-01-10 16:07:57 -08:00
|
|
|
_flags: 0,
|
|
|
|
_nid: 0,
|
|
|
|
};
|
|
|
|
vmemranges.push(stub);
|
2024-01-15 15:00:48 -08:00
|
|
|
debug!("BootSetup initialize_memory vmemranges: {:?}", vmemranges);
|
2024-01-10 16:07:57 -08:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2024-01-15 15:00:48 -08:00
|
|
|
if total != total_pages {
|
2024-01-10 16:07:57 -08:00
|
|
|
return Err(XenClientError::new(
|
2024-01-12 14:57:02 -08:00
|
|
|
"page count mismatch while calculating pages",
|
2024-01-10 16:07:57 -08:00
|
|
|
));
|
|
|
|
}
|
|
|
|
|
2024-01-15 15:00:48 -08:00
|
|
|
debug!("BootSetup initialize_memory total_pages={}", total);
|
2024-01-11 17:23:09 -08:00
|
|
|
self.total_pages = total;
|
|
|
|
|
2024-01-15 15:00:48 -08:00
|
|
|
let mut p2m = vec![u64::MAX; p2m_size as usize];
|
2024-01-10 16:07:57 -08:00
|
|
|
for range in &vmemranges {
|
2024-01-12 14:57:02 -08:00
|
|
|
let mut extents_init = vec![0u64; SUPERPAGE_BATCH_SIZE as usize];
|
2024-01-10 16:07:57 -08:00
|
|
|
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;
|
|
|
|
}
|
2024-01-12 14:57:02 -08:00
|
|
|
extents_init[j] = p2m[pfn as usize];
|
2024-01-10 19:18:48 -08:00
|
|
|
pfn += SUPERPAGE_2MB_NR_PFNS;
|
|
|
|
j += 1;
|
2024-01-10 16:07:57 -08:00
|
|
|
}
|
|
|
|
|
2024-01-14 16:00:44 -08:00
|
|
|
let extents_init_slice = extents_init.as_slice();
|
2024-01-12 14:57:02 -08:00
|
|
|
let extents = self.memctl.populate_physmap(
|
2024-01-10 16:07:57 -08:00
|
|
|
self.domid,
|
|
|
|
count,
|
|
|
|
SUPERPAGE_2MB_SHIFT as u32,
|
|
|
|
0,
|
2024-01-14 16:00:44 -08:00
|
|
|
&extents_init_slice[0usize..count as usize],
|
2024-01-10 16:07:57 -08:00
|
|
|
)?;
|
|
|
|
|
2024-01-10 19:18:48 -08:00
|
|
|
pfn = pfn_base_idx;
|
2024-01-12 14:57:02 -08:00
|
|
|
for mfn in extents {
|
2024-01-10 16:07:57 -08:00
|
|
|
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;
|
2024-01-14 16:00:44 -08:00
|
|
|
let input_extent_starts = &p2m[p2m_idx..p2m_end_idx];
|
|
|
|
let result =
|
|
|
|
self.memctl
|
|
|
|
.populate_physmap(self.domid, allocsz, 0, 0, input_extent_starts)?;
|
2024-01-10 19:18:48 -08:00
|
|
|
|
|
|
|
if result.len() != allocsz as usize {
|
|
|
|
return Err(XenClientError::new(
|
2024-01-14 16:00:44 -08:00
|
|
|
format!(
|
|
|
|
"failed to populate physmap: wanted={} received={} input_extents={}",
|
|
|
|
allocsz,
|
|
|
|
result.len(),
|
|
|
|
input_extent_starts.len()
|
|
|
|
)
|
|
|
|
.as_str(),
|
2024-01-10 19:18:48 -08:00
|
|
|
));
|
|
|
|
}
|
2024-01-15 18:50:12 -08:00
|
|
|
|
|
|
|
for (i, item) in result.iter().enumerate() {
|
|
|
|
let p = (pfn_base + j + i as u64) as usize;
|
|
|
|
let m = *item;
|
|
|
|
p2m[p] = m;
|
|
|
|
}
|
2024-01-10 16:07:57 -08:00
|
|
|
j += allocsz;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
self.phys.load_p2m(p2m);
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-01-11 21:10:59 -08:00
|
|
|
fn setup_hypercall_page(&mut self, image_info: &BootImageInfo) -> Result<(), XenClientError> {
|
|
|
|
if image_info.virt_hypercall == XEN_UNSET_ADDR {
|
|
|
|
return Ok(());
|
2024-01-10 16:07:57 -08:00
|
|
|
}
|
2024-01-11 21:10:59 -08:00
|
|
|
|
|
|
|
let pfn = (image_info.virt_hypercall - image_info.virt_base) >> X86_PAGE_SHIFT;
|
|
|
|
let mfn = self.phys.p2m[pfn as usize];
|
|
|
|
self.domctl.hypercall_init(self.domid, mfn)?;
|
2024-01-10 16:07:57 -08:00
|
|
|
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-16 17:57:19 -08:00
|
|
|
initrd: &[u8],
|
2024-01-16 23:07:34 -08:00
|
|
|
max_vcpus: u32,
|
2024-01-15 15:00:48 -08:00
|
|
|
mem_mb: u64,
|
2024-01-11 17:23:09 -08:00
|
|
|
) -> Result<BootState, XenClientError> {
|
2024-01-16 23:07:34 -08:00
|
|
|
debug!(
|
|
|
|
"BootSetup initialize max_vcpus={:?} mem_mb={:?}",
|
|
|
|
max_vcpus, mem_mb
|
|
|
|
);
|
|
|
|
self.domctl.set_max_vcpus(self.domid, max_vcpus)?;
|
2024-01-15 15:00:48 -08:00
|
|
|
self.domctl.set_max_mem(self.domid, mem_mb * 1024)?;
|
|
|
|
|
|
|
|
let total_pages = mem_mb << (20 - X86_PAGE_SHIFT);
|
|
|
|
self.initialize_memory(total_pages)?;
|
2024-01-11 17:23:09 -08:00
|
|
|
|
|
|
|
let image_info = image_loader.parse()?;
|
2024-01-12 14:57:02 -08:00
|
|
|
debug!("BootSetup initialize image_info={:?}", image_info);
|
2024-01-11 21:10:59 -08:00
|
|
|
self.virt_alloc_end = image_info.virt_base;
|
2024-01-11 17:23:09 -08:00
|
|
|
let kernel_segment = self.load_kernel_segment(image_loader, &image_info)?;
|
2024-01-16 17:57:19 -08:00
|
|
|
let mut p2m_segment: Option<DomainSegment> = None;
|
2024-01-15 16:25:06 -08:00
|
|
|
let mut page_table = PageTable::default();
|
2024-01-16 17:57:19 -08:00
|
|
|
if image_info.virt_p2m_base >= image_info.virt_base
|
|
|
|
|| (image_info.virt_p2m_base & ((1 << X86_PAGE_SHIFT) - 1)) != 0
|
|
|
|
{
|
|
|
|
p2m_segment = Some(self.alloc_p2m_segment(&mut page_table, &image_info)?);
|
|
|
|
}
|
2024-01-11 17:23:09 -08:00
|
|
|
let start_info_segment = self.alloc_page()?;
|
|
|
|
let xenstore_segment = self.alloc_page()?;
|
|
|
|
let console_segment = self.alloc_page()?;
|
2024-01-12 14:57:02 -08:00
|
|
|
let page_table_segment = self.alloc_page_tables(&mut page_table, &image_info)?;
|
2024-01-11 23:54:44 -08:00
|
|
|
let boot_stack_segment = self.alloc_page()?;
|
2024-01-16 23:07:34 -08:00
|
|
|
|
|
|
|
if self.virt_pgtab_end > 0 {
|
|
|
|
self.alloc_padding_pages(self.virt_pgtab_end)?;
|
|
|
|
}
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
let mut initrd_segment: Option<DomainSegment> = None;
|
|
|
|
if !image_info.unmapped_initrd {
|
|
|
|
initrd_segment = Some(self.alloc_module(initrd)?);
|
|
|
|
}
|
|
|
|
if p2m_segment.is_none() {
|
|
|
|
let mut segment = self.alloc_p2m_segment(&mut page_table, &image_info)?;
|
|
|
|
segment.vstart = image_info.virt_p2m_base;
|
|
|
|
p2m_segment = Some(segment);
|
|
|
|
}
|
|
|
|
let p2m_segment = p2m_segment.unwrap();
|
|
|
|
|
|
|
|
if image_info.unmapped_initrd {
|
|
|
|
initrd_segment = Some(self.alloc_module(initrd)?);
|
|
|
|
}
|
|
|
|
|
2024-01-16 23:07:34 -08:00
|
|
|
let initrd_segment = initrd_segment.unwrap();
|
2024-01-17 01:41:17 -08:00
|
|
|
let store_evtchn = self.domctl.call.evtchn_alloc_unbound(self.domid, 0)?;
|
|
|
|
let console_evtchn = self.domctl.call.evtchn_alloc_unbound(self.domid, 0)?;
|
2024-01-12 02:12:29 -08:00
|
|
|
let state = BootState {
|
2024-01-11 17:23:09 -08:00
|
|
|
kernel_segment,
|
|
|
|
start_info_segment,
|
|
|
|
xenstore_segment,
|
|
|
|
console_segment,
|
|
|
|
boot_stack_segment,
|
2024-01-12 14:57:02 -08:00
|
|
|
p2m_segment,
|
2024-01-11 17:23:09 -08:00
|
|
|
page_table_segment,
|
|
|
|
page_table,
|
2024-01-11 21:10:59 -08:00
|
|
|
image_info,
|
2024-01-16 23:07:34 -08:00
|
|
|
initrd_segment,
|
2024-01-17 01:41:17 -08:00
|
|
|
store_evtchn,
|
|
|
|
console_evtchn,
|
2024-01-16 23:07:34 -08:00
|
|
|
shared_info_frame: 0,
|
2024-01-12 02:12:29 -08:00
|
|
|
};
|
2024-01-12 14:57:02 -08:00
|
|
|
debug!("BootSetup initialize state={:?}", state);
|
2024-01-12 02:12:29 -08:00
|
|
|
Ok(state)
|
2024-01-11 17:23:09 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn boot(&mut self, state: &mut BootState, cmdline: &str) -> Result<(), XenClientError> {
|
2024-01-16 23:07:34 -08:00
|
|
|
let domain_info = self.domctl.get_domain_info(self.domid)?;
|
|
|
|
let shared_info_frame = domain_info.shared_info_frame;
|
|
|
|
state.shared_info_frame = shared_info_frame;
|
2024-01-11 17:23:09 -08:00
|
|
|
self.setup_page_tables(state)?;
|
2024-01-12 02:12:29 -08:00
|
|
|
self.setup_start_info(state, cmdline)?;
|
2024-01-11 21:10:59 -08:00
|
|
|
self.setup_hypercall_page(&state.image_info)?;
|
|
|
|
|
2024-01-15 18:50:12 -08:00
|
|
|
let pg_pfn = state.page_table_segment.pfn;
|
2024-01-16 19:25:38 -08:00
|
|
|
self.phys.unmap(pg_pfn)?;
|
|
|
|
self.phys.unmap(state.p2m_segment.pfn)?;
|
2024-01-15 18:50:12 -08:00
|
|
|
let pg_mfn = self.phys.p2m[pg_pfn as usize];
|
|
|
|
self.memctl
|
|
|
|
.mmuext(self.domid, MMUEXT_PIN_L4_TABLE, pg_mfn, 0)?;
|
2024-01-16 23:07:34 -08:00
|
|
|
self.setup_shared_info(state.shared_info_frame)?;
|
2024-01-15 18:50:12 -08:00
|
|
|
|
2024-01-11 21:10:59 -08:00
|
|
|
let mut vcpu = VcpuGuestContext::default();
|
|
|
|
vcpu.user_regs.rip = state.image_info.virt_entry;
|
|
|
|
vcpu.user_regs.rsp =
|
|
|
|
state.image_info.virt_base + (state.boot_stack_segment.pfn + 1) * X86_PAGE_SIZE;
|
|
|
|
vcpu.user_regs.rsi =
|
|
|
|
state.image_info.virt_base + (state.start_info_segment.pfn) * X86_PAGE_SIZE;
|
|
|
|
vcpu.user_regs.rflags = 1 << 9;
|
|
|
|
vcpu.debugreg[6] = 0xffff0ff0;
|
|
|
|
vcpu.debugreg[7] = 0x00000400;
|
2024-01-12 02:12:29 -08:00
|
|
|
vcpu.flags = VGCF_IN_KERNEL | VGCF_ONLINE;
|
2024-01-15 18:50:12 -08:00
|
|
|
let cr3_pfn = pg_mfn;
|
2024-01-14 16:00:44 -08:00
|
|
|
debug!(
|
|
|
|
"cr3: pfn {:#x} mfn {:#x}",
|
|
|
|
state.page_table_segment.pfn, cr3_pfn
|
|
|
|
);
|
2024-01-11 21:10:59 -08:00
|
|
|
vcpu.ctrlreg[3] = cr3_pfn << 12;
|
2024-01-12 14:57:02 -08:00
|
|
|
vcpu.user_regs.ds = 0x0;
|
|
|
|
vcpu.user_regs.es = 0x0;
|
|
|
|
vcpu.user_regs.fs = 0x0;
|
|
|
|
vcpu.user_regs.gs = 0x0;
|
2024-01-11 21:10:59 -08:00
|
|
|
vcpu.user_regs.ss = 0xe02b;
|
2024-01-12 14:57:02 -08:00
|
|
|
vcpu.user_regs.cs = 0xe033;
|
2024-01-11 21:10:59 -08:00
|
|
|
vcpu.kernel_ss = vcpu.user_regs.ss as u64;
|
|
|
|
vcpu.kernel_sp = vcpu.user_regs.rsp;
|
2024-01-16 23:07:34 -08:00
|
|
|
debug!("vcpu context: {:?}", vcpu);
|
2024-01-14 16:00:44 -08:00
|
|
|
self.domctl.set_vcpu_context(self.domid, 0, &vcpu)?;
|
2024-01-16 23:07:34 -08:00
|
|
|
self.phys.unmap_all()?;
|
|
|
|
self.gnttab_seed(state)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn gnttab_seed(&mut self, state: &mut BootState) -> Result<(), XenClientError> {
|
|
|
|
let console_gfn = self.phys.p2m[state.console_segment.pfn as usize];
|
|
|
|
let xenstore_gfn = self.phys.p2m[state.xenstore_segment.pfn as usize];
|
|
|
|
let addr = self
|
|
|
|
.domctl
|
|
|
|
.call
|
|
|
|
.mmap(0, 1 << XEN_PAGE_SHIFT)
|
|
|
|
.ok_or(XenClientError::new("failed to mmap for resource"))?;
|
|
|
|
self.domctl
|
|
|
|
.call
|
|
|
|
.map_resource(self.domid, 1, 0, 0, 1, addr)?;
|
|
|
|
let entries = unsafe { slice::from_raw_parts_mut(addr as *mut GrantEntry, 2) };
|
|
|
|
entries[0].flags = 1 << 0;
|
|
|
|
entries[0].domid = 0;
|
|
|
|
entries[0].frame = console_gfn as u32;
|
|
|
|
entries[1].flags = 1 << 0;
|
|
|
|
entries[1].domid = 0;
|
|
|
|
entries[1].frame = xenstore_gfn as u32;
|
|
|
|
unsafe {
|
|
|
|
let result = munmap(addr as *mut c_void, 1 << XEN_PAGE_SHIFT);
|
|
|
|
if result != 0 {
|
|
|
|
return Err(XenClientError::new("failed to unmap resource"));
|
|
|
|
}
|
|
|
|
}
|
2024-01-11 17:23:09 -08:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn setup_page_tables(&mut self, state: &mut BootState) -> Result<(), XenClientError> {
|
2024-01-12 14:57:02 -08:00
|
|
|
let p2m_guest = unsafe {
|
2024-01-16 23:07:34 -08:00
|
|
|
slice::from_raw_parts_mut(
|
|
|
|
state.p2m_segment.addr as *mut u64,
|
|
|
|
self.phys.p2m_size() as usize,
|
|
|
|
)
|
2024-01-12 14:57:02 -08:00
|
|
|
};
|
|
|
|
copy(p2m_guest, &self.phys.p2m);
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
for l in (0usize..X86_PGTABLE_LEVELS as usize).rev() {
|
|
|
|
for m1 in 0usize..state.page_table.mappings_count {
|
|
|
|
let map1 = &state.page_table.mappings[m1];
|
|
|
|
let from = map1.levels[l].from;
|
|
|
|
let to = map1.levels[l].to;
|
2024-01-16 19:25:38 -08:00
|
|
|
let pg_ptr = self.phys.pfn_to_ptr(map1.levels[l].pfn, 0)? as *mut u64;
|
2024-01-16 17:57:19 -08:00
|
|
|
for m2 in 0usize..state.page_table.mappings_count {
|
|
|
|
let map2 = &state.page_table.mappings[m2];
|
|
|
|
let lvl = if l > 0 {
|
|
|
|
&map2.levels[l - 1]
|
2024-01-11 17:23:09 -08:00
|
|
|
} else {
|
|
|
|
&map2.area
|
|
|
|
};
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
if l > 0 && lvl.pgtables == 0 {
|
2024-01-11 17:23:09 -08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if lvl.from >= to || lvl.to <= from {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
let p_s = (max(from, lvl.from) - from)
|
2024-01-16 17:57:19 -08:00
|
|
|
>> (X86_PAGE_SHIFT + l as u64 * X86_PGTABLE_LEVEL_SHIFT);
|
2024-01-11 17:23:09 -08:00
|
|
|
let p_e = (min(to, lvl.to) - from)
|
2024-01-16 17:57:19 -08:00
|
|
|
>> (X86_PAGE_SHIFT + l as u64 * X86_PGTABLE_LEVEL_SHIFT);
|
|
|
|
let rhs = X86_PAGE_SHIFT as usize + l * X86_PGTABLE_LEVEL_SHIFT as usize;
|
|
|
|
let mut pfn = ((max(from, lvl.from) - lvl.from) >> rhs) + lvl.pfn;
|
2024-01-11 17:23:09 -08:00
|
|
|
|
2024-01-15 15:00:48 -08:00
|
|
|
debug!(
|
2024-01-16 17:57:19 -08:00
|
|
|
"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
|
2024-01-15 15:00:48 -08:00
|
|
|
);
|
2024-01-16 19:25:38 -08:00
|
|
|
|
|
|
|
let pg = unsafe { slice::from_raw_parts_mut(pg_ptr, (p_e + 1) as usize) };
|
2024-01-15 15:00:48 -08:00
|
|
|
for p in p_s..p_e + 1 {
|
2024-01-16 17:57:19 -08:00
|
|
|
let prot = self.get_pg_prot(l, pfn, &state.page_table);
|
2024-01-15 15:00:48 -08:00
|
|
|
let pfn_paddr = self.phys.p2m[pfn as usize] << X86_PAGE_SHIFT;
|
2024-01-15 16:25:06 -08:00
|
|
|
let value = pfn_paddr | prot;
|
2024-01-16 19:25:38 -08:00
|
|
|
pg[p as usize] = value;
|
2024-01-11 17:23:09 -08:00
|
|
|
pfn += 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-01-14 16:00:44 -08:00
|
|
|
const PAGE_PRESENT: u64 = 0x001;
|
|
|
|
const PAGE_RW: u64 = 0x002;
|
2024-01-15 18:50:12 -08:00
|
|
|
const PAGE_USER: u64 = 0x004;
|
2024-01-14 16:00:44 -08:00
|
|
|
const PAGE_ACCESSED: u64 = 0x020;
|
|
|
|
const PAGE_DIRTY: u64 = 0x040;
|
|
|
|
fn get_pg_prot(&mut self, l: usize, pfn: u64, table: &PageTable) -> u64 {
|
|
|
|
let prot = [
|
|
|
|
BootSetup::PAGE_PRESENT | BootSetup::PAGE_RW | BootSetup::PAGE_ACCESSED,
|
|
|
|
BootSetup::PAGE_PRESENT
|
|
|
|
| BootSetup::PAGE_RW
|
|
|
|
| BootSetup::PAGE_ACCESSED
|
|
|
|
| BootSetup::PAGE_DIRTY
|
|
|
|
| BootSetup::PAGE_USER,
|
|
|
|
BootSetup::PAGE_PRESENT
|
|
|
|
| BootSetup::PAGE_RW
|
|
|
|
| BootSetup::PAGE_ACCESSED
|
|
|
|
| BootSetup::PAGE_DIRTY
|
|
|
|
| BootSetup::PAGE_USER,
|
|
|
|
BootSetup::PAGE_PRESENT
|
|
|
|
| BootSetup::PAGE_RW
|
|
|
|
| BootSetup::PAGE_ACCESSED
|
|
|
|
| BootSetup::PAGE_DIRTY
|
|
|
|
| BootSetup::PAGE_USER,
|
|
|
|
];
|
|
|
|
|
|
|
|
let prot = prot[l];
|
|
|
|
if l > 0 {
|
|
|
|
return prot;
|
|
|
|
}
|
|
|
|
|
2024-01-16 19:25:38 -08:00
|
|
|
for m in 0..table.mappings_count {
|
|
|
|
let map = &table.mappings[m];
|
2024-01-14 16:00:44 -08:00
|
|
|
let pfn_s = map.levels[(X86_PGTABLE_LEVELS - 1) as usize].pfn;
|
|
|
|
let pfn_e = map.area.pgtables as u64 + pfn_s;
|
2024-01-16 19:25:38 -08:00
|
|
|
if pfn >= pfn_s && pfn < pfn_e {
|
2024-01-14 16:00:44 -08:00
|
|
|
return prot & !BootSetup::PAGE_RW;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
prot
|
|
|
|
}
|
|
|
|
|
2024-01-12 02:12:29 -08:00
|
|
|
fn setup_start_info(&mut self, state: &BootState, cmdline: &str) -> Result<(), XenClientError> {
|
2024-01-16 23:07:34 -08:00
|
|
|
let ptr = self.phys.pfn_to_ptr(state.start_info_segment.pfn, 1)?;
|
|
|
|
let byte_slice =
|
|
|
|
unsafe { slice::from_raw_parts_mut(ptr as *mut u8, X86_PAGE_SIZE as usize) };
|
|
|
|
byte_slice.fill(0);
|
|
|
|
let info = ptr as *mut StartInfo;
|
2024-01-11 17:23:09 -08:00
|
|
|
unsafe {
|
|
|
|
for (i, c) in X86_GUEST_MAGIC.chars().enumerate() {
|
|
|
|
(*info).magic[i] = c as c_char;
|
|
|
|
}
|
2024-01-16 23:07:34 -08:00
|
|
|
(*info).magic[X86_GUEST_MAGIC.len()] = 0 as c_char;
|
2024-01-11 17:23:09 -08:00
|
|
|
(*info).nr_pages = self.total_pages;
|
2024-01-16 23:07:34 -08:00
|
|
|
(*info).shared_info = state.shared_info_frame << X86_PAGE_SHIFT;
|
2024-01-11 17:23:09 -08:00
|
|
|
(*info).pt_base = state.page_table_segment.vstart;
|
|
|
|
(*info).nr_pt_frames = state.page_table.mappings[0].area.pgtables as u64;
|
2024-01-16 23:07:34 -08:00
|
|
|
(*info).mfn_list = state.p2m_segment.vstart;
|
|
|
|
(*info).first_p2m_pfn = state.p2m_segment.pfn;
|
|
|
|
(*info).nr_p2m_frames = state.p2m_segment.pages;
|
2024-01-11 17:23:09 -08:00
|
|
|
(*info).flags = 0;
|
2024-01-17 01:41:17 -08:00
|
|
|
(*info).store_evtchn = state.store_evtchn;
|
2024-01-12 14:57:02 -08:00
|
|
|
(*info).store_mfn = self.phys.p2m[state.xenstore_segment.pfn as usize];
|
2024-01-11 17:23:09 -08:00
|
|
|
(*info).console.mfn = self.phys.p2m[state.console_segment.pfn as usize];
|
2024-01-17 01:41:17 -08:00
|
|
|
(*info).console.evtchn = state.console_evtchn;
|
2024-01-16 23:07:34 -08:00
|
|
|
(*info).mod_start = state.initrd_segment.vstart;
|
|
|
|
(*info).mod_len = state.initrd_segment.size;
|
2024-01-11 17:23:09 -08:00
|
|
|
for (i, c) in cmdline.chars().enumerate() {
|
|
|
|
(*info).cmdline[i] = c as c_char;
|
|
|
|
}
|
2024-01-16 23:07:34 -08:00
|
|
|
(*info).cmdline[MAX_GUEST_CMDLINE - 1] = 0;
|
2024-01-12 14:57:02 -08:00
|
|
|
trace!("BootSetup setup_start_info start_info={:?}", *info);
|
2024-01-11 17:23:09 -08:00
|
|
|
}
|
2024-01-12 02:12:29 -08:00
|
|
|
Ok(())
|
2024-01-11 17:23:09 -08:00
|
|
|
}
|
|
|
|
|
2024-01-16 23:07:34 -08:00
|
|
|
fn setup_shared_info(&mut self, shared_info_frame: u64) -> Result<(), XenClientError> {
|
|
|
|
let info = self
|
|
|
|
.phys
|
|
|
|
.map_foreign_pages(shared_info_frame, X86_PAGE_SIZE)?
|
|
|
|
as *mut SharedInfo;
|
2024-01-15 18:50:12 -08:00
|
|
|
unsafe {
|
|
|
|
let size = size_of::<SharedInfo>();
|
|
|
|
let info_as_buff = slice::from_raw_parts_mut(info as *mut u8, size);
|
|
|
|
info_as_buff.fill(0);
|
|
|
|
for i in 0..32 {
|
|
|
|
(*info).vcpu_info[i].evtchn_upcall_mask = 1;
|
|
|
|
}
|
|
|
|
trace!("BootSetup setup_shared_info shared_info={:?}", *info);
|
|
|
|
}
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:23:09 -08:00
|
|
|
fn load_kernel_segment(
|
|
|
|
&mut self,
|
|
|
|
image_loader: &dyn BootImageLoader,
|
|
|
|
image_info: &BootImageInfo,
|
|
|
|
) -> Result<DomainSegment, XenClientError> {
|
2024-01-11 23:54:44 -08:00
|
|
|
let kernel_segment = self.alloc_segment(
|
|
|
|
image_info.virt_kstart,
|
|
|
|
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 17:23:09 -08:00
|
|
|
let kernel_segment_slice =
|
2024-01-10 23:28:41 -08:00
|
|
|
unsafe { slice::from_raw_parts_mut(kernel_segment_ptr, kernel_segment.size as usize) };
|
2024-01-11 17:23:09 -08:00
|
|
|
image_loader.load(image_info, kernel_segment_slice)?;
|
|
|
|
Ok(kernel_segment)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn count_page_tables(
|
|
|
|
&mut self,
|
|
|
|
table: &mut PageTable,
|
|
|
|
from: u64,
|
|
|
|
to: u64,
|
|
|
|
pfn: u64,
|
2024-01-16 17:57:19 -08:00
|
|
|
) -> Result<usize, XenClientError> {
|
|
|
|
debug!("counting pgtables from={} to={} pfn={}", from, to, pfn);
|
2024-01-11 17:23:09 -08:00
|
|
|
if table.mappings_count == X86_PAGE_TABLE_MAX_MAPPINGS {
|
|
|
|
return Err(XenClientError::new("too many mappings"));
|
|
|
|
}
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
let m = table.mappings_count;
|
|
|
|
|
2024-01-11 17:23:09 -08:00
|
|
|
let pfn_end = pfn + ((to - from) >> X86_PAGE_SHIFT);
|
|
|
|
if pfn_end >= self.phys.p2m_size() {
|
|
|
|
return Err(XenClientError::new("not enough memory for initial mapping"));
|
|
|
|
}
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
for idx in 0..table.mappings_count {
|
|
|
|
if from < table.mappings[idx].area.to && to > table.mappings[idx].area.from {
|
2024-01-11 17:23:09 -08:00
|
|
|
return Err(XenClientError::new("overlapping mappings"));
|
|
|
|
}
|
|
|
|
}
|
2024-01-16 17:57:19 -08:00
|
|
|
let mut map = PageTableMapping::default();
|
2024-01-11 17:23:09 -08:00
|
|
|
map.area.from = from & X86_VIRT_MASK;
|
|
|
|
map.area.to = to & X86_VIRT_MASK;
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
for l in (0usize..X86_PGTABLE_LEVELS as usize).rev() {
|
|
|
|
map.levels[l].pfn = self.pfn_alloc_end + map.area.pgtables as u64;
|
|
|
|
if l as u64 == X86_PGTABLE_LEVELS - 1 {
|
2024-01-11 17:23:09 -08:00
|
|
|
if table.mappings_count == 0 {
|
2024-01-16 17:57:19 -08:00
|
|
|
map.levels[l].from = 0;
|
|
|
|
map.levels[l].to = X86_VIRT_MASK;
|
|
|
|
map.levels[l].pgtables = 1;
|
2024-01-11 17:23:09 -08:00
|
|
|
map.area.pgtables += 1;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
let bits = X86_PAGE_SHIFT + (l + 1) as u64 * X86_PGTABLE_LEVEL_SHIFT;
|
|
|
|
let mask = BootSetup::bits_to_mask(bits);
|
|
|
|
map.levels[l].from = map.area.from & !mask;
|
|
|
|
map.levels[l].to = map.area.to | mask;
|
2024-01-11 17:23:09 -08:00
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
for cmp in &mut table.mappings[0..table.mappings_count] {
|
|
|
|
if cmp.levels[l].from == cmp.levels[l].to {
|
2024-01-11 17:23:09 -08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
if map.levels[l].from >= cmp.levels[l].from && map.levels[l].to <= cmp.levels[l].to
|
|
|
|
{
|
|
|
|
map.levels[l].from = 0;
|
|
|
|
map.levels[l].to = 0;
|
2024-01-12 02:12:29 -08:00
|
|
|
break;
|
2024-01-11 17:23:09 -08:00
|
|
|
}
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
if map.levels[l].from >= cmp.levels[l].from
|
|
|
|
&& map.levels[l].from <= cmp.levels[l].to
|
|
|
|
{
|
|
|
|
map.levels[l].from = cmp.levels[l].to + 1;
|
2024-01-11 17:23:09 -08:00
|
|
|
}
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
if map.levels[l].to >= cmp.levels[l].from && map.levels[l].to <= cmp.levels[l].to {
|
|
|
|
map.levels[l].to = cmp.levels[l].from - 1;
|
2024-01-11 17:23:09 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
if map.levels[l].from < map.levels[l].to {
|
|
|
|
map.levels[l].pgtables =
|
|
|
|
(((map.levels[l].to - map.levels[l].from) >> bits) + 1) as usize;
|
2024-01-11 17:23:09 -08:00
|
|
|
}
|
|
|
|
|
2024-01-12 02:12:29 -08:00
|
|
|
debug!(
|
2024-01-12 14:57:02 -08:00
|
|
|
"BootSetup count_pgtables {:#x}/{}: {:#x} -> {:#x}, {} tables",
|
2024-01-16 17:57:19 -08:00
|
|
|
mask, bits, map.levels[l].from, map.levels[l].to, map.levels[l].pgtables
|
2024-01-12 02:12:29 -08:00
|
|
|
);
|
2024-01-16 17:57:19 -08:00
|
|
|
map.area.pgtables += map.levels[l].pgtables;
|
2024-01-11 17:23:09 -08:00
|
|
|
}
|
2024-01-16 17:57:19 -08:00
|
|
|
table.mappings[m] = map;
|
|
|
|
Ok(m)
|
2024-01-10 16:07:57 -08:00
|
|
|
}
|
|
|
|
|
2024-01-12 14:57:02 -08:00
|
|
|
fn alloc_p2m_segment(
|
|
|
|
&mut self,
|
|
|
|
page_table: &mut PageTable,
|
|
|
|
image_info: &BootImageInfo,
|
|
|
|
) -> Result<DomainSegment, XenClientError> {
|
|
|
|
let mut p2m_alloc_size =
|
|
|
|
((self.phys.p2m_size() * 8) + X86_PAGE_SIZE - 1) & !(X86_PAGE_SIZE - 1);
|
|
|
|
let from = image_info.virt_p2m_base;
|
|
|
|
let to = from + p2m_alloc_size - 1;
|
2024-01-16 17:57:19 -08:00
|
|
|
let m = self.count_page_tables(page_table, from, to, self.pfn_alloc_end)?;
|
2024-01-12 14:57:02 -08:00
|
|
|
|
|
|
|
let pgtables: usize;
|
|
|
|
{
|
2024-01-16 17:57:19 -08:00
|
|
|
let map = &mut page_table.mappings[m];
|
2024-01-12 14:57:02 -08:00
|
|
|
map.area.pfn = self.pfn_alloc_end;
|
|
|
|
for lvl_idx in 0..4 {
|
|
|
|
map.levels[lvl_idx].pfn += p2m_alloc_size >> X86_PAGE_SHIFT;
|
|
|
|
}
|
|
|
|
pgtables = map.area.pgtables;
|
|
|
|
}
|
|
|
|
page_table.mappings_count += 1;
|
|
|
|
p2m_alloc_size += (pgtables << X86_PAGE_SHIFT) as u64;
|
|
|
|
let p2m_segment = self.alloc_segment(0, p2m_alloc_size)?;
|
|
|
|
Ok(p2m_segment)
|
|
|
|
}
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
fn round_up(addr: u64, mask: u64) -> u64 {
|
|
|
|
addr | mask
|
|
|
|
}
|
|
|
|
|
|
|
|
fn bits_to_mask(bits: u64) -> u64 {
|
|
|
|
(1 << bits) - 1
|
|
|
|
}
|
|
|
|
|
2024-01-11 17:23:09 -08:00
|
|
|
fn alloc_page_tables(
|
|
|
|
&mut self,
|
2024-01-12 14:57:02 -08:00
|
|
|
table: &mut PageTable,
|
2024-01-11 17:23:09 -08:00
|
|
|
image_info: &BootImageInfo,
|
2024-01-12 14:57:02 -08:00
|
|
|
) -> Result<DomainSegment, XenClientError> {
|
2024-01-12 02:12:29 -08:00
|
|
|
let mut extra_pages = 1;
|
|
|
|
extra_pages += (512 * 1024) / X86_PAGE_SIZE;
|
2024-01-11 17:23:09 -08:00
|
|
|
let mut pages = extra_pages;
|
|
|
|
|
|
|
|
let mut try_virt_end: u64;
|
2024-01-16 17:57:19 -08:00
|
|
|
let mut m: usize;
|
2024-01-11 17:23:09 -08:00
|
|
|
loop {
|
2024-01-16 17:57:19 -08:00
|
|
|
try_virt_end = BootSetup::round_up(
|
|
|
|
self.virt_alloc_end + pages * X86_PAGE_SIZE,
|
|
|
|
BootSetup::bits_to_mask(22),
|
|
|
|
);
|
|
|
|
m = self.count_page_tables(table, image_info.virt_base, try_virt_end, 0)?;
|
|
|
|
pages = table.mappings[m].area.pgtables as u64 + extra_pages;
|
2024-01-11 17:23:09 -08:00
|
|
|
if self.virt_alloc_end + pages * X86_PAGE_SIZE <= try_virt_end + 1 {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
table.mappings[m].area.pfn = 0;
|
|
|
|
table.mappings_count += 1;
|
|
|
|
self.virt_pgtab_end = try_virt_end + 1;
|
|
|
|
let segment =
|
|
|
|
self.alloc_segment(0, table.mappings[m].area.pgtables as u64 * X86_PAGE_SIZE)?;
|
2024-01-11 17:23:09 -08:00
|
|
|
debug!(
|
|
|
|
"BootSetup alloc_page_tables table={:?} segment={:?}",
|
|
|
|
table, segment
|
|
|
|
);
|
2024-01-12 14:57:02 -08:00
|
|
|
Ok(segment)
|
2024-01-11 17:23:09 -08:00
|
|
|
}
|
|
|
|
|
2024-01-11 23:54:44 -08:00
|
|
|
fn alloc_segment(&mut self, start: u64, size: u64) -> Result<DomainSegment, XenClientError> {
|
|
|
|
if start > 0 {
|
|
|
|
self.alloc_padding_pages(start)?;
|
|
|
|
}
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
let page_size: u32 = (1i64 << XEN_PAGE_SHIFT) as u32;
|
|
|
|
let pages = (size + page_size as u64 - 1) / page_size as u64;
|
2024-01-11 23:54:44 -08:00
|
|
|
let start = self.virt_alloc_end;
|
|
|
|
|
2024-01-10 16:07:57 -08:00
|
|
|
let mut segment = DomainSegment {
|
2024-01-11 17:23:09 -08:00
|
|
|
vstart: start,
|
2024-01-10 16:07:57 -08:00
|
|
|
_vend: 0,
|
|
|
|
pfn: self.pfn_alloc_end,
|
2024-01-10 23:28:41 -08:00
|
|
|
addr: 0,
|
|
|
|
size,
|
2024-01-16 23:07:34 -08:00
|
|
|
pages,
|
2024-01-10 16:07:57 -08:00
|
|
|
};
|
2024-01-11 23:54:44 -08:00
|
|
|
|
|
|
|
self.chk_alloc_pages(pages)?;
|
|
|
|
|
2024-01-10 16:07:57 -08:00
|
|
|
let ptr = self.phys.pfn_to_ptr(segment.pfn, pages)?;
|
2024-01-10 23:28:41 -08:00
|
|
|
segment.addr = ptr;
|
2024-01-16 17:57:19 -08:00
|
|
|
let slice = unsafe {
|
|
|
|
slice::from_raw_parts_mut(ptr as *mut u8, (pages * page_size as u64) as usize)
|
|
|
|
};
|
2024-01-14 16:00:44 -08:00
|
|
|
slice.fill(0);
|
2024-01-10 16:07:57 -08:00
|
|
|
segment._vend = self.virt_alloc_end;
|
2024-01-11 23:54:44 -08:00
|
|
|
debug!(
|
2024-01-12 14:57:02 -08:00
|
|
|
"BootSetup alloc_segment {:#x} -> {:#x} (pfn {:#x} + {:#x} pages)",
|
2024-01-12 02:12:29 -08:00
|
|
|
start, segment._vend, segment.pfn, pages
|
2024-01-11 23:54:44 -08:00
|
|
|
);
|
2024-01-10 16:07:57 -08:00
|
|
|
Ok(segment)
|
|
|
|
}
|
2024-01-11 17:23:09 -08:00
|
|
|
|
|
|
|
fn alloc_page(&mut self) -> Result<DomainSegment, XenClientError> {
|
2024-01-12 02:12:29 -08:00
|
|
|
let start = self.virt_alloc_end;
|
|
|
|
let pfn = self.pfn_alloc_end;
|
|
|
|
|
|
|
|
self.chk_alloc_pages(1)?;
|
2024-01-12 14:57:02 -08:00
|
|
|
debug!("BootSetup alloc_page {:#x} (pfn {:#x})", start, pfn);
|
2024-01-12 02:12:29 -08:00
|
|
|
Ok(DomainSegment {
|
|
|
|
vstart: start,
|
|
|
|
_vend: (start + X86_PAGE_SIZE) - 1,
|
|
|
|
pfn,
|
|
|
|
addr: 0,
|
|
|
|
size: 0,
|
2024-01-16 23:07:34 -08:00
|
|
|
pages: 1,
|
2024-01-12 02:12:29 -08:00
|
|
|
})
|
2024-01-11 23:54:44 -08:00
|
|
|
}
|
|
|
|
|
2024-01-16 17:57:19 -08:00
|
|
|
fn alloc_module(&mut self, buffer: &[u8]) -> Result<DomainSegment, XenClientError> {
|
|
|
|
let segment = self.alloc_segment(0, buffer.len() as u64)?;
|
|
|
|
let slice = unsafe { slice::from_raw_parts_mut(segment.addr as *mut u8, buffer.len()) };
|
|
|
|
copy(slice, buffer);
|
|
|
|
Ok(segment)
|
|
|
|
}
|
|
|
|
|
2024-01-11 23:54:44 -08:00
|
|
|
fn alloc_padding_pages(&mut self, boundary: u64) -> Result<(), XenClientError> {
|
|
|
|
if (boundary & (X86_PAGE_SIZE - 1)) != 0 {
|
|
|
|
return Err(XenClientError::new(
|
|
|
|
format!("segment boundary isn't page aligned: {:#x}", boundary).as_str(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
if boundary < self.virt_alloc_end {
|
2024-01-16 17:57:19 -08:00
|
|
|
return Err(XenClientError::new(
|
|
|
|
format!("segment boundary too low: {:#x})", boundary).as_str(),
|
|
|
|
));
|
2024-01-11 23:54:44 -08:00
|
|
|
}
|
|
|
|
let pages = (boundary - self.virt_alloc_end) / X86_PAGE_SIZE;
|
|
|
|
self.chk_alloc_pages(pages)?;
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
fn chk_alloc_pages(&mut self, pages: u64) -> Result<(), XenClientError> {
|
|
|
|
if pages > self.total_pages
|
|
|
|
|| self.pfn_alloc_end > self.total_pages
|
|
|
|
|| pages > self.total_pages - self.pfn_alloc_end
|
|
|
|
{
|
|
|
|
return Err(XenClientError::new(
|
|
|
|
format!(
|
|
|
|
"segment too large: pages={} total_pages={} pfn_alloc_end={}",
|
|
|
|
pages, self.total_pages, self.pfn_alloc_end
|
|
|
|
)
|
|
|
|
.as_str(),
|
|
|
|
));
|
|
|
|
}
|
|
|
|
|
|
|
|
self.pfn_alloc_end += pages;
|
|
|
|
self.virt_alloc_end += pages * X86_PAGE_SIZE;
|
|
|
|
Ok(())
|
2024-01-11 17:23:09 -08:00
|
|
|
}
|
2024-01-09 22:39:32 -08:00
|
|
|
}
|