1mod 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#[derive(Clone, Copy, Debug, Eq, PartialEq)]
64pub enum Permissions {
65 Read,
67 Write,
69 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
100pub(crate) use private::Sealed;
103mod private {
104 pub trait Sealed {}
108}
109
110#[allow(clippy::len_without_is_empty)]
123pub trait PciRegion: Debug + Send + Sync + Sealed {
124 fn len(&self) -> u64;
126
127 fn permissions(&self) -> Permissions;
129
130 fn as_ptr(&self) -> Option<*const u8>;
134
135 fn as_mut_ptr(&self) -> Option<*mut u8>;
139
140 fn read_bytes(&self, offset: u64, buffer: &mut [u8]) -> io::Result<()>;
144
145 fn read_u8(&self, offset: u64) -> io::Result<u8>;
149
150 fn write_u8(&self, offset: u64, value: u8) -> io::Result<()>;
154
155 fn read_le_u16(&self, offset: u64) -> io::Result<u16>;
163
164 fn write_le_u16(&self, offset: u64, value: u16) -> io::Result<()>;
173
174 fn read_le_u32(&self, offset: u64) -> io::Result<u32>;
182
183 fn write_le_u32(&self, offset: u64, value: u32) -> io::Result<()>;
192}
193
194macro_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#[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
291pub trait AsPciSubregion<'a> {
297 fn as_subregion(&self) -> PciSubregion<'a>;
299
300 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
313impl<'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 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 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#[allow(dead_code)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
421pub(crate) enum RegionIdentifier {
422 Bar(usize),
423 Rom,
424}
425
426#[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)] 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 pub fn is_mappable(&self) -> bool {
472 self.is_mappable
473 }
474
475 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 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#[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 pub fn as_ptr(&self) -> *const u8 {
564 self.ptr
565 }
566
567 pub fn as_mut_ptr(&self) -> *mut u8 {
569 self.ptr
570 }
571
572 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#[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 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 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 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(®ion)
742 }
743}
744
745#[derive(Clone, Debug)]
749pub struct PciRegionSnapshot {
750 buffer: Box<[u8]>,
751 region: PciMemoryRegion<'static>,
752}
753
754impl PciRegionSnapshot {
755 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
795pub trait BackedByPciSubregion<'a> {
802 fn backed_by(as_subregion: impl AsPciSubregion<'a>) -> Self;
804}
805
806fn 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