• 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::os::unix::io::RawFd;
6 use std::sync::Arc;
7 
8 use byteorder::{ByteOrder, LittleEndian};
9 use sync::Mutex;
10 
11 use crate::pci::pci_configuration::{
12     PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType,
13 };
14 use crate::pci::pci_device::PciDevice;
15 use crate::BusDevice;
16 
17 // A PciDevice that holds the root hub's configuration.
18 struct PciRootConfiguration {
19     config: PciConfiguration,
20 }
21 
22 impl PciDevice for PciRootConfiguration {
debug_label(&self) -> String23     fn debug_label(&self) -> String {
24         "pci root device".to_owned()
25     }
keep_fds(&self) -> Vec<RawFd>26     fn keep_fds(&self) -> Vec<RawFd> {
27         Vec::new()
28     }
config_registers(&self) -> &PciConfiguration29     fn config_registers(&self) -> &PciConfiguration {
30         &self.config
31     }
32 
config_registers_mut(&mut self) -> &mut PciConfiguration33     fn config_registers_mut(&mut self) -> &mut PciConfiguration {
34         &mut self.config
35     }
36 
read_bar(&mut self, _addr: u64, _data: &mut [u8])37     fn read_bar(&mut self, _addr: u64, _data: &mut [u8]) {}
38 
write_bar(&mut self, _addr: u64, _data: &[u8])39     fn write_bar(&mut self, _addr: u64, _data: &[u8]) {}
40 }
41 
42 /// Emulates the PCI Root bridge.
43 pub struct PciRoot {
44     /// Bus configuration for the root device.
45     root_configuration: PciRootConfiguration,
46     /// Devices attached to this bridge.
47     devices: Vec<Arc<Mutex<dyn BusDevice>>>,
48 }
49 
50 impl PciRoot {
51     /// Create an empty PCI root bus.
new() -> Self52     pub fn new() -> Self {
53         PciRoot {
54             root_configuration: PciRootConfiguration {
55                 config: PciConfiguration::new(
56                     0,
57                     0,
58                     PciClassCode::BridgeDevice,
59                     &PciBridgeSubclass::HostBridge,
60                     None,
61                     PciHeaderType::Bridge,
62                     0,
63                     0,
64                 ),
65             },
66             devices: Vec::new(),
67         }
68     }
69 
70     /// Add a `device` to this root PCI bus.
add_device(&mut self, device: Arc<Mutex<dyn BusDevice>>)71     pub fn add_device(&mut self, device: Arc<Mutex<dyn BusDevice>>) {
72         self.devices.push(device);
73     }
74 
config_space_read( &self, bus: usize, device: usize, _function: usize, register: usize, ) -> u3275     pub fn config_space_read(
76         &self,
77         bus: usize,
78         device: usize,
79         _function: usize,
80         register: usize,
81     ) -> u32 {
82         // Only support one bus.
83         if bus != 0 {
84             return 0xffff_ffff;
85         }
86 
87         match device {
88             0 => {
89                 // If bus and device are both zero, then read from the root config.
90                 self.root_configuration.config_register_read(register)
91             }
92             dev_num => self
93                 .devices
94                 .get(dev_num - 1)
95                 .map_or(0xffff_ffff, |d| d.lock().config_register_read(register)),
96         }
97     }
98 
config_space_write( &mut self, bus: usize, device: usize, _function: usize, register: usize, offset: u64, data: &[u8], )99     pub fn config_space_write(
100         &mut self,
101         bus: usize,
102         device: usize,
103         _function: usize,
104         register: usize,
105         offset: u64,
106         data: &[u8],
107     ) {
108         if offset as usize + data.len() > 4 {
109             return;
110         }
111 
112         // Only support one bus.
113         if bus != 0 {
114             return;
115         }
116 
117         match device {
118             0 => {
119                 // If bus and device are both zero, then read from the root config.
120                 self.root_configuration
121                     .config_register_write(register, offset, data);
122             }
123             dev_num => {
124                 // dev_num is 1-indexed here.
125                 if let Some(d) = self.devices.get(dev_num - 1) {
126                     d.lock().config_register_write(register, offset, data);
127                 }
128             }
129         }
130     }
131 }
132 
133 /// Emulates PCI configuration access mechanism #1 (I/O ports 0xcf8 and 0xcfc).
134 pub struct PciConfigIo {
135     /// PCI root bridge.
136     pci_root: PciRoot,
137     /// Current address to read/write from (0xcf8 register, litte endian).
138     config_address: u32,
139 }
140 
141 impl PciConfigIo {
new(pci_root: PciRoot) -> Self142     pub fn new(pci_root: PciRoot) -> Self {
143         PciConfigIo {
144             pci_root,
145             config_address: 0,
146         }
147     }
148 
config_space_read(&self) -> u32149     fn config_space_read(&self) -> u32 {
150         let enabled = (self.config_address & 0x8000_0000) != 0;
151         if !enabled {
152             return 0xffff_ffff;
153         }
154 
155         let (bus, device, function, register) =
156             parse_config_address(self.config_address & !0x8000_0000);
157         self.pci_root
158             .config_space_read(bus, device, function, register)
159     }
160 
config_space_write(&mut self, offset: u64, data: &[u8])161     fn config_space_write(&mut self, offset: u64, data: &[u8]) {
162         let enabled = (self.config_address & 0x8000_0000) != 0;
163         if !enabled {
164             return;
165         }
166 
167         let (bus, device, function, register) =
168             parse_config_address(self.config_address & !0x8000_0000);
169         self.pci_root
170             .config_space_write(bus, device, function, register, offset, data)
171     }
172 
set_config_address(&mut self, offset: u64, data: &[u8])173     fn set_config_address(&mut self, offset: u64, data: &[u8]) {
174         if offset as usize + data.len() > 4 {
175             return;
176         }
177         let (mask, value): (u32, u32) = match data.len() {
178             1 => (
179                 0x0000_00ff << (offset * 8),
180                 (data[0] as u32) << (offset * 8),
181             ),
182             2 => (
183                 0x0000_ffff << (offset * 16),
184                 ((data[1] as u32) << 8 | data[0] as u32) << (offset * 16),
185             ),
186             4 => (0xffff_ffff, LittleEndian::read_u32(data)),
187             _ => return,
188         };
189         self.config_address = (self.config_address & !mask) | value;
190     }
191 }
192 
193 impl BusDevice for PciConfigIo {
debug_label(&self) -> String194     fn debug_label(&self) -> String {
195         format!("pci config io-port 0x{:03x}", self.config_address)
196     }
197 
read(&mut self, offset: u64, data: &mut [u8])198     fn read(&mut self, offset: u64, data: &mut [u8]) {
199         // `offset` is relative to 0xcf8
200         let value = match offset {
201             0...3 => self.config_address,
202             4...7 => self.config_space_read(),
203             _ => 0xffff_ffff,
204         };
205 
206         // Only allow reads to the register boundary.
207         let start = offset as usize % 4;
208         let end = start + data.len();
209         if end <= 4 {
210             for i in start..end {
211                 data[i - start] = (value >> (i * 8)) as u8;
212             }
213         } else {
214             for d in data {
215                 *d = 0xff;
216             }
217         }
218     }
219 
write(&mut self, offset: u64, data: &[u8])220     fn write(&mut self, offset: u64, data: &[u8]) {
221         // `offset` is relative to 0xcf8
222         match offset {
223             o @ 0...3 => self.set_config_address(o, data),
224             o @ 4...7 => self.config_space_write(o - 4, data),
225             _ => (),
226         };
227     }
228 }
229 
230 /// Emulates PCI memory-mapped configuration access mechanism.
231 pub struct PciConfigMmio {
232     /// PCI root bridge.
233     pci_root: PciRoot,
234 }
235 
236 impl PciConfigMmio {
new(pci_root: PciRoot) -> Self237     pub fn new(pci_root: PciRoot) -> Self {
238         PciConfigMmio { pci_root }
239     }
240 
config_space_read(&self, config_address: u32) -> u32241     fn config_space_read(&self, config_address: u32) -> u32 {
242         let (bus, device, function, register) = parse_config_address(config_address);
243         self.pci_root
244             .config_space_read(bus, device, function, register)
245     }
246 
config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8])247     fn config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8]) {
248         let (bus, device, function, register) = parse_config_address(config_address);
249         self.pci_root
250             .config_space_write(bus, device, function, register, offset, data)
251     }
252 }
253 
254 impl BusDevice for PciConfigMmio {
debug_label(&self) -> String255     fn debug_label(&self) -> String {
256         "pci config mmio".to_owned()
257     }
258 
read(&mut self, offset: u64, data: &mut [u8])259     fn read(&mut self, offset: u64, data: &mut [u8]) {
260         // Only allow reads to the register boundary.
261         let start = offset as usize % 4;
262         let end = start + data.len();
263         if end > 4 || offset > u32::max_value() as u64 {
264             for d in data {
265                 *d = 0xff;
266             }
267             return;
268         }
269 
270         let value = self.config_space_read(offset as u32);
271         for i in start..end {
272             data[i - start] = (value >> (i * 8)) as u8;
273         }
274     }
275 
write(&mut self, offset: u64, data: &[u8])276     fn write(&mut self, offset: u64, data: &[u8]) {
277         if offset > u32::max_value() as u64 {
278             return;
279         }
280         self.config_space_write(offset as u32, offset % 4, data)
281     }
282 }
283 
284 // Parse the CONFIG_ADDRESS register to a (bus, device, function, register) tuple.
parse_config_address(config_address: u32) -> (usize, usize, usize, usize)285 fn parse_config_address(config_address: u32) -> (usize, usize, usize, usize) {
286     const BUS_NUMBER_OFFSET: usize = 16;
287     const BUS_NUMBER_MASK: u32 = 0x00ff;
288     const DEVICE_NUMBER_OFFSET: usize = 11;
289     const DEVICE_NUMBER_MASK: u32 = 0x1f;
290     const FUNCTION_NUMBER_OFFSET: usize = 8;
291     const FUNCTION_NUMBER_MASK: u32 = 0x07;
292     const REGISTER_NUMBER_OFFSET: usize = 2;
293     const REGISTER_NUMBER_MASK: u32 = 0x3f;
294 
295     let bus_number = ((config_address >> BUS_NUMBER_OFFSET) & BUS_NUMBER_MASK) as usize;
296     let device_number = ((config_address >> DEVICE_NUMBER_OFFSET) & DEVICE_NUMBER_MASK) as usize;
297     let function_number =
298         ((config_address >> FUNCTION_NUMBER_OFFSET) & FUNCTION_NUMBER_MASK) as usize;
299     let register_number =
300         ((config_address >> REGISTER_NUMBER_OFFSET) & REGISTER_NUMBER_MASK) as usize;
301 
302     (bus_number, device_number, function_number, register_number)
303 }
304