//! Note for syscall registers usage (x86-64):
//! - %rax is the syscall number.
//! - %rax is also the return value.
//! - %rdi is the 1st argument.
//! - %rsi is the 2nd argument.
//! - %rdx is the 3rd argument.
//! - %r10 is the 4th argument (**yes it's %r10, not %rcx!**).
//! - %r8  is the 5th argument.
//! - %r9  is the 6th argument.
//!
//! `syscall` instruction will clobber %r11 and %rcx.

#![no_std]

use core::arch::asm;

#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
pub unsafe fn do_syscall0(number: u64) -> u64 {
    let ret;
    asm!(
        "syscall",
        inout("rax") number => ret,
        out("r11") _,
        out("rcx") _,
    );
    ret
}

#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
pub unsafe fn do_syscall1(number: u64, arg1: u64) -> u64 {
    let ret;
    asm!(
        "syscall",
        inout("rax") number => ret,
        in("rdi") arg1,
        out("r11") _,
        out("rcx") _,
    );
    ret
}

#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
pub unsafe fn do_syscall2(number: u64, arg1: u64, arg2: u64) -> u64 {
    let ret;
    asm!(
        "syscall",
        inout("rax") number => ret,
        in("rdi") arg1,
        in("rsi") arg2,
        out("r11") _,
        out("rcx") _,
    );
    ret
}

#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
pub unsafe fn do_syscall3(number: u64, arg1: u64, arg2: u64, arg3: u64) -> u64 {
    let ret;
    asm!(
        "syscall",
        inout("rax") number => ret,
        in("rdi") arg1,
        in("rsi") arg2,
        in("rdx") arg3,
        out("r11") _,
        out("rcx") _,
    );
    ret
}

#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
pub unsafe fn do_syscall4(number: u64, arg1: u64, arg2: u64, arg3: u64, arg4: u64) -> u64 {
    let ret;
    asm!(
        "syscall",
        inout("rax") number => ret,
        in("rdi") arg1,
        in("rsi") arg2,
        in("rdx") arg3,
        in("r10") arg4,
        out("r11") _,
        out("rcx") _,
    );
    ret
}

#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
pub unsafe fn do_syscall5(
    number: u64,
    arg1: u64,
    arg2: u64,
    arg3: u64,
    arg4: u64,
    arg5: u64,
) -> u64 {
    let ret;
    asm!(
        "syscall",
        inout("rax") number => ret,
        in("rdi") arg1,
        in("rsi") arg2,
        in("rdx") arg3,
        in("r10") arg4,
        in("r8") arg5,
        out("r11") _,
        out("rcx") _,
    );
    ret
}

#[cfg(all(target_arch = "x86_64", target_os = "linux"))]
pub unsafe fn do_syscall6(
    number: u64,
    arg1: u64,
    arg2: u64,
    arg3: u64,
    arg4: u64,
    arg5: u64,
    arg6: u64,
) -> u64 {
    let ret;
    asm!(
        "syscall",
        inout("rax") number => ret,
        in("rdi") arg1,
        in("rsi") arg2,
        in("rdx") arg3,
        in("r10") arg4,
        in("r8") arg5,
        in("r9") arg6,
        out("r11") _,
        out("rcx") _,
    );
    ret
}
