Alioth Code Coverage

bus.rs100.00%

1// Copyright 2024 Google LLC
2//
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 at
6//
7// https://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// 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 and
13// limitations under the License.
14
15use std::sync::Arc;
16use std::sync::atomic::{AtomicU32, Ordering};
17
18use bitfield::bitfield;
19
20use crate::mem;
21use crate::mem::emulated::{Action, Mmio};
22#[cfg(target_arch = "x86_64")]
23use crate::pci::host_bridge::HostBridge;
24use crate::pci::segment::PciSegment;
25use crate::pci::{Bdf, Pci, Result};
26
27bitfield! {
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
39impl Address {
40 pub fn to_ecam_addr(self) -> u64 {13x
41 let v = self.0 as u64;13x
42 ((v & 0xff_ff00) << 4) | (v & 0xfc)13x
43 }13x
44}
45
46#[derive(Debug)]
47pub struct PciIoBus {
48 address: AtomicU32,
49 segment: Arc<PciSegment>,
50}
51
52impl Mmio for PciIoBus {
53 fn size(&self) -> u64 {3x
54 83x
55 }3x
56
57 fn read(&self, offset: u64, size: u8) -> Result<u64, mem::Error> {25x
58 match offset {25x
59 0 => {
60 if size == 4 {9x
61 Ok(self.address.load(Ordering::Acquire) as u64)6x
62 } else {
63 Ok(0)3x
64 }
65 }
66 4..=7 => {16x
67 let addr = Address(self.address.load(Ordering::Acquire));13x
68 if addr.enabled() {13x
69 let ecam_addr = addr.to_ecam_addr() | (offset & 0b11);10x
70 self.segment.read(ecam_addr, size)10x
71 } else {
72 Ok(0)3x
73 }
74 }
75 _ => Ok(0),3x
76 }
77 }25x
78
79 fn write(&self, offset: u64, size: u8, val: u64) -> mem::Result<Action> {25x
80 match offset {25x
81 0 => {
82 if size == 4 {16x
83 self.address.store(val as u32, Ordering::Release);13x
84 }13x
85 Ok(Action::None)16x
86 }
87 4..=7 => {9x
88 let addr = Address(self.address.load(Ordering::Acquire));6x
89 if addr.enabled() {6x
90 let ecam_addr = addr.to_ecam_addr() | (offset & 0b11);3x
91 self.segment.write(ecam_addr, size, val)3x
92 } else {
93 Ok(Action::None)3x
94 }
95 }
96 _ => Ok(Action::None),3x
97 }
98 }25x
99}
100
101#[derive(Debug)]
102pub struct PciBus {
103 pub io_bus: Arc<PciIoBus>,
104 pub segment: Arc<PciSegment>,
105}
106
107impl PciBus {
108 pub fn new() -> Self {4x
109 let segment = Arc::new(PciSegment::new());4x
110
111 #[cfg(target_arch = "x86_64")]
112 segment.add(Bdf::new(0, 0, 0), Arc::new(HostBridge::new()));2x
113
114 PciBus {4x
115 io_bus: Arc::new(PciIoBus {4x
116 address: AtomicU32::new(0),4x
117 segment: segment.clone(),4x
118 }),4x
119 segment,4x
120 }4x
121 }4x
122
123 pub fn reserve(&self, bdf: Option<Bdf>) -> Option<Bdf> {3x
124 self.segment.reserve(bdf)3x
125 }3x
126
127 pub fn add(&self, bdf: Bdf, dev: Arc<dyn Pci>) -> Option<Arc<dyn Pci>> {3x
128 self.segment.add(bdf, dev)3x
129 }3x
130}
131
132impl Default for PciBus {
133 fn default() -> Self {3x
134 Self::new()3x
135 }3x
136}
137
138#[cfg(test)]
139#[path = "bus_test.rs"]
140mod tests;
141