vm_memory/
guest_address.rs1use std::cmp::Eq;
8use std::cmp::Ord;
9use std::cmp::Ordering;
10use std::cmp::PartialEq;
11use std::cmp::PartialOrd;
12use std::fmt;
13use std::fmt::Debug;
14use std::fmt::Display;
15use std::fmt::Formatter;
16use std::ops::BitAnd;
17use std::ops::BitOr;
18
19use serde::Deserialize;
20use serde::Serialize;
21
22#[derive(Clone, Copy, Deserialize, Serialize)]
24pub struct GuestAddress(pub u64);
25
26impl Debug for GuestAddress {
27 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
28 write!(f, "GuestAddress({:#018x})", self.0)
29 }
30}
31
32impl GuestAddress {
33 pub fn offset_from(self, base: GuestAddress) -> u64 {
44 self.0 - base.0
45 }
46
47 pub fn offset(self) -> u64 {
50 self.0
51 }
52
53 pub fn checked_add(self, other: u64) -> Option<GuestAddress> {
55 self.0.checked_add(other).map(GuestAddress)
56 }
57
58 #[inline]
61 pub fn unchecked_add(self, offset: u64) -> GuestAddress {
62 GuestAddress(self.0.wrapping_add(offset))
63 }
64
65 pub fn checked_sub(self, other: u64) -> Option<GuestAddress> {
67 self.0.checked_sub(other).map(GuestAddress)
68 }
69
70 pub fn mask(self, mask: u64) -> GuestAddress {
72 GuestAddress(self.0 & mask)
73 }
74
75 pub fn align(self, align: u64) -> Option<GuestAddress> {
80 if align <= 1 {
81 return Some(self);
82 }
83 self.checked_add(align - 1).map(|a| a & !(align - 1))
84 }
85
86 pub fn align_down(self, align: u64) -> GuestAddress {
91 if align <= 1 {
92 return self;
93 }
94 self & !(align - 1)
95 }
96}
97
98impl BitAnd<u64> for GuestAddress {
99 type Output = GuestAddress;
100
101 fn bitand(self, other: u64) -> GuestAddress {
102 GuestAddress(self.0 & other)
103 }
104}
105
106impl BitOr<u64> for GuestAddress {
107 type Output = GuestAddress;
108
109 fn bitor(self, other: u64) -> GuestAddress {
110 GuestAddress(self.0 | other)
111 }
112}
113
114impl PartialEq for GuestAddress {
115 fn eq(&self, other: &GuestAddress) -> bool {
116 self.0 == other.0
117 }
118}
119impl Eq for GuestAddress {}
120
121impl Ord for GuestAddress {
122 fn cmp(&self, other: &GuestAddress) -> Ordering {
123 self.0.cmp(&other.0)
124 }
125}
126
127impl PartialOrd for GuestAddress {
128 fn partial_cmp(&self, other: &GuestAddress) -> Option<Ordering> {
129 Some(self.cmp(other))
130 }
131}
132
133impl Display for GuestAddress {
134 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
135 write!(f, "{:#x}", self.0)
136 }
137}
138
139#[cfg(test)]
140mod tests {
141 use super::*;
142
143 #[test]
144 fn equals() {
145 let a = GuestAddress(0x300);
146 let b = GuestAddress(0x300);
147 let c = GuestAddress(0x301);
148 assert_eq!(a, b);
149 assert_eq!(b, a);
150 assert_ne!(a, c);
151 assert_ne!(c, a);
152 }
153
154 #[test]
155 #[allow(clippy::eq_op)]
156 #[allow(clippy::nonminimal_bool)]
157 fn cmp() {
158 let a = GuestAddress(0x300);
159 let b = GuestAddress(0x301);
160 assert!(a < b);
161 assert!(b > a);
162 assert!(!(a < a));
163 assert!(a >= a);
164 }
165
166 #[test]
167 fn mask() {
168 let a = GuestAddress(0x5050);
169 assert_eq!(GuestAddress(0x5000), a & 0xff00u64);
170 assert_eq!(GuestAddress(0x5055), a | 0x0005u64);
171 }
172
173 #[test]
174 fn add_sub() {
175 let a = GuestAddress(0x50);
176 let b = GuestAddress(0x60);
177 assert_eq!(Some(GuestAddress(0xb0)), a.checked_add(0x60));
178 assert_eq!(0x10, b.offset_from(a));
179 }
180
181 #[test]
182 fn checked_add_overflow() {
183 let a = GuestAddress(0xffffffffffffff55);
184 assert_eq!(Some(GuestAddress(0xffffffffffffff57)), a.checked_add(2));
185 assert!(a.checked_add(0xf0).is_none());
186 }
187
188 #[test]
189 fn align() {
190 assert_eq!(GuestAddress(12345).align(0), Some(GuestAddress(12345)));
191 assert_eq!(GuestAddress(12345).align(1), Some(GuestAddress(12345)));
192 assert_eq!(GuestAddress(12345).align(2), Some(GuestAddress(12346)));
193 assert_eq!(GuestAddress(0).align(4096), Some(GuestAddress(0)));
194 assert_eq!(GuestAddress(1).align(4096), Some(GuestAddress(4096)));
195 assert_eq!(GuestAddress(4095).align(4096), Some(GuestAddress(4096)));
196 assert_eq!(GuestAddress(4096).align(4096), Some(GuestAddress(4096)));
197 assert_eq!(GuestAddress(4097).align(4096), Some(GuestAddress(8192)));
198 assert_eq!(
199 GuestAddress(u64::MAX & !4095).align(4096),
200 Some(GuestAddress(u64::MAX & !4095)),
201 );
202 assert_eq!(GuestAddress(u64::MAX).align(2), None);
203 }
204
205 #[test]
206 fn align_down() {
207 assert_eq!(GuestAddress(12345).align_down(0), GuestAddress(12345));
208 assert_eq!(GuestAddress(12345).align_down(1), GuestAddress(12345));
209 assert_eq!(GuestAddress(12345).align_down(2), GuestAddress(12344));
210 assert_eq!(GuestAddress(0).align_down(4096), GuestAddress(0));
211 assert_eq!(GuestAddress(1).align_down(4096), GuestAddress(0));
212 assert_eq!(GuestAddress(4095).align_down(4096), GuestAddress(0));
213 assert_eq!(GuestAddress(4096).align_down(4096), GuestAddress(4096));
214 assert_eq!(GuestAddress(4097).align_down(4096), GuestAddress(4096));
215 assert_eq!(
216 GuestAddress(u64::MAX & !4095).align_down(4096),
217 GuestAddress(u64::MAX & !4095),
218 );
219 assert_eq!(
220 GuestAddress(u64::MAX).align_down(2),
221 GuestAddress(u64::MAX - 1)
222 );
223 }
224}