Skip to main content

kernel/arch/x86_64/syscall/
mod.rs

1// SPDX-License-Identifier: GPL-3.0-only
2//! x86_64 syscalls specifics
3//!
4//! Authors: MarioS271
5
6mod entry;
7mod frame;
8
9use crate::arch::x86_64::cpu::tables::gdt::GdtSetupInfo;
10use crate::lib::addr::VirtAddr;
11use crate::lib::panic::kernel_panic;
12use crate::lib::panic_codes::PanicCode;
13use x86_64::registers::control::{Efer, EferFlags};
14use x86_64::registers::model_specific::{LStar, SFMask, Star};
15use x86_64::registers::rflags::RFlags;
16
17/// Enable the `syscall`/`sysret` instructions for this CPU and set the syscall entry point
18///
19/// # Safety
20/// The caller must guarantee that:
21/// - This function is called exactly once per CPU
22/// - The GDT is already loaded on that CPU
23/// - This function is called before entering userspace for the first time on that CPU
24pub(crate) unsafe fn init(info: &GdtSetupInfo) {
25    Star::write(
26        info.user_code, info.user_data, info.kernel_code, info.kernel_data
27    ).unwrap_or_else(
28        |_| kernel_panic(
29            PanicCode::InitFailure,
30            "Invalid GDT layout for sysret"
31        )
32    );
33
34    LStar::write(
35        VirtAddr::from_ptr(entry::syscall_entry as *const ()).as_x86_64()
36    );
37
38    SFMask::write(
39        RFlags::CARRY_FLAG
40        | RFlags::PARITY_FLAG
41        | RFlags::AUXILIARY_CARRY_FLAG
42        | RFlags::ZERO_FLAG
43        | RFlags::SIGN_FLAG
44        | RFlags::TRAP_FLAG
45        | RFlags::INTERRUPT_FLAG
46        | RFlags::DIRECTION_FLAG
47        | RFlags::OVERFLOW_FLAG
48        | RFlags::IOPL_LOW
49        | RFlags::IOPL_HIGH
50        | RFlags::NESTED_TASK
51        | RFlags::RESUME_FLAG
52        | RFlags::ALIGNMENT_CHECK
53        | RFlags::ID
54    );
55
56    unsafe {
57        Efer::update(|efer| efer.insert(EferFlags::SYSTEM_CALL_EXTENSIONS))
58    }
59}