1 use x86::{current::task::TaskStateSegment, segmentation::SegmentSelector, Ring}; 2 3 use crate::{ 4 mm::{percpu::PerCpu, VirtAddr}, 5 smp::core::smp_get_processor_id, 6 }; 7 8 // === 段选择子在GDT中的索引 === 9 /// kernel code segment selector 10 pub const KERNEL_CS: SegmentSelector = SegmentSelector::new(1, Ring::Ring0); 11 /// kernel data segment selector 12 pub const KERNEL_DS: SegmentSelector = SegmentSelector::new(2, Ring::Ring0); 13 /// user code segment selector 14 pub const USER_CS: SegmentSelector = SegmentSelector::new(5, Ring::Ring3); 15 /// user data segment selector 16 pub const USER_DS: SegmentSelector = SegmentSelector::new(6, Ring::Ring3); 17 18 static mut TSS_MANAGER: TSSManager = TSSManager::new(); 19 20 extern "C" { 21 static mut GDT_Table: [u64; 512]; 22 } 23 /// 切换fs和gs段寄存器 24 /// 25 /// 由于需要return使得它生效,所以不能inline 26 #[inline(never)] 27 pub unsafe fn switch_fs_and_gs(fs: SegmentSelector, gs: SegmentSelector) { 28 x86::segmentation::load_fs(fs); 29 x86::segmentation::load_gs(gs); 30 } 31 32 #[derive(Debug)] 33 pub struct TSSManager { 34 tss: [TaskStateSegment; PerCpu::MAX_CPU_NUM], 35 } 36 37 impl TSSManager { 38 const fn new() -> Self { 39 return Self { 40 tss: [TaskStateSegment::new(); PerCpu::MAX_CPU_NUM], 41 }; 42 } 43 44 /// 获取当前CPU的TSS 45 pub unsafe fn current_tss() -> &'static mut TaskStateSegment { 46 &mut TSS_MANAGER.tss[smp_get_processor_id() as usize] 47 } 48 49 /// 加载当前CPU的TSS 50 pub unsafe fn load_tr() { 51 let index = (10 + smp_get_processor_id() * 2) as u16; 52 let selector = SegmentSelector::new(index, Ring::Ring0); 53 54 Self::set_tss_descriptor( 55 index, 56 VirtAddr::new(Self::current_tss() as *mut TaskStateSegment as usize), 57 ); 58 x86::task::load_tr(selector); 59 } 60 61 unsafe fn set_tss_descriptor(index: u16, vaddr: VirtAddr) { 62 const LIMIT: u64 = 103; 63 let gdt_vaddr = VirtAddr::new(&GDT_Table as *const _ as usize); 64 65 let gdt: &mut [u64] = core::slice::from_raw_parts_mut(gdt_vaddr.data() as *mut u64, 512); 66 67 let vaddr = vaddr.data() as u64; 68 gdt[index as usize] = (LIMIT & 0xffff) 69 | ((vaddr & 0xffff) << 16) 70 | (((vaddr >> 16) & 0xff) << 32) 71 | (0x89 << 40) 72 | (((vaddr >> 24) & 0xff) << 56); 73 gdt[index as usize + 1] = ((vaddr >> 32) & 0xffffffff) | 0; 74 } 75 } 76