1use bitflags::bitflags;
4use core::{
5 array,
6 convert::TryFrom,
7 fmt::{self, Display, Formatter},
8 ops::Deref,
9 ptr::NonNull,
10};
11use log::warn;
12use safe_mmio::{UniqueMmioPointer, fields::ReadPureWrite};
13use thiserror::Error;
14
15const INVALID_READ: u32 = 0xffffffff;
16
17const MAX_DEVICES: u8 = 32;
19const MAX_FUNCTIONS: u8 = 8;
21
22const STATUS_COMMAND_OFFSET: u8 = 0x04;
24const BAR0_OFFSET: u8 = 0x10;
26
27pub const PCI_CAP_ID_VNDR: u8 = 0x09;
29
30bitflags! {
31 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
33 pub struct Status: u16 {
34 const INTERRUPT_STATUS = 1 << 3;
37 const CAPABILITIES_LIST = 1 << 4;
39 const MHZ_66_CAPABLE = 1 << 5;
41 const FAST_BACK_TO_BACK_CAPABLE = 1 << 7;
44 const MASTER_DATA_PARITY_ERROR = 1 << 8;
46 const SIGNALED_TARGET_ABORT = 1 << 11;
49 const RECEIVED_TARGET_ABORT = 1 << 12;
51 const RECEIVED_MASTER_ABORT = 1 << 13;
53 const SIGNALED_SYSTEM_ERROR = 1 << 14;
55 const DETECTED_PARITY_ERROR = 1 << 15;
57 }
58}
59
60bitflags! {
61 #[derive(Copy, Clone, Debug, Default, Eq, PartialEq)]
63 pub struct Command: u16 {
64 const IO_SPACE = 1 << 0;
66 const MEMORY_SPACE = 1 << 1;
68 const BUS_MASTER = 1 << 2;
70 const SPECIAL_CYCLES = 1 << 3;
72 const MEMORY_WRITE_AND_INVALIDATE_ENABLE = 1 << 4;
74 const VGA_PALETTE_SNOOP = 1 << 5;
76 const PARITY_ERROR_RESPONSE = 1 << 6;
78 const SERR_ENABLE = 1 << 8;
81 const FAST_BACK_TO_BACK_ENABLE = 1 << 9;
83 const INTERRUPT_DISABLE = 1 << 10;
85 }
86}
87
88#[derive(Copy, Clone, Debug, Eq, Error, PartialEq)]
90pub enum PciError {
91 #[error("Invalid PCI BAR type")]
93 InvalidBarType,
94}
95
96#[derive(Debug)]
98pub struct PciRoot<C: ConfigurationAccess> {
99 pub(crate) configuration_access: C,
100}
101
102#[derive(Copy, Clone, Debug, Eq, PartialEq)]
104pub enum Cam {
105 MmioCam,
109 Ecam,
113}
114
115impl Cam {
116 pub const fn size(self) -> u32 {
118 match self {
119 Self::MmioCam => 0x1000000,
120 Self::Ecam => 0x10000000,
121 }
122 }
123
124 pub fn cam_offset(self, device_function: DeviceFunction, register_offset: u8) -> u32 {
127 assert!(device_function.valid());
128
129 let bdf = ((device_function.bus as u32) << 8)
130 | ((device_function.device as u32) << 3)
131 | (device_function.function as u32);
132 let address =
133 (bdf << match self {
134 Cam::MmioCam => 8,
135 Cam::Ecam => 12,
136 }) | (register_offset as u32);
137 assert!(address < self.size());
139 assert!(address & 0x3 == 0);
141 address
142 }
143}
144
145impl<C: ConfigurationAccess> PciRoot<C> {
146 pub fn new(configuration_access: C) -> Self {
149 Self {
150 configuration_access,
151 }
152 }
153
154 pub fn enumerate_bus(&self, bus: u8) -> BusDeviceIterator<C> {
156 let configuration_access = unsafe { self.configuration_access.unsafe_clone() };
158 BusDeviceIterator {
159 configuration_access,
160 next: DeviceFunction {
161 bus,
162 device: 0,
163 function: 0,
164 },
165 }
166 }
167
168 pub fn get_status_command(&self, device_function: DeviceFunction) -> (Status, Command) {
170 let status_command = self
171 .configuration_access
172 .read_word(device_function, STATUS_COMMAND_OFFSET);
173 let status = Status::from_bits_truncate((status_command >> 16) as u16);
174 let command = Command::from_bits_truncate(status_command as u16);
175 (status, command)
176 }
177
178 pub fn set_command(&mut self, device_function: DeviceFunction, command: Command) {
180 self.configuration_access.write_word(
181 device_function,
182 STATUS_COMMAND_OFFSET,
183 command.bits().into(),
184 );
185 }
186
187 pub fn capabilities(&self, device_function: DeviceFunction) -> CapabilityIterator<'_, C> {
189 CapabilityIterator {
190 configuration_access: &self.configuration_access,
191 device_function,
192 next_capability_offset: self.capabilities_offset(device_function),
193 }
194 }
195
196 pub fn bars(
198 &mut self,
199 device_function: DeviceFunction,
200 ) -> Result<[Option<BarInfo>; 6], PciError> {
201 let mut bars = array::from_fn(|_| None);
202 let mut bar_index = 0;
203 while bar_index < 6 {
204 let info = self.bar_info(device_function, bar_index)?;
205 let bar_entries = if info.as_ref().is_some_and(BarInfo::takes_two_entries) {
206 2
207 } else {
208 1
209 };
210 bars[usize::from(bar_index)] = info;
211 bar_index += bar_entries;
212 }
213 Ok(bars)
214 }
215
216 pub fn bar_info(
218 &mut self,
219 device_function: DeviceFunction,
220 bar_index: u8,
221 ) -> Result<Option<BarInfo>, PciError> {
222 let (_status, command_orig) = self.get_status_command(device_function);
224 let command_disable_decode = command_orig & !(Command::IO_SPACE | Command::MEMORY_SPACE);
225 if command_disable_decode != command_orig {
226 self.set_command(device_function, command_disable_decode);
227 }
228
229 let bar_orig = self
230 .configuration_access
231 .read_word(device_function, BAR0_OFFSET + 4 * bar_index);
232 let io_space = bar_orig & 0x00000001 == 0x00000001;
233
234 self.configuration_access.write_word(
236 device_function,
237 BAR0_OFFSET + 4 * bar_index,
238 0xffffffff,
239 );
240 let mut size_mask = u64::from(
241 self.configuration_access
242 .read_word(device_function, BAR0_OFFSET + 4 * bar_index),
243 );
244
245 let (address_top, size_top) = if bar_orig & 0b111 == 0b100 {
247 if bar_index >= 5 {
248 return Err(PciError::InvalidBarType);
249 }
250 let bar_top_orig = self
251 .configuration_access
252 .read_word(device_function, BAR0_OFFSET + 4 * (bar_index + 1));
253 self.configuration_access.write_word(
254 device_function,
255 BAR0_OFFSET + 4 * (bar_index + 1),
256 0xffffffff,
257 );
258 let size_top = self
259 .configuration_access
260 .read_word(device_function, BAR0_OFFSET + 4 * (bar_index + 1));
261 self.configuration_access.write_word(
262 device_function,
263 BAR0_OFFSET + 4 * (bar_index + 1),
264 bar_top_orig,
265 );
266 (bar_top_orig, size_top)
267 } else {
268 let size_top = if size_mask == 0 { 0 } else { 0xffffffff };
269 (0, size_top)
270 };
271 size_mask |= u64::from(size_top) << 32;
272
273 let flag_bits = if io_space { 0b11 } else { 0b1111 };
275 let size = (!(size_mask & !flag_bits)).wrapping_add(1);
278
279 self.configuration_access.write_word(
281 device_function,
282 BAR0_OFFSET + 4 * bar_index,
283 bar_orig,
284 );
285
286 if command_disable_decode != command_orig {
287 self.set_command(device_function, command_orig);
288 }
289
290 if size_mask == 0 {
291 Ok(None)
292 } else if io_space {
293 let address = bar_orig & 0xfffffffc;
295 Ok(Some(BarInfo::IO {
296 address,
297 size: size as u32,
298 }))
299 } else {
300 let address = u64::from(bar_orig & 0xfffffff0) | (u64::from(address_top) << 32);
302 let prefetchable = bar_orig & 0x00000008 != 0;
303 let address_type = MemoryBarType::try_from(((bar_orig & 0x00000006) >> 1) as u8)?;
304 Ok(Some(BarInfo::Memory {
305 address_type,
306 prefetchable,
307 address,
308 size,
309 }))
310 }
311 }
312
313 pub fn set_bar_32(&mut self, device_function: DeviceFunction, bar_index: u8, address: u32) {
315 self.configuration_access
316 .write_word(device_function, BAR0_OFFSET + 4 * bar_index, address);
317 }
318
319 pub fn set_bar_64(&mut self, device_function: DeviceFunction, bar_index: u8, address: u64) {
321 self.configuration_access.write_word(
322 device_function,
323 BAR0_OFFSET + 4 * bar_index,
324 address as u32,
325 );
326 self.configuration_access.write_word(
327 device_function,
328 BAR0_OFFSET + 4 * (bar_index + 1),
329 (address >> 32) as u32,
330 );
331 }
332
333 fn capabilities_offset(&self, device_function: DeviceFunction) -> Option<u8> {
335 let (status, _) = self.get_status_command(device_function);
336 if status.contains(Status::CAPABILITIES_LIST) {
337 Some((self.configuration_access.read_word(device_function, 0x34) & 0xFC) as u8)
338 } else {
339 None
340 }
341 }
342}
343
344pub trait ConfigurationAccess {
346 fn read_word(&self, device_function: DeviceFunction, register_offset: u8) -> u32;
348
349 fn write_word(&mut self, device_function: DeviceFunction, register_offset: u8, data: u32);
351
352 unsafe fn unsafe_clone(&self) -> Self;
360}
361
362pub struct MmioCam<'a> {
366 mmio: UniqueMmioPointer<'a, [ReadPureWrite<u32>]>,
367 cam: Cam,
368}
369
370impl MmioCam<'_> {
371 pub unsafe fn new(mmio_base: *mut u8, cam: Cam) -> Self {
382 assert!(mmio_base as usize & 0x3 == 0);
383 Self {
384 mmio: unsafe {
387 UniqueMmioPointer::new(NonNull::slice_from_raw_parts(
388 NonNull::new(mmio_base as *mut ReadPureWrite<u32>).unwrap(),
389 cam.size() as usize / size_of::<u32>(),
390 ))
391 },
392 cam,
393 }
394 }
395}
396
397impl ConfigurationAccess for MmioCam<'_> {
398 fn read_word(&self, device_function: DeviceFunction, register_offset: u8) -> u32 {
399 let address = self.cam.cam_offset(device_function, register_offset);
400 self.mmio
402 .deref()
403 .get((address >> 2) as usize)
404 .unwrap()
405 .read()
406 }
407
408 fn write_word(&mut self, device_function: DeviceFunction, register_offset: u8, data: u32) {
409 let address = self.cam.cam_offset(device_function, register_offset);
410 self.mmio.get((address >> 2) as usize).unwrap().write(data);
411 }
412
413 unsafe fn unsafe_clone(&self) -> Self {
414 Self {
415 mmio: unsafe {
419 UniqueMmioPointer::new(NonNull::new(self.mmio.ptr().cast_mut()).unwrap())
420 },
421 cam: self.cam,
422 }
423 }
424}
425
426unsafe impl Sync for MmioCam<'_> {}
429
430#[derive(Clone, Debug, Eq, PartialEq)]
432pub enum BarInfo {
433 Memory {
435 address_type: MemoryBarType,
437 prefetchable: bool,
440 address: u64,
442 size: u64,
444 },
445 IO {
447 address: u32,
449 size: u32,
451 },
452}
453
454impl BarInfo {
455 pub fn takes_two_entries(&self) -> bool {
458 matches!(
459 self,
460 BarInfo::Memory {
461 address_type: MemoryBarType::Width64,
462 ..
463 }
464 )
465 }
466
467 pub fn memory_address_size(&self) -> Option<(u64, u64)> {
470 if let Self::Memory { address, size, .. } = self {
471 Some((*address, *size))
472 } else {
473 None
474 }
475 }
476}
477
478impl Display for BarInfo {
479 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
480 match self {
481 Self::Memory {
482 address_type,
483 prefetchable,
484 address,
485 size,
486 } => write!(
487 f,
488 "Memory space at {:#010x}, size {}, type {:?}, prefetchable {}",
489 address, size, address_type, prefetchable
490 ),
491 Self::IO { address, size } => {
492 write!(f, "I/O space at {:#010x}, size {}", address, size)
493 }
494 }
495 }
496}
497
498#[derive(Copy, Clone, Debug, Eq, PartialEq)]
500pub enum MemoryBarType {
501 Width32,
503 Below1MiB,
505 Width64,
507}
508
509impl From<MemoryBarType> for u8 {
510 fn from(bar_type: MemoryBarType) -> Self {
511 match bar_type {
512 MemoryBarType::Width32 => 0,
513 MemoryBarType::Below1MiB => 1,
514 MemoryBarType::Width64 => 2,
515 }
516 }
517}
518
519impl TryFrom<u8> for MemoryBarType {
520 type Error = PciError;
521
522 fn try_from(value: u8) -> Result<Self, Self::Error> {
523 match value {
524 0 => Ok(Self::Width32),
525 1 => Ok(Self::Below1MiB),
526 2 => Ok(Self::Width64),
527 _ => Err(PciError::InvalidBarType),
528 }
529 }
530}
531
532#[derive(Debug)]
534pub struct CapabilityIterator<'a, C: ConfigurationAccess> {
535 configuration_access: &'a C,
536 device_function: DeviceFunction,
537 next_capability_offset: Option<u8>,
538}
539
540impl<C: ConfigurationAccess> Iterator for CapabilityIterator<'_, C> {
541 type Item = CapabilityInfo;
542
543 fn next(&mut self) -> Option<Self::Item> {
544 let offset = self.next_capability_offset?;
545
546 let capability_header = self
548 .configuration_access
549 .read_word(self.device_function, offset);
550 let id = capability_header as u8;
551 let next_offset = (capability_header >> 8) as u8;
552 let private_header = (capability_header >> 16) as u16;
553
554 self.next_capability_offset = if next_offset == 0 {
555 None
556 } else if next_offset < 64 || next_offset & 0x3 != 0 {
557 warn!("Invalid next capability offset {:#04x}", next_offset);
558 None
559 } else {
560 Some(next_offset)
561 };
562
563 Some(CapabilityInfo {
564 offset,
565 id,
566 private_header,
567 })
568 }
569}
570
571#[derive(Debug, Copy, Clone, Eq, PartialEq)]
573pub struct CapabilityInfo {
574 pub offset: u8,
576 pub id: u8,
578 pub private_header: u16,
580}
581
582#[derive(Debug)]
584pub struct BusDeviceIterator<C: ConfigurationAccess> {
585 configuration_access: C,
588 next: DeviceFunction,
589}
590
591impl<C: ConfigurationAccess> Iterator for BusDeviceIterator<C> {
592 type Item = (DeviceFunction, DeviceFunctionInfo);
593
594 fn next(&mut self) -> Option<Self::Item> {
595 while self.next.device < MAX_DEVICES {
596 let current = self.next;
598 let device_vendor = self.configuration_access.read_word(current, 0);
599
600 self.next.function += 1;
602 if self.next.function >= MAX_FUNCTIONS {
603 self.next.function = 0;
604 self.next.device += 1;
605 }
606
607 if device_vendor != INVALID_READ {
608 let class_revision = self.configuration_access.read_word(current, 8);
609 let device_id = (device_vendor >> 16) as u16;
610 let vendor_id = device_vendor as u16;
611 let class = (class_revision >> 24) as u8;
612 let subclass = (class_revision >> 16) as u8;
613 let prog_if = (class_revision >> 8) as u8;
614 let revision = class_revision as u8;
615 let bist_type_latency_cache = self.configuration_access.read_word(current, 12);
616 let header_type = HeaderType::from((bist_type_latency_cache >> 16) as u8 & 0x7f);
617 return Some((
618 current,
619 DeviceFunctionInfo {
620 vendor_id,
621 device_id,
622 class,
623 subclass,
624 prog_if,
625 revision,
626 header_type,
627 },
628 ));
629 }
630 }
631 None
632 }
633}
634
635#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd, Hash)]
637pub struct DeviceFunction {
638 pub bus: u8,
640 pub device: u8,
642 pub function: u8,
644}
645
646impl DeviceFunction {
647 pub fn valid(&self) -> bool {
650 self.device < 32 && self.function < 8
651 }
652}
653
654impl Display for DeviceFunction {
655 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
656 write!(f, "{:02x}:{:02x}.{}", self.bus, self.device, self.function)
657 }
658}
659
660#[derive(Clone, Debug, Eq, PartialEq)]
662pub struct DeviceFunctionInfo {
663 pub vendor_id: u16,
665 pub device_id: u16,
667 pub class: u8,
669 pub subclass: u8,
671 pub prog_if: u8,
673 pub revision: u8,
675 pub header_type: HeaderType,
677}
678
679impl Display for DeviceFunctionInfo {
680 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
681 write!(
682 f,
683 "{:04x}:{:04x} (class {:02x}.{:02x}, rev {:02x}) {:?}",
684 self.vendor_id,
685 self.device_id,
686 self.class,
687 self.subclass,
688 self.revision,
689 self.header_type,
690 )
691 }
692}
693
694#[derive(Copy, Clone, Debug, Eq, PartialEq)]
696pub enum HeaderType {
697 Standard,
699 PciPciBridge,
701 PciCardbusBridge,
703 Unrecognised(u8),
705}
706
707impl From<u8> for HeaderType {
708 fn from(value: u8) -> Self {
709 match value {
710 0x00 => Self::Standard,
711 0x01 => Self::PciPciBridge,
712 0x02 => Self::PciCardbusBridge,
713 _ => Self::Unrecognised(value),
714 }
715 }
716}
717
718#[cfg(test)]
719mod tests {
720 use super::*;
721
722 #[test]
723 fn read_status_command() {
724 let status_command = 0x0020_0003;
725 let device_function = DeviceFunction {
726 bus: 0,
727 device: 1,
728 function: 2,
729 };
730 let fake_cam = FakeCam {
731 device_function,
732 bar_values: [0, 1, 4, 0, 0, 0],
733 bar_masks: [
734 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
735 ],
736 status_command,
737 };
738 let root = PciRoot::new(fake_cam);
739
740 assert_eq!(
741 root.get_status_command(device_function),
742 (
743 Status::MHZ_66_CAPABLE,
744 Command::IO_SPACE | Command::MEMORY_SPACE
745 )
746 );
747 }
748
749 #[test]
750 fn bar_info_unused() {
751 let status_command = 0x0020_0003;
752 let device_function = DeviceFunction {
753 bus: 0,
754 device: 1,
755 function: 2,
756 };
757 let fake_cam = FakeCam {
758 device_function,
759 bar_values: [0, 1, 4, 0, 0, 0],
760 bar_masks: [
761 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
762 ],
763 status_command,
764 };
765 let fake_cam_orig = fake_cam.clone();
766 let mut root = PciRoot::new(fake_cam);
767
768 assert_eq!(
769 root.bars(device_function).unwrap(),
770 [
771 None,
772 Some(BarInfo::IO {
773 address: 0,
774 size: 0,
775 }),
776 Some(BarInfo::Memory {
777 address_type: MemoryBarType::Width64,
778 prefetchable: false,
779 address: 0,
780 size: 0,
781 }),
782 None,
783 None,
784 None,
785 ]
786 );
787
788 assert_eq!(root.configuration_access, fake_cam_orig);
790 }
791
792 #[test]
793 fn bar_info_32() {
794 let status_command = 0x0020_0003;
795 let device_function = DeviceFunction {
796 bus: 0,
797 device: 1,
798 function: 2,
799 };
800 let fake_cam = FakeCam {
801 device_function,
802 bar_values: [0b0000, 0b0010, 0b1000, 0b01, 0b0000, 0b0000],
803 bar_masks: [63, 31, 127, 7, 1023, 255],
804 status_command,
805 };
806 let fake_cam_orig = fake_cam.clone();
807 let mut root = PciRoot::new(fake_cam);
808
809 assert_eq!(
810 root.bars(device_function).unwrap(),
811 [
812 Some(BarInfo::Memory {
813 address_type: MemoryBarType::Width32,
814 prefetchable: false,
815 address: 0,
816 size: 64,
817 }),
818 Some(BarInfo::Memory {
819 address_type: MemoryBarType::Below1MiB,
820 prefetchable: false,
821 address: 0,
822 size: 32,
823 }),
824 Some(BarInfo::Memory {
825 address_type: MemoryBarType::Width32,
826 prefetchable: true,
827 address: 0,
828 size: 128,
829 }),
830 Some(BarInfo::IO {
831 address: 0,
832 size: 8,
833 }),
834 Some(BarInfo::Memory {
835 address_type: MemoryBarType::Width32,
836 prefetchable: false,
837 address: 0,
838 size: 1024,
839 }),
840 Some(BarInfo::Memory {
841 address_type: MemoryBarType::Width32,
842 prefetchable: false,
843 address: 0,
844 size: 256,
845 }),
846 ]
847 );
848
849 assert_eq!(root.configuration_access, fake_cam_orig);
851 }
852
853 #[test]
854 fn bar_info_64() {
855 let status_command = 0x0020_0003;
856 let device_function = DeviceFunction {
857 bus: 0,
858 device: 1,
859 function: 2,
860 };
861 let fake_cam = FakeCam {
862 device_function,
863 bar_values: [0b0100, 0, 0b0100, 0, 0b1100, 0],
864 bar_masks: [127, 0, 0xffffffff, 3, 255, 0],
865 status_command,
866 };
867 let fake_cam_orig = fake_cam.clone();
868 let mut root = PciRoot::new(fake_cam);
869
870 assert_eq!(
871 root.bars(device_function).unwrap(),
872 [
873 Some(BarInfo::Memory {
874 address_type: MemoryBarType::Width64,
875 prefetchable: false,
876 address: 0,
877 size: 128,
878 }),
879 None,
880 Some(BarInfo::Memory {
881 address_type: MemoryBarType::Width64,
882 prefetchable: false,
883 address: 0,
884 size: 0x400000000,
885 }),
886 None,
887 Some(BarInfo::Memory {
888 address_type: MemoryBarType::Width64,
889 prefetchable: true,
890 address: 0,
891 size: 256,
892 }),
893 None,
894 ]
895 );
896
897 assert_eq!(root.configuration_access, fake_cam_orig);
899 }
900
901 #[derive(Clone, Debug, Eq, PartialEq)]
902 struct FakeCam {
903 device_function: DeviceFunction,
904 bar_values: [u32; 6],
905 bar_masks: [u32; 6],
907 status_command: u32,
908 }
909
910 impl ConfigurationAccess for FakeCam {
911 fn read_word(&self, device_function: DeviceFunction, register_offset: u8) -> u32 {
912 assert_eq!(device_function, self.device_function);
913 assert_eq!(register_offset & 0b11, 0);
914 if register_offset == STATUS_COMMAND_OFFSET {
915 self.status_command
916 } else if register_offset >= BAR0_OFFSET && register_offset < 0x28 {
917 let bar_index = usize::from((register_offset - BAR0_OFFSET) / 4);
918 self.bar_values[bar_index]
919 } else {
920 println!("Reading unsupported register offset {}", register_offset);
921 0xffffffff
922 }
923 }
924
925 fn write_word(&mut self, device_function: DeviceFunction, register_offset: u8, data: u32) {
926 assert_eq!(device_function, self.device_function);
927 assert_eq!(register_offset & 0b11, 0);
928 if register_offset == STATUS_COMMAND_OFFSET {
929 self.status_command = (self.status_command & 0xffff_0000) | (data & 0x0000_ffff);
931 } else if register_offset >= BAR0_OFFSET && register_offset < 0x28 {
932 let bar_index = usize::from((register_offset - BAR0_OFFSET) / 4);
933 let bar_mask = self.bar_masks[bar_index];
934 self.bar_values[bar_index] =
935 (bar_mask & self.bar_values[bar_index]) | (!bar_mask & data);
936 } else {
937 println!("Ignoring write of {:#010x} to {}", data, register_offset);
938 return;
939 }
940 }
941
942 unsafe fn unsafe_clone(&self) -> Self {
943 self.clone()
944 }
945 }
946}