diff --git a/tools/hermit_proxy/src/dedicate/multi.rs b/tools/hermit_proxy/src/dedicate/multi.rs index 2da510a09..3701c0d85 100644 --- a/tools/hermit_proxy/src/dedicate/multi.rs +++ b/tools/hermit_proxy/src/dedicate/multi.rs @@ -14,24 +14,36 @@ pub struct Multi { impl Multi { pub fn new(num: u8, path: &str) -> Result { + 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::().map_err(|_| Error::InvalidFile)? == -1 { + if result.parse::().map_err(|_| Error::InvalidFile(cpu_path))? == -1 { return Err(Error::MultiIsleFailed); } diff --git a/tools/hermit_proxy/src/error.rs b/tools/hermit_proxy/src/error.rs index b0b118005..54406990e 100644 --- a/tools/hermit_proxy/src/error.rs +++ b/tools/hermit_proxy/src/error.rs @@ -1,18 +1,60 @@ -use std::result; +use std::{result, fmt}; use nix; +use errno::errno; pub type Result = result::Result; -#[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 } diff --git a/tools/hermit_proxy/src/hermit.rs b/tools/hermit_proxy/src/hermit.rs index 4e7c8ec44..d6aed5856 100644 --- a/tools/hermit_proxy/src/hermit.rs +++ b/tools/hermit_proxy/src/hermit.rs @@ -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(()) } diff --git a/tools/hermit_proxy/src/uhyve/kvm_header.rs b/tools/hermit_proxy/src/uhyve/kvm_header.rs index e52e5def1..c7c5da8b2 100644 --- a/tools/hermit_proxy/src/uhyve/kvm_header.rs +++ b/tools/hermit_proxy/src/uhyve/kvm_header.rs @@ -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] } } } diff --git a/tools/hermit_proxy/src/uhyve/uhyve.rs b/tools/hermit_proxy/src/uhyve/uhyve.rs index fa665fff4..00acb2bf5 100644 --- a/tools/hermit_proxy/src/uhyve/uhyve.rs +++ b/tools/hermit_proxy/src/uhyve/uhyve.rs @@ -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)) } } } diff --git a/tools/hermit_proxy/src/uhyve/vcpu.rs b/tools/hermit_proxy/src/uhyve/vcpu.rs index 7687df0fb..a87e125e9 100644 --- a/tools/hermit_proxy/src/uhyve/vcpu.rs +++ b/tools/hermit_proxy/src/uhyve/vcpu.rs @@ -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 { 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 { let mut cpuid = kvm_cpuid2::empty(); + debug!("Size {}", mem::size_of::()); + 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 { 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 { 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 => { diff --git a/tools/hermit_proxy/src/uhyve/vm.rs b/tools/hermit_proxy/src/uhyve/vm.rs index 6e0e23808..998bdf302 100644 --- a/tools/hermit_proxy/src/uhyve/vm.rs +++ b/tools/hermit_proxy/src/uhyve/vm.rs @@ -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(|_| ()) } } diff --git a/tools/hermit_proxy/src/utils.rs b/tools/hermit_proxy/src/utils.rs index fa8dfc683..e4c16adb6 100644 --- a/tools/hermit_proxy/src/utils.rs +++ b/tools/hermit_proxy/src/utils.rs @@ -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(()); }