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