//! 系统调用分发

use moa_rt_define::TrapFrameOps;
use moa_syscall_macros::syscall;
use moa_uapi::error::ERR_NOSYS;
#[allow(clippy::wildcard_imports)]
use moa_uapi::sysnr::*;

cfg_if::cfg_if! {
    if #[cfg(aarch64_moana)] {
        use moa_rt_define::aarch64::TrapFrame;
    } else if #[cfg(riscv64_moana)] {
        use moa_rt_define::riscv64::TrapFrame;
    } else {
        use moa_rt_define::aarch64::TrapFrame;
    }
}

mod channel;
mod connect;
mod device;
mod futex;
mod mem;
mod misc;
mod rlimit;
mod sched;
mod space;
mod system;
mod task;
mod timer;

/// 寄存器值到具体类型的转换
pub trait FromReg {
    /// 从寄存器原始值构造
    fn from_reg(val: usize) -> Self;
}

impl FromReg for usize {
    #[inline(always)]
    fn from_reg(val: usize) -> Self {
        val
    }
}

impl FromReg for u32 {
    #[inline(always)]
    fn from_reg(val: usize) -> Self {
        val as u32
    }
}

impl FromReg for i32 {
    #[inline(always)]
    #[allow(clippy::cast_possible_wrap)]
    fn from_reg(val: usize) -> Self {
        val as i32
    }
}

impl<T> FromReg for *const T {
    #[inline(always)]
    fn from_reg(val: usize) -> Self {
        val as *const T
    }
}

impl<T> FromReg for *mut T {
    #[inline(always)]
    fn from_reg(val: usize) -> Self {
        val as *mut T
    }
}

type SyscallFn = fn(&TrapFrame) -> isize;

fn sys_ni_syscall(_: &TrapFrame) -> isize {
    ERR_NOSYS
}

static SYSCALL_TABLE: [SyscallFn; SYSNR_MAX] = {
    let mut t = [sys_ni_syscall as SyscallFn; SYSNR_MAX];

    // rlimit
    t[SYSNR_RLIMIT_SET] = rlimit::sys_rlimit_set;
    t[SYSNR_RLIMIT_QUERY] = rlimit::sys_rlimit_query;

    // task
    t[SYSNR_TASK_CREATE] = task::sys_task_create;
    t[SYSNR_TASK_CLOSE] = task::sys_task_close;
    t[SYSNR_TASK_START] = task::sys_task_start;
    t[SYSNR_TASK_SET_REGS] = task::sys_task_set_regs;
    t[SYSNR_TASK_GET_REGS] = task::sys_task_get_regs;
    t[SYSNR_TASK_GET_STATUS] = task::sys_task_get_status;
    t[SYSNR_TASK_SET_POLICY] = task::sys_task_set_policy;

    // sched
    t[SYSNR_SCHED_REGISTER] = sched::sys_sched_register;
    t[SYSNR_SCHED_UNREGISTER] = sched::sys_sched_unregister;
    t[SYSNR_SCHED_SET_MODE] = sched::sys_sched_set_mode;
    t[SYSNR_SCHED_RESUME] = sched::sys_sched_resume;
    t[SYSNR_SCHED_SUSPEND] = sched::sys_sched_suspend;
    t[SYSNR_SCHED_SET_CPU] = sched::sys_sched_set_cpu;
    t[SYSNR_SCHED_GET_STATE] = sched::sys_sched_get_state;
    t[SYSNR_SCHED_GET_TASK_LOAD] = sched::sys_sched_get_task_load;

    // space
    t[SYSNR_SPACE_CREATE] = space::sys_space_create;
    t[SYSNR_SPACE_CLOSE] = space::sys_space_close;
    t[SYSNR_SPACE_MAP] = space::sys_space_map;
    t[SYSNR_SPACE_UNMAP] = space::sys_space_unmap;
    t[SYSNR_SPACE_PROTECT] = space::sys_space_protect;
    t[SYSNR_SPACE_WRITE] = space::sys_space_write;
    t[SYSNR_SPACE_READ] = space::sys_space_read;
    t[SYSNR_SPACE_GET_ID] = space::sys_space_get_id;

    // mem
    t[SYSNR_MEM_CREATE] = mem::sys_mem_create;
    t[SYSNR_MEM_RELEASE] = mem::sys_mem_release;
    t[SYSNR_MEM_WRITE] = mem::sys_mem_write;
    t[SYSNR_MEM_READ] = mem::sys_mem_read;
    t[SYSNR_MEM_COPY] = mem::sys_mem_copy;
    t[SYSNR_MEM_PHYS_ADDR] = mem::sys_mem_phys_addr;
    t[SYSNR_MEM_CACHE_OP] = mem::sys_mem_cache_op;

    // device / irq
    t[SYSNR_DEVICE_COUNT] = device::sys_device_count;
    t[SYSNR_DEVICE_QUERY] = device::sys_device_query;
    t[SYSNR_DEVICE_GET_PROP] = device::sys_device_get_prop;
    t[SYSNR_DEVICE_ACQUIRE] = device::sys_device_acquire;
    t[SYSNR_DEVICE_RELEASE] = device::sys_device_release;
    t[SYSNR_IRQ_BIND] = device::sys_irq_bind;
    t[SYSNR_IRQ_UNBIND] = device::sys_irq_unbind;
    t[SYSNR_IRQ_ACK] = device::sys_irq_ack;

    // system
    t[SYSNR_CLOCK_SET_OFFSET] = system::sys_clock_set_offset;
    t[SYSNR_REBOOT] = system::sys_reboot;
    t[SYSNR_DEBUG_PRINT] = system::sys_debug_print;

    // channel (server side)
    t[SYSNR_CHANNEL_CREATE] = channel::sys_channel_create;
    t[SYSNR_CHANNEL_CLOSE] = channel::sys_channel_close;
    t[SYSNR_RECV] = channel::sys_recv;
    t[SYSNR_REPLYV] = channel::sys_replyv;
    t[SYSNR_REPLY_RECV] = channel::sys_reply_recv;
    t[SYSNR_MSG_READ] = channel::sys_msg_read;
    t[SYSNR_MSG_WRITE] = channel::sys_msg_write;
    t[SYSNR_MSG_INFO] = channel::sys_msg_info;
    t[SYSNR_CONNECT_INFO] = channel::sys_connect_info;
    t[SYSNR_CONNECT_REJECT] = channel::sys_connect_reject;

    // connect (client side)
    t[SYSNR_CONNECT] = connect::sys_connect;
    t[SYSNR_DISCONNECT] = connect::sys_disconnect;
    t[SYSNR_SENDV] = connect::sys_sendv;
    t[SYSNR_SEND_PULSE] = connect::sys_send_pulse;

    // timer
    t[SYSNR_TIMER_CREATE] = timer::sys_timer_create;
    t[SYSNR_TIMER_BIND] = timer::sys_timer_bind;
    t[SYSNR_TIMER_UNBIND] = timer::sys_timer_unbind;
    t[SYSNR_TIMER_SET] = timer::sys_timer_set;
    t[SYSNR_TIMER_CLOSE] = timer::sys_timer_close;

    // futex
    t[SYSNR_FUTEX_WAIT] = futex::sys_futex_wait;
    t[SYSNR_FUTEX_WAITV] = futex::sys_futex_waitv;
    t[SYSNR_FUTEX_WAKE] = futex::sys_futex_wake;
    t[SYSNR_FUTEX_REQUEUE] = futex::sys_futex_requeue;
    t[SYSNR_ROBUST_LIST_SET] = futex::sys_robust_list_set;

    // misc
    t[SYSNR_YIELD] = misc::sys_yield;
    t[SYSNR_SLEEP] = misc::sys_sleep;
    t[SYSNR_EXIT] = misc::sys_exit;
    t[SYSNR_TASK_SELF] = misc::sys_task_self;

    t
};

/// 系统调用分发入口
#[allow(clippy::cast_sign_loss)]
pub fn syscall_dispatch(regs: &mut TrapFrame) {
    let nr = regs.sysnr();
    let ret = if nr < SYSNR_MAX { SYSCALL_TABLE[nr](regs) } else { ERR_NOSYS };
    regs.set_return(ret as usize);
}
