mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-02 12:50:54 +00:00
xenclient: move error to it's own mod
This commit is contained in:
parent
eec213c712
commit
890a8ee63f
@ -5,6 +5,7 @@ edition = "2021"
|
|||||||
resolver = "2"
|
resolver = "2"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
thiserror = { workspace = true }
|
||||||
libc = { workspace = true }
|
libc = { workspace = true }
|
||||||
elf = { workspace = true }
|
elf = { workspace = true }
|
||||||
flate2 = { workspace = true }
|
flate2 = { workspace = true }
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
use std::{env, process};
|
use std::{env, process};
|
||||||
use xenclient::{DomainConfig, XenClient, XenClientError};
|
use xenclient::error::Result;
|
||||||
|
use xenclient::{DomainConfig, XenClient};
|
||||||
|
|
||||||
fn main() -> Result<(), XenClientError> {
|
fn main() -> Result<()> {
|
||||||
env_logger::init();
|
env_logger::init();
|
||||||
|
|
||||||
let args: Vec<String> = env::args().collect();
|
let args: Vec<String> = env::args().collect();
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
|
use crate::error::Result;
|
||||||
use crate::mem::PhysicalPages;
|
use crate::mem::PhysicalPages;
|
||||||
use crate::sys::{GrantEntry, XEN_PAGE_SHIFT};
|
use crate::sys::{GrantEntry, XEN_PAGE_SHIFT};
|
||||||
use crate::XenClientError;
|
use crate::Error;
|
||||||
use libc::munmap;
|
use libc::munmap;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use slice_copy::copy;
|
use slice_copy::copy;
|
||||||
@ -10,8 +11,8 @@ use std::slice;
|
|||||||
use xencall::XenCall;
|
use xencall::XenCall;
|
||||||
|
|
||||||
pub trait BootImageLoader {
|
pub trait BootImageLoader {
|
||||||
fn parse(&self) -> Result<BootImageInfo, XenClientError>;
|
fn parse(&self) -> Result<BootImageInfo>;
|
||||||
fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<(), XenClientError>;
|
fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<()>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const XEN_UNSET_ADDR: u64 = -1i64 as u64;
|
pub const XEN_UNSET_ADDR: u64 = -1i64 as u64;
|
||||||
@ -77,11 +78,7 @@ impl BootSetup<'_> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize_memory(
|
fn initialize_memory(&mut self, arch: &mut dyn ArchBootSetup, total_pages: u64) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
arch: &mut dyn ArchBootSetup,
|
|
||||||
total_pages: u64,
|
|
||||||
) -> Result<(), XenClientError> {
|
|
||||||
self.call.set_address_size(self.domid, 64)?;
|
self.call.set_address_size(self.domid, 64)?;
|
||||||
arch.meminit(self, total_pages)?;
|
arch.meminit(self, total_pages)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -94,7 +91,7 @@ impl BootSetup<'_> {
|
|||||||
initrd: &[u8],
|
initrd: &[u8],
|
||||||
max_vcpus: u32,
|
max_vcpus: u32,
|
||||||
mem_mb: u64,
|
mem_mb: u64,
|
||||||
) -> Result<BootState, XenClientError> {
|
) -> Result<BootState> {
|
||||||
debug!(
|
debug!(
|
||||||
"BootSetup initialize max_vcpus={:?} mem_mb={:?}",
|
"BootSetup initialize max_vcpus={:?} mem_mb={:?}",
|
||||||
max_vcpus, mem_mb
|
max_vcpus, mem_mb
|
||||||
@ -164,7 +161,7 @@ impl BootSetup<'_> {
|
|||||||
arch: &mut dyn ArchBootSetup,
|
arch: &mut dyn ArchBootSetup,
|
||||||
state: &mut BootState,
|
state: &mut BootState,
|
||||||
cmdline: &str,
|
cmdline: &str,
|
||||||
) -> Result<(), XenClientError> {
|
) -> Result<()> {
|
||||||
let domain_info = self.call.get_domain_info(self.domid)?;
|
let domain_info = self.call.get_domain_info(self.domid)?;
|
||||||
let shared_info_frame = domain_info.shared_info_frame;
|
let shared_info_frame = domain_info.shared_info_frame;
|
||||||
state.shared_info_frame = shared_info_frame;
|
state.shared_info_frame = shared_info_frame;
|
||||||
@ -179,13 +176,13 @@ impl BootSetup<'_> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn gnttab_seed(&mut self, state: &mut BootState) -> Result<(), XenClientError> {
|
fn gnttab_seed(&mut self, state: &mut BootState) -> Result<()> {
|
||||||
let console_gfn = self.phys.p2m[state.console_segment.pfn as usize];
|
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 xenstore_gfn = self.phys.p2m[state.xenstore_segment.pfn as usize];
|
||||||
let addr = self
|
let addr = self
|
||||||
.call
|
.call
|
||||||
.mmap(0, 1 << XEN_PAGE_SHIFT)
|
.mmap(0, 1 << XEN_PAGE_SHIFT)
|
||||||
.ok_or(XenClientError::new("failed to mmap for resource"))?;
|
.ok_or(Error::new("failed to mmap for resource"))?;
|
||||||
self.call.map_resource(self.domid, 1, 0, 0, 1, addr)?;
|
self.call.map_resource(self.domid, 1, 0, 0, 1, addr)?;
|
||||||
let entries = unsafe { slice::from_raw_parts_mut(addr as *mut GrantEntry, 2) };
|
let entries = unsafe { slice::from_raw_parts_mut(addr as *mut GrantEntry, 2) };
|
||||||
entries[0].flags = 1 << 0;
|
entries[0].flags = 1 << 0;
|
||||||
@ -197,7 +194,7 @@ impl BootSetup<'_> {
|
|||||||
unsafe {
|
unsafe {
|
||||||
let result = munmap(addr as *mut c_void, 1 << XEN_PAGE_SHIFT);
|
let result = munmap(addr as *mut c_void, 1 << XEN_PAGE_SHIFT);
|
||||||
if result != 0 {
|
if result != 0 {
|
||||||
return Err(XenClientError::new("failed to unmap resource"));
|
return Err(Error::new("failed to unmap resource"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -208,7 +205,7 @@ impl BootSetup<'_> {
|
|||||||
arch: &mut dyn ArchBootSetup,
|
arch: &mut dyn ArchBootSetup,
|
||||||
image_loader: &dyn BootImageLoader,
|
image_loader: &dyn BootImageLoader,
|
||||||
image_info: &BootImageInfo,
|
image_info: &BootImageInfo,
|
||||||
) -> Result<DomainSegment, XenClientError> {
|
) -> Result<DomainSegment> {
|
||||||
let kernel_segment = self.alloc_segment(
|
let kernel_segment = self.alloc_segment(
|
||||||
arch,
|
arch,
|
||||||
image_info.virt_kstart,
|
image_info.virt_kstart,
|
||||||
@ -234,7 +231,7 @@ impl BootSetup<'_> {
|
|||||||
arch: &mut dyn ArchBootSetup,
|
arch: &mut dyn ArchBootSetup,
|
||||||
start: u64,
|
start: u64,
|
||||||
size: u64,
|
size: u64,
|
||||||
) -> Result<DomainSegment, XenClientError> {
|
) -> Result<DomainSegment> {
|
||||||
if start > 0 {
|
if start > 0 {
|
||||||
self.alloc_padding_pages(arch, start)?;
|
self.alloc_padding_pages(arch, start)?;
|
||||||
}
|
}
|
||||||
@ -268,10 +265,7 @@ impl BootSetup<'_> {
|
|||||||
Ok(segment)
|
Ok(segment)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_page(
|
fn alloc_page(&mut self, arch: &mut dyn ArchBootSetup) -> Result<DomainSegment> {
|
||||||
&mut self,
|
|
||||||
arch: &mut dyn ArchBootSetup,
|
|
||||||
) -> Result<DomainSegment, XenClientError> {
|
|
||||||
let start = self.virt_alloc_end;
|
let start = self.virt_alloc_end;
|
||||||
let pfn = self.pfn_alloc_end;
|
let pfn = self.pfn_alloc_end;
|
||||||
|
|
||||||
@ -291,26 +285,22 @@ impl BootSetup<'_> {
|
|||||||
&mut self,
|
&mut self,
|
||||||
arch: &mut dyn ArchBootSetup,
|
arch: &mut dyn ArchBootSetup,
|
||||||
buffer: &[u8],
|
buffer: &[u8],
|
||||||
) -> Result<DomainSegment, XenClientError> {
|
) -> Result<DomainSegment> {
|
||||||
let segment = self.alloc_segment(arch, 0, buffer.len() as u64)?;
|
let segment = self.alloc_segment(arch, 0, buffer.len() as u64)?;
|
||||||
let slice = unsafe { slice::from_raw_parts_mut(segment.addr as *mut u8, buffer.len()) };
|
let slice = unsafe { slice::from_raw_parts_mut(segment.addr as *mut u8, buffer.len()) };
|
||||||
copy(slice, buffer);
|
copy(slice, buffer);
|
||||||
Ok(segment)
|
Ok(segment)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn alloc_padding_pages(
|
fn alloc_padding_pages(&mut self, arch: &mut dyn ArchBootSetup, boundary: u64) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
arch: &mut dyn ArchBootSetup,
|
|
||||||
boundary: u64,
|
|
||||||
) -> Result<(), XenClientError> {
|
|
||||||
if (boundary & (arch.page_size() - 1)) != 0 {
|
if (boundary & (arch.page_size() - 1)) != 0 {
|
||||||
return Err(XenClientError::new(
|
return Err(Error::new(
|
||||||
format!("segment boundary isn't page aligned: {:#x}", boundary).as_str(),
|
format!("segment boundary isn't page aligned: {:#x}", boundary).as_str(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if boundary < self.virt_alloc_end {
|
if boundary < self.virt_alloc_end {
|
||||||
return Err(XenClientError::new(
|
return Err(Error::new(
|
||||||
format!("segment boundary too low: {:#x})", boundary).as_str(),
|
format!("segment boundary too low: {:#x})", boundary).as_str(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -319,16 +309,12 @@ impl BootSetup<'_> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn chk_alloc_pages(
|
fn chk_alloc_pages(&mut self, arch: &mut dyn ArchBootSetup, pages: u64) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
arch: &mut dyn ArchBootSetup,
|
|
||||||
pages: u64,
|
|
||||||
) -> Result<(), XenClientError> {
|
|
||||||
if pages > self.total_pages
|
if pages > self.total_pages
|
||||||
|| self.pfn_alloc_end > self.total_pages
|
|| self.pfn_alloc_end > self.total_pages
|
||||||
|| pages > self.total_pages - self.pfn_alloc_end
|
|| pages > self.total_pages - self.pfn_alloc_end
|
||||||
{
|
{
|
||||||
return Err(XenClientError::new(
|
return Err(Error::new(
|
||||||
format!(
|
format!(
|
||||||
"segment too large: pages={} total_pages={} pfn_alloc_end={}",
|
"segment too large: pages={} total_pages={} pfn_alloc_end={}",
|
||||||
pages, self.total_pages, self.pfn_alloc_end
|
pages, self.total_pages, self.pfn_alloc_end
|
||||||
@ -351,44 +337,32 @@ pub trait ArchBootSetup {
|
|||||||
&mut self,
|
&mut self,
|
||||||
setup: &mut BootSetup,
|
setup: &mut BootSetup,
|
||||||
image_info: &BootImageInfo,
|
image_info: &BootImageInfo,
|
||||||
) -> Result<DomainSegment, XenClientError>;
|
) -> Result<DomainSegment>;
|
||||||
|
|
||||||
fn alloc_page_tables(
|
fn alloc_page_tables(
|
||||||
&mut self,
|
&mut self,
|
||||||
setup: &mut BootSetup,
|
setup: &mut BootSetup,
|
||||||
image_info: &BootImageInfo,
|
image_info: &BootImageInfo,
|
||||||
) -> Result<DomainSegment, XenClientError>;
|
) -> Result<DomainSegment>;
|
||||||
|
|
||||||
fn setup_page_tables(
|
fn setup_page_tables(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()>;
|
||||||
&mut self,
|
|
||||||
setup: &mut BootSetup,
|
|
||||||
state: &mut BootState,
|
|
||||||
) -> Result<(), XenClientError>;
|
|
||||||
|
|
||||||
fn setup_start_info(
|
fn setup_start_info(
|
||||||
&mut self,
|
&mut self,
|
||||||
setup: &mut BootSetup,
|
setup: &mut BootSetup,
|
||||||
state: &BootState,
|
state: &BootState,
|
||||||
cmdline: &str,
|
cmdline: &str,
|
||||||
) -> Result<(), XenClientError>;
|
) -> Result<()>;
|
||||||
|
|
||||||
fn setup_shared_info(
|
fn setup_shared_info(&mut self, setup: &mut BootSetup, shared_info_frame: u64) -> Result<()>;
|
||||||
&mut self,
|
|
||||||
setup: &mut BootSetup,
|
|
||||||
shared_info_frame: u64,
|
|
||||||
) -> Result<(), XenClientError>;
|
|
||||||
|
|
||||||
fn setup_hypercall_page(
|
fn setup_hypercall_page(
|
||||||
&mut self,
|
&mut self,
|
||||||
setup: &mut BootSetup,
|
setup: &mut BootSetup,
|
||||||
image_info: &BootImageInfo,
|
image_info: &BootImageInfo,
|
||||||
) -> Result<(), XenClientError>;
|
) -> Result<()>;
|
||||||
|
|
||||||
fn meminit(&mut self, setup: &mut BootSetup, total_pages: u64) -> Result<(), XenClientError>;
|
fn meminit(&mut self, setup: &mut BootSetup, total_pages: u64) -> Result<()>;
|
||||||
fn bootlate(
|
fn bootlate(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()>;
|
||||||
&mut self,
|
fn vcpu(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()>;
|
||||||
setup: &mut BootSetup,
|
|
||||||
state: &mut BootState,
|
|
||||||
) -> Result<(), XenClientError>;
|
|
||||||
fn vcpu(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<(), XenClientError>;
|
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,10 @@
|
|||||||
use crate::boot::{BootImageInfo, BootImageLoader, XEN_UNSET_ADDR};
|
use crate::boot::{BootImageInfo, BootImageLoader, XEN_UNSET_ADDR};
|
||||||
|
use crate::error::Result;
|
||||||
use crate::sys::{
|
use crate::sys::{
|
||||||
XEN_ELFNOTE_ENTRY, XEN_ELFNOTE_HYPERCALL_PAGE, XEN_ELFNOTE_INIT_P2M, XEN_ELFNOTE_MOD_START_PFN,
|
XEN_ELFNOTE_ENTRY, XEN_ELFNOTE_HYPERCALL_PAGE, XEN_ELFNOTE_INIT_P2M, XEN_ELFNOTE_MOD_START_PFN,
|
||||||
XEN_ELFNOTE_PADDR_OFFSET, XEN_ELFNOTE_TYPES, XEN_ELFNOTE_VIRT_BASE,
|
XEN_ELFNOTE_PADDR_OFFSET, XEN_ELFNOTE_TYPES, XEN_ELFNOTE_VIRT_BASE,
|
||||||
};
|
};
|
||||||
use crate::XenClientError;
|
use crate::Error;
|
||||||
use elf::abi::{PF_R, PF_W, PF_X, PT_LOAD, SHT_NOTE};
|
use elf::abi::{PF_R, PF_W, PF_X, PT_LOAD, SHT_NOTE};
|
||||||
use elf::endian::AnyEndian;
|
use elf::endian::AnyEndian;
|
||||||
use elf::note::Note;
|
use elf::note::Note;
|
||||||
@ -18,21 +19,21 @@ use std::io::{BufReader, Read};
|
|||||||
use std::mem::size_of;
|
use std::mem::size_of;
|
||||||
use xz2::bufread::XzDecoder;
|
use xz2::bufread::XzDecoder;
|
||||||
|
|
||||||
impl From<ParseError> for XenClientError {
|
impl From<ParseError> for Error {
|
||||||
fn from(value: ParseError) -> Self {
|
fn from(value: ParseError) -> Self {
|
||||||
XenClientError::new(value.to_string().as_str())
|
Error::new(value.to_string().as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<FromVecWithNulError> for XenClientError {
|
impl From<FromVecWithNulError> for Error {
|
||||||
fn from(value: FromVecWithNulError) -> Self {
|
fn from(value: FromVecWithNulError) -> Self {
|
||||||
XenClientError::new(value.to_string().as_str())
|
Error::new(value.to_string().as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<IntoStringError> for XenClientError {
|
impl From<IntoStringError> for Error {
|
||||||
fn from(value: IntoStringError) -> Self {
|
fn from(value: IntoStringError) -> Self {
|
||||||
XenClientError::new(value.to_string().as_str())
|
Error::new(value.to_string().as_str())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -80,24 +81,24 @@ impl ElfImageLoader {
|
|||||||
ElfImageLoader { data }
|
ElfImageLoader { data }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_file(path: &str) -> Result<ElfImageLoader, XenClientError> {
|
pub fn load_file(path: &str) -> Result<ElfImageLoader> {
|
||||||
let data = std::fs::read(path)?;
|
let data = std::fs::read(path)?;
|
||||||
Ok(ElfImageLoader::new(data))
|
Ok(ElfImageLoader::new(data))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_gz(data: &[u8]) -> Result<ElfImageLoader, XenClientError> {
|
pub fn load_gz(data: &[u8]) -> Result<ElfImageLoader> {
|
||||||
let buff = BufReader::new(data);
|
let buff = BufReader::new(data);
|
||||||
let image = ElfImageLoader::read_one_stream(&mut GzDecoder::new(buff))?;
|
let image = ElfImageLoader::read_one_stream(&mut GzDecoder::new(buff))?;
|
||||||
Ok(ElfImageLoader::new(image))
|
Ok(ElfImageLoader::new(image))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_xz(data: &[u8]) -> Result<ElfImageLoader, XenClientError> {
|
pub fn load_xz(data: &[u8]) -> Result<ElfImageLoader> {
|
||||||
let buff = BufReader::new(data);
|
let buff = BufReader::new(data);
|
||||||
let image = ElfImageLoader::read_one_stream(&mut XzDecoder::new(buff))?;
|
let image = ElfImageLoader::read_one_stream(&mut XzDecoder::new(buff))?;
|
||||||
Ok(ElfImageLoader::new(image))
|
Ok(ElfImageLoader::new(image))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_one_stream(read: &mut dyn Read) -> Result<Vec<u8>, XenClientError> {
|
fn read_one_stream(read: &mut dyn Read) -> Result<Vec<u8>> {
|
||||||
let mut result: Vec<u8> = Vec::new();
|
let mut result: Vec<u8> = Vec::new();
|
||||||
let mut buffer = [0u8; 8192];
|
let mut buffer = [0u8; 8192];
|
||||||
|
|
||||||
@ -113,24 +114,24 @@ impl ElfImageLoader {
|
|||||||
if !result.is_empty() {
|
if !result.is_empty() {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return Err(XenClientError::from(error));
|
return Err(Error::from(error));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(result)
|
Ok(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_file_gz(path: &str) -> Result<ElfImageLoader, XenClientError> {
|
pub fn load_file_gz(path: &str) -> Result<ElfImageLoader> {
|
||||||
let file = std::fs::read(path)?;
|
let file = std::fs::read(path)?;
|
||||||
ElfImageLoader::load_gz(file.as_slice())
|
ElfImageLoader::load_gz(file.as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_file_xz(path: &str) -> Result<ElfImageLoader, XenClientError> {
|
pub fn load_file_xz(path: &str) -> Result<ElfImageLoader> {
|
||||||
let file = std::fs::read(path)?;
|
let file = std::fs::read(path)?;
|
||||||
ElfImageLoader::load_xz(file.as_slice())
|
ElfImageLoader::load_xz(file.as_slice())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn load_file_kernel(path: &str) -> Result<ElfImageLoader, XenClientError> {
|
pub fn load_file_kernel(path: &str) -> Result<ElfImageLoader> {
|
||||||
let file = std::fs::read(path)?;
|
let file = std::fs::read(path)?;
|
||||||
|
|
||||||
for start in find_iter(file.as_slice(), &[0x1f, 0x8b]) {
|
for start in find_iter(file.as_slice(), &[0x1f, 0x8b]) {
|
||||||
@ -145,7 +146,7 @@ impl ElfImageLoader {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Err(XenClientError::new(
|
Err(Error::new(
|
||||||
"Unable to parse kernel image: unknown compression type",
|
"Unable to parse kernel image: unknown compression type",
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
@ -156,9 +157,9 @@ struct ElfNoteValue {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BootImageLoader for ElfImageLoader {
|
impl BootImageLoader for ElfImageLoader {
|
||||||
fn parse(&self) -> Result<BootImageInfo, XenClientError> {
|
fn parse(&self) -> Result<BootImageInfo> {
|
||||||
let elf = ElfBytes::<AnyEndian>::minimal_parse(self.data.as_slice())?;
|
let elf = ElfBytes::<AnyEndian>::minimal_parse(self.data.as_slice())?;
|
||||||
let headers = elf.section_headers().ok_or(XenClientError::new(
|
let headers = elf.section_headers().ok_or(Error::new(
|
||||||
"Unable to parse kernel image: section headers not found.",
|
"Unable to parse kernel image: section headers not found.",
|
||||||
))?;
|
))?;
|
||||||
let mut linux_notes: HashMap<u64, Vec<u8>> = HashMap::new();
|
let mut linux_notes: HashMap<u64, Vec<u8>> = HashMap::new();
|
||||||
@ -197,56 +198,44 @@ impl BootImageLoader for ElfImageLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if linux_notes.is_empty() {
|
if linux_notes.is_empty() {
|
||||||
return Err(XenClientError::new(
|
return Err(Error::new(
|
||||||
"Provided kernel does not appear to be a Linux kernel image.",
|
"Provided kernel does not appear to be a Linux kernel image.",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
if xen_notes.is_empty() {
|
if xen_notes.is_empty() {
|
||||||
return Err(XenClientError::new(
|
return Err(Error::new("Provided kernel does not have Xen support."));
|
||||||
"Provided kernel does not have Xen support.",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let paddr_offset = xen_notes
|
let paddr_offset = xen_notes
|
||||||
.get(&XEN_ELFNOTE_PADDR_OFFSET)
|
.get(&XEN_ELFNOTE_PADDR_OFFSET)
|
||||||
.ok_or(XenClientError::new(
|
.ok_or(Error::new("Unable to find paddr_offset note in kernel."))?
|
||||||
"Unable to find paddr_offset note in kernel.",
|
|
||||||
))?
|
|
||||||
.value;
|
.value;
|
||||||
let virt_base = xen_notes
|
let virt_base = xen_notes
|
||||||
.get(&XEN_ELFNOTE_VIRT_BASE)
|
.get(&XEN_ELFNOTE_VIRT_BASE)
|
||||||
.ok_or(XenClientError::new(
|
.ok_or(Error::new("Unable to find virt_base note in kernel."))?
|
||||||
"Unable to find virt_base note in kernel.",
|
|
||||||
))?
|
|
||||||
.value;
|
.value;
|
||||||
let entry = xen_notes
|
let entry = xen_notes
|
||||||
.get(&XEN_ELFNOTE_ENTRY)
|
.get(&XEN_ELFNOTE_ENTRY)
|
||||||
.ok_or(XenClientError::new("Unable to find entry note in kernel."))?
|
.ok_or(Error::new("Unable to find entry note in kernel."))?
|
||||||
.value;
|
.value;
|
||||||
let virt_hypercall = xen_notes
|
let virt_hypercall = xen_notes
|
||||||
.get(&XEN_ELFNOTE_HYPERCALL_PAGE)
|
.get(&XEN_ELFNOTE_HYPERCALL_PAGE)
|
||||||
.ok_or(XenClientError::new(
|
.ok_or(Error::new("Unable to find hypercall_page note in kernel."))?
|
||||||
"Unable to find hypercall_page note in kernel.",
|
|
||||||
))?
|
|
||||||
.value;
|
.value;
|
||||||
let init_p2m = xen_notes
|
let init_p2m = xen_notes
|
||||||
.get(&XEN_ELFNOTE_INIT_P2M)
|
.get(&XEN_ELFNOTE_INIT_P2M)
|
||||||
.ok_or(XenClientError::new(
|
.ok_or(Error::new("Unable to find init_p2m note in kernel."))?
|
||||||
"Unable to find init_p2m note in kernel.",
|
|
||||||
))?
|
|
||||||
.value;
|
.value;
|
||||||
let mod_start_pfn = xen_notes
|
let mod_start_pfn = xen_notes
|
||||||
.get(&XEN_ELFNOTE_MOD_START_PFN)
|
.get(&XEN_ELFNOTE_MOD_START_PFN)
|
||||||
.ok_or(XenClientError::new(
|
.ok_or(Error::new("Unable to find mod_start_pfn note in kernel."))?
|
||||||
"Unable to find mod_start_pfn note in kernel.",
|
|
||||||
))?
|
|
||||||
.value;
|
.value;
|
||||||
|
|
||||||
let mut start: u64 = u64::MAX;
|
let mut start: u64 = u64::MAX;
|
||||||
let mut end: u64 = 0;
|
let mut end: u64 = 0;
|
||||||
|
|
||||||
let segments = elf.segments().ok_or(XenClientError::new(
|
let segments = elf.segments().ok_or(Error::new(
|
||||||
"Unable to parse kernel image: segments not found.",
|
"Unable to parse kernel image: segments not found.",
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
@ -266,7 +255,7 @@ impl BootImageLoader for ElfImageLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if paddr_offset != XEN_UNSET_ADDR && virt_base == XEN_UNSET_ADDR {
|
if paddr_offset != XEN_UNSET_ADDR && virt_base == XEN_UNSET_ADDR {
|
||||||
return Err(XenClientError::new(
|
return Err(Error::new(
|
||||||
"Unable to load kernel image: paddr_offset set but virt_base is unset.",
|
"Unable to load kernel image: paddr_offset set but virt_base is unset.",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -289,9 +278,9 @@ impl BootImageLoader for ElfImageLoader {
|
|||||||
Ok(image_info)
|
Ok(image_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<(), XenClientError> {
|
fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<()> {
|
||||||
let elf = ElfBytes::<AnyEndian>::minimal_parse(self.data.as_slice())?;
|
let elf = ElfBytes::<AnyEndian>::minimal_parse(self.data.as_slice())?;
|
||||||
let segments = elf.segments().ok_or(XenClientError::new(
|
let segments = elf.segments().ok_or(Error::new(
|
||||||
"Unable to parse kernel image: segments not found.",
|
"Unable to parse kernel image: segments not found.",
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
|
60
xen/xenclient/src/error.rs
Normal file
60
xen/xenclient/src/error.rs
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
use std::fmt::{Display, Formatter};
|
||||||
|
use std::string::FromUtf8Error;
|
||||||
|
use xencall::XenCallError;
|
||||||
|
|
||||||
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Error {
|
||||||
|
message: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error {
|
||||||
|
pub fn new(msg: &str) -> Error {
|
||||||
|
Error {
|
||||||
|
message: msg.to_string(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for Error {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl std::error::Error for Error {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
&self.message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::io::Error> for Error {
|
||||||
|
fn from(value: std::io::Error) -> Self {
|
||||||
|
Error::new(value.to_string().as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<xenstore::error::Error> for Error {
|
||||||
|
fn from(value: xenstore::error::Error) -> Self {
|
||||||
|
Error::new(value.to_string().as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<XenCallError> for Error {
|
||||||
|
fn from(value: XenCallError) -> Self {
|
||||||
|
Error::new(value.to_string().as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<FromUtf8Error> for Error {
|
||||||
|
fn from(value: FromUtf8Error) -> Self {
|
||||||
|
Error::new(value.to_string().as_str())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<xenevtchn::error::Error> for Error {
|
||||||
|
fn from(value: xenevtchn::error::Error) -> Self {
|
||||||
|
Error::new(value.to_string().as_str())
|
||||||
|
}
|
||||||
|
}
|
@ -1,24 +1,24 @@
|
|||||||
pub mod boot;
|
pub mod boot;
|
||||||
pub mod elfloader;
|
pub mod elfloader;
|
||||||
|
pub mod error;
|
||||||
pub mod mem;
|
pub mod mem;
|
||||||
pub mod sys;
|
pub mod sys;
|
||||||
mod x86;
|
pub mod x86;
|
||||||
|
|
||||||
use crate::boot::BootSetup;
|
use crate::boot::BootSetup;
|
||||||
use crate::elfloader::ElfImageLoader;
|
use crate::elfloader::ElfImageLoader;
|
||||||
|
use crate::error::{Error, Result};
|
||||||
use crate::x86::X86BootSetup;
|
use crate::x86::X86BootSetup;
|
||||||
use log::{trace, warn};
|
use log::{trace, warn};
|
||||||
use std::error::Error;
|
|
||||||
use std::fmt::{Display, Formatter};
|
|
||||||
use std::fs::{read, File, OpenOptions};
|
use std::fs::{read, File, OpenOptions};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::string::FromUtf8Error;
|
|
||||||
use std::thread;
|
use std::thread;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use uuid::Uuid;
|
use uuid::Uuid;
|
||||||
use xencall::sys::CreateDomain;
|
use xencall::sys::CreateDomain;
|
||||||
use xencall::{XenCall, XenCallError};
|
use xencall::XenCall;
|
||||||
use xenstore::client::{
|
use xenstore::client::{
|
||||||
XsPermission, XsdClient, XsdInterface, XS_PERM_NONE, XS_PERM_READ, XS_PERM_READ_WRITE,
|
XsPermission, XsdClient, XsdInterface, XS_PERM_NONE, XS_PERM_READ, XS_PERM_READ_WRITE,
|
||||||
};
|
};
|
||||||
@ -28,61 +28,6 @@ pub struct XenClient {
|
|||||||
call: XenCall,
|
call: XenCall,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct XenClientError {
|
|
||||||
message: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl XenClientError {
|
|
||||||
pub fn new(msg: &str) -> XenClientError {
|
|
||||||
XenClientError {
|
|
||||||
message: msg.to_string(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Display for XenClientError {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{}", self.message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for XenClientError {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
&self.message
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<std::io::Error> for XenClientError {
|
|
||||||
fn from(value: std::io::Error) -> Self {
|
|
||||||
XenClientError::new(value.to_string().as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<xenstore::error::Error> for XenClientError {
|
|
||||||
fn from(value: xenstore::error::Error) -> Self {
|
|
||||||
XenClientError::new(value.to_string().as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<XenCallError> for XenClientError {
|
|
||||||
fn from(value: XenCallError) -> Self {
|
|
||||||
XenClientError::new(value.to_string().as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<FromUtf8Error> for XenClientError {
|
|
||||||
fn from(value: FromUtf8Error) -> Self {
|
|
||||||
XenClientError::new(value.to_string().as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<xenevtchn::error::Error> for XenClientError {
|
|
||||||
fn from(value: xenevtchn::error::Error) -> Self {
|
|
||||||
XenClientError::new(value.to_string().as_str())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct BlockDeviceRef {
|
pub struct BlockDeviceRef {
|
||||||
pub path: String,
|
pub path: String,
|
||||||
@ -118,13 +63,13 @@ pub struct DomainConfig<'a> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl XenClient {
|
impl XenClient {
|
||||||
pub fn open() -> Result<XenClient, XenClientError> {
|
pub fn open() -> Result<XenClient> {
|
||||||
let store = XsdClient::open()?;
|
let store = XsdClient::open()?;
|
||||||
let call = XenCall::open()?;
|
let call = XenCall::open()?;
|
||||||
Ok(XenClient { store, call })
|
Ok(XenClient { store, call })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn create(&mut self, config: &DomainConfig) -> Result<u32, XenClientError> {
|
pub fn create(&mut self, config: &DomainConfig) -> Result<u32> {
|
||||||
let domain = CreateDomain {
|
let domain = CreateDomain {
|
||||||
max_vcpus: config.max_vcpus,
|
max_vcpus: config.max_vcpus,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
@ -141,7 +86,7 @@ impl XenClient {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destroy(&mut self, domid: u32) -> Result<(), XenClientError> {
|
pub fn destroy(&mut self, domid: u32) -> Result<()> {
|
||||||
if let Err(err) = self.destroy_store(domid) {
|
if let Err(err) = self.destroy_store(domid) {
|
||||||
warn!("failed to destroy store for domain {}: {}", domid, err);
|
warn!("failed to destroy store for domain {}: {}", domid, err);
|
||||||
}
|
}
|
||||||
@ -149,13 +94,11 @@ impl XenClient {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn destroy_store(&mut self, domid: u32) -> Result<(), XenClientError> {
|
fn destroy_store(&mut self, domid: u32) -> Result<()> {
|
||||||
let dom_path = self.store.get_domain_path(domid)?;
|
let dom_path = self.store.get_domain_path(domid)?;
|
||||||
let vm_path = self.store.read_string(&format!("{}/vm", dom_path))?;
|
let vm_path = self.store.read_string(&format!("{}/vm", dom_path))?;
|
||||||
if vm_path.is_empty() {
|
if vm_path.is_empty() {
|
||||||
return Err(XenClientError::new(
|
return Err(Error::new("cannot destroy domain that doesn't exist"));
|
||||||
"cannot destroy domain that doesn't exist",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut backend_paths: Vec<String> = Vec::new();
|
let mut backend_paths: Vec<String> = Vec::new();
|
||||||
@ -220,10 +163,10 @@ impl XenClient {
|
|||||||
let path = PathBuf::from(path);
|
let path = PathBuf::from(path);
|
||||||
let parent = path
|
let parent = path
|
||||||
.parent()
|
.parent()
|
||||||
.ok_or(XenClientError::new("unable to get parent of backend path"))?;
|
.ok_or(Error::new("unable to get parent of backend path"))?;
|
||||||
tx.rm(parent
|
tx.rm(parent
|
||||||
.to_str()
|
.to_str()
|
||||||
.ok_or(XenClientError::new("unable to convert parent to string"))?)?;
|
.ok_or(Error::new("unable to convert parent to string"))?)?;
|
||||||
}
|
}
|
||||||
tx.rm(&vm_path)?;
|
tx.rm(&vm_path)?;
|
||||||
tx.rm(&dom_path)?;
|
tx.rm(&dom_path)?;
|
||||||
@ -231,12 +174,7 @@ impl XenClient {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn init(
|
fn init(&mut self, domid: u32, domain: &CreateDomain, config: &DomainConfig) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
domid: u32,
|
|
||||||
domain: &CreateDomain,
|
|
||||||
config: &DomainConfig,
|
|
||||||
) -> Result<(), XenClientError> {
|
|
||||||
trace!(
|
trace!(
|
||||||
"XenClient init domid={} domain={:?} config={:?}",
|
"XenClient init domid={} domain={:?} config={:?}",
|
||||||
domid,
|
domid,
|
||||||
@ -398,7 +336,7 @@ impl XenClient {
|
|||||||
.store
|
.store
|
||||||
.introduce_domain(domid, xenstore_mfn, xenstore_evtchn)?
|
.introduce_domain(domid, xenstore_mfn, xenstore_evtchn)?
|
||||||
{
|
{
|
||||||
return Err(XenClientError::new("failed to introduce domain"));
|
return Err(Error::new("failed to introduce domain"));
|
||||||
}
|
}
|
||||||
self.console_device_add(
|
self.console_device_add(
|
||||||
&dom_path,
|
&dom_path,
|
||||||
@ -440,7 +378,7 @@ impl XenClient {
|
|||||||
domid: u32,
|
domid: u32,
|
||||||
index: usize,
|
index: usize,
|
||||||
disk: &DomainDisk,
|
disk: &DomainDisk,
|
||||||
) -> Result<(), XenClientError> {
|
) -> Result<()> {
|
||||||
let id = (202 << 8) | (index << 4) as u64;
|
let id = (202 << 8) | (index << 4) as u64;
|
||||||
let backend_items: Vec<(&str, String)> = vec![
|
let backend_items: Vec<(&str, String)> = vec![
|
||||||
("frontend-id", domid.to_string()),
|
("frontend-id", domid.to_string()),
|
||||||
@ -491,7 +429,7 @@ impl XenClient {
|
|||||||
domid: u32,
|
domid: u32,
|
||||||
port: u32,
|
port: u32,
|
||||||
mfn: u64,
|
mfn: u64,
|
||||||
) -> Result<(), XenClientError> {
|
) -> Result<()> {
|
||||||
let backend_entries = vec![
|
let backend_entries = vec![
|
||||||
("frontend-id", domid.to_string()),
|
("frontend-id", domid.to_string()),
|
||||||
("online", "1".to_string()),
|
("online", "1".to_string()),
|
||||||
@ -530,7 +468,7 @@ impl XenClient {
|
|||||||
domid: u32,
|
domid: u32,
|
||||||
index: usize,
|
index: usize,
|
||||||
filesystem: &DomainFilesystem,
|
filesystem: &DomainFilesystem,
|
||||||
) -> Result<(), XenClientError> {
|
) -> Result<()> {
|
||||||
let id = 90 + index as u64;
|
let id = 90 + index as u64;
|
||||||
let backend_items: Vec<(&str, String)> = vec![
|
let backend_items: Vec<(&str, String)> = vec![
|
||||||
("frontend-id", domid.to_string()),
|
("frontend-id", domid.to_string()),
|
||||||
@ -570,7 +508,7 @@ impl XenClient {
|
|||||||
domid: u32,
|
domid: u32,
|
||||||
frontend_items: Vec<(&str, String)>,
|
frontend_items: Vec<(&str, String)>,
|
||||||
backend_items: Vec<(&str, String)>,
|
backend_items: Vec<(&str, String)>,
|
||||||
) -> Result<(), XenClientError> {
|
) -> Result<()> {
|
||||||
let console_zero = typ == "console" && id == 0;
|
let console_zero = typ == "console" && id == 0;
|
||||||
|
|
||||||
let frontend_path = if console_zero {
|
let frontend_path = if console_zero {
|
||||||
@ -624,7 +562,7 @@ impl XenClient {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn open_console(&mut self, domid: u32) -> Result<(File, File), XenClientError> {
|
pub fn open_console(&mut self, domid: u32) -> Result<(File, File)> {
|
||||||
let dom_path = self.store.get_domain_path(domid)?;
|
let dom_path = self.store.get_domain_path(domid)?;
|
||||||
let console_tty_path = format!("{}/console/tty", dom_path);
|
let console_tty_path = format!("{}/console/tty", dom_path);
|
||||||
let tty = self
|
let tty = self
|
||||||
@ -632,10 +570,7 @@ impl XenClient {
|
|||||||
.read_string_optional(&console_tty_path)?
|
.read_string_optional(&console_tty_path)?
|
||||||
.unwrap_or("".to_string());
|
.unwrap_or("".to_string());
|
||||||
if tty.is_empty() {
|
if tty.is_empty() {
|
||||||
return Err(XenClientError::new(&format!(
|
return Err(Error::new(&format!("domain {} does not have a tty", domid)));
|
||||||
"domain {} does not have a tty",
|
|
||||||
domid
|
|
||||||
)));
|
|
||||||
}
|
}
|
||||||
let read = OpenOptions::new().read(true).write(false).open(&tty)?;
|
let read = OpenOptions::new().read(true).write(false).open(&tty)?;
|
||||||
let write = OpenOptions::new().read(false).write(true).open(&tty)?;
|
let write = OpenOptions::new().read(false).write(true).open(&tty)?;
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
|
use crate::error::Result;
|
||||||
use crate::sys::{XEN_PAGE_SHIFT, XEN_PAGE_SIZE};
|
use crate::sys::{XEN_PAGE_SHIFT, XEN_PAGE_SIZE};
|
||||||
use crate::XenClientError;
|
use crate::Error;
|
||||||
use libc::munmap;
|
use libc::munmap;
|
||||||
use log::debug;
|
use log::debug;
|
||||||
use std::ffi::c_void;
|
use std::ffi::c_void;
|
||||||
@ -40,7 +41,7 @@ impl PhysicalPages<'_> {
|
|||||||
self.p2m.len() as u64
|
self.p2m.len() as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
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> {
|
||||||
for page in &self.pages {
|
for page in &self.pages {
|
||||||
if pfn >= page.pfn + page.count {
|
if pfn >= page.pfn + page.count {
|
||||||
continue;
|
continue;
|
||||||
@ -52,7 +53,7 @@ impl PhysicalPages<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if pfn < page.pfn || (pfn + count) > page.pfn + page.count {
|
if pfn < page.pfn || (pfn + count) > page.pfn + page.count {
|
||||||
return Err(XenClientError::new("request overlaps allocated block"));
|
return Err(Error::new("request overlaps allocated block"));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if pfn < page.pfn {
|
if pfn < page.pfn {
|
||||||
@ -68,7 +69,7 @@ impl PhysicalPages<'_> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if count == 0 {
|
if count == 0 {
|
||||||
return Err(XenClientError::new(
|
return Err(Error::new(
|
||||||
"allocation is only allowed when a size is given",
|
"allocation is only allowed when a size is given",
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
@ -76,7 +77,7 @@ impl PhysicalPages<'_> {
|
|||||||
self.pfn_alloc(pfn, count)
|
self.pfn_alloc(pfn, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn pfn_alloc(&mut self, pfn: u64, count: u64) -> Result<u64, XenClientError> {
|
fn pfn_alloc(&mut self, pfn: u64, count: u64) -> Result<u64> {
|
||||||
let mut entries = vec![MmapEntry::default(); count as usize];
|
let mut entries = vec![MmapEntry::default(); count as usize];
|
||||||
for (i, entry) in entries.iter_mut().enumerate() {
|
for (i, entry) in entries.iter_mut().enumerate() {
|
||||||
entry.mfn = self.p2m[pfn as usize + i];
|
entry.mfn = self.p2m[pfn as usize + i];
|
||||||
@ -95,11 +96,11 @@ impl PhysicalPages<'_> {
|
|||||||
let addr = self
|
let addr = self
|
||||||
.call
|
.call
|
||||||
.mmap(0, actual_mmap_len)
|
.mmap(0, actual_mmap_len)
|
||||||
.ok_or(XenClientError::new("failed to mmap address"))?;
|
.ok_or(Error::new("failed to mmap address"))?;
|
||||||
debug!("mapped {:#x} foreign bytes at {:#x}", actual_mmap_len, addr);
|
debug!("mapped {:#x} foreign bytes at {:#x}", actual_mmap_len, addr);
|
||||||
let result = self.call.mmap_batch(self.domid, num as u64, addr, pfns)?;
|
let result = self.call.mmap_batch(self.domid, num as u64, addr, pfns)?;
|
||||||
if result != 0 {
|
if result != 0 {
|
||||||
return Err(XenClientError::new("mmap_batch call failed"));
|
return Err(Error::new("mmap_batch call failed"));
|
||||||
}
|
}
|
||||||
let page = PhysicalPage {
|
let page = PhysicalPage {
|
||||||
pfn,
|
pfn,
|
||||||
@ -114,7 +115,7 @@ impl PhysicalPages<'_> {
|
|||||||
Ok(addr)
|
Ok(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn map_foreign_pages(&mut self, mfn: u64, size: u64) -> Result<u64, XenClientError> {
|
pub fn map_foreign_pages(&mut self, mfn: u64, size: u64) -> Result<u64> {
|
||||||
let num = ((size + XEN_PAGE_SIZE - 1) >> XEN_PAGE_SHIFT) as usize;
|
let num = ((size + XEN_PAGE_SIZE - 1) >> XEN_PAGE_SHIFT) as usize;
|
||||||
let mut pfns = vec![u64::MAX; num];
|
let mut pfns = vec![u64::MAX; num];
|
||||||
for (i, item) in pfns.iter_mut().enumerate().take(num) {
|
for (i, item) in pfns.iter_mut().enumerate().take(num) {
|
||||||
@ -125,11 +126,11 @@ impl PhysicalPages<'_> {
|
|||||||
let addr = self
|
let addr = self
|
||||||
.call
|
.call
|
||||||
.mmap(0, actual_mmap_len)
|
.mmap(0, actual_mmap_len)
|
||||||
.ok_or(XenClientError::new("failed to mmap address"))?;
|
.ok_or(Error::new("failed to mmap address"))?;
|
||||||
debug!("mapped {:#x} foreign bytes at {:#x}", actual_mmap_len, addr);
|
debug!("mapped {:#x} foreign bytes at {:#x}", actual_mmap_len, addr);
|
||||||
let result = self.call.mmap_batch(self.domid, num as u64, addr, pfns)?;
|
let result = self.call.mmap_batch(self.domid, num as u64, addr, pfns)?;
|
||||||
if result != 0 {
|
if result != 0 {
|
||||||
return Err(XenClientError::new("mmap_batch call failed"));
|
return Err(Error::new("mmap_batch call failed"));
|
||||||
}
|
}
|
||||||
let page = PhysicalPage {
|
let page = PhysicalPage {
|
||||||
pfn: u64::MAX,
|
pfn: u64::MAX,
|
||||||
@ -144,7 +145,7 @@ impl PhysicalPages<'_> {
|
|||||||
Ok(addr)
|
Ok(addr)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unmap_all(&mut self) -> Result<(), XenClientError> {
|
pub fn unmap_all(&mut self) -> Result<()> {
|
||||||
for page in &self.pages {
|
for page in &self.pages {
|
||||||
unsafe {
|
unsafe {
|
||||||
let err = munmap(
|
let err = munmap(
|
||||||
@ -152,7 +153,7 @@ impl PhysicalPages<'_> {
|
|||||||
(page.count << X86_PAGE_SHIFT) as usize,
|
(page.count << X86_PAGE_SHIFT) as usize,
|
||||||
);
|
);
|
||||||
if err != 0 {
|
if err != 0 {
|
||||||
return Err(XenClientError::new("failed to munmap all pages"));
|
return Err(Error::new("failed to munmap all pages"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -160,10 +161,10 @@ impl PhysicalPages<'_> {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn unmap(&mut self, pfn: u64) -> Result<(), XenClientError> {
|
pub fn unmap(&mut self, pfn: u64) -> Result<()> {
|
||||||
let page = self.pages.iter().enumerate().find(|(_, x)| x.pfn == pfn);
|
let page = self.pages.iter().enumerate().find(|(_, x)| x.pfn == pfn);
|
||||||
if page.is_none() {
|
if page.is_none() {
|
||||||
return Err(XenClientError::new("unable to find page to unmap"));
|
return Err(Error::new("unable to find page to unmap"));
|
||||||
}
|
}
|
||||||
let (i, page) = page.unwrap();
|
let (i, page) = page.unwrap();
|
||||||
|
|
||||||
@ -178,7 +179,7 @@ impl PhysicalPages<'_> {
|
|||||||
page.ptr
|
page.ptr
|
||||||
);
|
);
|
||||||
if err != 0 {
|
if err != 0 {
|
||||||
return Err(XenClientError::new("failed to munmap page"));
|
return Err(Error::new("failed to munmap page"));
|
||||||
}
|
}
|
||||||
self.pages.remove(i);
|
self.pages.remove(i);
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
use crate::boot::{
|
use crate::boot::{
|
||||||
ArchBootSetup, BootImageInfo, BootSetup, BootState, DomainSegment, XEN_UNSET_ADDR,
|
ArchBootSetup, BootImageInfo, BootSetup, BootState, DomainSegment, XEN_UNSET_ADDR,
|
||||||
};
|
};
|
||||||
|
use crate::error::Result;
|
||||||
use crate::sys::{
|
use crate::sys::{
|
||||||
SUPERPAGE_2MB_NR_PFNS, SUPERPAGE_2MB_SHIFT, SUPERPAGE_BATCH_SIZE, VGCF_IN_KERNEL, VGCF_ONLINE,
|
SUPERPAGE_2MB_NR_PFNS, SUPERPAGE_2MB_SHIFT, SUPERPAGE_BATCH_SIZE, VGCF_IN_KERNEL, VGCF_ONLINE,
|
||||||
XEN_PAGE_SHIFT,
|
XEN_PAGE_SHIFT,
|
||||||
};
|
};
|
||||||
use crate::XenClientError;
|
use crate::Error;
|
||||||
use libc::c_char;
|
use libc::c_char;
|
||||||
use log::{debug, trace};
|
use log::{debug, trace};
|
||||||
use slice_copy::copy;
|
use slice_copy::copy;
|
||||||
@ -139,6 +140,12 @@ struct VmemRange {
|
|||||||
_nid: u32,
|
_nid: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for X86BootSetup {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl X86BootSetup {
|
impl X86BootSetup {
|
||||||
pub fn new() -> X86BootSetup {
|
pub fn new() -> X86BootSetup {
|
||||||
X86BootSetup {
|
X86BootSetup {
|
||||||
@ -193,22 +200,22 @@ impl X86BootSetup {
|
|||||||
from: u64,
|
from: u64,
|
||||||
to: u64,
|
to: u64,
|
||||||
pfn: u64,
|
pfn: u64,
|
||||||
) -> Result<usize, XenClientError> {
|
) -> Result<usize> {
|
||||||
debug!("counting pgtables from={} to={} pfn={}", from, to, pfn);
|
debug!("counting pgtables from={} to={} pfn={}", from, to, pfn);
|
||||||
if self.table.mappings_count == X86_PAGE_TABLE_MAX_MAPPINGS {
|
if self.table.mappings_count == X86_PAGE_TABLE_MAX_MAPPINGS {
|
||||||
return Err(XenClientError::new("too many mappings"));
|
return Err(Error::new("too many mappings"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let m = self.table.mappings_count;
|
let m = self.table.mappings_count;
|
||||||
|
|
||||||
let pfn_end = pfn + ((to - from) >> X86_PAGE_SHIFT);
|
let pfn_end = pfn + ((to - from) >> X86_PAGE_SHIFT);
|
||||||
if pfn_end >= setup.phys.p2m_size() {
|
if pfn_end >= setup.phys.p2m_size() {
|
||||||
return Err(XenClientError::new("not enough memory for initial mapping"));
|
return Err(Error::new("not enough memory for initial mapping"));
|
||||||
}
|
}
|
||||||
|
|
||||||
for idx in 0..self.table.mappings_count {
|
for idx in 0..self.table.mappings_count {
|
||||||
if from < self.table.mappings[idx].area.to && to > self.table.mappings[idx].area.from {
|
if from < self.table.mappings[idx].area.to && to > self.table.mappings[idx].area.from {
|
||||||
return Err(XenClientError::new("overlapping mappings"));
|
return Err(Error::new("overlapping mappings"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut map = PageTableMapping::default();
|
let mut map = PageTableMapping::default();
|
||||||
@ -284,7 +291,7 @@ impl ArchBootSetup for X86BootSetup {
|
|||||||
&mut self,
|
&mut self,
|
||||||
setup: &mut BootSetup,
|
setup: &mut BootSetup,
|
||||||
image_info: &BootImageInfo,
|
image_info: &BootImageInfo,
|
||||||
) -> Result<DomainSegment, XenClientError> {
|
) -> Result<DomainSegment> {
|
||||||
let mut p2m_alloc_size =
|
let mut p2m_alloc_size =
|
||||||
((setup.phys.p2m_size() * 8) + X86_PAGE_SIZE - 1) & !(X86_PAGE_SIZE - 1);
|
((setup.phys.p2m_size() * 8) + X86_PAGE_SIZE - 1) & !(X86_PAGE_SIZE - 1);
|
||||||
let from = image_info.virt_p2m_base;
|
let from = image_info.virt_p2m_base;
|
||||||
@ -310,7 +317,7 @@ impl ArchBootSetup for X86BootSetup {
|
|||||||
&mut self,
|
&mut self,
|
||||||
setup: &mut BootSetup,
|
setup: &mut BootSetup,
|
||||||
image_info: &BootImageInfo,
|
image_info: &BootImageInfo,
|
||||||
) -> Result<DomainSegment, XenClientError> {
|
) -> Result<DomainSegment> {
|
||||||
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;
|
||||||
@ -341,11 +348,7 @@ impl ArchBootSetup for X86BootSetup {
|
|||||||
Ok(segment)
|
Ok(segment)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_page_tables(
|
fn setup_page_tables(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
setup: &mut BootSetup,
|
|
||||||
state: &mut BootState,
|
|
||||||
) -> Result<(), XenClientError> {
|
|
||||||
let p2m_guest = unsafe {
|
let p2m_guest = unsafe {
|
||||||
slice::from_raw_parts_mut(
|
slice::from_raw_parts_mut(
|
||||||
state.p2m_segment.addr as *mut u64,
|
state.p2m_segment.addr as *mut u64,
|
||||||
@ -407,7 +410,7 @@ impl ArchBootSetup for X86BootSetup {
|
|||||||
setup: &mut BootSetup,
|
setup: &mut BootSetup,
|
||||||
state: &BootState,
|
state: &BootState,
|
||||||
cmdline: &str,
|
cmdline: &str,
|
||||||
) -> Result<(), XenClientError> {
|
) -> Result<()> {
|
||||||
let ptr = setup.phys.pfn_to_ptr(state.start_info_segment.pfn, 1)?;
|
let ptr = setup.phys.pfn_to_ptr(state.start_info_segment.pfn, 1)?;
|
||||||
let byte_slice =
|
let byte_slice =
|
||||||
unsafe { slice::from_raw_parts_mut(ptr as *mut u8, X86_PAGE_SIZE as usize) };
|
unsafe { slice::from_raw_parts_mut(ptr as *mut u8, X86_PAGE_SIZE as usize) };
|
||||||
@ -441,11 +444,7 @@ impl ArchBootSetup for X86BootSetup {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn setup_shared_info(
|
fn setup_shared_info(&mut self, setup: &mut BootSetup, shared_info_frame: u64) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
setup: &mut BootSetup,
|
|
||||||
shared_info_frame: u64,
|
|
||||||
) -> Result<(), XenClientError> {
|
|
||||||
let info = setup
|
let info = setup
|
||||||
.phys
|
.phys
|
||||||
.map_foreign_pages(shared_info_frame, X86_PAGE_SIZE)?
|
.map_foreign_pages(shared_info_frame, X86_PAGE_SIZE)?
|
||||||
@ -466,7 +465,7 @@ impl ArchBootSetup for X86BootSetup {
|
|||||||
&mut self,
|
&mut self,
|
||||||
setup: &mut BootSetup,
|
setup: &mut BootSetup,
|
||||||
image_info: &BootImageInfo,
|
image_info: &BootImageInfo,
|
||||||
) -> Result<(), XenClientError> {
|
) -> Result<()> {
|
||||||
if image_info.virt_hypercall == XEN_UNSET_ADDR {
|
if image_info.virt_hypercall == XEN_UNSET_ADDR {
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -477,7 +476,7 @@ impl ArchBootSetup for X86BootSetup {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn meminit(&mut self, setup: &mut BootSetup, total_pages: u64) -> Result<(), XenClientError> {
|
fn meminit(&mut self, setup: &mut BootSetup, total_pages: u64) -> Result<()> {
|
||||||
setup.call.claim_pages(setup.domid, total_pages)?;
|
setup.call.claim_pages(setup.domid, total_pages)?;
|
||||||
let mut vmemranges: Vec<VmemRange> = Vec::new();
|
let mut vmemranges: Vec<VmemRange> = Vec::new();
|
||||||
let stub = VmemRange {
|
let stub = VmemRange {
|
||||||
@ -495,9 +494,7 @@ impl ArchBootSetup for X86BootSetup {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if total != total_pages {
|
if total != total_pages {
|
||||||
return Err(XenClientError::new(
|
return Err(Error::new("page count mismatch while calculating pages"));
|
||||||
"page count mismatch while calculating pages",
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setup.total_pages = total;
|
setup.total_pages = total;
|
||||||
@ -564,7 +561,7 @@ impl ArchBootSetup for X86BootSetup {
|
|||||||
.populate_physmap(setup.domid, allocsz, 0, 0, input_extent_starts)?;
|
.populate_physmap(setup.domid, allocsz, 0, 0, input_extent_starts)?;
|
||||||
|
|
||||||
if result.len() != allocsz as usize {
|
if result.len() != allocsz as usize {
|
||||||
return Err(XenClientError::new(
|
return Err(Error::new(
|
||||||
format!(
|
format!(
|
||||||
"failed to populate physmap: wanted={} received={} input_extents={}",
|
"failed to populate physmap: wanted={} received={} input_extents={}",
|
||||||
allocsz,
|
allocsz,
|
||||||
@ -589,11 +586,7 @@ impl ArchBootSetup for X86BootSetup {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn bootlate(
|
fn bootlate(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()> {
|
||||||
&mut self,
|
|
||||||
setup: &mut BootSetup,
|
|
||||||
state: &mut BootState,
|
|
||||||
) -> Result<(), XenClientError> {
|
|
||||||
let pg_pfn = state.page_table_segment.pfn;
|
let pg_pfn = state.page_table_segment.pfn;
|
||||||
let pg_mfn = setup.phys.p2m[pg_pfn as usize];
|
let pg_mfn = setup.phys.p2m[pg_pfn as usize];
|
||||||
setup.phys.unmap(pg_pfn)?;
|
setup.phys.unmap(pg_pfn)?;
|
||||||
@ -604,7 +597,7 @@ impl ArchBootSetup for X86BootSetup {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn vcpu(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<(), XenClientError> {
|
fn vcpu(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()> {
|
||||||
let pg_pfn = state.page_table_segment.pfn;
|
let pg_pfn = state.page_table_segment.pfn;
|
||||||
let pg_mfn = setup.phys.p2m[pg_pfn as usize];
|
let pg_mfn = setup.phys.p2m[pg_pfn as usize];
|
||||||
let mut vcpu = VcpuGuestContext::default();
|
let mut vcpu = VcpuGuestContext::default();
|
||||||
|
Loading…
Reference in New Issue
Block a user