segment.rs41.60%
1
// Copyright 2024 Google LLC2
//3
// Licensed under the Apache License, Version 2.0 (the "License");4
// you may not use this file except in compliance with the License.5
// You may obtain a copy of the License at6
//7
// https://www.apache.org/licenses/LICENSE-2.08
//9
// Unless required by applicable law or agreed to in writing, software10
// distributed under the License is distributed on an "AS IS" BASIS,11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.12
// See the License for the specific language governing permissions and13
// limitations under the License.14
15
use std::collections::HashMap;16
use std::iter::zip;17
use std::sync::Arc;18
19
use parking_lot::{Mutex, RwLock};20
21
use crate::device::{self, Pause};22
use crate::mem::emulated::{Action, Mmio};23
use crate::pci::config::{BAR_IO, BAR_MEM64, BAR_PREFETCHABLE, PciConfig};24
use crate::pci::{Bdf, Pci, Result};25
use crate::{align_up, mem};26
27
#[derive(Debug)]28
struct EmptyDevice;29
30
impl Pause for EmptyDevice {31
fn pause(&self) -> device::Result<()> {32
Ok(())33
}34
35
fn resume(&self) -> device::Result<()> {36
Ok(())37
}38
}39
40
impl Pci for EmptyDevice {41
fn name(&self) -> &str {42
"empty_device"43
}44
45
fn config(&self) -> &dyn PciConfig {46
unreachable!()47
}48
49
fn reset(&self) -> Result<()> {50
unreachable!()51
}52
}53
54
#[derive(Debug)]55
pub struct PciSegment {56
devices: RwLock<HashMap<Bdf, Arc<dyn Pci>>>,57
next_bdf: Mutex<Bdf>,58
placeholder: Arc<dyn Pci>,59
}60
61
impl PciSegment {62
pub fn new() -> Self {31x63
Self {31x64
devices: RwLock::new(HashMap::new()),31x65
next_bdf: Mutex::new(Bdf::new(0, 0, 0)),31x66
placeholder: Arc::new(EmptyDevice),31x67
}31x68
}31x69
70
pub fn max_bus(&self) -> Option<u8> {71
let devices = self.devices.read();72
devices.keys().map(|bdf| bdf.bus()).max()73
}74
75
pub fn add(&self, bdf: Bdf, dev: Arc<dyn Pci>) -> Option<Arc<dyn Pci>> {71x76
let mut configs = self.devices.write();71x77
if let Some(exist_dev) = configs.insert(bdf, dev) {71x78
if Arc::ptr_eq(&exist_dev, &self.placeholder) {27x79
None12x80
} else {81
configs.insert(bdf, exist_dev)15x82
}83
} else {84
None44x85
}86
}71x87
88
pub fn reserve(&self, bdf: Option<Bdf>) -> Option<Bdf> {18x89
let mut empty_dev = self.placeholder.clone();18x90
match bdf {18x91
Some(bdf) => {9x92
if self.add(bdf, empty_dev).is_none() {9x93
Some(bdf)6x94
} else {95
None3x96
}97
}98
None => {99
let mut next_bdf = self.next_bdf.lock();9x100
let init = *next_bdf;9x101
loop {102
let bdf = *next_bdf;21x103
*next_bdf = Bdf(next_bdf.0.wrapping_add(8));21x104
match self.add(bdf, empty_dev) {21x105
None => break Some(bdf),9x106
Some(d) => empty_dev = d,12x107
}108
if *next_bdf == init {12x109
break None;110
}12x111
}112
}113
}114
}18x115
116
/// Assigns addresses to all devices' base address registers117
///118
/// `resources` is an array of 4 `(start, end)` tuples, corresponds to119
///120
/// - IO space,121
/// - 32-bit non-prefetchable memory space,122
/// - 32-bit prefetchable memory space,123
/// - 64-bit prefetchable memory space,124
///125
/// respectively.126
pub fn assign_resources(&self, resources: &[(u64, u64); 4]) {127
let mut bar_lists = [const { vec![] }; 4];128
let devices = self.devices.read();129
for (bdf, dev) in devices.iter() {130
let config = dev.config();131
let header = config.get_header().data.read();132
let mut index = 0;133
while index < 6 {134
let bar_index = index;135
index += 1;136
let (val, mask) = header.get_bar(bar_index);137
let mut mask = mask as u64;138
if val & BAR_MEM64 == BAR_MEM64 {139
let (_, mask_hi) = header.get_bar(bar_index + 1);140
mask |= (mask_hi as u64) << 32;141
index += 1;142
}143
if mask == 0 {144
continue;145
}146
let bar_list = if val & BAR_IO == BAR_IO {147
&mut bar_lists[0]148
} else if val & (BAR_MEM64 | BAR_PREFETCHABLE) == BAR_MEM64 | BAR_PREFETCHABLE {149
&mut bar_lists[3]150
} else if val & (BAR_MEM64 | BAR_PREFETCHABLE) == BAR_MEM64 {151
unreachable!("{bdf}: BAR {index} is 64-bit but not prefetchable")152
} else if val & BAR_PREFETCHABLE == BAR_PREFETCHABLE {153
&mut bar_lists[2]154
} else {155
&mut bar_lists[1]156
};157
bar_list.push((*bdf, dev, bar_index, 1 << mask.trailing_zeros()));158
}159
}160
for bar_list in bar_lists.iter_mut() {161
bar_list.sort_by_key(|(bdf, _, index, size)| (u64::MAX - size, *bdf, *index));162
}163
for (bar_list, (start, end)) in zip(bar_lists, resources) {164
let mut addr = *start;165
for (bdf, dev, index, size) in bar_list {166
let config = dev.config();167
let mut header = config.get_header().data.write();168
let aligned_addr = align_up!(addr, size.trailing_zeros());169
if aligned_addr + size > *end {170
log::error!(171
"{bdf}: cannot map BAR {index} into address range {start:#x}..{end:#x}"172
);173
continue;174
}175
header.set_bar(index, aligned_addr as u32);176
if aligned_addr > u32::MAX as u64 {177
header.set_bar(index + 1, (aligned_addr >> 32) as u32);178
}179
addr = aligned_addr + size;180
}181
}182
}183
184
pub fn reset(&self) -> Result<()> {185
let devices = self.devices.read();186
for (_, dev) in devices.iter() {187
dev.reset()?;188
dev.config().reset()?;189
}190
Ok(())191
}192
}193
194
impl Default for PciSegment {195
fn default() -> Self {12x196
Self::new()12x197
}12x198
}199
200
impl Mmio for PciSegment {201
fn size(&self) -> u64 {3x202
// 256 MiB: 256 buses, 32 devices, 8 functions203
256 * 32 * 8 * 40963x204
}3x205
206
fn read(&self, offset: u64, size: u8) -> Result<u64, mem::Error> {22x207
let bdf = Bdf((offset >> 12) as u16);22x208
let devices = self.devices.read();22x209
if let Some(dev) = devices.get(&bdf) {22x210
dev.config().read(offset & 0xfff, size)19x211
} else {212
Ok(u64::MAX)3x213
}214
}22x215
216
fn write(&self, offset: u64, size: u8, val: u64) -> mem::Result<Action> {9x217
let bdf = Bdf((offset >> 12) as u16);9x218
let devices = self.devices.read();9x219
if let Some(dev) = devices.get(&bdf) {9x220
dev.config().write(offset & 0xfff, size, val)6x221
} else {222
Ok(Action::None)3x223
}224
}9x225
}226
227
#[cfg(test)]228
#[path = "segment_test.rs"]229
mod tests;230