1 // Copyright 2018 The Chromium OS Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 use std::default::Default; 6 use std::error; 7 use std::fmt::{self, Display}; 8 use std::path::PathBuf; 9 use std::str::FromStr; 10 11 use audio_streams::shm_streams::{NullShmStreamSource, ShmStreamSource}; 12 use base::{error, Event, RawDescriptor}; 13 use libcras::{CrasClient, CrasClientType, CrasSocketType, CrasSysError}; 14 use resources::{Alloc, MmioType, SystemAllocator}; 15 use vm_memory::GuestMemory; 16 17 use crate::pci::ac97_bus_master::Ac97BusMaster; 18 use crate::pci::ac97_mixer::Ac97Mixer; 19 use crate::pci::ac97_regs::*; 20 use crate::pci::pci_configuration::{ 21 PciBarConfiguration, PciClassCode, PciConfiguration, PciHeaderType, PciMultimediaSubclass, 22 }; 23 use crate::pci::pci_device::{self, PciDevice, Result}; 24 use crate::pci::{PciAddress, PciDeviceError, PciInterruptPin}; 25 #[cfg(not(any(target_os = "linux", target_os = "android")))] 26 use crate::virtio::snd::vios_backend::Error as VioSError; 27 #[cfg(any(target_os = "linux", target_os = "android"))] 28 use crate::virtio::snd::vios_backend::VioSShmStreamSource; 29 30 // Use 82801AA because it's what qemu does. 31 const PCI_DEVICE_ID_INTEL_82801AA_5: u16 = 0x2415; 32 33 /// AC97 audio device emulation. 34 /// Provides the PCI interface for the internal Ac97 emulation. 35 /// Internally the `Ac97BusMaster` and `Ac97Mixer` structs are used to emulated the bus master and 36 /// mixer registers respectively. `Ac97BusMaster` handles moving smaples between guest memory and 37 /// the audio backend. 38 #[derive(Debug, Clone)] 39 pub enum Ac97Backend { 40 NULL, 41 CRAS, 42 VIOS, 43 } 44 45 impl Default for Ac97Backend { default() -> Self46 fn default() -> Self { 47 Ac97Backend::NULL 48 } 49 } 50 51 /// Errors that are possible from a `Ac97`. 52 #[derive(Debug)] 53 pub enum Ac97Error { 54 InvalidBackend, 55 MissingServerPath, 56 } 57 58 impl error::Error for Ac97Error {} 59 60 impl Display for Ac97Error { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result61 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 62 match self { 63 Ac97Error::InvalidBackend => write!(f, "Must be cras, vios or null"), 64 Ac97Error::MissingServerPath => write!(f, "server must be provided for vios backend"), 65 } 66 } 67 } 68 69 impl FromStr for Ac97Backend { 70 type Err = Ac97Error; from_str(s: &str) -> std::result::Result<Self, Self::Err>71 fn from_str(s: &str) -> std::result::Result<Self, Self::Err> { 72 match s { 73 "cras" => Ok(Ac97Backend::CRAS), 74 "vios" => Ok(Ac97Backend::VIOS), 75 "null" => Ok(Ac97Backend::NULL), 76 _ => Err(Ac97Error::InvalidBackend), 77 } 78 } 79 } 80 81 /// Holds the parameters for a AC97 device 82 #[derive(Default, Debug, Clone)] 83 pub struct Ac97Parameters { 84 pub backend: Ac97Backend, 85 pub capture: bool, 86 pub vios_server_path: Option<PathBuf>, 87 client_type: Option<CrasClientType>, 88 } 89 90 impl Ac97Parameters { 91 /// Set CRAS client type by given client type string. 92 /// 93 /// `client_type` - The client type string. set_client_type(&mut self, client_type: &str) -> std::result::Result<(), CrasSysError>94 pub fn set_client_type(&mut self, client_type: &str) -> std::result::Result<(), CrasSysError> { 95 self.client_type = Some(client_type.parse()?); 96 Ok(()) 97 } 98 } 99 100 pub struct Ac97Dev { 101 config_regs: PciConfiguration, 102 pci_address: Option<PciAddress>, 103 // The irq events are temporarily saved here. They need to be passed to the device after the 104 // jail forks. This happens when the bus is first written. 105 irq_evt: Option<Event>, 106 irq_resample_evt: Option<Event>, 107 bus_master: Ac97BusMaster, 108 mixer: Ac97Mixer, 109 backend: Ac97Backend, 110 } 111 112 impl Ac97Dev { 113 /// Creates an 'Ac97Dev' that uses the given `GuestMemory` and starts with all registers at 114 /// default values. new( mem: GuestMemory, backend: Ac97Backend, audio_server: Box<dyn ShmStreamSource>, ) -> Self115 pub fn new( 116 mem: GuestMemory, 117 backend: Ac97Backend, 118 audio_server: Box<dyn ShmStreamSource>, 119 ) -> Self { 120 let config_regs = PciConfiguration::new( 121 0x8086, 122 PCI_DEVICE_ID_INTEL_82801AA_5, 123 PciClassCode::MultimediaController, 124 &PciMultimediaSubclass::AudioDevice, 125 None, // No Programming interface. 126 PciHeaderType::Device, 127 0x8086, // Subsystem Vendor ID 128 0x1, // Subsystem ID. 129 0, // Revision ID. 130 ); 131 132 Self { 133 config_regs, 134 pci_address: None, 135 irq_evt: None, 136 irq_resample_evt: None, 137 bus_master: Ac97BusMaster::new(mem, audio_server), 138 mixer: Ac97Mixer::new(), 139 backend, 140 } 141 } 142 143 /// Creates an `Ac97Dev` with suitable audio server inside based on Ac97Parameters. If it fails 144 /// to create `Ac97Dev` with the given back-end, it'll fallback to the null audio device. try_new(mem: GuestMemory, param: Ac97Parameters) -> Result<Self>145 pub fn try_new(mem: GuestMemory, param: Ac97Parameters) -> Result<Self> { 146 match param.backend { 147 Ac97Backend::CRAS => Self::create_cras_audio_device(param, mem.clone()).or_else(|e| { 148 error!( 149 "Ac97Dev: create_cras_audio_device: {}. Fallback to null audio device", 150 e 151 ); 152 Ok(Self::create_null_audio_device(mem)) 153 }), 154 Ac97Backend::VIOS => Self::create_vios_audio_device(mem, param), 155 Ac97Backend::NULL => Ok(Self::create_null_audio_device(mem)), 156 } 157 } 158 159 /// Return the minijail policy file path for the current Ac97Dev. minijail_policy(&self) -> &'static str160 pub fn minijail_policy(&self) -> &'static str { 161 match self.backend { 162 Ac97Backend::CRAS => "cras_audio_device", 163 Ac97Backend::VIOS => "vios_audio_device", 164 Ac97Backend::NULL => "null_audio_device", 165 } 166 } 167 create_cras_audio_device(params: Ac97Parameters, mem: GuestMemory) -> Result<Self>168 fn create_cras_audio_device(params: Ac97Parameters, mem: GuestMemory) -> Result<Self> { 169 let mut server = Box::new( 170 CrasClient::with_type(CrasSocketType::Unified) 171 .map_err(pci_device::Error::CreateCrasClientFailed)?, 172 ); 173 server.set_client_type( 174 params 175 .client_type 176 .unwrap_or(CrasClientType::CRAS_CLIENT_TYPE_CROSVM), 177 ); 178 if params.capture { 179 server.enable_cras_capture(); 180 } 181 182 let cras_audio = Self::new(mem, Ac97Backend::CRAS, server); 183 Ok(cras_audio) 184 } 185 create_vios_audio_device(mem: GuestMemory, param: Ac97Parameters) -> Result<Self>186 fn create_vios_audio_device(mem: GuestMemory, param: Ac97Parameters) -> Result<Self> { 187 #[cfg(any(target_os = "linux", target_os = "android"))] 188 { 189 let server = Box::new( 190 // The presence of vios_server_path is checked during argument parsing 191 VioSShmStreamSource::new(param.vios_server_path.expect("Missing server path")) 192 .map_err(|e| pci_device::Error::CreateViosClientFailed(e))?, 193 ); 194 let vios_audio = Self::new(mem, Ac97Backend::VIOS, server); 195 return Ok(vios_audio); 196 } 197 #[cfg(not(any(target_os = "linux", target_os = "android")))] 198 Err(pci_device::Error::CreateViosClientFailed( 199 VioSError::PlatformNotSupported, 200 )) 201 } 202 create_null_audio_device(mem: GuestMemory) -> Self203 fn create_null_audio_device(mem: GuestMemory) -> Self { 204 let server = Box::new(NullShmStreamSource::new()); 205 Self::new(mem, Ac97Backend::NULL, server) 206 } 207 read_mixer(&mut self, offset: u64, data: &mut [u8])208 fn read_mixer(&mut self, offset: u64, data: &mut [u8]) { 209 match data.len() { 210 // The mixer is only accessed with 16-bit words. 211 2 => { 212 let val: u16 = self.mixer.readw(offset); 213 data[0] = val as u8; 214 data[1] = (val >> 8) as u8; 215 } 216 l => error!("mixer read length of {}", l), 217 } 218 } 219 write_mixer(&mut self, offset: u64, data: &[u8])220 fn write_mixer(&mut self, offset: u64, data: &[u8]) { 221 match data.len() { 222 // The mixer is only accessed with 16-bit words. 223 2 => self 224 .mixer 225 .writew(offset, u16::from(data[0]) | u16::from(data[1]) << 8), 226 l => error!("mixer write length of {}", l), 227 } 228 // Apply the new mixer settings to the bus master. 229 self.bus_master.update_mixer_settings(&self.mixer); 230 } 231 read_bus_master(&mut self, offset: u64, data: &mut [u8])232 fn read_bus_master(&mut self, offset: u64, data: &mut [u8]) { 233 match data.len() { 234 1 => data[0] = self.bus_master.readb(offset), 235 2 => { 236 let val: u16 = self.bus_master.readw(offset, &self.mixer); 237 data[0] = val as u8; 238 data[1] = (val >> 8) as u8; 239 } 240 4 => { 241 let val: u32 = self.bus_master.readl(offset); 242 data[0] = val as u8; 243 data[1] = (val >> 8) as u8; 244 data[2] = (val >> 16) as u8; 245 data[3] = (val >> 24) as u8; 246 } 247 l => error!("read length of {}", l), 248 } 249 } 250 write_bus_master(&mut self, offset: u64, data: &[u8])251 fn write_bus_master(&mut self, offset: u64, data: &[u8]) { 252 match data.len() { 253 1 => self.bus_master.writeb(offset, data[0], &self.mixer), 254 2 => self 255 .bus_master 256 .writew(offset, u16::from(data[0]) | u16::from(data[1]) << 8), 257 4 => self.bus_master.writel( 258 offset, 259 (u32::from(data[0])) 260 | (u32::from(data[1]) << 8) 261 | (u32::from(data[2]) << 16) 262 | (u32::from(data[3]) << 24), 263 &mut self.mixer, 264 ), 265 l => error!("write length of {}", l), 266 } 267 } 268 } 269 270 impl PciDevice for Ac97Dev { debug_label(&self) -> String271 fn debug_label(&self) -> String { 272 "AC97".to_owned() 273 } 274 allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress>275 fn allocate_address(&mut self, resources: &mut SystemAllocator) -> Result<PciAddress> { 276 if self.pci_address.is_none() { 277 self.pci_address = match resources.allocate_pci(self.debug_label()) { 278 Some(Alloc::PciBar { 279 bus, 280 dev, 281 func, 282 bar: _, 283 }) => Some(PciAddress { bus, dev, func }), 284 _ => None, 285 } 286 } 287 self.pci_address.ok_or(PciDeviceError::PciAllocationFailed) 288 } 289 assign_irq( &mut self, irq_evt: Event, irq_resample_evt: Event, irq_num: u32, irq_pin: PciInterruptPin, )290 fn assign_irq( 291 &mut self, 292 irq_evt: Event, 293 irq_resample_evt: Event, 294 irq_num: u32, 295 irq_pin: PciInterruptPin, 296 ) { 297 self.config_regs.set_irq(irq_num as u8, irq_pin); 298 self.irq_evt = Some(irq_evt); 299 self.irq_resample_evt = Some(irq_resample_evt); 300 } 301 allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>>302 fn allocate_io_bars(&mut self, resources: &mut SystemAllocator) -> Result<Vec<(u64, u64)>> { 303 let address = self 304 .pci_address 305 .expect("allocate_address must be called prior to allocate_io_bars"); 306 let mut ranges = Vec::new(); 307 let mixer_regs_addr = resources 308 .mmio_allocator(MmioType::Low) 309 .allocate_with_align( 310 MIXER_REGS_SIZE, 311 Alloc::PciBar { 312 bus: address.bus, 313 dev: address.dev, 314 func: address.func, 315 bar: 0, 316 }, 317 "ac97-mixer_regs".to_string(), 318 MIXER_REGS_SIZE, 319 ) 320 .map_err(|e| pci_device::Error::IoAllocationFailed(MIXER_REGS_SIZE, e))?; 321 let mixer_config = PciBarConfiguration::default() 322 .set_register_index(0) 323 .set_address(mixer_regs_addr) 324 .set_size(MIXER_REGS_SIZE); 325 self.config_regs 326 .add_pci_bar(mixer_config) 327 .map_err(|e| pci_device::Error::IoRegistrationFailed(mixer_regs_addr, e))?; 328 ranges.push((mixer_regs_addr, MIXER_REGS_SIZE)); 329 330 let master_regs_addr = resources 331 .mmio_allocator(MmioType::Low) 332 .allocate_with_align( 333 MASTER_REGS_SIZE, 334 Alloc::PciBar { 335 bus: address.bus, 336 dev: address.dev, 337 func: address.func, 338 bar: 1, 339 }, 340 "ac97-master_regs".to_string(), 341 MASTER_REGS_SIZE, 342 ) 343 .map_err(|e| pci_device::Error::IoAllocationFailed(MASTER_REGS_SIZE, e))?; 344 let master_config = PciBarConfiguration::default() 345 .set_register_index(1) 346 .set_address(master_regs_addr) 347 .set_size(MASTER_REGS_SIZE); 348 self.config_regs 349 .add_pci_bar(master_config) 350 .map_err(|e| pci_device::Error::IoRegistrationFailed(master_regs_addr, e))?; 351 ranges.push((master_regs_addr, MASTER_REGS_SIZE)); 352 Ok(ranges) 353 } 354 read_config_register(&self, reg_idx: usize) -> u32355 fn read_config_register(&self, reg_idx: usize) -> u32 { 356 self.config_regs.read_reg(reg_idx) 357 } 358 write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])359 fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) { 360 (&mut self.config_regs).write_reg(reg_idx, offset, data) 361 } 362 keep_rds(&self) -> Vec<RawDescriptor>363 fn keep_rds(&self) -> Vec<RawDescriptor> { 364 if let Some(server_fds) = self.bus_master.keep_rds() { 365 server_fds 366 } else { 367 Vec::new() 368 } 369 } 370 read_bar(&mut self, addr: u64, data: &mut [u8])371 fn read_bar(&mut self, addr: u64, data: &mut [u8]) { 372 let bar0 = self.config_regs.get_bar_addr(0); 373 let bar1 = self.config_regs.get_bar_addr(1); 374 match addr { 375 a if a >= bar0 && a < bar0 + MIXER_REGS_SIZE => self.read_mixer(addr - bar0, data), 376 a if a >= bar1 && a < bar1 + MASTER_REGS_SIZE => { 377 self.read_bus_master(addr - bar1, data) 378 } 379 _ => (), 380 } 381 } 382 write_bar(&mut self, addr: u64, data: &[u8])383 fn write_bar(&mut self, addr: u64, data: &[u8]) { 384 let bar0 = self.config_regs.get_bar_addr(0); 385 let bar1 = self.config_regs.get_bar_addr(1); 386 match addr { 387 a if a >= bar0 && a < bar0 + MIXER_REGS_SIZE => self.write_mixer(addr - bar0, data), 388 a if a >= bar1 && a < bar1 + MASTER_REGS_SIZE => { 389 // Check if the irq needs to be passed to the device. 390 if let (Some(irq_evt), Some(irq_resample_evt)) = 391 (self.irq_evt.take(), self.irq_resample_evt.take()) 392 { 393 self.bus_master.set_irq_event(irq_evt, irq_resample_evt); 394 } 395 self.write_bus_master(addr - bar1, data) 396 } 397 _ => (), 398 } 399 } 400 } 401 402 #[cfg(test)] 403 mod tests { 404 use super::*; 405 use audio_streams::shm_streams::MockShmStreamSource; 406 use vm_memory::GuestAddress; 407 408 #[test] create()409 fn create() { 410 let mem = GuestMemory::new(&[(GuestAddress(0u64), 4 * 1024 * 1024)]).unwrap(); 411 let mut ac97_dev = 412 Ac97Dev::new(mem, Ac97Backend::NULL, Box::new(MockShmStreamSource::new())); 413 let mut allocator = SystemAllocator::builder() 414 .add_io_addresses(0x1000_0000, 0x1000_0000) 415 .add_low_mmio_addresses(0x2000_0000, 0x1000_0000) 416 .add_high_mmio_addresses(0x3000_0000, 0x1000_0000) 417 .create_allocator(5) 418 .unwrap(); 419 assert!(ac97_dev.allocate_address(&mut allocator).is_ok()); 420 assert!(ac97_dev.allocate_io_bars(&mut allocator).is_ok()); 421 } 422 } 423