use core::arch::global_asm;
use x86::cpuid::CpuId;
use x86_64::{
registers::{
control::{Cr4, Cr4Flags},
model_specific::{Efer, EferFlags, LStar, SFMask},
rflags::RFlags,
},
VirtAddr,
};
use super::UserContext;
global_asm!(include_str!("syscall.S"));
pub fn init() {
let cpuid = CpuId::new();
unsafe {
assert!(cpuid
.get_extended_processor_and_feature_identifiers()
.unwrap()
.has_syscall_sysret());
Efer::update(|efer| {
efer.insert(EferFlags::SYSTEM_CALL_EXTENSIONS);
});
assert!(cpuid.get_extended_feature_info().unwrap().has_fsgsbase());
Cr4::update(|cr4| {
cr4.insert(Cr4Flags::FSGSBASE);
});
const RFLAGS_MASK: u64 = 0x47700;
LStar::write(VirtAddr::new(syscall_entry as usize as u64));
SFMask::write(RFlags::from_bits(RFLAGS_MASK).unwrap());
}
}
extern "sysv64" {
fn syscall_entry();
fn syscall_return(regs: &mut UserContext);
}
impl UserContext {
pub fn run(&mut self) {
unsafe {
syscall_return(self);
}
}
}