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" 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 }

View File

@ -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();

View File

@ -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>;
} }

View File

@ -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.",
))?; ))?;

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 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)?;

View File

@ -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);
} }

View File

@ -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();