1use core::fmt;
2
3use lazyinit::LazyInit;
4use x86_64::instructions::tables::{lgdt, load_tss};
5use x86_64::registers::segmentation::{CS, Segment, SegmentSelector};
6use x86_64::structures::gdt::{Descriptor, DescriptorFlags};
7use x86_64::structures::{DescriptorTablePointer, tss::TaskStateSegment};
8use x86_64::{PrivilegeLevel, addr::VirtAddr};
9
10#[unsafe(no_mangle)]
11#[percpu::def_percpu]
12static TSS: TaskStateSegment = TaskStateSegment::new();
13
14#[percpu::def_percpu]
15static GDT: LazyInit<GdtStruct> = LazyInit::new();
16
17#[repr(align(16))]
19pub struct GdtStruct {
20 table: [u64; 16],
21}
22
23impl GdtStruct {
24 pub const KCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(1, PrivilegeLevel::Ring0);
26 pub const KCODE64_SELECTOR: SegmentSelector = SegmentSelector::new(2, PrivilegeLevel::Ring0);
28 pub const KDATA_SELECTOR: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring0);
30 pub const UCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3);
32 pub const UDATA_SELECTOR: SegmentSelector = SegmentSelector::new(5, PrivilegeLevel::Ring3);
34 pub const UCODE64_SELECTOR: SegmentSelector = SegmentSelector::new(6, PrivilegeLevel::Ring3);
36 pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(7, PrivilegeLevel::Ring0);
38
39 pub fn new(tss: &'static TaskStateSegment) -> Self {
42 let mut table = [0; 16];
43 table[1] = DescriptorFlags::KERNEL_CODE32.bits(); table[2] = DescriptorFlags::KERNEL_CODE64.bits(); table[3] = DescriptorFlags::KERNEL_DATA.bits(); table[4] = DescriptorFlags::USER_CODE32.bits(); table[5] = DescriptorFlags::USER_DATA.bits(); table[6] = DescriptorFlags::USER_CODE64.bits(); if let Descriptor::SystemSegment(low, high) = Descriptor::tss_segment(tss) {
51 table[7] = low;
52 table[8] = high;
53 }
54 Self { table }
55 }
56
57 pub fn pointer(&self) -> DescriptorTablePointer {
60 DescriptorTablePointer {
61 base: VirtAddr::new(self.table.as_ptr() as u64),
62 limit: (core::mem::size_of_val(&self.table) - 1) as u16,
63 }
64 }
65
66 pub unsafe fn load(&'static self) {
74 unsafe {
75 lgdt(&self.pointer());
76 CS::set_reg(Self::KCODE64_SELECTOR);
77 }
78 }
79
80 pub unsafe fn load_tss(&'static self) {
87 unsafe {
88 load_tss(Self::TSS_SELECTOR);
89 }
90 }
91}
92
93impl fmt::Debug for GdtStruct {
94 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
95 f.debug_struct("GdtStruct")
96 .field("pointer", &self.pointer())
97 .field("table", &self.table)
98 .finish()
99 }
100}
101
102pub fn init_gdt() {
105 unsafe {
106 let gdt = GDT.current_ref_raw();
107 gdt.init_once(GdtStruct::new(TSS.current_ref_raw()));
108 gdt.load();
109 gdt.load_tss();
110 }
111}
112
113pub fn tss_get_rsp0() -> memory_addr::VirtAddr {
115 let tss = unsafe { TSS.current_ref_raw() };
116 memory_addr::VirtAddr::from(tss.privilege_stack_table[0].as_u64() as usize)
117}
118
119pub unsafe fn tss_set_rsp0(rsp0: memory_addr::VirtAddr) {
125 let tss = unsafe { TSS.current_ref_mut_raw() };
126 tss.privilege_stack_table[0] = VirtAddr::new_truncate(rsp0.as_usize() as u64);
127}