Skip to main content

fake_pci/
lib.rs

1// Copyright 2026 The Fuchsia 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//! A fake PCI device server for testing Fuchsia drivers.
6
7#![deny(missing_docs)]
8
9use arrayvec::ArrayVec;
10use core::fmt::Debug;
11use fidl_fuchsia_driver_framework as fdf;
12use fidl_next::{Request, Responder};
13use fidl_next_fuchsia_hardware_pci::{self as fpci, DeviceServerHandler};
14use fuchsia_async as fasync;
15use fuchsia_component::server::{ServiceFs, ServiceObjTrait};
16use fuchsia_sync::Mutex;
17use std::collections::HashMap;
18use std::mem::size_of;
19use std::sync::Arc;
20
21const BASE_CONFIG_SIZE: usize = 256;
22const CONFIG_HEADER_SIZE: usize = 64;
23const MSI_MAX_VECTORS: u32 = 32;
24const MSIX_MAX_VECTORS: u32 = 8;
25const PCI_EXPRESS_CAPABILITY_SIZE: u8 = 0x3B;
26
27// Note: IO BARs are not currently supported.
28enum Bar {
29    Vmo { size: u64, vmo: zx::Vmo },
30}
31
32impl Bar {
33    fn to_fidl(&self, bar_id: u32) -> Result<fpci::Bar, zx::Status> {
34        match self {
35            Self::Vmo { size, vmo } => {
36                let vmo_dup = vmo.duplicate_handle(zx::Rights::SAME_RIGHTS)?;
37                Ok(fpci::Bar { bar_id, size: *size, result: fpci::BarResult::Vmo(vmo_dup) })
38            }
39        }
40    }
41}
42
43#[derive(Clone, Debug, PartialEq, Eq)]
44struct Capability {
45    id: fpci::CapabilityId,
46    position: u8,
47    size: u8,
48}
49
50struct State {
51    device_info: fpci::DeviceInfo,
52    bus_mastering: Option<bool>,
53    config: Vec<u8>,
54    bars: [Option<Bar>; fpci::MAX_BAR_COUNT as usize],
55    btis: HashMap<u32, zx::Bti>,
56    capabilities: Vec<Capability>,
57    legacy_interrupt: Option<Arc<zx::VirtualInterrupt>>,
58    msi_interrupts: ArrayVec<Arc<zx::VirtualInterrupt>, { MSI_MAX_VECTORS as usize }>,
59    msix_interrupts: ArrayVec<Arc<zx::VirtualInterrupt>, { MSIX_MAX_VECTORS as usize }>,
60    interrupt_mode: fpci::InterruptMode,
61    requested_irq_count: u32,
62    reset_count: u32,
63}
64
65impl State {
66    fn new() -> Self {
67        Self {
68            device_info: fpci::DeviceInfo {
69                vendor_id: 0,
70                device_id: 0,
71                base_class: 0,
72                sub_class: 0,
73                program_interface: 0,
74                revision_id: 0,
75                bus_id: 0,
76                dev_id: 0,
77                func_id: 0,
78                padding: (),
79            },
80            bus_mastering: None,
81            config: vec![0u8; BASE_CONFIG_SIZE],
82            bars: Default::default(),
83            btis: HashMap::new(),
84            capabilities: Vec::new(),
85            legacy_interrupt: None,
86            msi_interrupts: ArrayVec::new(),
87            msix_interrupts: ArrayVec::new(),
88            interrupt_mode: fpci::InterruptMode::Disabled,
89            requested_irq_count: 0,
90            reset_count: 0,
91        }
92    }
93
94    fn write_raw(&mut self, offset: usize, bytes: &[u8]) {
95        self.config[offset..offset + bytes.len()].copy_from_slice(bytes);
96    }
97
98    fn config_slice(&self, offset: u16, length: usize) -> Result<&[u8], zx::Status> {
99        let start = usize::from(offset);
100        let end = start.checked_add(length).ok_or(zx::Status::OUT_OF_RANGE)?;
101        if end > BASE_CONFIG_SIZE {
102            return Err(zx::Status::OUT_OF_RANGE);
103        }
104        Ok(&self.config[start..end])
105    }
106
107    fn config_slice_mut(&mut self, offset: u16, length: usize) -> Result<&mut [u8], zx::Status> {
108        let start = usize::from(offset);
109        let end = start.checked_add(length).ok_or(zx::Status::OUT_OF_RANGE)?;
110        // We only allow config to be written past the header.
111        if start < CONFIG_HEADER_SIZE || end > BASE_CONFIG_SIZE {
112            return Err(zx::Status::OUT_OF_RANGE);
113        }
114        Ok(&mut self.config[start..end])
115    }
116
117    fn read_config8(&self, offset: u16) -> Result<u8, zx::Status> {
118        let slice = self.config_slice(offset, size_of::<u8>())?;
119        Ok(slice[0])
120    }
121
122    fn read_config16(&self, offset: u16) -> Result<u16, zx::Status> {
123        let slice = self.config_slice(offset, size_of::<u16>())?;
124        Ok(u16::from_le_bytes(slice.try_into().unwrap()))
125    }
126
127    fn read_config32(&self, offset: u16) -> Result<u32, zx::Status> {
128        let slice = self.config_slice(offset, size_of::<u32>())?;
129        Ok(u32::from_le_bytes(slice.try_into().unwrap()))
130    }
131
132    fn write_config8(&mut self, offset: u16, value: u8) -> Result<(), zx::Status> {
133        let slice = self.config_slice_mut(offset, size_of::<u8>())?;
134        slice[0] = value;
135        Ok(())
136    }
137
138    fn write_config16(&mut self, offset: u16, value: u16) -> Result<(), zx::Status> {
139        let slice = self.config_slice_mut(offset, size_of::<u16>())?;
140        slice.copy_from_slice(&value.to_le_bytes());
141        Ok(())
142    }
143
144    fn write_config32(&mut self, offset: u16, value: u32) -> Result<(), zx::Status> {
145        let slice = self.config_slice_mut(offset, size_of::<u32>())?;
146        slice.copy_from_slice(&value.to_le_bytes());
147        Ok(())
148    }
149
150    fn set_device_info(&mut self, info: fpci::DeviceInfo) {
151        self.device_info = info;
152        self.write_raw(u16::from(fpci::Config::VendorId).into(), &info.vendor_id.to_le_bytes());
153        self.write_raw(u16::from(fpci::Config::DeviceId).into(), &info.device_id.to_le_bytes());
154        self.write_raw(u16::from(fpci::Config::RevisionId).into(), &info.revision_id.to_le_bytes());
155        self.write_raw(
156            u16::from(fpci::Config::ClassCodeBase).into(),
157            &info.base_class.to_le_bytes(),
158        );
159        self.write_raw(u16::from(fpci::Config::ClassCodeSub).into(), &info.sub_class.to_le_bytes());
160        self.write_raw(
161            u16::from(fpci::Config::ClassCodeIntr).into(),
162            &info.program_interface.to_le_bytes(),
163        );
164    }
165
166    fn add_capability(&mut self, capability_id: fpci::CapabilityId, position: u8, size: u8) {
167        assert!(
168            !matches!(capability_id, fpci::CapabilityId::UnknownOrdinal_(_)),
169            "Unknown capability ID is forbidden"
170        );
171        let pos = usize::from(position);
172        let sz = usize::from(size);
173        assert!(
174            pos >= CONFIG_HEADER_SIZE && pos + sz <= BASE_CONFIG_SIZE,
175            "capability must fit the range [0x{CONFIG_HEADER_SIZE:X}, 0x{BASE_CONFIG_SIZE:X}]"
176        );
177
178        for cap in &self.capabilities {
179            let cap_pos = usize::from(cap.position);
180            let cap_sz = usize::from(cap.size);
181            let overlap = (pos < cap_pos + cap_sz) && (pos + sz > cap_pos);
182            assert!(!overlap, "New capability overlaps with a previous capability {cap:?}");
183        }
184
185        let next_ptr = if self.capabilities.is_empty() {
186            usize::from(u16::from(fpci::Config::CapabilitiesPtr))
187        } else {
188            usize::from(self.capabilities.last().unwrap().position) + 1
189        };
190
191        self.write_raw(pos, &[u8::from(capability_id)]);
192        self.write_raw(next_ptr, &[position]);
193
194        self.capabilities.push(Capability { id: capability_id, position, size });
195        self.capabilities.sort_by_key(|c| c.position);
196    }
197
198    fn add_vendor_capability(&mut self, position: u8, size: u8) {
199        assert!(size > 2, "vendor capability must be at least size 3");
200        self.add_capability(fpci::CapabilityId::Vendor, position, size);
201        // Vendor capabilities store a size at the byte following the next
202        // pointer.
203        self.write_raw(usize::from(position) + 2, &[size]);
204    }
205
206    fn add_pci_express_capability(&mut self, position: u8) {
207        self.add_capability(fpci::CapabilityId::PciExpress, position, PCI_EXPRESS_CAPABILITY_SIZE);
208    }
209
210    fn get_capabilities(&self, id: fpci::CapabilityId) -> Vec<u8> {
211        let mut offsets = Vec::new();
212        let mut current_offset: Option<u8> = None;
213
214        while let Some(found_offset) = self.common_capability_search(id, current_offset) {
215            offsets.push(found_offset);
216            current_offset = Some(found_offset);
217        }
218        offsets
219    }
220
221    fn common_capability_search(&self, id: fpci::CapabilityId, offset: Option<u8>) -> Option<u8> {
222        for cap in &self.capabilities {
223            if offset.is_some_and(|off| cap.position <= off) {
224                continue;
225            }
226            if cap.id == id {
227                return Some(cap.position);
228            }
229        }
230        None
231    }
232
233    fn all_mapped_interrupts_freed(&self) -> bool {
234        let legacy = self.legacy_interrupt.as_ref().into_iter();
235        for irq in legacy.chain(self.msi_interrupts.iter()).chain(self.msix_interrupts.iter()) {
236            let info = irq.count_info().expect("get irq info");
237            // We only expect the interrupt handle FakePci created to still be
238            // in use.
239            if info.handle_count > 1 {
240                return false;
241            }
242        }
243        true
244    }
245
246    fn get_interrupt_modes(&self) -> fpci::InterruptModes {
247        let has_legacy = self.legacy_interrupt.is_some();
248        let msi_count = if self.msi_interrupts.is_empty() {
249            0
250        } else if self.msi_interrupts.len() == 1 {
251            1
252        } else {
253            let len = u8::try_from(self.msi_interrupts.len()).unwrap();
254            1 << (7 - len.leading_zeros())
255        };
256        let msix_count = u16::try_from(self.msix_interrupts.len()).unwrap();
257        fpci::InterruptModes { has_legacy, msi_count, msix_count }
258    }
259
260    fn set_interrupt_mode(
261        &mut self,
262        mode: fpci::InterruptMode,
263        requested_irq_count: u32,
264    ) -> Result<(), zx::Status> {
265        if !self.all_mapped_interrupts_freed() {
266            return Err(zx::Status::BAD_STATE);
267        }
268        match mode {
269            fpci::InterruptMode::Disabled => {
270                self.interrupt_mode = mode;
271                self.requested_irq_count = 0;
272                Ok(())
273            }
274            fpci::InterruptMode::Legacy => {
275                if requested_irq_count > 1 {
276                    return Err(zx::Status::INVALID_ARGS);
277                }
278                if self.legacy_interrupt.is_none() {
279                    return Err(zx::Status::NOT_SUPPORTED);
280                }
281                self.interrupt_mode = mode;
282                self.requested_irq_count = 1;
283                Ok(())
284            }
285            fpci::InterruptMode::Msi => {
286                if self.msi_interrupts.is_empty() {
287                    return Err(zx::Status::NOT_SUPPORTED);
288                }
289                if requested_irq_count == 0
290                    || !requested_irq_count.is_power_of_two()
291                    || requested_irq_count > MSI_MAX_VECTORS
292                {
293                    return Err(zx::Status::INVALID_ARGS);
294                }
295                if u32::try_from(self.msi_interrupts.len()).unwrap() < requested_irq_count {
296                    return Err(zx::Status::INVALID_ARGS);
297                }
298                self.interrupt_mode = mode;
299                self.requested_irq_count = requested_irq_count;
300                Ok(())
301            }
302            fpci::InterruptMode::MsiX => {
303                if self.msix_interrupts.is_empty() {
304                    return Err(zx::Status::NOT_SUPPORTED);
305                }
306                if requested_irq_count == 0 || requested_irq_count > MSIX_MAX_VECTORS {
307                    return Err(zx::Status::INVALID_ARGS);
308                }
309                if u32::try_from(self.msix_interrupts.len()).unwrap() < requested_irq_count {
310                    return Err(zx::Status::INVALID_ARGS);
311                }
312                self.interrupt_mode = mode;
313                self.requested_irq_count = requested_irq_count;
314                Ok(())
315            }
316        }
317    }
318
319    fn map_interrupt(&self, which_irq: u32) -> Result<zx::Interrupt, zx::Status> {
320        match self.interrupt_mode {
321            fpci::InterruptMode::Legacy => {
322                if which_irq > 0 {
323                    return Err(zx::Status::INVALID_ARGS);
324                }
325                let irq = self.legacy_interrupt.as_ref().ok_or(zx::Status::BAD_STATE)?;
326                Ok(zx::Interrupt::from(
327                    irq.duplicate_handle(zx::Rights::SAME_RIGHTS)
328                        .expect("duplicate irq")
329                        .into_handle(),
330                ))
331            }
332            fpci::InterruptMode::Msi => {
333                let which = usize::try_from(which_irq).unwrap();
334                if which >= usize::try_from(self.requested_irq_count).unwrap() {
335                    return Err(zx::Status::INVALID_ARGS);
336                }
337                let irq = self.msi_interrupts.get(which).ok_or(zx::Status::INVALID_ARGS)?;
338                Ok(zx::Interrupt::from(
339                    irq.duplicate_handle(zx::Rights::SAME_RIGHTS)
340                        .expect("duplicate irq")
341                        .into_handle(),
342                ))
343            }
344            fpci::InterruptMode::MsiX => {
345                let which = usize::try_from(which_irq).unwrap();
346                if which >= usize::try_from(self.requested_irq_count).unwrap() {
347                    return Err(zx::Status::INVALID_ARGS);
348                }
349                let irq = self.msix_interrupts.get(which).ok_or(zx::Status::INVALID_ARGS)?;
350                Ok(zx::Interrupt::from(
351                    irq.duplicate_handle(zx::Rights::SAME_RIGHTS)
352                        .expect("duplicate irq")
353                        .into_handle(),
354                ))
355            }
356            _ => Err(zx::Status::BAD_STATE),
357        }
358    }
359
360    fn ack_interrupt(&self) -> Result<(), zx::Status> {
361        if self.interrupt_mode == fpci::InterruptMode::Legacy {
362            Ok(())
363        } else {
364            Err(zx::Status::BAD_STATE)
365        }
366    }
367}
368
369/// A fake implementation of the [`fpci::Device`] protocol for testing PCI drivers.
370#[derive(Clone)]
371pub struct FakePci {
372    state: Arc<Mutex<State>>,
373}
374
375impl Default for FakePci {
376    fn default() -> Self {
377        Self::new()
378    }
379}
380
381impl FakePci {
382    /// Creates a new empty [`FakePci`] instance.
383    pub fn new() -> Self {
384        Self { state: Arc::new(Mutex::new(State::new())) }
385    }
386
387    /// Sets the [`fpci::DeviceInfo`] for the fake PCI device and populates header fields.
388    pub fn set_device_info(&self, info: fpci::DeviceInfo) {
389        self.state.lock().set_device_info(info);
390    }
391
392    /// Returns the current [`fpci::DeviceInfo`].
393    pub fn device_info(&self) -> fpci::DeviceInfo {
394        self.state.lock().device_info
395    }
396
397    /// Returns whether bus mastering has been enabled, or [`None`] if not set.
398    pub fn bus_master_enabled(&self) -> Option<bool> {
399        self.state.lock().bus_mastering
400    }
401
402    /// Returns the number of times the device has been reset.
403    pub fn reset_count(&self) -> u32 {
404        self.state.lock().reset_count
405    }
406
407    /// Configures a VMO BAR with the given ID and size using an existing [`zx::Vmo`].
408    ///
409    /// # Panics
410    ///
411    /// Panics if `bar_id` is invalid (`>= fpci::MAX_BAR_COUNT`), or if a BAR has
412    /// already been set for `bar_id`.
413    pub fn add_vmo_bar(&self, bar_id: u32, size: u64, vmo: zx::Vmo) {
414        assert!(
415            self.state
416                .lock()
417                .bars
418                .get_mut(bar_id as usize)
419                .expect("invalid bar id")
420                .replace(Bar::Vmo { size, vmo })
421                .is_none(),
422            "{bar_id} already set"
423        );
424    }
425
426    /// Creates and configures a new VMO BAR with the given ID and size.
427    ///
428    /// # Panics
429    ///
430    /// Panics if VMO creation fails, or under the same conditions as
431    /// [`Self::add_vmo_bar`].
432    pub fn create_vmo_bar(&self, bar_id: u32, size: u64) {
433        self.add_vmo_bar(bar_id, size, zx::Vmo::create(size).unwrap());
434    }
435
436    /// Returns a duplicated handle to the [`zx::Vmo`] associated with `bar_id`, if present.
437    pub fn vmo_bar(&self, bar_id: u32) -> Option<zx::Vmo> {
438        let state = self.state.lock();
439        let Bar::Vmo { size: _, vmo } =
440            state.bars.get(bar_id as usize).expect("invalid bar id").as_ref()?;
441        Some(vmo.duplicate_handle(zx::Rights::SAME_RIGHTS).unwrap())
442    }
443
444    /// Registers a [`zx::Bti`] handle at the given index.
445    ///
446    /// # Panics
447    ///
448    /// Panics if a BTI is already registered at `index`.
449    pub fn add_bti(&self, index: u32, bti: zx::Bti) {
450        assert!(self.state.lock().btis.insert(index, bti).is_none());
451    }
452
453    /// Adds a PCI capability at the specified offset in configuration space.
454    ///
455    /// # Panics
456    ///
457    /// Panics if:
458    /// - `id` is an unknown capability ordinal.
459    /// - `position` is in the configuration header or the capability
460    ///   exceeds configuration space bounds.
461    /// - The capability overlaps with a previously added capability.
462    pub fn add_capability(&self, id: fpci::CapabilityId, position: u8, size: u8) {
463        self.state.lock().add_capability(id, position, size);
464    }
465
466    /// Adds a vendor-specific PCI capability at the specified offset.
467    ///
468    /// # Panics
469    ///
470    /// Panics if `size <= 2`, or under the same conditions as
471    /// [`Self::add_capability`].
472    pub fn add_vendor_capability(&self, position: u8, size: u8) {
473        self.state.lock().add_vendor_capability(position, size);
474    }
475
476    /// Adds a PCI Express capability at the specified offset.
477    ///
478    /// # Panics
479    ///
480    /// Panics under the same conditions as [`Self::add_capability`].
481    pub fn add_pci_express_capability(&self, position: u8) {
482        self.state.lock().add_pci_express_capability(position);
483    }
484
485    /// Adds a legacy virtual interrupt and returns its [`zx::VirtualInterrupt`].
486    ///
487    /// # Panics
488    ///
489    /// Panics if creation of the virtual interrupt fails, or if a legacy
490    /// interrupt has already been added.
491    pub fn add_legacy_interrupt(&self) -> Arc<zx::VirtualInterrupt> {
492        let virq = Arc::new(
493            zx::VirtualInterrupt::create_virtual().expect("Failed to create virtual interrupt"),
494        );
495        let mut state = self.state.lock();
496        assert!(state.legacy_interrupt.is_none(), "Legacy interrupt already added");
497        state.legacy_interrupt = Some(virq.clone());
498        virq
499    }
500
501    /// Adds an MSI virtual interrupt and returns its [`zx::VirtualInterrupt`].
502    ///
503    /// Subsequent calls populate interrupts at incrementing indices.
504    ///
505    /// # Panics
506    ///
507    /// Panics if creation of the virtual interrupt fails, or if the number of
508    /// MSI interrupts exceeds the protocol maximum.
509    pub fn add_msi_interrupt(&self) -> Arc<zx::VirtualInterrupt> {
510        let virq = Arc::new(
511            zx::VirtualInterrupt::create_virtual().expect("Failed to create virtual interrupt"),
512        );
513        let mut state = self.state.lock();
514        state.msi_interrupts.push(virq.clone());
515        virq
516    }
517
518    /// Adds an MSI-X virtual interrupt and returns its [`zx::VirtualInterrupt`].
519    ///
520    /// Subsequent calls populate interrupts at incrementing indices.
521    ///
522    /// # Panics
523    ///
524    /// Panics if creation of the virtual interrupt fails, or if the number of
525    /// MSI-X interrupts exceeds the protocol maximum.
526    pub fn add_msix_interrupt(&self) -> Arc<zx::VirtualInterrupt> {
527        let virq = Arc::new(
528            zx::VirtualInterrupt::create_virtual().expect("Failed to create virtual interrupt"),
529        );
530        let mut state = self.state.lock();
531        state.msix_interrupts.push(virq.clone());
532        virq
533    }
534
535    /// Returns the currently configured [`fpci::InterruptMode`].
536    pub fn interrupt_mode(&self) -> fpci::InterruptMode {
537        self.state.lock().interrupt_mode
538    }
539
540    /// Returns the number of requested interrupt vectors.
541    pub fn requested_irq_count(&self) -> u32 {
542        self.state.lock().requested_irq_count
543    }
544
545    /// Reads an 8-bit value from configuration space at `offset`.
546    ///
547    /// # Panics
548    ///
549    /// Panics if the read exceeds configuration space bounds.
550    pub fn read_config8(&self, offset: u16) -> u8 {
551        self.state.lock().read_config8(offset).expect("read_config8 failed")
552    }
553
554    /// Reads a 16-bit value from configuration space at `offset`.
555    ///
556    /// # Panics
557    ///
558    /// Panics if the read exceeds configuration space bounds.
559    pub fn read_config16(&self, offset: u16) -> u16 {
560        self.state.lock().read_config16(offset).expect("read_config16 failed")
561    }
562
563    /// Reads a 32-bit value from configuration space at `offset`.
564    ///
565    /// # Panics
566    ///
567    /// Panics if the read exceeds configuration space bounds.
568    pub fn read_config32(&self, offset: u16) -> u32 {
569        self.state.lock().read_config32(offset).expect("read_config32 failed")
570    }
571
572    /// Writes an 8-bit `value` to configuration space at `offset`.
573    ///
574    /// # Panics
575    ///
576    /// Panics if `offset` is in the configuration header or the write
577    /// exceeds configuration space bounds.
578    pub fn write_config8(&self, offset: u16, value: u8) {
579        self.state.lock().write_config8(offset, value).expect("write_config8 failed");
580    }
581
582    /// Writes a 16-bit `value` to configuration space at `offset`.
583    ///
584    /// # Panics
585    ///
586    /// Panics if `offset` is in the configuration header or the write
587    /// exceeds configuration space bounds.
588    pub fn write_config16(&self, offset: u16, value: u16) {
589        self.state.lock().write_config16(offset, value).expect("write_config16 failed");
590    }
591
592    /// Writes a 32-bit `value` to configuration space at `offset`.
593    ///
594    /// # Panics
595    ///
596    /// Panics if `offset` is in the configuration header or the write
597    /// exceeds configuration space bounds.
598    pub fn write_config32(&self, offset: u16, value: u32) {
599        self.state.lock().write_config32(offset, value).expect("write_config32 failed");
600    }
601
602    /// Offers the [`fpci::Service`] to `service_fs` and returns the [`fdf::Offer`].
603    pub fn serve<O: ServiceObjTrait>(
604        &self,
605        service_fs: &mut ServiceFs<O>,
606        scope: fasync::ScopeHandle,
607        instance_name: &str,
608    ) -> fdf::Offer {
609        fdf_component::ServiceOffer::<fpci::Service>::new_next()
610            .add_default_named_next(
611                service_fs,
612                instance_name,
613                Service { state: self.state.clone(), scope },
614            )
615            .build_zircon_offer_next()
616    }
617}
618
619struct Service {
620    state: Arc<Mutex<State>>,
621    scope: fasync::ScopeHandle,
622}
623
624impl fpci::ServiceHandler for Service {
625    fn device(&self, server_end: fidl_next::ServerEnd<fpci::Device>) {
626        server_end.spawn_on(Server { state: self.state.clone() }, &self.scope);
627    }
628}
629
630struct Server {
631    state: Arc<Mutex<State>>,
632}
633
634impl DeviceServerHandler for Server {
635    async fn get_device_info(&mut self, responder: Responder<fpci::device::GetDeviceInfo>) {
636        let info = self.state.lock().device_info;
637        responder.respond(&info).await.expect_respond("get_device_info");
638    }
639
640    async fn get_bar(
641        &mut self,
642        request: Request<fpci::device::GetBar>,
643        responder: Responder<fpci::device::GetBar>,
644    ) {
645        let bar_id = request.payload().bar_id;
646        let result = {
647            let state = self.state.lock();
648            match state.bars.get(bar_id as usize).as_ref() {
649                None => Err(zx::Status::INVALID_ARGS),
650                Some(None) => Err(zx::Status::NOT_FOUND),
651                Some(Some(bar)) => bar.to_fidl(bar_id),
652            }
653        };
654        match result {
655            Ok(bar) => {
656                responder.respond(bar).await.expect_respond("get_bar");
657            }
658            Err(e) => {
659                responder.respond_err(e).await.expect_respond("get_bar");
660            }
661        }
662    }
663
664    async fn set_bus_mastering(
665        &mut self,
666        request: Request<fpci::device::SetBusMastering>,
667        responder: Responder<fpci::device::SetBusMastering>,
668    ) {
669        self.state.lock().bus_mastering = Some(request.payload().enabled);
670        responder.respond(()).await.expect_respond("set_bus_mastering");
671    }
672
673    async fn reset_device(&mut self, responder: Responder<fpci::device::ResetDevice>) {
674        self.state.lock().reset_count += 1;
675        responder.respond(()).await.expect_respond("reset_device");
676    }
677
678    async fn ack_interrupt(&mut self, responder: Responder<fpci::device::AckInterrupt>) {
679        let result = self.state.lock().ack_interrupt();
680        match result {
681            Ok(()) => {
682                responder.respond(()).await.expect_respond("ack_interrupt");
683            }
684            Err(e) => {
685                responder.respond_err(e).await.expect_respond("ack_interrupt");
686            }
687        }
688    }
689
690    async fn map_interrupt(
691        &mut self,
692        request: Request<fpci::device::MapInterrupt>,
693        responder: Responder<fpci::device::MapInterrupt>,
694    ) {
695        let which_irq = request.payload().which_irq;
696        let result = self.state.lock().map_interrupt(which_irq);
697        match result {
698            Ok(interrupt) => {
699                responder.respond(interrupt).await.expect_respond("map_interrupt");
700            }
701            Err(e) => {
702                responder.respond_err(e).await.expect_respond("map_interrupt");
703            }
704        }
705    }
706
707    async fn get_interrupt_modes(&mut self, responder: Responder<fpci::device::GetInterruptModes>) {
708        let modes = self.state.lock().get_interrupt_modes();
709        responder.respond(&modes).await.expect_respond("get_interrupt_modes");
710    }
711
712    async fn set_interrupt_mode(
713        &mut self,
714        request: Request<fpci::device::SetInterruptMode>,
715        responder: Responder<fpci::device::SetInterruptMode>,
716    ) {
717        let payload = request.payload();
718        let result =
719            self.state.lock().set_interrupt_mode(payload.mode, payload.requested_irq_count);
720        match result {
721            Ok(()) => {
722                responder.respond(()).await.expect_respond("set_interrupt_mode");
723            }
724            Err(e) => {
725                responder.respond_err(e).await.expect_respond("set_interrupt_mode");
726            }
727        }
728    }
729
730    async fn read_config8(
731        &mut self,
732        request: Request<fpci::device::ReadConfig8>,
733        responder: Responder<fpci::device::ReadConfig8>,
734    ) {
735        let res = self.state.lock().read_config8(request.payload().offset);
736        match res {
737            Ok(val) => {
738                responder.respond(val).await.expect_respond("read_config8");
739            }
740            Err(e) => {
741                responder.respond_err(e).await.expect_respond("read_config8");
742            }
743        }
744    }
745
746    async fn read_config16(
747        &mut self,
748        request: Request<fpci::device::ReadConfig16>,
749        responder: Responder<fpci::device::ReadConfig16>,
750    ) {
751        let res = self.state.lock().read_config16(request.payload().offset);
752        match res {
753            Ok(val) => {
754                responder.respond(val).await.expect_respond("read_config16");
755            }
756            Err(e) => {
757                responder.respond_err(e).await.expect_respond("read_config16");
758            }
759        }
760    }
761
762    async fn read_config32(
763        &mut self,
764        request: Request<fpci::device::ReadConfig32>,
765        responder: Responder<fpci::device::ReadConfig32>,
766    ) {
767        let res = self.state.lock().read_config32(request.payload().offset);
768        match res {
769            Ok(val) => {
770                responder.respond(val).await.expect_respond("read_config32");
771            }
772            Err(e) => {
773                responder.respond_err(e).await.expect_respond("read_config32");
774            }
775        }
776    }
777
778    async fn write_config8(
779        &mut self,
780        request: Request<fpci::device::WriteConfig8>,
781        responder: Responder<fpci::device::WriteConfig8>,
782    ) {
783        let payload = request.payload();
784        let res = self.state.lock().write_config8(payload.offset, payload.value);
785        match res {
786            Ok(()) => {
787                responder.respond(()).await.expect_respond("write_config8");
788            }
789            Err(e) => {
790                responder.respond_err(e).await.expect_respond("write_config8");
791            }
792        }
793    }
794
795    async fn write_config16(
796        &mut self,
797        request: Request<fpci::device::WriteConfig16>,
798        responder: Responder<fpci::device::WriteConfig16>,
799    ) {
800        let payload = request.payload();
801        let res = self.state.lock().write_config16(payload.offset, payload.value);
802        match res {
803            Ok(()) => {
804                responder.respond(()).await.expect_respond("write_config16");
805            }
806            Err(e) => {
807                responder.respond_err(e).await.expect_respond("write_config16");
808            }
809        }
810    }
811
812    async fn write_config32(
813        &mut self,
814        request: Request<fpci::device::WriteConfig32>,
815        responder: Responder<fpci::device::WriteConfig32>,
816    ) {
817        let payload = request.payload();
818        let res = self.state.lock().write_config32(payload.offset, payload.value);
819        match res {
820            Ok(()) => {
821                responder.respond(()).await.expect_respond("write_config32");
822            }
823            Err(e) => {
824                responder.respond_err(e).await.expect_respond("write_config32");
825            }
826        }
827    }
828
829    async fn get_capabilities(
830        &mut self,
831        request: Request<fpci::device::GetCapabilities>,
832        responder: Responder<fpci::device::GetCapabilities>,
833    ) {
834        let id = request.payload().id;
835        let offsets = self.state.lock().get_capabilities(id);
836        responder.respond(&offsets).await.expect_respond("get_capabilities");
837    }
838
839    async fn get_extended_capabilities(
840        &mut self,
841        _request: Request<fpci::device::GetExtendedCapabilities>,
842        _responder: Responder<fpci::device::GetExtendedCapabilities>,
843    ) {
844        unimplemented!()
845    }
846
847    async fn get_bti(
848        &mut self,
849        request: Request<fpci::device::GetBti>,
850        responder: Responder<fpci::device::GetBti>,
851    ) {
852        let index = request.payload().index;
853        let result = {
854            let state = self.state.lock();
855            if let Some(bti) = state.btis.get(&index) {
856                bti.duplicate_handle(zx::Rights::SAME_RIGHTS)
857            } else {
858                Err(zx::Status::NOT_FOUND)
859            }
860        };
861        match result {
862            Ok(bti) => {
863                responder.respond(bti).await.expect_respond("get_bti");
864            }
865            Err(e) => {
866                responder.respond_err(e).await.expect_respond("get_bti");
867            }
868        }
869    }
870}
871
872trait RespondExt {
873    fn expect_respond(self, msg: &str);
874}
875
876impl<E: Debug> RespondExt for Result<(), fidl_next::Error<E>> {
877    fn expect_respond(self, msg: &str) {
878        self.unwrap_or_else(|e: fidl_next::Error<_>| {
879            // Allow some errors to pass, panic on everything else.
880            match e {
881                fidl_next::Error::Protocol(fidl_next::ProtocolError::PeerClosed) => {}
882                e => {
883                    panic!("responding {msg}: {e:?}")
884                }
885            }
886        })
887    }
888}
889
890#[cfg(test)]
891mod tests {
892    use super::*;
893    use fake_bti::FakeBti;
894    use fidl_next::fuchsia::create_channel;
895    use fixture::fixture;
896
897    async fn run_test_with_fake<F, Fut>(_test_name: &str, test_func: F)
898    where
899        F: FnOnce(fidl_next::Client<fpci::Device>, FakePci) -> Fut,
900        Fut: std::future::Future<Output = ()>,
901    {
902        let fake_pci = FakePci::new();
903
904        let (client_end, server_end) = create_channel::<fpci::Device>();
905        let server = Server { state: fake_pci.state.clone() };
906        let scope = fasync::Scope::new_with_name("test");
907        server_end.spawn_on(server, &scope);
908
909        let client = client_end.spawn();
910        test_func(client, fake_pci).await;
911    }
912
913    #[fixture(run_test_with_fake)]
914    #[fuchsia::test]
915    async fn test_get_device_info(client: fidl_next::Client<fpci::Device>, fake_pci: FakePci) {
916        let expected_info = fpci::DeviceInfo {
917            vendor_id: 0x1234,
918            device_id: 0x5678,
919            base_class: 0x01,
920            sub_class: 0x02,
921            program_interface: 0x03,
922            revision_id: 0x04,
923            bus_id: 1,
924            dev_id: 2,
925            func_id: 3,
926            padding: (),
927        };
928        fake_pci.set_device_info(expected_info);
929
930        let res = client.get_device_info().await.expect("Failed to send get_device_info request");
931        assert_eq!(res.info, expected_info);
932
933        // Verify that config header registers were updated
934        assert_eq!(
935            fake_pci.read_config16(u16::from(fpci::Config::VendorId)),
936            expected_info.vendor_id
937        );
938        assert_eq!(
939            fake_pci.read_config16(u16::from(fpci::Config::DeviceId)),
940            expected_info.device_id
941        );
942        assert_eq!(
943            fake_pci.read_config8(u16::from(fpci::Config::RevisionId)),
944            expected_info.revision_id
945        );
946        assert_eq!(
947            fake_pci.read_config8(u16::from(fpci::Config::ClassCodeBase)),
948            expected_info.base_class
949        );
950        assert_eq!(
951            fake_pci.read_config8(u16::from(fpci::Config::ClassCodeSub)),
952            expected_info.sub_class
953        );
954        assert_eq!(
955            fake_pci.read_config8(u16::from(fpci::Config::ClassCodeIntr)),
956            expected_info.program_interface
957        );
958    }
959
960    #[fixture(run_test_with_fake)]
961    #[fuchsia::test]
962    async fn test_get_vmo_bar(client: fidl_next::Client<fpci::Device>, fake_pci: FakePci) {
963        let bar_id = 0;
964        let bar_size = 4096;
965        let vmo = zx::Vmo::create(bar_size).expect("Failed to create VMO");
966        let expected_koid = vmo.koid().expect("Failed to get VMO koid");
967        fake_pci.add_vmo_bar(bar_id, bar_size, vmo);
968
969        let bar_res = client
970            .get_bar(bar_id)
971            .await
972            .expect("Failed to send get_bar request")
973            .expect("get_bar returned error status");
974        let fpci::Bar { bar_id: actual_bar_id, size, result } = bar_res.result;
975        assert_eq!(actual_bar_id, bar_id);
976        assert_eq!(size, bar_size);
977
978        let fpci::BarResult::Vmo(returned_vmo) = result else {
979            panic!("Expected VMO bar result");
980        };
981        assert_eq!(returned_vmo.koid().expect("Failed to get returned VMO koid"), expected_koid);
982
983        let non_existent_bar_id = 1;
984        let err_res = client
985            .get_bar(non_existent_bar_id)
986            .await
987            .expect("Failed to send get_bar request for non-existent BAR");
988        assert_eq!(
989            err_res.expect_err("Expected NOT_FOUND for non-existent BAR"),
990            zx::Status::NOT_FOUND
991        );
992    }
993
994    #[fixture(run_test_with_fake)]
995    #[fuchsia::test]
996    async fn test_set_bus_mastering(client: fidl_next::Client<fpci::Device>, fake_pci: FakePci) {
997        assert_eq!(fake_pci.bus_master_enabled(), None);
998
999        let res =
1000            client.set_bus_mastering(true).await.expect("Failed to send set_bus_mastering request");
1001        assert!(res.is_ok());
1002        assert_eq!(fake_pci.bus_master_enabled(), Some(true));
1003
1004        let res = client
1005            .set_bus_mastering(false)
1006            .await
1007            .expect("Failed to send set_bus_mastering request");
1008        assert!(res.is_ok());
1009        assert_eq!(fake_pci.bus_master_enabled(), Some(false));
1010    }
1011
1012    #[fixture(run_test_with_fake)]
1013    #[fuchsia::test]
1014    async fn test_reset_device(client: fidl_next::Client<fpci::Device>, fake_pci: FakePci) {
1015        assert_eq!(fake_pci.reset_count(), 0);
1016        let res = client.reset_device().await.expect("Failed to send reset_device request");
1017        assert!(res.is_ok());
1018        assert_eq!(fake_pci.reset_count(), 1);
1019        let res = client.reset_device().await.expect("Failed to send reset_device request");
1020        assert!(res.is_ok());
1021        assert_eq!(fake_pci.reset_count(), 2);
1022    }
1023
1024    #[fixture(run_test_with_fake)]
1025    #[fuchsia::test]
1026    async fn test_interrupt_api_and_modes(
1027        client: fidl_next::Client<fpci::Device>,
1028        fake_pci: FakePci,
1029    ) {
1030        let legacy_irq = fake_pci.add_legacy_interrupt();
1031        let msi0 = fake_pci.add_msi_interrupt();
1032        let _msi1 = fake_pci.add_msi_interrupt();
1033        let _msi2 = fake_pci.add_msi_interrupt();
1034        let msix0 = fake_pci.add_msix_interrupt();
1035
1036        // Get interrupt modes - msi should round down 3 -> 2
1037        let modes_res =
1038            client.get_interrupt_modes().await.expect("Failed to send get_interrupt_modes request");
1039        let fpci::DeviceGetInterruptModesResponse { modes } = modes_res;
1040        assert!(modes.has_legacy);
1041        assert_eq!(modes.msi_count, 2);
1042        assert_eq!(modes.msix_count, 1);
1043
1044        // Set Legacy mode
1045        let res = client
1046            .set_interrupt_mode(fpci::InterruptMode::Legacy, 1)
1047            .await
1048            .expect("Set legacy interrupt mode failed");
1049        assert!(res.is_ok());
1050        assert_eq!(fake_pci.interrupt_mode(), fpci::InterruptMode::Legacy);
1051
1052        // Ack interrupt should succeed for legacy
1053        let ack_res = client.ack_interrupt().await.expect("ack_interrupt failed");
1054        assert!(ack_res.is_ok());
1055
1056        // Map legacy interrupt
1057        let map_res = client.map_interrupt(0).await.expect("map_interrupt failed");
1058        let mapped = map_res.expect("map_interrupt error status").interrupt;
1059        assert_eq!(mapped.koid().unwrap(), legacy_irq.koid().unwrap());
1060
1061        // Setting interrupt mode while mapped handle is held should fail with BAD_STATE
1062        let bad_state_res = client
1063            .set_interrupt_mode(fpci::InterruptMode::Msi, 2)
1064            .await
1065            .expect("set_interrupt_mode failed");
1066        assert_eq!(bad_state_res.unwrap_err(), zx::Status::BAD_STATE);
1067
1068        // Drop mapped handle, now switching mode works
1069        std::mem::drop(mapped);
1070        let set_msi_res = client
1071            .set_interrupt_mode(fpci::InterruptMode::Msi, 2)
1072            .await
1073            .expect("set_interrupt_mode failed");
1074        assert!(set_msi_res.is_ok());
1075
1076        // Ack interrupt should fail for MSI mode
1077        let ack_err = client.ack_interrupt().await.expect("ack_interrupt failed");
1078        assert_eq!(ack_err.unwrap_err(), zx::Status::BAD_STATE);
1079
1080        // Map MSI 0
1081        let map_msi = client.map_interrupt(0).await.expect("map_interrupt failed");
1082        let mapped_msi = map_msi.expect("mapped msi").interrupt;
1083        assert_eq!(mapped_msi.koid().unwrap(), msi0.koid().unwrap());
1084
1085        // Map MSI-X
1086        std::mem::drop(mapped_msi);
1087        let set_msix_res = client
1088            .set_interrupt_mode(fpci::InterruptMode::MsiX, 1)
1089            .await
1090            .expect("set_interrupt_mode failed");
1091        assert_eq!(set_msix_res, Ok(()));
1092
1093        let map_msix =
1094            client.map_interrupt(0).await.expect("map_interrupt failed").expect("mapped msix");
1095        assert_eq!(map_msix.interrupt.koid().unwrap(), msix0.koid().unwrap());
1096    }
1097
1098    #[fixture(run_test_with_fake)]
1099    #[fuchsia::test]
1100    async fn test_config_space_bounds_and_header_protection(
1101        client: fidl_next::Client<fpci::Device>,
1102        fake_pci: FakePci,
1103    ) {
1104        // Reads in header space [0, 63] via FIDL succeed
1105        let r8 = client.read_config8(0).await.expect("read_config8");
1106        assert!(r8.is_ok());
1107
1108        // Writes in header space [0, 63] via FIDL fail with OUT_OF_RANGE
1109        let w8_header = client.write_config8(0, 0xff).await.expect("write_config8");
1110        assert_eq!(w8_header.unwrap_err(), zx::Status::OUT_OF_RANGE);
1111
1112        let w16_header = client.write_config16(0x3e, 0xffff).await.expect("write_config16");
1113        assert_eq!(w16_header.unwrap_err(), zx::Status::OUT_OF_RANGE);
1114
1115        // Valid reads and writes in range [0x40, 0xFF]
1116        let w8_valid = client.write_config8(0x40, 0xab).await.expect("write_config8");
1117        assert!(w8_valid.is_ok());
1118        assert_eq!(fake_pci.read_config8(0x40), 0xab);
1119
1120        let r8_valid = client.read_config8(0x40).await.expect("read_config8");
1121        assert_eq!(r8_valid.unwrap().value, 0xab);
1122
1123        // Out of bounds past 256 bytes fails with OUT_OF_RANGE over FIDL
1124        let r_oob = client.read_config8(256).await.expect("read_config8");
1125        assert_eq!(r_oob.unwrap_err(), zx::Status::OUT_OF_RANGE);
1126
1127        let w_oob = client.write_config8(256, 0x12).await.expect("write_config8");
1128        assert_eq!(w_oob.unwrap_err(), zx::Status::OUT_OF_RANGE);
1129    }
1130
1131    #[fixture(run_test_with_fake)]
1132    #[fuchsia::test]
1133    async fn test_capabilities_chain_and_search(
1134        client: fidl_next::Client<fpci::Device>,
1135        fake_pci: FakePci,
1136    ) {
1137        let pos1 = 0x50;
1138        let pos2 = 0x60;
1139        let pos3 = 0x70;
1140        fake_pci.add_vendor_capability(pos1, 6);
1141        fake_pci.add_vendor_capability(pos2, 8);
1142        fake_pci.add_pci_express_capability(pos3);
1143
1144        assert_eq!(fake_pci.read_config8(u16::from(fpci::Config::CapabilitiesPtr)), pos1);
1145        assert_eq!(fake_pci.read_config8((pos1 + 1).into()), pos2);
1146        assert_eq!(fake_pci.read_config8((pos2 + 1).into()), pos3);
1147
1148        let res_vendor =
1149            client.get_capabilities(fpci::CapabilityId::Vendor).await.expect("get_capabilities");
1150        assert_eq!(res_vendor.offsets, vec![pos1, pos2]);
1151
1152        let res_pcie = client
1153            .get_capabilities(fpci::CapabilityId::PciExpress)
1154            .await
1155            .expect("get_capabilities");
1156        assert_eq!(res_pcie.offsets, vec![pos3]);
1157    }
1158
1159    #[fuchsia::test(logging = false)]
1160    #[should_panic]
1161    fn test_add_capability_unknown_forbidden() {
1162        let fake = FakePci::new();
1163        fake.add_capability(fpci::CapabilityId::UnknownOrdinal_(0x99), 0x50, 6);
1164    }
1165
1166    #[fuchsia::test(logging = false)]
1167    #[should_panic]
1168    fn test_add_capability_overlap_panics() {
1169        let fake = FakePci::new();
1170        fake.add_capability(fpci::CapabilityId::Vendor, 0x50, 8);
1171        fake.add_capability(fpci::CapabilityId::PciExpress, 0x54, 8);
1172    }
1173
1174    #[fuchsia::test(logging = false)]
1175    #[should_panic]
1176    fn test_fake_pci_read_oob_panics() {
1177        let fake = FakePci::new();
1178        let _: u8 = fake.read_config8(256);
1179    }
1180
1181    #[fuchsia::test(logging = false)]
1182    #[should_panic]
1183    fn test_fake_pci_write_header_panics() {
1184        let fake = FakePci::new();
1185        fake.write_config8(0x10, 0xff);
1186    }
1187
1188    #[fuchsia::test(logging = false)]
1189    fn test_vmo_bar_readback_and_nonexistent() {
1190        let fake = FakePci::new();
1191        assert!(fake.vmo_bar(0).is_none());
1192
1193        fake.create_vmo_bar(0, 4096);
1194        let vmo = fake.vmo_bar(0).expect("Expected VMO for bar 0");
1195        assert_eq!(vmo.get_size().unwrap(), 4096);
1196
1197        assert!(fake.vmo_bar(1).is_none());
1198    }
1199
1200    #[fuchsia::test(logging = false)]
1201    #[should_panic]
1202    fn test_duplicate_add_vmo_bar() {
1203        let fake = FakePci::new();
1204        fake.create_vmo_bar(0, 4096);
1205        fake.create_vmo_bar(0, 4096);
1206    }
1207
1208    #[fuchsia::test(logging = false)]
1209    #[should_panic]
1210    fn test_duplicate_add_bti() {
1211        let fake = FakePci::new();
1212        let bti1 = FakeBti::create().expect("Failed to create FakeBti");
1213        let bti2 = FakeBti::create().expect("Failed to create FakeBti");
1214        fake.add_bti(
1215            0,
1216            bti1.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("Failed to duplicate BTI"),
1217        );
1218        fake.add_bti(
1219            0,
1220            bti2.duplicate_handle(zx::Rights::SAME_RIGHTS).expect("Failed to duplicate BTI"),
1221        );
1222    }
1223}