xenclient: move error to it's own mod

This commit is contained in:
Alex Zenla 2024-01-30 17:42:55 -08:00
parent eec213c712
commit 890a8ee63f
No known key found for this signature in database
GPG Key ID: 067B238899B51269
8 changed files with 182 additions and 228 deletions

View File

@ -5,6 +5,7 @@ edition = "2021"
resolver = "2"
[dependencies]
thiserror = { workspace = true }
libc = { workspace = true }
elf = { workspace = true }
flate2 = { workspace = true }

View File

@ -1,7 +1,8 @@
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();
let args: Vec<String> = env::args().collect();

View File

@ -1,6 +1,7 @@
use crate::error::Result;
use crate::mem::PhysicalPages;
use crate::sys::{GrantEntry, XEN_PAGE_SHIFT};
use crate::XenClientError;
use crate::Error;
use libc::munmap;
use log::debug;
use slice_copy::copy;
@ -10,8 +11,8 @@ use std::slice;
use xencall::XenCall;
pub trait BootImageLoader {
fn parse(&self) -> Result<BootImageInfo, XenClientError>;
fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<(), XenClientError>;
fn parse(&self) -> Result<BootImageInfo>;
fn load(&self, image_info: &BootImageInfo, dst: &mut [u8]) -> Result<()>;
}
pub const XEN_UNSET_ADDR: u64 = -1i64 as u64;
@ -77,11 +78,7 @@ impl BootSetup<'_> {
}
}
fn initialize_memory(
&mut self,
arch: &mut dyn ArchBootSetup,
total_pages: u64,
) -> Result<(), XenClientError> {
fn initialize_memory(&mut self, arch: &mut dyn ArchBootSetup, total_pages: u64) -> Result<()> {
self.call.set_address_size(self.domid, 64)?;
arch.meminit(self, total_pages)?;
Ok(())
@ -94,7 +91,7 @@ impl BootSetup<'_> {
initrd: &[u8],
max_vcpus: u32,
mem_mb: u64,
) -> Result<BootState, XenClientError> {
) -> Result<BootState> {
debug!(
"BootSetup initialize max_vcpus={:?} mem_mb={:?}",
max_vcpus, mem_mb
@ -164,7 +161,7 @@ impl BootSetup<'_> {
arch: &mut dyn ArchBootSetup,
state: &mut BootState,
cmdline: &str,
) -> Result<(), XenClientError> {
) -> Result<()> {
let domain_info = self.call.get_domain_info(self.domid)?;
let shared_info_frame = domain_info.shared_info_frame;
state.shared_info_frame = shared_info_frame;
@ -179,13 +176,13 @@ impl BootSetup<'_> {
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 xenstore_gfn = self.phys.p2m[state.xenstore_segment.pfn as usize];
let addr = self
.call
.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)?;
let entries = unsafe { slice::from_raw_parts_mut(addr as *mut GrantEntry, 2) };
entries[0].flags = 1 << 0;
@ -197,7 +194,7 @@ impl BootSetup<'_> {
unsafe {
let result = munmap(addr as *mut c_void, 1 << XEN_PAGE_SHIFT);
if result != 0 {
return Err(XenClientError::new("failed to unmap resource"));
return Err(Error::new("failed to unmap resource"));
}
}
Ok(())
@ -208,7 +205,7 @@ impl BootSetup<'_> {
arch: &mut dyn ArchBootSetup,
image_loader: &dyn BootImageLoader,
image_info: &BootImageInfo,
) -> Result<DomainSegment, XenClientError> {
) -> Result<DomainSegment> {
let kernel_segment = self.alloc_segment(
arch,
image_info.virt_kstart,
@ -234,7 +231,7 @@ impl BootSetup<'_> {
arch: &mut dyn ArchBootSetup,
start: u64,
size: u64,
) -> Result<DomainSegment, XenClientError> {
) -> Result<DomainSegment> {
if start > 0 {
self.alloc_padding_pages(arch, start)?;
}
@ -268,10 +265,7 @@ impl BootSetup<'_> {
Ok(segment)
}
fn alloc_page(
&mut self,
arch: &mut dyn ArchBootSetup,
) -> Result<DomainSegment, XenClientError> {
fn alloc_page(&mut self, arch: &mut dyn ArchBootSetup) -> Result<DomainSegment> {
let start = self.virt_alloc_end;
let pfn = self.pfn_alloc_end;
@ -291,26 +285,22 @@ impl BootSetup<'_> {
&mut self,
arch: &mut dyn ArchBootSetup,
buffer: &[u8],
) -> Result<DomainSegment, XenClientError> {
) -> Result<DomainSegment> {
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()) };
copy(slice, buffer);
Ok(segment)
}
fn alloc_padding_pages(
&mut self,
arch: &mut dyn ArchBootSetup,
boundary: u64,
) -> Result<(), XenClientError> {
fn alloc_padding_pages(&mut self, arch: &mut dyn ArchBootSetup, boundary: u64) -> Result<()> {
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(),
));
}
if boundary < self.virt_alloc_end {
return Err(XenClientError::new(
return Err(Error::new(
format!("segment boundary too low: {:#x})", boundary).as_str(),
));
}
@ -319,16 +309,12 @@ impl BootSetup<'_> {
Ok(())
}
fn chk_alloc_pages(
&mut self,
arch: &mut dyn ArchBootSetup,
pages: u64,
) -> Result<(), XenClientError> {
fn chk_alloc_pages(&mut self, arch: &mut dyn ArchBootSetup, pages: u64) -> Result<()> {
if pages > self.total_pages
|| self.pfn_alloc_end > self.total_pages
|| pages > self.total_pages - self.pfn_alloc_end
{
return Err(XenClientError::new(
return Err(Error::new(
format!(
"segment too large: pages={} total_pages={} pfn_alloc_end={}",
pages, self.total_pages, self.pfn_alloc_end
@ -351,44 +337,32 @@ pub trait ArchBootSetup {
&mut self,
setup: &mut BootSetup,
image_info: &BootImageInfo,
) -> Result<DomainSegment, XenClientError>;
) -> Result<DomainSegment>;
fn alloc_page_tables(
&mut self,
setup: &mut BootSetup,
image_info: &BootImageInfo,
) -> Result<DomainSegment, XenClientError>;
) -> Result<DomainSegment>;
fn setup_page_tables(
&mut self,
setup: &mut BootSetup,
state: &mut BootState,
) -> Result<(), XenClientError>;
fn setup_page_tables(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()>;
fn setup_start_info(
&mut self,
setup: &mut BootSetup,
state: &BootState,
cmdline: &str,
) -> Result<(), XenClientError>;
) -> Result<()>;
fn setup_shared_info(
&mut self,
setup: &mut BootSetup,
shared_info_frame: u64,
) -> Result<(), XenClientError>;
fn setup_shared_info(&mut self, setup: &mut BootSetup, shared_info_frame: u64) -> Result<()>;
fn setup_hypercall_page(
&mut self,
setup: &mut BootSetup,
image_info: &BootImageInfo,
) -> Result<(), XenClientError>;
) -> Result<()>;
fn meminit(&mut self, setup: &mut BootSetup, total_pages: u64) -> Result<(), XenClientError>;
fn bootlate(
&mut self,
setup: &mut BootSetup,
state: &mut BootState,
) -> Result<(), XenClientError>;
fn vcpu(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<(), XenClientError>;
fn meminit(&mut self, setup: &mut BootSetup, total_pages: u64) -> Result<()>;
fn bootlate(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()>;
fn vcpu(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()>;
}

View File

@ -1,9 +1,10 @@
use crate::boot::{BootImageInfo, BootImageLoader, XEN_UNSET_ADDR};
use crate::error::Result;
use crate::sys::{
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,
};
use crate::XenClientError;
use crate::Error;
use elf::abi::{PF_R, PF_W, PF_X, PT_LOAD, SHT_NOTE};
use elf::endian::AnyEndian;
use elf::note::Note;
@ -18,21 +19,21 @@ use std::io::{BufReader, Read};
use std::mem::size_of;
use xz2::bufread::XzDecoder;
impl From<ParseError> for XenClientError {
impl From<ParseError> for Error {
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 {
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 {
XenClientError::new(value.to_string().as_str())
Error::new(value.to_string().as_str())
}
}
@ -80,24 +81,24 @@ impl ElfImageLoader {
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)?;
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 image = ElfImageLoader::read_one_stream(&mut GzDecoder::new(buff))?;
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 image = ElfImageLoader::read_one_stream(&mut XzDecoder::new(buff))?;
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 buffer = [0u8; 8192];
@ -113,24 +114,24 @@ impl ElfImageLoader {
if !result.is_empty() {
break;
}
return Err(XenClientError::from(error));
return Err(Error::from(error));
}
}
}
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)?;
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)?;
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)?;
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",
))
}
@ -156,9 +157,9 @@ struct ElfNoteValue {
}
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 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.",
))?;
let mut linux_notes: HashMap<u64, Vec<u8>> = HashMap::new();
@ -197,56 +198,44 @@ impl BootImageLoader for ElfImageLoader {
}
if linux_notes.is_empty() {
return Err(XenClientError::new(
return Err(Error::new(
"Provided kernel does not appear to be a Linux kernel image.",
));
}
if xen_notes.is_empty() {
return Err(XenClientError::new(
"Provided kernel does not have Xen support.",
));
return Err(Error::new("Provided kernel does not have Xen support."));
}
let paddr_offset = xen_notes
.get(&XEN_ELFNOTE_PADDR_OFFSET)
.ok_or(XenClientError::new(
"Unable to find paddr_offset note in kernel.",
))?
.ok_or(Error::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.",
))?
.ok_or(Error::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."))?
.ok_or(Error::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.",
))?
.ok_or(Error::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.",
))?
.ok_or(Error::new("Unable to find init_p2m note in kernel."))?
.value;
let mod_start_pfn = xen_notes
.get(&XEN_ELFNOTE_MOD_START_PFN)
.ok_or(XenClientError::new(
"Unable to find mod_start_pfn note in kernel.",
))?
.ok_or(Error::new("Unable to find mod_start_pfn note in kernel."))?
.value;
let mut start: u64 = u64::MAX;
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.",
))?;
@ -266,7 +255,7 @@ impl BootImageLoader for ElfImageLoader {
}
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.",
));
}
@ -289,9 +278,9 @@ impl BootImageLoader for ElfImageLoader {
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 segments = elf.segments().ok_or(XenClientError::new(
let segments = elf.segments().ok_or(Error::new(
"Unable to parse kernel image: segments not found.",
))?;

View 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())
}
}

View File

@ -1,24 +1,24 @@
pub mod boot;
pub mod elfloader;
pub mod error;
pub mod mem;
pub mod sys;
mod x86;
pub mod x86;
use crate::boot::BootSetup;
use crate::elfloader::ElfImageLoader;
use crate::error::{Error, Result};
use crate::x86::X86BootSetup;
use log::{trace, warn};
use std::error::Error;
use std::fmt::{Display, Formatter};
use std::fs::{read, File, OpenOptions};
use std::path::PathBuf;
use std::str::FromStr;
use std::string::FromUtf8Error;
use std::thread;
use std::time::Duration;
use uuid::Uuid;
use xencall::sys::CreateDomain;
use xencall::{XenCall, XenCallError};
use xencall::XenCall;
use xenstore::client::{
XsPermission, XsdClient, XsdInterface, XS_PERM_NONE, XS_PERM_READ, XS_PERM_READ_WRITE,
};
@ -28,61 +28,6 @@ pub struct XenClient {
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)]
pub struct BlockDeviceRef {
pub path: String,
@ -118,13 +63,13 @@ pub struct DomainConfig<'a> {
}
impl XenClient {
pub fn open() -> Result<XenClient, XenClientError> {
pub fn open() -> Result<XenClient> {
let store = XsdClient::open()?;
let call = XenCall::open()?;
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 {
max_vcpus: config.max_vcpus,
..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) {
warn!("failed to destroy store for domain {}: {}", domid, err);
}
@ -149,13 +94,11 @@ impl XenClient {
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 vm_path = self.store.read_string(&format!("{}/vm", dom_path))?;
if vm_path.is_empty() {
return Err(XenClientError::new(
"cannot destroy domain that doesn't exist",
));
return Err(Error::new("cannot destroy domain that doesn't exist"));
}
let mut backend_paths: Vec<String> = Vec::new();
@ -220,10 +163,10 @@ impl XenClient {
let path = PathBuf::from(path);
let parent = path
.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
.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(&dom_path)?;
@ -231,12 +174,7 @@ impl XenClient {
Ok(())
}
fn init(
&mut self,
domid: u32,
domain: &CreateDomain,
config: &DomainConfig,
) -> Result<(), XenClientError> {
fn init(&mut self, domid: u32, domain: &CreateDomain, config: &DomainConfig) -> Result<()> {
trace!(
"XenClient init domid={} domain={:?} config={:?}",
domid,
@ -398,7 +336,7 @@ impl XenClient {
.store
.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(
&dom_path,
@ -440,7 +378,7 @@ impl XenClient {
domid: u32,
index: usize,
disk: &DomainDisk,
) -> Result<(), XenClientError> {
) -> Result<()> {
let id = (202 << 8) | (index << 4) as u64;
let backend_items: Vec<(&str, String)> = vec![
("frontend-id", domid.to_string()),
@ -491,7 +429,7 @@ impl XenClient {
domid: u32,
port: u32,
mfn: u64,
) -> Result<(), XenClientError> {
) -> Result<()> {
let backend_entries = vec![
("frontend-id", domid.to_string()),
("online", "1".to_string()),
@ -530,7 +468,7 @@ impl XenClient {
domid: u32,
index: usize,
filesystem: &DomainFilesystem,
) -> Result<(), XenClientError> {
) -> Result<()> {
let id = 90 + index as u64;
let backend_items: Vec<(&str, String)> = vec![
("frontend-id", domid.to_string()),
@ -570,7 +508,7 @@ impl XenClient {
domid: u32,
frontend_items: Vec<(&str, String)>,
backend_items: Vec<(&str, String)>,
) -> Result<(), XenClientError> {
) -> Result<()> {
let console_zero = typ == "console" && id == 0;
let frontend_path = if console_zero {
@ -624,7 +562,7 @@ impl XenClient {
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 console_tty_path = format!("{}/console/tty", dom_path);
let tty = self
@ -632,10 +570,7 @@ impl XenClient {
.read_string_optional(&console_tty_path)?
.unwrap_or("".to_string());
if tty.is_empty() {
return Err(XenClientError::new(&format!(
"domain {} does not have a tty",
domid
)));
return Err(Error::new(&format!("domain {} does not have a tty", domid)));
}
let read = OpenOptions::new().read(true).write(false).open(&tty)?;
let write = OpenOptions::new().read(false).write(true).open(&tty)?;

View File

@ -1,5 +1,6 @@
use crate::error::Result;
use crate::sys::{XEN_PAGE_SHIFT, XEN_PAGE_SIZE};
use crate::XenClientError;
use crate::Error;
use libc::munmap;
use log::debug;
use std::ffi::c_void;
@ -40,7 +41,7 @@ impl PhysicalPages<'_> {
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 {
if pfn >= page.pfn + page.count {
continue;
@ -52,7 +53,7 @@ impl PhysicalPages<'_> {
}
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 {
if pfn < page.pfn {
@ -68,7 +69,7 @@ impl PhysicalPages<'_> {
}
if count == 0 {
return Err(XenClientError::new(
return Err(Error::new(
"allocation is only allowed when a size is given",
));
}
@ -76,7 +77,7 @@ impl PhysicalPages<'_> {
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];
for (i, entry) in entries.iter_mut().enumerate() {
entry.mfn = self.p2m[pfn as usize + i];
@ -95,11 +96,11 @@ impl PhysicalPages<'_> {
let addr = self
.call
.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);
let result = self.call.mmap_batch(self.domid, num as u64, addr, pfns)?;
if result != 0 {
return Err(XenClientError::new("mmap_batch call failed"));
return Err(Error::new("mmap_batch call failed"));
}
let page = PhysicalPage {
pfn,
@ -114,7 +115,7 @@ impl PhysicalPages<'_> {
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 mut pfns = vec![u64::MAX; num];
for (i, item) in pfns.iter_mut().enumerate().take(num) {
@ -125,11 +126,11 @@ impl PhysicalPages<'_> {
let addr = self
.call
.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);
let result = self.call.mmap_batch(self.domid, num as u64, addr, pfns)?;
if result != 0 {
return Err(XenClientError::new("mmap_batch call failed"));
return Err(Error::new("mmap_batch call failed"));
}
let page = PhysicalPage {
pfn: u64::MAX,
@ -144,7 +145,7 @@ impl PhysicalPages<'_> {
Ok(addr)
}
pub fn unmap_all(&mut self) -> Result<(), XenClientError> {
pub fn unmap_all(&mut self) -> Result<()> {
for page in &self.pages {
unsafe {
let err = munmap(
@ -152,7 +153,7 @@ impl PhysicalPages<'_> {
(page.count << X86_PAGE_SHIFT) as usize,
);
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(())
}
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);
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();
@ -178,7 +179,7 @@ impl PhysicalPages<'_> {
page.ptr
);
if err != 0 {
return Err(XenClientError::new("failed to munmap page"));
return Err(Error::new("failed to munmap page"));
}
self.pages.remove(i);
}

View File

@ -1,11 +1,12 @@
use crate::boot::{
ArchBootSetup, BootImageInfo, BootSetup, BootState, DomainSegment, XEN_UNSET_ADDR,
};
use crate::error::Result;
use crate::sys::{
SUPERPAGE_2MB_NR_PFNS, SUPERPAGE_2MB_SHIFT, SUPERPAGE_BATCH_SIZE, VGCF_IN_KERNEL, VGCF_ONLINE,
XEN_PAGE_SHIFT,
};
use crate::XenClientError;
use crate::Error;
use libc::c_char;
use log::{debug, trace};
use slice_copy::copy;
@ -139,6 +140,12 @@ struct VmemRange {
_nid: u32,
}
impl Default for X86BootSetup {
fn default() -> Self {
Self::new()
}
}
impl X86BootSetup {
pub fn new() -> X86BootSetup {
X86BootSetup {
@ -193,22 +200,22 @@ impl X86BootSetup {
from: u64,
to: u64,
pfn: u64,
) -> Result<usize, XenClientError> {
) -> Result<usize> {
debug!("counting pgtables from={} to={} pfn={}", from, to, pfn);
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 pfn_end = pfn + ((to - from) >> X86_PAGE_SHIFT);
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 {
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();
@ -284,7 +291,7 @@ impl ArchBootSetup for X86BootSetup {
&mut self,
setup: &mut BootSetup,
image_info: &BootImageInfo,
) -> Result<DomainSegment, XenClientError> {
) -> Result<DomainSegment> {
let mut p2m_alloc_size =
((setup.phys.p2m_size() * 8) + X86_PAGE_SIZE - 1) & !(X86_PAGE_SIZE - 1);
let from = image_info.virt_p2m_base;
@ -310,7 +317,7 @@ impl ArchBootSetup for X86BootSetup {
&mut self,
setup: &mut BootSetup,
image_info: &BootImageInfo,
) -> Result<DomainSegment, XenClientError> {
) -> Result<DomainSegment> {
let mut extra_pages = 1;
extra_pages += (512 * 1024) / X86_PAGE_SIZE;
let mut pages = extra_pages;
@ -341,11 +348,7 @@ impl ArchBootSetup for X86BootSetup {
Ok(segment)
}
fn setup_page_tables(
&mut self,
setup: &mut BootSetup,
state: &mut BootState,
) -> Result<(), XenClientError> {
fn setup_page_tables(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()> {
let p2m_guest = unsafe {
slice::from_raw_parts_mut(
state.p2m_segment.addr as *mut u64,
@ -407,7 +410,7 @@ impl ArchBootSetup for X86BootSetup {
setup: &mut BootSetup,
state: &BootState,
cmdline: &str,
) -> Result<(), XenClientError> {
) -> Result<()> {
let ptr = setup.phys.pfn_to_ptr(state.start_info_segment.pfn, 1)?;
let byte_slice =
unsafe { slice::from_raw_parts_mut(ptr as *mut u8, X86_PAGE_SIZE as usize) };
@ -441,11 +444,7 @@ impl ArchBootSetup for X86BootSetup {
Ok(())
}
fn setup_shared_info(
&mut self,
setup: &mut BootSetup,
shared_info_frame: u64,
) -> Result<(), XenClientError> {
fn setup_shared_info(&mut self, setup: &mut BootSetup, shared_info_frame: u64) -> Result<()> {
let info = setup
.phys
.map_foreign_pages(shared_info_frame, X86_PAGE_SIZE)?
@ -466,7 +465,7 @@ impl ArchBootSetup for X86BootSetup {
&mut self,
setup: &mut BootSetup,
image_info: &BootImageInfo,
) -> Result<(), XenClientError> {
) -> Result<()> {
if image_info.virt_hypercall == XEN_UNSET_ADDR {
return Ok(());
}
@ -477,7 +476,7 @@ impl ArchBootSetup for X86BootSetup {
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)?;
let mut vmemranges: Vec<VmemRange> = Vec::new();
let stub = VmemRange {
@ -495,9 +494,7 @@ impl ArchBootSetup for X86BootSetup {
}
if total != total_pages {
return Err(XenClientError::new(
"page count mismatch while calculating pages",
));
return Err(Error::new("page count mismatch while calculating pages"));
}
setup.total_pages = total;
@ -564,7 +561,7 @@ impl ArchBootSetup for X86BootSetup {
.populate_physmap(setup.domid, allocsz, 0, 0, input_extent_starts)?;
if result.len() != allocsz as usize {
return Err(XenClientError::new(
return Err(Error::new(
format!(
"failed to populate physmap: wanted={} received={} input_extents={}",
allocsz,
@ -589,11 +586,7 @@ impl ArchBootSetup for X86BootSetup {
Ok(())
}
fn bootlate(
&mut self,
setup: &mut BootSetup,
state: &mut BootState,
) -> Result<(), XenClientError> {
fn bootlate(&mut self, setup: &mut BootSetup, state: &mut BootState) -> Result<()> {
let pg_pfn = state.page_table_segment.pfn;
let pg_mfn = setup.phys.p2m[pg_pfn as usize];
setup.phys.unmap(pg_pfn)?;
@ -604,7 +597,7 @@ impl ArchBootSetup for X86BootSetup {
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_mfn = setup.phys.p2m[pg_pfn as usize];
let mut vcpu = VcpuGuestContext::default();