use alloc::boxed::Box;
use alloc::vec::Vec;
use core::arch::asm;
use core::mem::size_of;
use x86_64::instructions::tables::{lgdt, load_tss};
use x86_64::registers::model_specific::{GsBase, Star};
use x86_64::structures::gdt::{Descriptor, SegmentSelector};
use x86_64::structures::DescriptorTablePointer;
use x86_64::{PrivilegeLevel, VirtAddr};
#[cfg(not(feature = "ioport_bitmap"))]
type TSS = x86_64::structures::tss::TaskStateSegment;
#[cfg(feature = "ioport_bitmap")]
type TSS = super::ioport::TSSWithPortBitmap;
pub fn init() {
let mut tss = Box::new(TSS::new());
let trap_stack_top = Box::leak(Box::new([0u8; 0x1000])).as_ptr() as u64 + 0x1000;
tss.privilege_stack_table[0] = VirtAddr::new(trap_stack_top);
let tss: &'static _ = Box::leak(tss);
let (tss0, tss1) = match Descriptor::tss_segment(tss) {
Descriptor::SystemSegment(tss0, tss1) => (tss0, tss1),
_ => unreachable!(),
};
#[cfg(feature = "ioport_bitmap")]
let tss0 = (tss0 & !0xFFFF) | (size_of::<TSS>() as u64);
unsafe {
let gdtp = sgdt();
let entry_count = (gdtp.limit + 1) as usize / size_of::<u64>();
let old_gdt = core::slice::from_raw_parts(gdtp.base.as_ptr::<u64>(), entry_count);
let mut gdt = Vec::from(old_gdt);
gdt.extend([tss0, tss1, KCODE64, KDATA64, UCODE32, UDATA32, UCODE64].iter());
let gdt = Vec::leak(gdt);
lgdt(&DescriptorTablePointer {
limit: gdt.len() as u16 * 8 - 1,
base: VirtAddr::new(gdt.as_ptr() as _),
});
load_tss(SegmentSelector::new(
entry_count as u16,
PrivilegeLevel::Ring0,
));
#[allow(const_item_mutation)]
GsBase::MSR.write(tss as *const _ as u64);
let sysret = SegmentSelector::new(entry_count as u16 + 4, PrivilegeLevel::Ring3).0;
let syscall = SegmentSelector::new(entry_count as u16 + 2, PrivilegeLevel::Ring0).0;
Star::write_raw(sysret, syscall);
USER_SS = sysret + 8;
USER_CS = sysret + 16;
}
}
#[inline]
unsafe fn sgdt() -> DescriptorTablePointer {
let mut gdt = DescriptorTablePointer {
limit: 0,
base: VirtAddr::zero(),
};
asm!("sgdt [{}]", in(reg) &mut gdt);
gdt
}
#[no_mangle]
static mut USER_SS: u16 = 0;
#[no_mangle]
static mut USER_CS: u16 = 0;
const KCODE64: u64 = 0x00209800_00000000; const UCODE64: u64 = 0x0020F800_00000000; const KDATA64: u64 = 0x00009200_00000000; #[allow(dead_code)]
const UDATA64: u64 = 0x0000F200_00000000; const UCODE32: u64 = 0x00cffa00_0000ffff; const UDATA32: u64 = 0x00cff200_0000ffff;