mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-02 21:00:55 +00:00
multiple fixes to vcpu setup and memory allocation
This commit is contained in:
parent
1f30f8315a
commit
a9275c4bdf
@ -33,3 +33,7 @@ path = "examples/domain_create.rs"
|
|||||||
[[example]]
|
[[example]]
|
||||||
name = "xencall-version-capabilities"
|
name = "xencall-version-capabilities"
|
||||||
path = "examples/version_capabilities.rs"
|
path = "examples/version_capabilities.rs"
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "xencall-vcpu-context"
|
||||||
|
path = "examples/vcpu_context.rs"
|
||||||
|
12
xencall/examples/vcpu_context.rs
Normal file
12
xencall/examples/vcpu_context.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
use xencall::domctl::DomainControl;
|
||||||
|
use xencall::{XenCall, XenCallError};
|
||||||
|
|
||||||
|
fn main() -> Result<(), XenCallError> {
|
||||||
|
env_logger::init();
|
||||||
|
|
||||||
|
let call = XenCall::open()?;
|
||||||
|
let domctl: DomainControl = DomainControl::new(&call);
|
||||||
|
let context = domctl.get_vcpu_context(224, 0)?;
|
||||||
|
println!("{:?}", context);
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -2,8 +2,9 @@ use crate::sys::{
|
|||||||
AddressSize, ArchDomainConfig, CreateDomain, DomCtl, DomCtlValue, DomCtlVcpuContext,
|
AddressSize, ArchDomainConfig, CreateDomain, DomCtl, DomCtlValue, DomCtlVcpuContext,
|
||||||
GetDomainInfo, HypercallInit, MaxMem, MaxVcpus, VcpuGuestContext, VcpuGuestContextAny,
|
GetDomainInfo, HypercallInit, MaxMem, MaxVcpus, VcpuGuestContext, VcpuGuestContextAny,
|
||||||
HYPERVISOR_DOMCTL, XEN_DOMCTL_CREATEDOMAIN, XEN_DOMCTL_DESTROYDOMAIN, XEN_DOMCTL_GETDOMAININFO,
|
HYPERVISOR_DOMCTL, XEN_DOMCTL_CREATEDOMAIN, XEN_DOMCTL_DESTROYDOMAIN, XEN_DOMCTL_GETDOMAININFO,
|
||||||
XEN_DOMCTL_HYPERCALL_INIT, XEN_DOMCTL_INTERFACE_VERSION, XEN_DOMCTL_MAX_MEM,
|
XEN_DOMCTL_GETVCPUCONTEXT, XEN_DOMCTL_HYPERCALL_INIT, XEN_DOMCTL_INTERFACE_VERSION,
|
||||||
XEN_DOMCTL_MAX_VCPUS, XEN_DOMCTL_SETVCPUCONTEXT, XEN_DOMCTL_SET_ADDRESS_SIZE,
|
XEN_DOMCTL_MAX_MEM, XEN_DOMCTL_MAX_VCPUS, XEN_DOMCTL_PAUSEDOMAIN, XEN_DOMCTL_SETVCPUCONTEXT,
|
||||||
|
XEN_DOMCTL_SET_ADDRESS_SIZE,
|
||||||
};
|
};
|
||||||
use crate::{XenCall, XenCallError};
|
use crate::{XenCall, XenCallError};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
@ -77,6 +78,23 @@ impl DomainControl<'_> {
|
|||||||
Ok(domctl.domid)
|
Ok(domctl.domid)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pause_domain(&self, domid: u32) -> Result<(), XenCallError> {
|
||||||
|
trace!(
|
||||||
|
"domctl fd={} pause_domain domid={:?}",
|
||||||
|
self.call.handle.as_raw_fd(),
|
||||||
|
domid,
|
||||||
|
);
|
||||||
|
let mut domctl = DomCtl {
|
||||||
|
cmd: XEN_DOMCTL_PAUSEDOMAIN,
|
||||||
|
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||||
|
domid,
|
||||||
|
value: DomCtlValue { pad: [0; 128] },
|
||||||
|
};
|
||||||
|
self.call
|
||||||
|
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_max_mem(&self, domid: u32, memkb: u64) -> Result<(), XenCallError> {
|
pub fn set_max_mem(&self, domid: u32, memkb: u64) -> Result<(), XenCallError> {
|
||||||
trace!(
|
trace!(
|
||||||
"domctl fd={} set_max_mem domid={} memkb={}",
|
"domctl fd={} set_max_mem domid={} memkb={}",
|
||||||
@ -137,6 +155,35 @@ impl DomainControl<'_> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn get_vcpu_context(
|
||||||
|
&self,
|
||||||
|
domid: u32,
|
||||||
|
vcpu: u32,
|
||||||
|
) -> Result<VcpuGuestContext, XenCallError> {
|
||||||
|
trace!(
|
||||||
|
"domctl fd={} get_vcpu_context domid={}",
|
||||||
|
self.call.handle.as_raw_fd(),
|
||||||
|
domid,
|
||||||
|
);
|
||||||
|
let mut wrapper = VcpuGuestContextAny {
|
||||||
|
value: VcpuGuestContext::default(),
|
||||||
|
};
|
||||||
|
let mut domctl = DomCtl {
|
||||||
|
cmd: XEN_DOMCTL_GETVCPUCONTEXT,
|
||||||
|
interface_version: XEN_DOMCTL_INTERFACE_VERSION,
|
||||||
|
domid,
|
||||||
|
value: DomCtlValue {
|
||||||
|
vcpu_context: DomCtlVcpuContext {
|
||||||
|
vcpu,
|
||||||
|
ctx: addr_of_mut!(wrapper) as c_ulong,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
self.call
|
||||||
|
.hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
|
||||||
|
Ok(unsafe { wrapper.value })
|
||||||
|
}
|
||||||
|
|
||||||
pub fn set_vcpu_context(
|
pub fn set_vcpu_context(
|
||||||
&self,
|
&self,
|
||||||
domid: u32,
|
domid: u32,
|
||||||
|
@ -3,11 +3,9 @@ use crate::sys::{
|
|||||||
};
|
};
|
||||||
use crate::{XenCall, XenCallError};
|
use crate::{XenCall, XenCallError};
|
||||||
|
|
||||||
|
use log::{trace};
|
||||||
use std::ffi::c_ulong;
|
use std::ffi::c_ulong;
|
||||||
use std::os::fd::AsRawFd;
|
use std::os::fd::AsRawFd;
|
||||||
|
|
||||||
use libc::c_long;
|
|
||||||
use log::trace;
|
|
||||||
use std::ptr::addr_of_mut;
|
use std::ptr::addr_of_mut;
|
||||||
|
|
||||||
pub struct MemoryControl<'a> {
|
pub struct MemoryControl<'a> {
|
||||||
@ -29,8 +27,10 @@ impl MemoryControl<'_> {
|
|||||||
) -> Result<Vec<u64>, XenCallError> {
|
) -> Result<Vec<u64>, XenCallError> {
|
||||||
trace!("memory fd={} populate_physmap domid={} nr_extents={} extent_order={} mem_flags={} extent_starts={:?}", self.call.handle.as_raw_fd(), domid, nr_extents, extent_order, mem_flags, extent_starts);
|
trace!("memory fd={} populate_physmap domid={} nr_extents={} extent_order={} mem_flags={} extent_starts={:?}", self.call.handle.as_raw_fd(), domid, nr_extents, extent_order, mem_flags, extent_starts);
|
||||||
let mut extent_starts = extent_starts.to_vec();
|
let mut extent_starts = extent_starts.to_vec();
|
||||||
|
let ptr = extent_starts.as_mut_ptr();
|
||||||
|
|
||||||
let mut reservation = MemoryReservation {
|
let mut reservation = MemoryReservation {
|
||||||
extent_start: extent_starts.as_mut_ptr() as c_ulong,
|
extent_start: ptr as c_ulong,
|
||||||
nr_extents,
|
nr_extents,
|
||||||
extent_order,
|
extent_order,
|
||||||
mem_flags,
|
mem_flags,
|
||||||
@ -50,15 +50,13 @@ impl MemoryControl<'_> {
|
|||||||
],
|
],
|
||||||
}];
|
}];
|
||||||
self.call.multicall(calls)?;
|
self.call.multicall(calls)?;
|
||||||
let code = calls[0].result as c_long;
|
let code = calls[0].result;
|
||||||
if code < 0 {
|
if code > !0xfff {
|
||||||
return Err(XenCallError::new("failed to populate physmap"));
|
return Err(XenCallError::new("failed to populate physmap"));
|
||||||
}
|
}
|
||||||
|
|
||||||
if code as usize > extent_starts.len() {
|
if code as usize > extent_starts.len() {
|
||||||
return Err(XenCallError::new("failed to populate physmap"));
|
return Err(XenCallError::new("failed to populate physmap"));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(extent_starts[0..code as usize].to_vec())
|
Ok(extent_starts[0..code as usize].to_vec())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -313,7 +313,7 @@ pub struct HypercallInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub const XEN_DOMCTL_INTERFACE_VERSION: u32 = 0x00000015;
|
pub const XEN_DOMCTL_INTERFACE_VERSION: u32 = 0x00000015;
|
||||||
pub const SECINITSID_DOMU: u32 = 13;
|
pub const SECINITSID_DOMU: u32 = 12;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
@ -19,6 +19,8 @@ fn main() -> Result<(), XenClientError> {
|
|||||||
let call = XenCall::open()?;
|
let call = XenCall::open()?;
|
||||||
let domctl = DomainControl::new(&call);
|
let domctl = DomainControl::new(&call);
|
||||||
let domid = domctl.create_domain(CreateDomain::default())?;
|
let domid = domctl.create_domain(CreateDomain::default())?;
|
||||||
|
domctl.pause_domain(domid)?;
|
||||||
|
domctl.set_max_vcpus(domid, 1)?;
|
||||||
let result = boot(domid, kernel_image_path.as_str(), &call, &domctl);
|
let result = boot(domid, kernel_image_path.as_str(), &call, &domctl);
|
||||||
domctl.destroy_domain(domid)?;
|
domctl.destroy_domain(domid)?;
|
||||||
result?;
|
result?;
|
||||||
|
@ -10,7 +10,8 @@ use crate::x86::{
|
|||||||
};
|
};
|
||||||
use crate::XenClientError;
|
use crate::XenClientError;
|
||||||
use libc::{c_char, memset};
|
use libc::{c_char, memset};
|
||||||
use log::debug;
|
use log::{debug, trace};
|
||||||
|
use slice_copy::copy;
|
||||||
use std::cmp::{max, min};
|
use std::cmp::{max, min};
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
@ -34,7 +35,7 @@ pub struct BootImageInfo {
|
|||||||
pub virt_kend: u64,
|
pub virt_kend: u64,
|
||||||
pub virt_hypercall: u64,
|
pub virt_hypercall: u64,
|
||||||
pub virt_entry: u64,
|
pub virt_entry: u64,
|
||||||
pub init_p2m: u64,
|
pub virt_p2m_base: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct BootSetup<'a> {
|
pub struct BootSetup<'a> {
|
||||||
@ -72,6 +73,7 @@ pub struct BootState {
|
|||||||
pub xenstore_segment: DomainSegment,
|
pub xenstore_segment: DomainSegment,
|
||||||
pub console_segment: DomainSegment,
|
pub console_segment: DomainSegment,
|
||||||
pub boot_stack_segment: DomainSegment,
|
pub boot_stack_segment: DomainSegment,
|
||||||
|
pub p2m_segment: DomainSegment,
|
||||||
pub page_table_segment: DomainSegment,
|
pub page_table_segment: DomainSegment,
|
||||||
pub page_table: PageTable,
|
pub page_table: PageTable,
|
||||||
pub image_info: BootImageInfo,
|
pub image_info: BootImageInfo,
|
||||||
@ -119,7 +121,7 @@ impl BootSetup<'_> {
|
|||||||
|
|
||||||
if total != page_count {
|
if total != page_count {
|
||||||
return Err(XenClientError::new(
|
return Err(XenClientError::new(
|
||||||
"Page count mismatch while calculating pages.",
|
"page count mismatch while calculating pages",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +129,7 @@ impl BootSetup<'_> {
|
|||||||
|
|
||||||
let mut p2m = vec![-1i64 as u64; p2m_size as usize];
|
let mut p2m = vec![-1i64 as u64; p2m_size as usize];
|
||||||
for range in &vmemranges {
|
for range in &vmemranges {
|
||||||
let mut extents = vec![0u64; SUPERPAGE_BATCH_SIZE as usize];
|
let mut extents_init = vec![0u64; SUPERPAGE_BATCH_SIZE as usize];
|
||||||
let pages = (range.end - range.start) >> XEN_PAGE_SHIFT;
|
let pages = (range.end - range.start) >> XEN_PAGE_SHIFT;
|
||||||
let pfn_base = range.start >> XEN_PAGE_SHIFT;
|
let pfn_base = range.start >> XEN_PAGE_SHIFT;
|
||||||
|
|
||||||
@ -147,21 +149,21 @@ impl BootSetup<'_> {
|
|||||||
if pfn >= pfn_base_idx + (count << SUPERPAGE_2MB_SHIFT) {
|
if pfn >= pfn_base_idx + (count << SUPERPAGE_2MB_SHIFT) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
extents[j] = p2m[pfn as usize];
|
extents_init[j] = p2m[pfn as usize];
|
||||||
pfn += SUPERPAGE_2MB_NR_PFNS;
|
pfn += SUPERPAGE_2MB_NR_PFNS;
|
||||||
j += 1;
|
j += 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let starts = self.memctl.populate_physmap(
|
let extents = self.memctl.populate_physmap(
|
||||||
self.domid,
|
self.domid,
|
||||||
count,
|
count,
|
||||||
SUPERPAGE_2MB_SHIFT as u32,
|
SUPERPAGE_2MB_SHIFT as u32,
|
||||||
0,
|
0,
|
||||||
extents.as_slice(),
|
extents_init.as_slice(),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
pfn = pfn_base_idx;
|
pfn = pfn_base_idx;
|
||||||
for mfn in starts {
|
for mfn in extents {
|
||||||
for k in 0..SUPERPAGE_2MB_NR_PFNS {
|
for k in 0..SUPERPAGE_2MB_NR_PFNS {
|
||||||
p2m[pfn as usize] = mfn + k;
|
p2m[pfn as usize] = mfn + k;
|
||||||
pfn += 1;
|
pfn += 1;
|
||||||
@ -192,8 +194,7 @@ impl BootSetup<'_> {
|
|||||||
format!("failed to populate physmap: {:?}", result).as_str(),
|
format!("failed to populate physmap: {:?}", result).as_str(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
copy(p2m.as_mut_slice(), result.as_slice());
|
||||||
p2m[p2m_idx] = result[0];
|
|
||||||
j += allocsz;
|
j += allocsz;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -223,27 +224,31 @@ impl BootSetup<'_> {
|
|||||||
self.initialize_memory(memkb)?;
|
self.initialize_memory(memkb)?;
|
||||||
|
|
||||||
let image_info = image_loader.parse()?;
|
let image_info = image_loader.parse()?;
|
||||||
|
debug!("BootSetup initialize image_info={:?}", image_info);
|
||||||
self.virt_alloc_end = image_info.virt_base;
|
self.virt_alloc_end = image_info.virt_base;
|
||||||
let kernel_segment = self.load_kernel_segment(image_loader, &image_info)?;
|
let kernel_segment = self.load_kernel_segment(image_loader, &image_info)?;
|
||||||
let start_info_segment = self.alloc_page()?;
|
let start_info_segment = self.alloc_page()?;
|
||||||
let xenstore_segment = self.alloc_page()?;
|
let xenstore_segment = self.alloc_page()?;
|
||||||
let console_segment = self.alloc_page()?;
|
let console_segment = self.alloc_page()?;
|
||||||
let (page_table_segment, page_table) = self.alloc_page_tables(&image_info)?;
|
let mut page_table = PageTable::default();
|
||||||
|
let page_table_segment = self.alloc_page_tables(&mut page_table, &image_info)?;
|
||||||
let boot_stack_segment = self.alloc_page()?;
|
let boot_stack_segment = self.alloc_page()?;
|
||||||
if self.virt_pgtab_end > 0 {
|
if self.virt_pgtab_end > 0 {
|
||||||
self.alloc_padding_pages(self.virt_pgtab_end)?;
|
self.alloc_padding_pages(self.virt_pgtab_end)?;
|
||||||
}
|
}
|
||||||
|
let p2m_segment = self.alloc_p2m_segment(&mut page_table, &image_info)?;
|
||||||
let state = BootState {
|
let state = BootState {
|
||||||
kernel_segment,
|
kernel_segment,
|
||||||
start_info_segment,
|
start_info_segment,
|
||||||
xenstore_segment,
|
xenstore_segment,
|
||||||
console_segment,
|
console_segment,
|
||||||
boot_stack_segment,
|
boot_stack_segment,
|
||||||
|
p2m_segment,
|
||||||
page_table_segment,
|
page_table_segment,
|
||||||
page_table,
|
page_table,
|
||||||
image_info,
|
image_info,
|
||||||
};
|
};
|
||||||
debug!("initialize state={:?}", state);
|
debug!("BootSetup initialize state={:?}", state);
|
||||||
Ok(state)
|
Ok(state)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,12 +269,12 @@ impl BootSetup<'_> {
|
|||||||
vcpu.flags = VGCF_IN_KERNEL | VGCF_ONLINE;
|
vcpu.flags = VGCF_IN_KERNEL | VGCF_ONLINE;
|
||||||
let cr3_pfn = self.phys.p2m[state.page_table_segment.pfn as usize];
|
let cr3_pfn = self.phys.p2m[state.page_table_segment.pfn as usize];
|
||||||
vcpu.ctrlreg[3] = cr3_pfn << 12;
|
vcpu.ctrlreg[3] = cr3_pfn << 12;
|
||||||
vcpu.user_regs.ds = 0xe021;
|
vcpu.user_regs.ds = 0x0;
|
||||||
vcpu.user_regs.es = 0xe021;
|
vcpu.user_regs.es = 0x0;
|
||||||
vcpu.user_regs.fs = 0xe021;
|
vcpu.user_regs.fs = 0x0;
|
||||||
vcpu.user_regs.gs = 0xe021;
|
vcpu.user_regs.gs = 0x0;
|
||||||
vcpu.user_regs.ss = 0xe02b;
|
vcpu.user_regs.ss = 0xe02b;
|
||||||
vcpu.user_regs.cs = 0xe019;
|
vcpu.user_regs.cs = 0xe033;
|
||||||
vcpu.kernel_ss = vcpu.user_regs.ss as u64;
|
vcpu.kernel_ss = vcpu.user_regs.ss as u64;
|
||||||
vcpu.kernel_sp = vcpu.user_regs.rsp;
|
vcpu.kernel_sp = vcpu.user_regs.rsp;
|
||||||
self.domctl.set_vcpu_context(self.domid, 0, Some(&vcpu))?;
|
self.domctl.set_vcpu_context(self.domid, 0, Some(&vcpu))?;
|
||||||
@ -277,7 +282,15 @@ impl BootSetup<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn setup_page_tables(&mut self, state: &mut BootState) -> Result<(), XenClientError> {
|
fn setup_page_tables(&mut self, state: &mut BootState) -> Result<(), XenClientError> {
|
||||||
for lvl_idx in (0usize..3usize).rev() {
|
let p2m_guest = unsafe {
|
||||||
|
slice::from_raw_parts_mut(
|
||||||
|
state.p2m_segment.addr as *mut u64,
|
||||||
|
state.p2m_segment.size as usize,
|
||||||
|
)
|
||||||
|
};
|
||||||
|
copy(p2m_guest, &self.phys.p2m);
|
||||||
|
|
||||||
|
for lvl_idx in (0usize..X86_PGTABLE_LEVELS as usize).rev() {
|
||||||
for map_idx_1 in 0usize..state.page_table.mappings_count {
|
for map_idx_1 in 0usize..state.page_table.mappings_count {
|
||||||
let map1 = &state.page_table.mappings[map_idx_1];
|
let map1 = &state.page_table.mappings[map_idx_1];
|
||||||
let from = map1.levels[lvl_idx].from;
|
let from = map1.levels[lvl_idx].from;
|
||||||
@ -337,7 +350,7 @@ impl BootSetup<'_> {
|
|||||||
(*info).nr_p2m_frames = 0;
|
(*info).nr_p2m_frames = 0;
|
||||||
(*info).flags = 0;
|
(*info).flags = 0;
|
||||||
(*info).store_evtchn = 0;
|
(*info).store_evtchn = 0;
|
||||||
(*info).store_mfn = 0;
|
(*info).store_mfn = self.phys.p2m[state.xenstore_segment.pfn as usize];
|
||||||
(*info).console.mfn = self.phys.p2m[state.console_segment.pfn as usize];
|
(*info).console.mfn = self.phys.p2m[state.console_segment.pfn as usize];
|
||||||
(*info).console.evtchn = 0;
|
(*info).console.evtchn = 0;
|
||||||
(*info).mod_start = 0;
|
(*info).mod_start = 0;
|
||||||
@ -346,7 +359,7 @@ impl BootSetup<'_> {
|
|||||||
(*info).cmdline[i] = c as c_char;
|
(*info).cmdline[i] = c as c_char;
|
||||||
(*info).cmdline[MAX_GUEST_CMDLINE - 1] = 0;
|
(*info).cmdline[MAX_GUEST_CMDLINE - 1] = 0;
|
||||||
}
|
}
|
||||||
debug!("BootSetup setup_start_info={:?}", *info);
|
trace!("BootSetup setup_start_info start_info={:?}", *info);
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -361,10 +374,6 @@ impl BootSetup<'_> {
|
|||||||
image_info.virt_kend - image_info.virt_kstart,
|
image_info.virt_kend - image_info.virt_kstart,
|
||||||
)?;
|
)?;
|
||||||
let kernel_segment_ptr = kernel_segment.addr as *mut u8;
|
let kernel_segment_ptr = kernel_segment.addr as *mut u8;
|
||||||
debug!(
|
|
||||||
"BootSetup initialize kernel_segment ptr={:#x}",
|
|
||||||
kernel_segment_ptr as u64
|
|
||||||
);
|
|
||||||
let kernel_segment_slice =
|
let kernel_segment_slice =
|
||||||
unsafe { slice::from_raw_parts_mut(kernel_segment_ptr, kernel_segment.size as usize) };
|
unsafe { slice::from_raw_parts_mut(kernel_segment_ptr, kernel_segment.size as usize) };
|
||||||
image_loader.load(image_info, kernel_segment_slice)?;
|
image_loader.load(image_info, kernel_segment_slice)?;
|
||||||
@ -399,7 +408,7 @@ impl BootSetup<'_> {
|
|||||||
map.area.from = from & X86_VIRT_MASK;
|
map.area.from = from & X86_VIRT_MASK;
|
||||||
map.area.to = to & X86_VIRT_MASK;
|
map.area.to = to & X86_VIRT_MASK;
|
||||||
|
|
||||||
for lvl_index in (0usize..3usize).rev() {
|
for lvl_index in (0usize..X86_PGTABLE_LEVELS as usize).rev() {
|
||||||
let lvl = &mut map.levels[lvl_index];
|
let lvl = &mut map.levels[lvl_index];
|
||||||
lvl.pfn = self.pfn_alloc_end + map.area.pgtables as u64;
|
lvl.pfn = self.pfn_alloc_end + map.area.pgtables as u64;
|
||||||
if lvl_index as u64 == X86_PGTABLE_LEVELS - 1 {
|
if lvl_index as u64 == X86_PGTABLE_LEVELS - 1 {
|
||||||
@ -443,7 +452,7 @@ impl BootSetup<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
debug!(
|
debug!(
|
||||||
"count_pgtables {:#x}/{}: {:#x} -> {:#x}, {} tables",
|
"BootSetup count_pgtables {:#x}/{}: {:#x} -> {:#x}, {} tables",
|
||||||
mask, bits, lvl.from, lvl.to, lvl.pgtables
|
mask, bits, lvl.from, lvl.to, lvl.pgtables
|
||||||
);
|
);
|
||||||
map.area.pgtables += lvl.pgtables;
|
map.area.pgtables += lvl.pgtables;
|
||||||
@ -451,20 +460,47 @@ impl BootSetup<'_> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
self.count_page_tables(page_table, from, to, self.pfn_alloc_end)?;
|
||||||
|
|
||||||
|
let pgtables: usize;
|
||||||
|
{
|
||||||
|
let map = &mut page_table.mappings[page_table.mappings_count];
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
|
||||||
fn alloc_page_tables(
|
fn alloc_page_tables(
|
||||||
&mut self,
|
&mut self,
|
||||||
|
table: &mut PageTable,
|
||||||
image_info: &BootImageInfo,
|
image_info: &BootImageInfo,
|
||||||
) -> Result<(DomainSegment, PageTable), XenClientError> {
|
) -> Result<DomainSegment, XenClientError> {
|
||||||
let mut table = PageTable::default();
|
|
||||||
let mut extra_pages = 1;
|
let mut extra_pages = 1;
|
||||||
extra_pages += (512 * 1024) / X86_PAGE_SIZE;
|
extra_pages += (512 * 1024) / X86_PAGE_SIZE;
|
||||||
let mut pages = extra_pages;
|
let mut pages = extra_pages;
|
||||||
|
let nr_mappings = table.mappings_count;
|
||||||
|
|
||||||
let mut try_virt_end: u64;
|
let mut try_virt_end: u64;
|
||||||
loop {
|
loop {
|
||||||
try_virt_end = (self.virt_alloc_end + pages * X86_PAGE_SIZE) | ((1 << 22) - 1);
|
try_virt_end = (self.virt_alloc_end + pages * X86_PAGE_SIZE) | ((1 << 22) - 1);
|
||||||
self.count_page_tables(&mut table, image_info.virt_base, try_virt_end, 0)?;
|
self.count_page_tables(table, image_info.virt_base, try_virt_end, 0)?;
|
||||||
pages = table.mappings[0].area.pgtables as u64 + extra_pages;
|
pages = table.mappings[nr_mappings].area.pgtables as u64 + extra_pages;
|
||||||
if self.virt_alloc_end + pages * X86_PAGE_SIZE <= try_virt_end + 1 {
|
if self.virt_alloc_end + pages * X86_PAGE_SIZE <= try_virt_end + 1 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -472,18 +508,17 @@ impl BootSetup<'_> {
|
|||||||
|
|
||||||
let segment: DomainSegment;
|
let segment: DomainSegment;
|
||||||
{
|
{
|
||||||
let map = &mut table.mappings[table.mappings_count];
|
let map = &mut table.mappings[nr_mappings];
|
||||||
map.area.pfn = 0;
|
map.area.pfn = 0;
|
||||||
table.mappings_count += 1;
|
table.mappings_count += 1;
|
||||||
self.virt_pgtab_end = try_virt_end + 1;
|
self.virt_pgtab_end = try_virt_end + 1;
|
||||||
segment =
|
segment = self.alloc_segment(0, map.area.pgtables as u64 * X86_PAGE_SIZE)?;
|
||||||
self.alloc_segment(0, (map.area.pgtables as u64 * X86_PAGE_SIZE) + extra_pages)?;
|
|
||||||
}
|
}
|
||||||
debug!(
|
debug!(
|
||||||
"BootSetup alloc_page_tables table={:?} segment={:?}",
|
"BootSetup alloc_page_tables table={:?} segment={:?}",
|
||||||
table, segment
|
table, segment
|
||||||
);
|
);
|
||||||
Ok((segment, table))
|
Ok(segment)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_segment(&mut self, start: u64, size: u64) -> Result<DomainSegment, XenClientError> {
|
fn alloc_segment(&mut self, start: u64, size: u64) -> Result<DomainSegment, XenClientError> {
|
||||||
@ -513,7 +548,7 @@ impl BootSetup<'_> {
|
|||||||
}
|
}
|
||||||
segment._vend = self.virt_alloc_end;
|
segment._vend = self.virt_alloc_end;
|
||||||
debug!(
|
debug!(
|
||||||
"alloc_segment {:#x} -> {:#x} (pfn {:#x} + {:#x} pages)",
|
"BootSetup alloc_segment {:#x} -> {:#x} (pfn {:#x} + {:#x} pages)",
|
||||||
start, segment._vend, segment.pfn, pages
|
start, segment._vend, segment.pfn, pages
|
||||||
);
|
);
|
||||||
Ok(segment)
|
Ok(segment)
|
||||||
@ -524,7 +559,7 @@ impl BootSetup<'_> {
|
|||||||
let pfn = self.pfn_alloc_end;
|
let pfn = self.pfn_alloc_end;
|
||||||
|
|
||||||
self.chk_alloc_pages(1)?;
|
self.chk_alloc_pages(1)?;
|
||||||
debug!("alloc_page {:#x} (pfn {:#x})", start, pfn);
|
debug!("BootSetup alloc_page {:#x} (pfn {:#x})", start, pfn);
|
||||||
Ok(DomainSegment {
|
Ok(DomainSegment {
|
||||||
vstart: start,
|
vstart: start,
|
||||||
_vend: (start + X86_PAGE_SIZE) - 1,
|
_vend: (start + X86_PAGE_SIZE) - 1,
|
||||||
|
@ -270,15 +270,16 @@ impl BootImageLoader for ElfImageLoader {
|
|||||||
let virt_kend = end + virt_offset;
|
let virt_kend = end + virt_offset;
|
||||||
let virt_entry = entry;
|
let virt_entry = entry;
|
||||||
|
|
||||||
Ok(BootImageInfo {
|
let image_info = BootImageInfo {
|
||||||
start,
|
start,
|
||||||
virt_base,
|
virt_base,
|
||||||
virt_kstart,
|
virt_kstart,
|
||||||
virt_kend,
|
virt_kend,
|
||||||
virt_hypercall,
|
virt_hypercall,
|
||||||
virt_entry,
|
virt_entry,
|
||||||
init_p2m,
|
virt_p2m_base: init_p2m,
|
||||||
})
|
};
|
||||||
|
Ok(image_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<(), XenClientError> {
|
fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<(), XenClientError> {
|
||||||
|
Loading…
Reference in New Issue
Block a user