use crate::{EnhancedChan, VmwError};
pub(crate) const BACKDOOR_MAGIC: u32 = 0x564D5868;
pub(crate) const BACKDOOR_PORT_LB: u32 = 0x5658;
pub(crate) const BACKDOOR_PORT_HB: u32 = 0x5659;
pub(crate) const COMMAND_GET_VERSION: u32 = 0x0A;
pub(crate) const COMMAND_ERPC: u32 = 0x1E;
pub fn access_backdoor_privileged() -> Result<BackdoorGuard, VmwError> {
BackdoorGuard::change_io_access(true)?;
Ok(BackdoorGuard {
release_on_drop: true,
})
}
pub fn access_backdoor() -> Result<BackdoorGuard, VmwError> {
Ok(BackdoorGuard {
release_on_drop: false,
})
}
pub fn probe_backdoor_privileged() -> Result<BackdoorGuard, VmwError> {
BackdoorGuard::change_io_access(true)?;
let mut guard = BackdoorGuard {
release_on_drop: true,
};
guard.probe_vmware_backdoor()?;
Ok(guard)
}
pub fn probe_backdoor() -> Result<BackdoorGuard, VmwError> {
let mut guard = BackdoorGuard {
release_on_drop: false,
};
guard.probe_vmware_backdoor()?;
Ok(guard)
}
#[derive(Debug)]
pub struct BackdoorGuard {
release_on_drop: bool,
}
impl BackdoorGuard {
pub fn probe_vmware_backdoor(&mut self) -> Result<(), VmwError> {
self.get_version().and(Ok(()))
}
pub fn release_access(self) -> Result<(), Self> {
let mut guard = self;
if Self::change_io_access(false).is_err() {
return Err(guard);
}
guard.release_on_drop = false;
drop(guard);
Ok(())
}
pub fn open_enhanced_chan(&mut self) -> Result<EnhancedChan, VmwError> {
EnhancedChan::open(self)
}
pub(crate) fn change_io_access(acquire: bool) -> Result<(), VmwError> {
let level = if acquire { 0b11 } else { 0b00 };
let err = unsafe { libc::iopl(level) };
if err != 0 {
let err_code = errno::errno();
return Err(format!("iopl failed: {} (errno: {})", err_code, err_code.0).into());
};
Ok(())
}
}
impl Drop for BackdoorGuard {
fn drop(&mut self) {
if self.release_on_drop {
if let Err(e) = Self::change_io_access(false) {
log::error!("failed to release backdoor access: {}", e);
}
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_magic_string() {
assert_eq!(BACKDOOR_MAGIC, u32::from_be_bytes(*b"VMXh"));
}
}