mirror of
https://github.com/asterinas/asterinas.git
synced 2025-06-09 05:16:47 +00:00
Adjust unsafe
blocks in syscall.rs
This commit is contained in:
parent
c9a7d501b2
commit
bf4950965b
@ -123,7 +123,9 @@ pub unsafe fn init() {
|
|||||||
unsafe { gdt::init() };
|
unsafe { gdt::init() };
|
||||||
|
|
||||||
idt::init();
|
idt::init();
|
||||||
syscall::init();
|
|
||||||
|
// SAFETY: `gdt::init` has been called before.
|
||||||
|
unsafe { syscall::init() };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// User space context.
|
/// User space context.
|
||||||
|
@ -36,31 +36,46 @@ global_asm!(
|
|||||||
USER_SS = const super::gdt::USER_SS.0,
|
USER_SS = const super::gdt::USER_SS.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
pub(super) fn init() {
|
/// # Safety
|
||||||
|
///
|
||||||
|
/// The caller needs to ensure that `gdt::init` has been called before, so the segment selectors
|
||||||
|
/// used in the `syscall` and `sysret` instructions have been properly initialized.
|
||||||
|
pub(super) unsafe fn init() {
|
||||||
let cpuid = CpuId::new();
|
let cpuid = CpuId::new();
|
||||||
unsafe {
|
|
||||||
// Enable `syscall` instruction.
|
|
||||||
assert!(cpuid
|
assert!(cpuid
|
||||||
.get_extended_processor_and_feature_identifiers()
|
.get_extended_processor_and_feature_identifiers()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.has_syscall_sysret());
|
.has_syscall_sysret());
|
||||||
|
assert!(cpuid.get_extended_feature_info().unwrap().has_fsgsbase());
|
||||||
|
|
||||||
|
// Flags to clear on syscall.
|
||||||
|
//
|
||||||
|
// Linux 5.0 uses TF|DF|IF|IOPL|AC|NT. Reference:
|
||||||
|
// <https://github.com/torvalds/linux/blob/v5.0/arch/x86/kernel/cpu/common.c#L1559-L1562>
|
||||||
|
const RFLAGS_MASK: u64 = 0x47700;
|
||||||
|
|
||||||
|
// SAFETY: The segment selectors are correctly initialized (as upheld by the caller), and the
|
||||||
|
// entry point and flags to clear are also correctly set, so enabling the `syscall` and
|
||||||
|
// `sysret` instructions is safe.
|
||||||
|
unsafe {
|
||||||
|
LStar::write(VirtAddr::new(syscall_entry as usize as u64));
|
||||||
|
SFMask::write(RFlags::from_bits(RFLAGS_MASK).unwrap());
|
||||||
|
|
||||||
|
// Enable the `syscall` and `sysret` instructions.
|
||||||
Efer::update(|efer| {
|
Efer::update(|efer| {
|
||||||
efer.insert(EferFlags::SYSTEM_CALL_EXTENSIONS);
|
efer.insert(EferFlags::SYSTEM_CALL_EXTENSIONS);
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// Enable `FSGSBASE` instructions.
|
// SAFETY: Enabling the `rdfsbase`, `wrfsbase`, `rdgsbase`, and `wrgsbase` instructions is safe
|
||||||
assert!(cpuid.get_extended_feature_info().unwrap().has_fsgsbase());
|
// as long as the kernel properly deals with the arbitrary base values set by the userspace
|
||||||
|
// program. (FIXME: Do we really need to unconditionally enable them?)
|
||||||
|
unsafe {
|
||||||
Cr4::update(|cr4| {
|
Cr4::update(|cr4| {
|
||||||
cr4.insert(Cr4Flags::FSGSBASE);
|
cr4.insert(Cr4Flags::FSGSBASE);
|
||||||
});
|
})
|
||||||
|
};
|
||||||
// Flags to clear on syscall.
|
|
||||||
// Copy from Linux 5.0, TF|DF|IF|IOPL|AC|NT
|
|
||||||
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" {
|
extern "sysv64" {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user