mirror of
https://github.com/hermitcore/libhermit.git
synced 2025-03-09 00:00:03 +01:00
Improved error handling
The error::Error enum has changed to provide additional information, especially about missing files and failed IOCTL commands.
This commit is contained in:
parent
d687208b01
commit
bb0e1f2a36
8 changed files with 104 additions and 41 deletions
|
@ -14,24 +14,36 @@ pub struct Multi {
|
|||
|
||||
impl Multi {
|
||||
pub fn new(num: u8, path: &str) -> Result<Multi> {
|
||||
let cpu_path = format!("/sys/hermit/isle{}/path", num);
|
||||
let bin_path= format!("/sys/hermit/isle{}/cpus", num);
|
||||
|
||||
// request a new isle, enforce close
|
||||
{
|
||||
let mut path_file = File::create(format!("/sys/hermit/isle{}/path", num)).map_err(|_| Error::InvalidFile)?;
|
||||
let mut cpus_file = File::create(format!("/sys/hermit/isle{}/cpus", num)).map_err(|_| Error::InvalidFile)?;
|
||||
let mut path_file = File::create(&bin_path)
|
||||
.map_err(|_| Error::InvalidFile(bin_path.clone()))?;
|
||||
|
||||
let mut cpus_file = File::create(&cpu_path)
|
||||
.map_err(|_| Error::InvalidFile(cpu_path.clone()))?;
|
||||
|
||||
let cpus = hermit_env::num_cpus();
|
||||
|
||||
path_file.write_all(path.as_bytes()).map_err(|_| Error::InvalidFile)?;
|
||||
cpus_file.write_all(cpus.as_bytes()).map_err(|_| Error::InvalidFile)?;
|
||||
path_file.write_all(path.as_bytes())
|
||||
.map_err(|_| Error::InvalidFile(cpu_path.clone()))?;
|
||||
|
||||
cpus_file.write_all(cpus.as_bytes())
|
||||
.map_err(|_| Error::InvalidFile(bin_path))?;
|
||||
}
|
||||
|
||||
// check the result
|
||||
let mut path_file = File::create(format!("/sys/hermit/isle{}/cpus", num)).map_err(|_| Error::InvalidFile)?;
|
||||
let mut path_file = File::create(&cpu_path)
|
||||
.map_err(|_| Error::InvalidFile(cpu_path.clone()))?;
|
||||
|
||||
let mut result = String::new();
|
||||
|
||||
path_file.read_to_string(&mut result).map_err(|_| Error::InvalidFile)?;
|
||||
path_file.read_to_string(&mut result)
|
||||
.map_err(|_| Error::InvalidFile(cpu_path.clone()))?;
|
||||
|
||||
if result.parse::<i32>().map_err(|_| Error::InvalidFile)? == -1 {
|
||||
if result.parse::<i32>().map_err(|_| Error::InvalidFile(cpu_path))? == -1 {
|
||||
return Err(Error::MultiIsleFailed);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,60 @@
|
|||
use std::result;
|
||||
use std::{result, fmt};
|
||||
use nix;
|
||||
use errno::errno;
|
||||
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
InternalError,
|
||||
NotEnoughMemory,
|
||||
InvalidFile,
|
||||
FailedIOCTL(nix::Error),
|
||||
InvalidFile(String),
|
||||
IOCTL(NameIOCTL),
|
||||
KernelNotLoaded,
|
||||
MissingFrequency,
|
||||
MultiIsleFailed,
|
||||
CannotCreateTmpFile(usize),
|
||||
QEmu((String, String))
|
||||
|
||||
}
|
||||
|
||||
impl fmt::Debug for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
Error::InternalError => write!(f, "An internal error has occurred, please report."),
|
||||
Error::NotEnoughMemory => write!(f, "The host system has not enough memory, please check your memory usage."),
|
||||
Error::InvalidFile(ref file) => write!(f, "The file {} was not found or is invalid.", file),
|
||||
Error::IOCTL(ref name) => {
|
||||
let e = errno();
|
||||
|
||||
write!(f, "The IOCTL command {:?} has failed: {}", name, e)
|
||||
},
|
||||
Error::KernelNotLoaded => write!(f, "Please load the kernel before your start the virtual machine."),
|
||||
Error::MissingFrequency => write!(f, "Couldn't get the CPU frequency from you system. (is /proc/cpuinfo missing?)"),
|
||||
Error::MultiIsleFailed => write!(f, "The Multi isle was selected on a system without supported, please load the kernel driver."),
|
||||
Error::CannotCreateTmpFile(_) => write!(f, "Couldn't create a tmp file in /tmp."),
|
||||
Error::QEmu((_, ref stderr)) => write!(f, "The qemu binary has encountered an error: {}", stderr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum NameIOCTL {
|
||||
GetVersion,
|
||||
CreateVM,
|
||||
GetMsrIndexList,
|
||||
CheckExtension,
|
||||
GetVCPUMMAPSize,
|
||||
GetSupportedCpuID,
|
||||
SetCpuID2,
|
||||
CreateVcpu,
|
||||
SetMemoryAlias,
|
||||
SetNRMMUPages,
|
||||
GetNRMMUPages,
|
||||
SetMemoryRegion,
|
||||
SetUserMemoryRegion,
|
||||
CreateIRQChip,
|
||||
Run,
|
||||
GetRegs,
|
||||
SetRegs,
|
||||
GetSRegs,
|
||||
SetSRegs
|
||||
}
|
||||
|
|
|
@ -54,7 +54,7 @@ impl IsleKind {
|
|||
_ => File::open(format!("/sys/hermit/isle{}/log", self.get_num()))
|
||||
};
|
||||
|
||||
let mut file = file.map_err(|_| Error::InvalidFile)?;
|
||||
let mut file = file.map_err(|x| Error::InvalidFile(format!("{:?}",x)))?;
|
||||
let mut reader = BufReader::new(file);
|
||||
|
||||
//let mut result = String::new();
|
||||
|
@ -95,11 +95,13 @@ impl IsleKind {
|
|||
}
|
||||
|
||||
pub fn stop(&self) -> Result<()> {
|
||||
let mut cpus_file = File::create(format!("/sys/hermit/isle{}/cpus", self.get_num()))
|
||||
.map_err(|_| Error::InvalidFile)?;
|
||||
let cpu_path = format!("/sys/hermit/isle{}/cpus", self.get_num());
|
||||
|
||||
let mut cpus_file = File::create(&cpu_path)
|
||||
.map_err(|_| Error::InvalidFile(cpu_path.clone()))?;
|
||||
|
||||
cpus_file.write("-1".as_bytes())
|
||||
.map_err(|_| Error::InvalidFile);
|
||||
.map_err(|_| Error::InvalidFile(cpu_path));
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1441,7 +1441,7 @@ impl kvm_cpuid_entry2 {
|
|||
ebx: 0,
|
||||
ecx: 0,
|
||||
edx: 0,
|
||||
padding: [0; 3]
|
||||
padding: [0u32; 3]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1497,19 +1497,19 @@ impl Clone for kvm_cpuid_entry2 {
|
|||
fn clone(&self) -> Self { *self }
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Copy)]
|
||||
#[derive(Debug, Copy)]
|
||||
pub struct kvm_cpuid2 {
|
||||
pub nent: __u32,
|
||||
pub padding: __u32,
|
||||
pub entries: [kvm_cpuid_entry2; 100]
|
||||
pub entries: [kvm_cpuid_entry2; 4]
|
||||
}
|
||||
|
||||
impl kvm_cpuid2 {
|
||||
pub fn empty() -> kvm_cpuid2 {
|
||||
kvm_cpuid2 {
|
||||
nent: 100,
|
||||
nent: 4,
|
||||
padding: 0,
|
||||
entries: [kvm_cpuid_entry2::empty(); 100]
|
||||
entries: [kvm_cpuid_entry2::empty(); 4]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ use std::os::unix::fs::OpenOptionsExt;
|
|||
use std::os::unix::io::AsRawFd;
|
||||
use libc;
|
||||
|
||||
use uhyve::{Error, Result};
|
||||
use uhyve::{Error, Result, NameIOCTL};
|
||||
use uhyve::vm::VirtualMachine;
|
||||
|
||||
/// The normal way of defining a IOCTL interface is provided by C macros. In Rust we have our own
|
||||
|
@ -80,7 +80,7 @@ impl Uhyve {
|
|||
match ioctl::get_version(self.file.as_raw_fd(), ptr::null_mut()) {
|
||||
Ok(12) => Ok(Version::Version12),
|
||||
Ok(_) => Ok(Version::Unsupported),
|
||||
Err(_) => Err(Error::InternalError)
|
||||
Err(_) => Err(Error::IOCTL(NameIOCTL::GetVersion))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@ use errno::errno;
|
|||
|
||||
use uhyve;
|
||||
use uhyve::kvm_header::{kvm_sregs, kvm_regs, kvm_segment, kvm_cpuid2};
|
||||
use uhyve::{Result, Error};
|
||||
use uhyve::{Result, Error, NameIOCTL};
|
||||
use uhyve::gdt;
|
||||
use uhyve::proto;
|
||||
|
||||
|
@ -38,6 +38,7 @@ pub const X86_PDPT_RW: u64 = (1 << 1);
|
|||
pub const X86_PDPT_PS: u64 = (1 << 7);
|
||||
|
||||
pub struct VirtualCPU {
|
||||
kvm_fd: libc::c_int,
|
||||
vm_fd: libc::c_int,
|
||||
pub vcpu_fd: libc::c_int,
|
||||
id: u8,
|
||||
|
@ -62,7 +63,7 @@ impl VirtualCPU {
|
|||
}?;
|
||||
|
||||
let cpu = VirtualCPU {
|
||||
vm_fd: vm_fd, vcpu_fd: fd, id: id, file: file, run_mem: run_mem
|
||||
kvm_fd: kvm_fd, vm_fd: vm_fd, vcpu_fd: fd, id: id, file: file, run_mem: run_mem
|
||||
};
|
||||
|
||||
if id == 0 {
|
||||
|
@ -83,6 +84,8 @@ impl VirtualCPU {
|
|||
|
||||
cpu.set_regs(regs)?;
|
||||
|
||||
debug!("Set the CPUID");
|
||||
|
||||
cpu.setup_cpuid()?;
|
||||
|
||||
Ok(cpu)
|
||||
|
@ -91,7 +94,7 @@ impl VirtualCPU {
|
|||
pub fn create_vcpu(fd: c_int) -> Result<c_int> {
|
||||
unsafe {
|
||||
uhyve::ioctl::create_vcpu(fd, ptr::null_mut())
|
||||
.map_err(|x| Error::FailedIOCTL(x))
|
||||
.map_err(|_| Error::IOCTL(NameIOCTL::CreateVcpu))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -99,7 +102,7 @@ impl VirtualCPU {
|
|||
let mut sregs = kvm_sregs::empty();
|
||||
unsafe {
|
||||
uhyve::ioctl::get_sregs(self.vcpu_fd, (&mut sregs) as *mut kvm_sregs)
|
||||
.map_err(|x| Error::FailedIOCTL(x))?;
|
||||
.map_err(|x| Error::IOCTL(NameIOCTL::GetSRegs))?;
|
||||
}
|
||||
|
||||
Ok(sregs)
|
||||
|
@ -108,7 +111,7 @@ impl VirtualCPU {
|
|||
pub fn set_sregs(&self, mut sregs: kvm_sregs) -> Result<()> {
|
||||
unsafe {
|
||||
uhyve::ioctl::set_sregs(self.vcpu_fd, (&mut sregs) as *mut kvm_sregs)
|
||||
.map_err(|x| Error::FailedIOCTL(x))?;
|
||||
.map_err(|x| Error::IOCTL(NameIOCTL::SetSRegs))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -117,7 +120,7 @@ impl VirtualCPU {
|
|||
pub fn set_regs(&self, mut regs: kvm_regs) -> Result<()> {
|
||||
unsafe {
|
||||
uhyve::ioctl::set_regs(self.vcpu_fd, (&mut regs) as *mut kvm_regs)
|
||||
.map_err(|x| Error::FailedIOCTL(x))?;
|
||||
.map_err(|x| Error::IOCTL(NameIOCTL::SetSRegs))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -125,9 +128,11 @@ impl VirtualCPU {
|
|||
|
||||
pub fn get_supported_cpuid(&self) -> Result<kvm_cpuid2> {
|
||||
let mut cpuid = kvm_cpuid2::empty();
|
||||
debug!("Size {}", mem::size_of::<kvm_cpuid2>());
|
||||
|
||||
unsafe {
|
||||
uhyve::ioctl::get_supported_cpuid(self.vm_fd, (&mut cpuid) as *mut kvm_cpuid2)
|
||||
.map_err(|x| Error::FailedIOCTL(x))?;
|
||||
uhyve::ioctl::get_supported_cpuid(self.kvm_fd, (&mut cpuid) as *mut kvm_cpuid2)
|
||||
.map_err(|x| Error::IOCTL(NameIOCTL::GetSupportedCpuID))?;
|
||||
}
|
||||
|
||||
Ok(cpuid)
|
||||
|
@ -136,7 +141,7 @@ impl VirtualCPU {
|
|||
pub fn set_cpuid2(&self, mut cpuid: kvm_cpuid2) -> Result<()> {
|
||||
unsafe {
|
||||
uhyve::ioctl::set_cpuid2(self.vm_fd, (&mut cpuid) as *mut kvm_cpuid2)
|
||||
.map_err(|x| Error::FailedIOCTL(x))?;
|
||||
.map_err(|x| Error::IOCTL(NameIOCTL::SetCpuID2))?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -145,14 +150,14 @@ impl VirtualCPU {
|
|||
pub fn get_mmap_size(vcpu_fd: libc::c_int) -> Result<usize> {
|
||||
unsafe {
|
||||
uhyve::ioctl::get_vcpu_mmap_size(vcpu_fd, ptr::null_mut())
|
||||
.map_err(|x| Error::FailedIOCTL(x)).map(|x| { debug!("MMAP size {}", x); x as usize })
|
||||
.map_err(|x| Error::IOCTL(NameIOCTL::GetVCPUMMAPSize)).map(|x| { x as usize})
|
||||
}
|
||||
}
|
||||
|
||||
pub fn single_run(&self, guest_mem: &mut [u8]) -> Result<i32> {
|
||||
let ret = unsafe {
|
||||
uhyve::ioctl::run(self.vcpu_fd, ptr::null_mut())
|
||||
.map_err(|x| Error::FailedIOCTL(x))
|
||||
.map_err(|x| Error::IOCTL(NameIOCTL::Run))
|
||||
}?;
|
||||
|
||||
if ret == -1 {
|
||||
|
@ -270,6 +275,8 @@ impl VirtualCPU {
|
|||
pub fn setup_cpuid(&self) -> Result<()> {
|
||||
let mut kvm_cpuid = self.get_supported_cpuid()?;
|
||||
|
||||
debug!("Supported CPUs {:?}", kvm_cpuid);
|
||||
|
||||
for entry in kvm_cpuid.entries.iter_mut() {
|
||||
match entry.function {
|
||||
1 => {
|
||||
|
|
|
@ -12,7 +12,7 @@ use elf::types::{ELFCLASS64, OSABI, PT_LOAD};
|
|||
use utils;
|
||||
use uhyve;
|
||||
use uhyve::kvm_header::{kvm_userspace_memory_region };
|
||||
use uhyve::{Result, Error};
|
||||
use uhyve::{Result, Error, NameIOCTL};
|
||||
use uhyve::vcpu::VirtualCPU;
|
||||
|
||||
//use byteorder::ByteOrder;
|
||||
|
@ -43,17 +43,17 @@ impl VirtualMachine {
|
|||
debug!("UHYVE - Load kernel from {}", path);
|
||||
|
||||
// open the file in read only
|
||||
let file = Mmap::open_path(path, Protection::Read).map_err(|_| Error::InvalidFile)?;
|
||||
let file = Mmap::open_path(path, Protection::Read).map_err(|_| Error::InvalidFile(path.into()))?;
|
||||
|
||||
// parse the header with ELF module
|
||||
let file_efi = {
|
||||
let mut data = unsafe { Cursor::new(file.as_slice()) };
|
||||
|
||||
elf::File::open_stream(&mut data).map_err(|_| Error::InvalidFile)
|
||||
elf::File::open_stream(&mut data).map_err(|_| Error::InvalidFile(path.into()))
|
||||
}?;
|
||||
|
||||
if file_efi.ehdr.class != ELFCLASS64 || file_efi.ehdr.osabi != OSABI(0x42) {
|
||||
return Err(Error::InvalidFile);
|
||||
return Err(Error::InvalidFile(path.into()));
|
||||
}
|
||||
|
||||
self.elf_entry = Some(file_efi.ehdr.entry);
|
||||
|
@ -116,14 +116,14 @@ impl VirtualMachine {
|
|||
pub fn set_user_memory_region(&self, mut region: kvm_userspace_memory_region) -> Result<()> {
|
||||
unsafe {
|
||||
uhyve::ioctl::set_user_memory_region(self.vm_fd, (&mut region) as *mut kvm_userspace_memory_region)
|
||||
.map_err(|x| Error::FailedIOCTL(x)).map(|_| ())
|
||||
.map_err(|x| Error::IOCTL(NameIOCTL::SetUserMemoryRegion)).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn create_irqchip(&self) -> Result<()> {
|
||||
unsafe {
|
||||
uhyve::ioctl::create_irqchip(self.vm_fd, ptr::null_mut())
|
||||
.map_err(|x| Error::FailedIOCTL(x)).map(|_| ())
|
||||
.map_err(|x| Error::IOCTL(NameIOCTL::CreateIRQChip)).map(|_| ())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,7 +57,7 @@ pub fn delete_tmp_file(name: &str) -> Result<()> {
|
|||
let res = libc::unlink(c_str.into_raw());
|
||||
|
||||
if res < 0 {
|
||||
return Err(Error::InvalidFile);
|
||||
return Err(Error::InvalidFile(name.into()));
|
||||
} else {
|
||||
return Ok(());
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue