/*
 * @author  xamidev <xamidev@riseup.net>
 * @brief   Kernel panic
 * @license GPL-3.0-only
 */

#include <stddef.h>
#include <arch/x86.h>
#include <io/serial/serial.h>
#include <kernel.h>

extern struct init_status init;
extern int panic_count;

/*
 * reaf_rflags - provide easy reading of the RFLAGS register
 * @rflags: RFLAGS register value
 */
void read_rflags(uint64_t rflags)
{
	printf("\x1b[38;5;226m%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s\x1b[38;5;231m",
		CHECK_BIT(rflags, 0) ? "CF " : "", /*carry flag*/
		CHECK_BIT(rflags, 2) ? "PF " : "", /*parity flag*/
		CHECK_BIT(rflags, 4) ? "AF " : "", /*auxiliary carry flag*/
		CHECK_BIT(rflags, 6) ? "ZF " : "", /*zero flag*/
		CHECK_BIT(rflags, 7) ? "SF " : "", /*sign flag*/
		CHECK_BIT(rflags, 8) ? "TF " : "", /*trap flag*/
		CHECK_BIT(rflags, 9) ? "IF " : "", /*interrupt enable flag*/
		CHECK_BIT(rflags, 10) ? "DF " : "", /*direction flag*/
		CHECK_BIT(rflags, 11) ? "OF " : "", /*overflow flag*/
		(CHECK_BIT(rflags, 12) && CHECK_BIT(rflags, 13)) ? "IOPL3 " : "IOPL0 ", /*io privilege lvl*/
		CHECK_BIT(rflags, 14) ? "NT " : "", /*nested task*/
		CHECK_BIT(rflags, 16) ? "RF " : "", /*resume flag*/
		CHECK_BIT(rflags, 17) ? "VM " : "", /*virtual 8086 mode*/
		CHECK_BIT(rflags, 18) ? "AC " : "", /*alignment check/access control*/
		CHECK_BIT(rflags, 19) ? "VIF " : "", /*virtual interrupt flag*/
		CHECK_BIT(rflags, 20) ? "VIP " : "", /*virtual interrupt pending*/
		CHECK_BIT(rflags, 21) ? "ID " : ""); /*id flag*/
}

/*
 * panic - Kernel panic
 * @ctx: CPU context (optional)
 * @str: Error message 
 *
 * Ends execution of the kernel in case of an unrecoverable error.
 * Will display to terminal if it is initialized, otherwise serial only.
 * Can be called with or without a CPU context.
 */
void panic(struct cpu_status* ctx, const char* str)
{
	CLEAR_INTERRUPTS;
	panic_count += 1;
	if (ctx == NULL) {
		printf("\r\n\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[48;5;232m Something went horribly wrong! (no cpu ctx)");
		printf("\r\n%s\r\n\x1b[38;5;231m\x1b[0m", str);
		debug_stack_trace(100);
		hcf();
	}

	printf("\r\n\x1b[38;5;231m\x1b[48;5;196mKernel panic!!!\x1b[48;5;232mat rip=%p\r\nSomething went horribly wrong! (%s) vect=0x%.2x errcode=0x%x\n\rrax=%p rbx=%p rcx=%p rdx=%p\n\rrsi=%p rdi=%p  r8=%p  r9=%p\n\rr10=%p r11=%p r12=%p r13=%p\n\rr14=%p r15=%p\n\n\rflags=%p ",
	ctx->iret_rip,
	str,
	ctx->vector_number, ctx->error_code, ctx->rax, ctx->rbx, ctx->rcx, ctx->rdx, ctx->rsi, ctx->rdi,
	ctx->r8, ctx->r9, ctx->r10, ctx->r11, ctx->r12, ctx->r13, ctx->r14, ctx->r15, ctx->iret_flags);

	read_rflags(ctx->iret_flags);
	debug_stack_trace(100);
	
	hcf();
}