@@ -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} ;
@@ -189,8 +198,20 @@ where
189198 . allocate_frame ( )
190199 . expect ( "failed to allocate GDT frame" ) ;
191200 gdt:: create_and_load ( gdt_frame) ;
201+ let gdt = mapping_addr (
202+ config. mappings . gdt ,
203+ u64:: from_usize ( size_of :: < GlobalDescriptorTable > ( ) ) ,
204+ 4096 ,
205+ & mut used_entries,
206+ ) ;
207+ let gdt_page = Page :: from_start_address ( gdt) . unwrap ( ) ;
192208 match unsafe {
193- kernel_page_table. identity_map ( gdt_frame, PageTableFlags :: PRESENT , frame_allocator)
209+ kernel_page_table. map_to (
210+ gdt_page,
211+ gdt_frame,
212+ PageTableFlags :: PRESENT ,
213+ frame_allocator,
214+ )
194215 } {
195216 Ok ( tlb) => tlb. flush ( ) ,
196217 Err ( err) => panic ! ( "failed to identity map frame {:?}: {:?}" , gdt_frame, err) ,
@@ -442,6 +463,7 @@ where
442463 physical_memory_offset,
443464 recursive_index,
444465 tls_template,
466+ gdt,
445467 context_switch_trampoline : trampoline_page. start_address ( ) ,
446468 context_switch_page_table,
447469 context_switch_page_table_frame,
@@ -466,6 +488,8 @@ pub struct Mappings {
466488 pub recursive_index : Option < PageTableIndex > ,
467489 /// The thread local storage template of the kernel executable, if it contains one.
468490 pub tls_template : Option < TlsTemplate > ,
491+ /// The address of the GDT in the kernel's address space.
492+ pub gdt : VirtAddr ,
469493 /// The address of the context switch trampoline in the bootloader's address space.
470494 pub context_switch_trampoline : VirtAddr ,
471495 /// The page table used for context switch from the bootloader to the kernel.
@@ -591,6 +615,7 @@ pub fn switch_to_kernel(
591615 ..
592616 } = page_tables;
593617 let addresses = Addresses {
618+ gdt : mappings. gdt ,
594619 context_switch_trampoline : mappings. context_switch_trampoline ,
595620 context_switch_page_table : mappings. context_switch_page_table_frame ,
596621 context_switch_addr : mappings. context_switch_addr ,
@@ -625,6 +650,18 @@ pub struct PageTables {
625650
626651/// Performs the actual context switch.
627652unsafe fn context_switch ( addresses : Addresses ) -> ! {
653+ // Update the GDT base address.
654+ let mut gdt_pointer = sgdt ( ) ;
655+ gdt_pointer. base = addresses. gdt ;
656+ unsafe {
657+ // SAFETY: Note that the base address points to memory that is only
658+ // mapped in the kernel's page table. We can do this because
659+ // just loading the GDT doesn't cause any immediate loads and
660+ // by the time the base address is dereferenced the context
661+ // switch will be done.
662+ lgdt ( & gdt_pointer) ;
663+ }
664+
628665 unsafe {
629666 asm ! (
630667 "mov rsp, {}; sub rsp, 8; jmp {}" ,
@@ -641,6 +678,7 @@ unsafe fn context_switch(addresses: Addresses) -> ! {
641678
642679/// Memory addresses required for the context switch.
643680struct Addresses {
681+ gdt : VirtAddr ,
644682 context_switch_trampoline : VirtAddr ,
645683 context_switch_page_table : PhysFrame ,
646684 context_switch_addr : VirtAddr ,
0 commit comments