pci_driver/regions/
mod.rs

1// SPDX-License-Identifier: MIT OR Apache-2.0
2
3//! Types representing PCI regions (config space, BARs, etc.) and other related types.
4//!
5//! ## Base machinery
6//!
7//! - [`trait PciRegion`](PciRegion). Sealed.
8//!   - `&'a dyn PciRegion` implements `AsPciSubregion<'a>`, for all `'a`.
9//!
10//! - [`struct PciSubregion<'a>`](PciSubregion).
11//!   - `PciSubregion<'a>` implements `PciRegion`, for all `'a`.
12//!   - `PciSubregion<'a>` implements `AsPciSubregion<'a>`, for all `'a`.
13//!
14//! - [`trait AsPciSubregion<'a>`](AsPciSubregion). Unlike `PciRegion`, this trait is not sealed.
15//!   - If `T` implements `AsPciSubregion<'a>`, then `&'b T` implements `AsPciSubregion<'a>`, for
16//!     all `'a`, `'b`, `T`.
17//!   - If `T` implements `AsPciSubregion<'a> + Debug + Send + Sync`, then `T` implements
18//!     `PciRegion`, for all `'a`, `T`.
19//!
20//! ## `PciRegion` implementations
21//!
22//! - [`struct OwningPciRegion`](OwningPciRegion). A region that somehow owns its backing resources,
23//!   and so is not bound by the lifetime of a [`PciDevice`](crate::device::PciDevice).
24//!   - `OwningPciRegion` implements `PciRegion`.
25//!   - `&'a OwningPciRegion` implements `AsPciSubregion<'a>`, for all `'a`.
26//!
27//! - [`struct MappedOwningPciRegion`](MappedOwningPciRegion). What you get by calling
28//!   [`OwningPciRegion::map`].
29//!   - `MappedOwningPciRegion` implements `PciRegion`.
30//!   - `&'a MappedOwningPciRegion` implements `AsPciSubregion<'a>`, for all `'a`.
31//!
32//! - [`struct PciMemoryRegion<'a>`](PciMemoryRegion). A region backed by a `&'a [u8]`, `&'a mut
33//!   [u8]`, or raw memory.
34//!   - `PciMemoryRegion<'a>` implements `PciRegion`, for all `'a`.
35//!   - `&'a PciMemoryRegion<'b>` implements `AsPciSubregion<'a>`, for all `'a`, `'b`.
36//!
37//! - [`struct PciRegionSnapshot`](PciRegionSnapshot).
38//!   - `PciRegionSnapshot` implements `PciRegion`.
39//!   - `&'a PciRegionSnapshot` implements `AsPciSubregion<'a>`, for all `'a`.
40//!
41//! ## And also
42//!
43//! - [`trait BackedByPciSubregion<'a>`](BackedByPciSubregion).
44
45/* ---------------------------------------------------------------------------------------------- */
46
47mod bit_field_macros;
48mod struct_macros;
49pub mod structured;
50
51use std::fmt::Debug;
52use std::io::{self, ErrorKind};
53use std::marker::PhantomData;
54use std::mem;
55use std::ops::{Bound, Range, RangeBounds};
56use std::sync::Arc;
57
58use crate::device::PciDeviceInternal;
59
60/* ---------------------------------------------------------------------------------------------- */
61
62/// Describes which operations may be performed on some piece of memory or other data region.
63#[derive(Clone, Copy, Debug, Eq, PartialEq)]
64pub enum Permissions {
65    /// Only reading is allowed.
66    Read,
67    /// Only writing is allowed.
68    Write,
69    /// Both reading and writing are allowed.
70    ReadWrite,
71}
72
73impl Permissions {
74    pub fn new(can_read: bool, can_write: bool) -> Option<Permissions> {
75        match (can_read, can_write) {
76            (false, false) => None,
77            (true, false) => Some(Permissions::Read),
78            (false, true) => Some(Permissions::Write),
79            (true, true) => Some(Permissions::ReadWrite),
80        }
81    }
82
83    pub fn can_read(&self) -> bool {
84        match self {
85            Permissions::Read => true,
86            Permissions::Write => false,
87            Permissions::ReadWrite => true,
88        }
89    }
90
91    pub fn can_write(&self) -> bool {
92        match self {
93            Permissions::Read => false,
94            Permissions::Write => true,
95            Permissions::ReadWrite => true,
96        }
97    }
98}
99
100/* ---------------------------------------------------------------------------------------------- */
101
102pub(crate) use private::Sealed;
103mod private {
104    /// Like [`crate::device::private::Sealed`]. We can't use that same trait here because users
105    /// would be able to indirectly implement it for their own types by implementing
106    /// `AsPciSubregion`, so we define another one with the same name.
107    pub trait Sealed {}
108}
109
110/// A region of PCI Configuration Space, or a BAR, or the Expansion ROM, or VGA Space, or some other
111/// device region, or maybe something else, as long it is safe to read and write to it concurrently
112/// with no data races.
113///
114/// The region does not necessarily have RAM semantics, i.e., values can change suddenly, writes
115/// might not actually write what is being written, reads can have side effects, etc.
116///
117/// Offsets are [`u64`], not [`usize`], so you can operate on 64-bit `PciRegion`s even when
118/// compiling for 32-bit.
119///
120/// This trait is _sealed_ for forward-compatibility reasons, and thus cannot be implemented by
121/// users of the crate.
122#[allow(clippy::len_without_is_empty)]
123pub trait PciRegion: Debug + Send + Sync + Sealed {
124    /// The length of the region in bytes.
125    fn len(&self) -> u64;
126
127    /// Whether the region may be read, written, or both.
128    fn permissions(&self) -> Permissions;
129
130    /// Returns a `const` pointer to the beginning of the `PciRegion`.
131    ///
132    /// If the region is not mapped into memory, this returns `None`.
133    fn as_ptr(&self) -> Option<*const u8>;
134
135    /// Returns a `mut` pointer to the beginning of the `PciRegion`.
136    ///
137    /// If the region is not writeable or not mapped into memory, this returns `None`.
138    fn as_mut_ptr(&self) -> Option<*mut u8>;
139
140    /// Read from a contiguous range of the region into a byte buffer.
141    ///
142    /// There is no guarantee that the access will be atomic in any sense, or terribly efficient.
143    fn read_bytes(&self, offset: u64, buffer: &mut [u8]) -> io::Result<()>;
144
145    /// Read an [`u8`] at the given byte offset from the beginning of the `PciRegion`.
146    ///
147    /// This will fail if `offset + 1 > self.len()`.
148    fn read_u8(&self, offset: u64) -> io::Result<u8>;
149
150    /// Write an [`u8`] at the given byte offset from the beginning of the `PciRegion`.
151    ///
152    /// This will fail if `offset + 1 > self.len()`.
153    fn write_u8(&self, offset: u64, value: u8) -> io::Result<()>;
154
155    /// Read a little-endian [`u16`] at the given byte offset from the beginning of the `PciRegion`.
156    ///
157    /// The read value will be converted from little-endian to the native endianness before being
158    /// returned.
159    ///
160    /// This will fail if `offset + 2 > self.len()`, or if the region requires aligned accesses and
161    /// `offset` is not 2-byte aligned.
162    fn read_le_u16(&self, offset: u64) -> io::Result<u16>;
163
164    /// Write a little-endian [`u16`] at the given byte offset from the beginning of the
165    /// `PciRegion`.
166    ///
167    /// The value will be converted from the native endianness to little-endian before being
168    /// written.
169    ///
170    /// This will fail if `offset + 2 > self.len()`, or if the region requires aligned accesses and
171    /// `offset` is not 2-byte aligned.
172    fn write_le_u16(&self, offset: u64, value: u16) -> io::Result<()>;
173
174    /// Read a little-endian [`u32`] at the given byte offset from the beginning of the `PciRegion`.
175    ///
176    /// The read value will be converted from little-endian to the native endianness before being
177    /// returned.
178    ///
179    /// This will fail if `offset + 4 > self.len()`, or if the region requires aligned accesses and
180    /// `offset` is not 4-byte aligned.
181    fn read_le_u32(&self, offset: u64) -> io::Result<u32>;
182
183    /// Write a little-endian [`u32`] at the given byte offset from the beginning of the
184    /// `PciRegion`.
185    ///
186    /// The value will be converted from the native endianness to little-endian before being
187    /// written.
188    ///
189    /// This will fail if `offset + 4 > self.len()`, or if the region requires aligned accesses and
190    /// `offset` is not 4-byte aligned.
191    fn write_le_u32(&self, offset: u64, value: u32) -> io::Result<()>;
192}
193
194/// Implements [`PciRegion`] for the given type `T` by delegating all methods to the existing
195/// implementation of [`PciRegion`] for `&T`.
196macro_rules! impl_delegating_pci_region {
197    ($type:ty) => {
198        impl $crate::regions::Sealed for $type {}
199        impl $crate::regions::PciRegion for $type {
200            fn len(&self) -> u64 {
201                $crate::regions::PciRegion::len(&self)
202            }
203
204            fn permissions(&self) -> $crate::regions::Permissions {
205                $crate::regions::PciRegion::permissions(&self)
206            }
207
208            fn as_ptr(&self) -> ::std::option::Option<*const u8> {
209                $crate::regions::PciRegion::as_ptr(&self)
210            }
211
212            fn as_mut_ptr(&self) -> ::std::option::Option<*mut u8> {
213                $crate::regions::PciRegion::as_mut_ptr(&self)
214            }
215
216            fn read_bytes(&self, offset: u64, buffer: &mut [u8]) -> ::std::io::Result<()> {
217                $crate::regions::PciRegion::read_bytes(&self, offset, buffer)
218            }
219
220            fn read_u8(&self, offset: u64) -> ::std::io::Result<u8> {
221                $crate::regions::PciRegion::read_u8(&self, offset)
222            }
223
224            fn write_u8(&self, offset: u64, value: u8) -> ::std::io::Result<()> {
225                $crate::regions::PciRegion::write_u8(&self, offset, value)
226            }
227
228            fn read_le_u16(&self, offset: u64) -> ::std::io::Result<u16> {
229                $crate::regions::PciRegion::read_le_u16(&self, offset)
230            }
231
232            fn write_le_u16(&self, offset: u64, value: u16) -> ::std::io::Result<()> {
233                $crate::regions::PciRegion::write_le_u16(&self, offset, value)
234            }
235
236            fn read_le_u32(&self, offset: u64) -> ::std::io::Result<u32> {
237                $crate::regions::PciRegion::read_le_u32(&self, offset)
238            }
239
240            fn write_le_u32(&self, offset: u64, value: u32) -> ::std::io::Result<()> {
241                $crate::regions::PciRegion::write_le_u32(&self, offset, value)
242            }
243        }
244    };
245}
246
247/* ---------------------------------------------------------------------------------------------- */
248
249/// A contiguous part of a [`PciRegion`], which is itself also a `PciRegion`.
250///
251/// Simply redirects accesses to the underlying `PciRegion`, offset by the `PciSubregion`'s offset.
252/// Also makes sure those accesses don't exceed the `PciSubregion`'s end (offset + length).
253///
254/// Create instances of this by calling [`AsPciSubregion::subregion`] on anything that implements
255/// it, for instance a [`&dyn PciRegion`](PciRegion) or [`OwningPciRegion`].
256#[derive(Clone, Copy, Debug)]
257pub struct PciSubregion<'a> {
258    region: &'a dyn PciRegion,
259    offset: u64,
260    length: u64,
261}
262
263impl<'a> PciSubregion<'a> {
264    pub fn underlying_region(&self) -> &'a dyn PciRegion {
265        self.region
266    }
267
268    pub fn offset_in_underlying_region(&self) -> u64 {
269        self.offset
270    }
271
272    fn validate_access(&self, offset: u64, len: usize) -> io::Result<()> {
273        let len = len as u64;
274
275        if offset + len > self.length {
276            return Err(io::Error::new(
277                ErrorKind::InvalidInput,
278                format!(
279                    "Tried to access region range [{:#x}, {:#x}), must be within [0x0, {:#x})",
280                    offset,
281                    offset + len,
282                    self.length
283                ),
284            ));
285        }
286
287        Ok(())
288    }
289}
290
291/* ---------------------------------------------------------------------------------------------- */
292
293/// For when it is possible to obtain a [`PciSubregion`] representation of a value cheaply.
294///
295/// Also provides a handy [`AsPciSubregion::subregion`] method with a default implementation.
296pub trait AsPciSubregion<'a> {
297    /// Returns a [`PciSubregion`] corresponding to `self`.
298    fn as_subregion(&self) -> PciSubregion<'a>;
299
300    /// Returns a [`PciSubregion`] corresponding to a range of `self`.
301    fn subregion(&self, range: impl RangeBounds<u64>) -> PciSubregion<'a> {
302        let subregion = Self::as_subregion(self);
303        let range = clamp_range(range, subregion.len());
304
305        PciSubregion {
306            region: subregion.underlying_region(),
307            offset: subregion.offset_in_underlying_region() + range.start,
308            length: range.end - range.start,
309        }
310    }
311}
312
313// If a `T` is `AsPciSubregion<'a>`, then any `&T` is also.
314impl<'a, 'b, T> AsPciSubregion<'a> for &'b T
315where
316    T: AsPciSubregion<'a>,
317{
318    fn as_subregion(&self) -> PciSubregion<'a> {
319        T::as_subregion(*self)
320    }
321}
322
323impl<'a> AsPciSubregion<'a> for &'a dyn PciRegion {
324    fn as_subregion(&self) -> PciSubregion<'a> {
325        PciSubregion {
326            region: *self,
327            offset: 0,
328            length: PciRegion::len(*self),
329        }
330    }
331}
332
333impl<'a> AsPciSubregion<'a> for PciSubregion<'a> {
334    fn as_subregion(&self) -> PciSubregion<'a> {
335        *self
336    }
337}
338
339impl<'a, T> Sealed for T where T: AsPciSubregion<'a> + Debug + Send + Sync {}
340impl<'a, T> PciRegion for T
341where
342    T: AsPciSubregion<'a> + Debug + Send + Sync,
343{
344    fn len(&self) -> u64 {
345        let subregion = T::as_subregion(self);
346        subregion.length
347    }
348
349    fn permissions(&self) -> Permissions {
350        let subregion = T::as_subregion(self);
351        subregion.region.permissions()
352    }
353
354    fn as_ptr(&self) -> Option<*const u8> {
355        let subregion = T::as_subregion(self);
356        let ptr = subregion.region.as_ptr()?;
357        // TODO: Can any of this overflow?
358        Some(unsafe { ptr.add(subregion.offset as usize) })
359    }
360
361    fn as_mut_ptr(&self) -> Option<*mut u8> {
362        let subregion = T::as_subregion(self);
363        let ptr = subregion.region.as_mut_ptr()?;
364        // TODO: Can any of this overflow?
365        Some(unsafe { ptr.add(subregion.offset as usize) })
366    }
367
368    fn read_bytes(&self, offset: u64, buffer: &mut [u8]) -> io::Result<()> {
369        let subregion = T::as_subregion(self);
370        subregion.validate_access(offset, buffer.len())?;
371        subregion
372            .region
373            .read_bytes(subregion.offset + offset, buffer)
374    }
375
376    fn read_u8(&self, offset: u64) -> io::Result<u8> {
377        let subregion = T::as_subregion(self);
378        subregion.validate_access(offset, mem::size_of::<u8>())?;
379        subregion.region.read_u8(subregion.offset + offset)
380    }
381
382    fn write_u8(&self, offset: u64, value: u8) -> io::Result<()> {
383        let subregion = T::as_subregion(self);
384        subregion.validate_access(offset, mem::size_of::<u8>())?;
385        subregion.region.write_u8(subregion.offset + offset, value)
386    }
387
388    fn read_le_u16(&self, offset: u64) -> io::Result<u16> {
389        let subregion = T::as_subregion(self);
390        subregion.validate_access(offset, mem::size_of::<u16>())?;
391        subregion.region.read_le_u16(subregion.offset + offset)
392    }
393
394    fn write_le_u16(&self, offset: u64, value: u16) -> io::Result<()> {
395        let subregion = T::as_subregion(self);
396        subregion.validate_access(offset, mem::size_of::<u16>())?;
397        subregion
398            .region
399            .write_le_u16(subregion.offset + offset, value)
400    }
401
402    fn read_le_u32(&self, offset: u64) -> io::Result<u32> {
403        let subregion = T::as_subregion(self);
404        subregion.validate_access(offset, mem::size_of::<u32>())?;
405        subregion.region.read_le_u32(subregion.offset + offset)
406    }
407
408    fn write_le_u32(&self, offset: u64, value: u32) -> io::Result<()> {
409        let subregion = T::as_subregion(self);
410        subregion.validate_access(offset, mem::size_of::<u32>())?;
411        subregion
412            .region
413            .write_le_u32(subregion.offset + offset, value)
414    }
415}
416
417/* ---------------------------------------------------------------------------------------------- */
418
419#[allow(dead_code)] // for when pci-driver is built with no backends
420#[derive(Copy, Clone, Debug, Eq, PartialEq)]
421pub(crate) enum RegionIdentifier {
422    Bar(usize),
423    Rom,
424}
425
426/// This is "owning" in the sense that it doesn't borrow the `PciDevice` it came from.
427///
428/// You can use the read and write methods to access the region. This should always work, but may
429/// not be the most efficient method to access it. If the region is "mappable", consider mapping it
430/// into memory using [`OwningPciRegion::map`] and using volatile memory accesses.
431///
432/// For instance, BARs can be I/O Space BARs or Memory Space BARs. In either case, you can access
433/// them through the [`PciRegion`] methods. In addition, if a BAR is a Memory Space BAR, you can map
434/// it, which gives you another type implementing [`PciRegion`], but accesses through it should be
435/// more efficient. You can also obtain a `*const u8` or `*mut u8` from that second [`PciRegion`]
436/// and use that directly.
437#[derive(Debug)]
438pub struct OwningPciRegion {
439    device: Arc<dyn PciDeviceInternal>,
440    region: Arc<dyn PciRegion>,
441    offset: u64,
442    length: u64,
443    identifier: RegionIdentifier,
444    is_mappable: bool,
445}
446
447impl OwningPciRegion {
448    #[allow(dead_code)] // for when pci-driver is built with no backends
449    pub(crate) fn new(
450        device: Arc<dyn PciDeviceInternal>,
451        region: Arc<dyn PciRegion>,
452        identifier: RegionIdentifier,
453        is_mappable: bool,
454    ) -> OwningPciRegion {
455        let offset = 0;
456        let length = region.len();
457
458        OwningPciRegion {
459            device,
460            region,
461            offset,
462            length,
463            identifier,
464            is_mappable,
465        }
466    }
467
468    /// Whether the region can be memory-mapped.
469    ///
470    /// If `false`, [`OwningPciRegion::map`] will always fail.
471    pub fn is_mappable(&self) -> bool {
472        self.is_mappable
473    }
474
475    /// Like PciSubregion's similar method, but returns an "owning" subregion.
476    pub fn owning_subregion(&self, range: impl RangeBounds<u64>) -> OwningPciRegion {
477        let range = clamp_range(range, self.length);
478
479        OwningPciRegion {
480            device: Arc::clone(&self.device),
481            region: Arc::clone(&self.region),
482            offset: self.offset + range.start,
483            length: range.end - range.start,
484            identifier: self.identifier,
485            is_mappable: self.is_mappable,
486        }
487    }
488
489    /// Memory-map some range of the region into the current process' address space.
490    pub fn map(
491        &self,
492        range: impl RangeBounds<u64>,
493        permissions: Permissions,
494    ) -> io::Result<MappedOwningPciRegion> {
495        let range = clamp_range(range, self.region.len());
496
497        if range.end - range.start > usize::MAX as u64 {
498            return Err(io::Error::new(
499                ErrorKind::InvalidInput,
500                "Range length exceeds usize::MAX",
501            ));
502        }
503
504        if (permissions.can_read() && !self.permissions().can_read())
505            || (permissions.can_write() && !self.permissions().can_write())
506        {
507            return Err(io::Error::new(
508                ErrorKind::InvalidInput,
509                "Requested incompatible permissions",
510            ));
511        }
512
513        let length = (range.end - range.start) as usize;
514
515        let ptr = self.device.region_map(
516            self.identifier,
517            self.offset + range.start,
518            length,
519            permissions,
520        )?;
521
522        let mapped_region = unsafe { PciMemoryRegion::new_raw(ptr, length, permissions) };
523
524        Ok(MappedOwningPciRegion {
525            device: Arc::clone(&self.device),
526            region: mapped_region,
527            identifier: self.identifier,
528            ptr,
529            length,
530        })
531    }
532}
533
534impl_delegating_pci_region! { OwningPciRegion }
535
536impl<'a> AsPciSubregion<'a> for &'a OwningPciRegion {
537    fn as_subregion(&self) -> PciSubregion<'a> {
538        (&*self.region).subregion(self.offset..self.offset + self.length)
539    }
540}
541
542/* ---------------------------------------------------------------------------------------------- */
543
544/// A memory-mapped [`OwningPciRegion`]. This is also a [`PciRegion`]. Dropping this unmaps the
545/// region.
546#[derive(Debug)]
547pub struct MappedOwningPciRegion {
548    device: Arc<dyn PciDeviceInternal>,
549    region: PciMemoryRegion<'static>,
550    identifier: RegionIdentifier,
551    ptr: *mut u8,
552    length: usize,
553}
554
555unsafe impl Send for MappedOwningPciRegion {}
556unsafe impl Sync for MappedOwningPciRegion {}
557
558#[allow(clippy::len_without_is_empty)]
559impl MappedOwningPciRegion {
560    // TODO: These three methods shadow PciRegion's. This probably isn't a good idea.
561
562    /// Returns a constant pointer to the beginning of the memory-mapped region.
563    pub fn as_ptr(&self) -> *const u8 {
564        self.ptr
565    }
566
567    /// Returns a mutable pointer to the beginning of the memory-mapped region.
568    pub fn as_mut_ptr(&self) -> *mut u8 {
569        self.ptr
570    }
571
572    /// The length of the region.
573    ///
574    /// Unlike [`PciRegion::len`], returns `usize`.
575    pub fn len(&self) -> usize {
576        self.length
577    }
578}
579
580impl_delegating_pci_region! { MappedOwningPciRegion }
581
582impl<'a> AsPciSubregion<'a> for &'a MappedOwningPciRegion {
583    fn as_subregion(&self) -> PciSubregion<'a> {
584        (&self.region).as_subregion()
585    }
586}
587
588impl Drop for MappedOwningPciRegion {
589    fn drop(&mut self) {
590        unsafe {
591            self.device
592                .region_unmap(self.identifier, self.ptr, self.length)
593        };
594    }
595}
596
597/* ---------------------------------------------------------------------------------------------- */
598
599#[derive(Clone, Copy, Debug)]
600pub struct PciMemoryRegion<'a> {
601    ptr: *mut u8,
602    length: usize,
603    permissions: Permissions,
604    phantom: PhantomData<&'a ()>,
605}
606
607unsafe impl Send for PciMemoryRegion<'_> {}
608unsafe impl Sync for PciMemoryRegion<'_> {}
609
610impl PciMemoryRegion<'_> {
611    pub fn new(data: &[u8]) -> PciMemoryRegion {
612        PciMemoryRegion {
613            ptr: data.as_ptr() as *mut _,
614            length: data.len(),
615            permissions: Permissions::Read,
616            phantom: PhantomData,
617        }
618    }
619
620    pub fn new_mut(data: &mut [u8]) -> PciMemoryRegion {
621        PciMemoryRegion {
622            ptr: data.as_mut_ptr(),
623            length: data.len(),
624            permissions: Permissions::ReadWrite,
625            phantom: PhantomData,
626        }
627    }
628
629    /// # Safety
630    ///
631    /// The returned `PciMemoryRegion` must not outlive the data.
632    pub unsafe fn new_raw<'a>(
633        data: *mut u8,
634        length: usize,
635        permissions: Permissions,
636    ) -> PciMemoryRegion<'a> {
637        PciMemoryRegion {
638            ptr: data,
639            length,
640            permissions,
641            phantom: PhantomData,
642        }
643    }
644
645    fn get_ptr<T>(&self, offset: u64) -> io::Result<*mut T> {
646        // TODO: Handle overflow.
647
648        let size = std::mem::size_of::<T>() as u64;
649
650        if offset + size > self.length as u64 {
651            return Err(io::Error::new(
652                ErrorKind::InvalidInput,
653                "Access falls outside region",
654            ));
655        }
656
657        if offset % size != 0 {
658            return Err(io::Error::new(ErrorKind::InvalidInput, "Unaligned access"));
659        }
660
661        Ok(unsafe { self.ptr.add(offset as usize).cast::<T>() })
662    }
663}
664
665impl Sealed for PciMemoryRegion<'_> {}
666impl PciRegion for PciMemoryRegion<'_> {
667    fn len(&self) -> u64 {
668        self.length as u64
669    }
670
671    fn permissions(&self) -> Permissions {
672        self.permissions
673    }
674
675    fn as_ptr(&self) -> Option<*const u8> {
676        Some(self.ptr)
677    }
678
679    fn as_mut_ptr(&self) -> Option<*mut u8> {
680        Some(self.ptr)
681    }
682
683    fn read_bytes(&self, offset: u64, buffer: &mut [u8]) -> io::Result<()> {
684        let end = offset + buffer.len() as u64;
685
686        if end > self.length as u64 {
687            return Err(io::Error::new(
688                ErrorKind::InvalidInput,
689                format!(
690                    "Invalid configuration space range [{:#x}, {:#x}), must be within [0x0, {:#x})",
691                    offset,
692                    end,
693                    self.len()
694                ),
695            ));
696        }
697
698        // TODO: Will these 1-byte accesses always work?
699
700        for (off, byte) in (offset..).zip(buffer) {
701            *byte = unsafe { self.get_ptr::<u8>(off)?.read_volatile() };
702        }
703
704        Ok(())
705    }
706
707    fn read_u8(&self, offset: u64) -> io::Result<u8> {
708        let v = unsafe { self.get_ptr::<u8>(offset)?.read_volatile() };
709        Ok(v)
710    }
711
712    fn write_u8(&self, offset: u64, value: u8) -> io::Result<()> {
713        unsafe { self.get_ptr::<u8>(offset)?.write_volatile(value) };
714        Ok(())
715    }
716
717    fn read_le_u16(&self, offset: u64) -> io::Result<u16> {
718        let v = unsafe { self.get_ptr::<u16>(offset)?.read_volatile() };
719        Ok(u16::from_le(v))
720    }
721
722    fn write_le_u16(&self, offset: u64, value: u16) -> io::Result<()> {
723        unsafe { self.get_ptr::<u16>(offset)?.write_volatile(value.to_le()) };
724        Ok(())
725    }
726
727    fn read_le_u32(&self, offset: u64) -> io::Result<u32> {
728        let v = unsafe { self.get_ptr::<u32>(offset)?.read_volatile() };
729        Ok(u32::from_le(v))
730    }
731
732    fn write_le_u32(&self, offset: u64, value: u32) -> io::Result<()> {
733        unsafe { self.get_ptr::<u32>(offset)?.write_volatile(value.to_le()) };
734        Ok(())
735    }
736}
737
738impl<'a> AsPciSubregion<'a> for &'a PciMemoryRegion<'_> {
739    fn as_subregion(&self) -> PciSubregion<'a> {
740        let region: &dyn PciRegion = *self;
741        <&dyn PciRegion>::as_subregion(&region)
742    }
743}
744
745/* ---------------------------------------------------------------------------------------------- */
746
747/// Use this to take snapshots of anything that is an [`AsPciSubregion`].
748#[derive(Clone, Debug)]
749pub struct PciRegionSnapshot {
750    buffer: Box<[u8]>,
751    region: PciMemoryRegion<'static>,
752}
753
754impl PciRegionSnapshot {
755    /// Take a snapshot of the given subregion.
756    pub fn take<'a>(as_subregion: impl AsPciSubregion<'a>) -> io::Result<PciRegionSnapshot> {
757        let subregion = as_subregion.as_subregion();
758
759        if subregion.len() > isize::MAX as u64 {
760            return Err(io::Error::new(ErrorKind::Other, "TODO"));
761        }
762
763        let mut buffer = vec![0u8; subregion.len() as usize];
764        subregion.read_bytes(0, &mut buffer)?;
765
766        let mut buffer = buffer.into_boxed_slice();
767        let region = unsafe {
768            PciMemoryRegion::new_raw(buffer.as_mut_ptr(), buffer.len(), Permissions::ReadWrite)
769        };
770
771        Ok(PciRegionSnapshot { buffer, region })
772    }
773}
774
775impl_delegating_pci_region! { PciRegionSnapshot }
776
777impl<'a> AsPciSubregion<'a> for &'a PciRegionSnapshot {
778    fn as_subregion(&self) -> PciSubregion<'a> {
779        (&self.region).as_subregion()
780    }
781}
782
783impl From<PciRegionSnapshot> for Box<[u8]> {
784    fn from(snapshot: PciRegionSnapshot) -> Self {
785        snapshot.buffer
786    }
787}
788
789impl From<PciRegionSnapshot> for Vec<u8> {
790    fn from(snapshot: PciRegionSnapshot) -> Self {
791        Vec::from(snapshot.buffer)
792    }
793}
794
795/* ---------------------------------------------------------------------------------------------- */
796
797/// Something that is backed by a [`PciSubregion`].
798///
799/// Types generated by [`pci_struct!`](crate::pci_struct!) and
800/// [`pci_bit_field!`](crate::pci_bit_field!) implement this.
801pub trait BackedByPciSubregion<'a> {
802    /// Does not check whether the subregion is big enough. If it isn't, accesses may later fail.
803    fn backed_by(as_subregion: impl AsPciSubregion<'a>) -> Self;
804}
805
806/* ---------------------------------------------------------------------------------------------- */
807
808fn clamp_range(range: impl RangeBounds<u64>, max_length: u64) -> Range<u64> {
809    let start = match range.start_bound() {
810        Bound::Included(&b) => b,
811        Bound::Excluded(&b) => b + 1,
812        Bound::Unbounded => 0,
813    };
814
815    let end = match range.end_bound() {
816        Bound::Included(&b) => b + 1,
817        Bound::Excluded(&b) => b,
818        Bound::Unbounded => max_length,
819    };
820
821    Range {
822        start: start.min(max_length),
823        end: end.max(start).min(max_length),
824    }
825}
826
827/* ---------------------------------------------------------------------------------------------- */