mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-08 14:16:47 +00:00
78 lines
2.5 KiB
Rust
78 lines
2.5 KiB
Rust
use x86::{current::task::TaskStateSegment, segmentation::SegmentSelector, Ring};
|
||
|
||
use crate::{
|
||
mm::{percpu::PerCpu, VirtAddr},
|
||
smp::core::smp_get_processor_id,
|
||
};
|
||
|
||
// === 段选择子在GDT中的索引 ===
|
||
/// kernel code segment selector
|
||
pub const KERNEL_CS: SegmentSelector = SegmentSelector::new(1, Ring::Ring0);
|
||
/// kernel data segment selector
|
||
pub const KERNEL_DS: SegmentSelector = SegmentSelector::new(2, Ring::Ring0);
|
||
/// user data segment selector
|
||
pub const USER_DS: SegmentSelector = SegmentSelector::new(5, Ring::Ring3);
|
||
/// user code segment selector
|
||
/// 如果改这里,记得改syscall_64里面写死的常量
|
||
pub const USER_CS: SegmentSelector = SegmentSelector::new(6, Ring::Ring3);
|
||
|
||
static mut TSS_MANAGER: TSSManager = TSSManager::new();
|
||
|
||
extern "C" {
|
||
static mut GDT_Table: [u64; 512];
|
||
}
|
||
/// 切换fs和gs段寄存器
|
||
///
|
||
/// 由于需要return使得它生效,所以不能inline
|
||
#[inline(never)]
|
||
pub unsafe fn switch_fs_and_gs(fs: SegmentSelector, gs: SegmentSelector) {
|
||
x86::segmentation::load_fs(fs);
|
||
x86::segmentation::load_gs(gs);
|
||
}
|
||
|
||
#[derive(Debug)]
|
||
pub struct TSSManager {
|
||
tss: [TaskStateSegment; PerCpu::MAX_CPU_NUM as usize],
|
||
}
|
||
|
||
impl TSSManager {
|
||
const fn new() -> Self {
|
||
return Self {
|
||
tss: [TaskStateSegment::new(); PerCpu::MAX_CPU_NUM as usize],
|
||
};
|
||
}
|
||
|
||
/// 获取当前CPU的TSS
|
||
pub unsafe fn current_tss() -> &'static mut TaskStateSegment {
|
||
&mut TSS_MANAGER.tss[smp_get_processor_id().data() as usize]
|
||
}
|
||
|
||
/// 加载当前CPU的TSS
|
||
pub unsafe fn load_tr() {
|
||
let index = (10 + smp_get_processor_id().data() * 2) as u16;
|
||
let selector = SegmentSelector::new(index, Ring::Ring0);
|
||
|
||
Self::set_tss_descriptor(
|
||
index,
|
||
VirtAddr::new(Self::current_tss() as *mut TaskStateSegment as usize),
|
||
);
|
||
x86::task::load_tr(selector);
|
||
}
|
||
|
||
#[allow(static_mut_refs)]
|
||
unsafe fn set_tss_descriptor(index: u16, vaddr: VirtAddr) {
|
||
const LIMIT: u64 = 103;
|
||
let gdt_vaddr = VirtAddr::new(&GDT_Table as *const _ as usize);
|
||
|
||
let gdt: &mut [u64] = core::slice::from_raw_parts_mut(gdt_vaddr.data() as *mut u64, 512);
|
||
|
||
let vaddr = vaddr.data() as u64;
|
||
gdt[index as usize] = (LIMIT & 0xffff)
|
||
| ((vaddr & 0xffff) << 16)
|
||
| (((vaddr >> 16) & 0xff) << 32)
|
||
| (0x89 << 40)
|
||
| (((vaddr >> 24) & 0xff) << 56);
|
||
gdt[index as usize + 1] = (vaddr >> 32) & 0xffffffff;
|
||
}
|
||
}
|