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