@@ -74,6 +74,154 @@ impl error::Error for Error {}
74
74
75
75
pub type Result < T > = result:: Result < T , Error > ;
76
76
77
+ /// A factory struct to build `MmapRegion` objects.
78
+ pub struct MmapRegionBuilder < B = ( ) > {
79
+ size : usize ,
80
+ prot : i32 ,
81
+ flags : i32 ,
82
+ file_offset : Option < FileOffset > ,
83
+ raw_ptr : Option < * mut u8 > ,
84
+ hugetlbfs : Option < bool > ,
85
+ bitmap : B ,
86
+ }
87
+
88
+ impl < B : Bitmap + Default > MmapRegionBuilder < B > {
89
+ /// Create a new `MmapRegionBuilder` using the default value for
90
+ /// the inner `Bitmap` object.
91
+ pub fn new ( size : usize ) -> Self {
92
+ Self :: new_with_bitmap ( size, B :: default ( ) )
93
+ }
94
+ }
95
+
96
+ impl < B : Bitmap > MmapRegionBuilder < B > {
97
+ /// Create a new `MmapRegionBuilder` using the provided `Bitmap` object.
98
+ ///
99
+ /// When instantiating the builder for a region that does not require dirty bitmap
100
+ /// bitmap tracking functionality, we can specify a trivial `Bitmap` implementation
101
+ /// such as `()`.
102
+ pub fn new_with_bitmap ( size : usize , bitmap : B ) -> Self {
103
+ MmapRegionBuilder {
104
+ size,
105
+ prot : 0 ,
106
+ flags : libc:: MAP_ANONYMOUS | libc:: MAP_PRIVATE ,
107
+ file_offset : None ,
108
+ raw_ptr : None ,
109
+ hugetlbfs : None ,
110
+ bitmap,
111
+ }
112
+ }
113
+
114
+ /// Create the `MmapRegion` object with the specified mmap memory protection flag `prot`.
115
+ pub fn with_mmap_prot ( mut self , prot : i32 ) -> Self {
116
+ self . prot = prot;
117
+ self
118
+ }
119
+
120
+ /// Create the `MmapRegion` object with the specified mmap `flags`.
121
+ pub fn with_mmap_flags ( mut self , flags : i32 ) -> Self {
122
+ self . flags = flags;
123
+ self
124
+ }
125
+
126
+ /// Create the `MmapRegion` object with the specified `file_offset`.
127
+ pub fn with_file_offset ( mut self , file_offset : FileOffset ) -> Self {
128
+ self . file_offset = Some ( file_offset) ;
129
+ self
130
+ }
131
+
132
+ /// Create the `MmapRegion` object with the specified `hugetlbfs` flag.
133
+ pub fn with_hugetlbfs ( mut self , hugetlbfs : bool ) -> Self {
134
+ self . hugetlbfs = Some ( hugetlbfs) ;
135
+ self
136
+ }
137
+
138
+ /// Create the `MmapRegion` object with pre-mmapped raw pointer.
139
+ ///
140
+ /// # Safety
141
+ ///
142
+ /// To use this safely, the caller must guarantee that `raw_addr` and `self.size` define a
143
+ /// region within a valid mapping that is already present in the process.
144
+ pub unsafe fn with_raw_mmap_pointer ( mut self , raw_ptr : * mut u8 ) -> Self {
145
+ self . raw_ptr = Some ( raw_ptr) ;
146
+ self
147
+ }
148
+
149
+ /// Build the `MmapRegion` object.
150
+ pub fn build ( self ) -> Result < MmapRegion < B > > {
151
+ if self . raw_ptr . is_some ( ) {
152
+ return self . build_raw ( ) ;
153
+ }
154
+
155
+ // Forbid MAP_FIXED, as it doesn't make sense in this context, and is pretty dangerous
156
+ // in general.
157
+ if self . flags & libc:: MAP_FIXED != 0 {
158
+ return Err ( Error :: MapFixed ) ;
159
+ }
160
+
161
+ let ( fd, offset) = if let Some ( ref f_off) = self . file_offset {
162
+ check_file_offset ( f_off, self . size ) ?;
163
+ ( f_off. file ( ) . as_raw_fd ( ) , f_off. start ( ) )
164
+ } else {
165
+ ( -1 , 0 )
166
+ } ;
167
+
168
+ // This is safe because we're not allowing MAP_FIXED, and invalid parameters cannot break
169
+ // Rust safety guarantees (things may change if we're mapping /dev/mem or some wacky file).
170
+ let addr = unsafe {
171
+ libc:: mmap (
172
+ null_mut ( ) ,
173
+ self . size ,
174
+ self . prot ,
175
+ self . flags ,
176
+ fd,
177
+ offset as libc:: off_t ,
178
+ )
179
+ } ;
180
+
181
+ if addr == libc:: MAP_FAILED {
182
+ return Err ( Error :: Mmap ( io:: Error :: last_os_error ( ) ) ) ;
183
+ }
184
+
185
+ Ok ( MmapRegion {
186
+ addr : addr as * mut u8 ,
187
+ size : self . size ,
188
+ bitmap : self . bitmap ,
189
+ file_offset : self . file_offset ,
190
+ prot : self . prot ,
191
+ flags : self . flags ,
192
+ owned : true ,
193
+ hugetlbfs : self . hugetlbfs ,
194
+ } )
195
+ }
196
+
197
+ fn build_raw ( self ) -> Result < MmapRegion < B > > {
198
+ // Safe because this call just returns the page size and doesn't have any side effects.
199
+ let page_size = unsafe { libc:: sysconf ( libc:: _SC_PAGESIZE) } as usize ;
200
+ let addr = self . raw_ptr . clone ( ) . unwrap ( ) ;
201
+
202
+ // Check that the pointer to the mapping is page-aligned.
203
+ if ( addr as usize ) & ( page_size - 1 ) != 0 {
204
+ return Err ( Error :: InvalidPointer ) ;
205
+ }
206
+
207
+ // Check that the size is a multiple of the page size.
208
+ if self . size & ( page_size - 1 ) != 0 {
209
+ return Err ( Error :: InvalidSize ) ;
210
+ }
211
+
212
+ Ok ( MmapRegion {
213
+ addr,
214
+ size : self . size ,
215
+ bitmap : self . bitmap ,
216
+ file_offset : self . file_offset ,
217
+ prot : self . prot ,
218
+ flags : self . flags ,
219
+ owned : false ,
220
+ hugetlbfs : self . hugetlbfs ,
221
+ } )
222
+ }
223
+ }
224
+
77
225
/// Helper structure for working with mmaped memory regions in Unix.
78
226
///
79
227
/// The structure is used for accessing the guest's physical memory by mmapping it into
@@ -108,12 +256,10 @@ impl<B: NewBitmap> MmapRegion<B> {
108
256
/// # Arguments
109
257
/// * `size` - The size of the memory region in bytes.
110
258
pub fn new ( size : usize ) -> Result < Self > {
111
- Self :: build (
112
- None ,
113
- size,
114
- libc:: PROT_READ | libc:: PROT_WRITE ,
115
- libc:: MAP_ANONYMOUS | libc:: MAP_NORESERVE | libc:: MAP_PRIVATE ,
116
- )
259
+ MmapRegionBuilder :: new_with_bitmap ( size, B :: with_len ( size) )
260
+ . with_mmap_prot ( libc:: PROT_READ | libc:: PROT_WRITE )
261
+ . with_mmap_flags ( libc:: MAP_ANONYMOUS | libc:: MAP_NORESERVE | libc:: MAP_PRIVATE )
262
+ . build ( )
117
263
}
118
264
119
265
/// Creates a shared file mapping of `size` bytes.
@@ -123,12 +269,11 @@ impl<B: NewBitmap> MmapRegion<B> {
123
269
/// referred to by `file_offset.file`.
124
270
/// * `size` - The size of the memory region in bytes.
125
271
pub fn from_file ( file_offset : FileOffset , size : usize ) -> Result < Self > {
126
- Self :: build (
127
- Some ( file_offset) ,
128
- size,
129
- libc:: PROT_READ | libc:: PROT_WRITE ,
130
- libc:: MAP_NORESERVE | libc:: MAP_SHARED ,
131
- )
272
+ MmapRegionBuilder :: new_with_bitmap ( size, B :: with_len ( size) )
273
+ . with_file_offset ( file_offset)
274
+ . with_mmap_prot ( libc:: PROT_READ | libc:: PROT_WRITE )
275
+ . with_mmap_flags ( libc:: MAP_NORESERVE | libc:: MAP_SHARED )
276
+ . build ( )
132
277
}
133
278
134
279
/// Creates a mapping based on the provided arguments.
@@ -147,37 +292,13 @@ impl<B: NewBitmap> MmapRegion<B> {
147
292
prot : i32 ,
148
293
flags : i32 ,
149
294
) -> Result < Self > {
150
- // Forbid MAP_FIXED, as it doesn't make sense in this context, and is pretty dangerous
151
- // in general.
152
- if flags & libc:: MAP_FIXED != 0 {
153
- return Err ( Error :: MapFixed ) ;
154
- }
155
-
156
- let ( fd, offset) = if let Some ( ref f_off) = file_offset {
157
- check_file_offset ( f_off, size) ?;
158
- ( f_off. file ( ) . as_raw_fd ( ) , f_off. start ( ) )
159
- } else {
160
- ( -1 , 0 )
161
- } ;
162
-
163
- // This is safe because we're not allowing MAP_FIXED, and invalid parameters cannot break
164
- // Rust safety guarantees (things may change if we're mapping /dev/mem or some wacky file).
165
- let addr = unsafe { libc:: mmap ( null_mut ( ) , size, prot, flags, fd, offset as libc:: off_t ) } ;
166
-
167
- if addr == libc:: MAP_FAILED {
168
- return Err ( Error :: Mmap ( io:: Error :: last_os_error ( ) ) ) ;
295
+ let mut builder = MmapRegionBuilder :: new_with_bitmap ( size, B :: with_len ( size) )
296
+ . with_mmap_prot ( prot)
297
+ . with_mmap_flags ( flags) ;
298
+ if let Some ( v) = file_offset {
299
+ builder = builder. with_file_offset ( v) ;
169
300
}
170
-
171
- Ok ( Self {
172
- addr : addr as * mut u8 ,
173
- size,
174
- bitmap : B :: with_len ( size) ,
175
- file_offset,
176
- prot,
177
- flags,
178
- owned : true ,
179
- hugetlbfs : None ,
180
- } )
301
+ builder. build ( )
181
302
}
182
303
183
304
/// Creates a `MmapRegion` instance for an externally managed mapping.
@@ -198,29 +319,11 @@ impl<B: NewBitmap> MmapRegion<B> {
198
319
/// To use this safely, the caller must guarantee that `addr` and `size` define a region within
199
320
/// a valid mapping that is already present in the process.
200
321
pub unsafe fn build_raw ( addr : * mut u8 , size : usize , prot : i32 , flags : i32 ) -> Result < Self > {
201
- // Safe because this call just returns the page size and doesn't have any side effects.
202
- let page_size = libc:: sysconf ( libc:: _SC_PAGESIZE) as usize ;
203
-
204
- // Check that the pointer to the mapping is page-aligned.
205
- if ( addr as usize ) & ( page_size - 1 ) != 0 {
206
- return Err ( Error :: InvalidPointer ) ;
207
- }
208
-
209
- // Check that the size is a multiple of the page size.
210
- if size & ( page_size - 1 ) != 0 {
211
- return Err ( Error :: InvalidSize ) ;
212
- }
213
-
214
- Ok ( Self {
215
- addr,
216
- size,
217
- bitmap : B :: with_len ( size) ,
218
- file_offset : None ,
219
- prot,
220
- flags,
221
- owned : false ,
222
- hugetlbfs : None ,
223
- } )
322
+ MmapRegionBuilder :: new_with_bitmap ( size, B :: with_len ( size) )
323
+ . with_raw_mmap_pointer ( addr)
324
+ . with_mmap_prot ( prot)
325
+ . with_mmap_flags ( flags)
326
+ . build ( )
224
327
}
225
328
}
226
329
@@ -510,6 +613,17 @@ mod tests {
510
613
assert_eq ! ( r. prot( ) , libc:: PROT_READ | libc:: PROT_WRITE ) ;
511
614
assert_eq ! ( r. flags( ) , libc:: MAP_NORESERVE | libc:: MAP_PRIVATE ) ;
512
615
assert ! ( r. owned( ) ) ;
616
+
617
+ let region_size = 0x10_0000 ;
618
+ let bitmap = AtomicBitmap :: new ( region_size, 0x1000 ) ;
619
+ let builder = MmapRegionBuilder :: new_with_bitmap ( region_size, bitmap)
620
+ . with_hugetlbfs ( true )
621
+ . with_mmap_prot ( libc:: PROT_READ | libc:: PROT_WRITE ) ;
622
+ assert_eq ! ( builder. size, region_size) ;
623
+ assert_eq ! ( builder. hugetlbfs, Some ( true ) ) ;
624
+ assert_eq ! ( builder. prot, libc:: PROT_READ | libc:: PROT_WRITE ) ;
625
+
626
+ crate :: bitmap:: tests:: test_volatile_memory ( & ( builder. build ( ) . unwrap ( ) ) ) ;
513
627
}
514
628
515
629
#[ test]
0 commit comments