good_os_framework/arch/
gdt.rs

1use spin::Lazy;
2use x86_64::instructions::segmentation::{Segment, CS, SS};
3use x86_64::instructions::tables::load_tss;
4use x86_64::structures::gdt::GlobalDescriptorTable;
5use x86_64::structures::gdt::{Descriptor, SegmentSelector};
6use x86_64::structures::tss::TaskStateSegment;
7use x86_64::VirtAddr;
8
9pub const DOUBLE_FAULT_IST_INDEX: usize = 0;
10const FAULT_STACK_SIZE: usize = 256;
11
12pub struct CpuInfo {
13    gdt: GlobalDescriptorTable,
14    tss: TaskStateSegment,
15    selectors: Option<Selectors>,
16    fault_stack: [u8; FAULT_STACK_SIZE],
17}
18
19impl CpuInfo {
20    pub fn new() -> Self {
21        Self {
22            gdt: GlobalDescriptorTable::new(),
23            tss: TaskStateSegment::new(),
24            selectors: None,
25            fault_stack: [0; FAULT_STACK_SIZE],
26        }
27    }
28
29    pub fn init(&mut self) {
30        let (mut gdt, mut selectors) = COMMON_GDT.clone();
31
32        self.tss.interrupt_stack_table[DOUBLE_FAULT_IST_INDEX] = {
33            let stack_start = self.fault_stack.as_ptr() as u64;
34            VirtAddr::new(stack_start + self.fault_stack.len() as u64)
35        };
36
37        let tss_ptr: *const _ = &self.tss;
38        let tss_selector = Some(gdt.append(Descriptor::tss_segment(unsafe { &*tss_ptr })));
39        selectors.tss_selector = tss_selector;
40
41        self.gdt = gdt;
42        self.selectors = Some(selectors);
43    }
44
45    pub fn load(&self) {
46        let gdt_ptr: *const _ = &self.gdt;
47        unsafe { (&*gdt_ptr).load() }
48
49        let selectors = &self.selectors.as_ref().unwrap();
50        unsafe {
51            CS::set_reg(selectors.code_selector);
52            SS::set_reg(selectors.data_selector);
53            load_tss(selectors.tss_selector.unwrap());
54        }
55    }
56
57    pub fn set_ring0_rsp(&mut self, rsp: VirtAddr) {
58        self.tss.privilege_stack_table[0] = rsp;
59    }
60}
61
62static COMMON_GDT: Lazy<(GlobalDescriptorTable, Selectors)> = Lazy::new(|| {
63    let mut gdt = GlobalDescriptorTable::new();
64
65    let code_selector = gdt.append(Descriptor::kernel_code_segment());
66    let data_selector = gdt.append(Descriptor::kernel_data_segment());
67    let user_data_selector = gdt.append(Descriptor::user_data_segment());
68    let user_code_selector = gdt.append(Descriptor::user_code_segment());
69
70    let selectors = Selectors {
71        code_selector,
72        data_selector,
73        user_data_selector,
74        user_code_selector,
75        tss_selector: None,
76    };
77
78    (gdt, selectors)
79});
80
81#[derive(Clone)]
82pub struct Selectors {
83    code_selector: SegmentSelector,
84    data_selector: SegmentSelector,
85    user_code_selector: SegmentSelector,
86    user_data_selector: SegmentSelector,
87    tss_selector: Option<SegmentSelector>,
88}
89
90impl Selectors {
91    pub fn get_kernel_segments() -> (SegmentSelector, SegmentSelector) {
92        let selectors = &COMMON_GDT.1;
93        (selectors.code_selector, selectors.data_selector)
94    }
95    pub fn get_user_segments() -> (SegmentSelector, SegmentSelector) {
96        let selectors = &COMMON_GDT.1;
97        (selectors.user_code_selector, selectors.user_data_selector)
98    }
99}