@@ -8,13 +8,22 @@ use bootloader_api::{
88    info:: { FrameBuffer ,  FrameBufferInfo ,  MemoryRegion ,  TlsTemplate } , 
99    BootInfo ,  BootloaderConfig , 
1010} ; 
11- use  core:: { alloc:: Layout ,  arch:: asm,  mem:: MaybeUninit ,  slice} ; 
11+ use  core:: { 
12+     alloc:: Layout , 
13+     arch:: asm, 
14+     mem:: { size_of,  MaybeUninit } , 
15+     slice, 
16+ } ; 
1217use  level_4_entries:: UsedLevel4Entries ; 
1318use  usize_conversions:: { FromUsize ,  IntoUsize } ; 
1419use  x86_64:: { 
15-     structures:: paging:: { 
16-         page_table:: PageTableLevel ,  FrameAllocator ,  Mapper ,  OffsetPageTable ,  Page ,  PageSize , 
17-         PageTable ,  PageTableFlags ,  PageTableIndex ,  PhysFrame ,  Size2MiB ,  Size4KiB , 
20+     instructions:: tables:: { lgdt,  sgdt} , 
21+     structures:: { 
22+         gdt:: GlobalDescriptorTable , 
23+         paging:: { 
24+             page_table:: PageTableLevel ,  FrameAllocator ,  Mapper ,  OffsetPageTable ,  Page ,  PageSize , 
25+             PageTable ,  PageTableFlags ,  PageTableIndex ,  PhysFrame ,  Size2MiB ,  Size4KiB , 
26+         } , 
1827    } , 
1928    PhysAddr ,  VirtAddr , 
2029} ; 
@@ -201,8 +210,20 @@ where
201210        . allocate_frame ( ) 
202211        . expect ( "failed to allocate GDT frame" ) ; 
203212    gdt:: create_and_load ( gdt_frame) ; 
213+     let  gdt = mapping_addr ( 
214+         config. mappings . gdt , 
215+         u64:: from_usize ( size_of :: < GlobalDescriptorTable > ( ) ) , 
216+         4096 , 
217+         & mut  used_entries, 
218+     ) ; 
219+     let  gdt_page = Page :: from_start_address ( gdt) . unwrap ( ) ; 
204220    match  unsafe  { 
205-         kernel_page_table. identity_map ( gdt_frame,  PageTableFlags :: PRESENT ,  frame_allocator) 
221+         kernel_page_table. map_to ( 
222+             gdt_page, 
223+             gdt_frame, 
224+             PageTableFlags :: PRESENT , 
225+             frame_allocator, 
226+         ) 
206227    }  { 
207228        Ok ( tlb)  => tlb. flush ( ) , 
208229        Err ( err)  => panic ! ( "failed to identity map frame {:?}: {:?}" ,  gdt_frame,  err) , 
@@ -459,6 +480,7 @@ where
459480
460481        kernel_slice_start, 
461482        kernel_slice_len, 
483+         gdt, 
462484        context_switch_trampoline :  trampoline_page. start_address ( ) , 
463485        context_switch_page_table, 
464486        context_switch_page_table_frame, 
@@ -488,6 +510,8 @@ pub struct Mappings {
488510pub  kernel_slice_start :  u64 , 
489511    /// Size of the kernel slice allocation in memory. 
490512pub  kernel_slice_len :  u64 , 
513+     /// The address of the GDT in the kernel's address space. 
514+ pub  gdt :  VirtAddr , 
491515    /// The address of the context switch trampoline in the bootloader's address space. 
492516pub  context_switch_trampoline :  VirtAddr , 
493517    /// The page table used for context switch from the bootloader to the kernel. 
@@ -611,6 +635,7 @@ pub fn switch_to_kernel(
611635        ..
612636    }  = page_tables; 
613637    let  addresses = Addresses  { 
638+         gdt :  mappings. gdt , 
614639        context_switch_trampoline :  mappings. context_switch_trampoline , 
615640        context_switch_page_table :  mappings. context_switch_page_table_frame , 
616641        context_switch_addr :  mappings. context_switch_addr , 
@@ -645,6 +670,18 @@ pub struct PageTables {
645670
646671/// Performs the actual context switch. 
647672unsafe  fn  context_switch ( addresses :  Addresses )  -> ! { 
673+     // Update the GDT base address. 
674+     let  mut  gdt_pointer = sgdt ( ) ; 
675+     gdt_pointer. base  = addresses. gdt ; 
676+     unsafe  { 
677+         // SAFETY: Note that the base address points to memory that is only 
678+         //         mapped in the kernel's page table. We can do this because 
679+         //         just loading the GDT doesn't cause any immediate loads and 
680+         //         by the time the base address is dereferenced the context 
681+         //         switch will be done. 
682+         lgdt ( & gdt_pointer) ; 
683+     } 
684+ 
648685    unsafe  { 
649686        asm ! ( 
650687            "mov rsp, {}; sub rsp, 8; jmp {}" , 
@@ -661,6 +698,7 @@ unsafe fn context_switch(addresses: Addresses) -> ! {
661698
662699/// Memory addresses required for the context switch. 
663700struct  Addresses  { 
701+     gdt :  VirtAddr , 
664702    context_switch_trampoline :  VirtAddr , 
665703    context_switch_page_table :  PhysFrame , 
666704    context_switch_addr :  VirtAddr , 
0 commit comments