From 2366b767186eca6c1e33d1a0bdfef239810db4f2 Mon Sep 17 00:00:00 2001 From: Stefano Garzarella Date: Mon, 3 Apr 2023 14:33:53 +0200 Subject: [PATCH] sound: add missing files --- crates/sound/src/lib.rs | 92 ++++++++++++++++++++++++ crates/sound/src/virtio_sound.rs | 119 +++++++++++++++++++++++++++++++ 2 files changed, 211 insertions(+) create mode 100644 crates/sound/src/lib.rs create mode 100644 crates/sound/src/virtio_sound.rs diff --git a/crates/sound/src/lib.rs b/crates/sound/src/lib.rs new file mode 100644 index 0000000..325266e --- /dev/null +++ b/crates/sound/src/lib.rs @@ -0,0 +1,92 @@ +// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause + +mod vhu_sound; +mod virtio_sound; + +use std::io::{Error as IoError, ErrorKind}; +use std::sync::Arc; + +use log::{info, warn}; +use thiserror::Error as ThisError; +use vhost::{vhost_user, vhost_user::Listener}; +use vhost_user_backend::VhostUserDaemon; +use vm_memory::{GuestMemoryAtomic, GuestMemoryMmap}; + +use crate::vhu_sound::VhostUserSoundBackend; + +pub type Result = std::result::Result; + +/// Custom error types +#[derive(Debug, ThisError)] +pub enum Error { + #[error("Failed to handle event other than EPOLLIN event")] + HandleEventNotEpollIn, + #[error("Failed to handle unknown event")] + HandleUnknownEvent, + #[error("Failed to create a new EventFd")] + EventFdCreate(IoError), +} + +impl std::convert::From for IoError { + fn from(e: Error) -> Self { + IoError::new(ErrorKind::Other, e) + } +} + +#[derive(Debug, Clone)] +/// This structure is the public API through which an external program +/// is allowed to configure the backend. +pub struct SoundConfig { + /// vhost-user Unix domain socket + socket: String, + /// use multiple threads to hanlde the virtqueues + multi_thread: bool, +} + +impl SoundConfig { + /// Create a new instance of the SoundConfig struct, containing the + /// parameters to be fed into the sound-backend server. + pub fn new(socket: String, multi_thread: bool) -> Self { + Self { + socket, + multi_thread, + } + } + + /// Return the path of the unix domain socket which is listening to + /// requests from the guest. + pub fn get_socket_path(&self) -> String { + String::from(&self.socket) + } +} + +/// This is the public API through which an external program starts the +/// vhost-user-sound backend server. +pub fn start_backend_server(config: SoundConfig) { + let listener = Listener::new(config.get_socket_path(), true).unwrap(); + let backend = Arc::new(VhostUserSoundBackend::new(config).unwrap()); + + let mut daemon = VhostUserDaemon::new( + String::from("vhost-user-sound"), + backend.clone(), + GuestMemoryAtomic::new(GuestMemoryMmap::new()), + ) + .unwrap(); + + daemon.start(listener).unwrap(); + + match daemon.wait() { + Ok(()) => { + info!("Stopping cleanly"); + } + Err(vhost_user_backend::Error::HandleRequest(vhost_user::Error::PartialMessage)) => { + info!("vhost-user connection closed with partial message. If the VM is shutting down, this is expected behavior; otherwise, it might be a bug."); + } + Err(e) => { + warn!("Error running daemon: {:?}", e); + } + } + + // No matter the result, we need to shut down the worker thread. + backend.send_exit_event(); +} diff --git a/crates/sound/src/virtio_sound.rs b/crates/sound/src/virtio_sound.rs new file mode 100644 index 0000000..60f9139 --- /dev/null +++ b/crates/sound/src/virtio_sound.rs @@ -0,0 +1,119 @@ +// SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause +#![allow(dead_code)] //TODO: remove + +use vm_memory::{ByteValued, Le32}; + +// virtqueues + +pub const CONTROL_QUEUE_IDX: u16 = 0; +pub const EVENT_QUEUE_IDX: u16 = 1; +pub const TX_QUEUE_IDX: u16 = 2; +pub const RX_QUEUE_IDX: u16 = 3; +pub const NUM_QUEUES: u16 = 4; + +// jack control request types + +pub const VIRTIO_SND_R_JACK_INFO: u32 = 1; +pub const VIRTIO_SND_R_JACK_REMAP: u32 = 2; + +// PCM control request types + +pub const VIRTIO_SND_R_PCM_INFO: u32 = 0x0100; +pub const VIRTIO_SND_R_PCM_SET_PARAMS: u32 = 0x0101; +pub const VIRTIO_SND_R_PCM_PREPARE: u32 = 0x0102; +pub const VIRTIO_SND_R_PCM_RELEASE: u32 = 0x0103; +pub const VIRTIO_SND_R_PCM_START: u32 = 0x0104; +pub const VIRTIO_SND_R_PCM_STOP: u32 = 0x0105; + +// channel map control request types + +pub const VIRTIO_SND_R_CHMAP_INFO: u32 = 0x0200; + +// jack event types + +pub const VIRTIO_SND_EVT_JACK_CONNECTED: u32 = 0x1000; +pub const VIRTIO_SND_EVT_JACK_DISCONNECTED: u32 = 0x1001; + +// PCM event types + +pub const VIRTIO_SND_EVT_PCM_PERIOD_ELAPSED: u32 = 0x1100; +pub const VIRTIO_SND_EVT_PCM_XRUN: u32 = 0x1101; + +// common status codes + +pub const VIRTIO_SND_S_OK: u32 = 0x8000; +pub const VIRTIO_SND_S_BAD_MSG: u32 = 0x8001; +pub const VIRTIO_SND_S_NOT_SUPP: u32 = 0x8002; +pub const VIRTIO_SND_S_IO_ERR: u32 = 0x8003; + +// device data flow directions + +pub const VIRTIO_SND_D_OUTPUT: u32 = 0; +pub const VIRTIO_SND_D_INPUT: u32 = 1; + +/// Virtio Sound Configuration +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct VirtioSoundConfig { + /// total number of all available jacks + pub jacks: Le32, + /// total number of all available PCM streams + pub streams: Le32, + /// total number of all available channel maps + pub chmpas: Le32, +} +// SAFETY: The layout of the structure is fixed and can be initialized by +// reading its content from byte array. +unsafe impl ByteValued for VirtioSoundConfig {} + +/// Virtio Sound Request / Response common header +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct VirtioSoundHeader { + /// request type / response status + pub code: Le32, +} +// SAFETY: The layout of the structure is fixed and can be initialized by +// reading its content from byte array. +unsafe impl ByteValued for VirtioSoundHeader {} + +/// Virtio Sound event notification +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct VirtioSoundEvent { + /// PCM stream event type + pub hdr: VirtioSoundHeader, + /// PCM stream identifier from 0 to streams - 1 + pub data: Le32, +} +// SAFETY: The layout of the structure is fixed and can be initialized by +// reading its content from byte array. +unsafe impl ByteValued for VirtioSoundEvent {} + +/// Virtio Sound request information about any kind of configuration item +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct VirtioSoundQueryInfo { + /// item request type (VIRTIO_SND_R_*_INFO) + pub hdr: VirtioSoundHeader, + /// starting identifier for the item + pub start_id: Le32, + /// number of items for which information is requested + pub cound: Le32, + /// size of the structure containing information for one item + pub size: Le32, +} +// SAFETY: The layout of the structure is fixed and can be initialized by +// reading its content from byte array. +unsafe impl ByteValued for VirtioSoundQueryInfo {} + +/// Virtio Sound response common information header +#[derive(Copy, Clone, Debug, Default, PartialEq)] +#[repr(C)] +pub struct VirtioSoundInfo { + /// function group node identifier + pub hda_fn_nid: Le32, +} +// SAFETY: The layout of the structure is fixed and can be initialized by +// reading its content from byte array. +unsafe impl ByteValued for VirtioSoundInfo {}