//! 多核启动相关结构定义

use core::{
    mem::offset_of,
    sync::atomic::{AtomicUsize, Ordering},
};

pub use semx_cpumask::{Cpumask, CpumaskIter, NR_CPUS};

/// PSCI 兼容版本
#[derive(Clone, Copy)]
pub enum PsciCompatible {
    /// arm,psci
    Psci0_1,
    /// arm,psci-0.2
    Psci0_2,
    /// arm,psci-1.0
    Psci1_0,
}

/// PSCI 调用方式
#[derive(Clone, Copy)]
pub enum PsciEnableMethod {
    /// HVC 调用
    Hvc,
    /// SMC 调用
    Smc,
}

/// CPU 启动方式
#[derive(Clone, Copy)]
pub enum CpuBootMethod {
    /// ARM PSCI 启动
    Psci {
        /// PSCI 兼容版本
        compatible: PsciCompatible,
        /// 调用方式（HVC/SMC）
        enable_method: PsciEnableMethod,
        /// PSCI 0.1 版本的 `cpu_on` function ID
        cpu_on: usize,
    },
    /// RISC-V SBI 启动
    Sbi,
}

/// 多核启动定义
#[derive(Clone, Copy)]
pub struct SmpDefine {
    boot_method: CpuBootMethod,
    hwid: [usize; NR_CPUS],
    nr_cpus: usize,
}

impl SmpDefine {
    /// 创建多核定义
    pub const fn create(
        boot_method: CpuBootMethod,
        hwid: [usize; NR_CPUS],
        nr_cpus: usize,
    ) -> Self {
        Self { boot_method, hwid, nr_cpus }
    }

    /// CPU 启动方式
    #[inline(always)]
    pub fn boot_method(&self) -> CpuBootMethod {
        self.boot_method
    }

    /// CPU ID 对应的硬件 ID
    #[inline(always)]
    pub fn hwid(&self, cpu: usize) -> usize {
        self.hwid[cpu]
    }

    /// 总的 CPU 数量
    #[inline(always)]
    pub fn nr_cpus(&self) -> usize {
        self.nr_cpus
    }
}

/// 从核启动数据
#[derive(Default)]
#[repr(C)]
pub struct SecondaryData {
    stack: AtomicUsize,
    task: AtomicUsize,
}

impl SecondaryData {
    /// 构造
    pub const fn new() -> Self {
        Self { stack: AtomicUsize::new(0), task: AtomicUsize::new(0) }
    }

    /// 设置 stack
    pub fn set_stack(&self, base: usize) {
        self.stack.store(base, Ordering::Relaxed);
    }

    /// 设置 task
    pub fn set_task(&self, task: usize) {
        self.task.store(task, Ordering::Relaxed);
    }
}

/// 从核启动数据中 stack 字段偏移
pub const CPU_BOOT_STACK: usize = offset_of!(SecondaryData, stack);
/// 从核启动数据中 task 字段偏移
pub const CPU_BOOT_TASK: usize = offset_of!(SecondaryData, task);
