@@ -10,10 +10,9 @@ use level_4_entries::UsedLevel4Entries;
1010use parsed_config:: CONFIG ;
1111use usize_conversions:: FromUsize ;
1212use x86_64:: {
13- registers,
1413 structures:: paging:: {
1514 FrameAllocator , Mapper , OffsetPageTable , Page , PageTableFlags , PageTableIndex , PhysFrame ,
16- Size2MiB , Size4KiB ,
15+ Size2MiB ,
1716 } ,
1817 PhysAddr , VirtAddr ,
1918} ;
@@ -90,13 +89,13 @@ where
9089 system_info. framebuffer_addr ,
9190 system_info. framebuffer_info . byte_len ,
9291 ) ;
93- let ( boot_info, two_frames ) = create_boot_info (
92+ let boot_info = create_boot_info (
9493 frame_allocator,
9594 & mut page_tables,
9695 & mut mappings,
9796 system_info,
9897 ) ;
99- switch_to_kernel ( page_tables, mappings, boot_info, two_frames ) ;
98+ switch_to_kernel ( page_tables, mappings, boot_info) ;
10099}
101100
102101/// Sets up mappings for a kernel stack and the framebuffer.
@@ -148,9 +147,27 @@ where
148147 . allocate_frame ( )
149148 . expect ( "frame allocation failed when mapping a kernel stack" ) ;
150149 let flags = PageTableFlags :: PRESENT | PageTableFlags :: WRITABLE ;
151- unsafe { kernel_page_table. map_to ( page, frame, flags, frame_allocator) }
152- . unwrap ( )
153- . flush ( ) ;
150+ match unsafe { kernel_page_table. map_to ( page, frame, flags, frame_allocator) } {
151+ Ok ( tlb) => tlb. flush ( ) ,
152+ Err ( err) => panic ! ( "failed to map page {:?}: {:?}" , page, err) ,
153+ }
154+ }
155+
156+ // identity-map context switch function, so that we don't get an immediate pagefault
157+ // after switching the active page table
158+ let context_switch_function = PhysAddr :: new ( context_switch as * const ( ) as u64 ) ;
159+ let context_switch_function_start_frame: PhysFrame =
160+ PhysFrame :: containing_address ( context_switch_function) ;
161+ for frame in PhysFrame :: range_inclusive (
162+ context_switch_function_start_frame,
163+ context_switch_function_start_frame + 1 ,
164+ ) {
165+ match unsafe {
166+ kernel_page_table. identity_map ( frame, PageTableFlags :: PRESENT , frame_allocator)
167+ } {
168+ Ok ( tlb) => tlb. flush ( ) ,
169+ Err ( err) => panic ! ( "failed to identity map frame {:?}: {:?}" , frame, err) ,
170+ }
154171 }
155172
156173 // map framebuffer
@@ -166,9 +183,13 @@ where
166183 {
167184 let page = start_page + u64:: from_usize ( i) ;
168185 let flags = PageTableFlags :: PRESENT | PageTableFlags :: WRITABLE ;
169- unsafe { kernel_page_table. map_to ( page, frame, flags, frame_allocator) }
170- . unwrap ( )
171- . flush ( ) ;
186+ match unsafe { kernel_page_table. map_to ( page, frame, flags, frame_allocator) } {
187+ Ok ( tlb) => tlb. flush ( ) ,
188+ Err ( err) => panic ! (
189+ "failed to map page {:?} to frame {:?}: {:?}" ,
190+ page, frame, err
191+ ) ,
192+ }
172193 }
173194 let framebuffer_virt_addr = start_page. start_address ( ) ;
174195 Some ( framebuffer_virt_addr)
@@ -189,9 +210,13 @@ where
189210 for frame in PhysFrame :: range_inclusive ( start_frame, end_frame) {
190211 let page = Page :: containing_address ( offset + frame. start_address ( ) . as_u64 ( ) ) ;
191212 let flags = PageTableFlags :: PRESENT | PageTableFlags :: WRITABLE ;
192- unsafe { kernel_page_table. map_to ( page, frame, flags, frame_allocator) }
193- . unwrap ( )
194- . ignore ( ) ;
213+ match unsafe { kernel_page_table. map_to ( page, frame, flags, frame_allocator) } {
214+ Ok ( tlb) => tlb. ignore ( ) ,
215+ Err ( err) => panic ! (
216+ "failed to map page {:?} to frame {:?}: {:?}" ,
217+ page, frame, err
218+ ) ,
219+ } ;
195220 }
196221
197222 Some ( offset)
@@ -262,7 +287,7 @@ pub fn create_boot_info<I, D>(
262287 page_tables : & mut PageTables ,
263288 mappings : & mut Mappings ,
264289 system_info : SystemInfo ,
265- ) -> ( & ' static mut BootInfo , TwoFrames )
290+ ) -> & ' static mut BootInfo
266291where
267292 I : ExactSizeIterator < Item = D > + Clone ,
268293 D : LegacyMemoryRegion ,
@@ -286,21 +311,23 @@ where
286311 let frame = frame_allocator
287312 . allocate_frame ( )
288313 . expect ( "frame allocation for boot info failed" ) ;
289- unsafe {
314+ match unsafe {
290315 page_tables
291316 . kernel
292317 . map_to ( page, frame, flags, & mut frame_allocator)
318+ } {
319+ Ok ( tlb) => tlb. flush ( ) ,
320+ Err ( err) => panic ! ( "failed to map page {:?}: {:?}" , page, err) ,
293321 }
294- . unwrap ( )
295- . flush ( ) ;
296322 // we need to be able to access it too
297- unsafe {
323+ match unsafe {
298324 page_tables
299325 . bootloader
300326 . map_to ( page, frame, flags, & mut frame_allocator)
327+ } {
328+ Ok ( tlb) => tlb. flush ( ) ,
329+ Err ( err) => panic ! ( "failed to map page {:?}: {:?}" , page, err) ,
301330 }
302- . unwrap ( )
303- . flush ( ) ;
304331 }
305332
306333 let boot_info: & ' static mut MaybeUninit < BootInfo > =
@@ -310,9 +337,6 @@ where
310337 ( boot_info, memory_regions)
311338 } ;
312339
313- // reserve two unused frames for context switch
314- let two_frames = TwoFrames :: new ( & mut frame_allocator) ;
315-
316340 log:: info!( "Create Memory Map" ) ;
317341
318342 // build memory map
@@ -341,19 +365,17 @@ where
341365 tls_template : mappings. tls_template . into ( ) ,
342366 } ) ;
343367
344- ( boot_info, two_frames )
368+ boot_info
345369}
346370
347371/// Switches to the kernel address space and jumps to the kernel entry point.
348372pub fn switch_to_kernel (
349373 page_tables : PageTables ,
350374 mappings : Mappings ,
351375 boot_info : & ' static mut BootInfo ,
352- two_frames : TwoFrames ,
353376) -> ! {
354377 let PageTables {
355378 kernel_level_4_frame,
356- kernel : kernel_page_table,
357379 ..
358380 } = page_tables;
359381 let addresses = Addresses {
@@ -369,7 +391,7 @@ pub fn switch_to_kernel(
369391 ) ;
370392
371393 unsafe {
372- context_switch ( addresses, kernel_page_table , two_frames ) ;
394+ context_switch ( addresses) ;
373395 }
374396}
375397
@@ -388,32 +410,7 @@ pub struct PageTables {
388410}
389411
390412/// Performs the actual context switch.
391- ///
392- /// This function uses the given `frame_allocator` to identity map itself in the kernel-level
393- /// page table. This is required to avoid a page fault after the context switch. Since this
394- /// function is relatively small, only up to two physical frames are required from the frame
395- /// allocator, so the [`TwoFrames`] type can be used here.
396- unsafe fn context_switch (
397- addresses : Addresses ,
398- mut kernel_page_table : OffsetPageTable ,
399- mut frame_allocator : impl FrameAllocator < Size4KiB > ,
400- ) -> ! {
401- // identity-map current and next frame, so that we don't get an immediate pagefault
402- // after switching the active page table
403- let current_addr = PhysAddr :: new ( registers:: read_rip ( ) . as_u64 ( ) ) ;
404- let current_frame: PhysFrame = PhysFrame :: containing_address ( current_addr) ;
405- for frame in PhysFrame :: range_inclusive ( current_frame, current_frame + 1 ) {
406- unsafe {
407- kernel_page_table. identity_map ( frame, PageTableFlags :: PRESENT , & mut frame_allocator)
408- }
409- . unwrap ( )
410- . flush ( ) ;
411- }
412-
413- // we don't need the kernel page table anymore
414- mem:: drop ( kernel_page_table) ;
415-
416- // do the context switch
413+ unsafe fn context_switch ( addresses : Addresses ) -> ! {
417414 unsafe {
418415 asm ! (
419416 "mov cr3, {}; mov rsp, {}; push 0; jmp {}" ,
@@ -434,36 +431,6 @@ struct Addresses {
434431 boot_info : & ' static mut crate :: boot_info:: BootInfo ,
435432}
436433
437- /// Used for reversing two physical frames for identity mapping the context switch function.
438- ///
439- /// In order to prevent a page fault, the context switch function must be mapped identically in
440- /// both address spaces. The context switch function is small, so this mapping requires only
441- /// two physical frames (one frame is not enough because the linker might place the function
442- /// directly before a page boundary). Since the frame allocator no longer exists when the
443- /// context switch function is invoked, we use this type to reserve two physical frames
444- /// beforehand.
445- pub struct TwoFrames {
446- frames : [ Option < PhysFrame > ; 2 ] ,
447- }
448-
449- impl TwoFrames {
450- /// Creates a new instance by allocating two physical frames from the given frame allocator.
451- pub fn new ( frame_allocator : & mut impl FrameAllocator < Size4KiB > ) -> Self {
452- TwoFrames {
453- frames : [
454- Some ( frame_allocator. allocate_frame ( ) . unwrap ( ) ) ,
455- Some ( frame_allocator. allocate_frame ( ) . unwrap ( ) ) ,
456- ] ,
457- }
458- }
459- }
460-
461- unsafe impl FrameAllocator < Size4KiB > for TwoFrames {
462- fn allocate_frame ( & mut self ) -> Option < PhysFrame < Size4KiB > > {
463- self . frames . iter_mut ( ) . find_map ( |f| f. take ( ) )
464- }
465- }
466-
467434fn boot_info_location ( used_entries : & mut UsedLevel4Entries ) -> VirtAddr {
468435 CONFIG
469436 . boot_info_address
0 commit comments