• 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::collections::BTreeMap;
6 use std::convert::TryInto;
7 use std::fmt::{self, Display};
8 use std::sync::Arc;
9 
10 use base::RawDescriptor;
11 use sync::Mutex;
12 
13 use crate::pci::pci_configuration::{
14     PciBridgeSubclass, PciClassCode, PciConfiguration, PciHeaderType,
15 };
16 use crate::pci::pci_device::{Error, PciDevice};
17 use crate::{BusAccessInfo, BusDevice};
18 use resources::SystemAllocator;
19 
20 // A PciDevice that holds the root hub's configuration.
21 struct PciRootConfiguration {
22     config: PciConfiguration,
23 }
24 
25 impl PciDevice for PciRootConfiguration {
debug_label(&self) -> String26     fn debug_label(&self) -> String {
27         "pci root device".to_owned()
28     }
allocate_address(&mut self, _resources: &mut SystemAllocator) -> Result<PciAddress, Error>29     fn allocate_address(&mut self, _resources: &mut SystemAllocator) -> Result<PciAddress, Error> {
30         // PCI root fixed address.
31         Ok(PciAddress {
32             bus: 0,
33             dev: 0,
34             func: 0,
35         })
36     }
keep_rds(&self) -> Vec<RawDescriptor>37     fn keep_rds(&self) -> Vec<RawDescriptor> {
38         Vec::new()
39     }
read_config_register(&self, reg_idx: usize) -> u3240     fn read_config_register(&self, reg_idx: usize) -> u32 {
41         self.config.read_reg(reg_idx)
42     }
43 
write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8])44     fn write_config_register(&mut self, reg_idx: usize, offset: u64, data: &[u8]) {
45         (&mut self.config).write_reg(reg_idx, offset, data)
46     }
47 
read_bar(&mut self, _addr: u64, _data: &mut [u8])48     fn read_bar(&mut self, _addr: u64, _data: &mut [u8]) {}
49 
write_bar(&mut self, _addr: u64, _data: &[u8])50     fn write_bar(&mut self, _addr: u64, _data: &[u8]) {}
51 }
52 
53 /// PCI Device Address, AKA Bus:Device.Function
54 #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
55 pub struct PciAddress {
56     pub bus: u8,
57     pub dev: u8,  /* u5 */
58     pub func: u8, /* u3 */
59 }
60 
61 impl Display for PciAddress {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result62     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
63         write!(f, "{:04x}:{:02x}.{:0x}", self.bus, self.dev, self.func)
64     }
65 }
66 
67 impl PciAddress {
68     const BUS_OFFSET: usize = 16;
69     const BUS_MASK: u32 = 0x00ff;
70     const DEVICE_OFFSET: usize = 11;
71     const DEVICE_MASK: u32 = 0x1f;
72     const FUNCTION_OFFSET: usize = 8;
73     const FUNCTION_MASK: u32 = 0x07;
74     const REGISTER_OFFSET: usize = 2;
75     const REGISTER_MASK: u32 = 0x3f;
76 
77     /// Construct PciAddress and register tuple from CONFIG_ADDRESS value.
from_config_address(config_address: u32) -> (Self, usize)78     pub fn from_config_address(config_address: u32) -> (Self, usize) {
79         let bus = ((config_address >> Self::BUS_OFFSET) & Self::BUS_MASK) as u8;
80         let dev = ((config_address >> Self::DEVICE_OFFSET) & Self::DEVICE_MASK) as u8;
81         let func = ((config_address >> Self::FUNCTION_OFFSET) & Self::FUNCTION_MASK) as u8;
82         let register = ((config_address >> Self::REGISTER_OFFSET) & Self::REGISTER_MASK) as usize;
83 
84         (PciAddress { bus, dev, func }, register)
85     }
86 
87     /// Construct PciAddress from string domain:bus:device.function.
from_string(address: &str) -> Self88     pub fn from_string(address: &str) -> Self {
89         let mut func_dev_bus_domain = address
90             .split(|c| c == ':' || c == '.')
91             .map(|v| u8::from_str_radix(v, 16).unwrap_or_default())
92             .rev()
93             .collect::<Vec<u8>>();
94         func_dev_bus_domain.resize(4, 0);
95         PciAddress {
96             bus: func_dev_bus_domain[2],
97             dev: func_dev_bus_domain[1],
98             func: func_dev_bus_domain[0],
99         }
100     }
101 
102     /// Encode PciAddress into CONFIG_ADDRESS value.
to_config_address(&self, register: usize) -> u32103     pub fn to_config_address(&self, register: usize) -> u32 {
104         ((Self::BUS_MASK & self.bus as u32) << Self::BUS_OFFSET)
105             | ((Self::DEVICE_MASK & self.dev as u32) << Self::DEVICE_OFFSET)
106             | ((Self::FUNCTION_MASK & self.func as u32) << Self::FUNCTION_OFFSET)
107             | ((Self::REGISTER_MASK & register as u32) << Self::REGISTER_OFFSET)
108     }
109 
110     /// Returns true if the address points to PCI root host-bridge.
is_root(&self) -> bool111     fn is_root(&self) -> bool {
112         matches!(
113             &self,
114             PciAddress {
115                 bus: 0,
116                 dev: 0,
117                 func: 0
118             }
119         )
120     }
121 }
122 
123 /// Emulates the PCI Root bridge.
124 pub struct PciRoot {
125     /// Bus configuration for the root device.
126     root_configuration: PciRootConfiguration,
127     /// Devices attached to this bridge.
128     devices: BTreeMap<PciAddress, Arc<Mutex<dyn BusDevice>>>,
129 }
130 
131 const PCI_VENDOR_ID_INTEL: u16 = 0x8086;
132 const PCI_DEVICE_ID_INTEL_82441: u16 = 0x1237;
133 
134 impl PciRoot {
135     /// Create an empty PCI root bus.
new() -> Self136     pub fn new() -> Self {
137         PciRoot {
138             root_configuration: PciRootConfiguration {
139                 config: PciConfiguration::new(
140                     PCI_VENDOR_ID_INTEL,
141                     PCI_DEVICE_ID_INTEL_82441,
142                     PciClassCode::BridgeDevice,
143                     &PciBridgeSubclass::HostBridge,
144                     None,
145                     PciHeaderType::Device,
146                     0,
147                     0,
148                     0,
149                 ),
150             },
151             devices: BTreeMap::new(),
152         }
153     }
154 
155     /// Add a `device` to this root PCI bus.
add_device(&mut self, address: PciAddress, device: Arc<Mutex<dyn BusDevice>>)156     pub fn add_device(&mut self, address: PciAddress, device: Arc<Mutex<dyn BusDevice>>) {
157         // Ignore attempt to replace PCI Root host bridge.
158         if !address.is_root() {
159             self.devices.insert(address, device);
160         }
161     }
162 
config_space_read(&self, address: PciAddress, register: usize) -> u32163     pub fn config_space_read(&self, address: PciAddress, register: usize) -> u32 {
164         if address.is_root() {
165             self.root_configuration.config_register_read(register)
166         } else {
167             self.devices
168                 .get(&address)
169                 .map_or(0xffff_ffff, |d| d.lock().config_register_read(register))
170         }
171     }
172 
config_space_write( &mut self, address: PciAddress, register: usize, offset: u64, data: &[u8], )173     pub fn config_space_write(
174         &mut self,
175         address: PciAddress,
176         register: usize,
177         offset: u64,
178         data: &[u8],
179     ) {
180         if offset as usize + data.len() > 4 {
181             return;
182         }
183         if address.is_root() {
184             self.root_configuration
185                 .config_register_write(register, offset, data);
186         } else if let Some(d) = self.devices.get(&address) {
187             d.lock().config_register_write(register, offset, data);
188         }
189     }
190 }
191 
192 /// Emulates PCI configuration access mechanism #1 (I/O ports 0xcf8 and 0xcfc).
193 pub struct PciConfigIo {
194     /// PCI root bridge.
195     pci_root: PciRoot,
196     /// Current address to read/write from (0xcf8 register, litte endian).
197     config_address: u32,
198 }
199 
200 impl PciConfigIo {
new(pci_root: PciRoot) -> Self201     pub fn new(pci_root: PciRoot) -> Self {
202         PciConfigIo {
203             pci_root,
204             config_address: 0,
205         }
206     }
207 
config_space_read(&self) -> u32208     fn config_space_read(&self) -> u32 {
209         let enabled = (self.config_address & 0x8000_0000) != 0;
210         if !enabled {
211             return 0xffff_ffff;
212         }
213 
214         let (address, register) = PciAddress::from_config_address(self.config_address);
215         self.pci_root.config_space_read(address, register)
216     }
217 
config_space_write(&mut self, offset: u64, data: &[u8])218     fn config_space_write(&mut self, offset: u64, data: &[u8]) {
219         let enabled = (self.config_address & 0x8000_0000) != 0;
220         if !enabled {
221             return;
222         }
223 
224         let (address, register) = PciAddress::from_config_address(self.config_address);
225         self.pci_root
226             .config_space_write(address, register, offset, data)
227     }
228 
set_config_address(&mut self, offset: u64, data: &[u8])229     fn set_config_address(&mut self, offset: u64, data: &[u8]) {
230         if offset as usize + data.len() > 4 {
231             return;
232         }
233         let (mask, value): (u32, u32) = match data.len() {
234             1 => (
235                 0x0000_00ff << (offset * 8),
236                 (data[0] as u32) << (offset * 8),
237             ),
238             2 => (
239                 0x0000_ffff << (offset * 16),
240                 u32::from(u16::from_le_bytes(data.try_into().unwrap())) << (offset * 16),
241             ),
242             4 => (0xffff_ffff, u32::from_le_bytes(data.try_into().unwrap())),
243             _ => return,
244         };
245         self.config_address = (self.config_address & !mask) | value;
246     }
247 }
248 
249 impl BusDevice for PciConfigIo {
debug_label(&self) -> String250     fn debug_label(&self) -> String {
251         format!("pci config io-port 0x{:03x}", self.config_address)
252     }
253 
read(&mut self, info: BusAccessInfo, data: &mut [u8])254     fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
255         // `offset` is relative to 0xcf8
256         let value = match info.offset {
257             0..=3 => self.config_address,
258             4..=7 => self.config_space_read(),
259             _ => 0xffff_ffff,
260         };
261 
262         // Only allow reads to the register boundary.
263         let start = info.offset as usize % 4;
264         let end = start + data.len();
265         if end <= 4 {
266             for i in start..end {
267                 data[i - start] = (value >> (i * 8)) as u8;
268             }
269         } else {
270             for d in data {
271                 *d = 0xff;
272             }
273         }
274     }
275 
write(&mut self, info: BusAccessInfo, data: &[u8])276     fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
277         // `offset` is relative to 0xcf8
278         match info.offset {
279             o @ 0..=3 => self.set_config_address(o, data),
280             o @ 4..=7 => self.config_space_write(o - 4, data),
281             _ => (),
282         };
283     }
284 }
285 
286 /// Emulates PCI memory-mapped configuration access mechanism.
287 pub struct PciConfigMmio {
288     /// PCI root bridge.
289     pci_root: PciRoot,
290 }
291 
292 impl PciConfigMmio {
new(pci_root: PciRoot) -> Self293     pub fn new(pci_root: PciRoot) -> Self {
294         PciConfigMmio { pci_root }
295     }
296 
config_space_read(&self, config_address: u32) -> u32297     fn config_space_read(&self, config_address: u32) -> u32 {
298         let (address, register) = PciAddress::from_config_address(config_address);
299         self.pci_root.config_space_read(address, register)
300     }
301 
config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8])302     fn config_space_write(&mut self, config_address: u32, offset: u64, data: &[u8]) {
303         let (address, register) = PciAddress::from_config_address(config_address);
304         self.pci_root
305             .config_space_write(address, register, offset, data)
306     }
307 }
308 
309 impl BusDevice for PciConfigMmio {
debug_label(&self) -> String310     fn debug_label(&self) -> String {
311         "pci config mmio".to_owned()
312     }
313 
read(&mut self, info: BusAccessInfo, data: &mut [u8])314     fn read(&mut self, info: BusAccessInfo, data: &mut [u8]) {
315         // Only allow reads to the register boundary.
316         let start = info.offset as usize % 4;
317         let end = start + data.len();
318         if end > 4 || info.offset > u32::max_value() as u64 {
319             for d in data {
320                 *d = 0xff;
321             }
322             return;
323         }
324 
325         let value = self.config_space_read(info.offset as u32);
326         for i in start..end {
327             data[i - start] = (value >> (i * 8)) as u8;
328         }
329     }
330 
write(&mut self, info: BusAccessInfo, data: &[u8])331     fn write(&mut self, info: BusAccessInfo, data: &[u8]) {
332         if info.offset > u32::max_value() as u64 {
333             return;
334         }
335         self.config_space_write(info.offset as u32, info.offset % 4, data)
336     }
337 }
338