@@ -7,8 +7,9 @@ pub use self::offset_page_table::OffsetPageTable;
77pub use self :: recursive_page_table:: { InvalidPageTable , RecursivePageTable } ;
88
99use crate :: structures:: paging:: {
10+ frame:: PhysFrameRange ,
1011 frame_alloc:: { FrameAllocator , FrameDeallocator } ,
11- page:: PageRangeInclusive ,
12+ page:: { PageRange , PageRangeInclusive } ,
1213 page_table:: PageTableFlags ,
1314 Page , PageSize , PhysFrame , Size1GiB , Size2MiB , Size4KiB ,
1415} ;
@@ -197,6 +198,52 @@ pub trait Mapper<S: PageSize> {
197198 }
198199 }
199200
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+
200247 /// Creates a new mapping in the page table.
201248 ///
202249 /// This function might need additional physical frames to create new page tables. These
@@ -279,11 +326,151 @@ pub trait Mapper<S: PageSize> {
279326 Self : Sized ,
280327 A : FrameAllocator < Size4KiB > + ?Sized ;
281328
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+
282434 /// Removes a mapping from the page table and returns the frame that used to be mapped.
283435 ///
284436 /// Note that no page tables or pages are deallocated.
285437 fn unmap ( & mut self , page : Page < S > ) -> Result < ( PhysFrame < S > , MapperFlush < S > ) , UnmapError > ;
286438
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+
287474 /// Updates the flags of an existing mapping.
288475 ///
289476 /// ## Safety
@@ -299,6 +486,41 @@ pub trait Mapper<S: PageSize> {
299486 flags : PageTableFlags ,
300487 ) -> Result < MapperFlush < S > , FlagUpdateError > ;
301488
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+
302524 /// Set the flags of an existing page level 4 table entry
303525 ///
304526 /// ## Safety
@@ -372,6 +594,31 @@ pub trait Mapper<S: PageSize> {
372594 let page = Page :: containing_address ( VirtAddr :: new ( frame. start_address ( ) . as_u64 ( ) ) ) ;
373595 unsafe { self . map_to ( page, frame, flags, frame_allocator) }
374596 }
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+ }
375622}
376623
377624/// This type represents a page whose mapping has changed in the page table.
@@ -405,6 +652,41 @@ impl<S: PageSize> MapperFlush<S> {
405652 pub fn ignore ( self ) { }
406653}
407654
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+
408690/// This type represents a change of a page table requiring a complete TLB flush
409691///
410692/// The old mapping might be still cached in the translation lookaside buffer (TLB), so it needs
0 commit comments