use core::fmt;
use x86_64::instructions::tables::{lgdt, load_tss};
use x86_64::registers::segmentation::{Segment, SegmentSelector, CS};
use x86_64::structures::gdt::{Descriptor, DescriptorFlags};
use x86_64::structures::{tss::TaskStateSegment, DescriptorTablePointer};
use x86_64::{addr::VirtAddr, PrivilegeLevel};
#[repr(align(16))]
pub struct GdtStruct {
table: [u64; 16],
}
impl GdtStruct {
pub const KCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(1, PrivilegeLevel::Ring0);
pub const KCODE64_SELECTOR: SegmentSelector = SegmentSelector::new(2, PrivilegeLevel::Ring0);
pub const KDATA_SELECTOR: SegmentSelector = SegmentSelector::new(3, PrivilegeLevel::Ring0);
pub const UCODE32_SELECTOR: SegmentSelector = SegmentSelector::new(4, PrivilegeLevel::Ring3);
pub const UDATA_SELECTOR: SegmentSelector = SegmentSelector::new(5, PrivilegeLevel::Ring3);
pub const UCODE64_SELECTOR: SegmentSelector = SegmentSelector::new(6, PrivilegeLevel::Ring3);
pub const TSS_SELECTOR: SegmentSelector = SegmentSelector::new(7, PrivilegeLevel::Ring0);
pub fn new(tss: &'static TaskStateSegment) -> Self {
let mut table = [0; 16];
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) {
table[7] = low;
table[8] = high;
}
Self { table }
}
pub fn pointer(&self) -> DescriptorTablePointer {
DescriptorTablePointer {
base: VirtAddr::new(self.table.as_ptr() as u64),
limit: (core::mem::size_of_val(&self.table) - 1) as u16,
}
}
pub unsafe fn load(&'static self) {
lgdt(&self.pointer());
CS::set_reg(Self::KCODE64_SELECTOR);
}
pub unsafe fn load_tss(&'static self) {
load_tss(Self::TSS_SELECTOR);
}
}
impl fmt::Debug for GdtStruct {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("GdtStruct")
.field("pointer", &self.pointer())
.field("table", &self.table)
.finish()
}
}