/*++

Copyright (c) 1999-2001  Microsoft Corporation

Module Name:

    platform.h

Abstract:

    Platform specific macros and functions.

Author:

    Matthew D Hendel (math) 28-Aug-1999

Revision History:

--*/

// Some processors use both a stack and a backing store.
// If a particular processor supports backing store add
// DUMP_BACKING_STORE.

#if defined (i386)

#define PROGRAM_COUNTER(_context)   ((_context)->Eip)
#define STACK_POINTER(_context)     ((_context)->Esp)
#define INSTRUCTION_WINDOW_SIZE     256
#define PAGE_SIZE                   4096

//
// The CONTEXT_FULL definition on x86 doesn't really get all
// the registers. Use ALL_REGISTERS to get the compelte
// context.
//

#define ALL_REGISTERS   (CONTEXT_CONTROL    |\
                         CONTEXT_INTEGER    |\
                         CONTEXT_SEGMENTS   |\
                         CONTEXT_FLOATING_POINT |\
                         CONTEXT_DEBUG_REGISTERS    |\
                         CONTEXT_EXTENDED_REGISTERS)

//
// The following are flags specific to the CPUID instruction on x86 only.
//

#define CPUID_VENDOR_ID             (0)
#define CPUID_VERSION_FEATURES      (1)
#define CPUID_AMD_EXTENDED_FEATURES (0x80000001)

// X86 doesn't have function entries but it makes the code
// cleaner to provide placeholder types to avoid some ifdefs in the code
// itself.
typedef struct _DYNAMIC_FUNCTION_TABLE {
    LIST_ENTRY Links;
    ULONG64 MinimumAddress;
    ULONG64 MaximumAddress;
    ULONG64 BaseAddress;
    ULONG EntryCount;
    PVOID FunctionTable;
} DYNAMIC_FUNCTION_TABLE, *PDYNAMIC_FUNCTION_TABLE;

typedef struct _RUNTIME_FUNCTION {
    ULONG64 Unused;
} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;

typedef struct _UNWIND_INFO {
    ULONG64 Unused;
} UNWIND_INFO, *PUNWIND_INFO;

#elif defined(_AMD64_)

#define PROGRAM_COUNTER(_context)   ((_context)->Rip)
#define STACK_POINTER(_context)     ((_context)->Rsp)
#define INSTRUCTION_WINDOW_SIZE     256
#define PAGE_SIZE                   4096

#define ALL_REGISTERS (CONTEXT_FULL | CONTEXT_SEGMENTS | CONTEXT_DEBUG_REGISTERS)

#elif defined (ALPHA)

#define PROGRAM_COUNTER(_context)   ((_context)->Fir)
#define STACK_POINTER(_context)     ((_context)->IntSp)
#define INSTRUCTION_WINDOW_SIZE     512
#define PAGE_SIZE                   8192
#define ALL_REGISTERS               (CONTEXT_FULL)

#elif defined (_IA64_)

#define PROGRAM_COUNTER(_context)   ((_context)->StIIP)
#define STACK_POINTER(_context)     ((_context)->IntSp)
#define INSTRUCTION_WINDOW_SIZE     768
#define PAGE_SIZE                   8192
#define ALL_REGISTERS               (CONTEXT_FULL | CONTEXT_DEBUG)

#define DUMP_BACKING_STORE
#if 1
// XXX drewb - The TEB bstore values don't seem to point to
// the actual base of the backing store.  Just
// assume it's contiguous with the stack.
#define BSTORE_BASE(_teb)           ((_teb)->NtTib.StackBase)
#else
#define BSTORE_BASE(_teb)           ((_teb)->DeallocationBStore)
#endif
#define BSTORE_LIMIT(_teb)           ((_teb)->BStoreLimit)
// The BSP points to the bottom of the current frame's
// storage area.  We need to add on the size of the
// current frame to get the amount of memory that
// really needs to be stored.  When computing the
// size of the current frame space for NAT bits
// must be figured in properly based on the number
// of entries in the frame.  The NAT collection
// is spilled on every 63'rd spilled register to
// make each block an every 64 ULONG64s long.
// On NT the backing store base is always 9-bit aligned
// so we can tell when exactly the next NAT spill
// will occur by looking for when the 9-bit spill
// region will overflow.
__inline ULONG64
BSTORE_POINTER(CONTEXT* Context)
{
    ULONG64 Limit = Context->RsBSP;
    ULONG Count = (ULONG)(Context->StIFS & 0x7f);

    // Add in a ULONG64 for every register in the
    // current frame.  While doing so, check for
    // spill entries.
    while (Count-- > 0)
    {
        Limit += sizeof(ULONG64);
        if ((Limit & 0x1f8) == 0x1f8)
        {
            // Spill will be placed at this address so
            // account for it.
            Limit += sizeof(ULONG64);
        }
    }

    return Limit;
}

#elif defined (ARM)

#define PROGRAM_COUNTER(_context)   ((_context)->Pc)
#define STACK_POINTER(_context)     ((_context)->Sp)
#define INSTRUCTION_WINDOW_SIZE     512
#define PAGE_SIZE                   4096
#define ALL_REGISTERS               (CONTEXT_CONTROL | CONTEXT_INTEGER)

// ARM doesn't have function entries but it makes the code
// cleaner to provide placeholder types to avoid some ifdefs in the code
// itself.
typedef struct _DYNAMIC_FUNCTION_TABLE {
    LIST_ENTRY Links;
    ULONG64 MinimumAddress;
    ULONG64 MaximumAddress;
    ULONG64 BaseAddress;
    ULONG EntryCount;
    PVOID FunctionTable;
} DYNAMIC_FUNCTION_TABLE, *PDYNAMIC_FUNCTION_TABLE;

typedef struct _RUNTIME_FUNCTION {
    ULONG64 Unused;
} RUNTIME_FUNCTION, *PRUNTIME_FUNCTION;

typedef struct _UNWIND_INFO {
    ULONG64 Unused;
} UNWIND_INFO, *PUNWIND_INFO;

#else

#error ("unknown processor type")

#endif

#define AMD_VENDOR_ID_0     ('htuA')
#define AMD_VENDOR_ID_1     ('itne')
#define AMD_VENDOR_ID_2     ('DMAc')

#define INTEL_VENDOR_ID_0   ('uneG')
#define INTEL_VENDOR_ID_1   ('Ieni')
#define INTEL_VENDOR_ID_2   ('letn')