/*
 * @author  xamidev <xamidev@riseup.net>
 * @brief   PepperOS kernel entry point
 * @license GPL-3.0-only
 */

#include <stdbool.h>	
#include <stddef.h>
#include <limine.h>
#include <io/term/term.h>
#include <io/serial/serial.h>
#include <arch/gdt.h>
#include <mem/utils.h>
#include <kernel.h>
#include <time/timer.h>
#include <io/kbd/ps2.h>
#include <mem/pmm.h>
#include <mem/paging.h>
#include <mem/vmm.h>
#include <mem/kheap.h>
#include <sched/process.h>
#include <sched/scheduler.h>
#include <config.h>
#include <io/term/flanterm.h>
#include <io/term/flanterm_backends/fb.h>
#include <arch/x86.h>
#include <boot/boot.h>
#include <fs/initfs.h>

// Limine version used
__attribute__((used, section(".limine_requests")))
volatile LIMINE_BASE_REVISION(3);

int panic_count = 0;

/*
 * hcf - Halt and catch fire
 *
 * This function is called only in the case of an unrecoverable
 * error. It halts interrupts, and stops execution. The machine
 * will stay in an infinite loop state.
 */
void hcf()
{
	CLEAR_INTERRUPTS; for (;;)asm("hlt");
}

/*
 * idle - Make the machine idle
 *
 * When there is nothing else to do, this function
 * gets called. It can be interrupted, so it allows
 * the scheduler, timer, and keyboard to work.
 */
void idle() {SET_INTERRUPTS; for(;;)asm("hlt");}

struct flanterm_context *ft_ctx;
struct boot_context boot_ctx;
struct init_status init = {0};

extern volatile struct limine_framebuffer_request framebuffer_request;
extern volatile struct limine_memmap_request memmap_request;
extern volatile struct limine_hhdm_request hhdm_request;
extern volatile struct limine_kernel_address_request kerneladdr_request;
extern volatile struct limine_boot_time_request date_request;
extern volatile struct limine_module_request module_request;

struct limine_file* file;

extern struct process* processes_list;
extern struct process* current_process;
struct process* idle_proc;

void idle_main(void* arg)
{
	(void)arg;
	for (;;) {
		asm("hlt");
	}
}

extern uintptr_t kheap_start;

/*
 * kmain - Kernel entry point
 *
 * This is where execution begins at handoff from Limine.
 * The function fetches all needed information from the
 * bootloader, initializes all kernel modules and structures,
 * and then goes in an idle state.
 */
void kmain()
{
	CLEAR_INTERRUPTS;
	if (!LIMINE_BASE_REVISION_SUPPORTED) hcf();

	populate_boot_context(&boot_ctx);

	term_init();
	serial_init();
	timer_init();

	x86_arch_init();

	boot_mem_display();
	pmm_init(boot_ctx);

	paging_init(boot_ctx);
	kheap_init();

	keyboard_init(FR);
	
	process_init();
	idle_proc = process_create("idle", (void*)idle_main, 0);

	if (!boot_ctx.module) {
		panic(NULL, "could not load initfs.tar :(");
	}
	if (boot_ctx.module->module_count == 1) {
		initfs_init(boot_ctx.module->modules[0]);
	}
	
	process_create("kshell", (void*)pedicel_main, 0);
	scheduler_init();

	printf(PEPPEROS_SPLASH);
	init.all = true;

	idle();
}
