mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-03 13:11:31 +00:00
implement memory allocation in boot setup
This commit is contained in:
@ -1,7 +1,17 @@
|
||||
use crate::mem::PhysicalPages;
|
||||
use crate::sys::{
|
||||
SUPERPAGE_2MB_NR_PFNS, SUPERPAGE_2MB_SHIFT, SUPERPAGE_BATCH_SIZE, XEN_PAGE_SHIFT,
|
||||
};
|
||||
use crate::XenClientError;
|
||||
use libc::memset;
|
||||
use std::ffi::c_void;
|
||||
use xencall::domctl::DomainControl;
|
||||
use xencall::memory::MemoryControl;
|
||||
use xencall::XenCall;
|
||||
|
||||
pub trait BootImageLoader {
|
||||
fn load(&self, dst: *mut u8) -> Result<BootImageInfo, XenClientError>;
|
||||
fn parse(&self) -> Result<BootImageInfo, XenClientError>;
|
||||
fn load(&self, image_info: BootImageInfo, dst: &mut [u8]) -> Result<(), XenClientError>;
|
||||
}
|
||||
|
||||
pub const XEN_UNSET_ADDR: u64 = -1i64 as u64;
|
||||
@ -11,6 +21,174 @@ pub struct BootImageInfo {
|
||||
pub virt_kstart: u64,
|
||||
pub virt_kend: u64,
|
||||
pub virt_hypercall: u64,
|
||||
pub entry: u64,
|
||||
pub hv_start_low: u64,
|
||||
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,
|
||||
memkb: u64,
|
||||
virt_alloc_end: u64,
|
||||
pfn_alloc_end: u64,
|
||||
}
|
||||
|
||||
struct DomainSegment {
|
||||
_vstart: u64,
|
||||
_vend: u64,
|
||||
pfn: u64,
|
||||
_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,
|
||||
memkb: u64,
|
||||
) -> BootSetup<'a> {
|
||||
BootSetup {
|
||||
domctl,
|
||||
memctl,
|
||||
phys: PhysicalPages::new(call, domid),
|
||||
domid,
|
||||
memkb,
|
||||
virt_alloc_end: 0,
|
||||
pfn_alloc_end: 0,
|
||||
}
|
||||
}
|
||||
|
||||
fn initialize_memory(&mut self) -> Result<(), XenClientError> {
|
||||
let mem_mb: u64 = self.memkb / 1024;
|
||||
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 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;
|
||||
while super_pages > 0 {
|
||||
let count = super_pages.min(SUPERPAGE_BATCH_SIZE);
|
||||
super_pages -= count;
|
||||
|
||||
for (i, pfn) in (pfn_base_idx..(count << SUPERPAGE_2MB_SHIFT))
|
||||
.step_by(SUPERPAGE_2MB_NR_PFNS as usize)
|
||||
.enumerate()
|
||||
{
|
||||
extents[i] = p2m[pfn as usize];
|
||||
}
|
||||
|
||||
let starts = self.memctl.populate_physmap(
|
||||
self.domid,
|
||||
count,
|
||||
SUPERPAGE_2MB_SHIFT as u32,
|
||||
0,
|
||||
extents.as_slice(),
|
||||
)?;
|
||||
|
||||
let pfn = pfn_base;
|
||||
for mfn in starts {
|
||||
for k in 0..SUPERPAGE_2MB_NR_PFNS {
|
||||
p2m[pfn as usize] = mfn + k;
|
||||
}
|
||||
}
|
||||
pfn_base_idx = pfn;
|
||||
}
|
||||
|
||||
let mut j = pfn_base_idx - pfn_base;
|
||||
|
||||
loop {
|
||||
if j >= pages {
|
||||
break;
|
||||
}
|
||||
|
||||
let allocsz = (pages - j).min(1024 * 1024);
|
||||
let result = self.memctl.populate_physmap(
|
||||
self.domid,
|
||||
allocsz,
|
||||
0,
|
||||
0,
|
||||
&[p2m[(pfn_base + j) as usize]],
|
||||
)?;
|
||||
p2m[(pfn_base + j) as usize] = result[0];
|
||||
j += allocsz;
|
||||
}
|
||||
}
|
||||
|
||||
self.phys.load_p2m(p2m);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn initialize_hypercall(&mut self, image_info: BootImageInfo) -> Result<(), XenClientError> {
|
||||
if image_info.virt_hypercall != XEN_UNSET_ADDR {
|
||||
self.domctl
|
||||
.hypercall_init(self.domid, image_info.virt_hypercall)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn initialize(&mut self, image_info: BootImageInfo) -> Result<(), XenClientError> {
|
||||
self.initialize_memory()?;
|
||||
let _kernel_segment = self.alloc_segment(image_info.virt_kend - image_info.virt_kstart)?;
|
||||
self.initialize_hypercall(image_info)?;
|
||||
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,
|
||||
_pages: pages,
|
||||
};
|
||||
let ptr = self.phys.pfn_to_ptr(segment.pfn, pages)?;
|
||||
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;
|
||||
Ok(segment)
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::boot::{BootImageInfo, BootImageLoader, XEN_UNSET_ADDR};
|
||||
use crate::sys::{
|
||||
XEN_ELFNOTE_ENTRY, XEN_ELFNOTE_HV_START_LOW, XEN_ELFNOTE_HYPERCALL_PAGE, XEN_ELFNOTE_VIRT_BASE,
|
||||
XEN_ELFNOTE_ENTRY, XEN_ELFNOTE_HYPERCALL_PAGE, XEN_ELFNOTE_INIT_P2M, XEN_ELFNOTE_PADDR_OFFSET,
|
||||
XEN_ELFNOTE_TYPES, XEN_ELFNOTE_VIRT_BASE,
|
||||
};
|
||||
use crate::XenClientError;
|
||||
use elf::abi::{PF_R, PF_W, PF_X, PT_LOAD, SHT_NOTE};
|
||||
@ -9,7 +10,9 @@ use elf::note::Note;
|
||||
use elf::{ElfBytes, ParseError};
|
||||
use flate2::bufread::GzDecoder;
|
||||
use memchr::memmem::find_iter;
|
||||
use slice_copy::copy;
|
||||
use std::collections::HashMap;
|
||||
use std::ffi::{FromVecWithNulError, IntoStringError};
|
||||
use std::io::{BufReader, Read};
|
||||
use std::mem::size_of;
|
||||
use xz2::bufread::XzDecoder;
|
||||
@ -20,40 +23,48 @@ impl From<ParseError> for XenClientError {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FromVecWithNulError> for XenClientError {
|
||||
fn from(value: FromVecWithNulError) -> Self {
|
||||
XenClientError::new(value.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IntoStringError> for XenClientError {
|
||||
fn from(value: IntoStringError) -> Self {
|
||||
XenClientError::new(value.to_string().as_str())
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ElfImageLoader {
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
fn xen_note_value_as_u64(
|
||||
endian: AnyEndian,
|
||||
notes: &HashMap<u64, Vec<u8>>,
|
||||
key: u64,
|
||||
) -> Option<u64> {
|
||||
let value = notes.get(&key)?;
|
||||
fn xen_note_value_as_u64(endian: AnyEndian, value: &[u8]) -> Option<u64> {
|
||||
let bytes = value.to_vec();
|
||||
match value.len() {
|
||||
1 => {
|
||||
let bytes: Option<[u8; size_of::<u8>()]> = value.clone().try_into().ok();
|
||||
let bytes: Option<[u8; size_of::<u8>()]> = bytes.try_into().ok();
|
||||
Some(match endian {
|
||||
AnyEndian::Little => u8::from_le_bytes(bytes?),
|
||||
AnyEndian::Big => u8::from_be_bytes(bytes?),
|
||||
} as u64)
|
||||
}
|
||||
2 => {
|
||||
let bytes: Option<[u8; size_of::<u16>()]> = value.clone().try_into().ok();
|
||||
let bytes: Option<[u8; size_of::<u16>()]> = bytes.try_into().ok();
|
||||
Some(match endian {
|
||||
AnyEndian::Little => u16::from_le_bytes(bytes?),
|
||||
AnyEndian::Big => u16::from_be_bytes(bytes?),
|
||||
} as u64)
|
||||
}
|
||||
4 => {
|
||||
let bytes: Option<[u8; size_of::<u32>()]> = value.clone().try_into().ok();
|
||||
let bytes: Option<[u8; size_of::<u32>()]> = bytes.try_into().ok();
|
||||
Some(match endian {
|
||||
AnyEndian::Little => u32::from_le_bytes(bytes?),
|
||||
AnyEndian::Big => u32::from_be_bytes(bytes?),
|
||||
} as u64)
|
||||
}
|
||||
8 => {
|
||||
let bytes: Option<[u8; size_of::<u64>()]> = value.clone().try_into().ok();
|
||||
let bytes: Option<[u8; size_of::<u64>()]> = bytes.try_into().ok();
|
||||
Some(match endian {
|
||||
AnyEndian::Little => u64::from_le_bytes(bytes?),
|
||||
AnyEndian::Big => u64::from_be_bytes(bytes?),
|
||||
@ -139,14 +150,18 @@ impl ElfImageLoader {
|
||||
}
|
||||
}
|
||||
|
||||
struct ElfNoteValue {
|
||||
value: u64,
|
||||
}
|
||||
|
||||
impl BootImageLoader for ElfImageLoader {
|
||||
fn load(&self, dst: *mut u8) -> Result<BootImageInfo, XenClientError> {
|
||||
fn parse(&self) -> Result<BootImageInfo, XenClientError> {
|
||||
let elf = ElfBytes::<AnyEndian>::minimal_parse(self.data.as_slice())?;
|
||||
let headers = elf.section_headers().ok_or(XenClientError::new(
|
||||
"Unable to parse kernel image: section headers not found.",
|
||||
))?;
|
||||
let mut linux_notes: HashMap<u64, Vec<u8>> = HashMap::new();
|
||||
let mut xen_notes: HashMap<u64, Vec<u8>> = HashMap::new();
|
||||
let mut xen_notes: HashMap<u64, ElfNoteValue> = HashMap::new();
|
||||
|
||||
for header in headers {
|
||||
if header.sh_type != SHT_NOTE {
|
||||
@ -161,7 +176,19 @@ impl BootImageLoader for ElfImageLoader {
|
||||
}
|
||||
|
||||
if note.name == "Xen" {
|
||||
xen_notes.insert(note.n_type, note.desc.to_vec());
|
||||
for typ in XEN_ELFNOTE_TYPES {
|
||||
if typ.id != note.n_type {
|
||||
continue;
|
||||
}
|
||||
|
||||
let value = if !typ.is_string {
|
||||
xen_note_value_as_u64(elf.ehdr.endianness, note.desc).unwrap_or(0)
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
xen_notes.insert(typ.id, ElfNoteValue { value });
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@ -180,23 +207,34 @@ impl BootImageLoader for ElfImageLoader {
|
||||
));
|
||||
}
|
||||
|
||||
let virt_base =
|
||||
xen_note_value_as_u64(elf.ehdr.endianness, &xen_notes, XEN_ELFNOTE_VIRT_BASE).ok_or(
|
||||
XenClientError::new("Unable to find virt_base note in kernel."),
|
||||
)?;
|
||||
let entry = xen_note_value_as_u64(elf.ehdr.endianness, &xen_notes, XEN_ELFNOTE_ENTRY)
|
||||
.ok_or(XenClientError::new("Unable to find entry note in kernel."))?;
|
||||
let hv_start_low =
|
||||
xen_note_value_as_u64(elf.ehdr.endianness, &xen_notes, XEN_ELFNOTE_HV_START_LOW)
|
||||
.ok_or(XenClientError::new(
|
||||
"Unable to find hv_start_low note in kernel.",
|
||||
))?;
|
||||
|
||||
let hypercall_page =
|
||||
xen_note_value_as_u64(elf.ehdr.endianness, &xen_notes, XEN_ELFNOTE_HYPERCALL_PAGE)
|
||||
.ok_or(XenClientError::new(
|
||||
"Unable to find hypercall_page note in kernel.",
|
||||
))?;
|
||||
let paddr_offset = xen_notes
|
||||
.get(&XEN_ELFNOTE_PADDR_OFFSET)
|
||||
.ok_or(XenClientError::new(
|
||||
"Unable to find paddr_offset note in kernel.",
|
||||
))?
|
||||
.value;
|
||||
let virt_base = xen_notes
|
||||
.get(&XEN_ELFNOTE_VIRT_BASE)
|
||||
.ok_or(XenClientError::new(
|
||||
"Unable to find virt_base note in kernel.",
|
||||
))?
|
||||
.value;
|
||||
let entry = xen_notes
|
||||
.get(&XEN_ELFNOTE_ENTRY)
|
||||
.ok_or(XenClientError::new("Unable to find entry note in kernel."))?
|
||||
.value;
|
||||
let virt_hypercall = xen_notes
|
||||
.get(&XEN_ELFNOTE_HYPERCALL_PAGE)
|
||||
.ok_or(XenClientError::new(
|
||||
"Unable to find hypercall_page note in kernel.",
|
||||
))?
|
||||
.value;
|
||||
let init_p2m = xen_notes
|
||||
.get(&XEN_ELFNOTE_INIT_P2M)
|
||||
.ok_or(XenClientError::new(
|
||||
"Unable to find init_p2m note in kernel.",
|
||||
))?
|
||||
.value;
|
||||
|
||||
let mut start: u64 = u64::MAX;
|
||||
let mut end: u64 = 0;
|
||||
@ -204,12 +242,13 @@ impl BootImageLoader for ElfImageLoader {
|
||||
let segments = elf.segments().ok_or(XenClientError::new(
|
||||
"Unable to parse kernel image: segments not found.",
|
||||
))?;
|
||||
for segment in segments {
|
||||
if (segment.p_type != PT_LOAD) || (segment.p_flags & (PF_R | PF_W | PF_X)) == 0 {
|
||||
|
||||
for header in segments {
|
||||
if (header.p_type != PT_LOAD) || (header.p_flags & (PF_R | PF_W | PF_X)) == 0 {
|
||||
continue;
|
||||
}
|
||||
let paddr = segment.p_paddr;
|
||||
let memsz = segment.p_memsz;
|
||||
let paddr = header.p_paddr;
|
||||
let memsz = header.p_memsz;
|
||||
if start > paddr {
|
||||
start = paddr;
|
||||
}
|
||||
@ -219,34 +258,61 @@ impl BootImageLoader for ElfImageLoader {
|
||||
}
|
||||
}
|
||||
|
||||
let base_dst_addr = dst as u64;
|
||||
for header in segments {
|
||||
let paddr = header.p_paddr;
|
||||
let filesz = header.p_filesz;
|
||||
let memsz = header.p_memsz;
|
||||
let dest = base_dst_addr + paddr - start;
|
||||
let data = elf.segment_data(&header)?;
|
||||
|
||||
unsafe {
|
||||
std::ptr::copy(data.as_ptr(), dest as *mut u8, filesz as usize);
|
||||
std::ptr::write_bytes((dest + filesz) as *mut u8, 0, (memsz - filesz) as usize);
|
||||
}
|
||||
if paddr_offset != XEN_UNSET_ADDR && virt_base == XEN_UNSET_ADDR {
|
||||
return Err(XenClientError::new(
|
||||
"Unable to load kernel image: paddr_offset set but virt_base is unset.",
|
||||
));
|
||||
}
|
||||
|
||||
let virt_base = if virt_base == XEN_UNSET_ADDR {
|
||||
0
|
||||
} else {
|
||||
virt_base
|
||||
};
|
||||
let virt_kstart = start.wrapping_add(virt_base);
|
||||
let virt_kend = end.wrapping_add(virt_base);
|
||||
let virt_hypercall = hypercall_page.wrapping_add(virt_base);
|
||||
|
||||
let paddr_offset = if paddr_offset == XEN_UNSET_ADDR {
|
||||
0
|
||||
} else {
|
||||
paddr_offset
|
||||
};
|
||||
|
||||
let virt_offset = virt_base - paddr_offset;
|
||||
let virt_kstart = start + virt_offset;
|
||||
let virt_kend = end + virt_offset;
|
||||
let virt_entry = if entry == XEN_UNSET_ADDR {
|
||||
elf.ehdr.e_entry
|
||||
} else {
|
||||
entry
|
||||
};
|
||||
|
||||
Ok(BootImageInfo {
|
||||
virt_kstart,
|
||||
virt_kend,
|
||||
virt_hypercall,
|
||||
entry,
|
||||
hv_start_low,
|
||||
virt_entry,
|
||||
init_p2m,
|
||||
})
|
||||
}
|
||||
|
||||
fn load(&self, image_info: BootImageInfo, dst: &mut [u8]) -> Result<(), XenClientError> {
|
||||
let elf = ElfBytes::<AnyEndian>::minimal_parse(self.data.as_slice())?;
|
||||
let segments = elf.segments().ok_or(XenClientError::new(
|
||||
"Unable to parse kernel image: segments not found.",
|
||||
))?;
|
||||
|
||||
for header in segments {
|
||||
let paddr = header.p_paddr;
|
||||
let filesz = header.p_filesz;
|
||||
let memsz = header.p_memsz;
|
||||
let base_offset = paddr - image_info.virt_kstart;
|
||||
let data = elf.segment_data(&header)?;
|
||||
let segment_dst = &mut dst[base_offset as usize..];
|
||||
copy(segment_dst, &data[0..filesz as usize]);
|
||||
if memsz - filesz > 0 {
|
||||
let remaining = &mut segment_dst[filesz as usize..(memsz - filesz) as usize];
|
||||
remaining.fill(0);
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
pub mod boot;
|
||||
pub mod create;
|
||||
pub mod elfloader;
|
||||
pub mod mem;
|
||||
pub mod sys;
|
||||
|
||||
use crate::create::DomainConfig;
|
||||
|
99
xenclient/src/mem.rs
Normal file
99
xenclient/src/mem.rs
Normal file
@ -0,0 +1,99 @@
|
||||
use crate::sys::XEN_PAGE_SHIFT;
|
||||
use crate::XenClientError;
|
||||
|
||||
use xencall::sys::MmapEntry;
|
||||
use xencall::XenCall;
|
||||
|
||||
pub struct PhysicalPage {
|
||||
pfn: u64,
|
||||
ptr: u64,
|
||||
size: u64,
|
||||
}
|
||||
|
||||
pub struct PhysicalPages<'a> {
|
||||
domid: u32,
|
||||
p2m: Vec<u64>,
|
||||
call: &'a XenCall,
|
||||
pages: Vec<PhysicalPage>,
|
||||
}
|
||||
|
||||
impl PhysicalPages<'_> {
|
||||
pub fn new(call: &XenCall, domid: u32) -> PhysicalPages {
|
||||
PhysicalPages {
|
||||
domid,
|
||||
p2m: Vec::new(),
|
||||
call,
|
||||
pages: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load_p2m(&mut self, p2m: Vec<u64>) {
|
||||
self.p2m = p2m;
|
||||
}
|
||||
|
||||
pub fn pfn_to_ptr(&mut self, pfn: u64, count: u64) -> Result<u64, XenClientError> {
|
||||
for page in &self.pages {
|
||||
if pfn >= page.pfn + page.size {
|
||||
continue;
|
||||
}
|
||||
|
||||
if count > 0 {
|
||||
if (pfn + count) <= page.pfn {
|
||||
continue;
|
||||
}
|
||||
|
||||
if pfn < page.pfn || (pfn + count) > page.pfn + page.size {
|
||||
return Err(XenClientError::new("request overlaps allocated block"));
|
||||
}
|
||||
} else {
|
||||
if pfn < page.pfn {
|
||||
continue;
|
||||
}
|
||||
|
||||
if pfn >= page.pfn + page.size {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
return Ok(page.ptr + ((pfn - page.pfn) << XEN_PAGE_SHIFT));
|
||||
}
|
||||
|
||||
if count == 0 {
|
||||
return Err(XenClientError::new(
|
||||
"allocation is only allowed when a size is given",
|
||||
));
|
||||
}
|
||||
|
||||
self.pfn_alloc(pfn, count)
|
||||
}
|
||||
|
||||
fn pfn_alloc(&mut self, pfn: u64, count: u64) -> Result<u64, XenClientError> {
|
||||
let mut entries = vec![MmapEntry::default(); count as usize];
|
||||
for (i, entry) in (0_u64..).zip(entries.iter_mut()) {
|
||||
entry.mfn = self.p2m[(pfn + i) as usize];
|
||||
}
|
||||
let chunk_size = 1 << XEN_PAGE_SHIFT;
|
||||
let num_per_entry = chunk_size >> XEN_PAGE_SHIFT;
|
||||
let num = num_per_entry * entries.len();
|
||||
let mut pfns = vec![0u64; num];
|
||||
for i in 0..entries.len() {
|
||||
for j in 0..num_per_entry {
|
||||
pfns[i * num_per_entry + j] = entries[i].mfn + j as u64;
|
||||
}
|
||||
}
|
||||
|
||||
let size = (num as u64) << XEN_PAGE_SHIFT;
|
||||
let addr = self
|
||||
.call
|
||||
.mmap(0, size)
|
||||
.ok_or(XenClientError::new("failed to mmap address"))?;
|
||||
self.call.mmap_batch(self.domid, num as u64, addr, pfns)?;
|
||||
let page = PhysicalPage {
|
||||
pfn,
|
||||
ptr: addr,
|
||||
size,
|
||||
};
|
||||
self.pages.push(page);
|
||||
Ok(addr)
|
||||
}
|
||||
}
|
@ -17,3 +17,105 @@ pub const XEN_ELFNOTE_INIT_P2M: u64 = 15;
|
||||
pub const XEN_ELFNOTE_MOD_START_PFN: u64 = 16;
|
||||
pub const XEN_ELFNOTE_SUPPORTED_FEATURES: u64 = 17;
|
||||
pub const XEN_ELFNOTE_PHYS32_ENTRY: u64 = 18;
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ElfNoteXenType {
|
||||
pub id: u64,
|
||||
pub name: &'static str,
|
||||
pub is_string: bool,
|
||||
}
|
||||
|
||||
pub const XEN_ELFNOTE_TYPES: &[ElfNoteXenType] = &[
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_ENTRY,
|
||||
name: "ENTRY",
|
||||
is_string: false,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_HYPERCALL_PAGE,
|
||||
name: "HYPERCALL_PAGE",
|
||||
is_string: false,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_VIRT_BASE,
|
||||
name: "VIRT_BASE",
|
||||
is_string: false,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_INIT_P2M,
|
||||
name: "INIT_P2M",
|
||||
is_string: false,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_PADDR_OFFSET,
|
||||
name: "PADDR_OFFSET",
|
||||
is_string: false,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_HV_START_LOW,
|
||||
name: "HV_START_LOW",
|
||||
is_string: false,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_XEN_VERSION,
|
||||
name: "XEN_VERSION",
|
||||
is_string: true,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_GUEST_OS,
|
||||
name: "GUEST_OS",
|
||||
is_string: true,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_GUEST_VERSION,
|
||||
name: "GUEST_VERSION",
|
||||
is_string: true,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_LOADER,
|
||||
name: "LOADER",
|
||||
is_string: true,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_PAE_MODE,
|
||||
name: "PAE_MODE",
|
||||
is_string: true,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_FEATURES,
|
||||
name: "FEATURES",
|
||||
is_string: true,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_SUPPORTED_FEATURES,
|
||||
name: "SUPPORTED_FEATURES",
|
||||
is_string: false,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_BSD_SYMTAB,
|
||||
name: "BSD_SYMTAB",
|
||||
is_string: true,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_SUSPEND_CANCEL,
|
||||
name: "SUSPEND_CANCEL",
|
||||
is_string: false,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_MOD_START_PFN,
|
||||
name: "MOD_START_PFN",
|
||||
is_string: false,
|
||||
},
|
||||
ElfNoteXenType {
|
||||
id: XEN_ELFNOTE_PHYS32_ENTRY,
|
||||
name: "PHYS32_ENTRY",
|
||||
is_string: false,
|
||||
},
|
||||
];
|
||||
|
||||
pub const XEN_PAGE_SHIFT: u64 = 12;
|
||||
pub const XEN_PAGE_SIZE: u64 = 1 << XEN_PAGE_SHIFT;
|
||||
pub const XEN_PAGE_MASK: u64 = !(XEN_PAGE_SIZE - 1);
|
||||
pub const SUPERPAGE_BATCH_SIZE: u64 = 512;
|
||||
pub const SUPERPAGE_2MB_SHIFT: u64 = 9;
|
||||
pub const SUPERPAGE_2MB_NR_PFNS: u64 = 1u64 << SUPERPAGE_2MB_SHIFT;
|
||||
|
Reference in New Issue
Block a user