panda/guest_ptr/
impls.rs

1use super::{GuestAlign, GuestPtr, GuestReadFail, GuestWriteFail};
2use crate::prelude::*;
3use crate::{enums::Endian, mem::*, GuestType, ARCH_ENDIAN};
4
5use std::alloc::Layout;
6
7macro_rules! impl_for_num {
8    ($($ty:ty),*) => {
9        $(
10            impl GuestType for $ty {
11                fn guest_layout() -> Option<Layout> {
12                    Layout::from_size_align(
13                        core::mem::size_of::<$ty>(),
14                        <$ty as GuestAlign>::ALIGN
15                    ).ok()
16                }
17
18                fn read_from_guest(cpu: &mut CPUState, ptr: target_ptr_t) -> Result<Self, GuestReadFail> {
19                    let mut bytes = [0u8; core::mem::size_of::<$ty>()];
20                    virtual_memory_read_into(cpu, ptr, &mut bytes).or(Err(GuestReadFail))?;
21
22                    Ok(match ARCH_ENDIAN {
23                        Endian::Big => <$ty>::from_be_bytes(bytes),
24                        Endian::Little => <$ty>::from_le_bytes(bytes),
25                    })
26                }
27
28                fn read_from_guest_phys(ptr: target_ptr_t) -> Result<Self, GuestReadFail> {
29                    let mut bytes = [0u8; core::mem::size_of::<$ty>()];
30                    physical_memory_read_into(ptr, &mut bytes).or(Err(GuestReadFail))?;
31
32                    Ok(match ARCH_ENDIAN {
33                        Endian::Big => <$ty>::from_be_bytes(bytes),
34                        Endian::Little => <$ty>::from_le_bytes(bytes),
35                    })
36                }
37
38                fn write_to_guest(&self, cpu: &mut CPUState, ptr: target_ptr_t) -> Result<(), GuestWriteFail> {
39                    let bytes = match ARCH_ENDIAN {
40                        Endian::Big => <$ty>::to_be_bytes(*self),
41                        Endian::Little => <$ty>::to_le_bytes(*self),
42                    };
43
44                    virtual_memory_write(cpu, ptr, &bytes);
45
46                    Ok(())
47                }
48
49                fn write_to_guest_phys(&self, ptr: target_ptr_t) -> Result<(), GuestWriteFail> {
50                    let bytes = match ARCH_ENDIAN {
51                        Endian::Big => <$ty>::to_be_bytes(*self),
52                        Endian::Little => <$ty>::to_le_bytes(*self),
53                    };
54
55                    physical_memory_write(ptr, &bytes);
56
57                    Ok(())
58                }
59            }
60        )*
61    };
62}
63
64impl_for_num!(u8, u16, u32, u64, u128, i8, i16, i32, i64, i128, f32, f64);
65
66impl<T: GuestType> GuestType for GuestPtr<T> {
67    fn guest_layout() -> Option<Layout> {
68        target_ptr_t::guest_layout()
69    }
70
71    fn read_from_guest(cpu: &mut CPUState, ptr: target_ptr_t) -> Result<Self, GuestReadFail> {
72        target_ptr_t::read_from_guest(cpu, ptr).map(Self::from)
73    }
74
75    fn write_to_guest(&self, cpu: &mut CPUState, ptr: target_ptr_t) -> Result<(), GuestWriteFail> {
76        self.pointer.write_to_guest(cpu, ptr)
77    }
78
79    fn read_from_guest_phys(ptr: target_ptr_t) -> Result<Self, GuestReadFail> {
80        target_ptr_t::read_from_guest_phys(ptr).map(Self::from)
81    }
82
83    fn write_to_guest_phys(&self, ptr: target_ptr_t) -> Result<(), GuestWriteFail> {
84        self.pointer.write_to_guest_phys(ptr)
85    }
86}
87
88fn padding_needed_for(layout: &Layout, align: usize) -> usize {
89    let len = layout.size();
90
91    let len_rounded_up = len.wrapping_add(align).wrapping_sub(1) & !align.wrapping_sub(1);
92    len_rounded_up.wrapping_sub(len)
93}
94
95fn padded_size(layout: &Layout) -> usize {
96    layout.size() + padding_needed_for(&layout, layout.align())
97}
98
99fn repeat(layout: &Layout, n: usize) -> Layout {
100    let alloc_size = padded_size(layout)
101        .checked_mul(n)
102        .expect("Layout of guest array overflow");
103
104    Layout::from_size_align(alloc_size, layout.align()).expect("Layout of guest array invalid")
105}
106
107impl<T: GuestType, const N: usize> GuestType for [T; N] {
108    fn guest_layout() -> Option<Layout> {
109        T::guest_layout().map(|layout| repeat(&layout, N))
110    }
111
112    fn read_from_guest(cpu: &mut CPUState, ptr: target_ptr_t) -> Result<Self, GuestReadFail> {
113        let padded_size = padded_size(
114            &T::guest_layout().expect("Cannot read array of unsized types from guest."),
115        );
116
117        array_init::from_iter(
118            (ptr..)
119                .step_by(padded_size)
120                .take(N)
121                .filter_map(|ptr| T::read_from_guest(cpu, ptr).ok()),
122        )
123        .ok_or(GuestReadFail)
124    }
125
126    fn write_to_guest(&self, cpu: &mut CPUState, ptr: target_ptr_t) -> Result<(), GuestWriteFail> {
127        let padded_size = padded_size(
128            &T::guest_layout().expect("Cannot write array of unsized types to the guest."),
129        );
130
131        for (ptr, item) in (ptr..).step_by(padded_size).zip(self.iter()) {
132            item.write_to_guest(cpu, ptr)?;
133        }
134
135        Ok(())
136    }
137
138    fn read_from_guest_phys(ptr: target_ptr_t) -> Result<Self, GuestReadFail> {
139        let padded_size = padded_size(
140            &T::guest_layout().expect("Cannot read array of unsized types from guest."),
141        );
142
143        array_init::from_iter(
144            (ptr..)
145                .step_by(padded_size)
146                .take(N)
147                .filter_map(|ptr| T::read_from_guest_phys(ptr).ok()),
148        )
149        .ok_or(GuestReadFail)
150    }
151
152    fn write_to_guest_phys(&self, ptr: target_ptr_t) -> Result<(), GuestWriteFail> {
153        let padded_size = padded_size(
154            &T::guest_layout().expect("Cannot write array of unsized types to the guest."),
155        );
156
157        for (ptr, item) in (ptr..).step_by(padded_size).zip(self.iter()) {
158            item.write_to_guest_phys(ptr)?;
159        }
160
161        Ok(())
162    }
163}