1 // Copyright 2021 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 base::{ioctl_with_ref, AsRawDescriptor, Event, RawDescriptor};
6 use data_model::vec_with_array_field;
7 use std::fmt;
8 use std::fs::{File, OpenOptions};
9 use std::io;
10 use std::mem::size_of;
11 
12 use vfio_sys::*;
13 
14 #[derive(Debug)]
15 pub enum DirectIrqError {
16     Open(io::Error),
17     Enable,
18 }
19 
20 impl fmt::Display for DirectIrqError {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result21     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
22         match self {
23             DirectIrqError::Open(e) => write!(f, "failed to open /dev/plat-irq-forward: {}", e),
24             DirectIrqError::Enable => write!(f, "failed to enable direct irq"),
25         }
26     }
27 }
28 
29 pub struct DirectIrq {
30     dev: File,
31     trigger: Event,
32     resample: Option<Event>,
33 }
34 
35 impl DirectIrq {
36     /// Create DirectIrq object to access hardware triggered interrupts.
new(trigger: Event, resample: Option<Event>) -> Result<Self, DirectIrqError>37     pub fn new(trigger: Event, resample: Option<Event>) -> Result<Self, DirectIrqError> {
38         let dev = OpenOptions::new()
39             .read(true)
40             .write(true)
41             .open("/dev/plat-irq-forward")
42             .map_err(DirectIrqError::Open)?;
43         Ok(DirectIrq {
44             dev,
45             trigger,
46             resample,
47         })
48     }
49 
50     /// Enable hardware triggered interrupt handling.
51     ///
52     /// Note: this feature is not part of VFIO, but provides
53     /// missing IRQ forwarding functionality.
54     ///
55     /// # Arguments
56     ///
57     /// * `irq_num` - host interrupt number (GSI).
58     ///
irq_enable(&self, irq_num: u32) -> Result<(), DirectIrqError>59     pub fn irq_enable(&self, irq_num: u32) -> Result<(), DirectIrqError> {
60         if let Some(resample) = &self.resample {
61             self.plat_irq_ioctl(
62                 irq_num,
63                 PLAT_IRQ_FORWARD_SET_LEVEL_TRIGGER_EVENTFD,
64                 self.trigger.as_raw_descriptor(),
65             )?;
66             self.plat_irq_ioctl(
67                 irq_num,
68                 PLAT_IRQ_FORWARD_SET_LEVEL_UNMASK_EVENTFD,
69                 resample.as_raw_descriptor(),
70             )?;
71         } else {
72             self.plat_irq_ioctl(
73                 irq_num,
74                 PLAT_IRQ_FORWARD_SET_EDGE_TRIGGER,
75                 self.trigger.as_raw_descriptor(),
76             )?;
77         };
78 
79         Ok(())
80     }
81 
plat_irq_ioctl( &self, irq_num: u32, action: u32, fd: RawDescriptor, ) -> Result<(), DirectIrqError>82     fn plat_irq_ioctl(
83         &self,
84         irq_num: u32,
85         action: u32,
86         fd: RawDescriptor,
87     ) -> Result<(), DirectIrqError> {
88         let count = 1;
89         let u32_size = size_of::<u32>();
90         let mut irq_set = vec_with_array_field::<plat_irq_forward_set, u32>(count);
91         irq_set[0].argsz = (size_of::<plat_irq_forward_set>() + count * u32_size) as u32;
92         irq_set[0].action_flags = action;
93         irq_set[0].count = count as u32;
94         irq_set[0].irq_number_host = irq_num;
95         // Safe as we are the owner of irq_set and allocation provides enough space for
96         // eventfd array.
97         let data = unsafe { irq_set[0].eventfd.as_mut_slice(count * u32_size) };
98         let (left, _right) = data.split_at_mut(u32_size);
99         left.copy_from_slice(&fd.to_ne_bytes()[..]);
100 
101         // Safe as we are the owner of plat_irq_forward and irq_set which are valid value
102         let ret = unsafe { ioctl_with_ref(self, PLAT_IRQ_FORWARD_SET(), &irq_set[0]) };
103         if ret < 0 {
104             Err(DirectIrqError::Enable)
105         } else {
106             Ok(())
107         }
108     }
109 }
110 
111 impl AsRawDescriptor for DirectIrq {
as_raw_descriptor(&self) -> i32112     fn as_raw_descriptor(&self) -> i32 {
113         self.dev.as_raw_descriptor()
114     }
115 }
116