• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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