use core::arch::asm; use crate::task::TSS; #[repr(transparent)] #[derive(Debug, Clone, Copy)] pub struct GDTEntry(u64); pub struct GDT([GDTEntry; GDT::LEN]); impl GDTEntry { const NULL: Self = Self(0); const KERNEL_CODE64: Self = Self::new(0, 0, 0x9a, 0x2); const KERNEL_DATA64: Self = Self::new(0, 0, 0x92, 0x0); const USER_CODE64: Self = Self::new(0, 0, 0xfa, 0x2); const USER_DATA64: Self = Self::new(0, 0, 0xf2, 0x0); const USER_CODE32: Self = Self::new(0, 0xfffff, 0xfa, 0xc); const USER_DATA32: Self = Self::new(0, 0xfffff, 0xf2, 0xc); pub const fn new(base: u32, limit: u32, access: u8, flags: u8) -> Self { let mut entry = 0u64; entry |= (limit & 0x0000_ffff) as u64; entry |= ((limit & 0x000f_0000) as u64) << 32; entry |= ((base & 0x00ff_ffff) as u64) << 16; entry |= ((base & 0xff00_0000) as u64) << 32; entry |= (access as u64) << 40; entry |= (flags as u64) << 52; GDTEntry(entry) } pub const fn new_ldt(base: u64, limit: u32) -> [Self; 2] { let first = Self::new(base as u32, limit, 0x82, 0x0); let second = Self(base >> 32); [first, second] } pub const fn new_tss(base: u64, limit: u32) -> [Self; 2] { let first = Self::new(base as u32, limit, 0x89, 0x0); let second = Self(base >> 32); [first, second] } } impl GDT { const LEN: usize = 10; const TLS32_INDEX: usize = 7; const TSS_INDEX: usize = 8; pub fn new() -> Self { Self([ GDTEntry::NULL, GDTEntry::KERNEL_CODE64, GDTEntry::KERNEL_DATA64, GDTEntry::USER_CODE64, GDTEntry::USER_DATA64, GDTEntry::USER_CODE32, GDTEntry::USER_DATA32, GDTEntry::NULL, // User TLS 32bit GDTEntry::NULL, // TSS Descriptor Low GDTEntry::NULL, // TSS Descriptor High ]) } pub fn set_tss(&mut self, base: u64) { let tss = GDTEntry::new_tss(base, size_of::() as u32 - 1); self.0[Self::TSS_INDEX] = tss[0]; self.0[Self::TSS_INDEX + 1] = tss[1]; } pub fn set_tls32(&mut self, desc: GDTEntry) { self.0[7] = desc; } pub unsafe fn load(&self) { let len = Self::LEN * 8 - 1; let descriptor: [u64; 2] = [(len as u64) << 48, self.0.as_ptr() as u64]; assert!(len < 0x10000, "GDT too large"); let descriptor_address = &descriptor as *const _ as usize + 6; asm!( "lgdt ({})", "ltr %ax", in(reg) descriptor_address, in("ax") Self::TSS_INDEX as u16 * 8, options(att_syntax) ); } }