device.rs0.00%
1
// Copyright 2024 Google LLC2
//3
// Licensed under the Apache License, Version 2.0 (the "License");4
// you may not use this file except in compliance with the License.5
// You may obtain a copy of the License at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// distributed under the License is distributed on an "AS IS" BASIS,11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12
// See the License for the specific language governing permissions and13
// limitations under the License.14
15
use std::fmt::Debug;16
use std::fs::File;17
use std::mem::size_of;18
use std::os::fd::AsRawFd;19
use std::os::unix::fs::FileExt;20
21
use crate::mem;22
use crate::sys::vfio::{23
VfioDeviceInfo, VfioIrqInfo, VfioIrqSet, VfioIrqSetData, VfioIrqSetFlag, VfioPciIrq,24
VfioRegionInfo, vfio_device_get_info, vfio_device_get_irq_info, vfio_device_get_region_info,25
vfio_device_reset, vfio_device_set_irqs,26
};27
use crate::vfio::Result;28
29
pub trait Device: Debug + Send + Sync + 'static {30
fn fd(&self) -> &File;31
32
fn get_info(&self) -> Result<VfioDeviceInfo> {33
let mut device_info = VfioDeviceInfo {34
argsz: size_of::<VfioDeviceInfo>() as u32,35
..Default::default()36
};37
unsafe { vfio_device_get_info(self.fd(), &mut device_info) }?;38
Ok(device_info)39
}40
41
fn get_region_info(&self, index: u32) -> Result<VfioRegionInfo> {42
let mut region_config = VfioRegionInfo {43
argsz: size_of::<VfioRegionInfo>() as u32,44
index,45
..Default::default()46
};47
unsafe { vfio_device_get_region_info(self.fd(), &mut region_config) }?;48
Ok(region_config)49
}50
51
fn get_irq_info(&self, index: u32) -> Result<VfioIrqInfo> {52
let mut irq_info = VfioIrqInfo {53
argsz: size_of::<VfioIrqInfo>() as u32,54
index,55
..Default::default()56
};57
unsafe { vfio_device_get_irq_info(self.fd(), &mut irq_info) }?;58
Ok(irq_info)59
}60
61
fn set_irqs<const N: usize>(&self, irq: &VfioIrqSet<N>) -> Result<()> {62
unsafe { vfio_device_set_irqs(self.fd(), irq) }?;63
Ok(())64
}65
66
fn disable_all_irqs(&self, index: VfioPciIrq) -> Result<()> {67
let vfio_irq_disable_all = VfioIrqSet {68
argsz: size_of::<VfioIrqSet<0>>() as u32,69
flags: VfioIrqSetFlag::DATA_NONE | VfioIrqSetFlag::ACTION_TRIGGER,70
index: index.raw(),71
start: 0,72
count: 0,73
data: VfioIrqSetData { eventfds: [] },74
};75
self.set_irqs(&vfio_irq_disable_all)76
}77
78
fn reset(&self) -> Result<()> {79
unsafe { vfio_device_reset(self.fd()) }?;80
Ok(())81
}82
83
fn read(&self, offset: u64, size: u8) -> mem::Result<u64> {84
let mut bytes = [0u8; 8];85
let Some(buf) = bytes.get_mut(0..size as usize) else {86
log::error!(87
"vfio-{}: invalid read: offset = {offset:#x}, size = {size:#x}",88
self.fd().as_raw_fd()89
);90
return Ok(0);91
};92
self.fd().read_exact_at(buf, offset)?;93
Ok(u64::from_ne_bytes(bytes))94
}95
96
fn write(&self, offset: u64, size: u8, val: u64) -> mem::Result<()> {97
let bytes = val.to_ne_bytes();98
let Some(buf) = bytes.get(..size as usize) else {99
log::error!(100
"vfio-{}: invalid write: offset = {offset:#x}, size = {size:#x}, val = {val:#x}",101
self.fd().as_raw_fd()102
);103
return Ok(());104
};105
self.fd().write_all_at(buf, offset)?;106
Ok(())107
}108
}109