#![no_std]
#![no_main]
#![feature(abi_x86_interrupt)]

mod allocator;
mod gdt;
mod interrupts;
mod memory;

use core::panic::PanicInfo;

use bootloader_api::{config::Mapping, entry_point, BootInfo, BootloaderConfig};
use tracing_subscriber::layer::SubscriberExt;
use x86_64::VirtAddr;

static BOOTLOADER_CONFIG: BootloaderConfig = {
    let mut config = BootloaderConfig::new_default();
    config.mappings.physical_memory = Some(Mapping::Dynamic);

    config
};
entry_point!(main, config = &BOOTLOADER_CONFIG);

#[no_mangle]
pub fn main(boot_info: &'static mut BootInfo) -> ! {
    init(boot_info);

    loop {}
}

fn init(boot_info: &'static mut BootInfo) {
    gdt::init();
    interrupts::init();
    let mut offset_table = unsafe {
        memory::init(VirtAddr::new(
            boot_info
                .physical_memory_offset
                .into_option()
                .unwrap_or_default(),
        ))
    };

    let mut frame_allocator = unsafe { memory::init_frame_allocator(&boot_info.memory_regions) };

    allocator::init_heap(&mut offset_table, &mut frame_allocator).unwrap();

    let serial_layer = tracing_serial::SerialLayer {};
    let subscriber = tracing_serial::MockSubscriber;
    tracing::subscriber::set_global_default(subscriber.with(serial_layer)).unwrap();

    tracing::info!("Initialized kernel");
}

#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
    tracing::error!(message = "Kernel panic", %info);

    loop {}
}