• 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::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