@@ -241,8 +241,18 @@ where
241241 context_switch_function_start_frame,
242242 context_switch_function_start_frame + 1 ,
243243 ) {
244+ let page = Page :: containing_address ( VirtAddr :: new ( frame. start_address ( ) . as_u64 ( ) ) ) ;
244245 match unsafe {
245- kernel_page_table. identity_map ( frame, PageTableFlags :: PRESENT , frame_allocator)
246+ // The parent table flags need to be both readable and writable to
247+ // support recursive page tables.
248+ // See https://github.com/rust-osdev/bootloader/issues/443#issuecomment-2130010621
249+ kernel_page_table. map_to_with_table_flags (
250+ page,
251+ frame,
252+ PageTableFlags :: PRESENT ,
253+ PageTableFlags :: PRESENT | PageTableFlags :: WRITABLE ,
254+ frame_allocator,
255+ )
246256 } {
247257 Ok ( tlb) => tlb. flush ( ) ,
248258 Err ( err) => panic ! ( "failed to identity map frame {:?}: {:?}" , frame, err) ,
@@ -254,8 +264,17 @@ where
254264 . allocate_frame ( )
255265 . expect ( "failed to allocate GDT frame" ) ;
256266 gdt:: create_and_load ( gdt_frame) ;
267+ let gdt_page = Page :: containing_address ( VirtAddr :: new ( gdt_frame. start_address ( ) . as_u64 ( ) ) ) ;
257268 match unsafe {
258- kernel_page_table. identity_map ( gdt_frame, PageTableFlags :: PRESENT , frame_allocator)
269+ // The parent table flags need to be both readable and writable to
270+ // support recursive page tables.
271+ kernel_page_table. map_to_with_table_flags (
272+ gdt_page,
273+ gdt_frame,
274+ PageTableFlags :: PRESENT ,
275+ PageTableFlags :: PRESENT | PageTableFlags :: WRITABLE ,
276+ frame_allocator,
277+ )
259278 } {
260279 Ok ( tlb) => tlb. flush ( ) ,
261280 Err ( err) => panic ! ( "failed to identity map frame {:?}: {:?}" , gdt_frame, err) ,
0 commit comments