use alloc::boxed::Box; use x86_64::registers::model_specific::Msr; use x86_64::structures::gdt::*; use x86_64::structures::tss::TaskStateSegment; use x86_64::{PrivilegeLevel, VirtAddr}; use crate::consts::MAX_CPU_NUM; /// Init TSS & GDT. pub fn init() { unsafe { CPUS[super::cpu::id()] = Some(Cpu::new()); CPUS[super::cpu::id()].as_mut().unwrap().init(); } } static mut CPUS: [Option; MAX_CPU_NUM] = [ // TODO: More elegant ? None, None, None, None, None, None, None, None, ]; pub struct Cpu { gdt: GlobalDescriptorTable, tss: TaskStateSegment, double_fault_stack: [u8; 0x100], } impl Cpu { pub fn current() -> &'static mut Self { unsafe { CPUS[super::cpu::id()].as_mut().unwrap() } } fn new() -> Self { Cpu { gdt: GlobalDescriptorTable::new(), tss: TaskStateSegment::new(), double_fault_stack: [0u8; 0x100], } } unsafe fn init(&'static mut self) { use x86_64::instructions::segmentation::{load_fs, set_cs}; use x86_64::instructions::tables::load_tss; // Set the stack when DoubleFault occurs let stack_top = VirtAddr::new(self.double_fault_stack.as_ptr() as u64 + 0x100); self.tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX] = stack_top; // GDT self.gdt.add_entry(KCODE); self.gdt.add_entry(KDATA); self.gdt.add_entry(UCODE32); self.gdt.add_entry(UDATA32); self.gdt.add_entry(UCODE); self.gdt.add_entry(Descriptor::tss_segment(&self.tss)); self.gdt.load(); // reload code segment register set_cs(KCODE_SELECTOR); // load TSS load_tss(TSS_SELECTOR); // for fast syscall: // store address of TSS to kernel_gsbase let mut kernel_gsbase = Msr::new(0xC0000102); kernel_gsbase.write(&self.tss as *const _ as u64); } /// 设置从Ring3跳到Ring0时,自动切换栈的地址 /// /// 每次进入用户态前,都要调用此函数,才能保证正确返回内核态 pub fn set_ring0_rsp(&mut self, rsp: usize) { trace!("gdt.set_ring0_rsp: {:#x}", rsp); self.tss.privilege_stack_table[0] = VirtAddr::new(rsp as u64); } } pub const DOUBLE_FAULT_IST_INDEX: usize = 0; // Copied from xv6 x86_64 const KCODE: Descriptor = Descriptor::UserSegment(0x0020980000000000); // EXECUTABLE | USER_SEGMENT | PRESENT | LONG_MODE const UCODE: Descriptor = Descriptor::UserSegment(0x0020F80000000000); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT | LONG_MODE const KDATA: Descriptor = Descriptor::UserSegment(0x0000920000000000); // DATA_WRITABLE | USER_SEGMENT | PRESENT const UDATA: Descriptor = Descriptor::UserSegment(0x0000F20000000000); // DATA_WRITABLE | USER_SEGMENT | USER_MODE | PRESENT // Copied from xv6 const UCODE32: Descriptor = Descriptor::UserSegment(0x00cffa00_0000ffff); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT const UDATA32: Descriptor = Descriptor::UserSegment(0x00cff200_0000ffff); // EXECUTABLE | USER_SEGMENT | USER_MODE | PRESENT // NOTICE: for fast syscall: // STAR[47:32] = K_CS = K_SS - 8 // STAR[63:48] = U_CS32 = U_SS32 - 8 = U_CS - 16 pub const KCODE_SELECTOR: SegmentSelector = SegmentSelector::new(1, PrivilegeLevel::Ring0); pub const KDATA_SELECTOR: SegmentSelector = SegmentSelector::new(2, PrivilegeLevel::Ring0); pub const UCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring3); pub const UDATA32_SELECTOR: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3); pub const UCODE_SELECTOR: SegmentSelector = SegmentSelector::new(5, PrivilegeLevel::Ring3); pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(6, PrivilegeLevel::Ring0);