bus.rs100.00%
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::sync::Arc;16
use std::sync::atomic::{AtomicU32, Ordering};17
18
use bitfield::bitfield;19
20
use crate::mem;21
use crate::mem::emulated::{Action, Mmio};22
#[cfg(target_arch = "x86_64")]23
use crate::pci::host_bridge::HostBridge;24
use crate::pci::segment::PciSegment;25
use crate::pci::{Bdf, Pci, Result};26
27
bitfield! {28
#[derive(Copy, Clone, Default)]29
struct Address(u32);30
impl Debug;31
impl new;32
pub bool, enabled, set_enabled: 31;33
pub u8, bus, set_bus: 23, 16;34
pub u8, dev, set_dev: 15, 11;35
pub u8, func, set_func: 10, 8;36
pub u8, offset, set_offset: 7, 0;37
}38
39
impl Address {40
pub fn to_ecam_addr(self) -> u64 {13x41
let v = self.0 as u64;13x42
((v & 0xff_ff00) << 4) | (v & 0xfc)13x43
}13x44
}45
46
#[derive(Debug)]47
pub struct PciIoBus {48
address: AtomicU32,49
segment: Arc<PciSegment>,50
}51
52
impl Mmio for PciIoBus {53
fn size(&self) -> u64 {3x54
83x55
}3x56
57
fn read(&self, offset: u64, size: u8) -> Result<u64, mem::Error> {25x58
match offset {25x59
0 => {60
if size == 4 {9x61
Ok(self.address.load(Ordering::Acquire) as u64)6x62
} else {63
Ok(0)3x64
}65
}66
4..=7 => {16x67
let addr = Address(self.address.load(Ordering::Acquire));13x68
if addr.enabled() {13x69
let ecam_addr = addr.to_ecam_addr() | (offset & 0b11);10x70
self.segment.read(ecam_addr, size)10x71
} else {72
Ok(0)3x73
}74
}75
_ => Ok(0),3x76
}77
}25x78
79
fn write(&self, offset: u64, size: u8, val: u64) -> mem::Result<Action> {25x80
match offset {25x81
0 => {82
if size == 4 {16x83
self.address.store(val as u32, Ordering::Release);13x84
}13x85
Ok(Action::None)16x86
}87
4..=7 => {9x88
let addr = Address(self.address.load(Ordering::Acquire));6x89
if addr.enabled() {6x90
let ecam_addr = addr.to_ecam_addr() | (offset & 0b11);3x91
self.segment.write(ecam_addr, size, val)3x92
} else {93
Ok(Action::None)3x94
}95
}96
_ => Ok(Action::None),3x97
}98
}25x99
}100
101
#[derive(Debug)]102
pub struct PciBus {103
pub io_bus: Arc<PciIoBus>,104
pub segment: Arc<PciSegment>,105
}106
107
impl PciBus {108
pub fn new() -> Self {4x109
let segment = Arc::new(PciSegment::new());4x110
111
#[cfg(target_arch = "x86_64")]112
segment.add(Bdf::new(0, 0, 0), Arc::new(HostBridge::new()));2x113
114
PciBus {4x115
io_bus: Arc::new(PciIoBus {4x116
address: AtomicU32::new(0),4x117
segment: segment.clone(),4x118
}),4x119
segment,4x120
}4x121
}4x122
123
pub fn reserve(&self, bdf: Option<Bdf>) -> Option<Bdf> {3x124
self.segment.reserve(bdf)3x125
}3x126
127
pub fn add(&self, bdf: Bdf, dev: Arc<dyn Pci>) -> Option<Arc<dyn Pci>> {3x128
self.segment.add(bdf, dev)3x129
}3x130
}131
132
impl Default for PciBus {133
fn default() -> Self {3x134
Self::new()3x135
}3x136
}137
138
#[cfg(test)]139
#[path = "bus_test.rs"]140
mod tests;141