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::{fields::ReadPureWrite, UniqueMmioPointer};
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: UniqueMmioPointer::new(NonNull::slice_from_raw_parts(
385 NonNull::new(mmio_base as *mut ReadPureWrite<u32>).unwrap(),
386 cam.size() as usize / size_of::<u32>(),
387 )),
388 cam,
389 }
390 }
391}
392
393impl ConfigurationAccess for MmioCam<'_> {
394 fn read_word(&self, device_function: DeviceFunction, register_offset: u8) -> u32 {
395 let address = self.cam.cam_offset(device_function, register_offset);
396 self.mmio
398 .deref()
399 .get((address >> 2) as usize)
400 .unwrap()
401 .read()
402 }
403
404 fn write_word(&mut self, device_function: DeviceFunction, register_offset: u8, data: u32) {
405 let address = self.cam.cam_offset(device_function, register_offset);
406 self.mmio.get((address >> 2) as usize).unwrap().write(data);
407 }
408
409 unsafe fn unsafe_clone(&self) -> Self {
410 Self {
411 mmio: UniqueMmioPointer::new(NonNull::new(self.mmio.ptr().cast_mut()).unwrap()),
412 cam: self.cam,
413 }
414 }
415}
416
417unsafe impl Sync for MmioCam<'_> {}
420
421#[derive(Clone, Debug, Eq, PartialEq)]
423pub enum BarInfo {
424 Memory {
426 address_type: MemoryBarType,
428 prefetchable: bool,
431 address: u64,
433 size: u64,
435 },
436 IO {
438 address: u32,
440 size: u32,
442 },
443}
444
445impl BarInfo {
446 pub fn takes_two_entries(&self) -> bool {
449 matches!(
450 self,
451 BarInfo::Memory {
452 address_type: MemoryBarType::Width64,
453 ..
454 }
455 )
456 }
457
458 pub fn memory_address_size(&self) -> Option<(u64, u64)> {
461 if let Self::Memory { address, size, .. } = self {
462 Some((*address, *size))
463 } else {
464 None
465 }
466 }
467}
468
469impl Display for BarInfo {
470 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
471 match self {
472 Self::Memory {
473 address_type,
474 prefetchable,
475 address,
476 size,
477 } => write!(
478 f,
479 "Memory space at {:#010x}, size {}, type {:?}, prefetchable {}",
480 address, size, address_type, prefetchable
481 ),
482 Self::IO { address, size } => {
483 write!(f, "I/O space at {:#010x}, size {}", address, size)
484 }
485 }
486 }
487}
488
489#[derive(Copy, Clone, Debug, Eq, PartialEq)]
491pub enum MemoryBarType {
492 Width32,
494 Below1MiB,
496 Width64,
498}
499
500impl From<MemoryBarType> for u8 {
501 fn from(bar_type: MemoryBarType) -> Self {
502 match bar_type {
503 MemoryBarType::Width32 => 0,
504 MemoryBarType::Below1MiB => 1,
505 MemoryBarType::Width64 => 2,
506 }
507 }
508}
509
510impl TryFrom<u8> for MemoryBarType {
511 type Error = PciError;
512
513 fn try_from(value: u8) -> Result<Self, Self::Error> {
514 match value {
515 0 => Ok(Self::Width32),
516 1 => Ok(Self::Below1MiB),
517 2 => Ok(Self::Width64),
518 _ => Err(PciError::InvalidBarType),
519 }
520 }
521}
522
523#[derive(Debug)]
525pub struct CapabilityIterator<'a, C: ConfigurationAccess> {
526 configuration_access: &'a C,
527 device_function: DeviceFunction,
528 next_capability_offset: Option<u8>,
529}
530
531impl<C: ConfigurationAccess> Iterator for CapabilityIterator<'_, C> {
532 type Item = CapabilityInfo;
533
534 fn next(&mut self) -> Option<Self::Item> {
535 let offset = self.next_capability_offset?;
536
537 let capability_header = self
539 .configuration_access
540 .read_word(self.device_function, offset);
541 let id = capability_header as u8;
542 let next_offset = (capability_header >> 8) as u8;
543 let private_header = (capability_header >> 16) as u16;
544
545 self.next_capability_offset = if next_offset == 0 {
546 None
547 } else if next_offset < 64 || next_offset & 0x3 != 0 {
548 warn!("Invalid next capability offset {:#04x}", next_offset);
549 None
550 } else {
551 Some(next_offset)
552 };
553
554 Some(CapabilityInfo {
555 offset,
556 id,
557 private_header,
558 })
559 }
560}
561
562#[derive(Debug, Copy, Clone, Eq, PartialEq)]
564pub struct CapabilityInfo {
565 pub offset: u8,
567 pub id: u8,
569 pub private_header: u16,
571}
572
573#[derive(Debug)]
575pub struct BusDeviceIterator<C: ConfigurationAccess> {
576 configuration_access: C,
579 next: DeviceFunction,
580}
581
582impl<C: ConfigurationAccess> Iterator for BusDeviceIterator<C> {
583 type Item = (DeviceFunction, DeviceFunctionInfo);
584
585 fn next(&mut self) -> Option<Self::Item> {
586 while self.next.device < MAX_DEVICES {
587 let current = self.next;
589 let device_vendor = self.configuration_access.read_word(current, 0);
590
591 self.next.function += 1;
593 if self.next.function >= MAX_FUNCTIONS {
594 self.next.function = 0;
595 self.next.device += 1;
596 }
597
598 if device_vendor != INVALID_READ {
599 let class_revision = self.configuration_access.read_word(current, 8);
600 let device_id = (device_vendor >> 16) as u16;
601 let vendor_id = device_vendor as u16;
602 let class = (class_revision >> 24) as u8;
603 let subclass = (class_revision >> 16) as u8;
604 let prog_if = (class_revision >> 8) as u8;
605 let revision = class_revision as u8;
606 let bist_type_latency_cache = self.configuration_access.read_word(current, 12);
607 let header_type = HeaderType::from((bist_type_latency_cache >> 16) as u8 & 0x7f);
608 return Some((
609 current,
610 DeviceFunctionInfo {
611 vendor_id,
612 device_id,
613 class,
614 subclass,
615 prog_if,
616 revision,
617 header_type,
618 },
619 ));
620 }
621 }
622 None
623 }
624}
625
626#[derive(Copy, Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
628pub struct DeviceFunction {
629 pub bus: u8,
631 pub device: u8,
633 pub function: u8,
635}
636
637impl DeviceFunction {
638 pub fn valid(&self) -> bool {
641 self.device < 32 && self.function < 8
642 }
643}
644
645impl Display for DeviceFunction {
646 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
647 write!(f, "{:02x}:{:02x}.{}", self.bus, self.device, self.function)
648 }
649}
650
651#[derive(Clone, Debug, Eq, PartialEq)]
653pub struct DeviceFunctionInfo {
654 pub vendor_id: u16,
656 pub device_id: u16,
658 pub class: u8,
660 pub subclass: u8,
662 pub prog_if: u8,
664 pub revision: u8,
666 pub header_type: HeaderType,
668}
669
670impl Display for DeviceFunctionInfo {
671 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
672 write!(
673 f,
674 "{:04x}:{:04x} (class {:02x}.{:02x}, rev {:02x}) {:?}",
675 self.vendor_id,
676 self.device_id,
677 self.class,
678 self.subclass,
679 self.revision,
680 self.header_type,
681 )
682 }
683}
684
685#[derive(Copy, Clone, Debug, Eq, PartialEq)]
687pub enum HeaderType {
688 Standard,
690 PciPciBridge,
692 PciCardbusBridge,
694 Unrecognised(u8),
696}
697
698impl From<u8> for HeaderType {
699 fn from(value: u8) -> Self {
700 match value {
701 0x00 => Self::Standard,
702 0x01 => Self::PciPciBridge,
703 0x02 => Self::PciCardbusBridge,
704 _ => Self::Unrecognised(value),
705 }
706 }
707}
708
709#[cfg(test)]
710mod tests {
711 use super::*;
712
713 #[test]
714 fn read_status_command() {
715 let status_command = 0x0020_0003;
716 let device_function = DeviceFunction {
717 bus: 0,
718 device: 1,
719 function: 2,
720 };
721 let fake_cam = FakeCam {
722 device_function,
723 bar_values: [0, 1, 4, 0, 0, 0],
724 bar_masks: [
725 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
726 ],
727 status_command,
728 };
729 let root = PciRoot::new(fake_cam);
730
731 assert_eq!(
732 root.get_status_command(device_function),
733 (
734 Status::MHZ_66_CAPABLE,
735 Command::IO_SPACE | Command::MEMORY_SPACE
736 )
737 );
738 }
739
740 #[test]
741 fn bar_info_unused() {
742 let status_command = 0x0020_0003;
743 let device_function = DeviceFunction {
744 bus: 0,
745 device: 1,
746 function: 2,
747 };
748 let fake_cam = FakeCam {
749 device_function,
750 bar_values: [0, 1, 4, 0, 0, 0],
751 bar_masks: [
752 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff, 0xffffffff,
753 ],
754 status_command,
755 };
756 let fake_cam_orig = fake_cam.clone();
757 let mut root = PciRoot::new(fake_cam);
758
759 assert_eq!(
760 root.bars(device_function).unwrap(),
761 [
762 None,
763 Some(BarInfo::IO {
764 address: 0,
765 size: 0,
766 }),
767 Some(BarInfo::Memory {
768 address_type: MemoryBarType::Width64,
769 prefetchable: false,
770 address: 0,
771 size: 0,
772 }),
773 None,
774 None,
775 None,
776 ]
777 );
778
779 assert_eq!(root.configuration_access, fake_cam_orig);
781 }
782
783 #[test]
784 fn bar_info_32() {
785 let status_command = 0x0020_0003;
786 let device_function = DeviceFunction {
787 bus: 0,
788 device: 1,
789 function: 2,
790 };
791 let fake_cam = FakeCam {
792 device_function,
793 bar_values: [0b0000, 0b0010, 0b1000, 0b01, 0b0000, 0b0000],
794 bar_masks: [63, 31, 127, 7, 1023, 255],
795 status_command,
796 };
797 let fake_cam_orig = fake_cam.clone();
798 let mut root = PciRoot::new(fake_cam);
799
800 assert_eq!(
801 root.bars(device_function).unwrap(),
802 [
803 Some(BarInfo::Memory {
804 address_type: MemoryBarType::Width32,
805 prefetchable: false,
806 address: 0,
807 size: 64,
808 }),
809 Some(BarInfo::Memory {
810 address_type: MemoryBarType::Below1MiB,
811 prefetchable: false,
812 address: 0,
813 size: 32,
814 }),
815 Some(BarInfo::Memory {
816 address_type: MemoryBarType::Width32,
817 prefetchable: true,
818 address: 0,
819 size: 128,
820 }),
821 Some(BarInfo::IO {
822 address: 0,
823 size: 8,
824 }),
825 Some(BarInfo::Memory {
826 address_type: MemoryBarType::Width32,
827 prefetchable: false,
828 address: 0,
829 size: 1024,
830 }),
831 Some(BarInfo::Memory {
832 address_type: MemoryBarType::Width32,
833 prefetchable: false,
834 address: 0,
835 size: 256,
836 }),
837 ]
838 );
839
840 assert_eq!(root.configuration_access, fake_cam_orig);
842 }
843
844 #[test]
845 fn bar_info_64() {
846 let status_command = 0x0020_0003;
847 let device_function = DeviceFunction {
848 bus: 0,
849 device: 1,
850 function: 2,
851 };
852 let fake_cam = FakeCam {
853 device_function,
854 bar_values: [0b0100, 0, 0b0100, 0, 0b1100, 0],
855 bar_masks: [127, 0, 0xffffffff, 3, 255, 0],
856 status_command,
857 };
858 let fake_cam_orig = fake_cam.clone();
859 let mut root = PciRoot::new(fake_cam);
860
861 assert_eq!(
862 root.bars(device_function).unwrap(),
863 [
864 Some(BarInfo::Memory {
865 address_type: MemoryBarType::Width64,
866 prefetchable: false,
867 address: 0,
868 size: 128,
869 }),
870 None,
871 Some(BarInfo::Memory {
872 address_type: MemoryBarType::Width64,
873 prefetchable: false,
874 address: 0,
875 size: 0x400000000,
876 }),
877 None,
878 Some(BarInfo::Memory {
879 address_type: MemoryBarType::Width64,
880 prefetchable: true,
881 address: 0,
882 size: 256,
883 }),
884 None,
885 ]
886 );
887
888 assert_eq!(root.configuration_access, fake_cam_orig);
890 }
891
892 #[derive(Clone, Debug, Eq, PartialEq)]
893 struct FakeCam {
894 device_function: DeviceFunction,
895 bar_values: [u32; 6],
896 bar_masks: [u32; 6],
898 status_command: u32,
899 }
900
901 impl ConfigurationAccess for FakeCam {
902 fn read_word(&self, device_function: DeviceFunction, register_offset: u8) -> u32 {
903 assert_eq!(device_function, self.device_function);
904 assert_eq!(register_offset & 0b11, 0);
905 if register_offset == STATUS_COMMAND_OFFSET {
906 self.status_command
907 } else if register_offset >= BAR0_OFFSET && register_offset < 0x28 {
908 let bar_index = usize::from((register_offset - BAR0_OFFSET) / 4);
909 self.bar_values[bar_index]
910 } else {
911 println!("Reading unsupported register offset {}", register_offset);
912 0xffffffff
913 }
914 }
915
916 fn write_word(&mut self, device_function: DeviceFunction, register_offset: u8, data: u32) {
917 assert_eq!(device_function, self.device_function);
918 assert_eq!(register_offset & 0b11, 0);
919 if register_offset == STATUS_COMMAND_OFFSET {
920 self.status_command = (self.status_command & 0xffff_0000) | (data & 0x0000_ffff);
922 } else if register_offset >= BAR0_OFFSET && register_offset < 0x28 {
923 let bar_index = usize::from((register_offset - BAR0_OFFSET) / 4);
924 let bar_mask = self.bar_masks[bar_index];
925 self.bar_values[bar_index] =
926 (bar_mask & self.bar_values[bar_index]) | (!bar_mask & data);
927 } else {
928 println!("Ignoring write of {:#010x} to {}", data, register_offset);
929 return;
930 }
931 }
932
933 unsafe fn unsafe_clone(&self) -> Self {
934 self.clone()
935 }
936 }
937}