@@ -7,8 +7,9 @@ pub use self::offset_page_table::OffsetPageTable;
7
7
pub use self :: recursive_page_table:: { InvalidPageTable , RecursivePageTable } ;
8
8
9
9
use crate :: structures:: paging:: {
10
+ frame:: PhysFrameRange ,
10
11
frame_alloc:: { FrameAllocator , FrameDeallocator } ,
11
- page:: PageRangeInclusive ,
12
+ page:: { PageRange , PageRangeInclusive } ,
12
13
page_table:: PageTableFlags ,
13
14
Page , PageSize , PhysFrame , Size1GiB , Size2MiB , Size4KiB ,
14
15
} ;
@@ -197,6 +198,52 @@ pub trait Mapper<S: PageSize> {
197
198
}
198
199
}
199
200
201
+ /// Maps the given range of frames to the range of virtual pages.
202
+ ///
203
+ /// ## Safety
204
+ ///
205
+ /// This is a convencience function that invokes [`Mapper::map_to`] internally, so
206
+ /// all safety requirements of it also apply for this function.
207
+ ///
208
+ /// ## Panics
209
+ ///
210
+ /// This function panics if the amount of pages does not equal the amount of frames.
211
+ ///
212
+ /// ## Errors
213
+ ///
214
+ /// If an error occurs half-way through a [`MapperFlushRange<S>`] is returned that contains the frames that were successfully mapped.
215
+ #[ inline]
216
+ unsafe fn map_to_range < A > (
217
+ & mut self ,
218
+ pages : PageRange < S > ,
219
+ frames : PhysFrameRange < S > ,
220
+ flags : PageTableFlags ,
221
+ frame_allocator : & mut A ,
222
+ ) -> Result < MapperFlushRange < S > , ( MapToError < S > , MapperFlushRange < S > ) >
223
+ where
224
+ Self : Sized ,
225
+ A : FrameAllocator < Size4KiB > + ?Sized ,
226
+ {
227
+ assert_eq ! ( pages. count( ) , frames. count( ) ) ;
228
+
229
+ pages
230
+ . zip ( frames)
231
+ . try_for_each ( |( page, frame) | {
232
+ unsafe { self . map_to ( page, frame, flags, frame_allocator) }
233
+ . map ( |_| ( ) )
234
+ . map_err ( |e| {
235
+ (
236
+ e,
237
+ MapperFlushRange :: new ( PageRange {
238
+ start : pages. start ,
239
+ end : page,
240
+ } ) ,
241
+ )
242
+ } )
243
+ } )
244
+ . map ( |_| MapperFlushRange :: new ( pages) )
245
+ }
246
+
200
247
/// Creates a new mapping in the page table.
201
248
///
202
249
/// This function might need additional physical frames to create new page tables. These
@@ -279,11 +326,151 @@ pub trait Mapper<S: PageSize> {
279
326
Self : Sized ,
280
327
A : FrameAllocator < Size4KiB > + ?Sized ;
281
328
329
+ /// Maps the given range of frames to the range of virtual pages.
330
+ ///
331
+ /// ## Safety
332
+ ///
333
+ /// This is a convencience function that invokes [`Mapper::map_to_with_table_flags`] internally, so
334
+ /// all safety requirements of it also apply for this function.
335
+ ///
336
+ /// ## Panics
337
+ ///
338
+ /// This function panics if the amount of pages does not equal the amount of frames.
339
+ ///
340
+ /// ## Errors
341
+ ///
342
+ /// If an error occurs half-way through a [`MapperFlushRange<S>`] is returned that contains the frames that were successfully mapped.
343
+ unsafe fn map_to_range_with_table_flags < A > (
344
+ & mut self ,
345
+ pages : PageRange < S > ,
346
+ frames : PhysFrameRange < S > ,
347
+ flags : PageTableFlags ,
348
+ parent_table_flags : PageTableFlags ,
349
+ frame_allocator : & mut A ,
350
+ ) -> Result < MapperFlushRange < S > , ( MapToError < S > , MapperFlushRange < S > ) >
351
+ where
352
+ Self : Sized ,
353
+ A : FrameAllocator < Size4KiB > + ?Sized ,
354
+ {
355
+ assert_eq ! ( pages. count( ) , frames. count( ) ) ;
356
+
357
+ pages
358
+ . zip ( frames)
359
+ . try_for_each ( |( page, frame) | {
360
+ unsafe {
361
+ self . map_to_with_table_flags (
362
+ page,
363
+ frame,
364
+ flags,
365
+ parent_table_flags,
366
+ frame_allocator,
367
+ )
368
+ }
369
+ . map ( |_| ( ) )
370
+ . map_err ( |e| {
371
+ (
372
+ e,
373
+ MapperFlushRange :: new ( PageRange {
374
+ start : pages. start ,
375
+ end : page,
376
+ } ) ,
377
+ )
378
+ } )
379
+ } )
380
+ . map ( |_| MapperFlushRange :: new ( pages) )
381
+ }
382
+
383
+ /// Maps frames from the allocator to the given range of virtual pages.
384
+ ///
385
+ /// ## Safety
386
+ ///
387
+ /// This is a convencience function that invokes [`Mapper::map_to_with_table_flags`] internally, so
388
+ /// all safety requirements of it also apply for this function.
389
+ ///
390
+ /// ## Errors
391
+ ///
392
+ /// If an error occurs half-way through a [`MapperFlushRange<S>`] is returned that contains the frames that were successfully mapped.
393
+ unsafe fn map_range_with_table_flags < A > (
394
+ & mut self ,
395
+ mut pages : PageRange < S > ,
396
+ flags : PageTableFlags ,
397
+ parent_table_flags : PageTableFlags ,
398
+ frame_allocator : & mut A ,
399
+ ) -> Result < MapperFlushRange < S > , ( MapToError < S > , MapperFlushRange < S > ) >
400
+ where
401
+ Self : Sized ,
402
+ A : FrameAllocator < Size4KiB > + FrameAllocator < S > + ?Sized ,
403
+ {
404
+ pages
405
+ . try_for_each ( |page| {
406
+ let frame = frame_allocator
407
+ . allocate_frame ( )
408
+ . ok_or ( ( MapToError :: FrameAllocationFailed , page) ) ?;
409
+
410
+ unsafe {
411
+ self . map_to_with_table_flags (
412
+ page,
413
+ frame,
414
+ flags,
415
+ parent_table_flags,
416
+ frame_allocator,
417
+ )
418
+ }
419
+ . map ( |_| ( ) )
420
+ . map_err ( |e| ( e, page) )
421
+ } )
422
+ . map ( |_| MapperFlushRange :: new ( pages) )
423
+ . map_err ( |( e, page) | {
424
+ (
425
+ e,
426
+ MapperFlushRange :: new ( PageRange {
427
+ start : pages. start ,
428
+ end : page,
429
+ } ) ,
430
+ )
431
+ } )
432
+ }
433
+
282
434
/// Removes a mapping from the page table and returns the frame that used to be mapped.
283
435
///
284
436
/// Note that no page tables or pages are deallocated.
285
437
fn unmap ( & mut self , page : Page < S > ) -> Result < ( PhysFrame < S > , MapperFlush < S > ) , UnmapError > ;
286
438
439
+ /// Removes a range of mapping from the page table and deallocate the frames that used to be mapped.
440
+ ///
441
+ /// Note that no page tables or pages are deallocated.
442
+ ///
443
+ /// ## Errors
444
+ /// If an error occurs half-way through a [`MapperFlushRange<S>`] is returned that contains the pages that were successfully unmapped.
445
+ fn unmap_range < D > (
446
+ & mut self ,
447
+ pages : PageRange < S > ,
448
+ deallocator : & mut D ,
449
+ ) -> Result < MapperFlushRange < S > , ( UnmapError , MapperFlushRange < S > ) >
450
+ where
451
+ D : FrameDeallocator < S > ,
452
+ {
453
+ pages
454
+ . clone ( )
455
+ . try_for_each ( |page| {
456
+ let ( frame, _) = self . unmap ( page) . map_err ( |e| {
457
+ (
458
+ e,
459
+ MapperFlushRange :: new ( PageRange {
460
+ start : pages. start ,
461
+ end : page,
462
+ } ) ,
463
+ )
464
+ } ) ?;
465
+ unsafe {
466
+ // SAFETY: the page has been unmapped so the frame is unused
467
+ deallocator. deallocate_frame ( frame) ;
468
+ }
469
+ Ok ( ( ) )
470
+ } )
471
+ . map ( |_| MapperFlushRange :: new ( pages) )
472
+ }
473
+
287
474
/// Updates the flags of an existing mapping.
288
475
///
289
476
/// ## Safety
@@ -299,6 +486,41 @@ pub trait Mapper<S: PageSize> {
299
486
flags : PageTableFlags ,
300
487
) -> Result < MapperFlush < S > , FlagUpdateError > ;
301
488
489
+ /// Updates the flags of a range of existing mappings.
490
+ ///
491
+ /// ## Safety
492
+ ///
493
+ /// This method is unsafe because changing the flags of a mapping
494
+ /// might result in undefined behavior. For example, setting the
495
+ /// `GLOBAL` and `WRITABLE` flags for a page might result in the corruption
496
+ /// of values stored in that page from processes running in other address
497
+ /// spaces.
498
+ ///
499
+ /// ## Errors
500
+ /// If an error occurs half-way through a [`MapperFlushRange<S>`] is returned that contains the pages that were successfully updated.
501
+ unsafe fn update_flags_range (
502
+ & mut self ,
503
+ pages : PageRange < S > ,
504
+ flags : PageTableFlags ,
505
+ ) -> Result < MapperFlushRange < S > , ( FlagUpdateError , MapperFlushRange < S > ) > {
506
+ pages
507
+ . clone ( )
508
+ . try_for_each ( |page| {
509
+ unsafe { self . update_flags ( page, flags) }
510
+ . map ( |_| ( ) )
511
+ . map_err ( |e| {
512
+ (
513
+ e,
514
+ MapperFlushRange :: new ( PageRange {
515
+ start : pages. start ,
516
+ end : page,
517
+ } ) ,
518
+ )
519
+ } )
520
+ } )
521
+ . map ( |_| MapperFlushRange :: new ( pages) )
522
+ }
523
+
302
524
/// Set the flags of an existing page level 4 table entry
303
525
///
304
526
/// ## Safety
@@ -372,6 +594,31 @@ pub trait Mapper<S: PageSize> {
372
594
let page = Page :: containing_address ( VirtAddr :: new ( frame. start_address ( ) . as_u64 ( ) ) ) ;
373
595
unsafe { self . map_to ( page, frame, flags, frame_allocator) }
374
596
}
597
+
598
+ /// Maps the given range of frames to the range of virtual pages with the same address.
599
+ ///
600
+ /// ## Safety
601
+ ///
602
+ /// This is a convencience function that invokes [`Mapper::map_to_range`] internally, so
603
+ /// all safety requirements of it also apply for this function.
604
+ #[ inline]
605
+ unsafe fn identity_map_range < A > (
606
+ & mut self ,
607
+ frames : PhysFrameRange < S > ,
608
+ flags : PageTableFlags ,
609
+ frame_allocator : & mut A ,
610
+ ) -> Result < MapperFlushRange < S > , ( MapToError < S > , MapperFlushRange < S > ) >
611
+ where
612
+ Self : Sized ,
613
+ A : FrameAllocator < Size4KiB > + ?Sized ,
614
+ S : PageSize ,
615
+ Self : Mapper < S > ,
616
+ {
617
+ let start = Page :: containing_address ( VirtAddr :: new ( frames. start . start_address ( ) . as_u64 ( ) ) ) ;
618
+ let end = Page :: containing_address ( VirtAddr :: new ( frames. end . start_address ( ) . as_u64 ( ) ) ) ;
619
+ let pages = PageRange { start, end } ;
620
+ unsafe { self . map_to_range ( pages, frames, flags, frame_allocator) }
621
+ }
375
622
}
376
623
377
624
/// This type represents a page whose mapping has changed in the page table.
@@ -405,6 +652,41 @@ impl<S: PageSize> MapperFlush<S> {
405
652
pub fn ignore ( self ) { }
406
653
}
407
654
655
+ /// This type represents a range of pages whose mappings have changed in the page table.
656
+ ///
657
+ /// The old mappings might be still cached in the translation lookaside buffer (TLB), so they need
658
+ /// to be flushed from the TLB before they're accessed. This type is returned from a function that
659
+ /// changed the mappings of a range of pages to ensure that the TLB flush is not forgotten.
660
+ #[ derive( Debug ) ]
661
+ #[ must_use = "Page Table changes must be flushed or ignored." ]
662
+ pub struct MapperFlushRange < S : PageSize > ( PageRange < S > ) ;
663
+
664
+ impl < S : PageSize > MapperFlushRange < S > {
665
+ /// Create a new flush promise
666
+ #[ inline]
667
+ fn new ( pages : PageRange < S > ) -> Self {
668
+ MapperFlushRange ( pages)
669
+ }
670
+
671
+ /// Flush the page from the TLB to ensure that the newest mapping is used.
672
+ #[ cfg( feature = "instructions" ) ]
673
+ #[ inline]
674
+ pub fn flush ( self ) {
675
+ for page in self . 0 {
676
+ crate :: instructions:: tlb:: flush ( page. start_address ( ) )
677
+ }
678
+ }
679
+
680
+ /// Don't flush the TLB and silence the “must be used” warning.
681
+ #[ inline]
682
+ pub fn ignore ( self ) { }
683
+
684
+ /// Get the range of changed pages.
685
+ pub fn pages ( & self ) -> PageRange < S > {
686
+ self . 0
687
+ }
688
+ }
689
+
408
690
/// This type represents a change of a page table requiring a complete TLB flush
409
691
///
410
692
/// The old mapping might be still cached in the translation lookaside buffer (TLB), so it needs
0 commit comments