/**
 * PROJECT:         ExectOS
 * COPYRIGHT:       See COPYING.md in the top level directory
 * FILE:            xtoskrnl/ar/amd64/traps.cc
 * DESCRIPTION:     AMD64 system traps
 * DEVELOPERS:      Rafal Kupiec <belliash@codingworkshop.eu.org>
 */

#include <xtos.hh>


/**
 * Dispatches the interrupt provided by common interrupt handler.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common interrupt handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::DispatchInterrupt(IN PKTRAP_FRAME TrapFrame)
{
    PINTERRUPT_HANDLER Handler;

    /* Read the handler pointer from the CPU's interrupt dispatch table */
    Handler = (PINTERRUPT_HANDLER)AR::CpuFunctions::ReadGSQuadWord(FIELD_OFFSET(KPROCESSOR_BLOCK, InterruptDispatchTable) +
                                                                   (TrapFrame->Vector * sizeof(PINTERRUPT_HANDLER)));

    /* Check if the interrupt has a handler registered */
    if(Handler != NULLPTR)
    {
        /* Call the handler */
        Handler(TrapFrame);
    }
    else if(UnhandledInterruptRoutine != NULLPTR)
    {
        /* Call the unhandled interrupt routine */
        UnhandledInterruptRoutine(TrapFrame);
    }
    else
    {
        /* Dispatcher not initialized, print a debug message */
        DebugPrint(L"ERROR: Caught unhandled interrupt: 0x%.2llX\n", TrapFrame->Vector);
    }
}

/**
 * Dispatches the trap provided by common trap handler.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::DispatchTrap(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Caught trap: 0x%.2llX with error code: %.4llX at RIP: 0x%.16llX\n"
               L"RAX: 0x%.16llX, RBX: 0x%.16llX, RCX: 0x%.16llX, RDX: 0x%.16llX\n"
               L"R8:  0x%.16llX, R9:  0x%.16llX, R10: 0x%.16llX, R11: 0x%.16llX\n"
               L"R12: 0x%.16llX, R13: 0x%.16llX, R14: 0x%.16llX, R15: 0x%.16llX\n"
               L"RBP: 0x%.16llX, RSP: 0x%.16llX, RDI: 0x%.16llX, RSI: 0x%.16llX\n"
               L"DR0: 0x%.16llX, DR1: 0x%.16llX, DR2: 0x%.16llX, DR3: 0x%.16llX\n"
               L"DR6: 0x%.16llX, DR7: 0x%.16llX\n"
               L"CR2: 0x%.16llX, CR3: 0x%.16llX, CS:  0x%.16llX, DS:  0x%.16hX\n"
               L"ES:  0x%.16hX, FS:  0x%.16hX, GS:  0x%.16hX, SS:  0x%.16llX\n",
               TrapFrame->Vector, TrapFrame->ErrorCode, TrapFrame->Rip,
               TrapFrame->Rax, TrapFrame->Rbx, TrapFrame->Rcx, TrapFrame->Rdx,
               TrapFrame->R8, TrapFrame->R9, TrapFrame->R10, TrapFrame->R11,
               TrapFrame->R12, TrapFrame->R13, TrapFrame->R14, TrapFrame->R15,
               TrapFrame->Rbp, TrapFrame->Rsp, TrapFrame->Rdi, TrapFrame->Rsi,
               TrapFrame->Dr0, TrapFrame->Dr1, TrapFrame->Dr2, TrapFrame->Dr3,
               TrapFrame->Dr6, TrapFrame->Dr7,
               TrapFrame->Cr2, TrapFrame->Cr3, TrapFrame->SegCs, TrapFrame->SegDs,
               TrapFrame->SegEs, TrapFrame->SegFs, TrapFrame->SegGs, TrapFrame->SegSs);

    /* Check vector and call appropriate handler */
    switch(TrapFrame->Vector)
    {
        case 0x00:
            /* Divide By Zero exception */
            HandleTrap00(TrapFrame);
            break;
        case 0x01:
            /* Debug exception */
            HandleTrap01(TrapFrame);
            break;
        case 0x02:
            /* Non-Maskable Interrupt (NMI) */
            HandleTrap02(TrapFrame);
            break;
        case 0x03:
            /* INT3 instruction executed */
            HandleTrap03(TrapFrame);
            break;
        case 0x04:
            /* Overflow exception */
            HandleTrap04(TrapFrame);
            break;
        case 0x05:
            /* Bound Range Exceeded exception */
            HandleTrap05(TrapFrame);
            break;
        case 0x06:
            /* Invalid Opcode exception */
            HandleTrap06(TrapFrame);
            break;
        case 0x07:
            /* Device Not Available exception */
            HandleTrap07(TrapFrame);
            break;
        case 0x08:
            /* Double Fault exception */
            HandleTrap08(TrapFrame);
            break;
        case 0x09:
            /* Segment Overrun exception */
            HandleTrap09(TrapFrame);
            break;
        case 0x0A:
            /* Invalid TSS exception */
            HandleTrap0A(TrapFrame);
            break;
        case 0x0B:
            /* Segment Not Present exception */
            HandleTrap0B(TrapFrame);
            break;
        case 0x0C:
            /* Stack Segment Fault exception */
            HandleTrap0C(TrapFrame);
            break;
        case 0x0D:
            /* General Protection Fault (GPF) exception*/
            HandleTrap0D(TrapFrame);
            break;
        case 0x0E:
            /* Page Fault exception */
            HandleTrap0E(TrapFrame);
            break;
        case 0x10:
            /* X87 Floating-Point exception */
            HandleTrap10(TrapFrame);
            break;
        case 0x11:
            /* Alignment Check exception */
            HandleTrap11(TrapFrame);
            break;
        case 0x12:
            /* Machine Check exception */
            HandleTrap12(TrapFrame);
            break;
        case 0x13:
            /* SIMD Floating-Point exception */
            HandleTrap13(TrapFrame);
            break;
        case 0x1F:
            /* Software Interrupt at APC level */
            HandleTrap1F(TrapFrame);
            break;
        case 0x2C:
            /* Assertion raised */
            HandleTrap2C(TrapFrame);
            break;
        case 0x2D:
            /* Debug-Service-Request raised */
            HandleTrap2D(TrapFrame);
            break;
        default:
            /* Unknown/Unexpected trap */
            HandleTrapFF(TrapFrame);
            break;
    }
}

/**
 * Handles a 32-bit system call.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleSystemCall32(VOID)
{
    DebugPrint(L"Handled 32-bit system call!\n");
}

/**
 * Handles a 64-bit system call.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleSystemCall64(VOID)
{
    DebugPrint(L"Handled 64-bit system call!\n");
}

/**
 * Handles the trap 0x00 when a Divide By Zero exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap00(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Division-By-Zero Error (0x00)!\n");
    KE::Crash::Panic(0x00);
}

/**
 * Handles the trap 0x01 when Debug exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap01(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Debug exception (0x01)!\n");
    KE::Crash::Panic(0x01);
}

/**
 * Handles the trap 0x02 when Non-Maskable Interrupt (NMI) occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap02(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Non-Maskable-Interrupt (0x02)!\n");
}

/**
 * Handles the trap 0x03 when the INT3 instruction is executed.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap03(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled INT3 (0x03)!\n");
    KE::Crash::Panic(0x03);
}

/**
 * Handles the trap 0x04 when the INTO instruction is executed and overflow bit is set.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap04(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Overflow exception (0x04)!\n");
    KE::Crash::Panic(0x04);
}

/**
 * Handles the trap 0x05 when the Bound Range Exceeded exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap05(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Bound-Range-Exceeded exception (0x05)!\n");
    KE::Crash::Panic(0x05);
}

/**
 * Handles the trap 0x06 when the Invalid Opcode exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap06(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Invalid Opcode exception (0x06)!\n");
    KE::Crash::Panic(0x06);
}

/**
 * Handles the trap 0x07 when the Device Not Available exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap07(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Device Not Available exception (0x07)!\n");
    KE::Crash::Panic(0x07);
}

/**
 * Handles the trap 0x08 when Double Fault exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap08(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Double-Fault exception (0x08)!\n");
    KE::Crash::Panic(0x08);
}

/**
 * Handles the trap 0x09 when the Segment Overrun exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap09(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Segment-Overrun exception (0x09)!\n");
    KE::Crash::Panic(0x09);
}

/**
 * Handles the trap 0x0A when the Invalid TSS exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap0A(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Invalid-TSS exception (0x0A)!\n");
    KE::Crash::Panic(0x0A);
}

/**
 * Handles the trap 0x0B when the Segment Not Present exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap0B(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Segment-Not-Present exception (0x0B)!\n");
    KE::Crash::Panic(0x0B);
}

/**
 * Handles the trap 0x0C when the Stack Segment Fault exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap0C(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Stack-Segment-Fault exception (0x0C)!\n");
    KE::Crash::Panic(0x0C);
}

/**
 * Handles the trap 0x0D when General Protection Fault (GPF) exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap0D(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled General-Protection-Fault (0x0D)!\n");
    KE::Crash::Panic(0x0D);
}

/**
 * Handles the trap 0x0E when the Page Fault (PF) exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap0E(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Page-Fault exception (0x0E)!\n");
    KE::Crash::Panic(0x0E);
}

/**
 * Handles the trap 0x10 when the X87 Floating-Point exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap10(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled x87 Floating-Point exception (0x10)!\n");
    KE::Crash::Panic(0x10);
}

/**
 * Handles the trap 0x11 when the Alignment Check exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap11(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Alignment-Check exception (0x11)!\n");
    KE::Crash::Panic(0x11);
}

/**
 * Handles the trap 0x12 when the Machine Check exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap12(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Machine-Check exception (0x12)!\n");
    KE::Crash::Panic(0x12);
}

/**
 * Handles the trap 0x13 when the SIMD Floating-Point exception occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap13(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled SIMD Floating-Point exception (0x13)!\n");
    KE::Crash::Panic(0x13);
}

/**
 * Handles the trap 0x1F when software interrupt gets generated at APC_LEVEL.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap1F(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Unhandled software interrupt at APC level (0x1F)!\n");
}

/**
 * Handles the trap 0x2C when an assertion is raised.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap2C(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Assertion (0x2C)!\n");
    KE::Crash::Panic(0x2C);
}

/**
 * Handles the trap 0x2D when a debug service is being requested.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrap2D(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Debug-Service-Request (0x2D)!\n");
    KE::Crash::Panic(0x2D);
}

/**
 * Handles the trap 0xFF when Unexpected Interrupt occurs.
 *
 * @param TrapFrame
 *        Supplies a kernel trap frame pushed by common trap handler on the stack.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::HandleTrapFF(IN PKTRAP_FRAME TrapFrame)
{
    DebugPrint(L"Handled Unexpected-Interrupt (0xFF)!\n");
    KE::Crash::Panic(0xFF);
}

/**
 * Initializes system call MSRs.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTCDECL
VOID
AR::Traps::InitializeSystemCallMsrs(VOID)
{
    /* Initialize system calls MSR */
    CpuFunctions::WriteModelSpecificRegister(X86_MSR_STAR, (((ULONG64)KGDT_R3_CMCODE | RPL_MASK) << 48) | ((ULONG64)KGDT_R0_CODE << 32));
    CpuFunctions::WriteModelSpecificRegister(X86_MSR_CSTAR, (ULONG64)&HandleSystemCall32);
    CpuFunctions::WriteModelSpecificRegister(X86_MSR_LSTAR, (ULONG64)&HandleSystemCall64);
    CpuFunctions::WriteModelSpecificRegister(X86_MSR_FMASK, X86_EFLAGS_IF_MASK | X86_EFLAGS_TF_MASK);

    /* Enable system call extensions (SCE) in EFER MSR */
    CpuFunctions::WriteModelSpecificRegister(X86_MSR_EFER, CpuFunctions::ReadModelSpecificRegister(X86_MSR_EFER) | X86_MSR_EFER_SCE);
}

/**
 * Sets the unhandled interrupt routine used for vectors that have no handler registered.
 *
 * @param Handler
 *        Supplies the pointer to the interrupt handler routine.
 *
 * @return This routine does not return any value.
 *
 * @since XT 1.0
 */
XTAPI
VOID
AR::Traps::SetUnhandledInterruptRoutine(PINTERRUPT_HANDLER Handler)
{
    /* Set the unhandled interrupt routine */
    UnhandledInterruptRoutine = Handler;
}
