// SPDX-License-Identifier: LCL-1.0
// Copyright (c) 2026 Markus Maiwald
// Stewardship: Self Sovereign Society Foundation
//
// This file is part of the Nexus Commonwealth.
// See legal/LICENSE_COMMONWEALTH.md for license terms.

//! Rumpk Boot Header
//!
//! Architecture-dispatched entry point for bare-metal boot.
//! Handles BSS clearing and stack initialization before jumping to HAL init.
//!
//! SAFETY: Executed in the earliest boot stage with no environment initialized.

const std = @import("std");
const builtin = @import("builtin");

// =========================================================
// Multiboot2 Header (for GRUB/QEMU — x86 only)
// =========================================================

const MULTIBOOT2_MAGIC: u32 = 0xe85250d6;
const MULTIBOOT2_ARCH_I386: u32 = 0;
const MULTIBOOT2_HEADER_LENGTH: u32 = @sizeOf(Multiboot2Header);

const Multiboot2Header = extern struct {
    magic: u32 = MULTIBOOT2_MAGIC,
    architecture: u32 = MULTIBOOT2_ARCH_I386,
    header_length: u32 = MULTIBOOT2_HEADER_LENGTH,
    checksum: u32,

    // End tag
    end_tag_type: u16 = 0,
    end_tag_flags: u16 = 0,
    end_tag_size: u32 = 8,
};

fn computeChecksum() u32 {
    return @bitCast(-%@as(i32, @bitCast(MULTIBOOT2_MAGIC +% MULTIBOOT2_ARCH_I386 +% MULTIBOOT2_HEADER_LENGTH)));
}

export const multiboot2_header linksection(".multiboot2") = Multiboot2Header{
    .checksum = computeChecksum(),
};

// =========================================================
// Arch-Specific HAL Entry Points
// =========================================================

extern fn riscv_init() noreturn;
extern fn aarch64_init() void; // Returns void (calls rumpk_halt internally)

// =========================================================
// Entry Point (Architecture Dispatched)
// =========================================================

// 1MB Kernel Stack
const STACK_SIZE = 0x100000;
export var kernel_stack: [STACK_SIZE]u8 align(16) linksection(".bss.stack") = undefined;

export fn _start() callconv(.naked) noreturn {
    switch (builtin.cpu.arch) {
        .riscv64 => {
            asm volatile (
                \\  // Set up stack
                \\  la sp, kernel_stack
                \\  li t0, %[stack_size]
                \\  add sp, sp, t0
                \\
                \\  // Clear BSS
                \\  la t0, __bss_start
                \\  la t1, __bss_end
                \\1:
                \\  bge t0, t1, 2f
                \\  sd zero, (t0)
                \\  addi t0, t0, 8
                \\  j 1b
                \\2:
                \\  // Jump to RISC-V HAL Init
                \\  call riscv_init
                \\
                \\  // Should never return
                \\  wfi
                \\  j 2b
                :
                : [stack_size] "i" (STACK_SIZE),
            );
        },
        .aarch64 => {
            asm volatile (
            // Mask all exceptions
                \\ msr daifset, #0xf
                //
                // Enable FP/SIMD (CPACR_EL1.FPEN = 0b11)
                \\ mov x0, #(3 << 20)
                \\ msr cpacr_el1, x0
                \\ isb
                //
                // Disable alignment check (SCTLR_EL1.A = 0)
                \\ mrs x0, sctlr_el1
                \\ bic x0, x0, #(1 << 1)
                \\ msr sctlr_el1, x0
                \\ isb
                //
                // Set up stack
                \\ adrp x0, kernel_stack
                \\ add x0, x0, :lo12:kernel_stack
                \\ mov x1, #0x100000
                \\ add sp, x0, x1
                //
                // Clear BSS
                \\ adrp x0, __bss_start
                \\ add x0, x0, :lo12:__bss_start
                \\ adrp x1, __bss_end
                \\ add x1, x1, :lo12:__bss_end
                \\ 1: cmp x0, x1
                \\ b.ge 2f
                \\ str xzr, [x0], #8
                \\ b 1b
                \\ 2:
                //
                // Jump to ARM64 HAL Init
                \\ bl aarch64_init
                //
                // Should never return
                \\ 3: wfe
                \\ b 3b
            );
        },
        else => {
            // Unsupported architecture
            unreachable;
        },
    }
}
