diff --git a/mythril/src/kmain.rs b/mythril/src/kmain.rs index 4482591..c6ffe66 100644 --- a/mythril/src/kmain.rs +++ b/mythril/src/kmain.rs @@ -83,45 +83,45 @@ fn build_vm( acpi.add_sdt(madt).unwrap(); - let device_map = config.virtual_devices_mut(); + let mut builder = config.device_map_builder(); - device_map + builder .register_device(virtdev::acpi::AcpiRuntime::new(0x600).unwrap()) .unwrap(); - device_map + builder .register_device(virtdev::debug::DebugPort::new(0x402)) .unwrap(); - device_map + builder .register_device(virtdev::com::Uart8250::new(0x3F8)) .unwrap(); - device_map + builder .register_device(virtdev::vga::VgaController::new()) .unwrap(); - device_map + builder .register_device(virtdev::dma::Dma8237::new()) .unwrap(); - device_map + builder .register_device(virtdev::ignore::IgnoredDevice::new()) .unwrap(); - device_map + builder .register_device(virtdev::pci::PciRootComplex::new()) .unwrap(); - device_map + builder .register_device(virtdev::pic::Pic8259::new()) .unwrap(); - device_map + builder .register_device(virtdev::keyboard::Keyboard8042::new()) .unwrap(); - device_map + builder .register_device(virtdev::pit::Pit8254::new()) .unwrap(); - device_map + builder .register_device(virtdev::pos::ProgrammableOptionSelect::new()) .unwrap(); - device_map + builder .register_device(virtdev::rtc::CmosRtc::new(cfg.memory)) .unwrap(); - device_map + builder .register_device(virtdev::ioapic::IoApic::new()) .unwrap(); @@ -155,7 +155,7 @@ fn build_vm( ) .unwrap(); - device_map.register_device(fw_cfg_builder.build()).unwrap(); + builder.register_device(fw_cfg_builder.build()).unwrap(); vm::VirtualMachine::new(vm_id, config, info).expect("Failed to create vm") } diff --git a/mythril/src/virtdev/acpi.rs b/mythril/src/virtdev/acpi.rs index d0dc188..e9a3334 100644 --- a/mythril/src/virtdev/acpi.rs +++ b/mythril/src/virtdev/acpi.rs @@ -1,6 +1,6 @@ -use crate::error::Result; use crate::time; use crate::virtdev::{DeviceEvent, DeviceRegion, EmulatedDevice, Event, Port}; +use crate::{error::Result, vm::VirtualMachineConfig}; use alloc::sync::Arc; use alloc::vec::Vec; use spin::RwLock; @@ -42,7 +42,7 @@ impl AcpiRuntime { } impl EmulatedDevice for AcpiRuntime { - fn services(&self) -> Vec { + fn services(&self, _vm_config: &VirtualMachineConfig) -> Vec { vec![ DeviceRegion::PortIo( Self::FADT_SMI_COMMAND..=Self::FADT_SMI_COMMAND, diff --git a/mythril/src/virtdev/com.rs b/mythril/src/virtdev/com.rs index 6d7162a..cb3a6ff 100644 --- a/mythril/src/virtdev/com.rs +++ b/mythril/src/virtdev/com.rs @@ -4,6 +4,7 @@ use crate::physdev::com::*; use crate::virtdev::{ DeviceEvent, DeviceEventResponse, DeviceRegion, EmulatedDevice, Event, Port, }; +use crate::vm::VirtualMachineConfig; use alloc::sync::Arc; use alloc::vec::Vec; use core::convert::TryInto; @@ -54,7 +55,7 @@ impl Uart8250 { } impl EmulatedDevice for Uart8250 { - fn services(&self) -> Vec { + fn services(&self, _vm_config: &VirtualMachineConfig) -> Vec { vec![DeviceRegion::PortIo(self.base_port..=self.base_port + 7)] } diff --git a/mythril/src/virtdev/debug.rs b/mythril/src/virtdev/debug.rs index f6443a4..dd1786c 100644 --- a/mythril/src/virtdev/debug.rs +++ b/mythril/src/virtdev/debug.rs @@ -1,7 +1,7 @@ -use crate::error::Result; use crate::virtdev::{ DeviceEvent, DeviceEventResponse, DeviceRegion, EmulatedDevice, Event, Port, }; +use crate::{error::Result, vm::VirtualMachineConfig}; use alloc::sync::Arc; use alloc::vec::Vec; use core::convert::TryInto; @@ -18,7 +18,7 @@ impl DebugPort { } impl EmulatedDevice for DebugPort { - fn services(&self) -> Vec { + fn services(&self, _vm_config: &VirtualMachineConfig) -> Vec { vec![DeviceRegion::PortIo(self.port..=self.port)] } diff --git a/mythril/src/virtdev/dma.rs b/mythril/src/virtdev/dma.rs index 12ad61b..7ff91b6 100644 --- a/mythril/src/virtdev/dma.rs +++ b/mythril/src/virtdev/dma.rs @@ -1,5 +1,5 @@ -use crate::error::Result; use crate::virtdev::{DeviceRegion, EmulatedDevice, Event, Port}; +use crate::{error::Result, vm::VirtualMachineConfig}; use alloc::sync::Arc; use alloc::vec::Vec; use spin::RwLock; @@ -31,7 +31,7 @@ impl Dma8237 { } impl EmulatedDevice for Dma8237 { - fn services(&self) -> Vec { + fn services(&self, _vm_config: &VirtualMachineConfig) -> Vec { vec![ DeviceRegion::PortIo( Self::DMA1_CHAN2_ADDR..=Self::DMA1_MASTER_CLEAR, diff --git a/mythril/src/virtdev/ignore.rs b/mythril/src/virtdev/ignore.rs index c32c42f..cc93fca 100644 --- a/mythril/src/virtdev/ignore.rs +++ b/mythril/src/virtdev/ignore.rs @@ -1,5 +1,5 @@ -use crate::error::Result; use crate::virtdev::{DeviceRegion, EmulatedDevice, Event}; +use crate::{error::Result, vm::VirtualMachineConfig}; use alloc::sync::Arc; use alloc::vec::Vec; use spin::RwLock; @@ -17,7 +17,7 @@ impl IgnoredDevice { } impl EmulatedDevice for IgnoredDevice { - fn services(&self) -> Vec { + fn services(&self, _vm_config: &VirtualMachineConfig) -> Vec { vec![ // Ignore #IGNNE stuff DeviceRegion::PortIo(241..=241), diff --git a/mythril/src/virtdev/ioapic.rs b/mythril/src/virtdev/ioapic.rs index 83b3341..b61e6c5 100644 --- a/mythril/src/virtdev/ioapic.rs +++ b/mythril/src/virtdev/ioapic.rs @@ -1,6 +1,6 @@ -use crate::error::Result; use crate::memory::GuestPhysAddr; use crate::virtdev::{DeviceRegion, EmulatedDevice, Event}; +use crate::{error::Result, vm::VirtualMachineConfig}; use alloc::sync::Arc; use alloc::vec::Vec; use spin::RwLock; @@ -15,7 +15,7 @@ impl IoApic { } impl EmulatedDevice for IoApic { - fn services(&self) -> Vec { + fn services(&self, _vm_config: &VirtualMachineConfig) -> Vec { vec![ DeviceRegion::MemIo( GuestPhysAddr::new(0xfec00000)..=GuestPhysAddr::new(0xfec010f0), diff --git a/mythril/src/virtdev/keyboard.rs b/mythril/src/virtdev/keyboard.rs index 1b2e986..2a99f6a 100644 --- a/mythril/src/virtdev/keyboard.rs +++ b/mythril/src/virtdev/keyboard.rs @@ -1,5 +1,5 @@ -use crate::error::Result; use crate::virtdev::{DeviceEvent, DeviceRegion, EmulatedDevice, Event, Port}; +use crate::{error::Result, vm::VirtualMachineConfig}; use alloc::sync::Arc; use alloc::vec::Vec; use spin::RwLock; @@ -17,7 +17,7 @@ impl Keyboard8042 { } impl EmulatedDevice for Keyboard8042 { - fn services(&self) -> Vec { + fn services(&self, _vm_config: &VirtualMachineConfig) -> Vec { vec![ DeviceRegion::PortIo(Self::PS2_DATA..=Self::PS2_DATA), DeviceRegion::PortIo(Self::PS2_STATUS..=Self::PS2_STATUS), diff --git a/mythril/src/virtdev/mod.rs b/mythril/src/virtdev/mod.rs index 42a3bfc..a82e0cb 100644 --- a/mythril/src/virtdev/mod.rs +++ b/mythril/src/virtdev/mod.rs @@ -1,5 +1,6 @@ use crate::error::{Error, Result}; use crate::memory::{GuestAddressSpaceView, GuestPhysAddr}; +use crate::vm::VirtualMachineConfig; use alloc::collections::btree_map::BTreeMap; use alloc::sync::Arc; use alloc::vec::Vec; @@ -159,6 +160,22 @@ impl DeviceInteraction for GuestPhysAddr { } } +pub struct DeviceMapBuilder<'config> { + pub vm_config: &'config mut VirtualMachineConfig, +} + +impl<'config> DeviceMapBuilder<'config> { + pub fn register_device( + &mut self, + dev: Arc>, + ) -> Result<()> { + let services = dev.read().services(&self.vm_config); + self.vm_config + .virtual_devices_mut() + .register_services(services, dev) + } +} + /// A structure for looking up `EmulatedDevice`s by port or address #[derive(Default)] pub struct DeviceMap { @@ -175,11 +192,11 @@ impl DeviceMap { op.find_device(self) } - pub fn register_device( + pub fn register_services( &mut self, + services: Vec, dev: Arc>, ) -> Result<()> { - let services = dev.read().services(); for region in services.into_iter() { match region { DeviceRegion::PortIo(val) => { @@ -220,7 +237,7 @@ impl DeviceMap { } pub trait EmulatedDevice: Send + Sync { - fn services(&self) -> Vec; + fn services(&self, vm_config: &VirtualMachineConfig) -> Vec; fn on_event(&mut self, _event: Event) -> Result<()> { Ok(()) @@ -483,7 +500,8 @@ impl<'a> fmt::Display for MemReadRequest<'a> { #[cfg(test)] mod test { use super::*; - use crate::virtdev::com::*; + use crate::percore::CoreId; + use crate::{virtdev::com::*, vm::PhysicalDeviceConfig}; use core::convert::TryInto; // This is just a dummy device so we can have arbitrary port ranges @@ -500,8 +518,18 @@ mod test { } } + // Default config used for testing + pub fn get_test_config() -> VirtualMachineConfig { + let cpus = [CoreId::from(0)]; + VirtualMachineConfig::new(&cpus, 1024, PhysicalDeviceConfig::default()) + .expect("Couldn't create a test VirtualMachineConfig") + } + impl EmulatedDevice for DummyDevice { - fn services(&self) -> Vec { + fn services( + &self, + _vm_config: &VirtualMachineConfig, + ) -> Vec { self.services .iter() .map(|x| DeviceRegion::PortIo(x.clone())) @@ -511,9 +539,13 @@ mod test { #[test] fn test_device_map() { - let mut map = DeviceMap::default(); + let mut config = get_test_config(); + + let mut builder = config.device_map_builder(); let com = Uart8250::new(0); - map.register_device(com).unwrap(); + builder.register_device(com).unwrap(); + + let map = config.virtual_devices(); let _dev = map.find_device(0u16).unwrap(); assert_eq!(map.find_device(10u16).is_none(), true); @@ -547,12 +579,14 @@ mod test { #[test] fn test_conflicting_portio_device() { - let mut map = DeviceMap::default(); + let mut config = get_test_config(); + + let mut builder = config.device_map_builder(); let com = Uart8250::new(0); - map.register_device(com).unwrap(); + builder.register_device(com).unwrap(); let com = Uart8250::new(0); - assert!(map.register_device(com).is_err()); + assert!(builder.register_device(com).is_err()); } #[test] @@ -560,9 +594,11 @@ mod test { // region 2 fully inside region 1 let services = vec![0..=10, 2..=8]; let dummy = DummyDevice::new(services); - let mut map = DeviceMap::default(); + let mut config = get_test_config(); - assert!(map.register_device(dummy).is_err()); + let mut builder = config.device_map_builder(); + + assert!(builder.register_device(dummy).is_err()); } #[test] @@ -570,9 +606,11 @@ mod test { // region 1 fully inside region 2 let services = vec![2..=8, 0..=10]; let dummy = DummyDevice::new(services); - let mut map = DeviceMap::default(); + let mut config = get_test_config(); + + let mut builder = config.device_map_builder(); - assert!(map.register_device(dummy).is_err()); + assert!(builder.register_device(dummy).is_err()); } #[test] @@ -581,9 +619,11 @@ mod test { // the start of region 2 let services = vec![0..=4, 3..=8]; let dummy = DummyDevice::new(services); - let mut map = DeviceMap::default(); + let mut config = get_test_config(); + + let mut builder = config.device_map_builder(); - assert!(map.register_device(dummy).is_err()); + assert!(builder.register_device(dummy).is_err()); } #[test] @@ -592,9 +632,11 @@ mod test { // the tail of region 2 let services = vec![3..=8, 0..=4]; let dummy = DummyDevice::new(services); - let mut map = DeviceMap::default(); + let mut config = get_test_config(); - assert!(map.register_device(dummy).is_err()); + let mut builder = config.device_map_builder(); + + assert!(builder.register_device(dummy).is_err()); } #[test] @@ -602,8 +644,10 @@ mod test { // region 1 and region 2 don't overlap let services = vec![0..=3, 4..=8]; let dummy = DummyDevice::new(services); - let mut map = DeviceMap::default(); + let mut config = get_test_config(); + + let mut builder = config.device_map_builder(); - assert!(map.register_device(dummy).is_ok()); + assert!(builder.register_device(dummy).is_ok()); } } diff --git a/mythril/src/virtdev/pci.rs b/mythril/src/virtdev/pci.rs index 855c211..355caee 100644 --- a/mythril/src/virtdev/pci.rs +++ b/mythril/src/virtdev/pci.rs @@ -1,5 +1,8 @@ -use crate::error::{Error, Result}; use crate::virtdev::{DeviceEvent, DeviceRegion, EmulatedDevice, Event, Port}; +use crate::{ + error::{Error, Result}, + vm::VirtualMachineConfig, +}; use alloc::collections::btree_map::BTreeMap; use alloc::sync::Arc; use alloc::vec::Vec; @@ -189,7 +192,7 @@ impl PciRootComplex { } impl EmulatedDevice for PciRootComplex { - fn services(&self) -> Vec { + fn services(&self, _vm_config: &VirtualMachineConfig) -> Vec { vec![ DeviceRegion::PortIo( Self::PCI_CONFIG_ADDRESS..=Self::PCI_CONFIG_ADDRESS, diff --git a/mythril/src/virtdev/pic.rs b/mythril/src/virtdev/pic.rs index d016a51..4c17774 100644 --- a/mythril/src/virtdev/pic.rs +++ b/mythril/src/virtdev/pic.rs @@ -1,5 +1,5 @@ -use crate::error::Result; use crate::virtdev::{DeviceEvent, DeviceRegion, EmulatedDevice, Event, Port}; +use crate::{error::Result, vm::VirtualMachineConfig}; use alloc::sync::Arc; use alloc::vec::Vec; use core::convert::TryInto; @@ -30,7 +30,7 @@ impl Pic8259 { } impl EmulatedDevice for Pic8259 { - fn services(&self) -> Vec { + fn services(&self, _vm_config: &VirtualMachineConfig) -> Vec { vec![ DeviceRegion::PortIo( Self::PIC_MASTER_COMMAND..=Self::PIC_MASTER_DATA, diff --git a/mythril/src/virtdev/pit.rs b/mythril/src/virtdev/pit.rs index c517fb8..e27794f 100644 --- a/mythril/src/virtdev/pit.rs +++ b/mythril/src/virtdev/pit.rs @@ -6,6 +6,7 @@ use crate::virtdev::{ DeviceEvent, DeviceRegion, EmulatedDevice, Event, Port, PortReadRequest, PortWriteRequest, }; +use crate::vm::VirtualMachineConfig; use alloc::sync::Arc; use alloc::vec::Vec; @@ -264,7 +265,7 @@ impl Pit8254 { } impl EmulatedDevice for Pit8254 { - fn services(&self) -> Vec { + fn services(&self, _vm_config: &VirtualMachineConfig) -> Vec { vec![ DeviceRegion::PortIo(PIT_COUNTER_0..=PIT_MODE_CONTROL), DeviceRegion::PortIo(PIT_PS2_CTRL_B..=PIT_PS2_CTRL_B), diff --git a/mythril/src/virtdev/pos.rs b/mythril/src/virtdev/pos.rs index f1a99ef..045ef72 100644 --- a/mythril/src/virtdev/pos.rs +++ b/mythril/src/virtdev/pos.rs @@ -1,5 +1,5 @@ -use crate::error::Result; use crate::virtdev::{DeviceEvent, DeviceRegion, EmulatedDevice, Event, Port}; +use crate::{error::Result, vm::VirtualMachineConfig}; use alloc::sync::Arc; use alloc::vec::Vec; use spin::RwLock; @@ -24,7 +24,7 @@ impl ProgrammableOptionSelect { // Currently we don't actually implement any of this, but I don't think we // need to either (kvm doesn't seem to) impl EmulatedDevice for ProgrammableOptionSelect { - fn services(&self) -> Vec { + fn services(&self, _vm_config: &VirtualMachineConfig) -> Vec { vec![DeviceRegion::PortIo( Self::POS_ARBITRATION_CLOCK..=Self::POS_ADAPTER_ENABLE_SETUP, )] diff --git a/mythril/src/virtdev/qemu_fw_cfg.rs b/mythril/src/virtdev/qemu_fw_cfg.rs index d505f47..86581b3 100644 --- a/mythril/src/virtdev/qemu_fw_cfg.rs +++ b/mythril/src/virtdev/qemu_fw_cfg.rs @@ -1,4 +1,3 @@ -use crate::error::{Error, Result}; use crate::memory::{ GuestAccess, GuestAddressSpaceView, GuestPhysAddr, GuestVirtAddr, PrivilegeLevel, @@ -7,6 +6,10 @@ use crate::virtdev::{ DeviceEvent, DeviceRegion, EmulatedDevice, Event, Port, PortReadRequest, PortWriteRequest, }; +use crate::{ + error::{Error, Result}, + vm::VirtualMachineConfig, +}; use alloc::collections::BTreeMap; use alloc::sync::Arc; use alloc::vec::Vec; @@ -388,7 +391,7 @@ impl QemuFwCfg { } impl EmulatedDevice for QemuFwCfg { - fn services(&self) -> Vec { + fn services(&self, _vm_config: &VirtualMachineConfig) -> Vec { vec![ DeviceRegion::PortIo( Self::FW_CFG_PORT_SEL..=Self::FW_CFG_PORT_DATA, diff --git a/mythril/src/virtdev/rtc.rs b/mythril/src/virtdev/rtc.rs index d89cacb..f5c6203 100644 --- a/mythril/src/virtdev/rtc.rs +++ b/mythril/src/virtdev/rtc.rs @@ -1,8 +1,8 @@ -use crate::error::Result; use crate::virtdev::{ DeviceEvent, DeviceRegion, EmulatedDevice, Event, Port, PortReadRequest, PortWriteRequest, }; +use crate::{error::Result, vm::VirtualMachineConfig}; use alloc::sync::Arc; use alloc::vec::Vec; use core::convert::{TryFrom, TryInto}; @@ -167,7 +167,7 @@ impl CmosRtc { //TODO: support the NMI masking stuff impl EmulatedDevice for CmosRtc { - fn services(&self) -> Vec { + fn services(&self, _vm_config: &VirtualMachineConfig) -> Vec { vec![DeviceRegion::PortIo(Self::RTC_ADDRESS..=Self::RTC_DATA)] } diff --git a/mythril/src/virtdev/vga.rs b/mythril/src/virtdev/vga.rs index 39f6c12..5cbeb11 100644 --- a/mythril/src/virtdev/vga.rs +++ b/mythril/src/virtdev/vga.rs @@ -1,8 +1,11 @@ -use crate::error::{Error, Result}; use crate::virtdev::{ DeviceEvent, DeviceRegion, EmulatedDevice, Event, Port, PortReadRequest, PortWriteRequest, }; +use crate::{ + error::{Error, Result}, + vm::VirtualMachineConfig, +}; use alloc::sync::Arc; use alloc::vec::Vec; use core::convert::{TryFrom, TryInto}; @@ -128,7 +131,7 @@ impl VgaController { } impl EmulatedDevice for VgaController { - fn services(&self) -> Vec { + fn services(&self, _vm_config: &VirtualMachineConfig) -> Vec { vec![ // vga stuff DeviceRegion::PortIo(Self::VGA_INDEX..=Self::VGA_DATA), diff --git a/mythril/src/vm.rs b/mythril/src/vm.rs index d3619da..3e01f0a 100644 --- a/mythril/src/vm.rs +++ b/mythril/src/vm.rs @@ -13,6 +13,7 @@ use crate::percore; use crate::physdev; use crate::time; use crate::vcpu; +use crate::virtdev::DeviceMapBuilder; use crate::virtdev::{ self, DeviceEvent, DeviceInteraction, DeviceMap, Event, ResponseEventArray, }; @@ -349,7 +350,12 @@ impl VirtualMachineConfig { &mut self.virtual_devices } - /// Access the configurations physical hardware + /// Creates a DeviceMapBuilder based on this config + pub fn device_map_builder(&mut self) -> DeviceMapBuilder<'_> { + DeviceMapBuilder { vm_config: self } + } + + /// Access the physical_devices `PhysicalDeviceConfig` attribute pub fn physical_devices(&self) -> &PhysicalDeviceConfig { &self.physical_devices }