//! Provides architecture/platform-specific implementation details

use abi::error::Error;
use kernel_arch::{Architecture, ArchitectureImpl};

#[cfg(any(target_arch = "aarch64", rust_analyzer))]
pub mod aarch64;
#[cfg(any(target_arch = "aarch64", rust_analyzer))]
pub use aarch64::{AArch64 as PlatformImpl, L3, PLATFORM};

#[cfg(any(target_arch = "x86_64", target_arch = "x86", rust_analyzer))]
pub mod x86;

#[cfg(any(target_arch = "x86_64", rust_analyzer))]
pub mod x86_64;
#[cfg(any(target_arch = "x86_64", rust_analyzer))]
pub use x86_64::{L3, PLATFORM, X86_64 as PlatformImpl};

#[cfg(any(target_arch = "riscv64", rust_analyzer))]
pub mod riscv64;
#[cfg(any(target_arch = "riscv64", rust_analyzer))]
pub use riscv64::{Riscv64 as PlatformImpl, L3, PLATFORM};

#[cfg(not(any(
    target_arch = "x86_64",
    target_arch = "aarch64",
    target_arch = "riscv64",
)))]
compile_error!("Unsupported architecture");

// Architecture interfaces

/// Interface for an architecture-specific facilities
pub trait Platform {
    /// Starts up the application processors that may be present in the system.
    ///
    /// # Safety
    ///
    /// Only safe to call once during system init.
    unsafe fn start_application_processors(&self) {}

    /// Performs a CPU reset.
    ///
    /// # Safety
    ///
    /// The caller must ensure it is actually safe to reset, i.e. no critical processes will be
    /// aborted and no data will be lost.
    unsafe fn reset(&self) -> ! {
        ArchitectureImpl::set_interrupt_mask(true);
        loop {
            ArchitectureImpl::wait_for_interrupt();
        }
    }

    /// Performs full system powerdown.
    ///
    /// # Safety
    ///
    /// The caller must ensure it is actually safe to power down, i.e. no critical processes will be
    /// aborted and no data will be lost.
    unsafe fn power_off(&self) -> Result<!, Error> {
        ArchitectureImpl::set_interrupt_mask(true);
        loop {
            ArchitectureImpl::wait_for_interrupt();
        }
    }

    //     /// Adds a reset device to the system
    //     fn register_reset_device(&self, reset: Arc<dyn ResetDevice>) -> Result<(), Error> {
    //         Err(Error::NotImplemented)
    //     }
    //
    //     /// Sends a message to the requested set of CPUs through an interprocessor interrupt.
    //     ///
    //     /// # Note
    //     ///
    //     /// u64 limits the number of targetable CPUs to (only) 64. Platform-specific implementations
    //     /// may impose narrower restrictions.
    //     ///
    //     /// # Safety
    //     ///
    //     /// As the call may alter the flow of execution on CPUs, this function is unsafe.
    //     unsafe fn send_ipi(&self, target: IpiDeliveryTarget, msg: IpiMessage) -> Result<bool, Error> {
    //         if let Some(intc) = ArchitectureImpl::local_interrupt_controller() {
    //             intc.send_ipi(target, msg).map(|_| true)
    //         } else {
    //             log::debug!("No local interrupt controller -> no IPI");
    //             Ok(false)
    //         }
    //     }
}
