actually allocate max memory

This commit is contained in:
Alex Zenla
2024-01-10 19:18:48 -08:00
parent 153619a02c
commit 629c3d81b0
7 changed files with 80 additions and 64 deletions

View File

@ -6,7 +6,7 @@ use crate::sys::{
}; };
use crate::{XenCall, XenCallError}; use crate::{XenCall, XenCallError};
use std::ffi::c_ulong; use std::ffi::c_ulong;
use std::ptr::addr_of; use std::ptr::addr_of_mut;
pub struct DomainControl<'a> { pub struct DomainControl<'a> {
call: &'a XenCall, call: &'a XenCall,
@ -18,7 +18,7 @@ impl DomainControl<'_> {
} }
pub fn get_domain_info(&self, domid: u32) -> Result<GetDomainInfo, XenCallError> { pub fn get_domain_info(&self, domid: u32) -> Result<GetDomainInfo, XenCallError> {
let domctl = DomCtl { let mut domctl = DomCtl {
cmd: XEN_DOMCTL_GETDOMAININFO, cmd: XEN_DOMCTL_GETDOMAININFO,
interface_version: XEN_DOMCTL_INTERFACE_VERSION, interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid, domid,
@ -48,24 +48,24 @@ impl DomainControl<'_> {
}, },
}; };
self.call self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of!(domctl) as c_ulong)?; .hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(unsafe { domctl.value.get_domain_info }) Ok(unsafe { domctl.value.get_domain_info })
} }
pub fn create_domain(&self, create_domain: CreateDomain) -> Result<u32, XenCallError> { pub fn create_domain(&self, create_domain: CreateDomain) -> Result<u32, XenCallError> {
let domctl = DomCtl { let mut domctl = DomCtl {
cmd: XEN_DOMCTL_CREATEDOMAIN, cmd: XEN_DOMCTL_CREATEDOMAIN,
interface_version: XEN_DOMCTL_INTERFACE_VERSION, interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid: 0, domid: 0,
value: DomCtlValue { create_domain }, value: DomCtlValue { create_domain },
}; };
self.call self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of!(domctl) as c_ulong)?; .hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(domctl.domid) Ok(domctl.domid)
} }
pub fn set_max_mem(&mut self, domid: u32, memkb: u64) -> Result<(), XenCallError> { pub fn set_max_mem(&self, domid: u32, memkb: u64) -> Result<(), XenCallError> {
let domctl = DomCtl { let mut domctl = DomCtl {
cmd: XEN_DOMCTL_MAX_MEM, cmd: XEN_DOMCTL_MAX_MEM,
interface_version: XEN_DOMCTL_INTERFACE_VERSION, interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid, domid,
@ -74,12 +74,12 @@ impl DomainControl<'_> {
}, },
}; };
self.call self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of!(domctl) as c_ulong)?; .hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(()) Ok(())
} }
pub fn set_max_vcpus(&mut self, domid: u32, max_vcpus: u32) -> Result<(), XenCallError> { pub fn set_max_vcpus(&self, domid: u32, max_vcpus: u32) -> Result<(), XenCallError> {
let domctl = DomCtl { let mut domctl = DomCtl {
cmd: XEN_DOMCTL_MAX_VCPUS, cmd: XEN_DOMCTL_MAX_VCPUS,
interface_version: XEN_DOMCTL_INTERFACE_VERSION, interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid, domid,
@ -88,12 +88,12 @@ impl DomainControl<'_> {
}, },
}; };
self.call self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of!(domctl) as c_ulong)?; .hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(()) Ok(())
} }
pub fn hypercall_init(&self, domid: u32, gmfn: u64) -> Result<(), XenCallError> { pub fn hypercall_init(&self, domid: u32, gmfn: u64) -> Result<(), XenCallError> {
let domctl = DomCtl { let mut domctl = DomCtl {
cmd: XEN_DOMCTL_HYPERCALL_INIT, cmd: XEN_DOMCTL_HYPERCALL_INIT,
interface_version: XEN_DOMCTL_INTERFACE_VERSION, interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid, domid,
@ -102,19 +102,19 @@ impl DomainControl<'_> {
}, },
}; };
self.call self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of!(domctl) as c_ulong)?; .hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(()) Ok(())
} }
pub fn destroy_domain(&self, domid: u32) -> Result<(), XenCallError> { pub fn destroy_domain(&self, domid: u32) -> Result<(), XenCallError> {
let domctl = DomCtl { let mut domctl = DomCtl {
cmd: XEN_DOMCTL_DESTROYDOMAIN, cmd: XEN_DOMCTL_DESTROYDOMAIN,
interface_version: XEN_DOMCTL_INTERFACE_VERSION, interface_version: XEN_DOMCTL_INTERFACE_VERSION,
domid, domid,
value: DomCtlValue { pad: [0; 128] }, value: DomCtlValue { pad: [0; 128] },
}; };
self.call self.call
.hypercall1(HYPERVISOR_DOMCTL, addr_of!(domctl) as c_ulong)?; .hypercall1(HYPERVISOR_DOMCTL, addr_of_mut!(domctl) as c_ulong)?;
Ok(()) Ok(())
} }
} }

View File

@ -12,7 +12,7 @@ use std::ffi::{c_long, c_ulong, c_void};
use std::fmt::{Display, Formatter}; use std::fmt::{Display, Formatter};
use std::fs::{File, OpenOptions}; use std::fs::{File, OpenOptions};
use std::os::fd::AsRawFd; use std::os::fd::AsRawFd;
use std::ptr::addr_of; use std::ptr::addr_of_mut;
pub struct XenCall { pub struct XenCall {
pub handle: File, pub handle: File,
@ -143,7 +143,7 @@ impl XenCall {
pub fn mmap_batch( pub fn mmap_batch(
&self, &self,
domid: u32, domid: u32,
count: u64, num: u64,
addr: u64, addr: u64,
mfns: Vec<u64>, mfns: Vec<u64>,
) -> Result<c_long, XenCallError> { ) -> Result<c_long, XenCallError> {
@ -151,7 +151,7 @@ impl XenCall {
let mut mfns = mfns.clone(); let mut mfns = mfns.clone();
let mut errors = vec![0i32; mfns.len()]; let mut errors = vec![0i32; mfns.len()];
let mut batch = MmapBatch { let mut batch = MmapBatch {
num: count as u32, num: num as u32,
domid: domid as u16, domid: domid as u16,
addr, addr,
mfns: mfns.as_mut_ptr(), mfns: mfns.as_mut_ptr(),
@ -163,13 +163,13 @@ impl XenCall {
} }
pub fn get_version_capabilities(&self) -> Result<XenCapabilitiesInfo, XenCallError> { pub fn get_version_capabilities(&self) -> Result<XenCapabilitiesInfo, XenCallError> {
let info = XenCapabilitiesInfo { let mut info = XenCapabilitiesInfo {
capabilities: [0; 1024], capabilities: [0; 1024],
}; };
self.hypercall2( self.hypercall2(
HYPERVISOR_XEN_VERSION, HYPERVISOR_XEN_VERSION,
XENVER_CAPABILITIES, XENVER_CAPABILITIES,
addr_of!(info) as c_ulong, addr_of_mut!(info) as c_ulong,
)?; )?;
Ok(info) Ok(info)
} }

View File

@ -3,7 +3,7 @@ use crate::{XenCall, XenCallError};
use std::ffi::c_ulong; use std::ffi::c_ulong;
use std::ptr::addr_of; use std::ptr::addr_of_mut;
pub struct MemoryControl<'a> { pub struct MemoryControl<'a> {
call: &'a XenCall, call: &'a XenCall,
@ -22,19 +22,28 @@ impl MemoryControl<'_> {
mem_flags: u32, mem_flags: u32,
extent_starts: &[u64], extent_starts: &[u64],
) -> Result<Vec<u64>, XenCallError> { ) -> Result<Vec<u64>, XenCallError> {
let extent_starts = extent_starts.to_vec(); let mut extent_starts = extent_starts.to_vec();
let reservation = MemoryReservation { let mut reservation = MemoryReservation {
extent_start: addr_of!(extent_starts) as c_ulong, extent_start: extent_starts.as_mut_ptr() as c_ulong,
nr_extents, nr_extents,
extent_order, extent_order,
mem_flags, mem_flags,
domid: domid as u16, domid: domid as u16,
}; };
self.call.hypercall2( let code = self.call.hypercall2(
HYPERVISOR_MEMORY_OP, HYPERVISOR_MEMORY_OP,
XEN_MEM_POPULATE_PHYSMAP as c_ulong, XEN_MEM_POPULATE_PHYSMAP as c_ulong,
addr_of!(reservation) as c_ulong, addr_of_mut!(reservation) as c_ulong,
)?; )?;
Ok(extent_starts)
if code < 0 {
return Err(XenCallError::new("failed to populate physmap"));
}
if code as usize > extent_starts.len() {
return Err(XenCallError::new("failed to populate physmap"));
}
Ok(extent_starts[0..code as usize].to_vec())
} }
} }

View File

@ -23,8 +23,8 @@ fn main() -> Result<(), XenClientError> {
let image_info = image_loader.parse()?; let image_info = image_loader.parse()?;
println!("loaded kernel image into memory: {:?}", image_info); println!("loaded kernel image into memory: {:?}", image_info);
let memctl = MemoryControl::new(&call); let memctl = MemoryControl::new(&call);
let mut boot = BootSetup::new(&call, &domctl, &memctl, domid, 512 * 1024); let mut boot = BootSetup::new(&call, &domctl, &memctl, domid);
boot.initialize(image_info)?; boot.initialize(image_info, 512 * 1024)?;
domctl.destroy_domain(domid)?; domctl.destroy_domain(domid)?;
println!("domain destroyed: {}", domid); println!("domain destroyed: {}", domid);
Ok(()) Ok(())

View File

@ -30,7 +30,6 @@ pub struct BootSetup<'a> {
memctl: &'a MemoryControl<'a>, memctl: &'a MemoryControl<'a>,
phys: PhysicalPages<'a>, phys: PhysicalPages<'a>,
domid: u32, domid: u32,
memkb: u64,
virt_alloc_end: u64, virt_alloc_end: u64,
pfn_alloc_end: u64, pfn_alloc_end: u64,
} }
@ -55,23 +54,20 @@ impl BootSetup<'_> {
domctl: &'a DomainControl<'a>, domctl: &'a DomainControl<'a>,
memctl: &'a MemoryControl<'a>, memctl: &'a MemoryControl<'a>,
domid: u32, domid: u32,
memkb: u64,
) -> BootSetup<'a> { ) -> BootSetup<'a> {
BootSetup { BootSetup {
domctl, domctl,
memctl, memctl,
phys: PhysicalPages::new(call, domid), phys: PhysicalPages::new(call, domid),
domid, domid,
memkb,
virt_alloc_end: 0, virt_alloc_end: 0,
pfn_alloc_end: 0, pfn_alloc_end: 0,
} }
} }
fn initialize_memory(&mut self) -> Result<(), XenClientError> { fn initialize_memory(&mut self, memkb: u64) -> Result<(), XenClientError> {
let mem_mb: u64 = self.memkb / 1024; let mem_mb: u64 = memkb / 1024;
let page_count: u64 = mem_mb << (20 - XEN_PAGE_SHIFT); let page_count: u64 = mem_mb << (20 - XEN_PAGE_SHIFT);
let mut pfn_base_idx: u64 = 0;
let mut vmemranges: Vec<VmemRange> = Vec::new(); let mut vmemranges: Vec<VmemRange> = Vec::new();
let stub = VmemRange { let stub = VmemRange {
start: 0, start: 0,
@ -105,15 +101,20 @@ impl BootSetup<'_> {
} }
let mut super_pages = pages >> SUPERPAGE_2MB_SHIFT; let mut super_pages = pages >> SUPERPAGE_2MB_SHIFT;
let mut pfn_base_idx: u64 = pfn_base;
while super_pages > 0 { while super_pages > 0 {
let count = super_pages.min(SUPERPAGE_BATCH_SIZE); let count = super_pages.min(SUPERPAGE_BATCH_SIZE);
super_pages -= count; super_pages -= count;
for (i, pfn) in (pfn_base_idx..(count << SUPERPAGE_2MB_SHIFT)) let mut j: usize = 0;
.step_by(SUPERPAGE_2MB_NR_PFNS as usize) let mut pfn: u64 = pfn_base_idx;
.enumerate() loop {
{ if pfn >= pfn_base_idx + (count << SUPERPAGE_2MB_SHIFT) {
extents[i] = p2m[pfn as usize]; break;
}
extents[j] = p2m[pfn as usize];
pfn += SUPERPAGE_2MB_NR_PFNS;
j += 1;
} }
let starts = self.memctl.populate_physmap( let starts = self.memctl.populate_physmap(
@ -124,31 +125,36 @@ impl BootSetup<'_> {
extents.as_slice(), extents.as_slice(),
)?; )?;
let pfn = pfn_base; pfn = pfn_base_idx;
for mfn in starts { for mfn in starts {
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_base_idx = pfn; pfn_base_idx = pfn;
} }
let mut j = pfn_base_idx - pfn_base; let mut j = pfn_base_idx - pfn_base;
loop { loop {
if j >= pages { if j >= pages {
break; break;
} }
let allocsz = (pages - j).min(1024 * 1024); let allocsz = (1024 * 1024).min(pages - j);
let result = self.memctl.populate_physmap( let p2m_idx = (pfn_base + j) as usize;
self.domid, let extent_start = p2m[p2m_idx];
allocsz, let result =
0, self.memctl
0, .populate_physmap(self.domid, allocsz, 0, 0, &[extent_start])?;
&[p2m[(pfn_base + j) as usize]],
)?; if result.len() != allocsz as usize {
p2m[(pfn_base + j) as usize] = result[0]; return Err(XenClientError::new(
format!("failed to populate physmap: {:?}", result).as_str(),
));
}
p2m[p2m_idx] = result[0];
j += allocsz; j += allocsz;
} }
} }
@ -165,8 +171,13 @@ impl BootSetup<'_> {
Ok(()) Ok(())
} }
pub fn initialize(&mut self, image_info: BootImageInfo) -> Result<(), XenClientError> { pub fn initialize(
self.initialize_memory()?; &mut self,
image_info: BootImageInfo,
memkb: u64,
) -> Result<(), XenClientError> {
self.domctl.set_max_mem(self.domid, memkb)?;
self.initialize_memory(memkb)?;
let _kernel_segment = self.alloc_segment(image_info.virt_kend - image_info.virt_kstart)?; let _kernel_segment = self.alloc_segment(image_info.virt_kend - image_info.virt_kstart)?;
self.initialize_hypercall(image_info)?; self.initialize_hypercall(image_info)?;
Ok(()) Ok(())

View File

@ -41,11 +41,7 @@ impl DomainConfig {
self.put_domain("memory/videoram", videokb.to_string()); self.put_domain("memory/videoram", videokb.to_string());
} }
pub fn configure_cpus(&mut self, maxvcpus: u32) { pub fn configure_cpus(&mut self, _maxvcpus: u32) {}
for i in 0..maxvcpus {
println!("{}", i);
}
}
pub fn configure_pv(&mut self, pv: PvDomainConfig) { pub fn configure_pv(&mut self, pv: PvDomainConfig) {
self.put_vm_str("image/ostype", "linux"); self.put_vm_str("image/ostype", "linux");

View File

@ -7,7 +7,7 @@ use xencall::XenCall;
pub struct PhysicalPage { pub struct PhysicalPage {
pfn: u64, pfn: u64,
ptr: u64, ptr: u64,
size: u64, count: u64,
} }
pub struct PhysicalPages<'a> { pub struct PhysicalPages<'a> {
@ -33,7 +33,7 @@ impl PhysicalPages<'_> {
pub fn pfn_to_ptr(&mut self, pfn: u64, count: u64) -> Result<u64, XenClientError> { pub fn pfn_to_ptr(&mut self, pfn: u64, count: u64) -> Result<u64, XenClientError> {
for page in &self.pages { for page in &self.pages {
if pfn >= page.pfn + page.size { if pfn >= page.pfn + page.count {
continue; continue;
} }
@ -42,7 +42,7 @@ impl PhysicalPages<'_> {
continue; continue;
} }
if pfn < page.pfn || (pfn + count) > page.pfn + page.size { if pfn < page.pfn || (pfn + count) > page.pfn + page.count {
return Err(XenClientError::new("request overlaps allocated block")); return Err(XenClientError::new("request overlaps allocated block"));
} }
} else { } else {
@ -50,7 +50,7 @@ impl PhysicalPages<'_> {
continue; continue;
} }
if pfn >= page.pfn + page.size { if pfn >= page.pfn + page.count {
continue; continue;
} }
} }
@ -82,7 +82,7 @@ impl PhysicalPages<'_> {
} }
} }
let size = (num as u64) << XEN_PAGE_SHIFT; let size = count << XEN_PAGE_SHIFT;
let addr = self let addr = self
.call .call
.mmap(0, size) .mmap(0, size)
@ -91,7 +91,7 @@ impl PhysicalPages<'_> {
let page = PhysicalPage { let page = PhysicalPage {
pfn, pfn,
ptr: addr, ptr: addr,
size, count,
}; };
self.pages.push(page); self.pages.push(page);
Ok(addr) Ok(addr)