vhost.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::fs::File;16
use std::os::fd::AsRawFd;17
use std::path::Path;18
use std::sync::Arc;19
20
use snafu::{ResultExt, Snafu};21
22
use crate::errors::{BoxTrace, DebugTrace, trace_error};23
use crate::mem::mapped::Ram;24
use crate::mem::{self, LayoutUpdated};25
use crate::sys::vhost::{26
MemoryMultipleRegion, MemoryRegion, VhostFeature, VirtqAddr, VirtqFile, VirtqState,27
vhost_get_backend_features, vhost_get_features, vhost_set_backend_features, vhost_set_features,28
vhost_set_mem_table, vhost_set_owner, vhost_set_virtq_addr, vhost_set_virtq_base,29
vhost_set_virtq_call, vhost_set_virtq_err, vhost_set_virtq_kick, vhost_set_virtq_num,30
vhost_vsock_set_guest_cid, vhost_vsock_set_running,31
};32
33
#[trace_error]34
#[derive(Snafu, DebugTrace)]35
#[snafu(module, visibility(pub(crate)), context(suffix(false)))]36
pub enum Error {37
#[snafu(display("Error from OS"), context(false))]38
System { error: std::io::Error },39
#[snafu(display("Cannot access device {path:?}"))]40
AccessDevice {41
path: Box<Path>,42
error: std::io::Error,43
},44
#[snafu(display("vhost backend is missing device feature {feature:#x}"))]45
VhostMissingDeviceFeature { feature: u128 },46
#[snafu(display("vhost-{dev} signals an error of queue {index:#x}"))]47
VhostQueueErr { dev: &'static str, index: u16 },48
}49
50
type Result<T, E = Error> = std::result::Result<T, E>;51
52
#[derive(Debug)]53
pub struct VhostDev {54
fd: File,55
}56
57
impl VhostDev {58
pub fn new<P: AsRef<Path>>(path: P) -> Result<Self> {59
let fd = File::open(&path).context(error::AccessDevice {60
path: path.as_ref(),61
})?;62
Ok(VhostDev { fd })63
}64
65
pub fn get_features(&self) -> Result<u64> {66
let feat = unsafe { vhost_get_features(&self.fd) }?;67
Ok(feat)68
}69
70
pub fn set_features(&self, val: &u64) -> Result<()> {71
unsafe { vhost_set_features(&self.fd, val) }?;72
Ok(())73
}74
75
pub fn get_backend_features(&self) -> Result<VhostFeature> {76
let feat = unsafe { vhost_get_backend_features(&self.fd) }?;77
Ok(VhostFeature::from_bits_retain(feat))78
}79
80
pub fn set_backend_features(&self, val: &VhostFeature) -> Result<()> {81
unsafe { vhost_set_backend_features(&self.fd, &val.bits()) }?;82
Ok(())83
}84
85
pub fn set_owner(&self) -> Result<()> {86
unsafe { vhost_set_owner(&self.fd) }?;87
Ok(())88
}89
90
pub fn set_virtq_num(&self, state: &VirtqState) -> Result<()> {91
unsafe { vhost_set_virtq_num(&self.fd, state) }?;92
Ok(())93
}94
95
pub fn set_virtq_addr(&self, addr: &VirtqAddr) -> Result<()> {96
unsafe { vhost_set_virtq_addr(&self.fd, addr) }?;97
Ok(())98
}99
100
pub fn set_virtq_base(&self, state: &VirtqState) -> Result<()> {101
unsafe { vhost_set_virtq_base(&self.fd, state) }?;102
Ok(())103
}104
105
pub fn set_virtq_kick(&self, file: &VirtqFile) -> Result<()> {106
unsafe { vhost_set_virtq_kick(&self.fd, file) }?;107
Ok(())108
}109
110
pub fn set_virtq_call(&self, file: &VirtqFile) -> Result<()> {111
unsafe { vhost_set_virtq_call(&self.fd, file) }?;112
Ok(())113
}114
115
pub fn set_virtq_err(&self, file: &VirtqFile) -> Result<()> {116
unsafe { vhost_set_virtq_err(&self.fd, file) }?;117
Ok(())118
}119
120
pub fn set_mem_table<const N: usize>(&self, table: &MemoryMultipleRegion<N>) -> Result<()> {121
unsafe { vhost_set_mem_table(&self.fd, table) }?;122
Ok(())123
}124
125
pub fn vsock_set_guest_cid(&self, cid: u64) -> Result<()> {126
unsafe { vhost_vsock_set_guest_cid(&self.fd, &cid) }?;127
Ok(())128
}129
130
pub fn vsock_set_running(&self, val: bool) -> Result<()> {131
unsafe { vhost_vsock_set_running(&self.fd, &(val as _)) }?;132
Ok(())133
}134
}135
136
#[derive(Debug)]137
pub struct UpdateVsockMem {138
pub dev: Arc<VhostDev>,139
}140
141
impl LayoutUpdated for UpdateVsockMem {142
fn ram_updated(&self, ram: &Ram) -> mem::Result<()> {143
let mut table = MemoryMultipleRegion {144
num: 0,145
_padding: 0,146
regions: [MemoryRegion::default(); 64],147
};148
for (index, (gpa, user_mem)) in ram.iter().enumerate() {149
table.num += 1;150
table.regions[index].gpa = gpa;151
table.regions[index].hva = user_mem.addr() as u64;152
table.regions[index].size = user_mem.size();153
}154
let ret = self.dev.set_mem_table(&table);155
ret.box_trace(mem::error::ChangeLayout)?;156
log::trace!(157
"vhost-{}: updated mem table to {:x?}",158
self.dev.fd.as_raw_fd(),159
&table.regions[..table.num as usize]160
);161
Ok(())162
}163
}164