//////////////////////////////////////////////////////////////////////////////
//
//  SArmBoot.cpp - Singularity ARM Boot Loader
//
//  Copyright Microsoft Corporation.
//
typedef int INT;
typedef char INT8, *PINT8;
typedef short INT16, *PINT16;
typedef long INT32, *PINT32;
typedef __int64 INT64, *PINT64;
typedef long LARGEST;
typedef char CHAR, *PCHAR;
typedef unsigned int UINT;
typedef unsigned char UINT8, *PUINT8;
typedef unsigned short UINT16, *PUINT16;
typedef unsigned long UINT32, *PUINT32;
typedef unsigned __int64 UINT64, *PUINT64;
typedef unsigned long ULARGEST;
typedef unsigned short WCHAR;
typedef unsigned char UCHAR;
typedef int BOOL;
typedef void *PVOID;
typedef UINT32 ULONG_PTR;
typedef UINT32 UINTPTR;

#define NULL    0
#define arrayof(a)      (sizeof(a)/sizeof(a[0]))
#define offsetof(s,m)   (size_t)&(((s *)0)->m)

//#define DEBUG 1

/////////////////////////////////////////// Core types used by runtime system.
//

extern "C" ULONG_PTR _security_cookie = 0;

typedef __wchar_t           bartok_char;

typedef signed char         int8;
typedef signed short        int16;
typedef signed int          int32;
typedef __int64             int64;

typedef unsigned int        uint;
typedef unsigned char       uint8;
typedef unsigned short      uint16;
typedef unsigned int        uint32;
typedef unsigned __int64    uint64;

typedef float               float32;
typedef double              float64;

typedef int                 intptr;
typedef unsigned int        uintptr;

struct uintPtr
{
    uintptr value;
};

struct intPtr
{
    intptr value;
};

typedef struct uintPtr *UIntPtr;
typedef struct intPtr *IntPtr;

//
// This saves the MiniDumpBase first time through since it gets
// updated by the kernel.
//
static uintptr DumpAddr32 = 0;

//////////////////////////////////////////////////////////////////////////////
//

/////////////////////////////////////////////////////////////// Static Assert.
//
// Compile-time (not run-time) assertion. Code will not compile if
// expr is false. Note: there is no non-debug version of this; we
// want this for all builds. The compiler optimizes the code away.
//
template <bool x> struct STATIC_ASSERT_FAILURE;
template <> struct STATIC_ASSERT_FAILURE<true> { };
template <int x> struct static_assert_test { };

#define STATIC_CAT_INNER(x,y) x##y
#define STATIC_CAT(x,y) STATIC_CAT_INNER(x,y)

#define STATIC_ASSERT(condition) \
   typedef static_assert_test< \
      sizeof(STATIC_ASSERT_FAILURE<(bool)(condition)>)> \
         STATIC_CAT(__static_assert_typedef_, __COUNTER__)

//////////////////////////////////////////////////////////////////////////////
//
#define OFFSETOF(s,m)   ((uintptr)&(((s *)0)->m))

//////////////////////////////////////////////////////////////////////////////
//
#pragma warning(disable: 4103)
#include "halclass.h"

//////////////////////////////////////////////////////////////////////////////

#define OMAP_CORE_CM_BASE              (0x48004A00)

#define CM_CLKSEL_CORE                 0x40
#define CM_CLKSEL_CORE_GPT1            0x01
#define CM_CLKSEL_CORE_GPT1_SYS32K     0x00

#define CM_CORE_EN_MMC1                (1 << 24)
#define CM_CORE_EN_MMC2                (1 << 25)
#define CM_CORE_EN_I2C1                (1 << 15)
#define CM_CORE_EN_UART2               (1 << 14)
#define CM_CORE_EN_UART1               (1 << 13)
#define CM_CORE_EN_GPT10               (1 << 11)

#define CM_FCLKEN1_CORE                (0)
#define CM_ICLKEN1_CORE                (0x10)
#define CM_ICLKEN2_CORE                (0x14)
#define CM_IDLEST_CORE                 (0x20)

#define OMAP_DSS_CM_BASE               (0x48004E00)

#define CM_FCLKEN_DSS                  (0)
#define CM_ICLKEN_DSS                  (0x10)

#define CM_DSS_EN_DSS1                 (1 << 0)
#define CM_DSS_EN_DSS2                 (1 << 1)
#define CM_DSS_EN_TV                   (1 << 2)

#define OMAP_WKUP_CM_BASE              (0x48004C00)

#define CM_CLKSEL_WKUP                 0x40
#define CM_CLKSEL_WKUP_GPT1            0x01
#define CM_CLKSEL_WKUP_GPT1_SYS32K     0x00

#define CM_WKUP_EN_GPT1                0x01
#define CM_WKUP_EN_GPIO1               (1 << 3)
#define CM_FCLKEN_WKUP                 (0)
#define CM_ICLKEN_WKUP                 (0x10)
#define CM_IDLEST_WKUP                 (0x20)

#define OMAP_PER_CM_BASE               (0x48005000)

#define CM_CLKSEL_PER                  0x40
#define CM_CLKSEL_PER_GPT2             0x01
#define CM_CLKSEL_PER_GPT2_SYS32K      0x00

#define CM_PER_EN_GPT2                 0x08
#define CM_FCLKEN_PER                  (0)
#define CM_ICLKEN_PER                  (0x10)
#define CM_IDLEST_PER                  (0x20)

//
// Registers to configure external pins for I2C, SD/MMC1, and SD/MMC2
//

#define OMAP_SCM_BASE                   (0x48002000)

#define OMAP_PADCONF_MASK               (0xffff)
#define OMAP_PADCONF_SHIFT              0x10

#define OMAP_PADCONF_MUXMODE_MASK       (0xfff8)
#define OMAP_PADCONF_MUXMODE_0          (0x0000)
#define OMAP_PADCONF_MUXMODE_1          (0x0001)
#define OMAP_PADCONF_MUXMODE_2          (0x0002)
#define OMAP_PADCONF_MUXMODE_3          (0x0003)
#define OMAP_PADCONF_MUXMODE_4          (0x0004)
#define OMAP_PADCONF_MUXMODE_5          (0x0005)
#define OMAP_PADCONF_MUXMODE_SAFE       (0x0007)
#define OMAP_PADCONF_PULLUDENABLE       (0x0008)
#define OMAP_PADCONF_PULLTYPESELECT     (0x0010)
#define OMAP_PADCONF_INPUTENABLE        (0x0100)
#define OMAP_PADCONF_OFFENABLE          (0x0200)
#define OMAP_PADCONF_OFFOUTENABLE       (0x0400)
#define OMAP_PADCONF_OFFOUTVALUE        (0x0800)
#define OMAP_PADCONF_OFFPULLUDENABLE    (0x1000)
#define OMAP_PADCONF_OFFPULLTYPESELECT  (0x2000)
#define OMAP_PADCONF_WAKEUPENABLE       (0x4000)
#define OMAP_PADCONF_WAKEUPEVENT        (0x8000)

#define OMAP_PADCONF_HSUSB0_DAT7        (0x1B8)
#define OMAP_PADCONF_I2C1_SDA           (0x1BC)
#define OMAP_PADCONF_SYS_NIRQ           (0x1E0)

#define OMAP_PADCONF_DSS_PCLK           (0x0D4)
#define OMAP_PADCONF_DSS_DAT18          (0x0FC)
#define OMAP_PADCONF_ETK_D10            (0xA40)
#define OMAP_PADCONF_ETK_D14            (0xA48)


#define OMAP_GPIO1_BASE                 (0x48310000)
#define OMAP_GPIO_OE                    (0x34)
#define OMAP_GPIO_SETDATAOUT            (0x94)
#define OMAP_GPIO_CLEARDATAOUT          (0x90)
#define OMAP_GPIO_PIN_24                (1 << 24)
#define OMAP_GPIO_PIN_28                (1 << 28)

//////////////////////////////////////////////////////////////////////////////

inline uint32 ReadReg32(volatile void * addr)
{
    return ((volatile uint32 *)addr)[0];
}

inline void WriteReg32(volatile void * addr, uint32 value)
{
    ((volatile uint32 *)addr)[0] = value;
}

inline void WriteReg16(volatile void * addr, uint16 value)
{
    ((volatile uint16 *)addr)[0] = value;
}

inline uint16 ReadReg16(volatile void * addr)
{
    return ((volatile uint16 *)addr)[0];
}

inline void WriteReg8(volatile void * addr, uint8 value)
{
    ((volatile uint8 *)addr)[0] = value;
}

inline uint8 ReadReg8(volatile void * addr)
{
    return ((volatile uint8 *)addr)[0];
}

//////////////////////////////////////////////////////////////////////////////
//

typedef unsigned int uint;
typedef unsigned int UINT;
typedef signed long LARGEST;
typedef unsigned long ULARGEST;

#include "strformat.cpp"
#include "printf.cpp"
#include "debuguart.cpp"
#include "debug.cpp"
#include "expandpe.cpp"

//////////////////////////////////////////////////////////////////////////////
//
void Halt(void);

#define ASSERT(b)   if (!(b)) { AssertFailed(#b);} else
void AssertFailed(const char *string)
{
    printf("Assert Failed [%s]\n", string);
    Halt();
}

////////////////////////////////////////////////////////////////////// Memory.
//
//  OMAP 3430 Memory Map:
//
#define ON_OMAP3430_RESERVE_ADDR    0x80000000
#define ON_OMAP3430_RESERVE_SIZE    0x00050000

#define ON_OMAP3430_LOADER_ADDR     0x80000000  // SArmBoot code.
#define ON_OMAP3430_LOADER_SIZE     0x0000fff0  // was 0x10000.

#define ON_OMAP3430_CPU_ARGS_ADDR   0x8000fff0  //
#define ON_OMAP3430_CPU_ARGS_SIZE   0x80000010  //

#define ON_OMAP3430_VIDEO_ADDR      0x80010000  // LCD Video.
#define ON_OMAP3430_VIDEO_SIZE      0x00025800

#define ON_OMAP3430_ALLOC_ADDR      0x80035800  // Boot "alloc()" heap.
#define ON_OMAP3430_ALLOC_SIZE      0x0000A800

#define ON_OMAP3430_LOGBUF_ADDR     0x80040000  // Logging record buffer.
#define ON_OMAP3430_LOGBUF_SIZE     0x00008000

#define ON_OMAP3430_LOGTXT_ADDR     0x80048000  // Logging text buffer.
#define ON_OMAP3430_LOGTXT_SIZE     0x00008000

#define ON_OMAP3430_STACK_ADDR      0x80050000  // Kernel stack.
#define ON_OMAP3430_STACK_SIZE      0x00010000

#define ON_OMAP3430_KERNEL_ADDR     0x80100000  // Base address of kernel.
//#define ON_OMAP3430_KERNEL_SIZE   0xFFFFFFFF  // Determined at runtime.

#define ON_OMAP3430_MEMORY_ADDR     0x80000000  // Base general memory.
#define ON_OMAP3430_MEMORY_SIZE     0x08000000

#define ON_OMAP3430_IFLASH_ADDR     0x84000000  // Memory to scan for flash image.
#define ON_OMAP3430_IFLASH_SIZE     0x04000000

//
// These should be in a general memory layout file
// rather than buried deeply in code
//
static uintptr heapTop = ON_OMAP3430_ALLOC_ADDR;
static uintptr heapMax = ON_OMAP3430_ALLOC_ADDR + ON_OMAP3430_ALLOC_SIZE;

extern "C" void * memset(void *dest, uint8 c, uint count);
extern "C" void * memmove(void *dest, const void *src, uint count);

void * alloc(uint cbSize, uint cbPad)
{
    cbPad = (cbPad != 0) ? ((cbPad + 0xf) & ~0xf) : 0x10;  // 16-byte pad minimum.
    uintptr newTop = (heapTop + (cbPad - 1)) & ~(cbPad - 1);
    void *pvData = (void *)newTop;

    cbSize = (cbSize != 0) ? ((cbSize + 0xf) & ~0xf) : 0x10;   //16-byte pad minimum.
    newTop += cbSize;
    if (newTop  > heapMax) {
        // Failure, no one checks this call
        printf("alloc failure req %d\n", cbSize);
        Halt();
        return NULL;
    }
    heapTop = newTop;
    memset(pvData, 0, cbSize);
    return pvData;
}

void * alloc(uint cbSize)
{
    return alloc(cbSize, 0x10);
}

void * allocpages(uint cPages)
{
    return alloc(Class_Microsoft_Singularity_Hal_Platform_PAGE_SIZE * cPages,
                 Class_Microsoft_Singularity_Hal_Platform_PAGE_SIZE);
}

void * operator new(uint cbSize)
{
    return alloc(cbSize, 0);
}

///////////////////////////////////////////////////////////// Screen Routines.
//

#define DISPC_REVISION              0x00
#define DISPC_SYSCONFIG             0x10
#define DISPC_SYSSTATUS             0x14
#define DISPC_IRQSTATUS             0x18
#define DISPC_IRQENABLE             0x1C
#define DISPC_CONTROL               0x40
#define DISPC_CONFIG                0x44
#define DISPC_CAPABLE               0x48
#define DISPC_DEFAULT_COLOR0        0x4C
#define DISPC_DEFAULT_COLOR1        0x50
#define DISPC_TRANS_COLOR0          0x54
#define DISPC_TRANS_COLOR1          0x58
#define DISPC_LINE_STATUS           0x5C
#define DISPC_LINE_NUMBER           0x60
#define DISPC_TIMING_H              0x64
#define DISPC_TIMING_V              0x68
#define DISPC_POL_FREQ              0x6C
#define DISPC_DIVISOR               0x70
#define DISPC_SIZE_DIG              0x78
#define DISPC_SIZE_LCD              0x7C
#define DISPC_GFX_BA0               0x80
#define DISPC_GFX_BA1               0x84
#define DISPC_GFX_POSITION          0x88
#define DISPC_GFX_SIZE              0x8C
#define DISPC_GFX_ATTRIBUTES        0xA0
#define DISPC_GFX_FIFO_THRESHOLD    0xA4
#define DISPC_GFX_FIFO_SIZE_STATUS  0xA8
#define DISPC_GFX_ROW_INC           0xAC
#define DISPC_GFX_PIXEL_INC         0xB0
#define DISPC_GFX_WINDOW_SKIP       0xB4
#define DISPC_GFX_TABLE_BA          0xB8
#define DISPC_VID1_BA0              0xBC
#define DISPC_VID1_BA1              0xC0
#define DISPC_VID1_POSITION         0xC4
#define DISPC_VID1_SIZE             0xC8
#define DISPC_VID1_ATTRIBUTES       0xCC
#define DISPC_VID1_FIFO_THRESHOLD   0xD0
#define DISPC_VID1_FIFO_SIZE_STATUS 0xD4
#define DISPC_VID1_ROW_INC          0xD8
#define DISPC_VID1_PIXEL_INC        0xDC
#define DISPC_VID1_FIR              0xE0
#define DISPC_VID1_PICTURE_SIZE     0xE4
#define DISPC_VID1_ACCU0            0xE8
#define DISPC_VID1_ACCU1            0xEC
#define DISPC_VID1_CONV_COEF0       0x130
#define DISPC_VID1_CONV_COEF1       0x134
#define DISPC_VID1_CONV_COEF2       0x138
#define DISPC_VID1_CONV_COEF3       0x13C
#define DISPC_VID1_CONV_COEF4       0x140
#define DISPC_VID2_BA0              0x14C
#define DISPC_VID2_BA1              0x150
#define DISPC_VID2_POSITION         0x154
#define DISPC_VID2_SIZE             0x158
#define DISPC_VID2_ATTRIBUTES       0x15C
#define DISPC_VID2_FIFO_THRESHOLD   0x160
#define DISPC_VID2_FIFO_SIZE_STATUS 0x164
#define DISPC_VID2_ROW_INC          0x168
#define DISPC_VID2_PIXEL_INC        0x16C
#define DISPC_VID2_FIR              0x170
#define DISPC_VID2_PICTURE_SIZE     0x174
#define DISPC_VID2_ACCU0            0x178
#define DISPC_VID2_ACCU1            0x17C
#define DISPC_VID2_CONV_COEF0       0x1C0
#define DISPC_VID2_CONV_COEF1       0x1C4
#define DISPC_VID2_CONV_COEF2       0x1C8
#define DISPC_VID2_CONV_COEF3       0x1CC
#define DISPC_VID2_CONV_COEF4       0x1D0
#define DISPC_DATA_CYCLE1           0x1D4
#define DISPC_DATA_CYCLE2           0x1D8
#define DISPC_DATA_CYCLE3           0x1DC
#define DISPC_CPR_COEF_R            0x220
#define DISPC_CPR_COEF_G            0x224
#define DISPC_CPR_COEF_B            0x228
#define DISPC_GFX_PRELOAD           0x22C
#define DISPC_VID1_PRELOAD          0x230
#define DISPC_VID2_PRELOAD          0x234

#define DISPC_CONFIG_LOADMODE_FRDATLEF  (2 << 1) //  XXX maybe

#define DISPC_CONTROL_DIGITALENABLE (1 << 1)
#define DISPC_CONTROL_GOLCD         (1 << 5)
#define DISPC_CONTROL_GPOUT0        (1 << 15)
#define DISPC_CONTROL_GPOUT1        (1 << 16)
#define DISPC_CONTROL_LCDENABLE     (1 << 0)
#define DISPC_CONTROL_RFBIMODE      (1 << 11)
#define DISPC_CONTROL_STNTFT        (1 << 3)
#define DISPC_CONTROL_TFTDATALINES_OALSB16B (1 << 8)

#define DISPC_DIVISOR_LCD_SHIFT     16
#define DISPC_DIVISOR_PCD_SHIFT     0

#define DISPC_GFX_ATTRIBUTES_ENABLE 1
#define DISPC_GFX_ATTRIBUTES_GFXFORMAT_RGB16 (6 << 1)

#define DISPC_GFX_FIFO_THRESHOLD_HIGH_SHIFT 16
#define DISPC_GFX_FIFO_THRESHOLD_LOW_SHIFT 0

#define DISPC_SYSCONFIG_MIDLEMODE_NSTANDBY (1 << 12)
#define DISPC_SYSCONFIG_SIDLEMODE_NIDLE    (1 << 3)
#define DISPC_SYSCONFIG_SOFTRESET          (1 << 1)

#define DISPC_SYSSTATUS_RESETDONE          (1)

#define DISPC_TIMING_H_HBP_SHIFT    20
#define DISPC_TIMING_H_HFP_SHIFT    8
#define DISPC_TIMING_H_HSW_SHIFT    0

#define DISPC_TIMING_V_VBP_SHIFT    20
#define DISPC_TIMING_V_VFP_SHIFT    8
#define DISPC_TIMING_V_VSW_SHIFT    0

#define DISPC_SIZE_LCD_QVGA_PORTRAIT (((320 - 1) << 16) | (240 - 1))
#define DISPC_SIZE_QVGA_PORTRAIT    DISPC_SIZE_LCD_QVGA_PORTRAIT

#define GPIO_LCD_BACKLIGHT          24
#define GPIO_LCD_POWER              28

//////////////////////////////////////////////////////////////////////////////
//
//
// I2C interface (used here to control power to SD/MMC cards via the 4030)
//

#define OMAP_I2C1_BASE                 (0x48070000)

#define I2C_STAT                       (0x8)
#define I2C_STAT_XDR                   (1 << 14)
#define I2C_STAT_RDR                   (1 << 13)
#define I2C_STAT_BUSY                  (1 << 12)
#define I2C_STAT_XRDY                  (1 << 4)
#define I2C_STAT_RRDY                  (1 << 3)
#define I2C_STAT_ARDY                  (1 << 2)
#define I2C_STAT_NACK                  (1 << 1)
#define I2C_STAT_AL                    (1 << 0)

#define I2C_BUF                        (0x14)
#define I2C_CNT                        (0x18)
#define I2C_DATA                       (0x1C)

#define I2C_CON                        (0x24)
#define I2C_CON_EN                     (1 << 15)
#define I2C_CON_STB                    (1 << 11)  // XXX REVIEW
#define I2C_CON_MASTER                 (1 << 10)
#define I2C_CON_DIR_MASK               (1 << 9)
#define I2C_CON_XMIT                   I2C_CON_DIR_MASK
#define I2C_CON_RECV                   (0)
#define I2C_CON_STP                    (1 << 1) // XXX REVIEW
#define I2C_CON_STT                    (1 << 0) // XXX REVIEW

#define I2C_PSC                        (0x30)
#define I2C_SCLL                       (0x34)
#define I2C_SCLH                       (0x38)
#define I2C_OA0                        (0x28)
#define I2C_SA                         (0x2C)
#define I2C_BUFSTAT                    (0x40)

#define OMAP_PM_RECEIVER               (0x4B)

void HalpClocksInitialize()
{
    uint32 Value;

    // Clock manager domain control registers
    uint8 * HalpWKUP_CM = (uint8 *)OMAP_WKUP_CM_BASE;
    uint8 * HalpCORE_CM = (uint8 *)OMAP_CORE_CM_BASE;
    uint8 * HalpDSS_CM  = (uint8 *)OMAP_DSS_CM_BASE;

    // Enable interface and function clocks for WKUP (power management)
    Value = ReadReg32(HalpWKUP_CM + CM_FCLKEN_WKUP);
    Value |= CM_WKUP_EN_GPIO1;
    WriteReg32(HalpWKUP_CM + CM_FCLKEN_WKUP, Value);

    Value = ReadReg32(HalpWKUP_CM + CM_ICLKEN_WKUP);
    Value |= CM_WKUP_EN_GPIO1;
    WriteReg32(HalpWKUP_CM + CM_ICLKEN_WKUP, Value);

    // Enable interface and function clocks for CORE (peripherals)
    Value = ReadReg32(HalpCORE_CM + CM_FCLKEN1_CORE);
    Value |= CM_CORE_EN_I2C1;
    WriteReg32(HalpCORE_CM + CM_FCLKEN1_CORE, Value);

    Value = ReadReg32(HalpCORE_CM + CM_ICLKEN1_CORE);
    Value |= CM_CORE_EN_I2C1;
    WriteReg32(HalpCORE_CM + CM_ICLKEN1_CORE,Value);

    // Enable interface and function clocks for DSS (display)
    Value = ReadReg32(HalpDSS_CM + CM_FCLKEN_DSS);
    Value |= CM_DSS_EN_DSS1 | CM_DSS_EN_DSS2 | CM_DSS_EN_TV;
    WriteReg32(HalpDSS_CM + CM_FCLKEN_DSS, Value);

    Value = ReadReg32(HalpDSS_CM + CM_ICLKEN_DSS);
    Value |= CM_DSS_EN_DSS1;
    WriteReg32(HalpDSS_CM + CM_ICLKEN_DSS, Value);
}

void HalpGpioInitialize()
{
    uint32 Value;
    uint8 * HalpSCM = (uint8 *)OMAP_SCM_BASE;

    //
    // Configure GPIO pads
    //
    // NB: mode 7 is 'safe' mode - GPIO as input with
    //     no function selected from multiplexer
    //

    // Enable i2c1_scl

    // OMAP_PADCONF_HSUSB0_DAT7[15:0]  is hsusb0_data7 (mode 0),
    // OMAP_PADCONF_HSUSB0_DAT7[31:16] is i2c1_scl (mode 0)
    Value = ReadReg32(HalpSCM + OMAP_PADCONF_HSUSB0_DAT7);
    // i2c1_scl mux mode 7 (reset) -> mode 0
    Value &= ((OMAP_PADCONF_MUXMODE_MASK << OMAP_PADCONF_SHIFT) | OMAP_PADCONF_MASK);
    WriteReg32(HalpSCM + OMAP_PADCONF_HSUSB0_DAT7,Value);

    // Enable i2c1_sda

    // OMAP_PADCONF_I2C1_SDA[15:0]  is i2c1_sda (mode 0),
    // OMAP_PADCONF_I2C1_SDA[31:16] is i2c2_scl (mode 0)
    Value = ReadReg32(HalpSCM + OMAP_PADCONF_I2C1_SDA);
    // i2c1_sda mux mode 7 (reset) -> mode 0 */
    Value &= ((OMAP_PADCONF_MASK << OMAP_PADCONF_SHIFT) | OMAP_PADCONF_MUXMODE_MASK);
    WriteReg32(HalpSCM + OMAP_PADCONF_I2C1_SDA,Value);

    // Enable sys_nirq
    // - connected to int1_n on TWL4030

    // OMAP_PADCONF_SYS_NIRQ[15:0]  is sys_nirq (mode 0),
    // OMAP_PADCONF_SYS_NIRQ[31:16] is sys_clkout2 (mode 0)
    Value = ReadReg32(HalpSCM + OMAP_PADCONF_SYS_NIRQ);
    // sys_nirq mux mode 7 (reset) -> mode 0
    Value &= ((OMAP_PADCONF_MASK << OMAP_PADCONF_SHIFT) | OMAP_PADCONF_MUXMODE_MASK);
    WriteReg32(HalpSCM + OMAP_PADCONF_I2C1_SDA,Value);

    // Enable dss_* for LCD; configure these as:
    //  PULLTYPESELECT = 0, PULLUDENABLE = 0, output
    uint8 * LcdGpioConfigRegister = (uint8 *)OMAP_SCM_BASE + OMAP_PADCONF_DSS_PCLK;
    uint8* const LcdGpioConfigRegisterEnd = (uint8 *)OMAP_SCM_BASE + OMAP_PADCONF_DSS_DAT18;

    // OMAP_PADCONF_DSS_PCLK[15:0]   is dss_pclk (mode 0),
    // OMAP_PADCONF_DSS_PCLK[31:16]  is dss_hsync (mode 0),
    // OMAP_PADCONF_DSS_VSYNC[15:0]  is dss_vsync (mode 0),
    // OMAP_PADCONF_DSS_VSYNC[31:16] is dss_acbias (mode 0),
    // OMAP_PADCONF_DSS_DATn[15:0]   is dss_data(n) (mode 0),
    // OMAP_PADCONF_DSS_DATn[31:16]  is dss_data(n+1) (mode 0)
    for (; LcdGpioConfigRegister <= LcdGpioConfigRegisterEnd; LcdGpioConfigRegister += 4) {
        WriteReg32(LcdGpioConfigRegister, (OMAP_PADCONF_MUXMODE_0 << OMAP_PADCONF_SHIFT) | OMAP_PADCONF_MUXMODE_0);
    }

    // [arog - Do we need to configure etk_d15/11 as well as gpio_24/28?]

    // OMAP_PADCONF_ETK_D14[15:0]  is gpio_28 (mode 4),
    // OMAP_PADCONF_ETK_D14[31:16] is etk_d15 (mode 0) */
    WriteReg32(HalpSCM + OMAP_PADCONF_ETK_D14, (OMAP_PADCONF_MUXMODE_0 << OMAP_PADCONF_SHIFT) | OMAP_PADCONF_MUXMODE_4);

    // OMAP_PADCONF_ETK_D10[15:0]  is gpio_24 (mode 4),
    // OMAP_PADCONF_ETK_D10[31:16] is etk_d11 (mode 0)
    WriteReg32(HalpSCM + OMAP_PADCONF_ETK_D10, (OMAP_PADCONF_MUXMODE_0 << OMAP_PADCONF_SHIFT) | OMAP_PADCONF_MUXMODE_4);
}

void HalpI2CMasterInitialize()
{
    uint16 ShortValue;
    uint8 * HalpI2C1 = (uint8 *)OMAP_I2C1_BASE;

    // Setup I2C1 controller
    // _ARM_WORKAROUND_ i2c code is erroring out
    if ((ReadReg16(HalpI2C1 + I2C_CON) & I2C_CON_EN) != 0) {
        ShortValue = ReadReg16(HalpI2C1 + I2C_CON);
        ShortValue &= I2C_CON_EN;
        WriteReg16(HalpI2C1 + I2C_CON, ShortValue);
        ReadReg16(HalpI2C1 + I2C_CON);
    }

    ASSERT((ReadReg16(HalpI2C1 + I2C_CON) & I2C_CON_EN) == 0);
    // We should handle the case where it was already enabled.

    // Configure internal sampling frequency for 12Mhz.
    WriteReg8(HalpI2C1 + I2C_PSC, 7);

    // Configure for 100 kb/s
    WriteReg8(HalpI2C1 + I2C_SCLL, 54);
    WriteReg8(HalpI2C1 + I2C_SCLH, 56);

    // Set own address address register
    WriteReg16(HalpI2C1 + I2C_OA0, 0x21);

    // Take I2C controller out of reset
    ShortValue = ReadReg16(HalpI2C1 + I2C_CON);
    ShortValue |= I2C_CON_EN;
    WriteReg16(HalpI2C1 + I2C_CON,ShortValue);
}

void HalpI2CMasterSetup(
    bool Xmit,
    uint8 SlaveAddress,
    uint16 Length,
    bool GenerateStart,
    bool GenerateStop
    )
{
    uint16 ShortValue;
    uint8 * HalpI2C1 = (uint8 *)OMAP_I2C1_BASE;

    WriteReg16(HalpI2C1 + I2C_CON,I2C_CON_EN);

    // Set slave address
    WriteReg16(HalpI2C1 + I2C_SA,SlaveAddress);

    // Set transfer length
    WriteReg16(HalpI2C1 + I2C_CNT,Length);

    // Clear status
    WriteReg16(HalpI2C1 + I2C_STAT,
               I2C_STAT_ARDY | I2C_STAT_NACK | I2C_STAT_AL);

    // wait for free bus?
    //    while ReadReg16(HalpI2C1 + I2C_STAT)) & I2C_STAT_BUSY);

    ShortValue = I2C_CON_EN | I2C_CON_MASTER;
    ShortValue |= Xmit ? I2C_CON_XMIT : I2C_CON_RECV;
    ShortValue |= GenerateStart ? I2C_CON_STT : 0;
    ShortValue |= GenerateStop ? I2C_CON_STP : 0;

    WriteReg16(HalpI2C1 + I2C_CON,ShortValue);
}

bool HalpI2CMasterTransfer(bool Xmit, uint16 Length, uint8 * Data)
{
    uint16 Stat;
    uint16 Room;
    uint8 * HalpI2C1 = (uint8 *)OMAP_I2C1_BASE;

    for (;;) {

        Stat = ReadReg16(HalpI2C1 + I2C_STAT);

        if (Stat & (I2C_STAT_NACK|I2C_STAT_AL)) {
            ASSERT(Stat == 0);
            return false;
        }

        if (Stat & (I2C_STAT_ARDY)) {
            return true;
        }

        if (Xmit) {
            if (Stat & I2C_STAT_XDR) {
                Room = ReadReg16(HalpI2C1 + I2C_BUFSTAT) & 0x3F;
                while (Room--) {
                    WriteReg8(HalpI2C1 + I2C_DATA, *Data);
                    Data++;
                    Length--;
                }
            }

            if (Stat & I2C_STAT_XRDY) {
                Room = ReadReg16(HalpI2C1 + I2C_BUF) & 0x3F;
                Room += 1;

                while (Room--) {
                    WriteReg8(HalpI2C1 + I2C_DATA, *Data);
                    Data++;
                    Length--;
                }
            }
        }
        else {
            if (Stat & I2C_STAT_RDR) {
                Room = (ReadReg16(HalpI2C1 + I2C_BUFSTAT) >> 8) & 0x3F;

                while (Room--) {
                    *Data = ReadReg8(HalpI2C1 + I2C_DATA);
                    Data++;
                    Length--;
                }
            }

            if (Stat & I2C_STAT_RRDY) {
                Room = (ReadReg16(HalpI2C1 + I2C_BUF) >> 8) & 0x3F;
                Room += 1;

                while (Room--) {
                    *Data = ReadReg8(HalpI2C1 + I2C_DATA);
                    Data++;
                    Length--;
                }
            }
        }

        WriteReg16(HalpI2C1 + I2C_STAT,Stat);
    }

    return true;
}

bool
HalpI2CMasterCommon(
    bool Xmit,
    uint8 SlaveAddress,
    uint16 Length,
    uint8 * Data,
    bool GenerateStart,
    bool GenerateStop
    )
{
    int retry = 10;

    while (retry--) {

        HalpI2CMasterSetup(Xmit, OMAP_PM_RECEIVER, Length, GenerateStart, GenerateStop);

        if (HalpI2CMasterTransfer(Xmit, Length, Data)) {
            return true;
        }
    }
    return false;
}

bool
HalpI2CMasterReceive(
    uint8 SlaveAddress,
    uint16 Length,
    uint8 * Data,
    bool GenerateStart,
    bool GenerateStop
    )
{
    return HalpI2CMasterCommon(false, OMAP_PM_RECEIVER, Length, Data,
                               GenerateStart, GenerateStop);
}

bool
HalpI2CMasterSend(
    uint8 SlaveAddress,
    uint16 Length,
    uint8 * Data,
    bool GenerateStart,
    bool GenerateStop
    )
{
    return HalpI2CMasterCommon(true, OMAP_PM_RECEIVER, Length, Data,
                               GenerateStart, GenerateStop);
}

//////////////////////////////////////////////////////////////////////////////
//
void InitializeDisplayPowerDomains()
{
    uint32 Value;
    bool Good;
    uint32 Count;
    uint8 Data[2];

    //
    // Bootstrap VAUX3
    //

    Data[0] = 0x7A;
    Data[1] = 1 << 5;
    Good = HalpI2CMasterSend(OMAP_PM_RECEIVER, 2, Data, true, true);
    ASSERT(Good);

    Data[0] = 0x7B;
    Data[1] = 4;
    Good = HalpI2CMasterSend(OMAP_PM_RECEIVER, 2, Data, true, true);
    ASSERT(Good);

    Data[0] = 0x7d;
    Data[1] = 0x3;
    Good = HalpI2CMasterSend(OMAP_PM_RECEIVER, 2, Data, true, true);
    ASSERT(Good);

    Data[0] = 0x7d;
    Good = HalpI2CMasterSend(OMAP_PM_RECEIVER, 1, Data, true, false);
    ASSERT(Good);
    Good = HalpI2CMasterReceive(OMAP_PM_RECEIVER, 1, Data, true, true);
    ASSERT(Good);
    ASSERT(Data[0] == 3);

    Count = 0xFFFF;
    while (Count--);

    uint8 * HalpGPIO1 = (uint8 *)OMAP_GPIO1_BASE;

    Value = ReadReg32(HalpGPIO1 + OMAP_GPIO_OE);
    Value &= ~(OMAP_GPIO_PIN_24 | OMAP_GPIO_PIN_28);
    WriteReg32(HalpGPIO1 + OMAP_GPIO_OE, Value);

    WriteReg32(HalpGPIO1 + OMAP_GPIO_SETDATAOUT, OMAP_GPIO_PIN_28);

    Count = 0xFFFF;
    while (Count--);

    WriteReg32(HalpGPIO1 + OMAP_GPIO_SETDATAOUT, OMAP_GPIO_PIN_24);
}

//////////////////////////////////////////////////////////////////////////////

uint8 Font8[] =
    {
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x7e,0x81,0xa5,0x81,0xbd,0x99,0x81,0x7e,
        0x7e,0xff,0xdb,0xff,0xc3,0xe7,0xff,0x7e,
        0x6c,0xfe,0xfe,0xfe,0x7c,0x38,0x10,0x00,
        0x10,0x38,0x7c,0xfe,0x7c,0x38,0x10,0x00,
        0x38,0x7c,0x38,0xfe,0xfe,0x7c,0x38,0x7c,
        0x10,0x10,0x38,0x7c,0xfe,0x7c,0x38,0x7c,
        0x00,0x00,0x18,0x3c,0x3c,0x18,0x00,0x00,
        0xff,0xff,0xe7,0xc3,0xc3,0xe7,0xff,0xff,
        0x00,0x3c,0x66,0x42,0x42,0x66,0x3c,0x00,
        0xff,0xc3,0x99,0xbd,0xbd,0x99,0xc3,0xff,
        0x0f,0x07,0x0f,0x7d,0xcc,0xcc,0xcc,0x78,
        0x3c,0x66,0x66,0x66,0x3c,0x18,0x7e,0x18,
        0x3f,0x33,0x3f,0x30,0x30,0x70,0xf0,0xe0,
        0x7f,0x63,0x7f,0x63,0x63,0x67,0xe6,0xc0,
        0x99,0x5a,0x3c,0xe7,0xe7,0x3c,0x5a,0x99,
        0x80,0xe0,0xf8,0xfe,0xf8,0xe0,0x80,0x00,
        0x02,0x0e,0x3e,0xfe,0x3e,0x0e,0x02,0x00,
        0x18,0x3c,0x7e,0x18,0x18,0x7e,0x3c,0x18,
        0x66,0x66,0x66,0x66,0x66,0x00,0x66,0x00,
        0x7f,0xdb,0xdb,0x7b,0x1b,0x1b,0x1b,0x00,
        0x3e,0x63,0x38,0x6c,0x6c,0x38,0xcc,0x78,
        0x00,0x00,0x00,0x00,0x7e,0x7e,0x7e,0x00,
        0x18,0x3c,0x7e,0x18,0x7e,0x3c,0x18,0xff,
        0x18,0x3c,0x7e,0x18,0x18,0x18,0x18,0x00,
        0x18,0x18,0x18,0x18,0x7e,0x3c,0x18,0x00,
        0x00,0x18,0x0c,0xfe,0x0c,0x18,0x00,0x00,
        0x00,0x30,0x60,0xfe,0x60,0x30,0x00,0x00,
        0x00,0x00,0xc0,0xc0,0xc0,0xfe,0x00,0x00,
        0x00,0x24,0x66,0xff,0x66,0x24,0x00,0x00,
        0x00,0x18,0x3c,0x7e,0xff,0xff,0x00,0x00,
        0x00,0xff,0xff,0x7e,0x3c,0x18,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
        0x30,0x78,0x78,0x30,0x30,0x00,0x30,0x00,
        0x6c,0x6c,0x6c,0x00,0x00,0x00,0x00,0x00,
        0x6c,0x6c,0xfe,0x6c,0xfe,0x6c,0x6c,0x00,
        0x30,0x7c,0xc0,0x78,0x0c,0xf8,0x30,0x00,
        0x00,0xc6,0xcc,0x18,0x30,0x66,0xc6,0x00,
        0x38,0x6c,0x38,0x76,0xdc,0xcc,0x76,0x00,
        0x60,0x60,0xc0,0x00,0x00,0x00,0x00,0x00,
        0x18,0x30,0x60,0x60,0x60,0x30,0x18,0x00,
        0x60,0x30,0x18,0x18,0x18,0x30,0x60,0x00,
        0x00,0x66,0x3c,0xff,0x3c,0x66,0x00,0x00,
        0x00,0x30,0x30,0xfc,0x30,0x30,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x60,
        0x00,0x00,0x00,0xfc,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,
        0x06,0x0c,0x18,0x30,0x60,0xc0,0x80,0x00,
        0x7c,0xc6,0xce,0xde,0xf6,0xe6,0x7c,0x00,
        0x30,0x70,0x30,0x30,0x30,0x30,0xfc,0x00,
        0x78,0xcc,0x0c,0x38,0x60,0xcc,0xfc,0x00,
        0x78,0xcc,0x0c,0x38,0x0c,0xcc,0x78,0x00,
        0x1c,0x3c,0x6c,0xcc,0xfe,0x0c,0x1e,0x00,
        0xfc,0xc0,0xf8,0x0c,0x0c,0xcc,0x78,0x00,
        0x38,0x60,0xc0,0xf8,0xcc,0xcc,0x78,0x00,
        0xfc,0xcc,0x0c,0x18,0x30,0x30,0x30,0x00,
        0x78,0xcc,0xcc,0x78,0xcc,0xcc,0x78,0x00,
        0x78,0xcc,0xcc,0x7c,0x0c,0x18,0x70,0x00,
        0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x00,
        0x00,0x30,0x30,0x00,0x00,0x30,0x30,0x60,
        0x18,0x30,0x60,0xc0,0x60,0x30,0x18,0x00,
        0x00,0x00,0xfc,0x00,0x00,0xfc,0x00,0x00,
        0x60,0x30,0x18,0x0c,0x18,0x30,0x60,0x00,
        0x78,0xcc,0x0c,0x18,0x30,0x00,0x30,0x00,
        0x7c,0xc6,0xde,0xde,0xde,0xc0,0x78,0x00,
        0x30,0x78,0xcc,0xcc,0xfc,0xcc,0xcc,0x00,
        0xfc,0x66,0x66,0x7c,0x66,0x66,0xfc,0x00,
        0x3c,0x66,0xc0,0xc0,0xc0,0x66,0x3c,0x00,
        0xf8,0x6c,0x66,0x66,0x66,0x6c,0xf8,0x00,
        0xfe,0x62,0x68,0x78,0x68,0x62,0xfe,0x00,
        0xfe,0x62,0x68,0x78,0x68,0x60,0xf0,0x00,
        0x3c,0x66,0xc0,0xc0,0xce,0x66,0x3e,0x00,
        0xcc,0xcc,0xcc,0xfc,0xcc,0xcc,0xcc,0x00,
        0x78,0x30,0x30,0x30,0x30,0x30,0x78,0x00,
        0x1e,0x0c,0x0c,0x0c,0xcc,0xcc,0x78,0x00,
        0xe6,0x66,0x6c,0x78,0x6c,0x66,0xe6,0x00,
        0xf0,0x60,0x60,0x60,0x62,0x66,0xfe,0x00,
        0xc6,0xee,0xfe,0xfe,0xd6,0xc6,0xc6,0x00,
        0xc6,0xe6,0xf6,0xde,0xce,0xc6,0xc6,0x00,
        0x38,0x6c,0xc6,0xc6,0xc6,0x6c,0x38,0x00,
        0xfc,0x66,0x66,0x7c,0x60,0x60,0xf0,0x00,
        0x78,0xcc,0xcc,0xcc,0xdc,0x78,0x1c,0x00,
        0xfc,0x66,0x66,0x7c,0x6c,0x66,0xe6,0x00,
        0x78,0xcc,0xe0,0x70,0x1c,0xcc,0x78,0x00,
        0xfc,0xb4,0x30,0x30,0x30,0x30,0x78,0x00,
        0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0xfc,0x00,
        0xcc,0xcc,0xcc,0xcc,0xcc,0x78,0x30,0x00,
        0xc6,0xc6,0xc6,0xd6,0xfe,0xee,0xc6,0x00,
        0xc6,0xc6,0x6c,0x38,0x38,0x6c,0xc6,0x00,
        0xcc,0xcc,0xcc,0x78,0x30,0x30,0x78,0x00,
        0xfe,0xc6,0x8c,0x18,0x32,0x66,0xfe,0x00,
        0x78,0x60,0x60,0x60,0x60,0x60,0x78,0x00,
        0xc0,0x60,0x30,0x18,0x0c,0x06,0x02,0x00,
        0x78,0x18,0x18,0x18,0x18,0x18,0x78,0x00,
        0x10,0x38,0x6c,0xc6,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,
        0x30,0x30,0x18,0x00,0x00,0x00,0x00,0x00,
        0x00,0x00,0x78,0x0c,0x7c,0xcc,0x76,0x00,
        0xe0,0x60,0x60,0x7c,0x66,0x66,0xdc,0x00,
        0x00,0x00,0x78,0xcc,0xc0,0xcc,0x78,0x00,
        0x1c,0x0c,0x0c,0x7c,0xcc,0xcc,0x76,0x00,
        0x00,0x00,0x78,0xcc,0xfc,0xc0,0x78,0x00,
        0x38,0x6c,0x60,0xf0,0x60,0x60,0xf0,0x00,
        0x00,0x00,0x76,0xcc,0xcc,0x7c,0x0c,0xf8,
        0xe0,0x60,0x6c,0x76,0x66,0x66,0xe6,0x00,
        0x30,0x00,0x70,0x30,0x30,0x30,0x78,0x00,
        0x0c,0x00,0x0c,0x0c,0x0c,0xcc,0xcc,0x78,
        0xe0,0x60,0x66,0x6c,0x78,0x6c,0xe6,0x00,
        0x70,0x30,0x30,0x30,0x30,0x30,0x78,0x00,
        0x00,0x00,0xcc,0xfe,0xfe,0xd6,0xc6,0x00,
        0x00,0x00,0xf8,0xcc,0xcc,0xcc,0xcc,0x00,
        0x00,0x00,0x78,0xcc,0xcc,0xcc,0x78,0x00,
        0x00,0x00,0xdc,0x66,0x66,0x7c,0x60,0xf0,
        0x00,0x00,0x76,0xcc,0xcc,0x7c,0x0c,0x1e,
        0x00,0x00,0xdc,0x76,0x66,0x60,0xf0,0x00,
        0x00,0x00,0x7c,0xc0,0x78,0x0c,0xf8,0x00,
        0x10,0x30,0x7c,0x30,0x30,0x34,0x18,0x00,
        0x00,0x00,0xcc,0xcc,0xcc,0xcc,0x76,0x00,
        0x00,0x00,0xcc,0xcc,0xcc,0x78,0x30,0x00,
        0x00,0x00,0xc6,0xd6,0xfe,0xfe,0x6c,0x00,
        0x00,0x00,0xc6,0x6c,0x38,0x6c,0xc6,0x00,
        0x00,0x00,0xcc,0xcc,0xcc,0x7c,0x0c,0xf8,
        0x00,0x00,0xfc,0x98,0x30,0x64,0xfc,0x00,
        0x1c,0x30,0x30,0xe0,0x30,0x30,0x1c,0x00,
        0x18,0x18,0x18,0x00,0x18,0x18,0x18,0x00,
        0xe0,0x30,0x30,0x1c,0x30,0x30,0xe0,0x00,
        0x76,0xdc,0x00,0x00,0x00,0x00,0x00,0x00,
        0x00,0x10,0x38,0x6c,0xc6,0xc6,0xfe,0x00,
        0x78,0xcc,0xc0,0xcc,0x78,0x18,0x0c,0x78,
        0x00,0xcc,0x00,0xcc,0xcc,0xcc,0x7e,0x00,
        0x1c,0x00,0x78,0xcc,0xfc,0xc0,0x78,0x00,
        0x7e,0xc3,0x3c,0x06,0x3e,0x66,0x3f,0x00,
        0xcc,0x00,0x78,0x0c,0x7c,0xcc,0x7e,0x00,
        0xe0,0x00,0x78,0x0c,0x7c,0xcc,0x7e,0x00,
        0x30,0x30,0x78,0x0c,0x7c,0xcc,0x7e,0x00,
        0x00,0x00,0x78,0xc0,0xc0,0x78,0x0c,0x38,
        0x7e,0xc3,0x3c,0x66,0x7e,0x60,0x3c,0x00,
        0xcc,0x00,0x78,0xcc,0xfc,0xc0,0x78,0x00,
        0xe0,0x00,0x78,0xcc,0xfc,0xc0,0x78,0x00,
        0xcc,0x00,0x70,0x30,0x30,0x30,0x78,0x00,
        0x7c,0xc6,0x38,0x18,0x18,0x18,0x3c,0x00,
        0xe0,0x00,0x70,0x30,0x30,0x30,0x78,0x00,
        0xc6,0x38,0x6c,0xc6,0xfe,0xc6,0xc6,0x00,
        0x30,0x30,0x00,0x78,0xcc,0xfc,0xcc,0x00,
        0x1c,0x00,0xfc,0x60,0x78,0x60,0xfc,0x00,
        0x00,0x00,0x7f,0x0c,0x7f,0xcc,0x7f,0x00,
        0x3e,0x6c,0xcc,0xfe,0xcc,0xcc,0xce,0x00,
        0x78,0xcc,0x00,0x78,0xcc,0xcc,0x78,0x00,
        0x00,0xcc,0x00,0x78,0xcc,0xcc,0x78,0x00,
        0x00,0xe0,0x00,0x78,0xcc,0xcc,0x78,0x00,
        0x78,0xcc,0x00,0xcc,0xcc,0xcc,0x7e,0x00,
        0x00,0xe0,0x00,0xcc,0xcc,0xcc,0x7e,0x00,
        0x00,0xcc,0x00,0xcc,0xcc,0x7c,0x0c,0xf8,
        0xc3,0x18,0x3c,0x66,0x66,0x3c,0x18,0x00,
        0xcc,0x00,0xcc,0xcc,0xcc,0xcc,0x78,0x00,
        0x18,0x18,0x7e,0xc0,0xc0,0x7e,0x18,0x18,
        0x38,0x6c,0x64,0xf0,0x60,0xe6,0xfc,0x00,
        0xcc,0xcc,0x78,0xfc,0x30,0xfc,0x30,0x30,
        0xf8,0xcc,0xcc,0xfa,0xc6,0xcf,0xc6,0xc7,
        0x0e,0x1b,0x18,0x3c,0x18,0x18,0xd8,0x70,
        0x1c,0x00,0x78,0x0c,0x7c,0xcc,0x7e,0x00,
        0x38,0x00,0x70,0x30,0x30,0x30,0x78,0x00,
        0x00,0x1c,0x00,0x78,0xcc,0xcc,0x78,0x00,
        0x00,0x1c,0x00,0xcc,0xcc,0xcc,0x7e,0x00,
        0x00,0xf8,0x00,0xf8,0xcc,0xcc,0xcc,0x00,
        0xfc,0x00,0xcc,0xec,0xfc,0xdc,0xcc,0x00,
        0x3c,0x6c,0x6c,0x3e,0x00,0x7e,0x00,0x00,
        0x38,0x6c,0x6c,0x38,0x00,0x7c,0x00,0x00,
        0x30,0x00,0x30,0x60,0xc0,0xcc,0x78,0x00,
        0x00,0x00,0x00,0xfc,0xc0,0xc0,0x00,0x00,
        0x00,0x00,0x00,0xfc,0x0c,0x0c,0x00,0x00,
        0xc3,0xc6,0xcc,0xde,0x33,0x66,0xcc,0x0f,
        0xc3,0xc6,0xcc,0xdb,0x37,0x6f,0xcf,0x03,
        0x18,0x18,0x00,0x18,0x18,0x18,0x18,0x00,
        0x00,0x33,0x66,0xcc,0x66,0x33,0x00,0x00,
        0x00,0xcc,0x66,0x33,0x66,0xcc,0x00,0x00,
        0x22,0x88,0x22,0x88,0x22,0x88,0x22,0x88,
        0x55,0xaa,0x55,0xaa,0x55,0xaa,0x55,0xaa,
        0xdb,0x77,0xdb,0xee,0xdb,0x77,0xdb,0xee,
        0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,
        0x18,0x18,0x18,0x18,0xf8,0x18,0x18,0x18,
        0x18,0x18,0xf8,0x18,0xf8,0x18,0x18,0x18,
        0x36,0x36,0x36,0x36,0xf6,0x36,0x36,0x36,
        0x00,0x00,0x00,0x00,0xfe,0x36,0x36,0x36,
        0x00,0x00,0xf8,0x18,0xf8,0x18,0x18,0x18,
        0x36,0x36,0xf6,0x06,0xf6,0x36,0x36,0x36,
        0x36,0x36,0x36,0x36,0x36,0x36,0x36,0x36,
        0x00,0x00,0xfe,0x06,0xf6,0x36,0x36,0x36,
        0x36,0x36,0xf6,0x06,0xfe,0x00,0x00,0x00,
        0x36,0x36,0x36,0x36,0xfe,0x00,0x00,0x00,
        0x18,0x18,0xf8,0x18,0xf8,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0xf8,0x18,0x18,0x18,
        0x18,0x18,0x18,0x18,0x1f,0x00,0x00,0x00,
        0x18,0x18,0x18,0x18,0xff,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0xff,0x18,0x18,0x18,
        0x18,0x18,0x18,0x18,0x1f,0x18,0x18,0x18,
        0x00,0x00,0x00,0x00,0xff,0x00,0x00,0x00,
        0x18,0x18,0x18,0x18,0xff,0x18,0x18,0x18,
        0x18,0x18,0x1f,0x18,0x1f,0x18,0x18,0x18,
        0x36,0x36,0x36,0x36,0x37,0x36,0x36,0x36,
        0x36,0x36,0x37,0x30,0x3f,0x00,0x00,0x00,
        0x00,0x00,0x3f,0x30,0x37,0x36,0x36,0x36,
        0x36,0x36,0xf7,0x00,0xff,0x00,0x00,0x00,
        0x00,0x00,0xff,0x00,0xf7,0x36,0x36,0x36,
        0x36,0x36,0x37,0x30,0x37,0x36,0x36,0x36,
        0x00,0x00,0xff,0x00,0xff,0x00,0x00,0x00,
        0x36,0x36,0xf7,0x00,0xf7,0x36,0x36,0x36,
        0x18,0x18,0xff,0x00,0xff,0x00,0x00,0x00,
        0x36,0x36,0x36,0x36,0xff,0x00,0x00,0x00,
        0x00,0x00,0xff,0x00,0xff,0x18,0x18,0x18,
        0x00,0x00,0x00,0x00,0xff,0x36,0x36,0x36,
        0x36,0x36,0x36,0x36,0x3f,0x00,0x00,0x00,
        0x18,0x18,0x1f,0x18,0x1f,0x00,0x00,0x00,
        0x00,0x00,0x1f,0x18,0x1f,0x18,0x18,0x18,
        0x00,0x00,0x00,0x00,0x3f,0x36,0x36,0x36,
        0x36,0x36,0x36,0x36,0xff,0x36,0x36,0x36,
        0x18,0x18,0xff,0x18,0xff,0x18,0x18,0x18,
        0x18,0x18,0x18,0x18,0xf8,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x1f,0x18,0x18,0x18,
        0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
        0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff,
        0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,
        0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,
        0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00,
        0x00,0x00,0x76,0xdc,0xc8,0xdc,0x76,0x00,
        0x00,0x78,0xcc,0xf8,0xcc,0xf8,0xc0,0xc0,
        0x00,0xfc,0xcc,0xc0,0xc0,0xc0,0xc0,0x00,
        0x00,0xfe,0x6c,0x6c,0x6c,0x6c,0x6c,0x00,
        0xfc,0xcc,0x60,0x30,0x60,0xcc,0xfc,0x00,
        0x00,0x00,0x7e,0xd8,0xd8,0xd8,0x70,0x00,
        0x00,0x66,0x66,0x66,0x66,0x7c,0x60,0xc0,
        0x00,0x76,0xdc,0x18,0x18,0x18,0x18,0x00,
        0xfc,0x30,0x78,0xcc,0xcc,0x78,0x30,0xfc,
        0x38,0x6c,0xc6,0xfe,0xc6,0x6c,0x38,0x00,
        0x38,0x6c,0xc6,0xc6,0x6c,0x6c,0xee,0x00,
        0x1c,0x30,0x18,0x7c,0xcc,0xcc,0x78,0x00,
        0x00,0x00,0x7e,0xdb,0xdb,0x7e,0x00,0x00,
        0x06,0x0c,0x7e,0xdb,0xdb,0x7e,0x60,0xc0,
        0x38,0x60,0xc0,0xf8,0xc0,0x60,0x38,0x00,
        0x78,0xcc,0xcc,0xcc,0xcc,0xcc,0xcc,0x00,
        0x00,0xfc,0x00,0xfc,0x00,0xfc,0x00,0x00,
        0x30,0x30,0xfc,0x30,0x30,0x00,0xfc,0x00,
        0x60,0x30,0x18,0x30,0x60,0x00,0xfc,0x00,
        0x18,0x30,0x60,0x30,0x18,0x00,0xfc,0x00,
        0x0e,0x1b,0x1b,0x18,0x18,0x18,0x18,0x18,
        0x18,0x18,0x18,0x18,0x18,0xd8,0xd8,0x70,
        0x30,0x30,0x00,0xfc,0x00,0x30,0x30,0x00,
        0x00,0x76,0xdc,0x00,0x76,0xdc,0x00,0x00,
        0x38,0x6c,0x6c,0x38,0x00,0x00,0x00,0x00,
        0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00,
        0x00,0x00,0x00,0x00,0x18,0x00,0x00,0x00,
        0x0f,0x0c,0x0c,0x0c,0xec,0x6c,0x3c,0x1c,
        0x78,0x6c,0x6c,0x6c,0x6c,0x00,0x00,0x00,
        0x70,0x18,0x30,0x60,0x78,0x00,0x00,0x00,
        0x00,0x00,0x3c,0x3c,0x3c,0x3c,0x00,0x00,
        0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,
    };

static uint32 videoCursor = 0;
static uint16 * videoBuffer = 0;

void InitializeDisplay(uint16 * VideoBuffer)
{
    InitializeDisplayPowerDomains();

    videoBuffer = VideoBuffer;

    uint8 * DispCRegBase = (uint8 *)0x48050400;

    //
    // XXX code derived from TI diagnostic, tainted.
    //

    // xxx dss_clock_init

    //
    // disable dss
    //

    uint32 Value = ReadReg32(DispCRegBase + DISPC_CONTROL);
    Value &= ~(DISPC_CONTROL_DIGITALENABLE | DISPC_CONTROL_LCDENABLE);
    WriteReg32(DispCRegBase + DISPC_CONTROL, Value);

    //
    // Reset display controller
    //

    WriteReg32(DispCRegBase + DISPC_SYSCONFIG, DISPC_SYSCONFIG_SOFTRESET);

    while((ReadReg32(DispCRegBase + DISPC_SYSSTATUS) & DISPC_SYSSTATUS_RESETDONE) == 0);
    Value = ReadReg32(DispCRegBase + DISPC_SYSCONFIG);
    Value &= ~DISPC_SYSCONFIG_SOFTRESET;
    WriteReg32(DispCRegBase + DISPC_SYSCONFIG, Value);


    //
    // _ARM_WORKAROUND_ cheat and setup lcd power and backlight
    // earlier in HAL.  Right way to do this is with query interface
    // of the stack to get a control interface.
    //
    // XXX do triton thing here to enable lcd power, and thena  gpio that i don't understand
    // xxx gpio thing to enable backlight

    // configure dss

    WriteReg32(DispCRegBase + DISPC_SYSCONFIG,
               DISPC_SYSCONFIG_MIDLEMODE_NSTANDBY |
               DISPC_SYSCONFIG_SIDLEMODE_NIDLE);

    // disable interrupts
    WriteReg32(DispCRegBase + DISPC_IRQENABLE, 0);

    // 2:1 - Frame Data only loaded every frame (10)

    WriteReg32(DispCRegBase + DISPC_CONFIG,
               DISPC_CONFIG_LOADMODE_FRDATLEF);

    // Default Color is white
    WriteReg32(DispCRegBase + DISPC_DEFAULT_COLOR0,
               0xFFFFFF);

    // Default Transparency Color is black */
    WriteReg32(DispCRegBase + DISPC_TRANS_COLOR0, 0);

    // timing logic for HSYNC signal

    uint32 bp = (3 - 1);
    uint32 fp = (4 - 1);
    uint32 sw = (2 - 1);

    Value = (bp << DISPC_TIMING_H_HBP_SHIFT) | (fp << DISPC_TIMING_H_HFP_SHIFT) | (sw << DISPC_TIMING_H_HSW_SHIFT);
    WriteReg32(DispCRegBase + DISPC_TIMING_H, Value);

    // timing logic for VSYNC signal

    bp = 6;
    fp = 9;
    sw = 1;

    Value = (bp << DISPC_TIMING_V_VBP_SHIFT) | (fp << DISPC_TIMING_V_VFP_SHIFT) | (sw << DISPC_TIMING_V_VSW_SHIFT);
    WriteReg32(DispCRegBase + DISPC_TIMING_V, Value);

    // signal configuration
    WriteReg32(DispCRegBase + DISPC_POL_FREQ, 0);

    // configures the divisor
    Value = (1 << DISPC_DIVISOR_LCD_SHIFT) | (17 << DISPC_DIVISOR_PCD_SHIFT);
    WriteReg32(DispCRegBase + DISPC_DIVISOR, Value);

    // configure panel size
    WriteReg32(DispCRegBase + DISPC_SIZE_LCD,
               DISPC_SIZE_LCD_QVGA_PORTRAIT);

    // set lcd interface datalines
    // defaults to 16

    // Configure Graphics Window
    WriteReg32(DispCRegBase + DISPC_GFX_BA0, (uint32)VideoBuffer);
    WriteReg32(DispCRegBase + DISPC_GFX_BA1, (uint32)VideoBuffer);

    // set window position
    WriteReg32(DispCRegBase + DISPC_GFX_POSITION, 0);

    // set window size
    WriteReg32(DispCRegBase + DISPC_GFX_SIZE, DISPC_SIZE_QVGA_PORTRAIT);

    Value = ReadReg32(DispCRegBase + DISPC_GFX_ATTRIBUTES);
    Value |= DISPC_GFX_ATTRIBUTES_GFXFORMAT_RGB16;
    WriteReg32(DispCRegBase + DISPC_GFX_ATTRIBUTES, Value);

    Value= (252 << DISPC_GFX_FIFO_THRESHOLD_HIGH_SHIFT) | (192 << DISPC_GFX_FIFO_THRESHOLD_LOW_SHIFT);

    WriteReg32(DispCRegBase + DISPC_GFX_FIFO_THRESHOLD, Value);

    WriteReg32(DispCRegBase + DISPC_GFX_ROW_INC, 1);

    WriteReg32(DispCRegBase + DISPC_GFX_PIXEL_INC, 1);

    Value = ReadReg32(DispCRegBase + DISPC_GFX_ATTRIBUTES);
    Value |= DISPC_GFX_ATTRIBUTES_ENABLE;
    WriteReg32(DispCRegBase + DISPC_GFX_ATTRIBUTES, Value);

    // LCD output enabled, active display,16-bit output.
    Value = DISPC_CONTROL_GPOUT1 | DISPC_CONTROL_GPOUT0
        | DISPC_CONTROL_TFTDATALINES_OALSB16B | DISPC_CONTROL_STNTFT |
        DISPC_CONTROL_LCDENABLE;
    Value &= ~DISPC_CONTROL_RFBIMODE; // RFBI mode disabled.
    WriteReg32(DispCRegBase + DISPC_CONTROL, Value);

    Value = ReadReg32(DispCRegBase + DISPC_CONTROL);
    Value |= DISPC_CONTROL_GOLCD; // LCD GO command.
    WriteReg32(DispCRegBase + DISPC_CONTROL, Value);

    memset(VideoBuffer, 0xff, 240 * 320 * 2);
}

void Draw(uint8 c)
{
    if (videoBuffer == NULL) {
        return;
    }

    if (c == '\f') {
        videoCursor = 0;
        memset(videoBuffer, 0, 240 * 320 * 2);
        return;
    }
    else if (c == '\n') {
        videoCursor += 30 - (videoCursor % 30);
      check_scroll:
        while (videoCursor >= 30 * 40) {
            memmove(videoBuffer, videoBuffer + 240 * 8, 240 * 312 * 2);
            memset(videoBuffer + 312 * 240, 0, 240 * 16);    // 2 bytes/pixel * 8 pixels
            videoCursor -= 30;
        }
        return;
    }

    uint cy = (videoCursor / 30) * 8;
    uint cx = (videoCursor % 30) * 8;
    uint16 * buffer = videoBuffer + 240 * cy + cx;

    if (c == '\r') {
        uint toclear = 30 - (videoCursor % 30);

        for (uint y = 0; y < 8; y++) {
            memset(buffer, 0, toclear * 16);    // 2 bytes/pixel * 8 pixels
            buffer += 240;
        }
        videoCursor -= videoCursor % 30;
        return;
    }

    // Find the glyph.
    uint8 *pixels = Font8 + c * 8;

    // Draw the pixels.
    for (uint y = 0; y < 8; y++) {
        uint8 line = *pixels++;
        for (int x = 7; x >= 0; x--) {
            buffer[x] = (line & 1) ? 0xffff : 0x0000;
            line >>= 1;
        }
        buffer += 240;
    }
    videoCursor++;
    goto check_scroll;
}

void Draw(const char * str)
{
    for (int i = 0; i < 2048 && str[i] != '\0'; i++) {
        Draw((uint8)str[i]);
    }
}

//////////////////////////////////////////////////////////////////////////////

void DebugBreak();

void Halt()
{
    printf("Halt.");
    DebugBreak();
}

void Cls()
{
    BdPrintString("-------------------------------------------------------------------------------\n", 80);
    Draw('\f');
}

void __cdecl PutChar(char cOut)
{
    Draw(cOut);

    static CHAR szBuffer[256];
    static INT nBuffer = 0;

    szBuffer[nBuffer++] = cOut;
    if (cOut == '\n' || nBuffer >= sizeof(szBuffer) - 1) {
        BdPrintString(szBuffer, nBuffer);
        nBuffer = 0;
    }
}

void Probe(UINT8 * pbData, UINT cbData)
{
    UINT8 b;

    for (UINT i = 0; i < cbData; i++) {
        b = pbData[i];
        pbData[i] = b;
    }
}

void Dump(UINT8 * pbData, UINT cbData)
{
    for (UINT n = 0; n < cbData; n += 16) {
        printf("  %08x:", pbData + n);
        UINT o = n;
        for (; o < n + 16; o++) {
            if (o >= cbData) {
                printf("  ");
            }
            else {
                printf("%02x", pbData[o]);
            }
            if (o % 4 == 3) {
                printf(" ");
            }
        }
        printf(" ");
        for (o = n; o < n + 16; o++) {
            if (o >= cbData) {
                printf("  ");
            }
            else {
                if (pbData[o] >= ' ' && pbData[o] < 127) {
                    printf("%c", pbData[o]);
                }
                else {
                    printf(".");
                }
            }
        }
        printf("\n");
    }
}

void Dump(UINT8 * pbData, UINT8 * pbLimit, UINT cbMax)
{
    UINT cbData = (uint) (pbLimit - pbData);
    if (cbData > cbMax) {
        cbData = cbMax;
    }
    Dump(pbData, cbData);
}

static void CopyDown(UINT8 *pbDst, UINT8 *pbSrc, UINT32 cbSrc)
{
    //!!! pbDst <= pbSrc
    if (pbDst > pbSrc) {
        printf("CopyDown(dst=%p > src=%p)\n", pbDst, pbSrc);
        Halt();
    }

    INT32 nSrc = (cbSrc + 3) / 4;
    volatile UINT32 *pDst = (UINT32*)pbDst;
    volatile UINT32 *pSrc = (UINT32*)pbSrc;

    while (nSrc-- > 0) {
        *pDst = *pSrc;
        if (*pDst != *pSrc) {
            printf("CopyDown error at %p/%p : %08x != %08x\n",
                   pDst, pSrc, *pDst, *pSrc);
            Halt();
        }
        pDst++;
        pSrc++;
    }
}

static void Zero(uint8 * pbData, uint32 cbData)
{
    INT32 nDst = (cbData + 3) / 4;
    volatile UINT32 *pDst = (UINT32*)pbData;

    while (nDst-- > 0) {
        *pDst++ = 0;
    }
}

const char * SmapTypeToString(int type)
{
    switch (type) {
      case 1: return "RAM     ";
      case 2: return "Reserved";
      case 3: return "ACPI RAM";
      case 4: return "ACPI NVS";
      default: return "Other   ";
    }
}

bool check(UINT8 *pbCache, UINT8 value, const char *pszDesc)
{
    for (int i = 0; i < 16; i++) {
        if (pbCache[i] == value) {
            pbCache[i] = 0;
            printf("      %s\n", pszDesc);
            return 1;
        }
    }
    return 0;
}

static bool CheckSmapForRam(const Class_Microsoft_Singularity_Hal_Platform *bi, UINT64 base, UINT64 size)
{
    Struct_Microsoft_Singularity_SMAPINFO *sm = (Struct_Microsoft_Singularity_SMAPINFO *) bi->Smap32;
    for (int32 i = 0; i < bi->SmapCount; i++) {
        if (sm[i].type == 1 &&
            sm[i].addr <= base &&
            sm[i].addr + sm[i].size >= base + size) {

            return true;
        }
    }
    return false;
}

static void CheckSmap(const Class_Microsoft_Singularity_Hal_Platform *bi)
{
    /////////////////////////////////////////////////////// System Memory Map.
    //
    printf(" BaseAddr LimtAddr Type      \n");
    printf(" ======== ======== ========== [%8x]\n", bi->Smap32);

    Struct_Microsoft_Singularity_SMAPINFO *sm = (Struct_Microsoft_Singularity_SMAPINFO *) bi->Smap32;
    for (int32 i = 0; i < bi->SmapCount; i++) {
        printf(" %8x", (UINT32)(sm[i].addr));
        printf(" %8x", (UINT32)(sm[i].addr + sm[i].size));
        printf(" %d:%s\n",
               sm[i].type,
               SmapTypeToString((int)sm[i].type));
    }
    printf("\n");
}

void SortSmap(const Class_Microsoft_Singularity_Hal_Platform *bi)
{
    Struct_Microsoft_Singularity_SMAPINFO *sm = (Struct_Microsoft_Singularity_SMAPINFO *) bi->Smap32;
    // Sort the system memory map.
  sortagain:
    for (int i = 0; i < bi->SmapCount - 1; i++) {
        if ((sm[i].addr > sm[i + 1].addr) ||
            (sm[i].addr == sm[i + 1].addr &&
             sm[i].addr > sm[i + 1].addr)) {

            Struct_Microsoft_Singularity_SMAPINFO s = sm[i];
            sm[i] = sm[i+1];
            sm[i+1] = s;

            goto sortagain;
        }
    }
}

static uintptr g_Entry = 0;
static uintptr g_Stack = 0;
static Class_Microsoft_Singularity_Hal_Platform  *g_bi = 0;
static Class_Microsoft_Singularity_Hal_Cpu *g_ci = 0;

//////////////////////////////////////////////////////////////////////////////

static bool memeq(const uint8 * p1, const uint8 * p2, uint size)
{
    for (; size > 0; size--) {
        if (*p1++ != *p2++) {
            return false;
        }
    }
    return true;
}

struct FlashHead
{
    uint8   label[18];
    uint8   headSize;
    uint8   fileSize;
    uint32  pageSize;
    uint32  majorVersion;
    uint32  minorVersion;
};

struct FlashFile
{
    uint32  pathOffset;
    uint32  dataOffset;
    uint32  size;
};

uintptr FindFlashImage(uintptr begin, uintptr limit)
{
    // Round begin and limit to nearest valid addresses.
    begin = (begin + 0xffff) & ~(uintptr)0xffff;
    limit = (limit + 0xffff) & ~(uintptr)0xffff;

    // walk through at 64KB boundaries looking for flash image.
    for (; begin < limit ; begin += 0x10000) {
        const FlashHead * head = (const FlashHead *)begin;
        if (!memeq(head->label, (uint8*)"SingularityFlash!", sizeof(head->label))) {
            continue;
        }
        if (head->headSize != sizeof(FlashHead)) {
            continue;
        }
        if (head->fileSize != sizeof(FlashFile)) {
            continue;
        }
        if (head->majorVersion != ~0u || head->minorVersion != ~0u) {
            continue;
        }
        if (head->pageSize != 0x1000) {
            continue;
        }

        // Header values all check out, now look at image content.

        const FlashFile *file = (FlashFile*)(head + 1);
        const FlashFile *fend = file + 8192;
        for (; file < fend; file++) {
            if ((file->dataOffset == 0xffffffff && file->size == 0xffffffff) ||
                (file->dataOffset == 0 && file->size == 0)) {
                continue;
            }
            else if (file->dataOffset == 0xffffffff && file->size == 0) {
                return begin;
            }
            else if ((file->dataOffset & 0xfff) != 0) {
                // file has unaligned offset.
                printf("Unaligned offset: %x\n", file);
                break;
            }
        }
    }
    return 0;
}

uintptr SizeFlashImage(uintptr begin, uint& count)
{
    uintptr limit = 0;
    count = 0;

    const FlashHead * head = (const FlashHead *)begin;
    const FlashFile *file = (FlashFile*)(head + 1);

    // Assumes that there is always at least one valid file in the flash.
    for (;; file++) {
        if ((file->dataOffset == 0xffffffff && file->size == 0xffffffff) ||
            (file->dataOffset == 0 && file->size == 0)) {
            continue;
        }
        else if (file->dataOffset == 0xffffffff && file->size == 0) {
            break;
        }

        if (limit < file->dataOffset + file->size) {
            limit = file->dataOffset + file->size;
        }
        count++;
    }

    return ((limit + 0xfff) & ~0xfff);
}

void ProcessFlashImage(uintptr begin,
                       Struct_Microsoft_Singularity_Io_FileImage *files, uint count)
{
    const FlashHead * head = (const FlashHead *)begin;
    const FlashFile *file = (FlashFile*)(head + 1);

    // Assumes that there is always at least one valid file in the flash.
    for (uint item = 0;; file++) {
        if ((file->dataOffset == 0xffffffff && file->size == 0xffffffff) ||
            (file->dataOffset == 0 && file->size == 0)) {
            continue;
        }
        else if (file->dataOffset == 0xffffffff && file->size == 0) {
            break;
        }

        if (item < count) {
            files[item].Address = begin + file->dataOffset;
            files[item].Size = file->size;
            item++;
        }
    }
}

//////////////////////////////////////////////////////////////////////////////
//

extern uintptr GetStack(void);
extern uintptr GetCode(void);
extern uint32 GetMidr(void);
extern uint32 GetPfr0(void);
extern uint32 GetPfr1(void);
extern uintptr GetVbar(void);
extern void SetVbar(uintptr);
extern void SetTpidrurw(uintptr);

uint MpStartupLock = 0;

int BootPhase1(void)
{
    HalpClocksInitialize();
    HalpGpioInitialize();
    HalpI2CMasterInitialize();

    BdInitDebugger(BdPortInit((uint32 *)OMAP_UART1_BASE, 115200));
    printf("\f\n\rSingularity ARM Boot Loader [" __DATE__ " "__TIME__ "]\n\r");

    InitializeDisplay((uint16 *)ON_OMAP3430_VIDEO_ADDR);
    Draw("\fSingularity ARM Boot Loader\n[" __DATE__ " "__TIME__ "]\n\r");

    uintptr base;
    uintptr size = SizeOfPeImage((uintptr)ON_OMAP3430_LOADER_ADDR, base);

    ASSERT(size <= ON_OMAP3430_LOADER_SIZE);

    // Find out what kind of processor we're running on.
    uint32 midr = GetMidr();
    switch ((midr & 0xff000000) >> 24) {
      case 0x41: printf("ARM Ltd "); break;
      case 0x44: printf("DEC "); break;
      case 0x4d: printf("Motorola "); break;
      case 0x51: printf("Qualcomm "); break;
      case 0x56: printf("Marvell "); break;
      case 0x69: printf("Intel "); break;
      default: printf("Implementor? ");

    }
    switch ((midr & 0xf0000) >> 16) {
      case 0x01: printf("ARMv4 "); break;
      case 0x02: printf("ARMv4T "); break;
      case 0x03: printf("ARMv5 "); break;
      case 0x04: printf("ARMv5T "); break;
      case 0x05: printf("ARMv5TE "); break;
      case 0x06: printf("ARMv5TEJ "); break;
      case 0x07: printf("ARMv6 "); break;
      case 0x0f: printf("ARMv7 "); break;
      default: printf("Variant? "); break;
    }
    printf("%x.%x\n", (midr & 0xfff0) >> 4, midr & 0xf);

    if ((midr & 0xf0000) == 0xf0000) {
        // ARMv7, Used CPUID scheme.
        printf("PFR: 0:%08x, 1:%08x\n", GetPfr0(), GetPfr1());
    }
    printf("\n");

    //
    // Get the BIOS info
    //
    g_bi = (Class_Microsoft_Singularity_Hal_Platform *)
        alloc(sizeof(Class_Microsoft_Singularity_Hal_Platform));
    g_bi->Size = sizeof(Class_Microsoft_Singularity_Hal_Platform);

    //
    // Save the debug information.
    //
    g_bi->DebugBasePort = OMAP_UART1_BASE;

    //
    // Set up Memory Map
    //
    Struct_Microsoft_Singularity_SMAPINFO *sm =
        (Struct_Microsoft_Singularity_SMAPINFO *)
        alloc(sizeof(Struct_Microsoft_Singularity_SMAPINFO) * 32);

    g_bi->Smap32 = (uintptr)sm;

    // Remember loader.
    sm[0].type = Struct_Microsoft_Singularity_SMAPINFO_AddressTypeReserved;
    sm[0].addr = ON_OMAP3430_LOADER_ADDR;
    sm[0].size = SizeOfPeImage((uintptr)ON_OMAP3430_LOADER_ADDR, base);

    // Remember other low reserved.
    sm[1].type = Struct_Microsoft_Singularity_SMAPINFO_AddressTypeReserved;
    sm[1].addr = ON_OMAP3430_RESERVE_ADDR + sm[0].size;
    sm[1].size = ON_OMAP3430_RESERVE_SIZE - (sm[1].addr - ON_OMAP3430_RESERVE_ADDR);

    // Remember RAM.
    sm[2].type = Struct_Microsoft_Singularity_SMAPINFO_AddressTypeFree;
    sm[2].addr = ON_OMAP3430_STACK_ADDR;
    sm[2].size = ON_OMAP3430_MEMORY_SIZE - (ON_OMAP3430_STACK_ADDR - ON_OMAP3430_MEMORY_ADDR);

    // Mark off I/O memory
    sm[3].type = Struct_Microsoft_Singularity_SMAPINFO_AddressTypeUnusable;
    sm[3].addr = 0;
    sm[3].size = 0x80000000;

    g_bi->SmapCount = 4;

    //
    // Register the boot memory that we use to allocated classes
    // that will be converted into managed classes once the kernel
    // initializes. This is so it can be properly reported to the
    // GC.
    //
    // Record the entire boot memory range so that the kernel does
    // not use it for working memory
    //
    g_bi->BootAllocatedMemory = 0;
    g_bi->BootAllocatedMemorySize = 0x00400000; // Leave this as a guess of memory usage

    g_bi->CpuRealCount = 1;
    g_bi->CpuMaxCount = 1;
    g_bi->BootCount = 0;

    g_bi->LogRecordBuffer   = ON_OMAP3430_LOGBUF_ADDR; // See Platform.cs
    g_bi->LogRecordSize     = ON_OMAP3430_LOGBUF_SIZE;
    g_bi->LogTextBuffer     = ON_OMAP3430_LOGTXT_ADDR;
    g_bi->LogTextSize       = ON_OMAP3430_LOGTXT_SIZE;
    g_bi->KernelDllFirstPage=
    g_bi->KernelDllBase     = ON_OMAP3430_KERNEL_ADDR;
    g_bi->PhysicalBase      = 0x00010000;

    //
    // NOTE: The singldr should edit the SMAP to not include memory
    //       allocated to the kernel, its stacks, etc, similar to busying
    //       out the dump record.
    //
    //       This would be a cleaner communication than the current
    //       combination of SMAP's, kernel base etc.
    //
    //       There has been discussion of a modified version of SMAP that
    //       is communicated to the kernel that describes how memory has
    //       been used. SMAP describes general memory information, while
    //       the kernel needs to know how memory taken from the SMAP was
    //       used. This is important for the kernel to build its GC
    //       structures that track which pages contain GC objects.
    //

    g_bi->CpuMaxCount = 1;

    g_ci = (Class_Microsoft_Singularity_Hal_Cpu *)
        alloc(sizeof(Class_Microsoft_Singularity_Hal_Cpu) * 1);
    g_bi->Cpus = (uintptr)g_ci;
    g_ci->Size = sizeof(Class_Microsoft_Singularity_Hal_Cpu);
    g_ci->Id = 0;
    g_ci->KernelStackLimit = ON_OMAP3430_STACK_ADDR; // See also Platform.cs
    g_ci->KernelStackBegin = ON_OMAP3430_STACK_ADDR + ON_OMAP3430_STACK_SIZE;

    // Default to the Serial debugger
    g_bi->DebuggerType = Class_Microsoft_Singularity_Hal_Platform_DEBUGGER_SERIAL;

    g_bi->CommandLine32 = 0;
    g_bi->CommandLineCount = 0;

    printf("\n");

#if 0
    //
    // Drop SMAP entries above supported limit
    //
    for (int i = 0; i < g_bi->SmapCount; i++) {
        if (sm[i].type != Struct_Microsoft_Singularity_SMAPINFO_AddressTypeFree) {
            continue;
        }

        if ((sm[i].addr != 0ul) ||
            (sm[i].addr >= Class_Microsoft_Singularity_Hal_Platform_MAX_VIRTUAL_ADDR)) {
            sm[i] = sm[--g_bi->SmapCount];
        }
        else if (sm[i].addr + sm[i].size >= Class_Microsoft_Singularity_Hal_Platform_MAX_VIRTUAL_ADDR) {
            sm[i].size = Class_Microsoft_Singularity_Hal_Platform_MAX_VIRTUAL_ADDR - sm[i].addr;
        }
    }
#endif

    // Sort the system memory map.
    SortSmap(g_bi);

    //
    // Make a reasonable guess at the size of physical memory.
    //
    uint32 memoryKB = 0;
    for (int i = 0; i < g_bi->SmapCount; i++) {
        if (sm[i].type == Struct_Microsoft_Singularity_SMAPINFO_AddressTypeFree) {
            memoryKB += (uint32)(sm[i].size / 1024);
        }
    }
    printf("Physical memory: %uMB\n", memoryKB / 1024);

    CheckSmap(g_bi);

    //
    // Find the flash image.
    //
    uintptr flash = 0;
    for (int i = 0; i < g_bi->SmapCount && flash == 0; i++) {
        if (sm[i].type == Struct_Microsoft_Singularity_SMAPINFO_AddressTypeFree ||
            sm[i].type == Struct_Microsoft_Singularity_SMAPINFO_AddressTypeReserved) {

            flash = FindFlashImage((uintptr)sm[i].addr,
                                   (uintptr)(sm[i].addr + sm[i].size));
        }
    }

    if (flash == 0) {
        printf("No valid flash image.\n");
        Halt();
    }

    //
    // Count the flash files and size the image.
    //
    uint nMaxImages = 0;
    g_bi->DumpAddr32 = flash;
    g_bi->DumpSize32 = SizeFlashImage(flash, nMaxImages);
    printf("Flash: %08x..%08x.\n",
           (uint32)g_bi->DumpAddr32,
           (uint32)(g_bi->DumpAddr32 + g_bi->DumpSize32));
    printf("Flash has %d files.\n", nMaxImages);

    //
    // Remember the flash files.
    //
    Struct_Microsoft_Singularity_Io_FileImage * files =
        (Struct_Microsoft_Singularity_Io_FileImage *)
        alloc(sizeof(Struct_Microsoft_Singularity_Io_FileImage) * nMaxImages);

    ProcessFlashImage(flash, files, nMaxImages);
    g_bi->FileImageTableBase32 = (uintptr)files;
    g_bi->FileImageTableEntries = nMaxImages;

#if LIEABOUTSMAP
    printf("\n");
    printf("Editing the SMAP to protect the dump area...\n");

    for (i = 0; i < g_bi->SmapCount; i++) {
        // Does this region straddle the start of the dump area?
        // if so, truncate it
        if (sm[i].type == 1 &&
            sm[i].addr < g_bi->DumpAddr32 &&
            sm[i].addr + sm[i].size > g_bi->DumpAddr32) {

            sm[i].size = g_bi->DumpAddr32 - sm[i].addr;
            printf("  %08x..%08x %d (truncated)\n",
                   (uint32)(sm[i].addr),
                   (uint32)(sm[i].addr + sm[i].size),
                   sm[i].type);
        }

        if (sm[i].type == 1 &&
            sm[i].addr >= g_bi->DumpAddr32) {

            sm[i].type = 2; // Arbitrary non-free value
            printf("  %08x..%08x %d (marked unavailable)\n",
                   (uint32)(sm[i].addr),
                   (uint32)(sm[i].addr + sm[i].size),
                   sm[i].type);
        }
    }
    // Sort the system memory map.
    SortSmap(g_bi);
#endif

    uintptr kernelBase;
    g_bi->KernelDllSize = SizeOfPeImage(files[0].Address, kernelBase);
    printf("Kernel: %08x..%08x\n",
           g_bi->KernelDllBase,
           g_bi->KernelDllBase + g_bi->KernelDllSize);

    uintptr kernelEntry = ExpandPeImage(g_bi->KernelDllBase, files[0].Address);
    printf("Kernel Entry: %08x\n", kernelEntry);

    //
    g_bi->MpCpuCount         = 0;
    g_bi->MpStartupLock32 = (uintptr)&MpStartupLock;

    //printf("MpStartupLock32* %x, value %x\n", g_bi->MpStartupLock32, MpStartupLock);

    //
    // Set the offset to the context pointers, which are the
    // first two pointer words allocated in the page.
    //
    //
    // Allocate pages for commonly referenced data
    //

    uint8 * cpuRecord = (uint8 *)allocpages(2);

    //
    // Set the offset to the context pointers, which are the
    // first two pointer words allocated in the page.
    //
    g_bi->CpuRecordPointerOffset = 0 * sizeof(uintptr);
    g_bi->ThreadRecordPointerOffset = 1 * sizeof(uintptr);

    //
    // Set the DS relative address to the ProcessorContext
    //
    // Set our base for storing our actual X86.ProcessorContext
    //
    SetTpidrurw((uintptr)cpuRecord);

    // Align CpuRecord to 16-bytes after CpuRecord & ThreadRecord pointers.
    g_ci->CpuRecordPage = (uint32)cpuRecord + 16;

    g_bi->MiniDumpBase = (uintptr)g_bi->DumpAddr32;
    g_bi->MiniDumpLimit = g_bi->MiniDumpBase + ((g_bi->DumpSize32 + 0xffff) & 0xffff0000);

    //
    // Move to next phase
    //
    Class_Microsoft_Singularity_Hal_Platform  *bi = g_bi;
    Class_Microsoft_Singularity_Hal_Cpu *ci = g_ci;
    void (* pfHal)(void *, void *) = (void (*)(void *, void *))kernelEntry;

    g_bi->IsaCsns = (uint32)videoBuffer;
    g_bi->IsaReadPort = videoCursor;
    g_bi->KillAction = 0xffff;

    pfHal((void*)g_bi, (void*)g_ci);

    videoCursor = g_bi->IsaReadPort;

    printf("\n");
    printf("Kernel exited: %04x\n", g_bi->KillAction);
    g_bi->BootCount++;

    Halt();
    for(;;);
}

extern "C" unsigned __int64 __rt_udiv64by64( unsigned __int64 x, unsigned __int64 y)
{
    unsigned __int64 q = 0;
    unsigned __int64 mask = 1;
    if (y == 0) {
        return (unsigned __int64)-1;
    }

    while (y <= x) {
        if (y & 0x8000000000000000) {
            x -= y;
            q += mask;
            break;
        }
        mask <<= 1;
        y <<= 1;
    }

    while (mask !=0) {
        if (y <= x) {
            q += mask;
            x -= y;
        }
        y >>= 1;
        mask >>= 1;
    }

    return q;
}
