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