Skip to content

Commit

Permalink
vhost-device-spi: Add initial implementation
Browse files Browse the repository at this point in the history
This program is a vhost-user backend that emulates a VirtIO SPI bus.
This program takes the layout of the spi bus and its devices on the host
OS and then talks to them via the /dev/spidevX.Y interface when a request
comes from the guest OS for a SPI device.

The implementation corresponds with the specification:
https://github.com/oasis-tcs/virtio-spec/tree/virtio-1.4/device-types/spi

Signed-off-by: Haixu Cui <[email protected]>
  • Loading branch information
HaixuCui authored and stefano-garzarella committed Jul 29, 2024
1 parent 7efcb34 commit d12bf98
Show file tree
Hide file tree
Showing 14 changed files with 3,219 additions and 1 deletion.
19 changes: 19 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ members = [
"vhost-device-scsi",
"vhost-device-scmi",
"vhost-device-sound",
"vhost-device-spi",
"vhost-device-template",
"vhost-device-vsock",
]
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ Here is the list of device backends that we support:
- [SCMI](https://github.com/rust-vmm/vhost-device/blob/main/vhost-device-scmi/README.md)
- [SCSI](https://github.com/rust-vmm/vhost-device/blob/main/vhost-device-scsi/README.md)
- [Sound](https://github.com/rust-vmm/vhost-device/blob/main/vhost-device-sound/README.md)
- [SPI](https://github.com/rust-vmm/vhost-device/blob/main/vhost-device-spi/README.md)
- [VSOCK](https://github.com/rust-vmm/vhost-device/blob/main/vhost-device-vsock/README.md)

The vhost-device workspace also provides a
Expand Down
2 changes: 1 addition & 1 deletion coverage_config_x86_64.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"coverage_score": 77.63,
"coverage_score": 75.76,
"exclude_path": "",
"crate_features": ""
}
15 changes: 15 additions & 0 deletions vhost-device-spi/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Changelog
## [Unreleased]

### Added

### Changed

### Fixed

### Deprecated

## [0.1.0]

First release

35 changes: 35 additions & 0 deletions vhost-device-spi/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
[package]
name = "vhost-device-spi"
version = "0.1.0"
authors = ["Haixu Cui <[email protected]>"]
description = "vhost spi backend device"
repository = "https://github.com/rust-vmm/vhost-device"
readme = "README.md"
keywords = ["spi", "vhost", "virt", "backend"]
categories = ["virtualization"]
license = "Apache-2.0 OR BSD-3-Clause"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[features]
xen = ["vm-memory/xen", "vhost/xen", "vhost-user-backend/xen"]

[dependencies]
clap = { version = "4.5", features = ["derive"] }
env_logger = "0.11"
libc = "0.2"
log = "0.4"
thiserror = "1.0"
vhost = { version = "0.11", features = ["vhost-user-backend"] }
vhost-user-backend = "0.15"
virtio-bindings = "0.2.2"
virtio-queue = "0.12"
vm-memory = "0.14.1"
vmm-sys-util = "0.12"
bitflags = "2.4.0"

[dev-dependencies]
assert_matches = "1.5"
virtio-queue = { version = "0.12", features = ["test-utils"] }
vm-memory = { version = "0.14.1", features = ["backend-mmap", "backend-atomic"] }
1 change: 1 addition & 0 deletions vhost-device-spi/LICENSE-APACHE
1 change: 1 addition & 0 deletions vhost-device-spi/LICENSE-BSD-3-Clause
80 changes: 80 additions & 0 deletions vhost-device-spi/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
# vhost-device-spi - SPI emulation backend daemon

## Description
This program is a vhost-user backend that emulates a VirtIO SPI bus.
This program takes the layout of the spi bus and its devices on the host
OS and then talks to them via the `/dev/spidevX.Y` interface when a request
comes from the guest OS for a SPI device.

## Synopsis

```shell
vhost-device-spi [OPTIONS]
```

## Options
```text
-h, --help
Print help.
-s, --socket-path=PATH
Location of vhost-user Unix domain sockets, this path will be suffixed with
0,1,2..socket_count-1.
-c, --socket-count=INT
Number of guests (sockets) to attach to, default set to 1.
-l, --device=SPI-DEVICES
Spi device full path at the host OS in the format:
/dev/spidevX.Y
Here,
X: is spi controller's bus number.
Y: is chip select index.
```

## Examples

### Dependencies
For testing the device the required dependencies are:
- Linux:
- Integrate *virtio-spi* driver:
- https://lwn.net/Articles/966715/
- Set `CONFIG_SPI_VIRTIO=y`
- QEMU:
- Integrate vhost-user-spi QEMU device:
- https://lore.kernel.org/all/[email protected]/

### Test the device
First start the daemon on the host machine::

````suggestion
```console
vhost-device-spi --socket-path=vspi.sock --socket-count=1 --device "/dev/spidev0.0"
```
````

The QEMU invocation needs to create a chardev socket the device spi
use to communicate as well as share the guests memory over a memfd.

````suggestion
```console
qemu-system-aarch64 -m 1G \
-chardev socket,path=/home/root/vspi.sock0,id=vspi \
-device vhost-user-spi-pci,chardev=vspi,id=spi \
-object memory-backend-file,id=mem,size=1G,mem-path=/dev/shm,share=on \
-numa node,memdev=mem \
...
```
````

## License

This project is licensed under either of

- [Apache License](http://www.apache.org/licenses/LICENSE-2.0), Version 2.0
- [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause)
77 changes: 77 additions & 0 deletions vhost-device-spi/src/linux_spi.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
// Linux SPI bindings
//
// Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
// Haixu Cui <[email protected]>
//
// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause

use bitflags::bitflags;
use vmm_sys_util::{ioctl_ioc_nr, ioctl_ior_nr, ioctl_iow_nr};

/// Describes a single SPI transfer
#[derive(Debug)]
#[repr(C)]
pub struct SpiIocTransfer {
/// Holds pointer to userspace buffer with transmit data, or null
pub tx_buf: u64,
/// Holds pointer to userspace buffer for receive data, or null.
pub rx_buf: u64,
/// Length of tx and rx buffers, in bytes.
pub len: u32,
/// Temporary override of the device's bitrate.
pub speed_hz: u32,
/// If nonzero, how long to delay after the last bit transfer
/// before optionally deselecting the device before the next transfer.
pub delay_usecs: u16,
/// Temporary override of the device's wordsize.
pub bits_per_word: u8,
/// True to deselect device before starting the next transfer.
pub cs_change: u8,
/// Number of bits used for writing.
pub tx_nbits: u8,
/// Number of bits used for reading.
pub rx_nbits: u8,
/// If nonzero, how long to wait between words within one
/// transfer. This property needs explicit support in the SPI controller,
/// otherwise it is silently ignored
pub word_delay_usecs: u8,
pub _padding: u8,
}

/// Linux SPI definitions
/// IOCTL commands, refer Linux's Documentation/spi/spidev.rst for further details.
const _IOC_SIZEBITS: u32 = 14;
const _IOC_SIZESHIFT: u32 = 16;
const SPI_IOC_MESSAGE_BASE: u32 = 0x40006b00;

ioctl_ior_nr!(SPI_IOC_RD_BITS_PER_WORD, 107, 3, u8);
ioctl_iow_nr!(SPI_IOC_WR_BITS_PER_WORD, 107, 3, u8);
ioctl_ior_nr!(SPI_IOC_RD_MAX_SPEED_HZ, 107, 4, u32);
ioctl_iow_nr!(SPI_IOC_WR_MAX_SPEED_HZ, 107, 4, u32);
ioctl_ior_nr!(SPI_IOC_RD_MODE32, 107, 5, u32);
ioctl_iow_nr!(SPI_IOC_WR_MODE32, 107, 5, u32);

// Corresponds to the SPI_IOC_MESSAGE macro in Linux
pub fn spi_ioc_message(n: u32) -> u64 {
let mut size: u32 = 0;
if n * 32 < (1 << _IOC_SIZEBITS) {
size = n * 32;
}
(SPI_IOC_MESSAGE_BASE | (size << _IOC_SIZESHIFT)) as u64
}

bitflags! {
pub struct LnxSpiMode: u32 {
const CPHA = 1 << 0;
const CPOL = 1 << 1;
const CS_HIGH = 1 << 2;
const LSB_FIRST = 1 << 3;
const LOOP = 1 << 5;
const TX_DUAL = 1 << 8;
const TX_QUAD = 1 << 9;
const TX_OCTAL = 1 << 13;
const RX_DUAL = 1 << 10;
const RX_QUAD = 1 << 11;
const RX_OCTAL = 1 << 14;
}
}
Loading

0 comments on commit d12bf98

Please sign in to comment.