/*++

Copyright (c) 1991  Microsoft Corporation
Copyright (c) 1992  Intel Corporation
All rights reserved

INTEL CORPORATION PROPRIETARY INFORMATION

This software is supplied to Microsoft under the terms
of a license agreement with Intel Corporation and may not be
copied nor disclosed except in accordance with the terms
of that agreement.

Module Name:

    mpdebug.c

Abstract:

    This module has some useful modules for debug aid.

Author:

    Ron Mosgrove (Intel) - Aug 1993.

Environment:

    Kernel mode or from textmode setup.

Revision History:

--*/

#ifndef _NTOS_
#include "halp.h"
#endif

#include "apic.inc"
#include "pcmp_nt.inc"
#include "stdio.h"

#define PCMP_TABLE_PTR_BASE           0x09f000
#define PCMP_TABLE_PTR_OFFSET         0x00000c00

// Create dummy PC+MP table at physical address 400K
#define  PCMP_TEST_TABLE        0x64000
#define TEST_FLOAT_PTR          0x7d000

extern struct PcMpTable *PcMpTablePtr, *PcMpDefaultTablePtrs[];
//extern struct HalpMpInfo *HalpMpInfoPtr;

CHAR Cbuf[120];

PVOID
HalpMapPhysicalMemory(
    IN PVOID PhysicalAddress,
    IN ULONG NumberPages
    );

UCHAR
ComputeCheckSum(
    IN PUCHAR SourcePtr,
    IN USHORT NumOfBytes
    );

#ifdef OLD_DEBUG
extern struct PcMpConfigTable *PcMpTablePtr;
#endif

#ifdef DEBUGGING

ULONG HalpUseDbgPrint = 0;

void
HalpDisplayString(
    IN PVOID String
    )
{
    if (!HalpUseDbgPrint) {
        HalDisplayString(String);
    } else {
        DbgPrint(String);
    }
}


void
HalpDisplayItemBuf(
    IN UCHAR Length,
    IN PUCHAR Buffer,
    IN PVOID Name
    )
{
    ULONG i;
    CHAR TmpBuf[80];
    
    sprintf(TmpBuf, "    %s -", Name);
    HalpDisplayString(TmpBuf);
    for (i=0; i< Length; i++) {
        sprintf(TmpBuf, " 0x%x", Buffer[i]);
        HalpDisplayString(TmpBuf);
    }
    HalpDisplayString("\n");
}    

void
HalpDisplayULItemBuf(
    IN UCHAR Length,
    IN PULONG Buffer,
    IN PVOID Name
    )
{
    ULONG i;
    CHAR TmpBuf[80];
    
    sprintf(TmpBuf, "    %s -", Name);
    HalpDisplayString(TmpBuf);
    for (i=0; i< Length; i++) {
        sprintf(TmpBuf, " 0x%lx", Buffer[i]);
        HalpDisplayString(TmpBuf);
    }
    HalpDisplayString("\n");
}    

void
HalpDisplayItem(
    IN ULONG Item,
    IN PVOID ItemStr
    )
{
    CHAR TmpBuf[80];

    sprintf(TmpBuf, "    %s - 0x%x\n", ItemStr, Item);
    HalpDisplayString(TmpBuf);
}

VOID
HalpDisplayBIOSSysCfg(
    IN struct SystemConfigTable *SysCfgPtr
    )
{
    HalpDisplayString("BIOS System Configuration Table\n");
    HalpDisplayItem(SysCfgPtr->ModelType, "ModelType");
    HalpDisplayItem(SysCfgPtr->SubModelType, "SubModelType");
    HalpDisplayItem(SysCfgPtr->BIOSRevision, "BIOSRevision");
    HalpDisplayItemBuf(3,SysCfgPtr->FeatureInfoByte,"FeatureInfoByte");
    HalpDisplayItem(SysCfgPtr->MpFeatureInfoByte1, "MpFeatureInfoByte1");
    HalpDisplayItem(SysCfgPtr->MpFeatureInfoByte2, "MpFeatureInfoByte2");
}

VOID
HalpDisplayLocalUnit(
    )
{
    ULONG Data;
    PKPCR   pPCR;

    pPCR = KeGetPcr();

    sprintf(Cbuf, "\nLocal Apic for P%d\n", pPCR->Prcb->Number);
    HalpDisplayString(Cbuf);

#define DisplayLuReg(Reg, RegStr)   Data = *((PVULONG) (LOCALAPIC+Reg)); \
                                    HalpDisplayItem(Data , RegStr);


    DisplayLuReg( LU_ID_REGISTER  , "LU_ID_REGISTER"  );
    DisplayLuReg( LU_VERS_REGISTER, "LU_VERS_REGISTER" );
    DisplayLuReg( LU_TPR, "LU_TPR");
    DisplayLuReg( LU_APR, "LU_APR");
    DisplayLuReg( LU_PPR, "LU_PPR");
    DisplayLuReg( LU_EOI, "LU_EOI");
    DisplayLuReg( LU_REMOTE_REGISTER, "LU_REMOTE_REGISTER");
    DisplayLuReg( LU_LOGICAL_DEST, "LU_LOGICAL_DEST");

    DisplayLuReg( LU_DEST_FORMAT, "LU_DEST_FORMAT");

    DisplayLuReg( LU_SPURIOUS_VECTOR , "LU_SPURIOUS_VECTOR" );

    DisplayLuReg( LU_ISR_0, "LU_ISR_0");
    DisplayLuReg( LU_TMR_0, "LU_TMR_0");
    DisplayLuReg( LU_IRR_0, "LU_IRR_0");
    DisplayLuReg( LU_ERROR_STATUS, "LU_ERROR_STATUS");
    DisplayLuReg( LU_INT_CMD_LOW, "LU_INT_CMD_LOW");
    DisplayLuReg( LU_INT_CMD_HIGH, "LU_INT_CMD_HIGH");
    DisplayLuReg( LU_TIMER_VECTOR, "LU_TIMER_VECTOR");
    DisplayLuReg( LU_INT_VECTOR_0, "LU_INT_VECTOR_0");
    DisplayLuReg( LU_INT_VECTOR_1, "LU_INT_VECTOR_1");
    DisplayLuReg( LU_INITIAL_COUNT, "LU_INITIAL_COUNT");
    DisplayLuReg( LU_CURRENT_COUNT, "LU_CURRENT_COUNT");

    DisplayLuReg( LU_DIVIDER_CONFIG, "LU_DIVIDER_CONFIG");
    HalpDisplayString("\n");
    
}

VOID
HalpDisplayIoUnit(
    )
/*++

Routine Description:

    Verify that an IO Unit exists at the specified address

 Arguments:

    BaseAddress - Address of the IO Unit to test.

 Return Value:
    BOOLEAN - TRUE if a IO Unit was found at the passed address
            - FALSE otherwise

--*/

{
#if 0
    struct ApicIoUnit *IoUnitPtr;
    ULONG Data,i,j;
    PKPCR   pPCR;

    pPCR = KeGetPcr();

    //
    //  The documented detection mechanism is to write all zeros to
    //  the Version register.  Then read it back.  The IO Unit exists if the
    //  same result is read both times and the Version is valid.
    //



    for (j=0; j<HalpMpInfoPtr->IOApicCount; j++) { 
        IoUnitPtr = (struct ApicIoUnit *) HalpMpInfoPtr->IoApicBase[j];

        sprintf(Cbuf,"\nIoApic %d at Vaddr 0x%x\n",j,(ULONG) IoUnitPtr);
        HalpDisplayString(Cbuf);

        IoUnitPtr->RegisterSelect = IO_ID_REGISTER;
        HalpDisplayItem(IoUnitPtr->RegisterWindow, "IO_ID_REGISTER");


        IoUnitPtr->RegisterSelect = IO_VERS_REGISTER;
        HalpDisplayItem(IoUnitPtr->RegisterWindow, "IO_VERS_REGISTER");

        for (i=0; i<16; i++) {

            IoUnitPtr->RegisterSelect = IO_REDIR_00_LOW+(i*2);
            Data = IoUnitPtr->RegisterWindow;
            sprintf(Cbuf, "    Redir [0x%x] - 0x%x, ", i, Data);
            HalpDisplayString(Cbuf);

            IoUnitPtr->RegisterSelect = IO_REDIR_00_LOW+(i*2)+1;
            Data = IoUnitPtr->RegisterWindow;
            sprintf(Cbuf, "0x%x\n", Data);
            HalpDisplayString(Cbuf);

        }  // for each Redirection entry
    } // for all Io Apics

#endif
}

void
HalpDisplayConfigTable ()
/*+++
    Debug routine  to display the PC+MP config table
--*/
{
    struct PcMpTable *MpPtr = PcMpTablePtr;
    PPCMPPROCESSOR ProcPtr;
    ULONG EntriesInTable = MpPtr->NumOfEntries;
    union PL {
        USHORT us;
        POLARITYANDLEVEL PnL;
        };

    HalpDisplayString("PcMp Configuration Table\n");

    HalpDisplayItem(MpPtr->Signature, "Signature");
    HalpDisplayItem(MpPtr->TableLength, "TableLength");
    HalpDisplayItem(MpPtr->Revision, "Revision");
    HalpDisplayItem(MpPtr->Checksum, "Checksum");

    HalpDisplayItemBuf(sizeof(MpPtr->OemId),
            MpPtr->OemId,"OemId");
    HalpDisplayItemBuf(sizeof(MpPtr->OemProductId),
            MpPtr->OemProductId,"OemProductId");
    
    HalpDisplayItem((ULONG) MpPtr->OemTablePtr, "OemTablePtr");
    HalpDisplayItem(MpPtr->OemTableSize, "OemTableSize");
    HalpDisplayItem(MpPtr->NumOfEntries, "NumOfEntries");
    HalpDisplayItem((ULONG) MpPtr->LocalApicAddress, "LocalApicAddress");
    HalpDisplayItem(MpPtr->Reserved, "Reserved");

    ProcPtr = (PPCMPPROCESSOR) ((PUCHAR) MpPtr + HEADER_SIZE);


    while (EntriesInTable) {
        EntriesInTable--;
        switch ( ProcPtr->EntryType ) {
            case ENTRY_PROCESSOR: {
                union xxx {
                    ULONG ul;
                    CPUIDENTIFIER CpuId;
                } u;
                
                sprintf (Cbuf, "Proc..: ApicId %x, Apic ver %x, Flags %x\n",
                    ProcPtr->LocalApicId,
                    ProcPtr->LocalApicVersion,
                    ProcPtr->CpuFlags
                    );
                HalpDisplayString (Cbuf);
                ProcPtr++;
                break;
            }

            case ENTRY_BUS: {
                PPCMPBUS BusPtr = (PPCMPBUS) ProcPtr;

                sprintf (Cbuf, "Bus...: id %02x, type '%.6s'\n",
                            BusPtr->BusId, BusPtr->BusType);

                HalpDisplayString (Cbuf);
                BusPtr++;
                ProcPtr = (PPCMPPROCESSOR) BusPtr;
                break;
            }

            case ENTRY_IOAPIC: {
                PPCMPIOAPIC IoApPtr = (PPCMPIOAPIC) ProcPtr;

                sprintf (Cbuf, "IoApic: id %02x, ver %x, Flags %x, Address %x\n",
                    IoApPtr->IoApicId,
                    IoApPtr->IoApicVersion,
                    IoApPtr->IoApicFlag,
                    (ULONG) IoApPtr->IoApicAddress
                    );
                HalpDisplayString (Cbuf);

                IoApPtr++;
                ProcPtr = (PPCMPPROCESSOR) IoApPtr;
                break;
            }

            case ENTRY_INTI: {
                PPCMPINTI IntiPtr = (PPCMPINTI) ProcPtr;
                union PL u;

                u.PnL = IntiPtr->Signal;

                sprintf (Cbuf, "Inti..: t%x, s%x, SInt %x-%x, Inti %x-%x\n",
                    IntiPtr->IntType,
                    u.us,
                    IntiPtr->SourceBusId,
                    IntiPtr->SourceBusIrq,
                    IntiPtr->IoApicId,
                    IntiPtr->IoApicInti
                );
                HalpDisplayString (Cbuf);

                IntiPtr++;
                ProcPtr = (PPCMPPROCESSOR) IntiPtr;
                break;
            }

            case ENTRY_LINTI: {
                PPCMPLINTI LIntiPtr = (PPCMPLINTI) ProcPtr;
                union PL u;

                u.PnL = LIntiPtr->Signal;

                sprintf (Cbuf, "Linti.: t%x, s%x, SInt %x-%x, Linti %x-%x\n",
                    LIntiPtr->IntType,
                    u.us,
                    LIntiPtr->SourceBusId,
                    LIntiPtr->SourceBusIrq,
                    LIntiPtr->DestLocalApicId,
                    LIntiPtr->DestLocalApicInti
                );
                HalpDisplayString (Cbuf);

                LIntiPtr++;
                ProcPtr = (PPCMPPROCESSOR) LIntiPtr;
                break;
            }
        
            default: {
                HalpDisplayItem(ProcPtr->EntryType, "Unknown Type");
                return;
            }
        }
    }
}

void
HalpDisplayExtConfigTable ()
{
    PMPS_EXTENTRY  ExtTable;
    extern struct HalpMpInfo HalpMpInfoTable;


    ExtTable = HalpMpInfoTable.ExtensionTable;
    while (ExtTable < HalpMpInfoTable.EndOfExtensionTable) {
        switch (ExtTable->Type) {

            case EXTTYPE_BUS_ADDRESS_MAP:
                sprintf (Cbuf, "BusMap: id %02x, t%x  Base %08x  Len %08x\n",
                    ExtTable->u.AddressMap.BusId,
                    ExtTable->u.AddressMap.Type,
                    (ULONG) ExtTable->u.AddressMap.Base,
                    (ULONG) ExtTable->u.AddressMap.Length
                );
                HalpDisplayString (Cbuf);
                break;

            case EXTTYPE_BUS_HIERARCHY:
                sprintf (Cbuf, "BusHie: id %02x, Parent:%x  sd:%x\n",
                    ExtTable->u.BusHierarchy.BusId,
                    ExtTable->u.BusHierarchy.ParentBusId,
                    ExtTable->u.BusHierarchy.SubtractiveDecode
                );
                HalpDisplayString (Cbuf);
                break;

            case EXTTYPE_BUS_COMPATIBLE_MAP:
                sprintf (Cbuf, "ComBus: id %02x %c List %x\n",
                    ExtTable->u.CompatibleMap.BusId,
                    ExtTable->u.CompatibleMap.Modifier ? '-' : '+',
                    ExtTable->u.CompatibleMap.List
                    );
                HalpDisplayString (Cbuf);
                break;

            case EXTTYPE_PERSISTENT_STORE:
                sprintf (Cbuf, "PreSTR: Address %08x Len %08x\n",
                    (ULONG) ExtTable->u.PersistentStore.Address,
                    (ULONG) ExtTable->u.PersistentStore.Length
                );
                HalpDisplayString (Cbuf);
                break;

            default:
                HalpDisplayItem(ExtTable->Type, "Unknown Type");
                break;
        }


        ExtTable = (PMPS_EXTENTRY) (((PUCHAR) ExtTable) + ExtTable->Length);
    }
    
}


void
HalpDisplayMpInfo()
{
#if 0
    struct HalpMpInfo *MpPtr = HalpMpInfoPtr;

    HalpDisplayString("\nHAL: Private Mp Info\n");

    HalpDisplayItem(MpPtr->ApicVersion, "ApicVersion");
    HalpDisplayItem(MpPtr->ProcessorCount, "ProcessorCount");
    HalpDisplayItem(MpPtr->BusCount, "BusCount");
    HalpDisplayItem(MpPtr->IOApicCount, "IOApicCount");
    HalpDisplayItem(MpPtr->IntiCount, "IntiCount");
    HalpDisplayItem(MpPtr->LintiCount, "LintiCount");
    HalpDisplayItem(MpPtr->IMCRPresent, "IMCRPresent");

    HalpDisplayULItemBuf(4,(PULONG) MpPtr->IoApicBase,"IoApicBase");
    HalpDisplayString("\n");
    HalpDisplayConfigTable();

#endif
}


#ifdef OLD_DEBUG

BOOLEAN
HalpVerifyLocalUnit(
    IN UCHAR ApicID
    )
/*++

Routine Description:

    Verify that a Local Apic has the specified Apic Id.

 Arguments:

    ApicId - Id to verify.

 Return Value:
    BOOLEAN - TRUE if found
            - FALSE otherwise

--*/

{
    union ApicUnion Temp;

    //
    //  The remote read command must be:
    //
    //      Vector - Bits 4-9 of the Version register
    //      Destination Mode - Physical
    //      Trigger Mode - Edge
    //      Delivery Mode - Remote Read
    //      Destination Shorthand - Destination Field
    //

#define LU_READ_REMOTE_VERSION   ( (LU_VERS_REGISTER >> 4) | \
                                    DELIVER_REMOTE_READ | \
                                    ICR_USE_DEST_FIELD)

#define DEFAULT_DELAY   100

    PVULONG LuDestAddress = (PVULONG) (LOCALAPIC + LU_INT_CMD_HIGH);
    PVULONG LuICR = (PVULONG) (LOCALAPIC + LU_INT_CMD_LOW);
    PVULONG LuRemoteReg = (PVULONG) (LOCALAPIC + LU_REMOTE_REGISTER);
    ULONG RemoteReadStatus;
    ULONG DelayCount = DEFAULT_DELAY;

    //
    //  First make sure we can get to the Apic Bus
    //

    while ( ( DelayCount-- ) && ( *LuICR & DELIVERY_PENDING ) );

    if (DelayCount == 0) {
        //
        //  We're toast, can't gain access to the APIC Bus
        //
        return (FALSE);
    }

    //
    //  Set the Address of the APIC we're looking for
    //

    *LuDestAddress = (ApicID << DESTINATION_SHIFT);

    //
    //  Issue the request
    //

    *LuICR = LU_READ_REMOTE_VERSION;

    //
    //  Reset the Delay so we can get out of here just in case...
    //

    DelayCount = DEFAULT_DELAY;

    while (DelayCount--) {

        RemoteReadStatus = *LuICR & ICR_RR_STATUS_MASK;

        if ( RemoteReadStatus == ICR_RR_INVALID) {
            //
            //  No One responded, device timed out
            //
            return (FALSE);
        }

        if ( RemoteReadStatus == ICR_RR_VALID) {
            //
            //  Someone is there and the Remote Register is valid
            //
            Temp.Raw = *LuRemoteReg;

            //
            // Do what we can to verify the Version
            //

            if (Temp.Ver.Version > 0x1f) {
                //
                //  Only known devices are 0.x and 1.x
                //
                return (FALSE);
            }

            return (TRUE);

        }   // RemoteRead Successfull

    }   // While DelayCount

    //
    //  No One responded, and the device did not time out
    //  This should never happen
    //

    return (FALSE);
}

#endif  // OLD_DEBUG

VOID
CreateBIOSTables(
    VOID)
/*++

Routine Description:
    This routine is used  to test the PC+MP detect code in the HAL.
    It creates the PC+MP structures that are really created by the
    BIOS. Since we presently do not have a BIOS that builds a PC+MP
    table, we need this for now.

Arguments:
    None.

 Return Value:
    None.

--*/

{
    PUCHAR TempPtr, BytePtr;
    UCHAR CheckSum;
    PULONG TraversePtr;
    USHORT BytesToCopy;

    HalpDisplayString("CreateBIOSTables : Entered\n");
    // First, copy default PC+MP configuration 2 table at physical
    // address PCMP_TEST_TABLE
    TempPtr = (PUCHAR) HalpMapPhysicalMemory(
                (PVOID) PCMP_TEST_TABLE, 1);

    BytesToCopy = (PcMpDefaultTablePtrs[1])->TableLength;
    RtlMoveMemory(TempPtr, (PUCHAR)PcMpDefaultTablePtrs[1],
        BytesToCopy);

    // Populate the checksum entry for the table.
    CheckSum = ComputeCheckSum(TempPtr, BytesToCopy);

    sprintf(Cbuf, "CreateBIOSTables: PC+MP table computed checksum = %x\n",
        CheckSum);
    HalpDisplayString(Cbuf);

    CheckSum = ~CheckSum + 1;
    ((struct PcMpTable *)TempPtr)->Checksum = CheckSum;

    sprintf(Cbuf, "CreateBIOSTables: PC+MP table written checksum = %x\n",
        CheckSum);
    HalpDisplayString(Cbuf);


    // Now create the floating pointer structure for the table.

    TraversePtr = (PULONG) HalpMapPhysicalMemory( (PVOID) TEST_FLOAT_PTR, 1);
    TempPtr = (PUCHAR) TraversePtr;

    *TraversePtr++ = MP_PTR_SIGNATURE;
    *TraversePtr++ = PCMP_TEST_TABLE;
    BytePtr = (PUCHAR)TraversePtr;
    *BytePtr++ = 1;  // Length in number of  16 byte paragraphs
    *BytePtr++ = 1;  // Spec Rev.
    *BytePtr++ = 0;  // CheckSum
    *BytePtr++ = 0;  // Reserved
    TraversePtr = (PULONG)BytePtr;
    *TraversePtr = 0; // Reserved

    CheckSum = ComputeCheckSum(TempPtr,16);

    sprintf(Cbuf, "CreateBIOSTables: FLOAT_PTR computed checksum = %x\n",
        CheckSum);
    HalpDisplayString(Cbuf);

    CheckSum = ~CheckSum + 1;

    sprintf(Cbuf, "CreateBIOSTables: FLOAT_PTR written checksum = %x\n",
        CheckSum);
    HalpDisplayString(Cbuf);

    ((struct PcMpTableLocator *)TempPtr)->TableChecksum = CheckSum;

    HalpDisplayString("CreateBIOSTables : Done\n");

}

#endif  // DEBUGGING