/*
 * PROJECT:         ReactOS Kernel
 * LICENSE:         GPL - See COPYING in the top level directory
 * FILE:            ntoskrnl/kd64/kdprint.c
 * PURPOSE:         KD64 Trap Handler Routines
 * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
 */

/* INCLUDES ******************************************************************/

#include <ntoskrnl.h>
#define NDEBUG
#include <debug.h>

/* FUNCTIONS *****************************************************************/

BOOLEAN
NTAPI
KdpPrintString(IN PSTRING Output)
{
    STRING Data, Header;
    DBGKD_DEBUG_IO DebugIo;
    ULONG Length = Output->Length;

    /* Copy the string */
    RtlMoveMemory(KdpMessageBuffer, Output->Buffer, Length);

    /* Make sure we don't exceed the KD Packet size */
    if ((sizeof(DBGKD_DEBUG_IO) + Length) > PACKET_MAX_SIZE)
    {
        /* Normalize length */
        Length = PACKET_MAX_SIZE - sizeof(DBGKD_DEBUG_IO);
    }

    /* Build the packet header */
    DebugIo.ApiNumber = DbgKdPrintStringApi;
    DebugIo.ProcessorLevel = KeProcessorLevel;
    DebugIo.Processor = KeGetCurrentPrcb()->Number;
    DebugIo.u.PrintString.LengthOfString = Length;
    Header.Length = sizeof(DBGKD_DEBUG_IO);
    Header.Buffer = (PCHAR)&DebugIo;

    /* Build the data */
    Data.Length = Length;
    Data.Buffer = KdpMessageBuffer;

    /* Send the packet */
    KdSendPacket(PACKET_TYPE_KD_DEBUG_IO, &Header, &Data, &KdpContext);

    /* Check if the user pressed CTRL+C */
    return KdpPollBreakInWithPortLock();
}

ULONG
NTAPI
KdpCommandString(IN ULONG Length,
                 IN LPSTR String,
                 IN KPROCESSOR_MODE PreviousMode,
                 IN PCONTEXT ContextRecord,
                 IN PKTRAP_FRAME TrapFrame,
                 IN PKEXCEPTION_FRAME ExceptionFrame)
{
    /* FIXME */
    return FALSE;
}

ULONG
NTAPI
KdpSymbol(IN PSTRING DllPath,
          IN PKD_SYMBOLS_INFO DllBase,
          IN BOOLEAN Unload,
          IN KPROCESSOR_MODE PreviousMode,
          IN PCONTEXT ContextRecord,
          IN PKTRAP_FRAME TrapFrame,
          IN PKEXCEPTION_FRAME ExceptionFrame)
{
    BOOLEAN Entered;
    PKPRCB Prcb = KeGetCurrentPrcb();
    ULONG Status;

    /* Check if we need to do anything */
    if ((PreviousMode != KernelMode) || (KdDebuggerNotPresent)) return 0;

    /* Enter the debugger */
    Entered = KdEnterDebugger(TrapFrame, ExceptionFrame);

    /* Save the CPU Control State and save the context */
    KiSaveProcessorControlState(&Prcb->ProcessorState);
    RtlCopyMemory(&Prcb->ProcessorState.ContextFrame,
                  ContextRecord,
                  sizeof(CONTEXT));

    /* Report the new state */
    Status = KdpReportLoadSymbolsStateChange(DllPath,
                                             DllBase,
                                             Unload,
                                             &Prcb->ProcessorState.
                                             ContextFrame);

    /* Now restore the processor state, manually again. */
    RtlCopyMemory(ContextRecord,
                  &Prcb->ProcessorState.ContextFrame,
                  sizeof(CONTEXT));
    //KiRestoreProcessorControlState(&Prcb->ProcessorState);

    /* Exit the debugger and clear the CTRL-C state */
    KdExitDebugger(Entered);
    return 0;
}

ULONG
NTAPI
KdpPrompt(IN LPSTR InString,
          IN ULONG InStringLength,
          OUT LPSTR OutString,
          IN ULONG OutStringLength,
          IN KPROCESSOR_MODE PreviousMode,
          IN PKTRAP_FRAME TrapFrame,
          IN PKEXCEPTION_FRAME ExceptionFrame)
{
    /* FIXME */
    return FALSE;
}

ULONG
NTAPI
KdpPrint(IN ULONG ComponentId,
         IN ULONG ComponentMask,
         IN LPSTR String,
         IN ULONG Length,
         IN KPROCESSOR_MODE PreviousMode,
         IN PKTRAP_FRAME TrapFrame,
         IN PKEXCEPTION_FRAME ExceptionFrame,
         OUT PBOOLEAN Status)
{
    NTSTATUS ReturnValue;
    BOOLEAN Entered;
    ANSI_STRING AnsiString;

    /* Assume failure */
    *Status = FALSE;

    /* Validate the mask */
    if (ComponentMask <= 0x1F) ComponentMask = 1 << ComponentMask;
    if (!(Kd_WIN2000_Mask & ComponentMask) ||
        ((ComponentId < KdComponentTableSize) &&
        !(*KdComponentTable[ComponentId] & ComponentMask)))
    {
        /* Mask validation failed */
        *Status = TRUE;
        return FALSE;
    }

    /* Normalize the length */
    Length = min(Length, 512);

    /* Check if we need to verify the buffer */
    if (PreviousMode != KernelMode)
    {
        /* FIXME: Support user-mode */
    }

    /* Setup the ANSI string */
    AnsiString.Buffer = String;
    AnsiString.Length = (USHORT)Length;

    /* Log the print */
    //KdLogDbgPrint(&AnsiString);

    /* Check for a debugger */
    if (KdDebuggerNotPresent)
    {
        /* Fail */
        *Status = TRUE;
        return (ULONG)STATUS_DEVICE_NOT_CONNECTED;
    }

    /* Enter the debugger */
    Entered = KdEnterDebugger(TrapFrame, ExceptionFrame);

    /* Print the string */
    if (KdpPrintString(&AnsiString))
    {
        /* User pressed CTRL-C, breakpoint on return */
        ReturnValue = STATUS_BREAKPOINT;
    }
    else
    {
        /* String was printed */
        ReturnValue = STATUS_SUCCESS;
    }

    /* Exit the debugger and return */
    KdExitDebugger(Entered);
    *Status = TRUE;
    return ReturnValue;
}

