Skip to main content

pci_core/
bus_cfg.rs

1// Copyright (c) Microsoft Corporation.
2// Licensed under the MIT License.
3
4//! Shared helpers for originating PCI configuration space accesses in bus emulators.
5
6use chipset_device::io::IoResult;
7use chipset_device::io::deferred::DeferredRead;
8use chipset_device::io::deferred::DeferredToken;
9use chipset_device::io::deferred::DeferredWrite;
10use chipset_device::io::deferred::defer_read;
11use chipset_device::io::deferred::defer_write;
12use chipset_device::pci::ByteEnabledDwordRead;
13use chipset_device::pci::ByteEnabledDwordWrite;
14use chipset_device::pci::PciConfigAddress;
15use chipset_device::pci::PciConfigByteEnable;
16use inspect::Inspect;
17use std::task::Context;
18use std::task::Poll;
19use zerocopy::IntoBytes;
20
21/// Callback trait for the [`PciBusCfgAccessHandler`] for bus-specific operations.
22pub trait PciBusCfgAccessCallbacks {
23    /// Dispatches a read to the downstream config-space target.
24    fn read(&mut self, addr: PciConfigAddress, value: ByteEnabledDwordRead<'_>) -> IoResult;
25
26    /// Dispatches a write to the downstream config-space target.
27    fn write(&mut self, addr: PciConfigAddress, value: ByteEnabledDwordWrite) -> IoResult;
28}
29
30/// A pending config space access that was deferred by a downstream device.
31#[derive(Inspect)]
32#[inspect(tag = "kind")]
33enum DeferredCfgAccess {
34    /// A read that was deferred by a downstream device.
35    Read {
36        #[inspect(skip)]
37        deferred_device_read: DeferredToken,
38        #[inspect(skip)]
39        bus_read: DeferredRead,
40        addr: PciConfigAddress,
41        byte_enable: PciConfigByteEnable,
42    },
43    /// A write that was deferred by a downstream device.
44    Write {
45        #[inspect(skip)]
46        deferred_device_write: DeferredToken,
47        #[inspect(skip)]
48        bus_write: DeferredWrite,
49        addr: PciConfigAddress,
50    },
51}
52
53/// A handler for managing PCI config space accesses to downstream devices.
54#[derive(Default, Inspect)]
55pub struct PciBusCfgAccessHandler {
56    #[inspect(with = "|x| x.is_some()")]
57    waker: Option<std::task::Waker>,
58    #[inspect(iter_by_index)]
59    actions: Vec<DeferredCfgAccess>,
60}
61
62impl PciBusCfgAccessHandler {
63    /// Creates an empty deferred-access tracker.
64    pub fn new() -> Self {
65        Self {
66            waker: None,
67            actions: Vec::new(),
68        }
69    }
70
71    /// Returns whether there are no deferred accesses pending.
72    pub fn is_empty(&self) -> bool {
73        self.actions.is_empty()
74    }
75
76    /// Handles a config space read request.
77    pub fn read(
78        &mut self,
79        addr: PciConfigAddress,
80        mut inline_completion_value: ByteEnabledDwordRead<'_>,
81        callbacks: &mut impl PciBusCfgAccessCallbacks,
82    ) -> IoResult {
83        match callbacks.read(addr, inline_completion_value.reborrow()) {
84            IoResult::Ok => IoResult::Ok,
85            IoResult::Err(err) => IoResult::Err(err),
86            IoResult::Defer(deferred_device_read) => {
87                let (bus_read, bus_token) = defer_read();
88                self.push_action(DeferredCfgAccess::Read {
89                    deferred_device_read,
90                    bus_read,
91                    addr,
92                    byte_enable: inline_completion_value.byte_enable(),
93                });
94                IoResult::Defer(bus_token)
95            }
96        }
97    }
98
99    /// Handles a config space write request.
100    pub fn write(
101        &mut self,
102        addr: PciConfigAddress,
103        value: ByteEnabledDwordWrite,
104        callbacks: &mut impl PciBusCfgAccessCallbacks,
105    ) -> IoResult {
106        let result = callbacks.write(addr, value);
107        if let IoResult::Defer(deferred_device_write) = result {
108            let (bus_write, bus_token) = defer_write();
109            self.push_action(DeferredCfgAccess::Write {
110                deferred_device_write,
111                bus_write,
112                addr,
113            });
114            return IoResult::Defer(bus_token);
115        }
116
117        result
118    }
119
120    /// Polls pending accesses and keeps any that are still incomplete.
121    pub fn poll(&mut self, cx: &mut Context<'_>) {
122        self.waker = Some(cx.waker().clone());
123        self.actions = std::mem::take(&mut self.actions)
124            .into_iter()
125            .filter_map(|action| match action {
126                DeferredCfgAccess::Read {
127                    mut deferred_device_read,
128                    bus_read,
129                    addr,
130                    byte_enable,
131                } => {
132                    // If the inner read is ready, complete the outer read accordingly.
133                    let mut dword_buffer = 0;
134                    if let Poll::Ready(res) =
135                        deferred_device_read.poll_read(cx, dword_buffer.as_mut_bytes())
136                    {
137                        match res {
138                            Ok(()) => {
139                                let (byte_offset, len) = byte_enable.to_byte_offset_len();
140                                let byte_offset = byte_offset as usize;
141                                bus_read.complete(
142                                    &dword_buffer.as_bytes()[byte_offset..byte_offset + len],
143                                );
144                            }
145                            Err(err) => bus_read.complete_error(err),
146                        }
147                        None
148                    } else {
149                        // If the inner read is not ready, keep the outer read pending and
150                        // leave the deferred action in the list for the next poll.
151                        Some(DeferredCfgAccess::Read {
152                            deferred_device_read,
153                            bus_read,
154                            addr,
155                            byte_enable,
156                        })
157                    }
158                }
159                DeferredCfgAccess::Write {
160                    mut deferred_device_write,
161                    bus_write,
162                    addr,
163                } => {
164                    // If the inner write completed, complete the outer write accordingly.
165                    if let Poll::Ready(res) = deferred_device_write.poll_write(cx) {
166                        match res {
167                            Ok(()) => bus_write.complete(),
168                            Err(err) => bus_write.complete_error(err),
169                        }
170                        None
171                    } else {
172                        // If the inner write is not ready, keep the outer write pending and
173                        // leave the deferred action in the list for the next poll.
174                        Some(DeferredCfgAccess::Write {
175                            deferred_device_write,
176                            bus_write,
177                            addr,
178                        })
179                    }
180                }
181            })
182            .collect();
183    }
184
185    fn push_action(&mut self, action: DeferredCfgAccess) {
186        self.actions.push(action);
187        if let Some(waker) = self.waker.take() {
188            waker.wake();
189        }
190    }
191}
192
193#[cfg(test)]
194mod tests {
195    use super::*;
196    use chipset_device::io::IoError;
197
198    #[derive(Clone, Copy)]
199    enum ReadAction {
200        Ok(u32),
201        Err(IoError),
202        Defer,
203    }
204
205    #[derive(Clone, Copy)]
206    enum WriteAction {
207        Ok,
208        Err(IoError),
209        Defer,
210    }
211
212    struct DeferredCallbacks {
213        read_action: ReadAction,
214        write_action: WriteAction,
215        pending_read: Option<DeferredRead>,
216        pending_write: Option<DeferredWrite>,
217        reads: Vec<PciConfigAddress>,
218        writes: Vec<(PciConfigAddress, u32)>,
219    }
220
221    impl DeferredCallbacks {
222        fn new(read_action: ReadAction, write_action: WriteAction) -> Self {
223            Self {
224                read_action,
225                write_action,
226                pending_read: None,
227                pending_write: None,
228                reads: Vec::new(),
229                writes: Vec::new(),
230            }
231        }
232
233        fn complete_read(&mut self, value: u32) {
234            self.pending_read
235                .take()
236                .unwrap()
237                .complete(&value.as_bytes()[..4]);
238        }
239
240        fn complete_read_error(&mut self, error: IoError) {
241            self.pending_read.take().unwrap().complete_error(error);
242        }
243
244        fn complete_write(&mut self) {
245            self.pending_write.take().unwrap().complete();
246        }
247
248        fn complete_write_error(&mut self, error: IoError) {
249            self.pending_write.take().unwrap().complete_error(error);
250        }
251    }
252
253    impl PciBusCfgAccessCallbacks for DeferredCallbacks {
254        fn read(
255            &mut self,
256            addr: PciConfigAddress,
257            mut value: ByteEnabledDwordRead<'_>,
258        ) -> IoResult {
259            self.reads.push(addr);
260            match self.read_action {
261                ReadAction::Ok(read_value) => {
262                    value.set(read_value);
263                    IoResult::Ok
264                }
265                ReadAction::Err(error) => IoResult::Err(error),
266                ReadAction::Defer => {
267                    let (deferred, token) = defer_read();
268                    assert!(self.pending_read.replace(deferred).is_none());
269                    IoResult::Defer(token)
270                }
271            }
272        }
273
274        fn write(&mut self, addr: PciConfigAddress, value: ByteEnabledDwordWrite) -> IoResult {
275            self.writes.push((addr, value.extract()));
276            match self.write_action {
277                WriteAction::Ok => IoResult::Ok,
278                WriteAction::Err(error) => IoResult::Err(error),
279                WriteAction::Defer => {
280                    let (deferred, token) = defer_write();
281                    assert!(self.pending_write.replace(deferred).is_none());
282                    IoResult::Defer(token)
283                }
284            }
285        }
286    }
287
288    fn poll_once(handler: &mut PciBusCfgAccessHandler) {
289        let mut cx = Context::from_waker(std::task::Waker::noop());
290        handler.poll(&mut cx);
291    }
292
293    fn poll_read_token(token: &mut DeferredToken, bytes: &mut [u8]) -> Poll<Result<(), IoError>> {
294        let mut cx = Context::from_waker(std::task::Waker::noop());
295        token.poll_read(&mut cx, bytes)
296    }
297
298    fn poll_write_token(token: &mut DeferredToken) -> Poll<Result<(), IoError>> {
299        let mut cx = Context::from_waker(std::task::Waker::noop());
300        token.poll_write(&mut cx)
301    }
302
303    #[test]
304    fn immediate_read_applies_byte_enable() {
305        let mut handler = PciBusCfgAccessHandler::new();
306        let mut callbacks = DeferredCallbacks::new(ReadAction::Ok(0x1122_3344), WriteAction::Ok);
307        let addr = PciConfigAddress::new(0, 0, 1).unwrap();
308        let mut buffer = 0xffff_ffff;
309        let value = ByteEnabledDwordRead::new(&mut buffer, PciConfigByteEnable::HIGH_WORD);
310
311        assert!(matches!(
312            handler.read(addr, value, &mut callbacks),
313            IoResult::Ok
314        ));
315        assert_eq!(callbacks.reads, vec![addr]);
316        assert_eq!(buffer, 0x1122_ffff);
317    }
318
319    #[test]
320    fn immediate_read_error_is_returned() {
321        let mut handler = PciBusCfgAccessHandler::new();
322        let mut callbacks =
323            DeferredCallbacks::new(ReadAction::Err(IoError::InvalidRegister), WriteAction::Ok);
324        let addr = PciConfigAddress::new(0, 0, 1).unwrap();
325        let mut buffer = 0;
326        let value = ByteEnabledDwordRead::with_all_bytes_enabled(&mut buffer);
327
328        assert!(matches!(
329            handler.read(addr, value, &mut callbacks),
330            IoResult::Err(IoError::InvalidRegister)
331        ));
332        assert_eq!(callbacks.reads, vec![addr]);
333    }
334
335    #[test]
336    fn deferred_read_applies_byte_enable() {
337        let mut handler = PciBusCfgAccessHandler::new();
338        let mut callbacks = DeferredCallbacks::new(ReadAction::Defer, WriteAction::Ok);
339        let addr = PciConfigAddress::new(0, 0, 1).unwrap();
340        let mut buffer = 0xffff_ffff;
341        let value = ByteEnabledDwordRead::new(&mut buffer, PciConfigByteEnable::HIGH_WORD);
342
343        let IoResult::Defer(mut bus_token) = handler.read(addr, value, &mut callbacks) else {
344            panic!("read should defer");
345        };
346
347        callbacks.complete_read(0x1122_3344);
348        poll_once(&mut handler);
349
350        let mut read_data = [0; 2];
351        assert!(matches!(
352            poll_read_token(&mut bus_token, &mut read_data),
353            Poll::Ready(Ok(()))
354        ));
355
356        assert_eq!(read_data, [0x22, 0x11]);
357    }
358
359    #[test]
360    fn deferred_read_error_completes_outer_read_with_error() {
361        let mut handler = PciBusCfgAccessHandler::new();
362        let mut callbacks = DeferredCallbacks::new(ReadAction::Defer, WriteAction::Ok);
363        let addr = PciConfigAddress::new(0, 0, 1).unwrap();
364        let mut buffer = 0;
365        let value = ByteEnabledDwordRead::with_all_bytes_enabled(&mut buffer);
366
367        let IoResult::Defer(mut bus_token) = handler.read(addr, value, &mut callbacks) else {
368            panic!("read should defer");
369        };
370
371        callbacks.complete_read_error(IoError::NoResponse);
372        poll_once(&mut handler);
373
374        let mut read_data = [0; 4];
375        assert!(matches!(
376            poll_read_token(&mut bus_token, &mut read_data),
377            Poll::Ready(Err(IoError::NoResponse))
378        ));
379    }
380
381    #[test]
382    fn partial_writes_do_not_read_for_write() {
383        let mut handler = PciBusCfgAccessHandler::new();
384        let mut callbacks = DeferredCallbacks::new(ReadAction::Ok(0x1122_3344), WriteAction::Ok);
385        let addr = PciConfigAddress::new(0, 0, 1).unwrap();
386        let write_value = ByteEnabledDwordWrite::new(0xaa00, PciConfigByteEnable::BYTE1);
387
388        assert!(matches!(
389            handler.write(addr, write_value, &mut callbacks),
390            IoResult::Ok
391        ));
392        assert_eq!(callbacks.reads, vec![]);
393        assert_eq!(callbacks.writes, vec![(addr, 0x0000_aa00)]);
394    }
395
396    #[test]
397    fn immediate_write_error_is_returned() {
398        let mut handler = PciBusCfgAccessHandler::new();
399        let mut callbacks = DeferredCallbacks::new(
400            ReadAction::Ok(0x1122_3344),
401            WriteAction::Err(IoError::InvalidRegister),
402        );
403        let addr = PciConfigAddress::new(0, 0, 1).unwrap();
404        let write_value = ByteEnabledDwordWrite::new(0xaa00, PciConfigByteEnable::BYTE1);
405
406        assert!(matches!(
407            handler.write(addr, write_value, &mut callbacks),
408            IoResult::Err(IoError::InvalidRegister)
409        ));
410        assert_eq!(callbacks.writes, vec![(addr, 0x0000_aa00)]);
411    }
412
413    #[test]
414    fn deferred_writes_complete_outer_write() {
415        let mut handler = PciBusCfgAccessHandler::new();
416        let mut callbacks = DeferredCallbacks::new(ReadAction::Ok(0), WriteAction::Defer);
417        let addr = PciConfigAddress::new(0, 0, 1).unwrap();
418        let write_value = ByteEnabledDwordWrite::with_all_bytes_enabled(0xaabb_ccdd);
419
420        let IoResult::Defer(mut bus_token) = handler.write(addr, write_value, &mut callbacks)
421        else {
422            panic!("write should defer");
423        };
424
425        callbacks.complete_write();
426        poll_once(&mut handler);
427
428        assert!(matches!(
429            poll_write_token(&mut bus_token),
430            Poll::Ready(Ok(()))
431        ));
432    }
433
434    #[test]
435    fn deferred_write_error_completes_outer_write_with_error() {
436        let mut handler = PciBusCfgAccessHandler::new();
437        let mut callbacks = DeferredCallbacks::new(ReadAction::Ok(0), WriteAction::Defer);
438        let addr = PciConfigAddress::new(0, 0, 1).unwrap();
439        let write_value = ByteEnabledDwordWrite::with_all_bytes_enabled(0xaabb_ccdd);
440
441        let IoResult::Defer(mut bus_token) = handler.write(addr, write_value, &mut callbacks)
442        else {
443            panic!("write should defer");
444        };
445
446        callbacks.complete_write_error(IoError::NoResponse);
447        poll_once(&mut handler);
448
449        assert!(matches!(
450            poll_write_token(&mut bus_token),
451            Poll::Ready(Err(IoError::NoResponse))
452        ));
453    }
454}