Alioth Code Coverage

device.rs0.00%

1// Copyright 2024 Google LLC
2//
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 at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// 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 and
13// limitations under the License.
14
15use std::fmt::Debug;
16use std::fs::File;
17use std::mem::size_of;
18use std::os::fd::AsRawFd;
19use std::os::unix::fs::FileExt;
20
21use crate::mem;
22use 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};
27use crate::vfio::Result;
28
29pub 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