@@ -7,10 +7,9 @@ pub use self::offset_page_table::OffsetPageTable;
77pub use self :: recursive_page_table:: { InvalidPageTable , RecursivePageTable } ;
88
99use crate :: structures:: paging:: {
10- frame_alloc:: { FrameAllocator , FrameDeallocator } ,
11- page:: PageRangeInclusive ,
12- page_table:: PageTableFlags ,
13- Page , PageSize , PhysFrame , Size1GiB , Size2MiB , Size4KiB ,
10+ frame:: PhysFrameRange , frame_alloc:: FrameAllocator , page:: PageRange ,
11+ page_table:: PageTableFlags , FrameDeallocator , Page , PageSize , PhysFrame , Size1GiB , Size2MiB ,
12+ Size4KiB ,
1413} ;
1514use crate :: { PhysAddr , VirtAddr } ;
1615
@@ -195,6 +194,52 @@ pub trait Mapper<S: PageSize> {
195194 self . map_to_with_table_flags ( page, frame, flags, parent_table_flags, frame_allocator)
196195 }
197196
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+
198243 /// Creates a new mapping in the page table.
199244 ///
200245 /// This function might need additional physical frames to create new page tables. These
@@ -277,11 +322,147 @@ pub trait Mapper<S: PageSize> {
277322 Self : Sized ,
278323 A : FrameAllocator < Size4KiB > + ?Sized ;
279324
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+
280426 /// Removes a mapping from the page table and returns the frame that used to be mapped.
281427 ///
282428 /// Note that no page tables or pages are deallocated.
283429 fn unmap ( & mut self , page : Page < S > ) -> Result < ( PhysFrame < S > , MapperFlush < S > ) , UnmapError > ;
284430
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+
285466 /// Updates the flags of an existing mapping.
286467 ///
287468 /// ## Safety
@@ -297,6 +478,39 @@ pub trait Mapper<S: PageSize> {
297478 flags : PageTableFlags ,
298479 ) -> Result < MapperFlush < S > , FlagUpdateError > ;
299480
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+
300514 /// Set the flags of an existing page level 4 table entry
301515 ///
302516 /// ## Safety
@@ -370,6 +584,31 @@ pub trait Mapper<S: PageSize> {
370584 let page = Page :: containing_address ( VirtAddr :: new ( frame. start_address ( ) . as_u64 ( ) ) ) ;
371585 self . map_to ( page, frame, flags, frame_allocator)
372586 }
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+ }
373612}
374613
375614/// This type represents a page whose mapping has changed in the page table.
@@ -403,6 +642,41 @@ impl<S: PageSize> MapperFlush<S> {
403642 pub fn ignore ( self ) { }
404643}
405644
645+ /// This type represents a range of pages whose mappings have changed in the page table.
646+ ///
647+ /// The old mappings might be still cached in the translation lookaside buffer (TLB), so they need
648+ /// to be flushed from the TLB before they're accessed. This type is returned from a function that
649+ /// changed the mappings of a range of pages to ensure that the TLB flush is not forgotten.
650+ #[ derive( Debug ) ]
651+ #[ must_use = "Page Table changes must be flushed or ignored." ]
652+ pub struct MapperFlushRange < S : PageSize > ( PageRange < S > ) ;
653+
654+ impl < S : PageSize > MapperFlushRange < S > {
655+ /// Create a new flush promise
656+ #[ inline]
657+ fn new ( pages : PageRange < S > ) -> Self {
658+ MapperFlushRange ( pages)
659+ }
660+
661+ /// Flush the page from the TLB to ensure that the newest mapping is used.
662+ #[ cfg( feature = "instructions" ) ]
663+ #[ inline]
664+ pub fn flush ( self ) {
665+ for page in self . 0 {
666+ crate :: instructions:: tlb:: flush ( page. start_address ( ) )
667+ }
668+ }
669+
670+ /// Don't flush the TLB and silence the “must be used” warning.
671+ #[ inline]
672+ pub fn ignore ( self ) { }
673+
674+ /// Get the range of changed pages.
675+ pub fn pages ( & self ) -> PageRange < S > {
676+ self . 0
677+ }
678+ }
679+
406680/// This type represents a change of a page table requiring a complete TLB flush
407681///
408682/// The old mapping might be still cached in the translation lookaside buffer (TLB), so it needs
0 commit comments