Skip to content

Commit

Permalink
add port io support
Browse files Browse the repository at this point in the history
  • Loading branch information
aarkegz committed Dec 4, 2024
1 parent 51bf078 commit 65fecf9
Show file tree
Hide file tree
Showing 2 changed files with 97 additions and 18 deletions.
4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ serde = { version = "1.0.204", default-features = false, features = ["derive", "
# System independent crates provided by ArceOS.
axerrno = "0.1.0"
memory_addr = "0.3"
axaddrspace = { git = "https://github.com/arceos-hypervisor/axaddrspace.git" }
axdevice_base = { git = "https://github.com/arceos-hypervisor/axdevice_crates.git"}
axaddrspace = { git = "https://github.com/arceos-hypervisor/axaddrspace.git", branch = "inject_interrupt" }
axdevice_base = { git = "https://github.com/arceos-hypervisor/axdevice_crates.git", branch = "inject_interrupt" }
111 changes: 95 additions & 16 deletions src/device.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,32 +3,58 @@ use crate::AxVmDeviceConfig;
use alloc::sync::Arc;
use alloc::vec::Vec;

use axaddrspace::GuestPhysAddr;
use axdevice_base::EmulatedDeviceConfig;
use axdevice_base::{BaseDeviceOps, EmuDeviceType};
use axaddrspace::{device::{DeviceAddrRange, Port, PortRange, SysRegAddr, SysRegAddrRange}, GuestPhysAddr, GuestPhysAddrRange};
use axdevice_base::{BaseDeviceOps, BaseMmioDeviceOps, BasePortDeviceOps, BaseSysRegDeviceOps, EmuDeviceType, EmulatedDeviceConfig, VCpuInfo};
use axerrno::AxResult;

pub struct AxEmuDevices<R: DeviceAddrRange, U: VCpuInfo> {
emu_devices: Vec<Arc<dyn BaseDeviceOps<R, U>>>,
}

impl<R: DeviceAddrRange, U: VCpuInfo> AxEmuDevices<R, U> {
pub fn new() -> Self {
Self {
emu_devices: Vec::new(),
}
}

pub fn find_dev(&self, addr: R::Addr) -> Option<Arc<dyn BaseDeviceOps<R, U>>> {
self.emu_devices
.iter()
.find(|&dev| dev.address_range().contains(addr))
.cloned()
}
}

type AxEmuMmioDevices<U> = AxEmuDevices<GuestPhysAddrRange, U>;
type AxEmuSysRegDevices<U> = AxEmuDevices<SysRegAddrRange, U>;
type AxEmuPortDevices<U> = AxEmuDevices<PortRange, U>;

/// represent A vm own devices
pub struct AxVmDevices {
pub struct AxVmDevices<U: VCpuInfo> {
/// emu devices
emu_devices: Vec<Arc<dyn BaseDeviceOps>>,
emu_mmio_devices: AxEmuMmioDevices<U>,
emu_sysreg_devices: AxEmuSysRegDevices<U>,
emu_port_devices: AxEmuPortDevices<U>,
// TODO passthrough devices or other type devices ...
}

/// The implemention for AxVmDevices
impl AxVmDevices {
impl<U: VCpuInfo> AxVmDevices<U> {
/// According AxVmDeviceConfig to init the AxVmDevices
pub fn new(config: AxVmDeviceConfig) -> Self {
let mut this = Self {
emu_devices: Vec::new(),
emu_mmio_devices: AxEmuMmioDevices::new(),
emu_sysreg_devices: AxEmuSysRegDevices::new(),
emu_port_devices: AxEmuPortDevices::new(),
};

Self::init(&mut this, &config.emu_configs);
this
}

/// According the emu_configs to init every specific device
fn init(this: &mut Self, emu_configs: &Vec<EmulatedDeviceConfig>) {
fn init(_this: &mut Self, _emu_configs: &Vec<EmulatedDeviceConfig>) {
/*
for config in emu_configs {
let dev = match EmuDeviceType::from_usize(config.emu_type) {
Expand All @@ -53,17 +79,24 @@ impl AxVmDevices {
*/
}

/// Find specific device by ipa
pub fn find_dev(&self, ipa: GuestPhysAddr) -> Option<Arc<dyn BaseDeviceOps>> {
self.emu_devices
.iter()
.find(|&dev| dev.address_range().contains(ipa))
.cloned()
/// Find specific MMIO device by ipa
pub fn find_mmio_dev(&self, ipa: GuestPhysAddr) -> Option<Arc<dyn BaseMmioDeviceOps<U>>> {
self.emu_mmio_devices.find_dev(ipa)
}

/// Find specific system register device by ipa
pub fn find_sysreg_dev(&self, sysreg_addr: SysRegAddr) -> Option<Arc<dyn BaseSysRegDeviceOps<U>>> {
self.emu_sysreg_devices.find_dev(sysreg_addr)
}

/// Find specific port device by port number
pub fn find_port_dev(&self, port: Port) -> Option<Arc<dyn BasePortDeviceOps<U>>> {
self.emu_port_devices.find_dev(port)
}

/// Handle the MMIO read by GuestPhysAddr and data width, return the value of the guest want to read
pub fn handle_mmio_read(&self, addr: GuestPhysAddr, width: usize) -> AxResult<usize> {
if let Some(emu_dev) = self.find_dev(addr) {
if let Some(emu_dev) = self.find_mmio_dev(addr) {
info!(
"emu: {:?} handler read ipa {:#x}",
emu_dev.address_range(),
Expand All @@ -76,7 +109,7 @@ impl AxVmDevices {

/// Handle the MMIO write by GuestPhysAddr, data width and the value need to write, call specific device to write the value
pub fn handle_mmio_write(&self, addr: GuestPhysAddr, width: usize, val: usize) {
if let Some(emu_dev) = self.find_dev(addr) {
if let Some(emu_dev) = self.find_mmio_dev(addr) {
info!(
"emu: {:?} handler write ipa {:#x}",
emu_dev.address_range(),
Expand All @@ -90,4 +123,50 @@ impl AxVmDevices {
addr
);
}

/// Handle the system register read by SysRegAddr and data width, return the value of the guest want to read
pub fn handle_sysreg_read(&self, addr: SysRegAddr, width: usize) -> AxResult<usize> {
if let Some(emu_dev) = self.find_sysreg_dev(addr) {
info!(
"emu: {:?} handler read sysreg {:#x}",
emu_dev.address_range(),
addr.0
);
return emu_dev.handle_read(addr, width);
}
panic!("emu_handle: no emul handler for sysreg read {:#x}", addr.0);
}

/// Handle the system register write by SysRegAddr, data width and the value need to write, call specific device to write the value
pub fn handle_sysreg_write(&self, addr: SysRegAddr, width: usize, val: usize) {
if let Some(emu_dev) = self.find_sysreg_dev(addr) {
info!(
"emu: {:?} handler write sysreg {:#x}",
emu_dev.address_range(),
addr.0
);
emu_dev.handle_write(addr, width, val);
return;
}
panic!("emu_handler: no emul handler for sysreg write {:#x}", addr.0);
}

/// Handle the port read by port number and data width, return the value of the guest want to read
pub fn handle_port_read(&self, port: Port, width: usize) -> AxResult<usize> {
if let Some(emu_dev) = self.find_port_dev(port) {
info!("emu: {:?} handler read port {:#x}", emu_dev.address_range(), port.0);
return emu_dev.handle_read(port, width);
}
panic!("emu_handle: no emul handler for port read {:#x}", port.0);
}

/// Handle the port write by port number, data width and the value need to write, call specific device to write the value
pub fn handle_port_write(&self, port: Port, width: usize, val: usize) {
if let Some(emu_dev) = self.find_port_dev(port) {
info!("emu: {:?} handler write port {:#x}", emu_dev.address_range(), port.0);
emu_dev.handle_write(port, width, val);
return;
}
panic!("emu_handler: no emul handler for port write {:#x}", port.0);
}
}

0 comments on commit 65fecf9

Please sign in to comment.