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