// PORT TARGET: kernel/src/loader/aarch64.rs
// Status: minimal — load Linux aarch64 Image (raw flat binary).
//
// Linux aarch64 boot protocol (Documentation/arm64/booting.rst):
//   The kernel image is loaded at OFFSET 0x80000 from the start of
//   RAM. Image header at offset 0:
//     0x00: u32 code0          (executable code)
//     0x04: u32 code1          (executable code)
//     0x08: u64 text_offset    (suggested text offset from RAM start)
//     0x10: u64 image_size     (effective image size, big endian on
//                               older kernels but LE on modern)
//     0x18: u64 flags
//     0x20: u64 res2-4         (reserved)
//     0x38: u32 magic          ("ARM\x64" = 0x644d5241)
//     0x3c: u32 res5
//
// We read the magic to validate, then copy the whole file into
// guest RAM at ram_start + 0x80000.

use std::fs::File;
use std::io::{Read, Result};

/// AArch64 Linux Image magic at offset 0x38 ("ARM\x64").
const ARM64_IMAGE_MAGIC: u32 = 0x644d_5241;

/// Read a kernel image into a Vec, validating the aarch64 boot
/// protocol magic.
pub fn read_image(path: &str) -> Result<Vec<u8>> {
    let mut f = File::open(path)?;
    let mut buf = Vec::new();
    f.read_to_end(&mut buf)?;
    if buf.len() < 0x40 {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            "image too short",
        ));
    }
    let magic = u32::from_le_bytes(buf[0x38..0x3c].try_into().unwrap());
    if magic != ARM64_IMAGE_MAGIC {
        return Err(std::io::Error::new(
            std::io::ErrorKind::InvalidData,
            format!("not a Linux aarch64 Image (magic=0x{magic:08x})"),
        ));
    }
    Ok(buf)
}

/// Read an initramfs / initrd into a Vec (no validation — kernel
/// expects gzipped cpio or similar; we don't crack it).
pub fn read_initramfs(path: &str) -> Result<Vec<u8>> {
    let mut f = File::open(path)?;
    let mut buf = Vec::new();
    f.read_to_end(&mut buf)?;
    Ok(buf)
}
