@@ -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.
@@ -153,6 +152,20 @@ where
153152 . flush ( ) ;
154153 }
155154
155+ // identity-map context switch function, so that we don't get an immediate pagefault
156+ // after switching the active page table
157+ let context_switch_function = PhysAddr :: new ( context_switch as * const ( ) as u64 ) ;
158+ let context_switch_function_start_frame: PhysFrame =
159+ PhysFrame :: containing_address ( context_switch_function) ;
160+ for frame in PhysFrame :: range_inclusive (
161+ context_switch_function_start_frame,
162+ context_switch_function_start_frame + 1 ,
163+ ) {
164+ unsafe { kernel_page_table. identity_map ( frame, PageTableFlags :: PRESENT , frame_allocator) }
165+ . unwrap ( )
166+ . flush ( ) ;
167+ }
168+
156169 // map framebuffer
157170 let framebuffer_virt_addr = if CONFIG . map_framebuffer {
158171 log:: info!( "Map framebuffer" ) ;
@@ -262,7 +275,7 @@ pub fn create_boot_info<I, D>(
262275 page_tables : & mut PageTables ,
263276 mappings : & mut Mappings ,
264277 system_info : SystemInfo ,
265- ) -> ( & ' static mut BootInfo , TwoFrames )
278+ ) -> & ' static mut BootInfo
266279where
267280 I : ExactSizeIterator < Item = D > + Clone ,
268281 D : LegacyMemoryRegion ,
@@ -310,9 +323,6 @@ where
310323 ( boot_info, memory_regions)
311324 } ;
312325
313- // reserve two unused frames for context switch
314- let two_frames = TwoFrames :: new ( & mut frame_allocator) ;
315-
316326 log:: info!( "Create Memory Map" ) ;
317327
318328 // build memory map
@@ -341,19 +351,17 @@ where
341351 tls_template : mappings. tls_template . into ( ) ,
342352 } ) ;
343353
344- ( boot_info, two_frames )
354+ boot_info
345355}
346356
347357/// Switches to the kernel address space and jumps to the kernel entry point.
348358pub fn switch_to_kernel (
349359 page_tables : PageTables ,
350360 mappings : Mappings ,
351361 boot_info : & ' static mut BootInfo ,
352- two_frames : TwoFrames ,
353362) -> ! {
354363 let PageTables {
355364 kernel_level_4_frame,
356- kernel : kernel_page_table,
357365 ..
358366 } = page_tables;
359367 let addresses = Addresses {
@@ -369,7 +377,7 @@ pub fn switch_to_kernel(
369377 ) ;
370378
371379 unsafe {
372- context_switch ( addresses, kernel_page_table , two_frames ) ;
380+ context_switch ( addresses) ;
373381 }
374382}
375383
@@ -388,32 +396,7 @@ pub struct PageTables {
388396}
389397
390398/// 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
399+ unsafe fn context_switch ( addresses : Addresses ) -> ! {
417400 unsafe {
418401 asm ! (
419402 "mov cr3, {}; mov rsp, {}; push 0; jmp {}" ,
@@ -434,36 +417,6 @@ struct Addresses {
434417 boot_info : & ' static mut crate :: boot_info:: BootInfo ,
435418}
436419
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-
467420fn boot_info_location ( used_entries : & mut UsedLevel4Entries ) -> VirtAddr {
468421 CONFIG
469422 . boot_info_address
0 commit comments