From de3e8e1a6ecabd2e23c72d0ada6335046e611baf Mon Sep 17 00:00:00 2001 From: Dan Robertson Date: Fri, 30 Apr 2021 19:20:29 +0000 Subject: [PATCH] vioapic: add vioapic support --- mythril/src/virtdev/hpet.rs | 29 +++++++++ mythril/src/virtdev/ioapic.rs | 114 +++++++++++++++++++++++++++++----- 2 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 mythril/src/virtdev/hpet.rs diff --git a/mythril/src/virtdev/hpet.rs b/mythril/src/virtdev/hpet.rs new file mode 100644 index 0000000..06da420 --- /dev/null +++ b/mythril/src/virtdev/hpet.rs @@ -0,0 +1,29 @@ +use crate::error::Result; +use crate::memory::GuestPhysAddr; +use crate::virtdev::{DeviceRegion, EmulatedDevice, Event}; +use alloc::sync::Arc; +use alloc::vec::Vec; +use spin::RwLock; + +#[derive(Default)] +pub struct Hpet; + +impl Hpet { + pub fn new() -> Arc> { + Arc::new(RwLock::new(Hpet {})) + } +} + +impl EmulatedDevice for Hpet { + fn services(&self) -> Vec { + vec![ + DeviceRegion::MemIo( + GuestPhysAddr::new(0xfed00000)..=GuestPhysAddr::new(0xfed010f0), + ), + ] + } + + fn on_event(&mut self, _event: Event) -> Result<()> { + Ok(()) + } +} diff --git a/mythril/src/virtdev/ioapic.rs b/mythril/src/virtdev/ioapic.rs index 3c7d8c4..350bb8d 100644 --- a/mythril/src/virtdev/ioapic.rs +++ b/mythril/src/virtdev/ioapic.rs @@ -1,31 +1,115 @@ -use crate::error::Result; +use crate::error::{Error, Result}; use crate::memory::GuestPhysAddr; -use crate::virtdev::{DeviceRegion, EmulatedDevice, Event}; +use crate::virtdev::{DeviceEvent, DeviceRegion}; +use crate::virtdev::{EmulatedDevice, Event}; +use crate::virtdev::{MemReadRequest, MemWriteRequest}; use alloc::vec::Vec; +use byteorder::{ByteOrder, NativeEndian}; + +#[derive(Debug)] +enum Request<'a> { + Read(u8, MemReadRequest<'a>), + Write(u8, MemWriteRequest<'a>), +} + +#[derive(Clone, Copy, Debug)] +enum RequestState { + Pending, + RegSel(u8), +} + +impl RequestState { + fn reset(&mut self) { + *self = RequestState::Pending; + } +} + +impl Default for RequestState { + fn default() -> RequestState { + RequestState::Pending + } +} + #[derive(Default)] -pub struct IoApic; +pub struct IoApic { + state: RequestState, + version: u32, +} impl IoApic { pub fn new() -> Result { - Ok(IoApic {}) + Ok(IoApic { + state: RequestState::Pending, + version: 0x11, + }) } } impl EmulatedDevice for IoApic { fn services(&self) -> Vec { - vec![ - DeviceRegion::MemIo( - GuestPhysAddr::new(0xfec00000)..=GuestPhysAddr::new(0xfec010f0), - ), - //FIXME: this is actually the 1st HPET - DeviceRegion::MemIo( - GuestPhysAddr::new(0xfed00000)..=GuestPhysAddr::new(0xfed010f0), - ), - ] + vec![DeviceRegion::MemIo( + GuestPhysAddr::new(0xfec00000)..=GuestPhysAddr::new(0xfec010f0), + )] } - fn on_event(&mut self, _event: Event) -> Result<()> { - Ok(()) + fn on_event<'a>(&mut self, event: Event) -> Result<()> { + // Parse the event into a register request based on the address given, + // input, and the current request state. + let mut req = match self.state { + RequestState::Pending => match event.kind { + DeviceEvent::MemWrite(addr, val) + if addr.as_u64() == 0xfec00000 => + { + if val.as_slice().len() != 4 { + Err(Error::NotSupported) + } else { + let reg = NativeEndian::read_u32(val.as_slice()); + self.state = RequestState::RegSel(reg as u8); + return Ok(()); + } + } + _ => Err(Error::NotSupported), + }, + RequestState::RegSel(reg) => match event.kind { + DeviceEvent::MemWrite(addr, val) + if addr.as_u64() == 0xfec00010 => + { + if val.as_slice().len() != 4 { + Err(Error::NotSupported) + } else { + self.state.reset(); + Ok(Request::Write(reg, val)) + } + } + DeviceEvent::MemRead(addr, val) + if addr.as_u64() == 0xfec00010 => + { + if val.as_slice().len() != 4 { + Err(Error::NotSupported) + } else { + self.state.reset(); + Ok(Request::Read(reg, val)) + } + } + _ => Err(Error::NotSupported), + }, + }?; + + info!("I/O APIC Request {:?}", req); + match req { + Request::Read(0, ref mut data) => { + NativeEndian::write_u32(data.as_mut_slice(), self.version); + Ok(()) + } + Request::Write(0, ref data) => { + self.version = NativeEndian::read_u32(data.as_slice()); + Ok(()) + } + _ => { + info!("I/O APIC Unsupported Request: {:?}", req); + Err(Error::NotSupported) + } + } } }