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