Skip to content

Commit d12bf98

Browse files
HaixuCuistefano-garzarella
authored andcommitted
vhost-device-spi: Add initial implementation
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]>
1 parent 7efcb34 commit d12bf98

File tree

14 files changed

+3219
-1
lines changed

14 files changed

+3219
-1
lines changed

Cargo.lock

Lines changed: 19 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ members = [
99
"vhost-device-scsi",
1010
"vhost-device-scmi",
1111
"vhost-device-sound",
12+
"vhost-device-spi",
1213
"vhost-device-template",
1314
"vhost-device-vsock",
1415
]

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ Here is the list of device backends that we support:
2121
- [SCMI](https://github.com/rust-vmm/vhost-device/blob/main/vhost-device-scmi/README.md)
2222
- [SCSI](https://github.com/rust-vmm/vhost-device/blob/main/vhost-device-scsi/README.md)
2323
- [Sound](https://github.com/rust-vmm/vhost-device/blob/main/vhost-device-sound/README.md)
24+
- [SPI](https://github.com/rust-vmm/vhost-device/blob/main/vhost-device-spi/README.md)
2425
- [VSOCK](https://github.com/rust-vmm/vhost-device/blob/main/vhost-device-vsock/README.md)
2526

2627
The vhost-device workspace also provides a

coverage_config_x86_64.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
{
2-
"coverage_score": 77.63,
2+
"coverage_score": 75.76,
33
"exclude_path": "",
44
"crate_features": ""
55
}

vhost-device-spi/CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# Changelog
2+
## [Unreleased]
3+
4+
### Added
5+
6+
### Changed
7+
8+
### Fixed
9+
10+
### Deprecated
11+
12+
## [0.1.0]
13+
14+
First release
15+

vhost-device-spi/Cargo.toml

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
[package]
2+
name = "vhost-device-spi"
3+
version = "0.1.0"
4+
authors = ["Haixu Cui <[email protected]>"]
5+
description = "vhost spi backend device"
6+
repository = "https://github.com/rust-vmm/vhost-device"
7+
readme = "README.md"
8+
keywords = ["spi", "vhost", "virt", "backend"]
9+
categories = ["virtualization"]
10+
license = "Apache-2.0 OR BSD-3-Clause"
11+
edition = "2021"
12+
13+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
14+
15+
[features]
16+
xen = ["vm-memory/xen", "vhost/xen", "vhost-user-backend/xen"]
17+
18+
[dependencies]
19+
clap = { version = "4.5", features = ["derive"] }
20+
env_logger = "0.11"
21+
libc = "0.2"
22+
log = "0.4"
23+
thiserror = "1.0"
24+
vhost = { version = "0.11", features = ["vhost-user-backend"] }
25+
vhost-user-backend = "0.15"
26+
virtio-bindings = "0.2.2"
27+
virtio-queue = "0.12"
28+
vm-memory = "0.14.1"
29+
vmm-sys-util = "0.12"
30+
bitflags = "2.4.0"
31+
32+
[dev-dependencies]
33+
assert_matches = "1.5"
34+
virtio-queue = { version = "0.12", features = ["test-utils"] }
35+
vm-memory = { version = "0.14.1", features = ["backend-mmap", "backend-atomic"] }

vhost-device-spi/LICENSE-APACHE

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../LICENSE-APACHE
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
../LICENSE-BSD-3-Clause

vhost-device-spi/README.md

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
# vhost-device-spi - SPI emulation backend daemon
2+
3+
## Description
4+
This program is a vhost-user backend that emulates a VirtIO SPI bus.
5+
This program takes the layout of the spi bus and its devices on the host
6+
OS and then talks to them via the `/dev/spidevX.Y` interface when a request
7+
comes from the guest OS for a SPI device.
8+
9+
## Synopsis
10+
11+
```shell
12+
vhost-device-spi [OPTIONS]
13+
```
14+
15+
## Options
16+
```text
17+
-h, --help
18+
19+
Print help.
20+
21+
-s, --socket-path=PATH
22+
23+
Location of vhost-user Unix domain sockets, this path will be suffixed with
24+
0,1,2..socket_count-1.
25+
26+
-c, --socket-count=INT
27+
28+
Number of guests (sockets) to attach to, default set to 1.
29+
30+
-l, --device=SPI-DEVICES
31+
32+
Spi device full path at the host OS in the format:
33+
/dev/spidevX.Y
34+
35+
Here,
36+
X: is spi controller's bus number.
37+
Y: is chip select index.
38+
```
39+
40+
## Examples
41+
42+
### Dependencies
43+
For testing the device the required dependencies are:
44+
- Linux:
45+
- Integrate *virtio-spi* driver:
46+
- https://lwn.net/Articles/966715/
47+
- Set `CONFIG_SPI_VIRTIO=y`
48+
- QEMU:
49+
- Integrate vhost-user-spi QEMU device:
50+
- https://lore.kernel.org/all/[email protected]/
51+
52+
### Test the device
53+
First start the daemon on the host machine::
54+
55+
````suggestion
56+
```console
57+
vhost-device-spi --socket-path=vspi.sock --socket-count=1 --device "/dev/spidev0.0"
58+
```
59+
````
60+
61+
The QEMU invocation needs to create a chardev socket the device spi
62+
use to communicate as well as share the guests memory over a memfd.
63+
64+
````suggestion
65+
```console
66+
qemu-system-aarch64 -m 1G \
67+
-chardev socket,path=/home/root/vspi.sock0,id=vspi \
68+
-device vhost-user-spi-pci,chardev=vspi,id=spi \
69+
-object memory-backend-file,id=mem,size=1G,mem-path=/dev/shm,share=on \
70+
-numa node,memdev=mem \
71+
...
72+
```
73+
````
74+
75+
## License
76+
77+
This project is licensed under either of
78+
79+
- [Apache License](http://www.apache.org/licenses/LICENSE-2.0), Version 2.0
80+
- [BSD-3-Clause License](https://opensource.org/licenses/BSD-3-Clause)

vhost-device-spi/src/linux_spi.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// Linux SPI bindings
2+
//
3+
// Copyright (c) 2024 Qualcomm Innovation Center, Inc. All rights reserved.
4+
// Haixu Cui <[email protected]>
5+
//
6+
// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause
7+
8+
use bitflags::bitflags;
9+
use vmm_sys_util::{ioctl_ioc_nr, ioctl_ior_nr, ioctl_iow_nr};
10+
11+
/// Describes a single SPI transfer
12+
#[derive(Debug)]
13+
#[repr(C)]
14+
pub struct SpiIocTransfer {
15+
/// Holds pointer to userspace buffer with transmit data, or null
16+
pub tx_buf: u64,
17+
/// Holds pointer to userspace buffer for receive data, or null.
18+
pub rx_buf: u64,
19+
/// Length of tx and rx buffers, in bytes.
20+
pub len: u32,
21+
/// Temporary override of the device's bitrate.
22+
pub speed_hz: u32,
23+
/// If nonzero, how long to delay after the last bit transfer
24+
/// before optionally deselecting the device before the next transfer.
25+
pub delay_usecs: u16,
26+
/// Temporary override of the device's wordsize.
27+
pub bits_per_word: u8,
28+
/// True to deselect device before starting the next transfer.
29+
pub cs_change: u8,
30+
/// Number of bits used for writing.
31+
pub tx_nbits: u8,
32+
/// Number of bits used for reading.
33+
pub rx_nbits: u8,
34+
/// If nonzero, how long to wait between words within one
35+
/// transfer. This property needs explicit support in the SPI controller,
36+
/// otherwise it is silently ignored
37+
pub word_delay_usecs: u8,
38+
pub _padding: u8,
39+
}
40+
41+
/// Linux SPI definitions
42+
/// IOCTL commands, refer Linux's Documentation/spi/spidev.rst for further details.
43+
const _IOC_SIZEBITS: u32 = 14;
44+
const _IOC_SIZESHIFT: u32 = 16;
45+
const SPI_IOC_MESSAGE_BASE: u32 = 0x40006b00;
46+
47+
ioctl_ior_nr!(SPI_IOC_RD_BITS_PER_WORD, 107, 3, u8);
48+
ioctl_iow_nr!(SPI_IOC_WR_BITS_PER_WORD, 107, 3, u8);
49+
ioctl_ior_nr!(SPI_IOC_RD_MAX_SPEED_HZ, 107, 4, u32);
50+
ioctl_iow_nr!(SPI_IOC_WR_MAX_SPEED_HZ, 107, 4, u32);
51+
ioctl_ior_nr!(SPI_IOC_RD_MODE32, 107, 5, u32);
52+
ioctl_iow_nr!(SPI_IOC_WR_MODE32, 107, 5, u32);
53+
54+
// Corresponds to the SPI_IOC_MESSAGE macro in Linux
55+
pub fn spi_ioc_message(n: u32) -> u64 {
56+
let mut size: u32 = 0;
57+
if n * 32 < (1 << _IOC_SIZEBITS) {
58+
size = n * 32;
59+
}
60+
(SPI_IOC_MESSAGE_BASE | (size << _IOC_SIZESHIFT)) as u64
61+
}
62+
63+
bitflags! {
64+
pub struct LnxSpiMode: u32 {
65+
const CPHA = 1 << 0;
66+
const CPOL = 1 << 1;
67+
const CS_HIGH = 1 << 2;
68+
const LSB_FIRST = 1 << 3;
69+
const LOOP = 1 << 5;
70+
const TX_DUAL = 1 << 8;
71+
const TX_QUAD = 1 << 9;
72+
const TX_OCTAL = 1 << 13;
73+
const RX_DUAL = 1 << 10;
74+
const RX_QUAD = 1 << 11;
75+
const RX_OCTAL = 1 << 14;
76+
}
77+
}

0 commit comments

Comments
 (0)