From fe5750a3854c98635755cd9d0ceb05de896c0e67 Mon Sep 17 00:00:00 2001 From: Alyssa Ross Date: Tue, 11 Aug 2020 10:49:38 +0000 Subject: devices: port vhost-user-net from cloud-hypervisor This is the cloud-hypervisor vhost-user-net code, modified just enough to compile as part of crosvm. There is currently no way to run crosvm with a vhost-user-net device, and even if there were, it wouldn't work without some further fixes. --- vhost_rs/src/vhost_kern/vhost_binding.rs | 405 +++++++++++++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 vhost_rs/src/vhost_kern/vhost_binding.rs (limited to 'vhost_rs/src/vhost_kern/vhost_binding.rs') diff --git a/vhost_rs/src/vhost_kern/vhost_binding.rs b/vhost_rs/src/vhost_kern/vhost_binding.rs new file mode 100644 index 0000000..21fd82c --- /dev/null +++ b/vhost_rs/src/vhost_kern/vhost_binding.rs @@ -0,0 +1,405 @@ +// Copyright (C) 2019 Alibaba Cloud Computing. All rights reserved. +// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause +// +// Portions Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. +// +// Portions Copyright 2017 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE-BSD file. + +/* Auto-generated by bindgen then manually edited for simplicity */ + +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(missing_docs)] + +use std::os::raw; +use {Error, Result}; + +pub const VHOST: raw::c_uint = 0xaf; +pub const VHOST_VRING_F_LOG: raw::c_uint = 0; +pub const VHOST_ACCESS_RO: raw::c_uint = 1; +pub const VHOST_ACCESS_WO: raw::c_uint = 2; +pub const VHOST_ACCESS_RW: raw::c_uint = 3; +pub const VHOST_IOTLB_MISS: raw::c_uint = 1; +pub const VHOST_IOTLB_UPDATE: raw::c_uint = 2; +pub const VHOST_IOTLB_INVALIDATE: raw::c_uint = 3; +pub const VHOST_IOTLB_ACCESS_FAIL: raw::c_uint = 4; +pub const VHOST_IOTLB_MSG: raw::c_uint = 1; +pub const VHOST_PAGE_SIZE: raw::c_uint = 4096; +pub const VHOST_VIRTIO: raw::c_uint = 175; +pub const VHOST_VRING_LITTLE_ENDIAN: raw::c_uint = 0; +pub const VHOST_VRING_BIG_ENDIAN: raw::c_uint = 1; +pub const VHOST_F_LOG_ALL: raw::c_uint = 26; +pub const VHOST_NET_F_VIRTIO_NET_HDR: raw::c_uint = 27; +pub const VHOST_SCSI_ABI_VERSION: raw::c_uint = 1; + +ioctl_ior_nr!(VHOST_GET_FEATURES, VHOST, 0x00, raw::c_ulonglong); +ioctl_iow_nr!(VHOST_SET_FEATURES, VHOST, 0x00, raw::c_ulonglong); +ioctl_io_nr!(VHOST_SET_OWNER, VHOST, 0x01); +ioctl_io_nr!(VHOST_RESET_OWNER, VHOST, 0x02); +ioctl_iow_nr!(VHOST_SET_MEM_TABLE, VHOST, 0x03, vhost_memory); +ioctl_iow_nr!(VHOST_SET_LOG_BASE, VHOST, 0x04, raw::c_ulonglong); +ioctl_iow_nr!(VHOST_SET_LOG_FD, VHOST, 0x07, raw::c_int); +ioctl_iow_nr!(VHOST_SET_VRING_NUM, VHOST, 0x10, vhost_vring_state); +ioctl_iow_nr!(VHOST_SET_VRING_ADDR, VHOST, 0x11, vhost_vring_addr); +ioctl_iow_nr!(VHOST_SET_VRING_BASE, VHOST, 0x12, vhost_vring_state); +ioctl_iowr_nr!(VHOST_GET_VRING_BASE, VHOST, 0x12, vhost_vring_state); +ioctl_iow_nr!(VHOST_SET_VRING_KICK, VHOST, 0x20, vhost_vring_file); +ioctl_iow_nr!(VHOST_SET_VRING_CALL, VHOST, 0x21, vhost_vring_file); +ioctl_iow_nr!(VHOST_SET_VRING_ERR, VHOST, 0x22, vhost_vring_file); +ioctl_iow_nr!(vhost_SET_BACKEND, VHOST, 0x30, vhost_vring_file); +ioctl_iow_nr!(VHOST_SCSI_SET_ENDPOINT, VHOST, 0x40, vhost_scsi_target); +ioctl_iow_nr!(VHOST_SCSI_CLEAR_ENDPOINT, VHOST, 0x41, vhost_scsi_target); +ioctl_iow_nr!(VHOST_SCSI_GET_ABI_VERSION, VHOST, 0x42, raw::c_int); +ioctl_iow_nr!(VHOST_SCSI_SET_EVENTS_MISSED, VHOST, 0x43, raw::c_uint); +ioctl_iow_nr!(VHOST_SCSI_GET_EVENTS_MISSED, VHOST, 0x44, raw::c_uint); +ioctl_iow_nr!(VHOST_VSOCK_SET_GUEST_CID, VHOST, 0x60, raw::c_ulonglong); +ioctl_iow_nr!(VHOST_VSOCK_SET_RUNNING, VHOST, 0x61, raw::c_int); + +#[repr(C)] +#[derive(Default)] +pub struct __IncompleteArrayField(::std::marker::PhantomData); + +impl __IncompleteArrayField { + #[inline] + pub fn new() -> Self { + __IncompleteArrayField(::std::marker::PhantomData) + } + + #[inline] + #[allow(clippy::trivially_copy_pass_by_ref)] + #[allow(clippy::useless_transmute)] + pub unsafe fn as_ptr(&self) -> *const T { + ::std::mem::transmute(self) + } + + #[inline] + #[allow(clippy::useless_transmute)] + pub unsafe fn as_mut_ptr(&mut self) -> *mut T { + ::std::mem::transmute(self) + } + + #[inline] + pub unsafe fn as_slice(&self, len: usize) -> &[T] { + ::std::slice::from_raw_parts(self.as_ptr(), len) + } + + #[inline] + pub unsafe fn as_mut_slice(&mut self, len: usize) -> &mut [T] { + ::std::slice::from_raw_parts_mut(self.as_mut_ptr(), len) + } +} + +impl ::std::fmt::Debug for __IncompleteArrayField { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fmt.write_str("__IncompleteArrayField") + } +} + +impl ::std::clone::Clone for __IncompleteArrayField { + #[inline] + fn clone(&self) -> Self { + Self::new() + } +} + +impl ::std::marker::Copy for __IncompleteArrayField {} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct vhost_vring_state { + pub index: raw::c_uint, + pub num: raw::c_uint, +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct vhost_vring_file { + pub index: raw::c_uint, + pub fd: raw::c_int, +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct vhost_vring_addr { + pub index: raw::c_uint, + pub flags: raw::c_uint, + pub desc_user_addr: raw::c_ulonglong, + pub used_user_addr: raw::c_ulonglong, + pub avail_user_addr: raw::c_ulonglong, + pub log_guest_addr: raw::c_ulonglong, +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct vhost_iotlb_msg { + pub iova: raw::c_ulonglong, + pub size: raw::c_ulonglong, + pub uaddr: raw::c_ulonglong, + pub perm: raw::c_uchar, + pub type_: raw::c_uchar, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct vhost_msg { + pub type_: raw::c_int, + pub __bindgen_anon_1: vhost_msg__bindgen_ty_1, +} + +impl Default for vhost_msg { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub union vhost_msg__bindgen_ty_1 { + pub iotlb: vhost_iotlb_msg, + pub padding: [raw::c_uchar; 64usize], + _bindgen_union_align: [u64; 8usize], +} + +impl Default for vhost_msg__bindgen_ty_1 { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} + +#[repr(C)] +#[derive(Debug, Default, Copy, Clone)] +pub struct vhost_memory_region { + pub guest_phys_addr: raw::c_ulonglong, + pub memory_size: raw::c_ulonglong, + pub userspace_addr: raw::c_ulonglong, + pub flags_padding: raw::c_ulonglong, +} + +#[repr(C)] +#[derive(Debug, Default, Clone)] +pub struct vhost_memory { + pub nregions: raw::c_uint, + pub padding: raw::c_uint, + pub regions: __IncompleteArrayField, + __force_alignment: [u64; 0], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct vhost_scsi_target { + pub abi_version: raw::c_int, + pub vhost_wwpn: [raw::c_char; 224usize], + pub vhost_tpgt: raw::c_ushort, + pub reserved: raw::c_ushort, +} + +impl Default for vhost_scsi_target { + fn default() -> Self { + unsafe { ::std::mem::zeroed() } + } +} + +/// Helper to support vhost::set_mem_table() +pub struct VhostMemory { + buf: Vec, +} + +impl VhostMemory { + // Limit number of regions to u16 to simplify error handling + pub fn new(entries: u16) -> Self { + let size = std::mem::size_of::() * entries as usize; + let count = (size + 2 * std::mem::size_of::() - 1) + / std::mem::size_of::(); + let mut buf: Vec = vec![Default::default(); count]; + buf[0].nregions = u32::from(entries); + VhostMemory { buf } + } + + pub fn as_ptr(&self) -> *const char { + &self.buf[0] as *const vhost_memory as *const char + } + + pub fn get_header(&self) -> &vhost_memory { + &self.buf[0] + } + + pub fn get_region(&self, index: u32) -> Option<&vhost_memory_region> { + if index >= self.buf[0].nregions { + return None; + } + // Safe because we have allocated enough space nregions + let regions = unsafe { self.buf[0].regions.as_slice(self.buf[0].nregions as usize) }; + Some(®ions[index as usize]) + } + + pub fn set_region(&mut self, index: u32, region: &vhost_memory_region) -> Result<()> { + if index >= self.buf[0].nregions { + return Err(Error::InvalidGuestMemory); + } + // Safe because we have allocated enough space nregions and checked the index. + let regions = unsafe { self.buf[0].regions.as_mut_slice(index as usize + 1) }; + regions[index as usize] = *region; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn bindgen_test_layout_vhost_vring_state() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(vhost_vring_state)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(vhost_vring_state)) + ); + } + + #[test] + fn bindgen_test_layout_vhost_vring_file() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(vhost_vring_file)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(vhost_vring_file)) + ); + } + + #[test] + fn bindgen_test_layout_vhost_vring_addr() { + assert_eq!( + ::std::mem::size_of::(), + 40usize, + concat!("Size of: ", stringify!(vhost_vring_addr)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(vhost_vring_addr)) + ); + } + + #[test] + fn bindgen_test_layout_vhost_msg__bindgen_ty_1() { + assert_eq!( + ::std::mem::size_of::(), + 64usize, + concat!("Size of: ", stringify!(vhost_msg__bindgen_ty_1)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(vhost_msg__bindgen_ty_1)) + ); + } + + #[test] + fn bindgen_test_layout_vhost_msg() { + assert_eq!( + ::std::mem::size_of::(), + 72usize, + concat!("Size of: ", stringify!(vhost_msg)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(vhost_msg)) + ); + } + + #[test] + fn bindgen_test_layout_vhost_memory_region() { + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(vhost_memory_region)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(vhost_memory_region)) + ); + } + + #[test] + fn bindgen_test_layout_vhost_memory() { + assert_eq!( + ::std::mem::size_of::(), + 8usize, + concat!("Size of: ", stringify!(vhost_memory)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(vhost_memory)) + ); + } + + #[test] + fn bindgen_test_layout_vhost_iotlb_msg() { + assert_eq!( + ::std::mem::size_of::(), + 32usize, + concat!("Size of: ", stringify!(vhost_iotlb_msg)) + ); + assert_eq!( + ::std::mem::align_of::(), + 8usize, + concat!("Alignment of ", stringify!(vhost_iotlb_msg)) + ); + } + + #[test] + fn bindgen_test_layout_vhost_scsi_target() { + assert_eq!( + ::std::mem::size_of::(), + 232usize, + concat!("Size of: ", stringify!(vhost_scsi_target)) + ); + assert_eq!( + ::std::mem::align_of::(), + 4usize, + concat!("Alignment of ", stringify!(vhost_scsi_target)) + ); + } + + #[test] + fn test_vhostmemory() { + let mut obj = VhostMemory::new(2); + let region = vhost_memory_region { + guest_phys_addr: 0x1000u64, + memory_size: 0x2000u64, + userspace_addr: 0x300000u64, + flags_padding: 0u64, + }; + assert!(obj.get_region(2).is_none()); + + { + let header = obj.get_header(); + assert_eq!(header.nregions, 2u32); + } + { + assert!(obj.set_region(0, ®ion).is_ok()); + assert!(obj.set_region(1, ®ion).is_ok()); + assert!(obj.set_region(2, ®ion).is_err()); + } + + let region1 = obj.get_region(1).unwrap(); + assert_eq!(region1.guest_phys_addr, 0x1000u64); + assert_eq!(region1.memory_size, 0x2000u64); + assert_eq!(region1.userspace_addr, 0x300000u64); + } +} -- cgit 1.4.1