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