//! 系统处理器相关操作

use core::sync::atomic::{self, Ordering};

use moa_cpumask::CpuId;

use crate::{bsp::__smp_define, irq::irqflags::local_irq_disable, println, smp::smp_send_stop};

cfg_if::cfg_if! {
    if #[cfg(aarch64_moana)] {
        mod aarch64;
        use aarch64::{arch_set_my_processor_id, arch_my_processor_id, arch_cpu_relax, arch_cpu_wfe, arch_smp_mb_acquire, arch_smp_mb_release, arch_smp_mb, arch_isb};
    } else {
        mod dummy;
        use dummy::{arch_set_my_processor_id, arch_my_processor_id, arch_cpu_relax, arch_cpu_wfe, arch_smp_mb_acquire, arch_smp_mb_release, arch_smp_mb, arch_isb};
    }
}

// 设置当前处理器自定义 id
#[inline(always)]
pub(crate) fn set_this_processor_id(id: CpuId) {
    arch_set_my_processor_id(id.raw());
}

/// 获取当前处理器自定义 id
#[inline(always)]
pub fn this_processor_id() -> CpuId {
    CpuId::from_raw(arch_my_processor_id())
}

/// 处理器"小憩"
#[inline(always)]
pub fn cpu_relax() {
    arch_cpu_relax();
}

/// 处理器低功耗等待事件
#[inline(always)]
pub fn cpu_wfe() {
    arch_cpu_wfe();
}

/// 实际的处理器数量, 最大不能超过`NR_CPUS`
#[inline(always)]
pub fn nr_cpus() -> usize {
    unsafe { __smp_define().nr_cpus() }
}

/// 编译器内存屏障
///
/// 阻止当前位置前后读写编译器的重排序
#[inline(always)]
pub fn barrier() {
    atomic::compiler_fence(Ordering::SeqCst);
}

/// 处理器读内存屏障
///
/// 适用于读数据操作, 防止编译器和处理器重排序读写操作到该位置之前
#[inline(always)]
pub fn smp_mb_acquire() {
    arch_smp_mb_acquire();
}

/// 处理器写内存屏障
///
/// 适用于写数据操作, 防止编译器和处理器重排序读写操作到该位置之后
#[inline(always)]
pub fn smp_mb_release() {
    arch_smp_mb_release();
}

/// 处理器写内存屏障
///
/// 同 `smp_mb_release` 一致
#[inline(always)]
pub fn smp_wmb() {
    smp_mb_release();
}

/// 处理器读内存屏障
///
/// 同 `smp_mb_acquire` 一致
#[inline(always)]
pub fn smp_rmb() {
    smp_mb_acquire();
}

/// 处理器内存屏障
///
/// 根据指定的顺序, 防止编译器和处理器围绕它重新排序某些类型的内存操作,
/// 该函数具有最严格的屏障级别
#[inline(always)]
pub fn smp_mb() {
    arch_smp_mb();
}

/// 处理器指令屏障
#[inline(always)]
pub fn isb() {
    arch_isb();
}

#[inline(always)]
fn dummy_cpu_on(cpu: usize, _entry_point: usize) -> bool {
    cpu == this_processor_id().raw()
}
pub(crate) static mut PROCESSOR_CPU_ON: fn(usize, usize) -> bool = dummy_cpu_on;

#[inline(always)]
fn dummy_sys_restart() {}
pub(crate) static mut PROCESSOR_SYS_RESTART: fn() = dummy_sys_restart;

#[inline(always)]
fn dummy_sys_poweroff() {}
pub(crate) static mut PROCESSOR_SYS_POWEROFF: fn() = dummy_sys_poweroff;

/// 机器关机
pub fn machine_power_off() -> ! {
    local_irq_disable();
    smp_send_stop();
    unsafe {
        PROCESSOR_SYS_POWEROFF();
    }

    println!("Power off failed -- System halted");
    loop {
        cpu_relax();
    }
}

/// 机器重启
pub fn machine_restart() -> ! {
    local_irq_disable();
    smp_send_stop();

    unsafe {
        PROCESSOR_SYS_RESTART();
    }

    println!("Reboot failed -- System halted");
    loop {
        cpu_relax();
    }
}
