summaryrefslogtreecommitdiffstats
path: root/private/ntos/fw/mips
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/fw/mips
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to '')
-rw-r--r--private/ntos/fw/mips/arceisa.h547
-rw-r--r--private/ntos/fw/mips/bmp.c164
-rw-r--r--private/ntos/fw/mips/confsub.s51
-rw-r--r--private/ntos/fw/mips/conftest.c965
-rw-r--r--private/ntos/fw/mips/d4reset.s3046
-rw-r--r--private/ntos/fw/mips/debug.c119
-rw-r--r--private/ntos/fw/mips/debug.h7
-rw-r--r--private/ntos/fw/mips/dmaregs.h207
-rw-r--r--private/ntos/fw/mips/duosync.c516
-rw-r--r--private/ntos/fw/mips/eisafunc.c680
-rw-r--r--private/ntos/fw/mips/eisaini.c3195
-rw-r--r--private/ntos/fw/mips/eisaintr.c298
-rw-r--r--private/ntos/fw/mips/eisamisc.c213
-rw-r--r--private/ntos/fw/mips/eisapod.c3675
-rw-r--r--private/ntos/fw/mips/eisastr.h37
-rw-r--r--private/ntos/fw/mips/eisausa.c99
-rw-r--r--private/ntos/fw/mips/fwentry.c57
-rw-r--r--private/ntos/fw/mips/fwio.c1327
-rw-r--r--private/ntos/fw/mips/fwload.c1043
-rw-r--r--private/ntos/fw/mips/fwp.h659
-rw-r--r--private/ntos/fw/mips/fwprint.c84
-rw-r--r--private/ntos/fw/mips/fwsignal.c617
-rw-r--r--private/ntos/fw/mips/fwstring.h131
-rw-r--r--private/ntos/fw/mips/fwtime.c172
-rw-r--r--private/ntos/fw/mips/fwtrap.s655
-rw-r--r--private/ntos/fw/mips/fwusa.c209
-rw-r--r--private/ntos/fw/mips/inc.h883
-rw-r--r--private/ntos/fw/mips/ioaccess.h79
-rw-r--r--private/ntos/fw/mips/ioaccess.s119
-rw-r--r--private/ntos/fw/mips/iodevice.h376
-rw-r--r--private/ntos/fw/mips/j3inter.s372
-rw-r--r--private/ntos/fw/mips/j3reset.s1818
-rw-r--r--private/ntos/fw/mips/j3trap.s288
-rw-r--r--private/ntos/fw/mips/j4cache.s669
-rw-r--r--private/ntos/fw/mips/j4inter.s514
-rw-r--r--private/ntos/fw/mips/j4reset.h115
-rw-r--r--private/ntos/fw/mips/j4reset.s2598
-rw-r--r--private/ntos/fw/mips/j4start.s756
-rw-r--r--private/ntos/fw/mips/jazzg364.c336
-rw-r--r--private/ntos/fw/mips/jg364h.s60
-rw-r--r--private/ntos/fw/mips/jxbmp.c129
-rw-r--r--private/ntos/fw/mips/jxboot.c1137
-rw-r--r--private/ntos/fw/mips/jxconfig.c1956
-rw-r--r--private/ntos/fw/mips/jxdisp.c2158
-rw-r--r--private/ntos/fw/mips/jxenvir.c502
-rw-r--r--private/ntos/fw/mips/jxfboot.c2057
-rw-r--r--private/ntos/fw/mips/jxfont.s3126
-rw-r--r--private/ntos/fw/mips/jxfwhal.h94
-rw-r--r--private/ntos/fw/mips/jxhwsup.c1512
-rw-r--r--private/ntos/fw/mips/jxkbd.c491
-rw-r--r--private/ntos/fw/mips/jxmemory.c397
-rw-r--r--private/ntos/fw/mips/jxport.c401
-rw-r--r--private/ntos/fw/mips/jxreboot.c403
-rw-r--r--private/ntos/fw/mips/jxserial.c566
-rw-r--r--private/ntos/fw/mips/jxsysid.c144
-rw-r--r--private/ntos/fw/mips/jxvendor.c195
-rw-r--r--private/ntos/fw/mips/jxvideo.c337
-rw-r--r--private/ntos/fw/mips/jxvideo.h158
-rw-r--r--private/ntos/fw/mips/jzboot.c1201
-rw-r--r--private/ntos/fw/mips/jzcommon.c876
-rw-r--r--private/ntos/fw/mips/jzconfig.c1613
-rw-r--r--private/ntos/fw/mips/jzenvir.c381
-rw-r--r--private/ntos/fw/mips/jzether.c158
-rw-r--r--private/ntos/fw/mips/jzgetpar.c690
-rw-r--r--private/ntos/fw/mips/jzmake.c496
-rw-r--r--private/ntos/fw/mips/jzsetup.c307
-rw-r--r--private/ntos/fw/mips/jzsetup.h154
-rw-r--r--private/ntos/fw/mips/jzstring.h102
-rw-r--r--private/ntos/fw/mips/jzstubs.c36
-rw-r--r--private/ntos/fw/mips/jztime.c415
-rw-r--r--private/ntos/fw/mips/jzusa.c173
-rw-r--r--private/ntos/fw/mips/jzvxl484.c724
-rw-r--r--private/ntos/fw/mips/jzvxlh.s61
-rw-r--r--private/ntos/fw/mips/kbdmouse.h149
-rw-r--r--private/ntos/fw/mips/kbdtest.c317
-rw-r--r--private/ntos/fw/mips/led.h127
-rw-r--r--private/ntos/fw/mips/linkj4fw.rsp79
-rw-r--r--private/ntos/fw/mips/linkj4rs.rsp9
-rw-r--r--private/ntos/fw/mips/linkj4sy.rsp75
-rw-r--r--private/ntos/fw/mips/linkset.rsp21
-rw-r--r--private/ntos/fw/mips/lk364h.rsp7
-rw-r--r--private/ntos/fw/mips/lk364rom.rsp9
-rw-r--r--private/ntos/fw/mips/lkvxlh.rsp7
-rw-r--r--private/ntos/fw/mips/lkvxlrom.rsp10
-rw-r--r--private/ntos/fw/mips/memtest.s926
-rw-r--r--private/ntos/fw/mips/mg364h.s60
-rw-r--r--private/ntos/fw/mips/monitor.c1499
-rw-r--r--private/ntos/fw/mips/monitor.h159
-rw-r--r--private/ntos/fw/mips/oli2msft.h39
-rw-r--r--private/ntos/fw/mips/omf.c3791
-rw-r--r--private/ntos/fw/mips/pldfont.c178
-rw-r--r--private/ntos/fw/mips/rlefont.c5342
-rw-r--r--private/ntos/fw/mips/scsiport.c4927
-rw-r--r--private/ntos/fw/mips/selfmap.h335
-rw-r--r--private/ntos/fw/mips/selftest.c2519
-rw-r--r--private/ntos/fw/mips/selftest.h224
-rw-r--r--private/ntos/fw/mips/sonictst.c822
-rw-r--r--private/ntos/fw/mips/sonictst.h246
-rw-r--r--private/ntos/fw/mips/stubs.c395
-rw-r--r--private/ntos/fw/mips/subrout.s63
-rw-r--r--private/ntos/fw/mips/x4trap.s1068
-rw-r--r--private/ntos/fw/mips/xxfonts.c1661
-rw-r--r--private/ntos/fw/mips/xxirql.s89
-rw-r--r--private/ntos/fw/mips/xxldfont.c267
104 files changed, 76326 insertions, 0 deletions
diff --git a/private/ntos/fw/mips/arceisa.h b/private/ntos/fw/mips/arceisa.h
new file mode 100644
index 000000000..df162ec7a
--- /dev/null
+++ b/private/ntos/fw/mips/arceisa.h
@@ -0,0 +1,547 @@
+// -----------------------------------------------------------------------------
+//
+// Copyright (c) 1992 Olivetti
+//
+// File: arceisa.h
+//
+// Description: ARC-EISA Addendum Structures and Defines.
+//
+// -----------------------------------------------------------------------------
+
+
+//
+// Define the EISA firmware entry points
+//
+
+typedef enum _EISA_FIRMWARE_ENTRY
+ {
+ ProcessEOIRoutine,
+ TestIntRoutine,
+ RequestDMARoutine,
+ AbortDMARoutine,
+ GetDMAStatusRoutine,
+ DoLockRoutine,
+ RequestBusMasterRoutine,
+ ReleaseBusMasterRoutine,
+ RequestCpuAccessToBusRoutine,
+ ReleaseCpuAccessToBusRoutine,
+ FlushCacheRoutine,
+ InvalidateCacheRoutine,
+ ReservedRoutine,
+ BeginCriticalSectionRoutine,
+ EndCriticalSectionRoutine,
+ GenerateToneRoutine,
+ FlushWriteBuffersRoutine,
+ YieldRoutine,
+ StallProcessorRoutine,
+ MaximumEisaRoutine
+ } EISA_FIRMWARE_ENTRY;
+
+
+//
+// Define EISA interrupt functions
+//
+
+typedef
+ARC_STATUS
+(*PEISA_PROCESS_EOI_RTN)
+ (
+ IN ULONG BusNumber,
+ IN USHORT IRQ
+ );
+
+typedef
+BOOLEAN_ULONG
+(*PEISA_TEST_INT_RTN)
+ (
+ IN ULONG BusNumber,
+ IN USHORT IRQ
+ );
+
+//
+// Define EISA DMA functions
+//
+
+typedef enum _DMA_TRANSFER_TYPE
+ {
+ DmaVerify,
+ DmaWrite,
+ DmaRead,
+ DmaMaxType
+ } DMA_TRANSFER_TYPE, *PDMA_TRANSFER_TYPE;
+
+typedef enum _DMA_TRANSFER_MODE
+ {
+ DmaDemand,
+ DmaSingle,
+ DmaBlock,
+ DmaCascade,
+ DmaMaxMode
+ } DMA_TRANSFER_MODE, *PDMA_TRANSFER_MODE;
+
+typedef enum _DMA_TIMING_MODE
+ {
+ DmaIsaCompatible,
+ DmaTypeA,
+ DmaTypeB,
+ DmaBurst,
+ DmaMaxTiming
+ } DMA_TIMING_MODE, *PDMA_TIMING_MODE;
+
+typedef enum _DMA_ADDRESSING_MODE
+ {
+ Dma8Bit,
+ Dma16sBit,
+ Dma32Bit,
+ Dma16Bit,
+ DmaMaxAddressing
+ } DMA_ADDRESSING_MODE, *PDMA_ADDRESSING_MODE;
+
+typedef struct _DMA_TRANSFER
+ {
+ DMA_TRANSFER_MODE TransferMode;
+ ULONG ChannelNumber;
+ DMA_TRANSFER_TYPE TransferType;
+ ULONG Size;
+ PVOID Buffer;
+ } DMA_TRANSFER, *PDMA_TRANSFER;
+
+typedef struct _DMA_STATUS
+ {
+ BOOLEAN_ULONG CompleteTransfer;
+ ULONG ByteTransferred;
+ } DMA_STATUS, *PDMA_STATUS;
+
+typedef
+ARC_STATUS
+(*PEISA_REQ_DMA_XFER_RTN)
+ (
+ IN ULONG BusNumber,
+ IN PDMA_TRANSFER pDmaTransfer
+ );
+
+typedef
+ARC_STATUS
+(*PEISA_ABORT_DMA_RTN)
+ (
+ IN ULONG BusNumber,
+ IN PDMA_TRANSFER pDmaTransfer
+ );
+
+typedef
+ARC_STATUS
+(*PEISA_DMA_XFER_STATUS_RTN)
+ (
+ IN ULONG BusNumber,
+ IN PDMA_TRANSFER pDmaTransfer,
+ OUT PDMA_STATUS pDmaStatus
+ );
+
+//
+// Define EISA lock function
+//
+
+typedef enum _EISA_LOCK_OPERATION
+ {
+ Exchange,
+ LockMaxOperation
+ } EISA_LOCK_OPERATION;
+
+
+typedef enum _SEMAPHORE_SIZE
+ {
+ ByteSemaphore,
+ HalfWordSemaphore,
+ WordSemaphore,
+ MaxSemaphore
+ } SEMAPHORE_SIZE;
+
+typedef
+ARC_STATUS
+(*PEISA_LOCK_RTN)
+ (
+ IN ULONG BusNumber,
+ IN EISA_LOCK_OPERATION Operation,
+ IN PVOID Semaphore,
+ IN SEMAPHORE_SIZE SemaphoreSize,
+ IN PVOID OperationArgument,
+ OUT PVOID OperationResult
+ );
+
+//
+// Define EISA bus master functions.
+//
+
+typedef enum _BUS_MASTER_TRANSFER_TYPE
+ {
+ BusMasterWrite,
+ BusMasterRead,
+ BusMasterMaxType
+ } BUS_MASTER_TRANSFER_TYPE, *PBUS_MASTER_TRANSFER_TYPE;
+
+typedef enum _ADDRESS_RESTRICTION
+ {
+ LimitNone,
+ Limit16Mb,
+ Limit4Gb,
+ LimitMax
+ } ADDRESS_RESTRICTION, *PADDRESS_RESTRICTION;
+
+typedef struct _BUS_MASTER_TRANSFER
+ {
+ ADDRESS_RESTRICTION Limit;
+ ULONG SlotNumber;
+ BUS_MASTER_TRANSFER_TYPE TransferType;
+ ULONG Size;
+ PVOID Buffer;
+ } BUS_MASTER_TRANSFER, *PBUS_MASTER_TRANSFER;
+
+typedef
+ARC_STATUS
+(*PEISA_REQUEST_BUS_MASTER_RTN)
+ (
+ IN ULONG BusNumber,
+ IN PBUS_MASTER_TRANSFER pBusMasterTransfer,
+ OUT ULONG *TranslateBufferAddress
+ );
+
+typedef
+ARC_STATUS
+(*PEISA_RELEASE_BUS_MASTER_RTN)
+ (
+ IN ULONG BusNumber,
+ IN PBUS_MASTER_TRANSFER pBusMasterTransfer,
+ IN ULONG TranslateBufferAddress
+ );
+
+//
+// Define EISA slave functions
+//
+
+typedef struct _SLAVE_TRANSFER
+ {
+ ULONG SlotNumber;
+ ULONG Size;
+ ULONG Buffer;
+ } SLAVE_TRANSFER, *PSLAVE_TRANSFER;
+
+typedef
+ARC_STATUS
+(*PEISA_REQUEST_CPU_TO_BUS_ACCESS_RTN)
+ (
+ IN ULONG BusNumber,
+ IN PSLAVE_TRANSFER pSlaveTransfer,
+ OUT PVOID *TranslatedBufferAddress
+ );
+
+typedef
+ARC_STATUS
+(*PEISA_RELEASE_CPU_TO_BUS_ACCESS_RTN)
+ (
+ IN ULONG BusNumber,
+ IN PSLAVE_TRANSFER pSlaveTransfer,
+ IN PVOID TranslateBufferAddress
+ );
+
+typedef
+VOID
+(*PEISA_FLUSH_CACHE_RTN)
+ (
+ IN PVOID Address,
+ IN ULONG Length
+ );
+
+typedef
+VOID
+(*PEISA_INVALIDATE_CACHE_RTN)
+ (
+ IN PVOID Address,
+ IN ULONG Length
+ );
+
+typedef
+VOID
+(*PEISA_RESERVED_RTN)
+ (
+ VOID
+ );
+
+typedef
+VOID
+(*PEISA_BEGIN_CRITICAL_SECTION_RTN)
+ (
+ VOID
+ );
+
+typedef
+VOID
+(*PEISA_END_CRITICAL_SECTION_RTN)
+ (
+ VOID
+ );
+
+typedef
+ARC_STATUS
+(*PEISA_GENERATE_TONE_RTN)
+ (
+ IN ULONG Frequency,
+ IN ULONG Duration
+ );
+
+typedef
+VOID
+(*PEISA_FLUSH_WRITE_BUFFER_RTN)
+ (
+ VOID
+ );
+
+typedef
+BOOLEAN_ULONG
+(*PEISA_YIELD_RTN)
+ (
+ VOID
+ );
+
+typedef
+VOID
+(*PEISA_STALL_PROCESSOR_RTN)
+ (
+ IN ULONG Duration
+ );
+
+
+//
+// Define EISA callback vectors prototypes.
+//
+
+ARC_STATUS
+EisaProcessEndOfInterrupt
+ (
+ IN ULONG BusNumber,
+ IN USHORT Irq
+ );
+
+BOOLEAN_ULONG
+EisaTestEisaInterrupt
+ (
+ IN ULONG BusNumber,
+ IN USHORT Irq
+ );
+
+ARC_STATUS
+EisaRequestEisaDmaTransfer
+ (
+ IN ULONG BusNumber,
+ IN PDMA_TRANSFER pDmaTransfer
+ );
+
+ARC_STATUS
+EisaAbortEisaDmaTransfer
+ (
+ IN ULONG BusNumber,
+ IN PDMA_TRANSFER pDmaTransfer
+ );
+
+ARC_STATUS
+EisaGetEisaDmaTransferStatus
+ (
+ IN ULONG BusNumber,
+ IN PDMA_TRANSFER pDmaTransfer,
+ OUT PDMA_STATUS pDmaStatus
+ );
+
+ARC_STATUS
+EisaDoLockedOperation
+ (
+ IN ULONG BusNumber,
+ IN EISA_LOCK_OPERATION Operation,
+ IN PVOID Semaphore,
+ IN SEMAPHORE_SIZE SemaphoreSize,
+ IN PVOID OperationArgument,
+ OUT PVOID OperationResult
+ );
+
+ARC_STATUS
+EisaRequestEisaBusMasterTransfer
+ (
+ IN ULONG BusNumber,
+ IN PBUS_MASTER_TRANSFER pBusMasterTransfer,
+ OUT ULONG *TranslatedBufferAddress
+ );
+
+ARC_STATUS
+EisaReleaseEisaBusMasterTransfer
+ (
+ IN ULONG BusNumber,
+ IN PBUS_MASTER_TRANSFER pBusMasterTransfer,
+ IN ULONG TranslatedBufferAddress
+ );
+
+ARC_STATUS
+EisaRequestCpuAccessToEisaBus
+ (
+ IN ULONG BusNumber,
+ IN PSLAVE_TRANSFER pSlaveTransfer,
+ OUT PVOID *TranslatedAddress
+ );
+
+ARC_STATUS
+EisaReleaseCpuAccessToEisaBus
+ (
+ IN ULONG BusNumber,
+ IN PSLAVE_TRANSFER pSlaveTransfer,
+ IN PVOID TranslatedAddress
+ );
+
+VOID
+EisaFlushCache
+ (
+ IN PVOID Address,
+ IN ULONG Length
+ );
+
+VOID
+EisaInvalidateCache
+ (
+ IN PVOID Address,
+ IN ULONG Length
+ );
+
+VOID
+EisaBeginCriticalSection
+ (
+ IN VOID
+ );
+
+VOID
+EisaEndCriticalSection
+ (
+ IN VOID
+ );
+
+VOID
+EisaFlushWriteBuffers
+ (
+ VOID
+ );
+
+ARC_STATUS
+EisaGenerateTone
+ (
+ IN ULONG Frequency,
+ IN ULONG Duration
+ );
+
+BOOLEAN_ULONG
+EisaYield
+ (
+ VOID
+ );
+
+VOID
+EisaStallProcessor
+ (
+ IN ULONG Duration
+ );
+
+
+//
+// Define macros that call the EISA firmware routines indirectly through the
+// EISA firmware vector and provide type checking of argument values.
+//
+
+#define ArcEisaProcessEndOfInterrupt(BusNumber, IRQ) \
+ ((PEISA_PROCESS_EOI_RTN)(SYSTEM_BLOCK->Adapter0Vector[ProcessEOIRoutine])) \
+ ((BusNumber), (IRQ))
+
+#define ArcEisaTestEisaInterupt(BusNumber, IRQ) \
+ ((PEISA_TEST_INT_RTN)(SYSTEM_BLOCK->Adapter0Vector[TestIntRoutine])) \
+ ((BusNumber), (IRQ))
+
+#define ArcEisaRequestEisaDmaTransfer(BusNumber, pDmaTransfer) \
+ ((PEISA_REQ_DMA_XFER_RTN)(SYSTEM_BLOCK->Adapter0Vector[RequestDMARoutine])) \
+ ((BusNumber), (pDmaTransfer))
+
+#define ArcEisaAbortEisaDmaTransfer(BusNumber, pDmaTransfer) \
+ ((PEISA_ABORT_DMA_RTN)(SYSTEM_BLOCK->Adapter0Vector[AbortDMARoutine])) \
+ ((BusNumber), (pDmaTransfer))
+
+#define ArcEisaGetEisaDmaTransferStatus(BusNumber, pDmaTransfer, pDmaStatus) \
+ ((PEISA_DMA_XFER_STATUS_RTN)(SYSTEM_BLOCK->Adapter0Vector[GetDMAStatusRoutine])) \
+ ((BusNumber), (pDmaTransfer), (pDmaStatus))
+
+#define ArcEisaDoLockedOperation(BusNumber, Operation, Semaphore, SemaphoreSize, OperationArgument, OperationResult) \
+ ((PEISA_LOCK_RTN)(SYSTEM_BLOCK->Adapter0Vector[DoLockRoutine])) \
+ ((BusNumber), (Operation), (Semaphore), (SemaphoreSize), (OperationArgument), (OperationResult))
+
+#define ArcEisaRequestEisaBusMasterTransferCPUAddressToBusAddress(BusNumber, pBusMasterTransfer, TranslateBufferAddress) \
+ ((PEISA_REQUEST_BUS_MASTER_RTN)(SYSTEM_BLOCK->Adapter0Vector[RequestBusMasterRoutine])) \
+ ((BusNumber), (pBusMasterTransfer), (TranslateBufferAddress))
+
+#define ArcEisaReleaseEisaBusMasterTransfer(BusNumber, pBusMasterTransfer, TranslateBufferAddress) \
+ ((PEISA_RELEASE_BUS_MASTER_RTN)(SYSTEM_BLOCK->Adapter0Vector[ReleaseBusMasterRoutine])) \
+ ((BusNumber), (pBusMasterTransfer), (TranslateBufferAddress))
+
+#define ArcEisaRequestCpuAccessToEisaBus(BusNumber, pSlaveTransfer, TranslatedBufferAddress) \
+ ((PEISA_REQUEST_CPU_TO_BUS_ACCESS_RTN)(SYSTEM_BLOCK->Adapter0Vector[RequestCpuAccessToBusRoutine])) \
+ ((BusNumber), (pSlaveTransfer), (TranslatedBufferAddress))
+
+#define ArcEisaReleaseCpuAccessToEisaBus(BusNumber, pSlaveTransfer, TranslatedBufferAddress) \
+ ((PEISA_RELEASE_CPU_TO_BUS_ACCESS_RTN)(SYSTEM_BLOCK->Adapter0Vector[ReleaseCpuAccessToBusRoutine])) \
+ ((BusNumber), (pSlaveTransfer), (TranslatedBufferAddress))
+
+#define ArcEisaFlushCache(Address, Length) \
+ ((PEISA_FLUSH_CACHE_RTN)(SYSTEM_BLOCK->Adapter0Vector[FlushCacheRoutine])) \
+ ((Address), (Length))
+
+#define ArcEisaInvalidateCache(Address, Length) \
+ ((PEISA_INVALIDATE_CACHE_RTN)(SYSTEM_BLOCK->Adapter0Vector[InvalidateCacheRoutine])) \
+ ((Address), (Length))
+
+#define ArcEisaBeginCriticalSection() \
+ ((PEISA_BEGIN_CRITICAL_SECTION_RTN)(SYSTEM_BLOCK->Adapter0Vector[BeginCriticalSectionRoutine]))()
+
+#define ArcEisaEndCriticalSection() \
+ ((PEISA_END_CRITICAL_SECTION_RTN)(SYSTEM_BLOCK->Adapter0Vector[EndCriticalSectionRoutine]))()
+
+#define ArcEisaGenerateTone() \
+ ((PEISA_GENERATE_TONE_RTN)(SYSTEM_BLOCK->Adapter0Vector[GenerateToneRoutine])) \
+ ((Freqency), (Duration))
+
+#define ArcEisaFlushWriteBuffers() \
+ ((PEISA_FLUSH_WRITE_BUFFER_RTN)(SYSTEM_BLOCK->Adapter0Vector[FlushWriteBuffersRoutine]))()
+
+#define ArcEisaYield() \
+ ((PEISA_YIELD_RTN)(SYSTEM_BLOCK->Adapter0Vector[YieldRoutine]))()
+
+#define ArcEisaStallProcessor(Duration) \
+ ((PEISA_STALL_PROCESSOR_RTN)(SYSTEM_BLOCK->Adapter0Vector[StallProcessorRoutine])) \
+ (Duration)
+
+
+//
+// General OMF defines
+//
+
+#define OMF_BLOCK_SIZE 512 // OMF block size in bytes
+#define OMF_MAX_SIZE (32*1024*1024) // max OMF size in bytes
+#define OMF_MAX_FILE_LEN ((16*1024*1024)/(1<<WORD_2P2)) // (16 Mbytes max)/4
+#define OMF_MAX_FILE_LINK ((16*1024*1024)/(1<<WORD_2P2)) // (16 Mbytes max)/4
+#define OMF_ID_1ST 0x55 // 1st OMF ID
+#define OMF_ID_2ND 0x00 // 2nd OMF ID
+#define OMF_ID_3RD 0xAA // 3rd OMF ID
+#define OMF_ID_4TH 0xFF // 4th OMF ID
+#define OMF_FILE_NAME_LEN 12 // 12 chars
+
+//
+// Define OMF FAT file name structure
+//
+typedef struct _OMF_FAT_FILE_NAME
+ {
+ CHAR ProductId[7];
+ CHAR Version;
+ CHAR Dot;
+ CHAR Extension[2];
+ CHAR Revision;
+ } OMF_FAT_FILE_NAME, *POMF_FAT_FILE_NAME;
+
diff --git a/private/ntos/fw/mips/bmp.c b/private/ntos/fw/mips/bmp.c
new file mode 100644
index 000000000..4b91e3c04
--- /dev/null
+++ b/private/ntos/fw/mips/bmp.c
@@ -0,0 +1,164 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ bmp.c
+
+Abstract:
+
+ This module contains a bitmap.
+
+Author:
+
+ David M. Robinson (davidro) 17-Aug-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+
+
+#include "fwp.h"
+
+ULONG FwBmpHeight = 128;
+ULONG FwBmpWidth = 512;
+
+unsigned char FwBmp[] = {
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x40, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x1b, 0x85, 0x7f, 0x7f, 0x7f, 0x7c, 0x89, 0x7f, 0x7f,
+ 0x7f, 0x79, 0x8c, 0x7f, 0x7f, 0x7f, 0x76, 0x8e, 0x7f, 0x7f, 0x7f, 0x75, 0x90, 0x7f, 0x7f, 0x7f,
+ 0x73, 0x91, 0x7f, 0x7f, 0x7f, 0x72, 0x92, 0x7f, 0x7f, 0x7f, 0x71, 0x8c, 0x03, 0x84, 0x7f, 0x7f,
+ 0x7f, 0x71, 0x8a, 0x06, 0x83, 0x7f, 0x7f, 0x7f, 0x71, 0x88, 0x08, 0x83, 0x7f, 0x7f, 0x7f, 0x71,
+ 0x85, 0x0b, 0x83, 0x7f, 0x6a, 0x7f, 0x7f, 0x16, 0x83, 0x7f, 0x7f, 0x7f, 0x7f, 0x01, 0x84, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x85, 0x7f, 0x7f, 0x7f, 0x7f, 0x85, 0x7f, 0x7f, 0x7f, 0x7e, 0x86, 0x7f, 0x7f,
+ 0x7f, 0x7d, 0x86, 0x7f, 0x7f, 0x7f, 0x7d, 0x87, 0x7f, 0x7f, 0x7f, 0x7c, 0x88, 0x7f, 0x7f, 0x7f,
+ 0x7b, 0x89, 0x7f, 0x7f, 0x7f, 0x3b, 0x81, 0x12, 0x8b, 0x21, 0x89, 0x17, 0x81, 0x0a, 0x88, 0x18,
+ 0x86, 0x1b, 0x8a, 0x4e, 0x85, 0x7f, 0x54, 0x8d, 0x18, 0x82, 0x0c, 0x94, 0x1d, 0x8a, 0x16, 0x83,
+ 0x03, 0x90, 0x13, 0x8a, 0x16, 0x91, 0x13, 0x8c, 0x0d, 0x8c, 0x10, 0x8a, 0x27, 0x96, 0x10, 0x9e,
+ 0x02, 0xa0, 0x11, 0x93, 0x1a, 0x96, 0x14, 0x84, 0x06, 0x9a, 0x1b, 0x8b, 0x15, 0x8c, 0x05, 0x87,
+ 0x10, 0x8d, 0x12, 0x96, 0x10, 0x8c, 0x0d, 0x8c, 0x0f, 0x8d, 0x25, 0x96, 0x10, 0x9e, 0x02, 0xa0,
+ 0x10, 0x94, 0x17, 0x9c, 0x11, 0xa6, 0x19, 0x8c, 0x15, 0x89, 0x08, 0x88, 0x0e, 0x8e, 0x10, 0x99,
+ 0x0f, 0x8b, 0x0e, 0x8b, 0x0f, 0x8e, 0x26, 0x8f, 0x1a, 0x97, 0x09, 0x96, 0x14, 0x93, 0x17, 0xa0,
+ 0x0f, 0x92, 0x07, 0x8e, 0x18, 0x8c, 0x15, 0x88, 0x0a, 0x88, 0x0c, 0x91, 0x0e, 0x9a, 0x0e, 0x8b,
+ 0x0e, 0x8b, 0x0e, 0x90, 0x27, 0x8b, 0x1e, 0x93, 0x0d, 0x92, 0x16, 0x91, 0x17, 0x91, 0x09, 0x8a,
+ 0x0d, 0x8f, 0x0c, 0x8d, 0x17, 0x8d, 0x14, 0x87, 0x0c, 0x88, 0x0b, 0x8c, 0x02, 0x84, 0x0c, 0x9d,
+ 0x0c, 0x8c, 0x0d, 0x8c, 0x0d, 0x91, 0x27, 0x89, 0x1f, 0x92, 0x0f, 0x90, 0x16, 0x91, 0x16, 0x8f,
+ 0x11, 0x87, 0x0c, 0x8d, 0x0f, 0x8d, 0x16, 0x8a, 0x01, 0x83, 0x13, 0x86, 0x0d, 0x88, 0x0b, 0x8c,
+ 0x04, 0x82, 0x0b, 0x8f, 0x08, 0x88, 0x0c, 0x8b, 0x0e, 0x8b, 0x0d, 0x8c, 0x03, 0x83, 0x19, 0x0e,
+ 0x87, 0x21, 0x90, 0x11, 0x8e, 0x16, 0x91, 0x15, 0x8f, 0x15, 0x87, 0x0a, 0x8c, 0x11, 0x8d, 0x15,
+ 0x8a, 0x01, 0x83, 0x13, 0x86, 0x0d, 0x89, 0x0a, 0x8c, 0x05, 0x82, 0x0a, 0x8d, 0x0e, 0x85, 0x0b,
+ 0x8b, 0x0e, 0x8b, 0x0e, 0x8b, 0x04, 0x83, 0x27, 0x86, 0x20, 0x90, 0x12, 0x8e, 0x15, 0x91, 0x15,
+ 0x8f, 0x18, 0x86, 0x09, 0x8b, 0x13, 0x8d, 0x14, 0x8a, 0x02, 0x83, 0x13, 0x84, 0x0e, 0x8a, 0x0a,
+ 0x8b, 0x06, 0x82, 0x09, 0x8c, 0x11, 0x84, 0x0a, 0x8b, 0x0e, 0x8c, 0x0d, 0x8b, 0x05, 0x82, 0x28,
+ 0x85, 0x20, 0x90, 0x12, 0x8e, 0x15, 0x91, 0x14, 0x8f, 0x1b, 0x85, 0x09, 0x89, 0x15, 0x8d, 0x13,
+ 0x8a, 0x03, 0x83, 0x12, 0x84, 0x0e, 0x8a, 0x0a, 0x8b, 0x07, 0x81, 0x08, 0x8c, 0x14, 0x84, 0x08,
+ 0x8c, 0x0d, 0x8c, 0x0d, 0x8c, 0x05, 0x82, 0x27, 0x85, 0x20, 0x8f, 0x13, 0x8e, 0x14, 0x91, 0x14,
+ 0x8f, 0x1d, 0x85, 0x08, 0x89, 0x15, 0x8d, 0x13, 0x8a, 0x03, 0x83, 0x12, 0x84, 0x0e, 0x8a, 0x0a,
+ 0x8c, 0x06, 0x81, 0x08, 0x8c, 0x16, 0x81, 0x0a, 0x8b, 0x0e, 0x8b, 0x0d, 0x8c, 0x06, 0x81, 0x28,
+ 0x85, 0x1e, 0x90, 0x13, 0x8e, 0x13, 0x91, 0x14, 0x8f, 0x1f, 0x85, 0x07, 0x88, 0x17, 0x8d, 0x12,
+ 0x8a, 0x04, 0x83, 0x11, 0x83, 0x0e, 0x8c, 0x09, 0x8c, 0x0f, 0x8b, 0x22, 0x8b, 0x0e, 0x8c, 0x0c,
+ 0x8c, 0x2f, 0x85, 0x1e, 0x8f, 0x14, 0x8e, 0x12, 0x92, 0x13, 0x8f, 0x21, 0x84, 0x07, 0x87, 0x18,
+ 0x8d, 0x12, 0x8a, 0x05, 0x83, 0x10, 0x83, 0x0e, 0x8c, 0x0a, 0x8b, 0x0f, 0x8b, 0x22, 0x8c, 0x0d,
+ 0x8c, 0x0d, 0x8c, 0x2f, 0x84, 0x1d, 0x90, 0x14, 0x8e, 0x12, 0x91, 0x13, 0x90, 0x22, 0x83, 0x08,
+ 0x86, 0x18, 0x8d, 0x12, 0x8a, 0x05, 0x83, 0x11, 0x82, 0x0d, 0x8d, 0x0a, 0x8c, 0x0e, 0x8b, 0x23,
+ 0x8b, 0x0e, 0x8b, 0x0d, 0x8c, 0x2f, 0x85, 0x1c, 0x8f, 0x15, 0x8e, 0x11, 0x91, 0x14, 0x8f, 0x24,
+ 0x82, 0x08, 0x86, 0x18, 0x8e, 0x11, 0x8a, 0x06, 0x83, 0x10, 0x81, 0x0e, 0x8d, 0x0a, 0x8c, 0x0e,
+ 0x8b, 0x23, 0x8b, 0x0e, 0x8c, 0x0c, 0x8c, 0x30, 0x84, 0x1c, 0x8f, 0x15, 0x8e, 0x10, 0x91, 0x14,
+ 0x90, 0x25, 0x81, 0x08, 0x85, 0x19, 0x8e, 0x11, 0x8a, 0x07, 0x83, 0x0f, 0x81, 0x0d, 0x8e, 0x0a,
+ 0x8c, 0x0e, 0x8b, 0x23, 0x8c, 0x0d, 0x8c, 0x0d, 0x8b, 0x30, 0x85, 0x1a, 0x8f, 0x16, 0x8e, 0x0f,
+ 0x92, 0x13, 0x90, 0x2f, 0x85, 0x19, 0x8e, 0x11, 0x8a, 0x07, 0x83, 0x1c, 0x8f, 0x0b, 0x8b, 0x0e,
+ 0x8b, 0x23, 0x8c, 0x0d, 0x8c, 0x0d, 0x8c, 0x30, 0x84, 0x1a, 0x8f, 0x16, 0x8e, 0x0f, 0x91, 0x14,
+ 0x90, 0x2f, 0x85, 0x19, 0x8e, 0x10, 0x8b, 0x08, 0x83, 0x1b, 0x8f, 0x0b, 0x8c, 0x0d, 0x8b, 0x24,
+ 0x8c, 0x0d, 0x8c, 0x0c, 0x8c, 0x30, 0x85, 0x18, 0x8f, 0x17, 0x8e, 0x0e, 0x91, 0x14, 0x90, 0x31,
+ 0x83, 0x19, 0x8f, 0x10, 0x8b, 0x08, 0x83, 0x1a, 0x8f, 0x0c, 0x8c, 0x0e, 0x8a, 0x24, 0x8c, 0x0d,
+ 0x8c, 0x0d, 0x8b, 0x31, 0x84, 0x18, 0x8f, 0x17, 0x8e, 0x0d, 0x91, 0x15, 0x90, 0x31, 0x83, 0x19,
+ 0x8f, 0x10, 0x8b, 0x09, 0x83, 0x18, 0x90, 0x0d, 0x8b, 0x0e, 0x8f, 0x1f, 0x8d, 0x0c, 0x8d, 0x0c,
+ 0x8c, 0x30, 0xab, 0x17, 0x8e, 0x0c, 0x92, 0x14, 0x91, 0x31, 0x83, 0x18, 0x90, 0x10, 0x8a, 0x0a,
+ 0x83, 0x17, 0x90, 0x0e, 0x8c, 0x0d, 0x94, 0x1b, 0x8d, 0x0c, 0x8c, 0x0c, 0x8c, 0x31, 0xa9, 0x18,
+ 0x8e, 0x0c, 0x91, 0x15, 0x91, 0x31, 0x83, 0x18, 0x90, 0x10, 0x8a, 0x0b, 0x83, 0x16, 0x90, 0x0e,
+ 0x8c, 0x0e, 0x8a, 0x03, 0x89, 0x18, 0x8d, 0x0c, 0x8d, 0x0c, 0x8b, 0x31, 0xa9, 0x18, 0x8e, 0x0b,
+ 0x91, 0x16, 0x90, 0x33, 0x82, 0x17, 0x91, 0x10, 0x8a, 0x0c, 0x82, 0x15, 0x90, 0x10, 0x8b, 0x0e,
+ 0x8a, 0x06, 0x89, 0x15, 0x8e, 0x0b, 0x8e, 0x0b, 0x8c, 0x1a, 0x17, 0xa7, 0x19, 0x8e, 0x0a, 0x91,
+ 0x16, 0x91, 0x33, 0x82, 0x16, 0x91, 0x11, 0x8a, 0x0c, 0x83, 0x13, 0x90, 0x11, 0x8b, 0x0e, 0x8b,
+ 0x07, 0x89, 0x13, 0x8f, 0x0a, 0x8e, 0x0b, 0x8c, 0x31, 0x84, 0x14, 0x8f, 0x19, 0x8e, 0x09, 0x92,
+ 0x16, 0x91, 0x4b, 0x91, 0x11, 0x8a, 0x0d, 0x83, 0x11, 0x91, 0x11, 0x8c, 0x0e, 0x8a, 0x08, 0x8a,
+ 0x12, 0x8e, 0x0b, 0x8e, 0x0b, 0x8b, 0x31, 0x85, 0x12, 0x8f, 0x1a, 0x8e, 0x09, 0x91, 0x17, 0x91,
+ 0x4a, 0x92, 0x11, 0x8a, 0x0d, 0x83, 0x11, 0x90, 0x13, 0x8b, 0x0e, 0x8a, 0x0a, 0x89, 0x11, 0x8b,
+ 0x01, 0x83, 0x0a, 0x8f, 0x0a, 0x8c, 0x31, 0x84, 0x12, 0x8f, 0x1a, 0x8e, 0x08, 0x91, 0x18, 0x91,
+ 0x49, 0x92, 0x12, 0x8a, 0x0d, 0x84, 0x0f, 0x90, 0x14, 0x8b, 0x0f, 0x8a, 0x0a, 0x89, 0x10, 0x8b,
+ 0x01, 0x84, 0x09, 0x8c, 0x01, 0x83, 0x09, 0x8c, 0x31, 0x85, 0x10, 0x8f, 0x1b, 0x8e, 0x07, 0x91,
+ 0x18, 0x91, 0x49, 0x93, 0x12, 0x8a, 0x0e, 0x83, 0x0e, 0x90, 0x15, 0x8c, 0x0e, 0x8a, 0x0a, 0x8b,
+ 0x0f, 0x8b, 0x01, 0x84, 0x09, 0x8b, 0x01, 0x84, 0x08, 0x8c, 0x32, 0x84, 0x10, 0x8f, 0x1b, 0x8e,
+ 0x06, 0x92, 0x18, 0x91, 0x48, 0x93, 0x13, 0x8a, 0x0e, 0x83, 0x0e, 0x90, 0x15, 0x8c, 0x0f, 0x8a,
+ 0x0a, 0x8a, 0x0f, 0x8b, 0x02, 0x84, 0x08, 0x8c, 0x01, 0x83, 0x09, 0x8c, 0x31, 0x85, 0x0e, 0x90,
+ 0x1b, 0x8e, 0x06, 0x91, 0x19, 0x91, 0x47, 0x94, 0x13, 0x8a, 0x0e, 0x84, 0x0d, 0x8f, 0x17, 0x8b,
+ 0x0f, 0x8a, 0x0b, 0x8a, 0x0e, 0x8b, 0x02, 0x84, 0x08, 0x8c, 0x02, 0x83, 0x08, 0x8c, 0x32, 0x84,
+ 0x0e, 0x8f, 0x1c, 0x8e, 0x05, 0x91, 0x1a, 0x91, 0x46, 0x94, 0x14, 0x8a, 0x0e, 0x84, 0x0c, 0x8f,
+ 0x0b, 0x81, 0x0c, 0x8c, 0x0f, 0x8a, 0x0a, 0x8b, 0x0e, 0x8b, 0x02, 0x84, 0x08, 0x8b, 0x03, 0x83,
+ 0x07, 0x8c, 0x32, 0x84, 0x0e, 0x8f, 0x1c, 0xa4, 0x1a, 0x91, 0x45, 0x94, 0x15, 0x8a, 0x0e, 0x85,
+ 0x0b, 0x8e, 0x0c, 0x81, 0x0c, 0x8c, 0x10, 0x89, 0x0b, 0x8b, 0x0d, 0x8b, 0x03, 0x84, 0x07, 0x8b,
+ 0x03, 0x84, 0x07, 0x8c, 0x32, 0x84, 0x0c, 0x8f, 0x1d, 0xa7, 0x17, 0x91, 0x44, 0x94, 0x16, 0x8a,
+ 0x0d, 0x86, 0x0b, 0x8e, 0x0c, 0x82, 0x0c, 0x8b, 0x11, 0x89, 0x0a, 0x8b, 0x0d, 0x8b, 0x04, 0x84,
+ 0x06, 0x8c, 0x03, 0x84, 0x06, 0x8c, 0x32, 0x84, 0x0c, 0x8f, 0x1d, 0xa9, 0x15, 0x91, 0x44, 0x93,
+ 0x17, 0x8a, 0x0c, 0x87, 0x0b, 0x8d, 0x0c, 0x83, 0x0c, 0x8b, 0x11, 0x89, 0x0b, 0x8b, 0x0c, 0x8b,
+ 0x04, 0x85, 0x05, 0x8c, 0x04, 0x84, 0x05, 0x8c, 0x32, 0x85, 0x0a, 0x8f, 0x1e, 0x8e, 0x0a, 0x93,
+ 0x13, 0x91, 0x43, 0x93, 0x17, 0x8b, 0x0b, 0x89, 0x0a, 0x8c, 0x0d, 0x83, 0x0c, 0x8c, 0x11, 0x89,
+ 0x0a, 0x8b, 0x0d, 0x8b, 0x04, 0x85, 0x05, 0x8b, 0x05, 0x84, 0x04, 0x8c, 0x33, 0x84, 0x0a, 0x8f,
+ 0x1e, 0x8e, 0x0e, 0x90, 0x12, 0x91, 0x42, 0x93, 0x18, 0x8a, 0x0b, 0x8a, 0x0a, 0x8c, 0x0d, 0x83,
+ 0x0d, 0x8b, 0x12, 0x88, 0x0a, 0x8c, 0x0c, 0x8b, 0x05, 0x86, 0x02, 0x8d, 0x04, 0x86, 0x02, 0x8c,
+ 0x33, 0x85, 0x08, 0x90, 0x1e, 0x8e, 0x10, 0x8f, 0x11, 0x91, 0x41, 0x93, 0x19, 0x8a, 0x0a, 0x8b,
+ 0x0a, 0x8b, 0x0d, 0x84, 0x0d, 0x8b, 0x13, 0x88, 0x0a, 0x8b, 0x0c, 0x8b, 0x06, 0x94, 0x05, 0x94,
+ 0x33, 0x84, 0x08, 0x8f, 0x1f, 0x8e, 0x11, 0x8f, 0x10, 0x91, 0x41, 0x93, 0x19, 0x8a, 0x0a, 0x8b,
+ 0x0b, 0x8a, 0x0d, 0x85, 0x0c, 0x8c, 0x14, 0x87, 0x09, 0x8b, 0x0c, 0x8c, 0x06, 0x93, 0x06, 0x93,
+ 0x33, 0x85, 0x06, 0x90, 0x1f, 0x8e, 0x12, 0x8f, 0x0f, 0x91, 0x40, 0x93, 0x19, 0x8b, 0x0a, 0x8b,
+ 0x0b, 0x8a, 0x0c, 0x86, 0x06, 0x97, 0x10, 0x87, 0x08, 0x8b, 0x0c, 0x8c, 0x07, 0x92, 0x07, 0x92,
+ 0x16, 0x1e, 0x84, 0x06, 0x8f, 0x20, 0x8e, 0x13, 0x8f, 0x0f, 0x90, 0x3f, 0x93, 0x19, 0x8c, 0x0a,
+ 0x8b, 0x0c, 0x89, 0x0c, 0x86, 0x06, 0x97, 0x11, 0x87, 0x07, 0x8b, 0x0c, 0x8c, 0x08, 0x91, 0x08,
+ 0x90, 0x35, 0x84, 0x06, 0x8f, 0x20, 0x8e, 0x13, 0x8f, 0x0f, 0x90, 0x3f, 0x92, 0x16, 0x8f, 0x0b,
+ 0x8b, 0x0d, 0x88, 0x0b, 0x87, 0x07, 0x96, 0x13, 0x86, 0x06, 0x8b, 0x0b, 0x8d, 0x09, 0x8f, 0x0a,
+ 0x8f, 0x36, 0x84, 0x04, 0x8f, 0x21, 0x8e, 0x14, 0x8f, 0x0e, 0x91, 0x3d, 0x92, 0x19, 0x8d, 0x0c,
+ 0x89, 0x0f, 0x88, 0x08, 0x89, 0x07, 0x97, 0x14, 0x85, 0x04, 0x8b, 0x09, 0x91, 0x09, 0x8e, 0x0b,
+ 0x8e, 0x36, 0x84, 0x04, 0x8f, 0x21, 0x8e, 0x14, 0x8f, 0x0e, 0x91, 0x3d, 0x91, 0x1d, 0x8a, 0x0c,
+ 0x89, 0x10, 0x89, 0x04, 0x8c, 0x08, 0x95, 0x16, 0x92, 0x0c, 0x8e, 0x0a, 0x8d, 0x0d, 0x8b, 0x38,
+ 0x84, 0x02, 0x8f, 0x22, 0x8e, 0x15, 0x8e, 0x0f, 0x90, 0x3d, 0x90, 0x21, 0x86, 0x0e, 0x87, 0x13,
+ 0x97, 0x0a, 0x93, 0x18, 0x8e, 0x13, 0x89, 0x0c, 0x8a, 0x0f, 0x89, 0x39, 0x84, 0x02, 0x8f, 0x22,
+ 0x8e, 0x15, 0x8f, 0x0e, 0x90, 0x3c, 0x91, 0x13, 0x81, 0x11, 0x81, 0x10, 0x84, 0x18, 0x8a, 0x08,
+ 0x82, 0x0c, 0x8d, 0x20, 0x89, 0x19, 0x85, 0x0d, 0x86, 0x13, 0x86, 0x3a, 0x95, 0x22, 0x8e, 0x15,
+ 0x8f, 0x0f, 0x8f, 0x28, 0x82, 0x12, 0x90, 0x14, 0x82, 0x5f, 0x8b, 0x7f, 0x2f, 0x93, 0x23, 0x8e,
+ 0x15, 0x8f, 0x0f, 0x90, 0x27, 0x82, 0x12, 0x90, 0x13, 0x83, 0x60, 0x8a, 0x7f, 0x2f, 0x93, 0x23,
+ 0x8e, 0x15, 0x8f, 0x0f, 0x90, 0x26, 0x83, 0x12, 0x8f, 0x14, 0x83, 0x62, 0x88, 0x7f, 0x30, 0x91,
+ 0x24, 0x8e, 0x15, 0x8f, 0x10, 0x8f, 0x26, 0x83, 0x12, 0x8f, 0x14, 0x83, 0x63, 0x88, 0x7f, 0x2f,
+ 0x91, 0x24, 0x8e, 0x15, 0x8f, 0x10, 0x90, 0x25, 0x83, 0x12, 0x8e, 0x15, 0x84, 0x63, 0x87, 0x7f,
+ 0x30, 0x8f, 0x25, 0x8e, 0x15, 0x8f, 0x11, 0x8f, 0x24, 0x84, 0x12, 0x8e, 0x15, 0x84, 0x64, 0x86,
+ 0x7f, 0x30, 0x8f, 0x25, 0x8e, 0x15, 0x8f, 0x12, 0x8e, 0x24, 0x84, 0x12, 0x8e, 0x14, 0x85, 0x65,
+ 0x86, 0x7f, 0x30, 0x8d, 0x26, 0x8e, 0x15, 0x8e, 0x13, 0x8f, 0x22, 0x85, 0x12, 0x8e, 0x14, 0x85,
+ 0x66, 0x85, 0x7f, 0x30, 0x8d, 0x26, 0x8e, 0x14, 0x8f, 0x14, 0x8e, 0x22, 0x85, 0x13, 0x8d, 0x14,
+ 0x86, 0x66, 0x84, 0x7f, 0x30, 0x8d, 0x26, 0x8e, 0x14, 0x8f, 0x15, 0x8e, 0x20, 0x86, 0x13, 0x8d,
+ 0x13, 0x87, 0x67, 0x83, 0x7f, 0x0c, 0x25, 0x8b, 0x27, 0x8e, 0x14, 0x8e, 0x17, 0x8e, 0x1e, 0x87,
+ 0x14, 0x8c, 0x12, 0x88, 0x67, 0x84, 0x7f, 0x30, 0x8b, 0x27, 0x8e, 0x13, 0x8f, 0x18, 0x8e, 0x1c,
+ 0x88, 0x14, 0x8d, 0x11, 0x88, 0x68, 0x83, 0x7f, 0x31, 0x89, 0x28, 0x8e, 0x13, 0x8e, 0x1a, 0x8e,
+ 0x1a, 0x89, 0x15, 0x8c, 0x10, 0x8a, 0x7f, 0x7f, 0x1c, 0x89, 0x28, 0x8e, 0x12, 0x8e, 0x1c, 0x8e,
+ 0x18, 0x8a, 0x15, 0x8d, 0x0e, 0x8b, 0x7f, 0x7f, 0x1d, 0x87, 0x29, 0x8e, 0x11, 0x8e, 0x1e, 0x8e,
+ 0x16, 0x8b, 0x16, 0x8d, 0x0c, 0x8c, 0x7f, 0x7f, 0x1d, 0x87, 0x29, 0x8e, 0x10, 0x8f, 0x1f, 0x8f,
+ 0x12, 0x8d, 0x17, 0x8d, 0x0a, 0x8d, 0x7f, 0x7f, 0x1e, 0x86, 0x28, 0x8f, 0x0e, 0x8f, 0x23, 0x8f,
+ 0x0e, 0x8f, 0x18, 0x8e, 0x06, 0x90, 0x7f, 0x7f, 0x1d, 0x85, 0x28, 0x90, 0x0b, 0x91, 0x25, 0x91,
+ 0x08, 0x92, 0x1a, 0xa2, 0x7f, 0x7f, 0x1e, 0x84, 0x26, 0xac, 0x29, 0xa1, 0x04, 0x84, 0x1b, 0x98,
+ 0x05, 0x84, 0x7f, 0x7f, 0x1e, 0x83, 0x22, 0xae, 0x2f, 0x9a, 0x09, 0x83, 0x1d, 0x92, 0x0a, 0x83,
+ 0x7f, 0x7f, 0x1e, 0x83, 0x22, 0xa9, 0x36, 0x95, 0x0d, 0x82, 0x21, 0x8a, 0x0f, 0x83, 0x7f, 0x7f,
+ 0x1e, 0x81, 0x7f, 0x08, 0x8b, 0x12, 0x82, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x41, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f,
+ 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x7f, 0x40
+};
diff --git a/private/ntos/fw/mips/confsub.s b/private/ntos/fw/mips/confsub.s
new file mode 100644
index 000000000..ec2ea25b7
--- /dev/null
+++ b/private/ntos/fw/mips/confsub.s
@@ -0,0 +1,51 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ conftest.s
+
+Abstract:
+
+ This module contains configuration test subroutines.
+
+Author:
+
+ David Robinson (davidro) 21-May-1992
+
+--*/
+
+//
+// include header file
+//
+#include <ksmips.h>
+
+
+/*++
+
+Routine Description:
+
+ This routine reads the processor id register and returns the
+ value.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+.text
+.set noat
+.set noreorder
+
+ LEAF_ENTRY(CtReadProcessorId)
+ mfc0 v0,prid // read the processor id
+ nop
+ j ra
+ nop
+ .end CtReadProcessorId
+
diff --git a/private/ntos/fw/mips/conftest.c b/private/ntos/fw/mips/conftest.c
new file mode 100644
index 000000000..78514fe07
--- /dev/null
+++ b/private/ntos/fw/mips/conftest.c
@@ -0,0 +1,965 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ conftest.c
+
+Abstract:
+
+ This program tests the ARC configuration functions.
+
+Author:
+
+ David M. Robinson (davidro) 4-Sept-1991
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#include "jzsetup.h"
+#include "oli2msft.h"
+#include "inc.h"
+
+#define MAXIMUM_DEVICE_SPECIFIC_DATA 32
+
+PCHAR Banner1 = " JAZZ Configuration Test Program Version 0.15\r\n";
+PCHAR Banner2 = " Copyright (c) 1991, 1992 Microsoft Corporation\r\n";
+
+ULONG
+CtReadProcessorId(
+ VOID
+ );
+
+
+VOID
+JzShowTime (
+ BOOLEAN First
+ )
+{
+ return;
+}
+
+
+VOID
+CtPrintData(
+ PCONFIGURATION_COMPONENT Component
+ )
+
+/*++
+
+--*/
+
+{
+ ARC_STATUS Status;
+ MONITOR_CONFIGURATION_DATA MonitorData; // TEMPTEMP
+ EISA_ADAPTER_DETAILS EisaDetails;
+ JAZZ_G300_CONFIGURATION_DATA VideoData; // TEMPTEMP
+ PCM_VIDEO_DEVICE_DATA VideoDeviceData;
+ PCM_MONITOR_DEVICE_DATA MonitorDeviceData;
+ PCM_SONIC_DEVICE_DATA SonicDeviceData;
+ PCM_SCSI_DEVICE_DATA ScsiDeviceData;
+ PCM_FLOPPY_DEVICE_DATA FloppyDeviceData;
+ PCM_SERIAL_DEVICE_DATA SerialDeviceData;
+ ULONG LineSize;
+ UCHAR Buffer[sizeof(CM_PARTIAL_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 5) +
+ MAXIMUM_DEVICE_SPECIFIC_DATA];
+ PCM_PARTIAL_RESOURCE_LIST Descriptor = (PCM_PARTIAL_RESOURCE_LIST)&Buffer;
+ ULONG Count;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial;
+ ULONG Prid;
+ BOOLEAN OldData;
+ ULONG Version;
+ ULONG Index;
+
+ JzPrint("\n\r");
+
+ if (Component == NULL) {
+ JzPrint(" NULL component");
+ return;
+ }
+
+ if (Component->IdentifierLength != 0) {
+ JzPrint(" Identifier = ");
+ JzPrint(Component->Identifier);
+ }
+ JzPrint("\n\r");
+
+ OldData = FALSE;
+ switch (Component->Class) {
+
+ case SystemClass:
+ JzPrint(" Class = System\r\n");
+ JzPrint(" Type = ");
+ if (Component->Type == ArcSystem) {
+ JzPrint("Arc");
+ } else {
+ JzPrint("Unknown");
+ }
+ JzPrint("\r\n");
+ break;
+ case ProcessorClass:
+ JzPrint(" Class = Processor\r\n");
+ JzPrint(" Type = ");
+
+ switch (Component->Type) {
+ case CentralProcessor:
+ JzPrint("CPU");
+ break;
+
+ case FloatingPointProcessor:
+ JzPrint("FPU");
+ break;
+
+ default:
+ JzPrint("Unknown");
+ break;
+ }
+ JzPrint("\r\n");
+ JzPrint(" Number = %d\r\n", Component->Key);
+
+ JzPrint(" Processor = ");
+ Prid = CtReadProcessorId();
+ if ((Prid >> 8) != 4) {
+ JzPrint("Unknown\r\n");
+ } else {
+ JzPrint("R4000\r\n");
+ JzPrint(" Revision = %d.%d\r\n", (Prid >> 4) & 0xF, Prid & 0xF);
+ }
+
+ break;
+
+ case CacheClass:
+ JzPrint(" Class = Cache\r\n");
+ JzPrint(" Type = ");
+
+ switch (Component->Type) {
+ case PrimaryIcache:
+ JzPrint("Primary Instruction");
+ break;
+
+ case PrimaryDcache:
+ JzPrint("Primary Data");
+ break;
+
+ case SecondaryIcache:
+ JzPrint("Secondary Instruction");
+ break;
+
+ case SecondaryDcache:
+ JzPrint("Secondary Data");
+ break;
+
+ case SecondaryCache:
+ JzPrint("Secondary");
+ break;
+
+ default:
+ JzPrint("Unknown");
+ break;
+
+ }
+
+ LineSize = 1 << ((Component->Key & 0xFF0000) >> 16);
+ JzPrint("\r\n");
+ JzPrint(" Block = %d\r\n", ((Component->Key & 0xFF000000) >> 24) * LineSize);
+ JzPrint(" Line = %d\r\n", LineSize);
+ JzPrint(" Size = %d\r\n", (1 << (Component->Key & 0xFFFF) << PAGE_SHIFT));
+ break;
+
+ case AdapterClass:
+ JzPrint(" Class = Adapter\r\n");
+ JzPrint(" Type = ");
+
+ switch (Component->Type) {
+ case EisaAdapter:
+ JzPrint("EISA");
+ OldData = TRUE;
+ break;
+
+ case TcAdapter:
+ JzPrint("Turbochannel");
+ break;
+
+ case ScsiAdapter:
+ JzPrint("SCSI");
+ break;
+
+ case DtiAdapter:
+ JzPrint("Desktop Interface");
+ break;
+
+ case MultiFunctionAdapter:
+ JzPrint("Multifunction");
+ break;
+
+ default:
+ JzPrint("Unknown");
+ break;
+
+ }
+ JzPrint("\r\n");
+ break;
+
+ case ControllerClass:
+ JzPrint(" Class = Controller\r\n");
+ JzPrint(" Type = ");
+
+ switch (Component->Type) {
+
+ case DiskController:
+ JzPrint("Disk");
+ break;
+
+ case TapeController:
+ JzPrint("Tape");
+ break;
+
+ case CdromController:
+ JzPrint("CDROM");
+ break;
+
+ case WormController:
+ JzPrint("WORM");
+ break;
+
+ case SerialController:
+ JzPrint("Serial");
+ break;
+
+ case NetworkController:
+ JzPrint("Network");
+ break;
+
+ case DisplayController:
+ OldData = TRUE;
+ JzPrint("Display");
+ break;
+
+ case ParallelController:
+ JzPrint("Parallel");
+ break;
+
+ case PointerController:
+ JzPrint("Pointer");
+ break;
+
+ case KeyboardController:
+ JzPrint("Keyboard");
+ break;
+
+ case AudioController:
+ JzPrint("Audio");
+ break;
+
+ case OtherController:
+ JzPrint("Other");
+ break;
+
+ default:
+ JzPrint("Unknown");
+ break;
+
+ }
+ JzPrint("\r\n");
+ break;
+
+ case PeripheralClass:
+ JzPrint(" Class = Peripheral\r\n");
+ JzPrint(" Type = ");
+
+ switch (Component->Type) {
+
+ case DiskPeripheral:
+ JzPrint("Disk");
+ break;
+
+ case FloppyDiskPeripheral:
+ JzPrint("Floppy disk");
+ break;
+
+ case TapePeripheral:
+ JzPrint("Tape");
+ break;
+
+ case ModemPeripheral:
+ JzPrint("Modem");
+ break;
+
+ case PrinterPeripheral:
+ JzPrint("Printer");
+ break;
+
+ case KeyboardPeripheral:
+ JzPrint("Keyboard");
+ break;
+
+ case PointerPeripheral:
+ JzPrint("Pointer");
+ break;
+
+ case MonitorPeripheral:
+ OldData = TRUE;
+ JzPrint("Monitor");
+ break;
+
+ case TerminalPeripheral:
+ JzPrint("Terminal");
+ break;
+
+ case OtherPeripheral:
+ JzPrint("Other");
+ break;
+
+ default:
+ JzPrint("Unknown");
+ break;
+
+ }
+ JzPrint("\r\n");
+ break;
+
+
+ default:
+ JzPrint(" Unknown class,");
+ break;
+ }
+
+ JzPrint(" Key = %08lx\r\n", Component->Key);
+// JzPrint(" Affinity = %08lx\r\n", Component->AffinityMask);
+ JzPrint(" Flags:\r\n");
+
+ if (Component->Flags.Failed) {
+ JzPrint(" Failed\r\n");
+ }
+
+ if (Component->Flags.ReadOnly) {
+ JzPrint(" ReadOnly\r\n");
+ }
+
+ if (Component->Flags.Removable) {
+ JzPrint(" Removable\r\n");
+ }
+
+ if (Component->Flags.ConsoleIn) {
+ JzPrint(" ConsoleIn\r\n");
+ }
+
+ if (Component->Flags.ConsoleOut) {
+ JzPrint(" ConsoleOut\r\n");
+ }
+
+ if (Component->Flags.Input) {
+ JzPrint(" Input\r\n");
+ }
+
+ if (Component->Flags.Output) {
+ JzPrint(" Output\r\n");
+ }
+
+ JzPrint("\r\n");
+
+ if (!OldData &&
+ (Component->ConfigurationDataLength != 0) &&
+ (Component->ConfigurationDataLength < sizeof(Buffer))) {
+
+ Status = ArcGetConfigurationData( Descriptor, Component );
+ if ((Status != ESUCCESS) || (Descriptor->Count > 10)) {
+ JzPrint(" Error reading configuration data");
+ } else {
+ JzPrint(" Version %d.%d\r\n", Descriptor->Version, Descriptor->Revision);
+ Version = Descriptor->Version * 100 + Descriptor->Revision;
+ for (Count = 0 ; Count < Descriptor->Count ; Count++ ) {
+ Partial = &Descriptor->PartialDescriptors[Count];
+ switch (Partial->Type) {
+ case CmResourceTypePort:
+ JzPrint(" Port Config -- %08lx - %08lx\r\n",
+ Partial->u.Port.Start.LowPart,
+ Partial->u.Port.Start.LowPart +
+ Partial->u.Port.Length - 1);
+ break;
+ case CmResourceTypeInterrupt:
+ JzPrint(" Interrupt Config -- ");
+ if (Partial->Flags & CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE) {
+ JzPrint(" Level triggered,");
+ } else {
+ JzPrint(" Edge triggered,");
+ }
+ JzPrint(" Irql = ");
+ switch (Partial->u.Interrupt.Level) {
+ case DEVICE_LEVEL:
+ JzPrint("DEVICE_LEVEL");
+ break;
+ case PASSIVE_LEVEL:
+ JzPrint("PASSIVE_LEVEL");
+ break;
+ case APC_LEVEL:
+ JzPrint("APC_LEVEL");
+ break;
+ case DISPATCH_LEVEL:
+ JzPrint("DISPATCH_LEVEL");
+ break;
+ case IPI_LEVEL:
+ JzPrint("IPI_LEVEL");
+ break;
+ case HIGH_LEVEL:
+ JzPrint("HIGH_LEVEL");
+ break;
+ default:
+ JzPrint("Unknown level");
+ }
+ JzPrint(", Vector = %08lx\r\n", Partial->u.Interrupt.Vector);
+ break;
+ case CmResourceTypeMemory:
+ JzPrint(" Memory Config -- %08lx - %08lx\r\n",
+ Partial->u.Memory.Start.LowPart,
+ Partial->u.Memory.Start.LowPart +
+ Partial->u.Memory.Length - 1);
+ break;
+ case CmResourceTypeDma:
+ JzPrint(" DMA Config -- Channel = %d\r\n",
+ Partial->u.Dma.Channel);
+ break;
+ case CmResourceTypeDeviceSpecific:
+ switch (Component->Class) {
+
+ case AdapterClass:
+ switch (Component->Type) {
+ case ScsiAdapter:
+ ScsiDeviceData = (PCM_SCSI_DEVICE_DATA)&Descriptor->PartialDescriptors[Count+1];
+ JzPrint(" Scsi Host Identifier = %d\r\n",
+ ScsiDeviceData->HostIdentifier);
+ break;
+ default:
+ break;
+ }
+
+ case ControllerClass:
+ switch (Component->Type) {
+ case DisplayController:
+ VideoDeviceData = (PCM_VIDEO_DEVICE_DATA)&Descriptor->PartialDescriptors[Count+1];
+ JzPrint(" Video Clock = %d\r\n",
+ VideoDeviceData->VideoClock);
+ break;
+ case NetworkController:
+ SonicDeviceData = (PCM_SONIC_DEVICE_DATA)&Descriptor->PartialDescriptors[Count+1];
+ JzPrint(" Sonic Data Configuration Register = %04x\r\n",
+ SonicDeviceData->DataConfigurationRegister);
+ if (Version >= 101) {
+ JzPrint(" Sonic Ethernet Address = ");
+ for (Index = 0; Index < 6 ; Index++) {
+ JzPrint("%02lx", SonicDeviceData->EthernetAddress[Index]);
+ }
+ JzPrint("\r\n");
+ JzPrint(" Sonic Ethernet Checksum = ");
+ for (Index = 6; Index < 8 ; Index++) {
+ JzPrint("%02lx", SonicDeviceData->EthernetAddress[Index]);
+ }
+ JzPrint("\r\n");
+
+ }
+ break;
+
+ case SerialController:
+ SerialDeviceData = (PCM_SERIAL_DEVICE_DATA)&Descriptor->PartialDescriptors[Count+1];
+ JzPrint(" Serial Baud Clock = %d\r\n",
+ SerialDeviceData->BaudClock);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ case PeripheralClass:
+
+ switch (Component->Type) {
+
+ case FloppyDiskPeripheral:
+ FloppyDeviceData = (PCM_FLOPPY_DEVICE_DATA)&Descriptor->PartialDescriptors[Count+1];
+ JzPrint(" Floppy data:\n\r");
+ JzPrint(" Size = %s\n\r", FloppyDeviceData->Size);
+ JzPrint(" MaxDensity = %d Kb\n\r", FloppyDeviceData->MaxDensity);
+ break;
+
+ case MonitorPeripheral:
+ MonitorDeviceData = (PCM_MONITOR_DEVICE_DATA)&Descriptor->PartialDescriptors[Count+1];
+ JzPrint(" Monitor data:\n\r");
+ JzPrint(" HorizontalResolution = %d\n\r", MonitorDeviceData->HorizontalResolution);
+ JzPrint(" HorizontalDisplayTime = %d\n\r", MonitorDeviceData->HorizontalDisplayTime);
+ JzPrint(" HorizontalBackPorch = %d\n\r", MonitorDeviceData->HorizontalBackPorch);
+ JzPrint(" HorizontalFrontPorch = %d\n\r", MonitorDeviceData->HorizontalFrontPorch);
+ JzPrint(" HorizontalSync = %d\n\r", MonitorDeviceData->HorizontalSync);
+ JzPrint(" VerticalResolution = %d\n\r", MonitorDeviceData->VerticalResolution);
+ JzPrint(" VerticalBackPorch = %d\n\r", MonitorDeviceData->VerticalBackPorch);
+ JzPrint(" VerticalFrontPorch = %d\n\r", MonitorDeviceData->VerticalFrontPorch);
+ JzPrint(" VerticalSync = %d\n\r", MonitorDeviceData->VerticalSync);
+ JzPrint(" HorizontalScreenSize = %d\n\r", MonitorDeviceData->HorizontalScreenSize);
+ JzPrint(" VerticalScreenSize = %d\n\r", MonitorDeviceData->VerticalScreenSize);
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ JzPrint(" Unknown data\r\n");
+ break;
+ }
+ }
+ }
+ } else {
+ if (OldData) {
+ if (Component->Type == DisplayController) {
+ Status = ArcGetConfigurationData( &VideoData, Component);
+ if (Status != ESUCCESS) {
+ JzPrint(" Error reading video configuration data");
+ } else {
+ JzPrint(" Video controller data:\n\r");
+ JzPrint(" Irql = %d\n\r", VideoData.Irql);
+ JzPrint(" Vector = %d\n\r", VideoData.Vector);
+ JzPrint(" ControlBase = %08xl\n\r", VideoData.ControlBase);
+ JzPrint(" ControlSize = %d\n\r", VideoData.ControlSize);
+ JzPrint(" CursorBase = %08xl\n\r", VideoData.CursorBase);
+ JzPrint(" CursorSize = %d\n\r", VideoData.CursorSize);
+ JzPrint(" FrameBase = %08xl\n\r", VideoData.FrameBase);
+ JzPrint(" FrameSize = %d\n\r", VideoData.FrameSize);
+ }
+ } else if (Component->Type == MonitorPeripheral) {
+ Status = ArcGetConfigurationData( &MonitorData, Component);
+ if (Status != ESUCCESS) {
+ JzPrint(" Error reading monitor configuration data");
+ } else {
+ JzPrint(" Monitor data:\n\r");
+ JzPrint(" HorizontalResolution = %d\n\r", MonitorData.HorizontalResolution);
+ JzPrint(" HorizontalDisplayTime = %d\n\r", MonitorData.HorizontalDisplayTime);
+ JzPrint(" HorizontalBackPorch = %d\n\r", MonitorData.HorizontalBackPorch);
+ JzPrint(" HorizontalFrontPorch = %d\n\r", MonitorData.HorizontalFrontPorch);
+ JzPrint(" HorizontalSync = %d\n\r", MonitorData.HorizontalSync);
+ JzPrint(" VerticalResolution = %d\n\r", MonitorData.VerticalResolution);
+ JzPrint(" VerticalBackPorch = %d\n\r", MonitorData.VerticalBackPorch);
+ JzPrint(" VerticalFrontPorch = %d\n\r", MonitorData.VerticalFrontPorch);
+ JzPrint(" VerticalSync = %d\n\r", MonitorData.VerticalSync);
+ JzPrint(" HorizontalScreenSize = %d\n\r", MonitorData.HorizontalScreenSize);
+ JzPrint(" VerticalScreenSize = %d\n\r", MonitorData.VerticalScreenSize);
+ }
+ } else if (Component->Type == EisaAdapter) {
+ Status = ArcGetConfigurationData( &EisaDetails, Component);
+ if (Status != ESUCCESS) {
+ JzPrint(" Error reading Eisa bus data");
+ } else {
+ JzPrint(" Eisa Details:\n\r");
+ JzPrint(" Number of slots = %d\n\r", EisaDetails.NumberOfSlots);
+ JzPrint(" Io start address = %08lx\n\r", EisaDetails.IoStart);
+ JzPrint(" Io size = %lx\n\r", EisaDetails.IoSize);
+ }
+ }
+ }
+ }
+ return;
+}
+
+VOID
+main(
+ int argc,
+ char *argv[],
+ char *envp[]
+ )
+{
+ ULONG Index;
+ UCHAR Character;
+ ULONG Count;
+ LONG DefaultChoice = 0;
+ ARC_STATUS Status;
+ CHAR PathName[80];
+ PCONFIGURATION_COMPONENT Component;
+ PCONFIGURATION_COMPONENT NewComponent;
+ PSYSTEM_ID SystemId;
+ BOOLEAN Update;
+ PMEMORY_DESCRIPTOR MemoryDescriptor;
+ GETSTRING_ACTION Action;
+ PCHAR Choices[] = {
+ "Walk through the configuration tree",
+ "Enter a pathname and display the configuration data",
+ "Display memory configuration",
+ "Test Unicode",
+ "Other ARC Tests",
+ "Exit"
+ };
+#define NUMBER_OF_CHOICES (sizeof(Choices) / sizeof(ULONG))
+ ULONG Fid;
+ ULONG CrLf;
+ ULONG Space;
+ ULONG i, j;
+ BOOLEAN Unicode;
+ PARC_DISPLAY_STATUS DisplayStatus;
+ ULONG x, y;
+
+ while (TRUE) {
+
+ JzSetScreenAttributes( TRUE, FALSE, FALSE);
+ JzPrint("%c2J", ASCII_CSI);
+ JzSetPosition( 0, 0);
+ JzPrint(Banner1);
+ JzPrint(Banner2);
+
+ for (Index = 0; Index < NUMBER_OF_CHOICES ; Index++ ) {
+ JzSetPosition( Index + 3, 5);
+ if (Index == DefaultChoice) {
+ JzSetScreenAttributes( TRUE, FALSE, TRUE);
+ JzPrint(Choices[Index]);
+ JzSetScreenAttributes( TRUE, FALSE, FALSE);
+ } else {
+ JzPrint(Choices[Index]);
+ }
+ }
+
+ JzSetPosition(NUMBER_OF_CHOICES + 4, 0);
+ SystemId = ArcGetSystemId();
+ JzPrint(" System = ");
+ JzPrint(&SystemId->VendorId[0]);
+ JzPrint("\r\n");
+ JzPrint(" Serial = %8lx\r\n", SystemId->ProductId);
+
+ Character = 0;
+ do {
+ if (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ switch (Character) {
+
+ case ASCII_ESC:
+ return;
+
+ case ASCII_CSI:
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ JzSetPosition( DefaultChoice + 3, 5);
+ JzPrint(Choices[DefaultChoice]);
+ switch (Character) {
+ case 'A':
+ case 'D':
+ DefaultChoice--;
+ if (DefaultChoice < 0) {
+ DefaultChoice = NUMBER_OF_CHOICES-1;
+ }
+ break;
+ case 'B':
+ case 'C':
+ DefaultChoice++;
+ if (DefaultChoice == NUMBER_OF_CHOICES) {
+ DefaultChoice = 0;
+ }
+ break;
+ case 'H':
+ DefaultChoice = 0;
+ break;
+ default:
+ break;
+ }
+ JzSetPosition( DefaultChoice + 3, 5);
+ JzSetScreenAttributes( TRUE, FALSE, TRUE);
+ JzPrint(Choices[DefaultChoice]);
+ JzSetScreenAttributes( TRUE, FALSE, FALSE);
+ continue;
+
+ default:
+ break;
+ }
+ }
+
+ } while ((Character != '\n') && (Character != '\r'));
+
+ switch (DefaultChoice) {
+
+ case 0:
+
+ Component = ArcGetChild(NULL);
+ NewComponent = Component;
+ Character = 0;
+ do {
+
+ JzSetPosition( 3, 5);
+ JzPrint("\x9BJ");
+ JzPrint("Use arrow keys to walk the tree, ESC to return");
+ JzPrint("\n\r\n\r");
+
+ CtPrintData(Component);
+ Update = FALSE;
+ do {
+ if (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ switch (Character) {
+
+ case ASCII_CSI:
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ switch (Character) {
+ case 'A':
+ NewComponent = ArcGetParent(Component);
+ Update = TRUE;
+ break;
+
+ case 'B':
+ NewComponent = ArcGetChild(Component);
+ Update = TRUE;
+ break;
+
+ case 'C':
+ NewComponent = ArcGetPeer(Component);
+ Update = TRUE;
+ break;
+
+ case 'D':
+ NewComponent = ArcGetParent(Component);
+ NewComponent = ArcGetChild(NewComponent);
+ while ((NewComponent != NULL) &&
+ (ArcGetPeer(NewComponent) != Component)) {
+ NewComponent = ArcGetPeer(NewComponent);
+ }
+ Update = TRUE;
+ break;
+
+ default:
+ break;
+
+ }
+
+ if (NewComponent != NULL) {
+ Component = NewComponent;
+ }
+
+ default:
+ break;
+ }
+ }
+ } while (!Update && (Character != ASCII_ESC));
+ } while ((Character != ASCII_ESC));
+ break;
+
+ case 1:
+
+ JzSetPosition( 3, 5);
+ JzPrint("\x9BJ");
+ JzPrint("Enter component pathname: ");
+ do {
+ Action = FwGetString( PathName,
+ sizeof(PathName),
+ NULL,
+ 3,
+ sizeof(" Enter component pathname: "));
+
+ if (Action == GetStringEscape) {
+ break;
+ }
+
+ } while ( Action != GetStringSuccess );
+ if (Action == GetStringEscape) {
+ continue;
+ }
+ JzPrint("\n\r");
+
+ Component = ArcGetComponent(PathName);
+
+ CtPrintData(Component);
+
+ JzPrint(" Press any key to continue...");
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ continue;
+
+ case 2:
+
+ MemoryDescriptor = ArcGetMemoryDescriptor(NULL);
+ while (MemoryDescriptor != NULL) {
+
+ JzSetPosition( 3, 5);
+ JzPrint("\x9BJ");
+
+ JzPrint("Memory type = ");
+ switch (MemoryDescriptor->MemoryType) {
+ case MemoryExceptionBlock:
+ JzPrint("ExceptionBlock");
+ break;
+ case MemorySystemBlock:
+ JzPrint("SystemBlock");
+ break;
+ case MemoryFree:
+ JzPrint("Free");
+ break;
+ case MemoryBad:
+ JzPrint("Bad");
+ break;
+ case MemoryLoadedProgram:
+ JzPrint("LoadedProgram");
+ break;
+ case MemoryFirmwareTemporary:
+ JzPrint("FirmwareTemporary");
+ break;
+ case MemoryFirmwarePermanent:
+ JzPrint("FirmwarePermanent");
+ break;
+ default:
+ JzPrint("Unknown");
+ break;
+ }
+
+ JzSetPosition( 4, 5);
+ JzPrint("Base Page = %08lx", MemoryDescriptor->BasePage);
+ JzSetPosition( 5, 5);
+ JzPrint("Page Count = %d", MemoryDescriptor->PageCount);
+ JzSetPosition( 6,5);
+
+
+ JzPrint(" Press any key to continue, ESC to return");
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ if (Character == ASCII_ESC) {
+ break;
+ }
+
+ MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor);
+ }
+ break;
+
+ case 3:
+
+ JzPrint("\r\n\r\n");
+ CrLf = (ASCII_CR << 16) + ASCII_LF;
+ Space = ' ';
+
+ ArcClose(ARC_CONSOLE_OUTPUT);
+ ArcOpen("multi()video()monitor()console(1)",ArcOpenWriteOnly,&Fid);
+ for (j = 0; j < 16 ; j++ ) {
+ for (i = 0 ; i < 9 ; i++ ) {
+ Index = 0x2500 + (i << 4) + j;
+ ArcWrite(ARC_CONSOLE_OUTPUT, &Space, 2, &Count);
+ ArcWrite(ARC_CONSOLE_OUTPUT, &Index, 2, &Count);
+ }
+ ArcWrite(ARC_CONSOLE_OUTPUT, &CrLf, 4, &Count);
+ }
+ ArcClose(ARC_CONSOLE_OUTPUT);
+ ArcOpen("multi()video()monitor()console()",ArcOpenWriteOnly,&Fid);
+
+ JzPrint("\r\nPress any key to continue");
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+
+
+ ArcClose(ARC_CONSOLE_INPUT);
+ ArcOpen("multi()key()keyboard()console(1)",ArcOpenReadOnly,&Fid);
+ ArcOpen("multi()video()monitor()console(1)",ArcOpenWriteOnly,&Fid);
+
+ do {
+ JzPrint("\r\nPress any key, ESC to stop: ");
+ ArcRead(ARC_CONSOLE_INPUT, &Index, 2, &Count);
+ ArcWrite(Fid, &Index, 2, &Count);
+ } while ( Index != ASCII_ESC );
+
+ JzPrint(" \r\n Searching for valid Unicode ranges...");
+
+ Unicode = FALSE;
+ for (Index = 0; Index < 0xffff ; Index++ ) {
+ if (ArcTestUnicodeCharacter(Fid, (WCHAR)Index) == ESUCCESS) {
+ if (!Unicode) {
+ JzPrint("\r\n Start = %04lx, ", Index);
+ Unicode = TRUE;
+ }
+ } else {
+ if (Unicode) {
+ JzPrint("End = %04lx, ", Index);
+ Unicode = FALSE;
+ }
+ }
+ }
+
+ ArcClose(Fid);
+ ArcClose(ARC_CONSOLE_INPUT);
+ ArcOpen("multi()key()keyboard()console()",ArcOpenWriteOnly,&Fid);
+
+ JzPrint("\r\nPress any key to continue");
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+
+ break;
+
+ case 4:
+
+ DisplayStatus = ArcGetDisplayStatus(ARC_CONSOLE_OUTPUT);
+
+ x = (DisplayStatus->CursorMaxXPosition / 2) - 24;
+ y = (DisplayStatus->CursorMaxYPosition / 2) - 7;
+
+ JzSetPosition(y++,x);
+
+ JzPrint("ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»");
+
+ for (Index = 0; Index < 10 ; Index++ ) {
+ JzSetPosition(y++,x);
+ JzPrint("º º");
+ }
+ JzSetPosition(y++,x);
+ JzPrint("ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ");
+
+ x = (DisplayStatus->CursorMaxXPosition / 2) - 23;
+ y = (DisplayStatus->CursorMaxYPosition / 2) - 6;
+
+ JzSetPosition(y++,x);
+ JzSetScreenColor(ArcColorCyan,ArcColorBlack);
+
+ JzPrint("ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»");
+
+ for (Index = 0; Index < 6 ; Index++ ) {
+ JzSetPosition(y++,x);
+ JzPrint("º º");
+ }
+ JzSetPosition(y++,x);
+ JzPrint("ÇÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄĶ");
+ JzSetPosition(y++,x);
+ JzPrint("º º");
+ JzSetPosition(y++,x);
+ JzPrint("ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ");
+
+ x = (DisplayStatus->CursorMaxXPosition / 2) - 22;
+ y = (DisplayStatus->CursorMaxYPosition / 2) - 5;
+ JzSetPosition(y++,x);
+
+ DisplayStatus = ArcGetDisplayStatus(ARC_CONSOLE_OUTPUT);
+
+ JzPrint("X Cursor = %d", DisplayStatus->CursorXPosition);
+ JzSetPosition(y++,x);
+ JzPrint("Y Cursor = %d", DisplayStatus->CursorYPosition);
+ JzSetPosition(y++,x);
+ JzPrint("Max X Cursor = %d", DisplayStatus->CursorMaxXPosition);
+ JzSetPosition(y++,x);
+ JzPrint("Max Y Cursor = %d", DisplayStatus->CursorMaxYPosition);
+
+
+ JzSetPosition(y++,x);
+ JzPrint("Press any key to continue...");
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+
+ for (Index = 0; Index < argc ; Index++ ) {
+ JzPrint("\r\n Argument #%d = ", Index);
+ JzPrint(argv[Index]);
+ }
+
+ if (argc == 0) {
+ JzPrint("\r\n No arguments");
+ }
+
+ JzPrint("\r\n Press any key to continue...");
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+
+ break;
+
+ case 5:
+ return;
+
+ default:
+ continue;
+ }
+ }
+}
diff --git a/private/ntos/fw/mips/d4reset.s b/private/ntos/fw/mips/d4reset.s
new file mode 100644
index 000000000..ab4c2ecea
--- /dev/null
+++ b/private/ntos/fw/mips/d4reset.s
@@ -0,0 +1,3046 @@
+#if defined(DUO) && defined(R4000)
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ d4reset.s
+
+Abstract:
+
+ This module is the start of the flash prom code. This code will
+ be the first run upon reset. It contains the self-test and
+ initialization.
+
+Author:
+
+ Lluis Abello (lluis) 8-Jan-91
+
+Environment:
+
+ Executes in kernal mode.
+
+Notes:
+
+ ***** IMPORTANT *****
+
+ This module must be linked such that it resides in the
+ first page of the rom.
+
+Revision History:
+
+
+--*/
+//
+// include header file
+//
+#include <ksmips.h>
+#include <duoprom.h>
+#include "dmaregs.h"
+#include "selfmap.h"
+#include "led.h"
+#include "j4reset.h"
+
+
+#define TlbInit PROM_ENTRY(10)
+
+
+
+//TEMPTEMP
+
+#define COPY_ENTRY 6
+
+.text
+.set noreorder
+.set noat
+
+
+ ALTERNATE_ENTRY(ResetVector)
+/*++
+
+Routine Description:
+
+ This routine will provide the jump vectors located
+ at the targets of the processor exception vectors.
+
+ N.B. This routine must be located at the start of ROM which
+ is the location of the reset vector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+//
+// this instruction must be loaded at location 0 in the
+// rom. This will appear as BFC00000 to the processor
+//
+ b ResetException
+ nop
+
+//
+// This is the jump table for rom routines that other
+// programs can call. They are placed here so that they
+// will be unlikely to move.
+//
+//
+// This becomes PROM_ENTRY(2) as defined in ntmips.h
+//
+ .align 4
+ nop
+//
+// Entries 4 to 7 are used for the ROM Version and they
+// must be zero in this file.
+//
+
+//
+// This becomes PROM_ENTRYS(8,9...)
+//
+ .align 6
+ nop // entry 8
+ nop
+ nop // entry 9
+ nop
+ b InvalidateDCache // entry 10
+ nop
+ b InvalidateSCache // entry 11
+ nop
+ b InvalidateICache // entry 12
+ nop
+ nop // entry 13
+ nop
+ b PutLedDisplay // entry 14
+ nop
+ nop // entry 15
+ nop
+ nop // entry 16
+ nop
+
+RomRemoteSpeedValues:
+//
+// This table contains the default values for the remote speed regs.
+//
+ .byte REMSPEED1 // ethernet
+ .byte REMSPEED2 // SCSI
+ .byte REMSPEED3 // SCSI
+ .byte REMSPEED4 // RTC
+ .byte REMSPEED5 // Kbd/Mouse
+ .byte REMSPEED6 // Serial port 1
+ .byte REMSPEED7 // Serial port 2
+ .byte REMSPEED8 // Parallel
+ .byte REMSPEED9 // NVRAM
+ .byte REMSPEED10 // Int src reg
+ .byte REMSPEED11 // PROM
+ .byte REMSPEED12 // New dev
+ .byte REMSPEED13 // New dev
+ .byte REMSPEED14 // LED
+
+ .align 4
+
+//
+// New TLB Entries can be added to the following table
+// The format of the table is:
+// entryhi; entrylo0; entrylo1; pagemask
+//
+#define TLB_HI 0
+#define TLB_LO0 4
+#define TLB_LO1 8
+#define TLB_MASK 12
+
+TlbEntryTable:
+
+//
+// 256KB Base PROM Read only
+// 256KB Flash PROM Read/Write
+//
+
+ .word ((PROM_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((PROM_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + (2 << ENTRYLO_C)
+
+
+ .word (((PROM_PHYSICAL_BASE+0x40000) >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \
+ (2 << ENTRYLO_C) + (1 << ENTRYLO_D)
+
+ .word (PAGEMASK_256KB << PAGEMASK_PAGEMASK)
+
+//
+// I/O Device space non-cached, valid, dirty
+//
+ .word ((DEVICE_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((DEVICE_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (1 << ENTRYLO_G) // set global bit even if page not used
+ .word (PAGEMASK_64KB << PAGEMASK_PAGEMASK)
+//
+// video control 2MB non-cached read/write.
+//
+ .word ((VIDEO_CONTROL_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((VIDEO_CONTROL_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \
+ (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((VIDEO_CONTROL_PHYSICAL_BASE+0x100000) >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \
+ (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_1MB << PAGEMASK_PAGEMASK)
+//
+// extended video control 2MB non-cached read/write.
+//
+ .word ((EXTENDED_VIDEO_CONTROL_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((EXTENDED_VIDEO_CONTROL_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \
+ (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+
+ .word (((EXTENDED_VIDEO_CONTROL_PHYSICAL_BASE+0x100000) >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \
+ (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_1MB << PAGEMASK_PAGEMASK)
+//
+// video memory space 8Mb non-cached read/write
+//
+ .word ((VIDEO_MEMORY_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((VIDEO_MEMORY_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((VIDEO_MEMORY_PHYSICAL_BASE+0x400000) >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \
+ (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_4MB << PAGEMASK_PAGEMASK)
+//
+// EISA I/O 16Mb non-cached read/write
+// EISA MEM 16Mb non-cached read/write
+//
+ .word ((EISA_IO_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((EISA_IO_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word ((0x100000) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_16MB << PAGEMASK_PAGEMASK)
+//
+// EISA I/O page 0 non-cached read/write
+// EISA I/O page 1 non-cached read/write
+//
+ .word ((EISA_EXTERNAL_IO_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((0 >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((EISA_IO_PHYSICAL_BASE + 1 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \
+ (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK)
+//
+// EISA I/O page 2 non-cached read/write
+// EISA I/O page 3 non-cached read/write
+//
+ .word (((EISA_EXTERNAL_IO_VIRTUAL_BASE + 2 * PAGE_SIZE) >> 13) << ENTRYHI_VPN2)
+ .word (((EISA_IO_PHYSICAL_BASE + 2 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \
+ (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((EISA_IO_PHYSICAL_BASE + 3 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \
+ (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK)
+//
+// EISA I/O page 4 non-cached read/write
+// EISA I/O page 5 non-cached read/write
+//
+ .word (((EISA_EXTERNAL_IO_VIRTUAL_BASE + 4 * PAGE_SIZE) >> 13) << ENTRYHI_VPN2)
+ .word (((EISA_IO_PHYSICAL_BASE + 4 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) +\
+ (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((EISA_IO_PHYSICAL_BASE + 5 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \
+ (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK)
+//
+// EISA I/O page 6 non-cached read/write
+// EISA I/O page 7 non-cached read/write
+//
+ .word (((EISA_EXTERNAL_IO_VIRTUAL_BASE + 6 * PAGE_SIZE) >> 13) << ENTRYHI_VPN2)
+ .word (((EISA_IO_PHYSICAL_BASE + 6 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \
+ (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((EISA_IO_PHYSICAL_BASE + 7 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK)
+//
+// EISA I/O pages 8,9,a,b non-cached read/write
+// EISA I/O pages c,d,e,f non-cached read/write
+//
+ .word (((EISA_EXTERNAL_IO_VIRTUAL_BASE + 8 * PAGE_SIZE) >> 13) << ENTRYHI_VPN2)
+ .word (((EISA_IO_PHYSICAL_BASE + 8 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((EISA_IO_PHYSICAL_BASE + 12 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + \
+ (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_16KB << PAGEMASK_PAGEMASK)
+//
+// Map 64KB of memory for the video prom code&data cached.
+//
+ .word ((VIDEO_PROM_CODE_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((VIDEO_PROM_CODE_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (3 << ENTRYLO_C)
+ .word (1 << ENTRYLO_G) // set global bit even if page not used
+ .word (PAGEMASK_64KB << PAGEMASK_PAGEMASK)
+
+//
+// Map 4kb of exclusive memory and 4Kb of shared
+//
+ .word ((EXCLUSIVE_PAGE_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((EXCLUSIVE_PAGE_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (4 << ENTRYLO_C)
+ .word ((SHARED_PAGE_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (5 << ENTRYLO_C)
+ .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK)
+
+
+//
+// Map PCR for kernel debugger.
+//
+ .word ((PCR_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word (1 << ENTRYLO_G) // set global bit even if page not used
+ .word ((PCR_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK)
+
+TlbEntryEnd:
+ .byte 0
+
+
+
+//
+// these next vectors should be loaded at PROM_BASE + 0x200, 0x300,
+// and 0x380. They are for the TLBmiss, cache_error, and
+// common exceptions respectively.
+//
+ .align 9
+ LEAF_ENTRY(UserTlbMiss200)
+UserTlbMiss:
+ li k0,KSEG1_BASE
+ lw k0,0x1018(k0) // Load address of UTBMiss handler
+ nop
+ jal k1,k0 // jump to handler saving return
+ nop // address in k1
+ mtc0 k0,epc // Handler returns return address in K0
+ nop // 2 cycle Hazard
+ nop
+ eret // restore from exception
+ .end UserTlbMiss200
+
+
+ParityError:
+//
+// Change kseg0 coherency to non cached.
+//
+ mfc0 k0,config // get config register
+ li k1,~(7 << CONFIG_K0) // mask to clear Kseg0 coherency bits
+ and k0,k0,k1 // clear bits
+ ori k0,(2 << CONFIG_K0) // make kseg0 non cached
+ mtc0 k0,config //
+//
+// Copy the copy routines to memory
+//
+ la a0,MemoryRoutines // source
+ la a1,MemoryRoutines-LINK_ADDRESS+KSEG1_BASE // destination location
+ la t2,EndMemoryRoutines // end
+ bal DataCopy // copy code to memory
+ subu a2,t2,a0 // length of code
+//
+// Copy the firmware from PROM to memory.
+//
+ la s0,Decompress-LINK_ADDRESS+KSEG1_BASE
+ // address of decompression routine in cached space
+ la a0,end // end of this file is start of selftest
+ li a1,RAM_TEST_DESTINATION_ADDRESS
+ // destination is uncached link address.
+ jal s0 // jump to decompress
+ nop
+
+//
+// Initialize the stack to the low memory and Call Rom tests.
+//
+ li t0,RAM_TEST_DESTINATION_ADDRESS // address of copied code
+ li sp,RAM_TEST_STACK_ADDRESS | KSEG1_BASE // init stack non cached
+ move a1,s5 // Pass cacheerr register as 2nd arg
+ jal t0 // jump to self-test in memory
+ li a0,3 // pass cause of exception as argument.
+
+//
+// This becomes the entry point of a Cache Error Exception.
+// It should be located at offset 0x300
+//
+ .align 8
+/*++
+ParityHandler();
+Routine Description:
+
+ This routine is called as a result of a Cache Error exception
+ It copies the firmware to memory and jumps to it where error
+ information is printed.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Does not return
+
+--*/
+ LEAF_ENTRY(ParityHandler300)
+ //
+ // Should save state.
+ //
+ li k0,(1<<PSR_BEV) | (1 << PSR_CU1) | (1<<PSR_ERL)
+ mtc0 k0,psr // initialize psr
+ nop
+ li k0,(1<<PSR_BEV) | (1 << PSR_CU1)
+ nop
+ mtc0 k0,psr // Clear ERL bit
+
+//
+// TMPTMP
+// Reinitialize tlb. Should save state somewhere.
+// Copy the tlb table to memory. And call the map routine in the base prom.
+//
+ la t0, TlbEntryTable // Load address of table in prom
+ la t1, TlbEntryEnd //
+ li a1, KSEG1_BASE+0x400 // Destination address.
+10:
+ lw v0,0(t0) // Load from prom
+ sw v0,0(a1) // store into memory
+ addiu t0,t0,4 // next source
+ bne t0,t1,10b // branch if not end
+ addiu a1,a1,4 // next dest address
+
+ li a0,KSEG1_BASE+0x400 // base of table in memory
+ li k0,TlbInit // Get address of TLB init in base prom
+ jal k0 // Go to reinitialize the tlb
+ li a2,COPY_ENTRY+1 // tlb index
+ li t0,TRANSFER_VECTOR // get address of transfer vector
+ sw v0,4(t0) // set next free TB entry index.
+ mfc0 s5,cacheerr // Load cache error register
+ bal PutLedDisplay
+ ori a0,zero,LED_PARITY //
+ b ParityError
+ nop
+
+ .end ParityHandler300
+//
+// This becomes the entry point of a General Exception.
+// It should be located at offset 380
+//
+/*++
+GeneralExceptionHandler();
+Routine Description:
+
+ This routine is called as a result of a General Exception
+ The address of the General Exception Handler is loaded from the
+ ArcVector and the handler is called.
+
+ For DUO. A DBE can mean memory ECC error.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+ .align 7
+ LEAF_ENTRY(GeneralException380)
+ mfc0 k0,cause // read cause register.
+ li k1,XCODE_DATA_BUS_ERROR //
+ andi k0,R4000_XCODE_MASK // Extract xcode bits
+ beq k1,k0,BusError // Branch if DBE
+ li k1,XCODE_INSTRUCTION_BUS_ERROR //
+ beq k1,k0,BusError // Branch if IBE
+CallArcGEHandler: //
+ li k0,KSEG1_BASE
+ lw k0,0x1014(k0) // Load address of GE handler
+ nop
+ jal k1,k0 // jump to handler saving return
+ nop // address in k1
+ mtc0 k0,epc // Handler returns return address in K0
+ nop // 2 cycle Hazard
+ nop
+ eret // restore from exception
+ nop
+BusError:
+ //
+ // If this is actually an ECC Error then call the Cache Error Handler
+ // Otherwise call the ARC GE Exception Handler.
+ //
+ li k0,DMA_VIRTUAL_BASE // load base address of MCT_ADR
+ lw k0,DmaNMISource(k0) // Read the interrupt source register.
+ li k1,1 // Memory Error bit
+ bne k0,k1,CallArcGEHandler // If Bit Not set Call the Arc Handler
+
+//
+// This is an ECC error.
+//
+DuoEccHandler:
+ li k0,DMA_VIRTUAL_BASE // load base address of MCT_ADR
+ lw k1,DmaMemoryFailedAddress(k0) // read MFAR to clear bit
+ lw k1,DmaEccDiagnostic(k0) // clear error in parity diag reg.
+ mfc0 k0,epc // get address of exception
+ li k1,0xFFFFFFF0 // mask to align address of exception
+ and k0,k1,k0 // align epc
+ la k1,ExpectedParityException // get address where exception is expected
+ bne k0,k1,CallArcGEHandler // if not equal call ARC handler
+ addiu k1,0x10 // set exception return address 4 instructions further
+ mtc0 k1,epc // move into epc
+ addiu v1,zero,1 // set return value to 1.
+ nop // fill second cycle hazard
+ eret // return
+ // Return.
+ .end GeneralException380
+
+ ALTERNATE_ENTRY(ResetException)
+/*++
+
+Routine Description:
+
+ This is the handler for the reset exception. It first checks the cause
+ of the exception. If it is an NMI, then control is passed to the
+ exception dispatch routine. Otherwise the machine is initialized.
+
+ The basic are:
+ 1) Map the I/O devices.
+ 2) Test the processor.
+ 3) Test the MCTADR
+ 4) Map ROM. Perform a ROM checksum.
+ 5) Test a portion of Memory
+ 6) Test TLB
+ 7) Copy routines to memory
+ 8) Initialize caches
+ 9) Initialize stack for C language calls and other stack operations
+ 10) Copy selftest and firmware code to memory and jump to it.
+
+ N.B. This routine must be loaded into the first page of rom.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+//
+// If the exception is a hard reset, the TLB has been initialized by the
+// base prom to map all the system resources.
+// If it's a soft reset, the only device we know is mapped is the flash prom
+// since this code is being fetched from it.
+//
+
+//
+// Check cause of exception, if SR bit in PSR is set treat it as a soft reset
+// or an NMI, otherwise it's a cold reset.
+//
+ mfc0 k0,psr // get cause register
+ li k1,(1<<PSR_SR) // bit indicates soft reset.
+ mtc0 zero,watchlo // initialize the watch
+ mtc0 zero,watchhi // address registers
+ and k1,k1,k0 // mask PSR with SR bit
+ li k0,(1<<PSR_BEV) | (1 << PSR_CU1) | (1<<PSR_ERL)
+ mtc0 k0,psr // Clear interrupt bit while ERL still set
+ nop
+ beq k1,zero,10f // branch if cold reset
+ move s5,zero // clear s5 to indicate cold reset
+ ori s5,zero,1 // set s5 to 1 to indicate soft reset
+10:
+ li k0,(1<<PSR_BEV) | (1 << PSR_CU1)
+ nop
+ mtc0 k0,psr // Clear ERL bit
+
+//
+// TMPTMP
+// Reinitialize tlb. Should save state somewhere.
+// Copy the tlb table to memory. And call the map routine in the base prom.
+//
+ la t0, TlbEntryTable // Load address of table in prom
+ la t1, TlbEntryEnd //
+ li a1, KSEG1_BASE+0x400 // Destination address.
+10:
+ lw v0,0(t0) // Load from prom
+ sw v0,0(a1) // store into memory
+ addiu t0,t0,4 // next source
+ bne t0,t1,10b // branch if not end
+ addiu a1,a1,4 // next dest address
+
+ li a0,KSEG1_BASE+0x400 // base of table in memory
+ li k0,TlbInit // Get address of TLB init in base prom
+ jal k0 // Go to reinitialize the tlb
+ li a2,COPY_ENTRY+1 // tlb index
+
+ li t0,TRANSFER_VECTOR // get address of transfer vector
+ sw v0,4(t0) // set next free TB entry index.
+ beq s5,zero,Reset // branch if cold reset
+ li k0,DMA_VIRTUAL_BASE // load base address of MCT_ADR
+ lw k1,DmaNMISource(k0) // Read the interrupt source register.
+ andi k0,k1,(1<<3) // test for NMI
+ beq k0,zero,Reset // if bit not set this is a Soft Reset
+ // otherwise is an NMI
+
+ //
+ // Nmi Handler jump to firmware to print message.
+ //
+ li k0,DMA_VIRTUAL_BASE // load base address of MCT_ADR
+ lw k1,DmaWhoAmI(k0) // Read who am I
+ beq k1,zero,ProcessorANMI // Processor B dies here in a loop.
+ lw zero,DmaIpInterruptAcknowledge(k0)// read IP Ack register to clear pending interrupts
+ li k1,(1 << 4) // IP interrupt enable bit
+ sw k1,DmaInterruptEnable(k0) // Enable IP interrupts.
+5:
+ mfc0 k0,cause // get cause register
+ li k1,1<<14 // mask to test IP interrupt
+ and k0,k1 // and them
+ beq k0,zero,5b // Keep looping if not set
+ li k1,DMA_VIRTUAL_BASE // load DMA base
+ lw k1,DmaIpInterruptAcknowledge(k1)// read IP Ack register to clear it
+30:
+ mfc0 k0,cause // get cause register
+ li k1,1<<14 // mask to test IP interrupt
+ and k0,k1 // and them
+ bne k0,zero,30b // Keep looping if still set
+
+ bal InvalidateICache // Invalidate the instruction cache
+ nop
+ bal FlushDCache // Flush the data cache
+ nop
+
+ li k0,RAM_TEST_LINK_ADDRESS // address of copied code
+ li sp,RAM_TEST_STACK_ADDRESS_B // init stack
+ mfc0 a1,errorepc // pass cause of exception as argument.
+ jal k0 // jump to self-test in memory
+ li a0,2 // set exception cause to 2=NMI
+
+ProcessorANMI:
+
+ bal PutLedDisplay // set a dash in the LED
+ ori a0,zero,LED_NMI //
+
+ //
+ // Copy the copy routines to memory
+ //
+
+ la a0,MemoryRoutines // source
+ la a1,MemoryRoutines-LINK_ADDRESS+KSEG1_BASE // destination location
+ la t2,EndMemoryRoutines // end
+ bal DataCopy // copy code to memory
+ sub a2,t2,a0 // length of code
+
+ la t2,InvalidateICache-LINK_ADDRESS+KSEG1_BASE // non-cached space
+ jal t2 // Invalidate the instruction cache
+ nop
+ la k0,NMI // Join common code
+ mfc0 s6,errorepc // get error epc
+ j k0 // running at PROM Vaddress.
+ li s5,2
+
+Reset:
+//
+// Initialize PSR to BEV and COP1 enabled. It's important to clear ERL since
+// the ErrorEPC is undefined and further exceptions will set ERL or EXL
+// according to the nature of the exception.
+//
+ li k0,(1<<PSR_BEV) | (1 << PSR_CU1)
+ mtc0 k0,psr
+ nop
+ nop
+
+//
+// Set the primary instruction cache block size to 32 bytes
+// Set the primary data cache block size to 32 bytes
+//
+//
+
+ mfc0 t0,config
+ li t1, (1 << CONFIG_IB) + (1 << CONFIG_DB) + (0 << CONFIG_CU) + \
+ (3 << CONFIG_K0)
+ li t2, 0xFFFFFFC0
+ and t0,t0,t2 // clear soft bits in config
+ or t0,t0,t1 // set soft bits in config
+ mtc0 t0,config
+ nop
+ nop
+
+ bal PutLedDisplay // BLANK the LED
+ ori a0,zero,LED_BLANK<<TEST_SHIFT
+
+ beq s5,1,SkipProcessorTest // Skip processor test if softreset
+ nop
+ bal PutLedDisplay // Show processor test is staring
+ ori a0,zero,LED_PROCESSOR_TEST
+ bal ProcessorTest // Test the processor
+ nop
+ move s5,zero // clear s5 to indicate cold reset
+
+SkipProcessorTest:
+ li t0,DMA_VIRTUAL_BASE // load base address of MCT_ADR
+ lw s6,DmaWhoAmI(t0) // s6 = processor number.
+ bne s6,zero,ProcessorBReset
+ nop
+ bal PutLedDisplay // Show MCT_ADR reset test is starting
+ ori a0,zero,LED_MCTADR_RESET
+ bal MctadrResetTest
+ nop
+
+ bal PutLedDisplay // Show MCT_ADR register test is starting
+ ori a0,zero,LED_MCTADR_REG
+ bal MctadrRegisterTest
+ nop
+
+ beq s5,1,SkipRomChecksum // Skip checksum if softreset
+ nop
+//
+// Perform a ROM Checksum.
+//
+ bal PutLedDisplay // Display in the LED that
+ ori a0,zero,LED_ROM_CHECKSUM // ROM Checksum is being executed
+ li a0,PROM_VIRTUAL_BASE // address of PROM
+ li t0,ROM_SIZE
+ add a1,a0,t0 // end of loop address
+ move t0,zero // init sum register
+
+RomCheckSum:
+ lw t1,0(a0) // fetch word
+ lw t2,4(a0) // fetch second word
+ addu t0,t0,t1 // calculate checksum add from ofs 0
+ lw t1,8(a0)
+ addu t0,t0,t2 // calculate checksum add from ofs 4
+ lw t2,0xC(a0)
+ addu t0,t0,t1 // calculate checksum add from ofs 8
+ addiu a0,a0,16 // compute next address
+ bne a0,a1,RomCheckSum // check end of loop condition
+ addu t0,t0,t2 // calculate checksum add from ofs c
+
+//
+// if test passes, jump to next part of initialization code.
+//
+ beq t0,zero,TestMemory // Branch if calculated checksum is correct
+ move s5,zero // clear s5 this tells to run selftest
+ lui a0,LED_BLINK // otherwise hang
+ bal PutLedDisplay // by calling PutLedDisplay
+ ori a0,a0,LED_ROM_CHECKSUM // blinking the test number
+
+SkipRomChecksum:
+TestMemory:
+ bal PutLedDisplay // call PutLedDisplay to show that
+ ori a0,zero,LED_MEMORY_TEST_1 // Mem test is starting
+
+ bal SizeMemory // start by sizing the memory.
+ nop //
+
+//
+// Call memory test routine to test small portion of memory.
+// a0 is start of tested memory. a1 is length in bytes to test
+//
+//
+// Disable Parity exceptions for the first memory test. Otherwise
+// if something is wrong with the memory we jump to the moon.
+//
+// DUO ECC diag register resets to zero which forces good ecc to be
+// written during read modify write cycles.
+//
+ li t0, (1<<PSR_DE) | (1 << PSR_CU1) | (1 << PSR_BEV)
+ mtc0 t0,psr
+ nop
+
+ li a0,KSEG1_BASE // start of mem test
+ ori a1,zero,MEMTEST_SIZE // length to test in bytes
+ ctc1 zero,fsr // clear floating status
+ nop
+ bal WriteNoXorAddressTest
+ move a2,zero // xor pattern zero
+ bal CheckNoXorAddressTest
+ ori a3,zero,LED_MEMORY_TEST_1 // set Test/Subtest ID
+//
+// Do the same flipping all bits
+//
+ bal WriteAddressTest
+ li a2,-1 // Xor pattern = FFFFFFFF
+ bal CheckAddressTest
+ nop
+//
+// Do the same flipping some bits to be sure parity bits are flipped in each byte
+//
+ lui a2,0x0101
+ bal WriteAddressTest
+ ori a2,a2,0x0101 // Xor pattern = 01010101
+ bal CheckAddressTest
+ nop
+
+//
+// The next step is to copy a number of routines to memory so they can
+// be executed more quickly. Calculate the arguments for DataCopy call:
+// a0 is source of data, a1 is dest, a2 is length in bytes
+//
+ la a0,MemoryRoutines // source
+ la a1,MemoryRoutines-LINK_ADDRESS+KSEG1_BASE // destination location
+ la t2,EndMemoryRoutines // end
+ bal DataCopy // copy code to memory
+ sub a2,t2,a0 // length of code
+
+//
+// Call cache initialization routine in non-cached memory
+//
+ bal PutLedDisplay // display that cache init
+ ori a0,zero,LED_CACHE_INIT // is starting
+ la s1,R4000CacheInit-LINK_ADDRESS+KSEG1_BASE // non-cached address
+ jal s1 // initialize caches
+ nop
+
+/*
+//
+// TMPTMP
+//
+// li t0, (1<<PSR_DE) | (1 << PSR_CU1) | (1 << PSR_BEV)
+// mtc0 t0,psr
+
+ bal PutLedDisplay
+ ori a0,zero,0x11
+ li a0,KSEG1_BASE+(1<<20) // start of memory to write non cached
+ li a1,KSEG1_BASE+(2<<20) // start of memory to write non cached
+ li t0,0xF0F0F0F0 //
+ li t1,0xAAAAAAAA //
+ li t2,0x55555555 //
+ li t3,0x0F0F0F0F //
+10:
+ sw t0,0x0(a0)
+ sw t1,0x4(a0)
+ sw t2,0x8(a0)
+ sw t3,0xC(a0)
+ addiu a0,a0,0x10
+ bne a0,a1,10b
+ nop
+
+ bal PutLedDisplay
+ ori a0,zero,0x22
+
+ li t0,0xF0F0F0F0 //
+ li t1,0xAAAAAAAA //
+ li t2,0x55555555 //
+ li t3,0x0F0F0F0F //
+
+ li a0,KSEG0_BASE+(1<<20) // start of memory to write non cached
+ li a1,KSEG0_BASE+(2<<20) // start of memory to write non cached
+10:
+ lw v0,0x0(a0)
+ bne v0,t0,20f
+ move v1,v0
+ lw v0,0x4(a0)
+ bne v0,t1,20f
+ move v1,v0
+ lw v0,0x8(a0)
+ bne v0,t2,20f
+ move v1,v0
+ lw v0,0xC(a0)
+ bne v0,t3,20f
+ move v1,v0
+ addiu a0,a0,0x10
+ bne a0,a1,10b
+ nop
+ b 30f
+ nop
+
+20:
+ li t0,KSEG1_BASE
+ sw v1,0(t0)
+ sw v1,8(t0)
+ sw v1,0x10(t0)
+ sw v1,0x18(t0)
+ lui a0,LED_BLINK // otherwise hang
+ bal PutLedDisplay // by calling PutLedDisplay
+ ori a0,a0,0x69 // blink a 69
+
+30:
+
+// lui a0,LED_BLINK // otherwise hang
+// bal PutLedDisplay // by calling PutLedDisplay
+// ori a0,a0,0xFF // blink a FF
+*/
+
+/*
+ bal PutLedDisplay
+ ori a0,zero,0x11
+ li a0,KSEG1_BASE+(1<<20) // start of memory to write non cached
+ li a1,(1<<20) // start of memory to write non cached
+ la s1,WriteNoXorAddressTest-LINK_ADDRESS+KSEG1_BASE // address of routine in memory non cached
+ jal s1 // Write and therefore init mem.
+ move a2,zero
+
+ bal PutLedDisplay
+ ori a0,zero,0x22
+ li a0,KSEG0_BASE+(1<<20) // start of memory to write non cached
+ li a1,(1<<20) // start of memory to write non cached
+ la s1,WriteNoXorAddressTest-LINK_ADDRESS+KSEG1_BASE // address of routine in memory non cached
+ jal s1 // Write and therefore init mem.
+ move a2,zero
+
+ bal PutLedDisplay
+ ori a0,zero,0x33
+ li a0,KSEG0_BASE+(1<<20) // start of memory to write non cached
+ li a1,(1<<20) // start of memory to write non cached
+ la s1,CheckNoXorAddressTest-LINK_ADDRESS+KSEG1_BASE // address of routine in memory non cached
+ jal s1 // Write and therefore init mem.
+ move a2,zero
+ bal PutLedDisplay
+ ori a0,a0,0x44
+*/
+
+//
+// End TMPTMP
+//
+
+//
+// call routine now in cached memory to test bigger portion of memory
+//
+ bal PutLedDisplay // display that memory test
+ ori a0,zero,LED_WRITE_MEMORY_2 // is starting
+ li a0,KSEG1_BASE+MEMTEST_SIZE // start of memory to write non cached
+ li a1,FW_TOP_ADDRESS-MEMTEST_SIZE // test the memory needed to copy the code
+ // to memory, the stack and the video prom.
+ la s1,WriteNoXorAddressTest-LINK_ADDRESS+KSEG0_BASE // address of routine in memory cached
+ jal s1 // Write and therefore init mem.
+ move a2,zero // xor pattern
+ la s2,CheckNoXorAddressTest-LINK_ADDRESS+KSEG0_BASE // address of routine in memory
+ jal s2 // Check written memory
+ ori a3,zero,LED_READ_MEMORY_2 // load LED value if memory test fails
+ la s1,WriteAddressTest-LINK_ADDRESS+KSEG0_BASE // address of routine cached
+ li a0,KSEG0_BASE+MEMTEST_SIZE // start of memory now cached
+ li a2,0xDFFFFFFF // to flipp all bits
+ jal s1 // Write second time now cached.
+ la s2,CheckAddressTest-LINK_ADDRESS+KSEG0_BASE // address of routine in memory
+ jal s2 // check also cached.
+ nop
+ lui a2,0x0101
+ jal s1 // Write third time cached.
+ ori a2,a2,0x0101 // flipping some bits
+ jal s2 // check also cached.
+ nop
+
+//
+// if we come back, the piece of memory is tested and therefore initialized.
+//
+
+ //
+ // Do not force Correct ECC Data to be written during Read Modify
+ // Write Cycles any more. Since from now on memory is always cached.
+ // Or already initialized.
+ //
+ li t1,0xEE0000 // Do not Force Correct ECC on rmw
+ // ECC correction Enabled.
+ // ECC correction occurs without notification
+ mtc1 t1,f0 //
+ mtc1 zero,f1 // zero error bits
+ li t0,DMA_VIRTUAL_BASE // Get base address of MCTADR
+ sdc1 f0,DmaEccDiagnostic(t0) // Write ECC Diagnostic register
+
+//
+// If an NMI occurred. s6 contains the erorrepc.
+// the Tlb has already been initialized and the I cache flushed.
+// Copy the firmware to memory and display a message from there.
+//
+
+NMI:
+//
+// Invalidate the data caches so that the firmware can be copied to
+// noncached space without a conflict.
+//
+
+ bal InvalidateDCache
+ nop
+ bal InvalidateSCache
+ nop
+
+//
+// Copy the firmware.
+//
+ la s0,Decompress-LINK_ADDRESS+KSEG0_BASE
+ // address of decompression routine in cached space
+ la a0,end // end of this file is start of selftest
+ li a1,RAM_TEST_DESTINATION_ADDRESS
+ // destination is uncached link address.
+ jal s0 // jump to decompress
+ nop
+ bal InvalidateICache // Invalidate the instruction cache
+ nop
+
+//
+// Flush the data cache
+//
+ bal FlushDCache
+ nop
+
+//
+// Initialize the stack to the low memory and Call Rom tests.
+//
+ li t0,RAM_TEST_LINK_ADDRESS // address of copied code
+ li sp,RAM_TEST_STACK_ADDRESS // init stack
+ move a1,s6 // pass cause of exception as argument.
+ jal t0 // jump to self-test in memory
+ move a0,s5 // pass cause of exception as argument.
+99:
+ b 99b // hang if we get here.
+ nop //
+
+
+//
+// This is the initialization code for processor B.
+// At this point the processor has:
+//
+// - Initialized the TLB.
+// - Initialized the config register.
+// - Run the processor selftest
+//
+// The system has already been initialized by processor A.
+// Only the caches need to be initialized.
+//
+//
+ProcessorBReset:
+
+//
+// Call cache initialization routine in non-cached memory
+//
+ bal PutLedDisplay // display that cache init
+ ori a0,zero,LED_CACHE_INIT // is starting
+ la s1,R4000CacheInit-LINK_ADDRESS+KSEG1_BASE // non-cached address
+ jal s1 // initialize caches
+ nop
+ li t0,RAM_TEST_LINK_ADDRESS // address of copied code
+ li sp,RAM_TEST_STACK_ADDRESS_B // init stack
+ move a1,s6
+ jal t0 // jump to self-test in memory
+ move a0,s5 // pass cause of exception as argument.
+99:
+ b 99b // hang if we get here.
+ nop //
+
+
+//
+// Routines between MemoryRoutines and EndMemoryRoutines are copied
+// into memory to run them cached.
+//
+
+ .align 4 // Align it to 16 bytes boundary so that
+ ALTERNATE_ENTRY(MemoryRoutines) // DataCopy doesn't need to check alignments
+/*++
+VOID
+PutLedDisplay(
+ a0 - display value.
+ )
+Routine Description:
+
+ This routine will display in the LED the value specified as argument
+ a0.
+
+ bits [31:16] specify the mode.
+ bits [7:4] specify the Test number.
+ bits [3:0] specify the Subtest number.
+
+ The mode can be:
+
+ LED_NORMAL Display the Test number
+ LED_BLINK Loop displaying Test - Dot - Subtest
+ LED_LOOP_ERROR Display the Test number with the dot iluminated
+
+ N.B. This routine must reside in the first page of ROM because it is
+ called before mapping the rom!!
+
+Arguments:
+
+ a0 value to display.
+
+ Note: The value of the argument is preserved
+
+Return Value:
+
+ If a0 set to LED_BLINK does not return.
+
+--*/
+ LEAF_ENTRY(PutLedDisplay)
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // load address of display
+LedBlinkLoop:
+ srl t1,a0,16 // get upper bits of a0 in t1
+ srl t3,a0,4 // get test number
+ li t4,LED_LOOP_ERROR //
+ bne t1,t4, DisplayTestID
+ andi t3,t3,0xF // clear other bits.
+ ori t3,t3,LED_DECIMAL_POINT // Set decimal point
+DisplayTestID:
+ li t4,LED_BLINK // check if need to hung
+ sb t3,0(t0) // write test ID to led.
+ beq t1,t4, ShowSubtestID
+ nop
+ j ra // return to caller.
+ nop
+
+ShowSubtestID:
+ li t2,LED_DELAY_LOOP // get delay value.
+TestWait:
+ bne t2,zero,TestWait // loop until zero
+ addiu t2,t2,-1 // decrement counter
+ li t3,LED_DECIMAL_POINT+LED_BLANK
+ sb t3,0(t0) // write decimal point
+ li t2,LED_DELAY_LOOP/2 // get delay value.
+DecPointWait:
+ bne t2,zero,DecPointWait // loop until zero
+ addiu t2,t2,-1 // decrement counter
+ andi t3,a0,0xF // get subtest number
+ sb t3,0(t0) // write subtest in LED
+ li t2,LED_DELAY_LOOP // get delay value.
+SubTestWait:
+ bne t2,zero,SubTestWait // loop until zero
+ addiu t2,t2,-1 // decrement counter
+ b LedBlinkLoop // go to it again
+ nop
+ .end PutLedDisplay
+
+ LEAF_ENTRY(InvalidateICache)
+/*++
+
+Routine Description:
+
+ This routine invalidates the contents of the instruction cache.
+
+ The instruction cache is invalidated by writing an invalid tag to
+ each cache line, therefore nothing is written back to memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+//
+// invalid state
+//
+ mfc0 t5,config // read config register
+ li t0,(PRIMARY_CACHE_INVALID << TAGLO_PSTATE)
+ mtc0 t0,taglo // set tag registers to invalid
+ mtc0 zero,taghi
+
+ srl t0,t5,CONFIG_IC // compute instruction cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li t6,1 //
+ sll t6,t6,t0 // t6 = I cache size
+ srl t0,t5,CONFIG_IB // compute instruction cache line size
+ and t0,t0,1 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = I cache line size
+//
+// store tag to all icache lines
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t0,t1,t6 // get last index address
+ subu t0,t0,t7
+WriteICacheTag:
+ cache INDEX_STORE_TAG_I,0(t1) // store tag in Instruction cache
+ bne t1,t0,WriteICacheTag // loop
+ addu t1,t1,t7 // increment index
+ j ra
+ nop
+ .end InvalidateICache
+
+
+ LEAF_ENTRY(InvalidateDCache)
+/*++
+
+Routine Description:
+
+ This routine invalidates the contents of the D cache.
+
+ Data cache is invalidated by writing an invalid tag to each cache
+ line, therefore nothing is written back to memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+//
+// invalid state
+//
+ mfc0 t5,config // read config register for cache size
+ li t0, (PRIMARY_CACHE_INVALID << TAGLO_PSTATE)
+ mtc0 t0,taglo // set tag to invalid
+ mtc0 zero,taghi
+ srl t0,t5,CONFIG_DC // compute data cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li t6,1 //
+ sll t6,t6,t0 // t6 = data cache size
+ srl t0,t5,CONFIG_DB // compute data cache line size
+ and t0,t0,1 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = data cache line size
+
+//
+// store tag to all Dcache
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t2,t1,t6 // add cache size
+ subu t2,t2,t7 // adjust for cache line size.
+WriteDCacheTag:
+ cache INDEX_STORE_TAG_D,0(t1) // store tag in Data cache
+ bne t1,t2,WriteDCacheTag // loop
+ addu t1,t1,t7 // increment index by cache line
+ j ra
+ nop
+ .end InvalidateDCache
+
+
+ LEAF_ENTRY(FlushDCache)
+/*++
+
+Routine Description:
+
+ This routine flushes the whole contents of the Dcache
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+ mfc0 t5,config // read config register
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ srl t0,t5,CONFIG_DC // compute data cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li t6,1 //
+ sll t6,t6,t0 // t6 = data cache size
+ srl t0,t5,CONFIG_DB // compute data cache line size
+ and t0,t0,1 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = data cache line size
+ addu t0,t1,t6 // compute last index address
+ subu t0,t0,t7
+FlushDCacheTag:
+ cache INDEX_WRITEBACK_INVALIDATE_D,0(t1) // Invalidate data cache
+ bne t1,t0,FlushDCacheTag // loop
+ addu t1,t1,t7 // increment index
+
+//
+// check for a secondary cache.
+//
+
+ li t1,(1 << CONFIG_SC)
+ and t0,t5,t1
+ bne t0,zero,10f // if non-zero no secondary cache
+
+ li t6,SECONDARY_CACHE_SIZE // t6 = secondary cache size
+ srl t0,t5,CONFIG_SB // compute secondary cache line size
+ and t0,t0,3 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = secondary cache line size
+//
+// invalidate all secondary lines
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t0,t1,t6 // get last index address
+ subu t0,t0,t7
+FlushSDCacheTag:
+ cache INDEX_WRITEBACK_INVALIDATE_SD,0(t1) // invalidate secondary cache
+ bne t1,t0,FlushSDCacheTag // loop
+ addu t1,t1,t7 // increment index
+10:
+ j ra
+ nop
+ .end FlushDCache
+
+
+ LEAF_ENTRY(InvalidateSCache)
+/*++
+
+Routine Description:
+
+ This routine invalidates the contents of the secondary cache.
+
+ The secondary cache is invalidated by writing an invalid tag to
+ each cache line, therefore nothing is written back to memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+ mfc0 t5,config // read config register
+
+//
+// check for a secondary cache.
+//
+
+ li t1,(1 << CONFIG_SC)
+ and t0,t5,t1
+ bne t0,zero,NoSecondaryCache // if non-zero no secondary cache
+
+ li t0,(SECONDARY_CACHE_INVALID << TAGLO_SSTATE)
+ mtc0 t0,taglo // set tag registers to invalid
+ mtc0 zero,taghi
+
+ li t6,SECONDARY_CACHE_SIZE // t6 = secondary cache size
+ srl t0,t5,CONFIG_SB // compute secondary cache line size
+ and t0,t0,3 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = secondary cache line size
+//
+// store tag to all secondary lines
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t0,t1,t6 // get last index address
+ subu t0,t0,t7
+WriteSICacheTag:
+ cache INDEX_STORE_TAG_SD,0(t1) // store tag in secondary cache
+ bne t1,t0,WriteSICacheTag // loop
+ addu t1,t1,t7 // increment index
+
+NoSecondaryCache:
+ j ra
+ nop
+ .end InvalidateSCache
+
+
+ LEAF_ENTRY(InitDataCache)
+/*++
+
+Routine Description:
+
+ This routine initializes the data fields of the primary and
+ secondary data caches.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+ mfc0 t5,config // read config register
+
+//
+// check for a secondary cache.
+//
+
+ li t1,(1 << CONFIG_SC)
+ and t0,t5,t1
+ bne t0,zero,NoSecondaryCache1 // if non-zero no secondary cache
+
+ li t6,SECONDARY_CACHE_SIZE // t6 = secondary cache size
+ srl t0,t5,CONFIG_SB // compute secondary cache line size
+ and t0,t0,3 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = secondary cache line size
+//
+// store tag to all secondary lines
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t0,t1,t6 // get last index address
+ subu t0,t0,t7
+
+WriteSCacheTag:
+ cache CREATE_DIRTY_EXCLUSIVE_SD,0(t1) // store tag in secondary cache
+ bne t1,t0,WriteSCacheTag // loop
+ addu t1,t1,t7 // increment index
+
+//
+// store data to all secondary lines. 1MB
+//
+ mtc1 zero,f0 // zero f0
+ mtc1 zero,f1 // zero f1
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t0,t1,t6 // get last index address
+ subu t0,t0,t7
+
+WriteSCacheData:
+ //
+ // Init Data 64 bytes per loop.
+ //
+
+ // TMPTMP
+ move t2,t1
+ // TMPTMP
+
+
+ // TMPTMP
+ mtc1 t2,f0
+ mtc1 t2,f1
+ // TMPTMP
+
+ sdc1 f0,0(t1) // write
+
+ // TMPTMP
+ addiu t2,t2,8
+ mtc1 t2,f0
+ mtc1 t2,f1
+ // TMPTMP
+
+ sdc1 f0,8(t1) // write
+
+ // TMPTMP
+ addiu t2,t2,8
+ mtc1 t2,f0
+ mtc1 t2,f1
+ // TMPTMP
+
+ sdc1 f0,16(t1) // write
+
+ // TMPTMP
+ addiu t2,t2,8
+ mtc1 t2,f0
+ mtc1 t2,f1
+ // TMPTMP
+
+ sdc1 f0,24(t1) // write
+
+ // TMPTMP
+ addiu t2,t2,8
+ mtc1 t2,f0
+ mtc1 t2,f1
+ // TMPTMP
+
+ sdc1 f0,32(t1) // write
+
+ // TMPTMP
+ addiu t2,t2,8
+ mtc1 t2,f0
+ mtc1 t2,f1
+ // TMPTMP
+
+ sdc1 f0,40(t1) // write
+
+ // TMPTMP
+ addiu t2,t2,8
+ mtc1 t2,f0
+ mtc1 t2,f1
+ // TMPTMP
+
+ sdc1 f0,48(t1) // write
+
+ // TMPTMP
+ addiu t2,t2,8
+ mtc1 t2,f0
+ mtc1 t2,f1
+ // TMPTMP
+
+ sdc1 f0,56(t1) // write
+ bne t1,t0,WriteSCacheData // loop
+ addu t1,t1,t7 // increment index
+
+//
+// TMPTMP
+//
+
+ li t1, (1 << PSR_CU1) | (1 << PSR_BEV)
+ mtc0 t1,psr
+ nop
+ nop
+
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t0,t1,t6 // get last index address
+ subu t0,t0,t7
+
+10:
+ ldc1 f0,0(t1)
+ ldc1 f0,8(t1)
+ ldc1 f0,16(t1)
+ ldc1 f0,24(t1)
+ ldc1 f0,32(t1)
+ ldc1 f0,40(t1)
+ ldc1 f0,48(t1)
+ ldc1 f0,56(t1)
+
+ bne t1,t0,10b // loop
+ addu t1,t1,t7 // increment index
+
+
+//
+// END
+//
+
+//
+// Flush the primary data cache to the secondary cache
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ srl t0,t5,CONFIG_DC // compute data cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li t6,1 //
+ sll t6,t6,t0 // t6 = data cache size
+ srl t0,t5,CONFIG_DB // compute data cache line size
+ and t0,t0,1 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = data cache line size
+ addu t0,t1,t6 // compute last index address
+ subu t0,t0,t7
+FlushPDCacheTag:
+ cache INDEX_WRITEBACK_INVALIDATE_D,0(t1) // Invalidate data cache
+ bne t1,t0,FlushPDCacheTag // loop
+ addu t1,t1,t7 // increment index
+
+ j ra // return
+ nop
+
+NoSecondaryCache1:
+
+ srl t0,t5,CONFIG_DC // compute data cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li t6,1 //
+ sll t6,t6,t0 // t6 = data cache size
+ srl t0,t5,CONFIG_DB // compute data cache line size
+ and t0,t0,1 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = data cache line size
+
+//
+// create dirty exclusive to all Dcache
+//
+ mtc1 zero,f0 // zero f0
+ mtc1 zero,f1 // zero f1
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t2,t1,t6 // add cache size
+ subu t2,t2,t7 // adjust for cache line size.
+WriteDCacheDe:
+ cache CREATE_DIRTY_EXCLUSIVE_D,0(t1) // store tag in Data cache
+ nop
+ sdc1 f0,0(t1) // write
+ sdc1 f0,8(t1) // write
+ bne t1,t2,WriteDCacheDe // loop
+ addu t1,t1,t7 // increment index by cache line
+
+ j ra // return
+ nop
+ .end InitDataCache
+
+ LEAF_ENTRY(R4000CacheInit)
+/*++
+
+Routine Description:
+
+ This routine will initialize the cache tags and data for the
+ primary data cache, primary instruction cache, and the secondary cache
+ (if present).
+
+ Subroutines are called to invalidate all of the tags in the
+ instruction and data caches.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+ move s0,ra // save ra.
+
+//
+// Disable Cache Error exceptions.
+//
+
+ li t0, (1<<PSR_DE) | (1 << PSR_CU1) | (1 << PSR_BEV)
+ mtc0 t0,psr
+
+//
+// Invalidate the caches
+//
+
+ bal InvalidateICache
+ nop
+
+ bal InvalidateDCache
+ nop
+
+ bal InvalidateSCache
+ nop
+
+//
+// Initialize the data cache(s)
+//
+
+ bal InitDataCache
+ nop
+
+//
+// Fill the Icache, all icache lines
+//
+
+ mfc0 t5,config // read config register
+ nop
+ srl t0,t5,CONFIG_IC // compute instruction cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li s1,1 //
+ sll s1,s1,t0 // s1 = I cache size
+ srl t0,t5,CONFIG_IB // compute instruction cache line size
+ and t0,t0,1 //
+ li s2,16 //
+ sll s2,s2,t0 // s2 = I cache line size
+
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t0,t1,s1 // add I cache size
+ subu t0,t0,s2 // sub line size.
+FillICache:
+ cache INDEX_FILL_I,0(t1) // Fill I cache from memory
+ bne t1,t0,FillICache // loop
+ addu t1,t1,s2 // increment index
+
+//
+// Invalidate the caches again
+//
+ bal InvalidateICache
+ nop
+
+ bal InvalidateDCache
+ nop
+
+ bal InvalidateSCache
+ nop
+
+//
+// Enable cache error exception.
+//
+ mfc0 t0,config
+ li t1, (1 << CONFIG_IB) + (1 << CONFIG_DB) + (0 << CONFIG_CU) + \
+ (5 << CONFIG_K0)
+ li t2, 0xFFFFFFC0
+ and t0,t0,t2 // clear soft bits in config
+ or t0,t0,t1 // set soft bits in config
+ mtc0 t0,config
+ nop
+
+ li t1, (1 << PSR_CU1) | (1 << PSR_BEV)
+ mtc0 t1,psr
+ nop
+ nop
+ nop
+ move ra,s0 // move return address back to ra
+ j ra // return from routine
+ nop
+ .end R4000CacheInit
+
+
+/*++
+VOID
+WriteAddressTest(
+ StartAddress
+ Size
+ Xor pattern
+ )
+Routine Description:
+
+ This routine will store the address of each location xored with
+ the Pattern into each location.
+
+Arguments:
+
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+ a2 - supplies the pattern to Xor with.
+
+ Note: the values of the arguments are preserved.
+
+Return Value:
+
+ This routine returns no value.
+--*/
+ LEAF_ENTRY(WriteAddressTest)
+ add t1,a0,a1 // t1 = last address.
+ xor t0,a0,a2 // t0 value to write
+ move t2,a0 // t2=current address
+writeaddress:
+ sw t0,0(t2) // store
+ addiu t2,t2,4 // compute next address
+ xor t0,t2,a2 // next pattern
+ sw t0,0(t2)
+ addiu t2,t2,4 // compute next address
+ xor t0,t2,a2 // next pattern
+ sw t0,0(t2)
+ addiu t2,t2,4 // compute next address
+ xor t0,t2,a2 // next pattern
+ sw t0,0(t2)
+ addiu t2,t2,4 // compute next address
+ bne t2,t1, writeaddress // check for end condition
+ xor t0,t2,a2 // value to write
+ j ra
+ nop
+ .end WriteAddressTest
+
+/*++
+VOID
+WriteNoXorAddressTest(
+ StartAddress
+ Size
+ )
+Routine Description:
+
+ This routine will store the address of each location
+ into each location.
+
+Arguments:
+
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+
+ Note: the values of the arguments are preserved.
+
+Return Value:
+
+ This routine returns no value.
+--*/
+ LEAF_ENTRY(WriteNoXorAddressTest)
+ nop
+ nop
+ nop
+ nop
+ add t1,a0,a1 // t1 = last address.
+ addiu t1,t1,-4
+ move t2,a0 // t2=current address
+writenoXoraddress:
+ sw t2,0(t2) // store first address
+ addiu t2,t2,4 // compute next address
+ sw t2,0(t2) // store first address
+ addiu t2,t2,4 // compute next address
+ sw t2,0(t2) // store first address
+ addiu t2,t2,4 // compute next address
+ sw t2,0(t2) // store
+ bne t2,t1, writenoXoraddress // check for end condition
+ addiu t2,t2,4 // compute next address
+ j ra
+ nop
+ .end WriteNoXorAddressTest
+
+
+/*++
+VOID
+CheckAddressTest(
+ StartAddress
+ Size
+ Xor pattern
+ LedDisplayValue
+ )
+Routine Description:
+
+
+ This routine will check that each location contains it's address
+ xored with the Pattern as written by WriteAddressTest. The memory
+ is read cached or non cached according to the address specified by a0.
+ if WriteAddressTest used a KSEG1_ADR to write the data and this
+ routine is called to read KSEG0_ADR in order to read the data cached,
+ then the XOR_PATTERN Must be such that:
+
+ KSEG0_ADR ^ KSEG0_XOR = KSEG1_ADR ^ KSEG1_XOR
+
+ Examples:
+
+ If XorPattern with which WriteAddressTest was called is KSEG1_XOR
+ then the XorPattern this routine needs is KSEG0_XOR:
+
+ KSEG1_XOR Written KSEG0_XOR So that
+ 0x00000000 0xA00000000 0x20000000 0x8000000 ^ 0x2000000 = 0xA0000000
+ 0xFFFFFFFF 0x5F0000000 0xDFFFFFFF 0x8000000 ^ 0xDF00000 = 0x5F000000
+ 0x01010101 0xA10000000 0x21010101 0x8000000 ^ 0x2100000 = 0xA1000000
+
+ This allows to write non cached to initialize memory and check the same
+ data trough cached addresses.
+
+Arguments:
+
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+ a2 - supplies the pattern to Xor with.
+ a3 - suplies the value to display in the led in case of failure
+
+ Note: the values of the arguments are preserved.
+
+Return Value:
+
+ Returns a zero if no error is found.
+
+ If errors are found, this routine behaves different depending
+ on where the caller resides:
+ - If the caller is executing in KSEG0 or KSEG1 returns 1
+ - If the caller is executing im ROM_VIRT addresses the
+ routine hangs blinking the LED or looping if the loop on error
+ bit is set in the config register.
+
+--*/
+ LEAF_ENTRY(CheckAddressTest)
+ move t3,a0 // t3 first address.
+ add t2,t3,a1 // last address.
+checkaddress:
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail
+ addiu t3,t3,4 // compute next address
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail
+ addiu t3,t3,4 // compute next address
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail
+ addiu t3,t3,4 // compute next address
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail // check last one.
+ addiu t3,t3,4 // compute next address
+ bne t3,t2, checkaddress // check for end condition
+ move v0,zero // set return value to zero.
+ j ra // return a zero to the caller
+
+PatternFail:
+ //
+ // check if we are in loop on error
+ //
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register
+ lb t0,0(t0) // read register value.
+ li t1,LOOP_ON_ERROR_MASK // get value to compare
+ andi t0,DIAGNOSTIC_MASK // mask diagnostic bits.
+ li v0,PROM_ENTRY(14) // load address of PutLedDisplay
+ beq t1,t0,10f // brnach if loop on error.
+ move s8,a0 // save register a0
+ lui t0,LED_BLINK // get LED blink code
+ jal v0 // Blink LED and hang.
+ or a0,a3,t0 // pass a3 as argument in a0
+10:
+ lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code
+ jal v0 // Set LOOP ON ERROR on LED
+ or a0,a3,t0 // pass a3 as argument in a0
+ b CheckAddressTest // Loop back to test again.
+ move a0,s8 // restoring arguments.
+ .end CheckAddressTest
+
+/*++
+VOID
+CheckNoXorAddressTest(
+ StartAddress
+ Size
+ not used
+ LedDisplayValue
+ )
+Routine Description:
+
+ This routine will check that each location contains it's address.
+ as written by WriteNoXorAddressTest.
+
+Arguments:
+
+ Note: the values of the arguments are preserved.
+
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+ a2 - Not used
+ a3 - suplies the value to display in the led in case of failure
+
+Return Value:
+
+ This routine returns no value.
+ The routine hangs blinking the LED or looping if the loop on error
+ bit is set in the config register.
+--*/
+ LEAF_ENTRY(CheckNoXorAddressTest)
+ addiu t3,a0,-4 // t3 first address-4
+ add t2,a0,a1 // last address.
+ addiu t2,t2,-8 // adjust
+ move t1,t3 // get copy of t3 just for first check
+checkaddressNX:
+ bne t1,t3,PatternFailNX
+ lw t1,4(t3) // load from first location
+ addiu t3,t3,4 // compute next address
+ bne t1,t3,PatternFailNX
+ lw t1,4(t3) // load from next location
+ addiu t3,t3,4 // compute next address
+ bne t1,t3,PatternFailNX
+ lw t1,4(t3) // load from next location
+ addiu t3,t3,4 // compute next address
+ bne t1,t3,PatternFailNX // check
+ lw t1,4(t3) // load from next location
+ bne t3,t2, checkaddressNX // check for end condition
+ addiu t3,t3,4 // compute next address
+ bne t1,t3,PatternFailNX // check last
+ nop
+ j ra // return a zero to the caller
+ move v0,zero //
+PatternFailNX:
+ //
+ // check if we are in loop on error
+ //
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register
+ lb t0,0(t0) // read register value.
+ li t1,LOOP_ON_ERROR_MASK // get value to compare
+ andi t0,DIAGNOSTIC_MASK // mask diagnostic bits.
+ li v0,PROM_ENTRY(14) // load address of PutLedDisplay
+ beq t1,t0,10f // brnach if loop on error.
+ move s8,a0 // save register a0
+ lui t0,LED_BLINK // get LED blink code
+ jal v0 // Blink LED and hang.
+ or a0,a3,t0 // pass a3 as argument in a0
+10:
+ lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code
+ jal v0 // Set LOOP ON ERROR on LED
+ or a0,a3,t0 // pass a3 as argument in a0
+ b CheckNoXorAddressTest // Loop back to test again.
+ move a0,s8 // restoring arguments.
+ .end CheckNoXorAddressTest
+
+
+/*++
+VOID
+ZeroMemory(
+ ULONG StartAddress
+ ULONG Size
+ );
+Routine Description:
+
+ This routine will zero a range of memory.
+
+Arguments:
+
+ a0 - supplies start of memory
+ a1 - supplies length of memory in bytes
+
+Return Value:
+
+ None.
+
+--*/
+ LEAF_ENTRY(ZeroMemory)
+ add a1,a1,a0 // Compute End address
+ addiu a1,a1,-4 // adjust address
+ZeroMemoryLoop:
+ sw zero,0(a0) // zero memory.
+ bne a0,a1,ZeroMemoryLoop // loop until done.
+ addiu a0,a0,4 // compute next address
+ j ra // return
+ nop
+ ALTERNATE_ENTRY(ZeroMemoryEnd)
+ nop
+ .end ZeroMemory
+
+//++
+//
+//PULONG
+//Decompress(
+// IN PULONG InputImage,
+// IN PULONG OutputImage
+// )
+//
+//
+//Routine Description:
+//
+// This routine decompresses the input image.
+//
+//Arguments:
+//
+// InputImage (a0) - byte pointer to the image to be decompressed.
+// OutputImage (a1) - byte pointer to the area to write decompressed image.
+//
+// N.B. The first ULONG of the InputImage contains the decompressed length in bytes.
+// See romcomp.c for a description of method.
+//
+//Return Value:
+//
+// None.
+//
+//--
+
+.set reorder
+ LEAF_ENTRY(Decompress)
+
+ lw a2,(a0) // get the target size.
+ srl a2,a2,2 // get size of output in words/symbols.
+ addiu a0,a0,4 // address of next word
+ move a3,a1 // stash output image base
+
+//
+// Calculate the offset width from the size. Assume size > 2 ULONG.
+//
+#define SHORT_INDEX_WIDTH 10
+
+ li t8,1 // start at two
+ srl t0,a2,1 // offset must only span half the image.
+5:
+ addiu t8,t8,1 // next bit
+ srl t1,t0,t8 // shift off low bits
+ bgtz t1,5b // quit when we find the highest set bit.
+
+//
+// Set the symbol register bit count to zero so that on the first iteration of the loop we will
+// get the first symbol longword. Add one to the symbol count to allow for first loop entry.
+//
+
+ li t1,0 // number of valid bits
+ addiu a2,a2,1 // increment symbol count
+
+//
+// Loop, decompressing the data. There is always at least one bit in the register at this point.
+//
+
+10:
+
+//
+// Decrement the symbol count and exit the loop when done.
+//
+
+ addiu a2,a2,-1 // decrement symbol count
+ beq zero,a2,99f // return
+
+//
+// Load symbol register if it is empty.
+//
+
+ bne zero,t1,12f // check for lack of bits
+ lw t0,(a0) // get the next word
+ addiu a0,a0,4 // address of next word
+ li t1,32 // number of valid bits
+12:
+
+//
+// Test first bit of symbol
+//
+
+ andi t2,t0,0x1 // test the low bit
+ addiu t1,t1,-1 // decrement bit count
+ srl t0,t0,1 // shift symbol
+ bne zero,t1,20f // check for lack of bits
+ lw t0,(a0) // get the next word
+ addiu a0,a0,4 // address of next word
+ li t1,32 // number of valid bits
+20:
+ bne zero,t2,50f // if not zero then this is an index
+
+30:
+
+//
+// First bit of symbol is zero, this is the zero or unique case. Check the next bit.
+//
+
+ andi t2,t0,0x1 // test the low bit
+ addiu t1,t1,-1 // decrement bit count
+ srl t0,t0,1 // shift symbol
+ bne zero,t2,40f // if not zero then this is a unique word symbol
+
+//
+// This is the zero case. 0b00
+//
+
+ sw zero,(a1) // store the zero
+ addiu a1,a1,4 // increment the output image pointer
+ b 10b // go get the next symbol.
+
+//
+// The symbol is a unique word. 0b10. Get the next 32 bits and write them to the output.
+//
+// The symbol register contains 0 to 31 bits of the word to be written. Get the next
+// word, shift and merge it with the existing symbol to produce a complete word. The remainder
+// of the new word becomes the next symbol register contents.
+//
+// Note that since we read a new word we don't have to decrement the bit counter since it runs
+// mod 32.
+//
+
+40:
+ lw t3,(a0) // get next word
+ addiu a0,a0,4 // address of next word
+
+ sll t2,t3,t1 // shift it by the bit count
+ or t0,t0,t2 // put it in with the existing contents of the symbol register
+
+ sw t0,(a1) // store the word
+ addiu a1,a1,4 // increment the output image pointer
+
+ li t2,32 // get shift count for new word to make new symbol register
+ subu t2,t2,t1 //
+ srl t0,t3,t2 // new contents of symbol register. For bit count zero case
+ // this is a nop
+
+ b 10b // go get the next symbol.
+
+//
+// This is the index case. 0bX1. Now the next bit determines whether the offset is relative(1) or
+// absolute(0). Stash the next bit for when we use the offset.
+//
+
+50:
+ andi t4,t0,0x1 // get the relative/absolute bit
+ addiu t1,t1,-1 // decrement bit count
+ srl t0,t0,1 // shift symbol
+ bne zero,t1,55f // check for lack of bits
+ lw t0,(a0) // get the next word
+ addiu a0,a0,4 // address of next word
+ li t1,32 // number of valid bits
+55:
+
+//
+// Get the next bit. This tells us whether we have a long(0) or a short(1) index.
+//
+
+ andi t2,t0,0x1 // test the low bit
+ addiu t1,t1,-1 // decrement bit count
+ srl t0,t0,1 // shift symbol
+ bne zero,t1,60f // check for lack of bits
+ lw t0,(a0) // get the next word
+ addiu a0,a0,4 // address of next word
+ li t1,32 // number of valid bits
+60:
+ li t5,SHORT_INDEX_WIDTH // preload with short index width
+ bne zero,t2,70f // if not zero then this is a short index.
+ move t5,t8 // use long index width
+
+//
+// Get the index based on the width. If the currently available bits are less than the
+// number that we need then we must read another word.
+//
+70:
+ li t7,0 // zero the remainder
+ sub t2,t5,t1 // get difference between what we need and what we have
+ blez t2,75f // if we got what we need
+
+ lw t6,(a0) // get next word
+ addiu a0,a0,4 // address of next word
+ sll t7,t6,t1 // shift new bits into position
+ or t0,t0,t7 // move new bits into symbol register
+ srl t7,t6,t2 // adjust remainder
+ addiu t1,t1,32 // pre-bias the bit count for later decrement.
+
+75:
+ li t3,1 // grab a one
+ sll t3,t3,t5 // shift it by number of bits we will extract
+ addiu t3,t3,-1 // make a mask
+ and t2,t0,t3 // grab the index
+ sll t2,t2,2 // make it a byte index
+ srl t0,t0,t5 // shift out bits we used.
+ or t0,t0,t7 // merge in remainder if any.
+ sub t1,t1,t5 // decrement the bit count, correct regardless
+
+//
+// Use index to write output based on the absolute(0)/relative(1) bit.
+//
+80:
+ bne zero,t4,85f // test for the relative case.
+ addu t3,a3,t2 // address by absolute
+ b 87f // go move the word
+85:
+ subu t3,a1,t2 // address by relative
+
+//
+// Move the byte.
+//
+87:
+ lw t2,(t3) // get the word
+ sw t2,(a1) // store the word
+ addiu a1,a1,4 // increment output pointer
+ b 10b // go do next symbol
+
+//
+// Return
+//
+
+99:
+
+ j ra // return
+
+ .end Decompress
+.set noreorder
+
+/*++
+VOID
+DataCopy(
+ ULONG SourceAddress
+ ULONG DestinationAddress
+ ULONG Length
+ );
+Routine Description:
+
+ This routine will copy data from one location to another
+ Source, destination, and length must be dword aligned.
+
+ For DUO since 64 bit reads from the prom are not supported, the
+ reads and writes are done word by word.
+
+Arguments:
+
+ a0 - supplies source of data
+ a1 - supplies destination of data
+ a2 - supplies length of data in bytes
+
+Return Value:
+
+ None.
+--*/
+
+
+ LEAF_ENTRY(DataCopy)
+
+ add a2,a2,a0 // get last address
+CopyLoop:
+ lw t0, 0(a0) // load 1st word
+ lw t1, 4(a0) // load 2nd word
+ lw t2, 8(a0) // load 3rd word
+ lw t3,12(a0) // load 4th word
+ addiu a0,a0,16 // increment source pointer
+ sw t0, 0(a1) // load 1st word
+ sw t1, 4(a1) // load 2nd word
+ sw t2, 8(a1) // load 3rd word
+ sw t3,12(a1) // load 4th word
+ bne a0,a2,CopyLoop // loop until address=last address
+ addiu a1,a1,16 // increment destination pointer
+ j ra // return
+ nop
+ .align 4 // Align it to 16 bytes boundary so that
+ ALTERNATE_ENTRY(EndMemoryRoutines) // DataCopy doesn't need to check alignments
+ nop
+ .end DataCopy
+
+/*++
+VOID
+ProcessorTest(
+ VOID
+ );
+
+Routine Description:
+
+ This routine tests the processor. Test uses all registers and almost all
+ the instructions.
+
+ N.B. This routine destroys the values in all of the registers.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None, but will hang flashing the led if an error occurs.
+
+--*/
+ LEAF_ENTRY(ProcessorTest)
+ lui a0,0x1234 // a0=0x12340000
+ ori a1,a0,0x4321 // a1=0x12344321
+ add a2,zero,a0 // a2=0x12340000
+ addiu a3,zero,-0x4321 // a3=0xFFFFBCDF
+ subu AT,a2,a3 // AT=0x12344321
+ bne a1,AT,ProcessorError // branch if no match match
+ andi v0,a3,0xFFFF // v0=0x0000BCDF
+ ori v1,v0,0xFFFF // v1=0x0000FFFF
+ sll t0,v1,16 // t0=0xFFFF0000
+ xor t1,t0,v1 // t1=0xFFFFFFFF
+ sra t2,t0,16 // t2=0xFFFFFFFF
+ beq t1,t2,10f // if eq good
+ srl t3,t0,24 // t3=0x000000FF
+ j ProcessorError // if wasn't eq error.
+10: sltu s0,t0,v1 // S0=0 because t0 > v1
+ bgtz s0,ProcessorError // if s0 > zero error
+ or t4,AT,v0 // t4=X
+ bltz s0,ProcessorError // if s0 < zero error
+ nor t5,v0,AT // t5=~X
+ and t6,t4,t5 // t6=0
+ move s0,ra // save ra in s0
+ bltzal t6,ProcessorError // if t6 < 0 error, load ra in case
+ nop
+RaAddress:
+ //la t7,RaAddress - LINK_ADDRESS + RESET_VECTOR // get expected address in ra
+ la t7,RaAddress // get expected address in ra
+ bne ra,t7,ProcessorError // error if don't match
+ move ra,s0 // put ra back
+ ori s1,zero,0x100 // load constant
+ mult s1,t3 // 0x100*0xFF
+ mfhi s3 // s3=0
+ mflo s2 // s2=0xFF00
+ blez s3,10f // branch if correct
+ sll s4,t3,zero // move t3 into s4
+ addiu s4,100 // change value in s4 to produce an error
+10: divu s5,s2,s4 // divide 0xFF00/0xFF
+ nop
+ nop
+ mfhi s6 // remainder s6=0
+ bne s5,s1,ProcessorError
+ nop
+ blez s6,10f // branch if no error
+ nop
+ j ProcessorError
+10: sub s7,s5,s4 // s7=1
+ mthi s7
+ mtlo AT
+ xori gp,s5,0x2566 // gp=0x2466
+ move s0,sp // save sp for now
+ srl sp,gp,s7 // sp=0x1233
+ mflo s8 // s8=0x12344321
+ mfhi k0 // k0=1
+ ori k1,zero,16 // k1=16
+ sra k1,s8,k1 // k1=0x1234
+ add AT,sp,k0 // AT=0x1234
+ bne k1,AT,ProcessorError // branch on error
+ nop
+#ifdef R4001
+ //
+ // Some extra stuff added to verify that the R4000 bug is fixed
+ // If it hangs a minus sign will be displayed in the LED
+ //
+ li t0,DIAGNOSTIC_VIRTUAL_BASE
+ li t1,0xB // value to display '-' in the LED
+ sw t1,0(t0) // write to the LED should be sb
+ lw t2,8(t0) // do something
+ sll t5,t0,t1 // 2 cycle instruction
+#endif
+ j ra // return
+ nop
+ProcessorError:
+ lui a0,LED_BLINK // blink also means that
+ bal PutLedDisplay // the routine hangs.
+ ori a0,LED_PROCESSOR_TEST // displaying this value.
+ .end ProcessorTest
+
+
+/*++
+VOID
+MctadrReset(
+ VOID
+ );
+
+Routine Description:
+
+ This routine tests the reset values of the MP_ADR asic.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None, but will hang flashing the led if an error occurs.
+
+--*/
+ LEAF_ENTRY(MctadrResetTest)
+ move s0,ra // save return address.
+//
+// Test the mctadr reset values.
+//
+MctadrReset:
+ li t0,DMA_VIRTUAL_BASE // Get base address of MP_ADR
+ lw v0,DmaConfiguration(t0) // Check Config reset value
+ li t1,CONFIG_RESET_MP_ADR_REV1 // Check for REV1 ASIC, i.e. DUO
+ bne v0,t1,MctadrResetError
+ lw v0,DmaRevisionLevel(t0) // Get revision level register
+ bne v0,zero,MctadrResetError // If not REV1 Error
+
+ addiu t1,t0,DmaInterruptEnable //
+ // enable register in REV2
+ li v0,0x1f // MCTADR interrupt enable mask
+ sw v0,0(t1) // Enable all interrupts in MCTADR
+
+10:
+ lw v0,DmaInvalidAddress(t0)
+ lw v1,DmaTranslationBase(t0)
+ bne v0,zero,MctadrResetError // Check LFAR reset value
+ lw v0,DmaTranslationLimit(t0)
+ bne v1,zero,MctadrResetError // Check Ttable base reset value
+ lw v1,DmaRemoteFailedAddress(t0)
+ bne v0,zero,MctadrResetError // Check TT limit reset value
+ lw v0,DmaMemoryFailedAddress(t0)
+ bne v1,zero,MctadrResetError // Check RFAR reset value
+ lw v1,DmaChannelInterruptAcknowledge(t0)
+ bne v0,zero,MctadrResetError // Check MFAR reset value
+ addiu t1,t0,DmaRemoteSpeed0 // address of REM_SPEED 0
+ bne v1,zero,MctadrResetError // Check Channel Interrup Ack reset value
+ addiu t2,t0,DmaRemoteSpeed14 // address of REM_SPEED 14
+ lw v0,0(t1) // read register
+ li t3,REMSPEED_RESET //
+ addiu t1,t1,8 // next register address.
+NextRemSpeed:
+ bne v0,t3,MctadrResetError // Check Rem speed reg reset value
+ lw v0,0(t1) // read next rem speed
+ bne t1,t2,NextRemSpeed
+ addiu t1,t1,8 // next register address.
+ bne v0,t3,MctadrResetError // Check last Rem speed reg reset value
+ addiu t1,t0,DmaChannel0Mode // address of first channel register
+ addiu t2,t0,DmaChannel3Address // address of last channel register
+ lw v0,0(t1) // read register
+ addiu t1,t1,8 // next register address.
+NextChannelReg:
+ bne v0,zero,MctadrResetError // Check channel reg reset value
+ lw v0,0(t1) // read next channel
+ bne t1,t2,NextChannelReg
+ addiu t1,t1,8 // next register address.
+ bne v0,zero,MctadrResetError // Check last channel reg reset value
+
+ lw v0,DmaArbitrationControl(t0)
+ bne v0,zero,MctadrResetError // check IO arbitration reset value
+ lw v1,DmaErrortype(t0) // read eisa/ethernet error reg
+ lw v0,DmaRefreshRate(t0)
+ bne v1,zero,MctadrResetError // check Eisa error type reset value
+ li t1,REFRRATE_RESET
+ bne v0,t1,MctadrResetError // check Refresh rate reset value
+ lw v0,DmaSystemSecurity(t0)
+ li t1,SECURITY_RESET
+ bne v0,t1,MctadrResetError // check Security reg reset value
+ lw v0,DmaEisaInterruptAcknowledge(t0) // read register but don't check
+
+ addiu t1,t0,DmaIoCacheLowByteMask0// address of first bytemask register
+ addiu t2,t0,DmaIoCacheHighByteMask7// address of last Byte Mask register.
+ lw v0,0(t1) // read register
+ addiu t1,t1,8 // next register address.
+NextByteMaskReg:
+ bne v0,zero,MctadrResetError // Check ByteMask reg reset value
+ lw v0,0(t1) // read next register
+ bne t1,t2,NextByteMaskReg // Loop
+ addiu t1,t1,8 // next register address.
+ j s0 // return to caller
+MctadrResetError:
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register
+ lb t0,0(t0) // read register value.
+ li t1,LOOP_ON_ERROR_MASK // get value to compare
+ andi t0,DIAGNOSTIC_MASK // mask diagnostic bits.
+ beq t1,t0,10f // branch if loop on error.
+ ori a0,zero,LED_MCTADR_RESET// load LED display value.
+ lui t0,LED_BLINK // get LED blink code
+ bal PutLedDisplay // Blink LED and hang.
+ or a0,a0,t0 // pass argument in a0
+10:
+ lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code
+ bal PutLedDisplay // Set LOOP ON ERROR on LED
+ or a0,a0,t0 // pass argument in a0
+ b MctadrReset
+ nop
+ .end MctadrResetTest
+
+/*++
+VOID
+MctadrRegisterTest(
+ VOID
+ );
+
+Routine Description:
+
+ This routine tests the MP_ADR registers.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None, but will hang flashing the led if an error occurs.
+
+--*/
+ LEAF_ENTRY(MctadrRegisterTest)
+ move s0,ra // save return address.
+//
+// Check the data path between R4K and Mctadr by writing to Byte mask reg.
+//
+MctadrReg:
+ li t0,DMA_VIRTUAL_BASE
+ li t1,0x5 // 2Mb Video Map Prom
+ sw t1,DmaConfiguration(t0) // Init Global Config
+ lw v0,DmaConfiguration(t0) // Read Configuration
+ bne v0,t1,MctadrRegError // check GLOBAL CONFIG
+ li t1,1
+ sw t1,DmaIoCacheLogicalTag0(t0) // Set LFN=zero, Offset=0 , Direction=READ from memory, Valid
+ li t2,0x55555555
+ sw t2,DmaIoCacheLowByteMask0(t0) // write pattern to LowByte mask
+ li t3,0xAAAAAAAA
+ sw t3,DmaIoCacheHighByteMask0(t0) // write pattern to HighByte mask
+ lw v0,DmaIoCacheLowByteMask0(t0) // Read LowByte mask
+ lw v1,DmaIoCacheHighByteMask0(t0) // Read HighByte mask
+ bne v0,t2,MctadrRegError //
+ sw t1,DmaIoCachePhysicalTag0(t0) // PFN=0 and Valid
+ bne v1,t3,MctadrRegError //
+ sw t3,DmaIoCacheLowByteMask0(t0) // write pattern to LowByte mask
+ sw t2,DmaIoCacheHighByteMask0(t0) // write pattern to HighByte mask
+ li t2,0xFFFFFFFF // expected value
+ lw v0,DmaIoCacheLowByteMask0(t0) // Read LowByte mask
+ bne v0,t2,MctadrRegError // Check byte mask
+ lw v1,DmaIoCacheHighByteMask0(t0) // Read HighByte mask
+ bne v1,t2,MctadrRegError // Check byte mask
+ li a0,0xA0000000 // get memory address zero.
+ sw zero,0(a0) // write address zero -> flushes buffers
+ lw v0,DmaIoCacheLowByteMask0(t0) // Read LowByte mask
+ bne v0,zero,MctadrRegError // Check byte mask was cleared.
+ lw v1,DmaIoCacheHighByteMask0(t0) // Read HighByte mask
+ bne v1,zero,MctadrRegError // Check byte mask was cleared.
+
+ li t4,MEMORY_REFRESH_RATE //
+ sw t4,DmaRefreshRate(t0) //
+ li t2,0x15555000 //
+ sw t2,DmaTranslationBase(t0) // write base of Translation Table
+ li t3,0xAAA0
+ sw t3,DmaTranslationLimit(t0) // write to TT_limit
+ lw v1,DmaTranslationBase(t0) // read TT Base
+ lw v0,DmaTranslationLimit(t0) // read TT_limit
+ bne v1,t2,MctadrRegError // check TT-BASE
+ lw v1,DmaRefreshRate(t0)
+ bne v0,t3,MctadrRegError // check TT-LIMIT
+ li t2,0x5550
+ bne v1,t4,MctadrRegError // check REFRESH Rate
+ li t1,0xAAAA000
+ sw t1,DmaTranslationBase(t0) // write to Translation Base
+ sw t2,DmaTranslationLimit(t0) // write to Translation Limit
+ lw v0,DmaTranslationBase(t0) // read TT Base
+ lw v1,DmaTranslationLimit(t0) // read TT limit
+ bne v0,t1,MctadrRegError // check TT Base
+ li t1,TT_BASE_ADDRESS // Init translation table base address
+ sw t1,DmaTranslationBase(t0) // Initialize TT Base
+ bne v1,t2,MctadrRegError // check TT Limit
+ nop
+ sw zero,DmaTranslationLimit(t0) // clear TT Limit
+
+//
+// Initialize remote speed registers.
+//
+ addiu t1,t0,DmaRemoteSpeed1 // address of REM_SPEED 1
+ la a1,RomRemoteSpeedValues // - LINK_ADDRESS + RESET_VECTOR //
+ addiu t2,a1,14 // addres of last value
+WriteNextRemSpeed:
+ lbu v0,0(a1) // load init value for rem speed
+ addiu a1,a1,1 // compute next address
+ sw v0,0(t1) // write to rem speed reg
+ bne a1,t2,WriteNextRemSpeed // check for end condition
+ addiu t1,t1,8 // next register address
+ addiu a1,t2,-14 // address of first value for rem speed register
+ addiu t1,t0,DmaRemoteSpeed1 // address of REM_SPEED 1
+ lbu v1,0(a1) // read expected value
+CheckNextRemSpeed:
+ lw v0,0(t1) // read register
+ addiu a1,a1,1 // address of next value
+ bne v0,v1,MctadrRegError // check register
+ addiu t1,t1,8 // address of next register
+ bne a1,t2,CheckNextRemSpeed // check for end condition
+ lbu v1,0(a1) // read expected value
+
+//
+// Initialize the IO Arb register
+//
+ li v0,2
+ sw v0,DmaArbitrationControl(t0)
+//
+// Now test the DMA channel registers
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,4*DMA_CHANNEL_GAP // last address of channel regs
+ li a0,0x15 // Mode
+ li a1,0x2 // enable
+ li a2,0xAAAAA // byte count
+ li a3,0x555555 // address
+WriteNextChannel:
+ sw a0,0(t1) // write mode
+ sw a1,0x8(t1) // write enable
+ sw a2,0x10(t1) // write byte count
+ sw a3,0x18(t1) // write address
+ addiu t1,t1,DMA_CHANNEL_GAP // compute address of next channel
+ addiu a2,a2,1 // change addres
+ bne t1,t2,WriteNextChannel
+ addiu a3,a3,-1 // change Byte count
+//
+// Check channel regs.
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,4*DMA_CHANNEL_GAP // last address of channel regs
+ li a2,0xAAAAA // byte count
+ li a3,0x555555 // address
+CheckNextChannel:
+ lw t4,0x0(t1) // read mode
+ lw t5,0x8(t1) // read enable
+ bne t4,a0,MctadrRegError // check mode
+ lw t4,0x10(t1) // read byte count
+ bne t5,a1,MctadrRegError // check enable
+ lw t5,0x18(t1) // read address
+ bne t4,a2,MctadrRegError // check abyte count
+ addiu a2,a2,1 // next expected byte count
+ bne t5,a3,MctadrRegError // check address
+ addiu t1,t1,DMA_CHANNEL_GAP // next channel address
+ bne t1,t2,CheckNextChannel
+ addiu a3,a3,-1
+//
+// Now do a second test on DMA channel registers
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,4*DMA_CHANNEL_GAP // last address of channel regs
+ li a0,0x2A // Mode
+ li a2,0x55555 // byte count
+ li a3,0xAAAAAA // address
+WriteNextChannel2:
+ sw a0,0(t1) // write mode
+ sw a2,0x10(t1) // write byte count
+ sw a3,0x18(t1) // write address
+ addiu t1,t1,DMA_CHANNEL_GAP // compute address of next channel
+ addiu a2,a2,1 // change addres
+ bne t1,t2,WriteNextChannel2
+ addiu a3,a3,-1 // change Byte count
+//
+// Check channel regs.
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,4*DMA_CHANNEL_GAP // last address of channel regs
+ li a2,0x55555 // byte count
+ li a3,0xAAAAAA // address
+CheckNextChannel2:
+ lw t4,0x0(t1) // read mode
+ lw t5,0x10(t1) // read byte count
+ bne t4,a0,MctadrRegError // check mode
+ lw t4,0x18(t1) // read address
+ bne t5,a2,MctadrRegError // check abyte count
+ addiu a2,a2,1 // next expected byte count
+ bne t4,a3,MctadrRegError // check address
+ addiu t1,t1,DMA_CHANNEL_GAP // next channel address
+ bne t1,t2,CheckNextChannel2
+ addiu a3,a3,-1
+//
+// Now zero the channel registers
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,4*DMA_CHANNEL_GAP // last address of channel regs
+ZeroChannelRegs:
+ addiu t1,t1,8
+ sw zero,-8(t1) // clear reg
+ bne t1,t2,ZeroChannelRegs
+ nop //R4KFIX
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,4*DMA_CHANNEL_GAP // last address of channel regs
+CheckZeroedChannelRegs:
+ lw a0,0(t1)
+ bne a0,zero,MctadrRegError // check
+ addiu t1,t1,8 // next channel
+ bne t1,t2,CheckZeroedChannelRegs
+ nop
+ j s0 // return to caller.
+MctadrRegError:
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register
+ lb t0,0(t0) // read register value.
+ li t1,LOOP_ON_ERROR_MASK // get value to compare
+ andi t0,DIAGNOSTIC_MASK // mask diagnostic bits.
+ beq t1,t0,10f // branch if loop on error.
+ ori a0,zero,LED_MCTADR_REG // load LED display value.
+ lui t0,LED_BLINK // get LED blink code
+ bal PutLedDisplay // Blink LED and hang.
+ or a0,a0,t0 // pass argument in a0
+10:
+ lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code
+ bal PutLedDisplay // Set LOOP ON ERROR on LED
+ or a0,a0,t0 // pass argument in a0
+ b MctadrReg
+ nop
+ .end MctadrRegisterTest
+
+/*
+
+ LEAF_ENTRY(SizeMemory)
+ .set noat
+ .set noreorder
+ li t0,DMA_VIRTUAL_BASE+DmaMemoryConfig0
+ li t1,0x5
+ sw t1,0x0(t0)
+ li t1,0x1000005
+ sw t1,0x8(t0)
+ li t1,0x2000005
+ sw t1,0x10(t0)
+ li t1,0x3000005
+ sw t1,0x18(t0)
+ j ra
+ nop
+ExpectedParityException:
+ .end
+ LEAF_ENTRY(SizeMemory)
+ .set noat
+ .set noreorder
+ li t0,DMA_VIRTUAL_BASE+DmaMemoryConfig0
+ li t1,0xD
+ sw t1,0x0(t0)
+ li t1,0x200000D
+ sw t1,0x8(t0)
+ li t1,0x400000D
+ sw t1,0x10(t0)
+ li t1,0x600000D
+ sw t1,0x18(t0)
+ j ra
+ nop
+ExpectedParityException:
+ .end
+*/
+
+/*++
+SizeMemory(
+ );
+Routine Description:
+
+ This routine sizes the memory and writes the proper value into
+ the GLOBAL CONFIG register. The way memory is sized is the following:
+
+ For Each of the four Memory Groups:
+ ConfigurationRegister is set to 0xE
+
+ ID0 is written to offset 0 from base of bank
+ ID4 is written to offset 4MB from base of bank
+ ID20 is written to offset 20MB from base of bank
+ if ID20 is found at offset 0 the current bank has 1MB SIMMs.
+ if ID0 is found at offset 0 and ID20 is found at offset 4,
+ the current bank has 4MB SIMMs.
+ if ID0 is found at offset 0 and ID4 is found at offset 4
+ and ID20 is found at offset 20, the current bank has 16MB SIMMs.
+ if data does not match or a parity exception is taken
+ then memory is not present in that bank.
+
+ Once The size of the first side is determined, the second side
+ is checked.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the installed memory is inconsistent, does not return
+ and the LED flashes A.E
+
+--*/
+
+#define MEM_ID0 0x0A0A0A0A
+#define MEM_ID4 0xF5F5F5F5
+#define MEM_ID20 0xA0A0A0A0
+
+ LEAF_ENTRY(SizeMemory)
+ .set noat
+ .set noreorder
+
+//
+// Size Memory for DUO
+//
+#define SIZE_1MBIT 0x0000 // Low byte. Shift value
+#define SIZE_4MBIT 0x0102 // High byte configuration value.
+#define SIZE_16MBIT 0x0204
+//
+// Size memory for duo.
+//
+ li t1,MEM_ID0 // get ID0
+ li t3,MEM_ID4 // get ID4
+ li t5,MEM_ID20 // get ID20
+ li s0,8 // counts how many banks left to check
+ li s1,DMA_VIRTUAL_BASE+DmaMemoryConfig0
+
+
+DSizeGroup:
+ li t0,0xA0000000 // get address 0MB
+ li t2,0xA0400000 // get address 4MB
+ li t4,0xA1400000 // get address 20MB
+ li a2,0xE // Memory Config Full Enable Value
+ sw a2,0(s1) // Store it.
+
+DSizeBank:
+ li a1,SIZE_1MBIT // set current bank to 1 MB by default
+ sw t1,0x0(t0) // fill whole memory line at base of bank
+ sw t1,0x4(t0)
+ sw t1,0x8(t0)
+ sw t1,0xC(t0)
+ sw t3,0x0(t2) // fill whole memory line at base of bank + 4MB
+ sw t3,0x4(t2)
+ sw t3,0x8(t2)
+ sw t3,0xC(t2)
+ sw t5,0x0(t4) // fill whole memory line at base of bank + 20MB
+ sw t5,0x4(t4)
+ sw t5,0x8(t4)
+ sw t5,0xC(t4)
+ //
+ // Check written data
+ //
+ move v1,zero // init v1 to zero
+ .align 4 // align address so that Parity Handler
+ // can easily determine if it happened here
+ExpectedParityException:
+ lw t6,0x0(t0) // read whole memory line.
+ lw t7,0x4(t0) // the four words must be identical
+ lw t8,0x8(t0) //
+ lw t9,0xC(t0) //
+ParityExceptionReturnAddress:
+ bne v1,zero,10f // if v1!=0 Parity exception occurred.
+ move a0,zero // tells that bank not present
+ bne t6,t7,10f // check for consistency
+ nop
+ bne t6,t8,10f // check for consistency
+ nop
+ bne t6,t9,10f // check for consistency
+ nop
+ beq t6,t5,10f // If ID20 is found at 0MB
+ li a0,0x4 // bank is present and SIMMS are 1 MB
+ bne t6,t1,10f // if neither ID20 nor ID0 is found we are in trouble
+ move a0,zero // no memory in bank
+ li a0,0x4 // bank is present
+
+ //
+ // ID written at Address 0 has been correctly checked
+ // Now check the ID written at address 4MB
+ //
+ lw t6,0x0(t2) // read the whole memory line.
+ lw t7,0x4(t2) // the four words must be identical
+ bne t6,t7,WrongMemory // check for consistency
+ lw t8,0x8(t2) //
+ bne t6,t8,WrongMemory // check for consistency
+ lw t9,0xC(t2) //
+ bne t6,t9,WrongMemory // check for consistency
+ nop
+ beq t6,t5,10f // If ID20 is found at 4MB
+ li a1,SIZE_4MBIT // bank is present and SIMMS are 4 MB
+ bne t6,t3,WrongMemory // if neither ID20 nor ID4 is found we are in trouble
+ nop
+ //
+ // ID written at Address 4MB has been correctly checked
+ // Now check the ID written at address 20MB
+ //
+ lw t6,0x0(t4) // read the whole memory line.
+ lw t7,0x4(t4) // the four words must be identical
+ bne t6,t7,WrongMemory // check for consistency
+ lw t8,0x8(t4) //
+ bne t6,t8,WrongMemory // check for consistency
+ lw t9,0xC(t4) //
+ bne t6,t9,WrongMemory // check for consistency
+ nop
+ bne t6,t5,WrongMemory // if ID20 is not found we are in trouble
+ nop
+ li a1,SIZE_16MBIT // If all matches SIMMs are 16MB
+
+10: //
+ // a0 has the value 0 if no memory in bank, 4 if memory in bank
+ //
+ // The lower byte of a1 has the amount the constant 4MB should be
+ // left shifted by to get the nex address.
+ // The second byte of a12 has the matching value for the SIMM
+ // size bits of the Configuration register.
+ //
+
+ andi AT,s0,1 // Check if first side
+ bne AT,zero,GroupDone // Branch if second side
+ addiu s0,s0,-1 // Decrement Bank counter
+
+ //
+ // First Side.
+ //
+ beq a0,zero,GroupNotPresent // No memory present in this group
+
+ move a3,a0 // Save bank presence bit.
+ move v0,a1 // Save first side SIMM size
+
+ //
+ // Increment Base addresses by half the maximum size of a bank.
+ //
+ li AT,0x4000000 // 64MB
+ addu t0,AT // get Next bank address + 0MB
+ addu t2,AT // get Next bank address + 4MB
+ addu t4,AT // get Next bank address +20MB
+ b DSizeBank // Repeat for second side.
+ nop
+
+GroupNotPresent:
+ sw zero,0x0(s1) // Disable current bank
+ b NextGroup
+ addiu s0,s0,-1 // Skip 2nd side of non exitent Group.
+
+
+GroupDone:
+
+ //
+ // We are done with the current group.
+ // a1 and v0 have the SIMM size.
+ // a3 has first side presence bit a0 has second size presence bit.
+ //
+ beq a0,zero,SingleSidedBank // if a0 is zero no memory found in
+ nop // the second side. Don't check
+ // consistency between sizes.
+ bne a1,v0,WrongMemory // Both sides must have same size.
+SingleSidedBank:
+ sll a0,1 // shift enable second side bit.
+ or a3,a0,a3 // or in first side presence.
+ srl v0,8 // Get SIMM size config value.
+ or a3,v0 // or in with bank presence
+
+ //
+ // Set base of the sized bank up so that next bank
+ // can be sized as if it started at offset zero.
+ // When code gets here s0 has the value 6,4,2,0
+ // shift it left by 26 bits to make the base of the bank
+ // at address 6*64MB,4*64Mb,2*64MB,0MB
+ //
+ sll AT,s0,26 // set base of bank to avoid colision between banks
+ or a3,AT,a3 // or physical base address.
+ sw a3,0x0(s1) // Store into config register
+
+NextGroup:
+ bne s0,zero,DSizeGroup // Repeat for next group.
+ addiu s1,s1,8 // Next configuration register.
+
+ //
+ // The four groups have been sized and it's SIMM type and size
+ // value stored in the configuration register.
+ // Set their base addresses sorting them from big to small
+ //
+ // Mask = 0;
+ // BaseAddress = 0;
+ // do {
+ // BiggestSize = 0;
+ // BiggestIndex = 0;
+ // for (t2=0; t2 < 4; t2++) {
+ // if (Mask & (1 << t2)) {
+ // continue;
+ // }
+ // if (GroupSize[Config[t2]] == 0) {
+ // Mask |= 1 << t2;
+ // continue;
+ // }
+ // if (GroupSize[Config[t2]] > BiggestSize) {
+ // BiggestSize = GroupSize[Config[t2]];
+ // BiggestIndex = t2;
+ // }
+ // }
+ // Config[BiggestIndex] = Config[BiggestIndex]&0xF + BaseAddress;
+ // Mask |= 1 << BiggestIndex;
+ // BaseAddress += BiggestSize;
+ // } while (Mask != 0xF);
+ //
+ //
+ // t0 = BiggestSize
+ // a3 = Biggest index
+ // a1 = Mask. Each bit indicates that group has been dealth with
+ // a2 = BaseAddress
+ //
+
+ la v0,MemoryGroupSize // Address of table
+ li v1,DMA_VIRTUAL_BASE+DmaMemoryConfig0 // Address of first config register
+ move a2,zero // base address of group
+ move a1,zero // mask register
+Loop:
+ move t2,zero // loop count
+ move a3,zero // biggest group index
+ move t0,zero // size of biggest group
+
+ReadNextGroup:
+ li t4,1
+ sll t4,t4,t2 // set Nth bit for iteration N
+ nop
+ and t5,a1,t4 // test if bit set in mask
+ beq t5,zero,10f // if not set read current group config
+ nop
+ b ForEachGroup
+ addiu t2,t2,1 // Increment group index
+
+10:
+ sll t3,t2,3 // multiply loop count by 8
+ addu t3,t3,v1 // add to base of config registers
+ lw a0,0x0(t3) // read config register
+ andi a0,0xF // extract SIMM type bits
+ addu a0,a0,v0 // add to base of table
+ lbu a0,0(a0) // index table to get size in MB
+ beq a0,zero,SizeZeroGroup // if zero set mask bit for this group
+ sltu t1,t0,a0 // Branch if the size of the biggest group is
+ bne t1,zero,BiggerFound // smaller than the current group
+ nop
+ b ForEachGroup // Go for next group
+ addiu t2,t2,1 // Increment index
+
+BiggerFound:
+ //
+ // The current group is the biggest found so far
+ //
+ move t0,a0 // set biggest group to current
+ move a3,t2 // save biggest group index
+ b ForEachGroup
+ addiu t2,t2,1 // next group index.
+
+
+SizeZeroGroup:
+ //
+ // Or Nth bit to tell that this group doesn't
+ // need to be dealth with since it's size is zero
+ //
+ or a1,a1,t4
+ addiu t2,t2,1 // increment group index
+
+ForEachGroup:
+ li t1,4 // last group
+ bne t2,t1,ReadNextGroup // if not last group repeat
+
+ //
+ // The four groups where checked.
+ // t0 has the size of the biggest found.
+ // a3 has the index of the biggest found.
+ // Set the current base to the config register
+ // Increment the base by the size of the register
+ //
+ sll t3,a3,3 // multiply index by 8
+ addu t3,t3,v1 // add to base of config registers
+ lw a0,0x0(t3) // read config register
+ andi a0,0xF // extract SIMM type bits
+ or a0,a2 // or in the current base address
+ sw a0,0(t3) // store
+ sll t0,20 // shift size in MB to address
+ addu a2,a2,t0 // add size to current base
+
+ li t4,1 // get a 1
+ sll t4,t4,a3 // set Nth bit for biggest found N
+ or a1,a1,t4 // or into mask of processed groups
+ li t1,0xF //
+ bne t1,a1,Loop // if not all bits set in the mask Loop
+ nop
+ j ra // return to caller.
+ nop
+
+WrongMemory:
+ //
+ // Control reaches here if the memory can't be sized.
+ //
+ lui a0,LED_BLINK // Hang
+ bal PutLedDisplay // blinking the error code
+ ori a0,a0,LED_WRONG_MEMORY // in the LED
+ .end SizeMemory
+
+
+//
+// This table indexed with the low 4 bits of the MemoryGroup config register,
+// returns the size of memory installed in the group in Megabytes.
+//
+//
+MemoryGroupSize:
+.byte 0 // No SIMM installed
+.byte 0 // No SIMM installed
+.byte 0 // No SIMM installed
+.byte 0 // No SIMM installed
+.byte 4 // Single Sided 4MB
+.byte 16 // Single Sided 16MB
+.byte 64 // Single Sided 64MB
+.byte 0 // Single Sided reserved
+.byte 0 // Reserved
+.byte 0 // Reserved
+.byte 0 // Reserved
+.byte 0 // Reserved
+.byte 8 // Double Sided 4MB
+.byte 32 // Double Sided 16MB
+.byte 128 // Double Sided 64MB
+.byte 0 // Double Sided reserved
+
+#endif // DUO && R4000
diff --git a/private/ntos/fw/mips/debug.c b/private/ntos/fw/mips/debug.c
new file mode 100644
index 000000000..da20a3401
--- /dev/null
+++ b/private/ntos/fw/mips/debug.c
@@ -0,0 +1,119 @@
+// TITLE("Debug Support Functions")
+//++
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// debug.s
+//
+// Abstract:
+//
+// This module implements functions to support debugging NT.
+//
+// Author:
+//
+// Steven R. Wood (stevewo) 3-Aug-1989
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "stdarg.h"
+#include "stdio.h"
+#include "ntrtlp.h"
+
+//
+// Define procedure prototypes for debug input and output.
+//
+
+NTSTATUS
+DebugPrint (
+ IN PSTRING Output
+ );
+
+ULONG
+DebugPrompt (
+ IN PSTRING Output,
+ IN PSTRING Input
+ );
+
+
+ULONG
+DbgPrint (
+ PCHAR Format,
+ ...
+ )
+
+{
+
+ va_list ArgumentList;
+ UCHAR Buffer[512];
+ STRING Output;
+
+ //
+ // Format the output into a buffer and then print it.
+ //
+
+ va_start(ArgumentList, Format);
+ Output.Length = vsprintf(&Buffer[0], Format, ArgumentList);
+ Output.Buffer = &Buffer[0];
+ va_end(ArgumentList);
+ return DebugPrint(&Output);
+}
+
+ULONG
+DbgPrompt (
+ IN PCHAR Prompt,
+ OUT PCHAR Response,
+ IN ULONG MaximumResponseLength
+ )
+
+//++
+//
+// Routine Description:
+//
+// This function displays the prompt string on the debugging console and
+// then reads a line of text from the debugging console. The line read
+// is returned in the memory pointed to by the second parameter. The
+// third parameter specifies the maximum number of characters that can
+// be stored in the response area.
+//
+// Arguments:
+//
+// Prompt - specifies the text to display as the prompt.
+//
+// Response - specifies where to store the response read from the
+// debugging console.
+//
+// Prompt - specifies the maximum number of characters that can be
+// stored in the Response buffer.
+//
+// Return Value:
+//
+// Number of characters stored in the Response buffer. Includes the
+// terminating newline character, but not the null character after
+// that.
+//
+//--
+
+{
+
+ STRING Input;
+ STRING Output;
+
+ //
+ // Output the prompt string and read input.
+ //
+
+ Input.MaximumLength = MaximumResponseLength;
+ Input.Buffer = Response;
+ Output.Length = strlen(Prompt);
+ Output.Buffer = Prompt;
+ return DebugPrompt(&Output, &Input);
+}
+
diff --git a/private/ntos/fw/mips/debug.h b/private/ntos/fw/mips/debug.h
new file mode 100644
index 000000000..d72c62146
--- /dev/null
+++ b/private/ntos/fw/mips/debug.h
@@ -0,0 +1,7 @@
+
+#if OMF_DEBUG==TRUE
+ #define PRINTDBG(x) FwPrint(x); \
+ FwStallExecution(50*1000);
+#else
+ #define PRINTDBG(x) //
+#endif
diff --git a/private/ntos/fw/mips/dmaregs.h b/private/ntos/fw/mips/dmaregs.h
new file mode 100644
index 000000000..c78e63cfc
--- /dev/null
+++ b/private/ntos/fw/mips/dmaregs.h
@@ -0,0 +1,207 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ dmaregs.h
+
+Abstract:
+
+ This module defines the offsets of the MCTADR registers to allow
+ access to them from assembly code.
+
+ Register names correspond to the ones in the structure DMA_REGISTERS
+ declared in jazzdma.h
+
+Author:
+
+ Lluis Abello 6-May-91
+
+Revision History:
+
+ Lluis Abello 1-Apr-93 Added DUO registers
+
+--*/
+#ifndef _DMAREGS
+#define _DMAREGS
+
+#ifndef DUO
+//
+// DMA REGISTER OFFSETS
+//
+#define DmaConfiguration 0x000
+#define DmaRevisionLevel 0x008
+#define DmaInvalidAddress 0x010
+#define DmaTranslationBase 0x018
+#define DmaTranslationLimit 0x020
+#define DmaTranslationInvalidate 0x028
+#define DmaCacheMaintenance 0x030
+#define DmaRemoteFailedAddress 0x038
+#define DmaMemoryFailedAddress 0x040
+#define DmaPhysicalTag 0x048
+#define DmaLogicalTag 0x050
+#define DmaByteMask 0x058
+#define DmaBufferWindowLow 0x060
+#define DmaBufferWindowHigh 0x068
+#define DmaRemoteSpeed0 0x070
+#define DmaRemoteSpeed1 0x078
+#define DmaRemoteSpeed2 0x080
+#define DmaRemoteSpeed3 0x088
+#define DmaRemoteSpeed4 0x090
+#define DmaRemoteSpeed5 0x098
+#define DmaRemoteSpeed6 0x0a0
+#define DmaRemoteSpeed7 0x0a8
+#define DmaRemoteSpeed8 0x0b0
+#define DmaRemoteSpeed9 0x0b8
+#define DmaRemoteSpeed10 0x0c0
+#define DmaRemoteSpeed11 0x0c8
+#define DmaRemoteSpeed12 0x0d0
+#define DmaRemoteSpeed13 0x0d8
+#define DmaRemoteSpeed14 0x0e0
+#define DmaRemoteSpeed15 0x0e8
+#define DmaParityDiagnosticLow 0x0f0
+#define DmaParityDiagnosticHigh 0x0f8
+#define DmaChannel0Mode 0x100
+#define DmaChannel0Enable 0x108
+#define DmaChannel0ByteCount 0x110
+#define DmaChannel0Address 0x118
+#define DmaChannel1Mode 0x120
+#define DmaChannel1Enable 0x128
+#define DmaChannel1ByteCount 0x130
+#define DmaChannel1Address 0x138
+#define DmaChannel2Mode 0x140
+#define DmaChannel2Enable 0x148
+#define DmaChannel2ByteCount 0x150
+#define DmaChannel2Address 0x158
+#define DmaChannel3Mode 0x160
+#define DmaChannel3Enable 0x168
+#define DmaChannel3ByteCount 0x170
+#define DmaChannel3Address 0x178
+#define DmaChannel4Mode 0x180
+#define DmaChannel4Enable 0x188
+#define DmaChannel4ByteCount 0x190
+#define DmaChannel4Address 0x198
+#define DmaChannel5Mode 0x1a0
+#define DmaChannel5Enable 0x1a8
+#define DmaChannel5ByteCount 0x1b0
+#define DmaChannel5Address 0x1b8
+#define DmaChannel6Mode 0x1c0
+#define DmaChannel6Enable 0x1c8
+#define DmaChannel6ByteCount 0x1d0
+#define DmaChannel6Address 0x1d8
+#define DmaChannel7Mode 0x1e0
+#define DmaChannel7Enable 0x1e8
+#define DmaChannel7ByteCount 0x1f0
+#define DmaChannel7Address 0x1f8
+#define DmaInterruptSource 0x200
+#define DmaErrortype 0x208
+#define DmaRefreshRate 0x210
+#define DmaRefreshCounter 0x218
+#define DmaSystemSecurity 0x220
+#define DmaInterruptInterval 0x228
+#define DmaIntervalTimer 0x230
+#define DmaInterruptAcknowledge 0x238
+
+#else
+//
+// MP_DMA register offsets for DUO.
+//
+#define DmaConfiguration 0x000
+#define DmaRevisionLevel 0x008
+#define DmaRemoteFailedAddress 0x010
+#define DmaMemoryFailedAddress 0x018
+#define DmaInvalidAddress 0x020
+#define DmaTranslationBase 0x028
+#define DmaTranslationLimit 0x030
+#define DmaTranslationInvalidate 0x038
+#define DmaChannelInterruptAcknowledge 0x040
+#define DmaLocalInterruptAcknowledge 0x048
+#define DmaEisaInterruptAcknowledge 0x050
+#define DmaTimerInterruptAcknowledge 0x058
+#define DmaIpInterruptAcknowledge 0x060
+#define DmaWhoAmI 0x070
+#define DmaNMISource 0x078
+#define DmaRemoteSpeed0 0x080
+#define DmaRemoteSpeed1 0x088
+#define DmaRemoteSpeed2 0x090
+#define DmaRemoteSpeed3 0x098
+#define DmaRemoteSpeed4 0x0A0
+#define DmaRemoteSpeed5 0x0A8
+#define DmaRemoteSpeed6 0x0B0
+#define DmaRemoteSpeed7 0x0B8
+#define DmaRemoteSpeed8 0x0C0
+#define DmaRemoteSpeed9 0x0C8
+#define DmaRemoteSpeed10 0x0D0
+#define DmaRemoteSpeed11 0x0D8
+#define DmaRemoteSpeed12 0x0E0
+#define DmaRemoteSpeed13 0x0E8
+#define DmaRemoteSpeed14 0x0F0
+#define DmaInterruptEnable 0x0F8
+#define DmaChannel0Mode 0x100
+#define DmaChannel0Enable 0x108
+#define DmaChannel0ByteCount 0x110
+#define DmaChannel0Address 0x118
+#define DmaChannel1Mode 0x120
+#define DmaChannel1Enable 0x128
+#define DmaChannel1ByteCount 0x130
+#define DmaChannel1Address 0x138
+#define DmaChannel2Mode 0x140
+#define DmaChannel2Enable 0x148
+#define DmaChannel2ByteCount 0x150
+#define DmaChannel2Address 0x158
+#define DmaChannel3Mode 0x160
+#define DmaChannel3Enable 0x168
+#define DmaChannel3ByteCount 0x170
+#define DmaChannel3Address 0x178
+#define DmaArbitrationControl 0x180
+#define DmaErrortype 0x188
+#define DmaRefreshRate 0x190
+#define DmaRefreshCounter 0x198
+#define DmaSystemSecurity 0x1A0
+#define DmaInterruptInterval 0x1A8
+#define DmaIntervalTimer 0x1B0
+#define DmaIpi 0x1B8
+#define DmaInterruptDiagnostic 0x1C0
+#define DmaEccDiagnostic 0x1C8
+#define DmaMemoryConfig0 0x1D0
+#define DmaMemoryConfig1 0x1D8
+#define DmaMemoryConfig2 0x1E0
+#define DmaMemoryConfig3 0x1E8
+#define IoCacheBufferBase 0x200
+#define DmaIoCachePhysicalTag0 0x400
+#define DmaIoCachePhysicalTag1 0x408
+#define DmaIoCachePhysicalTag2 0x410
+#define DmaIoCachePhysicalTag3 0x418
+#define DmaIoCachePhysicalTag4 0x420
+#define DmaIoCachePhysicalTag5 0x428
+#define DmaIoCachePhysicalTag6 0x430
+#define DmaIoCachePhysicalTag7 0x438
+#define DmaIoCacheLogicalTag0 0x440
+#define DmaIoCacheLogicalTag1 0x448
+#define DmaIoCacheLogicalTag2 0x450
+#define DmaIoCacheLogicalTag3 0x458
+#define DmaIoCacheLogicalTag4 0x460
+#define DmaIoCacheLogicalTag5 0x468
+#define DmaIoCacheLogicalTag6 0x470
+#define DmaIoCacheLogicalTag7 0x478
+#define DmaIoCacheLowByteMask0 0x480
+#define DmaIoCacheLowByteMask1 0x488
+#define DmaIoCacheLowByteMask2 0x490
+#define DmaIoCacheLowByteMask3 0x498
+#define DmaIoCacheLowByteMask4 0x4A0
+#define DmaIoCacheLowByteMask5 0x4A8
+#define DmaIoCacheLowByteMask6 0x4B0
+#define DmaIoCacheLowByteMask7 0x4B8
+#define DmaIoCacheHighByteMask0 0x4C0
+#define DmaIoCacheHighByteMask1 0x4C8
+#define DmaIoCacheHighByteMask2 0x4D0
+#define DmaIoCacheHighByteMask3 0x4D8
+#define DmaIoCacheHighByteMask4 0x4E0
+#define DmaIoCacheHighByteMask5 0x4E8
+#define DmaIoCacheHighByteMask6 0x4F0
+#define DmaIoCacheHighByteMask7 0x4F8
+
+#endif // DUO
+
+#endif //_DMAREGS
diff --git a/private/ntos/fw/mips/duosync.c b/private/ntos/fw/mips/duosync.c
new file mode 100644
index 000000000..09b515258
--- /dev/null
+++ b/private/ntos/fw/mips/duosync.c
@@ -0,0 +1,516 @@
+#ifdef DUO
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ duosync.c
+
+Abstract:
+
+ This module contains the routines that perform synchronization
+ among processors.
+
+Author:
+
+ Lluis Abello (lluis) 06-Apr-1993
+
+Environment:
+
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#include "iodevice.h"
+#include "led.h"
+#include "selfmap.h"
+#include "selftest.h"
+#include "ioaccess.h"
+#include "fwstring.h"
+
+volatile PROCESSOR_B_TASK_VECTOR ProcessorBTask;
+extern BOOLEAN ProcessorBEnabled;
+
+VOID
+InitializePCR(
+ );
+
+
+
+MEMORY_TEST_DATA BMemTest1 = {
+ 0xA0100000,
+ 0x100000,
+ 0,
+ LED_B_MEMORY_TEST_1
+ };
+
+
+MEMORY_TEST_DATA BMemTest2 = {
+ 0x80200000,
+ 0x100000,
+ 0,
+ LED_B_MEMORY_TEST_2
+ };
+
+
+MEMORY_TEST_DATA BMemTest3 = {
+ VIDEO_MEMORY_VIRTUAL_BASE+1280*1024, // start adr = end of visible screen
+ 0x200000-1280*1024, // size = rest of video memory.
+ 0,
+ LED_VIDEOMEM
+ };
+
+//
+// The following table defines the selftest routines that will be executed
+// by processor B.
+//
+
+PROCESSOR_B_TEST ProcessorBSelfTests[] = {
+ {ProcessorBMemoryTest,&BMemTest1},
+ {ProcessorBMemoryTest,&BMemTest2},
+ {ProcessorBVideoMemoryTest,&BMemTest3},
+ {NULL,0}
+ };
+
+ULONG
+ExecuteOnProcessorB(
+ IN PPROCESSOR_TASK_ROUTINE Routine,
+ IN PVOID Data
+ )
+/*++
+
+Routine Description:
+
+ This routine puts the supplied Routine and Data in processor B task vector
+ and issues an IP interrupt to processor B which will then execute
+ it and set the return value.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ PPROCESSOR_B_TASK_VECTOR TaskVector;
+
+ if (!ProcessorBEnabled) {
+ return 0;
+ }
+
+ //
+ // Get a non pointer to the Task Vector
+ //
+ TaskVector = (PPROCESSOR_B_TASK_VECTOR)&ProcessorBTask;
+
+ TaskVector->Routine = Routine;
+ TaskVector->Data = Data;
+ //
+ // Issue an IP interrupt to notify processor B that a task has
+ // been scheduled for execution.
+ //
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
+
+ //
+ // If timeout or Return Value indicates error, stop here.
+ //
+
+ if (WaitForIpInterrupt(5000) == FALSE) {
+ FwPrint("\r\nTimeout waiting for B to execute %lx\r\n",Routine);
+ }
+
+ return (TaskVector->ReturnValue);
+}
+
+
+VOID
+ProcessorBMain(
+ )
+/*++
+
+Routine Description:
+
+ This is the main routine for processor B.
+ It jumps here after initialization.
+ The startup sequence is as follows:
+
+ ProcessorA sets the address of this routine in the ProcessorBTask vector.
+ ProcessorA Enables Processor B in the Global Configuration register.
+ ProcessorA Calls WaitForIPInterrupt.
+
+ When Processor B is enabled it runs at the PROM reset vector, it
+ initializes itself and jumps to the routine pointed to by ProcessorTask
+ which is this routine.
+
+ Once here processor B Wakes up processor A by issuing an IP interrupt
+ and Loops for ever waiting for IP interrupts and executing the Task
+ pointed to by ProcessorBTask.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PPROCESSOR_TASK_ROUTINE Task;
+ PVOID TaskData;
+ ULONG ReturnValue;
+
+ //
+ // Get a pointer to the Task Vector
+ //
+
+ PPROCESSOR_B_TASK_VECTOR TaskVector = (PPROCESSOR_B_TASK_VECTOR)&ProcessorBTask;
+
+ //
+ // Enable IP interrupts.
+ // All interrupts are disabled in the psr.
+ //
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->InterruptEnable.Long,ENABLE_IP_INTERRUPTS);
+
+ for (;;) {
+
+ //
+ // Wake up processor A
+ //
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,1);
+
+ WaitForIpInterrupt(0);
+
+ //
+ // Execute Task
+ //
+ Task = TaskVector->Routine;
+ TaskData = TaskVector->Data;
+ ReturnValue = Task(TaskData);
+ TaskVector->ReturnValue = ReturnValue;
+ }
+}
+
+
+ULONG
+ProcessorBMemoryTest(
+ IN PMEMORY_TEST_DATA MemoryData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine tests the portion of memory supplied by Data.
+
+Arguments:
+
+ MemoryData - Pointer to a data structure describing the range of
+ memory to be tested.
+
+Return Value:
+
+ None
+
+--*/
+
+
+{
+ PutLedDisplay(MemoryData->LedDisplayValue);
+ WriteMemoryAddressTest(MemoryData->StartAddress,MemoryData->Size,MemoryData->XorPattern);
+ CheckMemoryAddressTest(MemoryData->StartAddress,MemoryData->Size,MemoryData->XorPattern,MemoryData->LedDisplayValue);
+ return 1;
+}
+
+
+ULONG
+ProcessorBVideoMemoryTest(
+ IN PMEMORY_TEST_DATA MemoryData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine tests the portion of video memory supplied by Data.
+
+Arguments:
+
+ MemoryData - Pointer to a data structure describing the range of
+ memory to be tested.
+
+Return Value:
+
+ None
+
+--*/
+
+
+{
+ PutLedDisplay(MemoryData->LedDisplayValue);
+ WriteVideoMemoryAddressTest(MemoryData->StartAddress,MemoryData->Size);
+ CheckVideoMemoryAddressTest(MemoryData->StartAddress,MemoryData->Size);
+ return 1;
+}
+
+ULONG
+CoherencyTest(
+ IN PVOID CoherentPage
+ )
+/*++
+
+Routine Description:
+
+ This routine performs a coherency test. This routine will be executed
+ simultaneously by both processors.
+
+ Processor A stores even bytes and Processor B stores the odd bytes.
+ To make sure that cache blocks are passed back and forth, a semaphore
+ locks it's access so that the cache line ping pongs from processor to
+ processor.
+
+
+Arguments:
+
+ CoherentPage. Pointer aligned to a page boundary. Which is marked
+ either Exclusive or Shared in the TLB.
+
+ The first ulong is used as the semaphore. The rest of the page
+ is used as data.
+
+
+Return Value:
+
+ Number of errors found.
+
+--*/
+
+
+{
+ volatile PULONG Semaphore = (PULONG)CoherentPage;
+ PULONG CoherentData = Semaphore+64/sizeof(ULONG);
+ ULONG Counter;
+ ULONG Processor;
+ ULONG DataLong;
+ ULONG Errors = 0;
+ if (READ_REGISTER_ULONG(&DMA_CONTROL->WhoAmI.Long)) {
+ //
+ // Processor B
+ //
+ Processor = 1;
+ DataLong = 0xB0B00000;
+ } else {
+ Processor = 0;
+ DataLong = 0xA0A00000;
+ }
+
+ for (Counter = 0; Counter < (0x1000-64)/sizeof(ULONG); Counter += 2) {
+
+ //
+ // Wait for counter.
+ // No need for interlocks since each processor waits
+ // for a different value.
+ //
+
+ while (*Semaphore != Counter+Processor) {
+ }
+ *(CoherentData+Processor) = DataLong | Counter;
+ *Semaphore = Counter+Processor+1;
+ CoherentData += 2;
+ }
+
+ //
+ // Both processors check all the data.
+ //
+ CoherentData = Semaphore+64/sizeof(ULONG);;
+ for (Counter = 0; Counter < (0x1000-64)/sizeof(ULONG); Counter +=2) {
+ if (*CoherentData != (Counter | 0xA0A00000)) {
+ Errors++;
+ }
+ CoherentData++;
+ if (*CoherentData != (Counter | 0xB0B00000)) {
+ Errors++;
+ }
+ CoherentData++;
+ }
+ return Errors;
+}
+
+
+BOOLEAN
+ProcessorBSelftest(
+ IN VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the different tasks to be executed by processor
+ b and waits for them to complete. This routine is executed by the
+ master processor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if passed FALSE otherwise
+
+
+--*/
+{
+ BOOLEAN ReturnValue;
+ BOOLEAN Timeout;
+
+ //
+ // Get a pointer to the Task Vector
+ //
+ PPROCESSOR_B_TASK_VECTOR TaskVector = (PPROCESSOR_B_TASK_VECTOR)&ProcessorBTask;
+ PPROCESSOR_B_TEST ProcessorBTestList = ProcessorBSelfTests;
+
+ //
+ // Place each task of the SelftestTable in the TaskVector to be executed
+ // by processor B.
+ //
+ while (ProcessorBTestList->Routine != NULL) {
+ TaskVector->Routine = ProcessorBTestList->Routine;
+ TaskVector->Data = ProcessorBTestList->Data;
+ //
+ // Issue an IP interrupt to notify processor B that a task has
+ // been scheduled for execution.
+ //
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
+
+ //
+ // If timeout or Return Value indicates error, stop here.
+ //
+ if (((Timeout = WaitForIpInterrupt(5000)) == FALSE) || (TaskVector->ReturnValue == FALSE)) {
+ if (!Timeout) {
+ FwPrint("\r\n Wait for Processor B timeout occurred");
+ } else {
+ FwPrint("\r\n Processor B failed a test");
+ }
+ FwPrint(" Failed test = %08lx\r\n", (ULONG)ProcessorBTestList->Routine);
+ //return FALSE;
+ }
+
+ //
+ // Next test.
+ //
+ ProcessorBTestList++;
+ }
+
+ //
+ // Now perform two CoherencyTest
+ //
+
+ FwPrint("\r\n Coherency Test.");
+ ReturnValue = TRUE;
+
+ //
+ // Zero the page. Set the Task and notify processor B.
+ // And execute the test simultaneously.
+ //
+ RtlZeroMemory((PVOID)EXCLUSIVE_PAGE_VIRTUAL_BASE,0x1000);
+ FwFlushAllCaches();
+ TaskVector->Routine = CoherencyTest;
+ TaskVector->Data = (PVOID)EXCLUSIVE_PAGE_VIRTUAL_BASE;
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
+
+ if (CoherencyTest((PVOID)EXCLUSIVE_PAGE_VIRTUAL_BASE) != 0) {
+ FwPrint(" Processor A Failed.");
+ ReturnValue = FALSE;
+ } else {
+ FwPrint("...");
+ }
+
+ //
+ // Get and display results from B
+ //
+ WaitForIpInterrupt(1000);
+ if (TaskVector->ReturnValue != 0) {
+ FwPrint(" Processor B Failed.");
+ ReturnValue = FALSE;
+ } else {
+ FwPrint("...");
+ }
+
+ //
+ // Do the same with a shared page
+ //
+ RtlZeroMemory((PVOID)SHARED_PAGE_VIRTUAL_BASE,0x1000);
+ FwFlushAllCaches();
+ TaskVector->Routine = CoherencyTest;
+ TaskVector->Data = (PVOID)SHARED_PAGE_VIRTUAL_BASE;
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
+ if (CoherencyTest((PVOID)SHARED_PAGE_VIRTUAL_BASE) != 0) {
+ FwPrint(" Processor A Failed.");
+ ReturnValue = FALSE;
+ } else {
+ FwPrint("...");
+ }
+ WaitForIpInterrupt(1000);
+ if (TaskVector->ReturnValue != 0) {
+ FwPrint(" Processor B Failed.");
+ ReturnValue = FALSE;
+ } else {
+ FwPrint("...");
+ }
+
+ //
+ // Make processor B initialize its PCR
+ //
+
+ TaskVector->Routine = (PPROCESSOR_TASK_ROUTINE)InitializePCR;
+ TaskVector->Data = 0;
+ //
+ // Issue an IP interrupt to notify processor B that a task has
+ // been scheduled for execution.
+ //
+
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
+
+ //
+ // If timeout or Return Value indicates error, stop here.
+ //
+ if (WaitForIpInterrupt(5000) == FALSE) {
+// FwPrint("\r\n Wait for Processor B timeout occurred in init PCR\r\n");
+ return FALSE;
+ }
+
+ //
+ // Make processor B cleanup it's caches.
+ //
+
+ TaskVector->Routine = (PPROCESSOR_TASK_ROUTINE)HalSweepDcache;
+ TaskVector->Data = 0;
+ //
+ // Issue an IP interrupt to notify processor B that a task has
+ // been scheduled for execution.
+ //
+
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
+
+ //
+ // If timeout or Return Value indicates error, stop here.
+ //
+ if (WaitForIpInterrupt(5000) == FALSE) {
+// FwPrint("\r\n Wait for Processor B timeout occurred Hal sweep d cachew\r\n");
+ return FALSE;
+ }
+ FwPrint(FW_OK_MSG);
+ return ReturnValue;
+}
+
+
+#endif // DUO
diff --git a/private/ntos/fw/mips/eisafunc.c b/private/ntos/fw/mips/eisafunc.c
new file mode 100644
index 000000000..fdfcf9bbe
--- /dev/null
+++ b/private/ntos/fw/mips/eisafunc.c
@@ -0,0 +1,680 @@
+// ----------------------------------------------------------------------------
+// Copyright (c) 1992 Olivetti
+//
+// File: eisafunc.c
+//
+// Description: Eisa code support functions.
+// ----------------------------------------------------------------------------
+//
+
+#include "fwp.h"
+#include "oli2msft.h"
+#include "arceisa.h"
+#include "inc.h"
+#include "string.h"
+#include "debug.h"
+
+extern EISA_BUS_INFO EisaBusInfo[];
+extern BL_FILE_TABLE BlFileTable [BL_FILE_TABLE_SIZE];
+
+// Function prototypes.
+
+
+VOID
+EisaFlushCache
+ (
+ IN PVOID Address,
+ IN ULONG Length
+ );
+
+VOID
+EisaInvalidateCache
+ (
+ IN PVOID Address,
+ IN ULONG Length
+ );
+
+ARC_STATUS
+EisaDoLockedOperation
+ (
+ IN ULONG BusNumber,
+ IN EISA_LOCK_OPERATION Operation,
+ IN PVOID Semaphore,
+ IN SEMAPHORE_SIZE SemaphoreSize,
+ IN PVOID OperationArgument,
+ OUT PVOID OperationResult
+ );
+
+ARC_STATUS
+EisaCheckLockPassingParameters
+ (
+ IN ULONG BusNumber,
+ IN EISA_LOCK_OPERATION Operation,
+ IN PVOID Semaphore,
+ IN SEMAPHORE_SIZE SemaphoreSize,
+ IN PVOID OperationArgument,
+ OUT PVOID OperationResult
+ );
+
+VOID
+EisaFlushWriteBuffers
+ (
+ VOID
+ );
+
+ARC_STATUS
+EisaGenerateTone
+ (
+ IN ULONG Frequency,
+ IN ULONG Duration
+ );
+
+BOOLEAN_ULONG
+EisaYield
+ (
+ VOID
+ );
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaFlushCache:
+//
+// DESCRIPTION: This function flushes the instruction and data caches
+// starting at the address specified in "Address" for
+// number of bytes specified in "Length".
+//
+// ARGUMENTS: Address - Starting virtual address of a range of virtual
+// addresses that are to be flushed from the instruction
+// and data caches. If Address is 0 the entire instruction
+// and data caches are flushed.
+//
+// Length - The length of range of virtual addresses that
+// are to be flushed from the instruction and data caches.
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS: GetICacheSize, GetDCacheSize, FlushInvalidateDCacheIndex
+//
+// GLOBALS: none.
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+// NOTE: Not used on JAZZ.
+#if 0
+
+VOID
+EisaFlushCache
+ (
+ IN PVOID Address,
+ IN ULONG Length
+ )
+{
+ ULONG CacheSize;
+ ULONG CacheLineSize;
+
+ if ( !Length ) // flush entire cache ?
+ { // yes, get cache sizes and flush
+
+ GetDCacheSize( (ULONG)&CacheSize, (ULONG)&CacheLineSize );
+ FlushInvalidateDCacheIndex( (PVOID)KSEG0_BASE, CacheSize );
+
+ return; // return to caller
+ }
+
+//
+// User specified a specific address to flush. So take the users starting
+// virtual address and size and flush data cache.
+//
+
+ Address = (PVOID)((ULONG)Address & 0x1FFFFFFF | KSEG0_BASE);
+ FlushInvalidateDCacheIndex( Address, Length );
+
+ return; // return
+}
+
+#endif // 0
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaInvalidateCache:
+//
+// DESCRIPTION: This functions sets the invalid bit in the cache line for
+// the specified range of addresses.
+//
+// ARGUMENTS: Address - Starting virtual address of a range of virtual
+// addresses that are to be invalidated in the instruction
+// and data caches. If Address is 0 the entire instruction
+// and data caches are invalidated.
+//
+// Length - The length of range of virtual addresses that
+// are to be invalidated in the instruction and data caches.
+//
+// RETURN: none
+//
+// ASSUMPTIONS: none
+//
+// CALLS: GetICacheSize, GetDCacheSize, InvalidateICacheIndex,
+// FlushInvalidateDCacheIndex
+//
+// GLOBALS: none
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+// NOTE: Not used on JAZZ.
+#if 0
+
+VOID
+EisaInvalidateCache
+ (
+ IN PVOID Address,
+ IN ULONG Length
+ )
+{
+ ULONG CacheSize;
+ ULONG CacheLineSize;
+
+ if ( !Length ) // invalidate entire cache ?
+ { // yes, get cache sizes and invalidate
+
+ GetDCacheSize( (ULONG)&CacheSize, (ULONG)&CacheLineSize );
+ FlushInvalidateDCacheIndex( (PVOID)KSEG0_BASE, CacheSize );
+
+ GetICacheSize( (ULONG)&CacheSize, (ULONG)&CacheLineSize );
+ InvalidateICacheIndex( (PVOID)KSEG0_BASE, CacheSize );
+
+ return; // return to caller
+ }
+
+//
+// User specified a specific address to invalidate. So take the users
+// starting virtual address and size and invalidate both instruction and
+// data caches.
+//
+
+ Address = (PVOID)((ULONG)Address & 0x1FFFFFFF | KSEG0_BASE);
+ FlushInvalidateDCacheIndex( Address, Length );
+ InvalidateICacheIndex( Address, Length );
+
+ return; // return to caller
+}
+
+#endif // 0
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaDoEISALockedOperation:
+//
+// DESCRIPTION: A CPU or a bus master can assert LOCK* to guarantee
+// exclusive memory access during the time LOCK* is
+// asserted. Assertion of LOCK* allows bit test and set
+// operations (as used for semaphores) to be executed
+// as a unit (atomically), with the bus lock preventing
+// multiple devices from simultaneously modifying the
+// semaphore bit. The MIPS family of microprocessors
+// does not assert LOCK* during the execution of any
+// function. As such, the system firmware provides an
+// abstracted programmatic interface through which option
+// module firmware (OMF) can assert and negate LOCK*.
+//
+// EISA option module firmware's LOCK* requests are
+// performed by the EISA LOCK function. If there are
+// multiple EISA buses in the system, the buses may share
+// the LOCK hardware among the different EISA buses.
+//
+// ARGUMENTS: BusNumber The bus that contains the device that
+// is sharing semaphore. This number is
+// the Key of the buses' component
+// structure.
+//
+// Opeation The type of locked operation to be
+// performed.
+//
+// Semaphore A pointer to the varialbe in EISA or
+// system memory.
+//
+// SemaphoreSize The size of the semaphore.
+//
+// OperationArgument The value to change the Semaphore to.
+//
+// OperationResult A pointer to a memory location that
+// will receive the value of Semaphore
+// before Operation.
+//
+// RETURN: ESUCCESS all done
+// EINVAL passing parameters error
+//
+// ASSUMPTIONS: none
+//
+// CALLS: EisaCheckLockPassingParameters
+//
+// GLOBALS: none
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+// NOTE: Not used on JAZZ.
+#if 0
+
+ARC_STATUS
+EisaDoLockedOperation
+ (
+ IN ULONG BusNumber,
+ IN EISA_LOCK_OPERATION Operation,
+ IN PVOID Semaphore,
+ IN SEMAPHORE_SIZE SemaphoreSize,
+ IN PVOID OperationArgument,
+ OUT PVOID OperationResult
+ )
+{
+ ARC_STATUS Status;
+
+ //
+ // validate the passing parameters to avoind exceptions.
+ //
+
+ if ( Status = EisaCheckLockPassingParameters( BusNumber, Operation,
+ Semaphore, SemaphoreSize, OperationArgument, OperationResult ))
+ {
+ return Status;
+ }
+
+ //
+ // assert lock on the BUS.
+ //
+
+ WRITE_REGISTER_UCHAR( EISA_LOCK_VIRTUAL_BASE,
+ READ_REGISTER_UCHAR( EISA_LOCK_VIRTUAL_BASE ) | 0x01 );
+
+ //
+ // Now check to see what type of operation the caller is asking us
+ // to perform.
+ //
+
+ if (Operation == Exchange)
+ {
+ //
+ // User wants to exchange the current semaphore value with the
+ // one passed. So, lets get the semaphore size and do the
+ // exchange.
+ //
+
+ switch(SemaphoreSize)
+ {
+ case ByteSemaphore:
+ *(PUCHAR)OperationResult = *(PUCHAR)Semaphore;
+ *(PUCHAR)Semaphore = *(PUCHAR)OperationArgument;
+ break;
+
+ case HalfWordSemaphore:
+ *(PUSHORT)OperationResult = *(PUSHORT)Semaphore;
+ *(PUSHORT)Semaphore = *(PUSHORT)OperationArgument;
+ break;
+
+ case WordSemaphore:
+ *(PULONG)OperationResult = *(PULONG)Semaphore;
+ *(PULONG)Semaphore = *(PULONG)OperationArgument;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ //
+ // The operation on the semaphore is now complete. Now we need to
+ // negate the LOCK* signal.
+ //
+
+ WRITE_REGISTER_UCHAR( EISA_LOCK_VIRTUAL_BASE,
+ READ_REGISTER_UCHAR( EISA_LOCK_VIRTUAL_BASE ) & 0xFE );
+
+ return ESUCCESS;
+}
+
+#endif // 0
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaCheckLockPassingParameters:
+//
+// DESCRIPTION: The functions checks the lock function passing
+// parameters. This is neccessary to avoin exceptions.
+//
+// ARGUMENTS: BusNumber The bus that contains the device that
+// is sharing semaphore. This number is
+// the Key of the buses' component
+// structure.
+//
+// Opeation The type of locked operation to be
+// performed.
+//
+// Semaphore A pointer to the varialbe in EISA or
+// system memory.
+//
+// SemaphoreSize The size of the semaphore.
+//
+// OperationArgument The value to change the Semaphore to.
+//
+// OperationResult A pointer to a memory location that
+// will receive the value of Semaphore
+// before Operation.
+//
+// RETURN: ESUCCESS parameters are correct.
+// EINVAL at least one parameter was not correct.
+//
+// ASSUMPTIONS: none
+//
+// CALLS: EisaCheckBusNumber
+//
+// GLOBALS: none
+//
+// NOTES: none
+// ----------------------------------------------------------------------------
+//
+
+// NOTE: Not used on JAZZ.
+#if 0
+
+ARC_STATUS
+EisaCheckLockPassingParameters
+ (
+ IN ULONG BusNumber,
+ IN EISA_LOCK_OPERATION Operation,
+ IN PVOID Semaphore,
+ IN SEMAPHORE_SIZE SemaphoreSize,
+ IN PVOID OperationArgument,
+ OUT PVOID OperationResult
+ )
+{
+ ARC_STATUS Status = EINVAL;
+ ULONG Size = 1 << SemaphoreSize; // semaphore size (# bytes)
+
+ //
+ // check the bus number
+ //
+
+ if ( EisaCheckBusNumber( BusNumber ) != ESUCCESS );
+
+ //
+ // check lock operation
+ //
+
+ else if ( Operation >= LockMaxOperation );
+
+ //
+ // check semaphore size
+ //
+
+ else if ( SemaphoreSize >= MaxSemaphore );
+
+ //
+ // make sure that there is physical memory at the specified locations
+ //
+
+ else if ( EisaCheckVirtualAddress( BusNumber, Semaphore, Size ));
+ else if ( EisaCheckVirtualAddress( BusNumber, OperationArgument, Size ));
+ else if ( EisaCheckVirtualAddress( BusNumber, OperationResult, Size ));
+
+ //
+ // check pointers boundaries
+ //
+
+ else if ( ((ULONG)Semaphore | (ULONG)OperationArgument |
+ (ULONG)OperationResult) & ((1 << SemaphoreSize)-1) );
+
+ //
+ // if we got here, the parameters are correct
+ //
+
+ else
+ {
+ Status = ESUCCESS;
+ }
+
+ return Status;
+}
+
+#endif // 0
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaFlushWriteBuffers:
+//
+// DESCRIPTION: This function flushes any external write buffers.
+//
+// ARGUMENTS: none.
+//
+// RETURN: none
+//
+// ASSUMPTIONS: none
+//
+// CALLS: FlushWriteBuffers
+//
+// GLOBALS: none
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+// NOTE: Not used on JAZZ.
+#if 0
+
+VOID
+EisaFlushWriteBuffers
+ (
+ VOID
+ )
+{
+ FlushWriteBuffers(); // flush external write buffers.
+ return; // return to caller.
+}
+
+#endif // 0
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaGenerateTone:
+//
+// DESCRIPTION: This function generate tones of a specified
+// frequency and duration an the system speaker.
+//
+// ARGUMENTS: Frequency the frequency of the tone in hertz
+// Duration The duration of the tone in msec
+//
+// RETURN: ESUCCESS Operation completed successfully
+// ENODEV System can not generate tones
+//
+// ASSUMPTIONS: none
+//
+// CALLS: none
+//
+// GLOBALS: none
+//
+// NOTES: The routine uses the timer1-counter2 and the system
+// control port B of the 1st EISA bus to generate the
+// specified tone.
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+EisaGenerateTone
+ (
+ IN ULONG Frequency,
+ IN ULONG Duration
+ )
+{
+ //
+ // define local variables
+ //
+
+ PUCHAR EisaIoStart, Ctrl, Data, Port61; // general I/O address
+
+ //
+ // exit if duration is null
+ //
+
+ if ( !Duration )
+ {
+ return ESUCCESS;
+ }
+
+ //
+ // initialize local variables
+ //
+
+ EisaIoStart = EisaBusInfo[ 0 ].IoBusInfo->VirAddr;
+ Ctrl = EisaIoStart + EISA_TIMER1_CTRL;
+ Data = EisaIoStart + EISA_TIMER1_COUNTER2;
+ Port61 = EisaIoStart + EISA_SYS_CTRL_PORTB;
+
+ //
+ // make sure that the speaker is disabled
+ //
+
+ EisaOutUchar( Port61, ( EisaInUchar( Port61 ) &
+ ~( EISA_SPEAKER_GATE | EISA_SPEAKER_TIMER )) & 0x0F );
+
+ //
+ // if frequency value is valid, program timer1-counter2 and enable speaker
+ //
+
+ if (Frequency>=EISA_SPEAKER_MIN_FREQ && Frequency<=EISA_SPEAKER_MAX_FREQ)
+ {
+ //
+ // initialize timer1 counter2 in 16-bit , mode 3
+ //
+
+// NOTE: CriticalSection not supported in JAZZ.
+// EisaBeginCriticalSection();
+ EisaOutUchar( Ctrl, 0xB6 );
+ EisaOutUchar( Data, (UCHAR)(EISA_SPEAKER_CLOCK/Frequency));
+ EisaOutUchar( Data, (UCHAR)(EISA_SPEAKER_CLOCK/Frequency >> 8));
+// NOTE: CriticalSection not supported in JAZZ.
+// EisaEndCriticalSection();
+
+ //
+ // enable speaker gate and speaker output
+ //
+
+ EisaOutUchar( Port61, ( EisaInUchar( Port61 ) |
+ EISA_SPEAKER_GATE | EISA_SPEAKER_TIMER ) & 0x0F );
+ }
+
+ //
+ // ... wait
+ //
+
+ while ( Duration-- )
+ {
+ ArcEisaStallProcessor( 1000 ); // 1 msec
+ }
+
+ //
+ // disable speaker before returning
+ //
+
+ EisaOutUchar( Port61, ( EisaInUchar( Port61 ) &
+ ~( EISA_SPEAKER_GATE | EISA_SPEAKER_TIMER )) & 0x0F );
+
+ //
+ // all done
+ //
+
+ return ESUCCESS;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaYield:
+//
+// DESCRIPTION: System utilities and option module firmware
+// must surrender the processor so that the system
+// module firmware can check for pending input.
+// To surrender the prcessor, call this function.
+//
+// ARGUMENTS: none
+//
+// RETURN: TRUE Indicates that the BREAK key was
+// pressed. Yield continues to return
+// TREUE until the BREAK key is read
+// from the console input device.
+// FALSE Inidicates that the BREAK key has
+// not been pressed.
+// ASSUMPTIONS: none
+//
+// CALLS: none
+//
+// GLOBALS: none
+//
+// NOTES: none
+// ----------------------------------------------------------------------------
+//
+
+// NOTE: Not used on JAZZ.
+#if 0
+
+BOOLEAN_ULONG
+EisaYield
+ (
+ VOID
+ )
+{
+ //
+ // call all device strategy routines with FC_POLL command
+ //
+
+ EisaOmfPoll();
+
+ //
+ // read any char available from the console in into the console in buffer
+ //
+
+ if ( !BlFileTable[ 0 ].Flags.Open )
+ {
+ //
+ // the console in device is not available, return no Ctrl-C.
+ //
+
+ return FALSE;
+ }
+
+ //
+ // read any available data from the console in device
+ //
+
+ ConsoleInFill();
+
+ //
+ // and scan buffer checking contrl-C
+ //
+
+ return ConsoleInCtrlC();
+}
+
+#endif // 0
diff --git a/private/ntos/fw/mips/eisaini.c b/private/ntos/fw/mips/eisaini.c
new file mode 100644
index 000000000..257f6b9ec
--- /dev/null
+++ b/private/ntos/fw/mips/eisaini.c
@@ -0,0 +1,3195 @@
+// ----------------------------------------------------------------------------
+// Copyright (c) 1992 Olivetti
+//
+// File: eisaini.c
+//
+// Description: EISA initialization routines.
+// ----------------------------------------------------------------------------
+//
+
+#include "fwp.h"
+#include "oli2msft.h"
+#include "arceisa.h"
+#include "inc.h"
+#include "string.h"
+#include "debug.h"
+#include "eisastr.h"
+
+
+//extern BL_DEVICE_ENTRY_TABLE OmfEntryTable[];
+
+// NOTE: Not used in JAZZ.
+//extern ULONG ErrorWord; // POD error flags
+//extern ULONG FlagWord; // system flags
+extern ULONG MemorySize; // size of memory in Mb
+
+extern PCHAR MnemonicTable[];
+
+extern ULONG EisaPoolSize; // # bytes really used
+extern ULONG EisaDynMemSize; // dynamic memory size (bytes)
+extern ULONG EisaFreeTop; // top of free mem
+extern ULONG EisaFreeBytes; // free bytes left
+
+
+
+// remove the following function prototypes when using common code
+
+PFW_MD
+GetFwMd
+ (
+ VOID
+ );
+
+PFW_MD
+LinkPhysFwMd
+ (
+ PFW_MD * pFwMdBase,
+ PFW_MD pFwMd
+ );
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// Declare Function Prototypes
+// ----------------------------------------------------------------------------
+
+
+VOID
+EisaIni
+ (
+ VOID
+ );
+
+VOID
+EisaGeneralIni
+ (
+ VOID
+ );
+
+BOOLEAN
+EisaBusStructIni
+ (
+ IN ULONG BusNumber
+ );
+
+BOOLEAN
+EisaCheckAdapterComponent
+ (
+ IN ULONG BusNumber,
+ OUT PCONFIGURATION_COMPONENT *pEisaComp
+ );
+
+BOOLEAN
+EisaBusPod
+ (
+ IN ULONG BusNumber
+ );
+
+BOOLEAN
+EisaPortIni
+ (
+ IN PUCHAR EisaIoStart
+ );
+
+BOOLEAN
+EisaIntIni
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_INT_INFO pIntInfo
+ );
+
+BOOLEAN
+EisaDmaIni
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ );
+
+BOOLEAN
+EisaBusCfg
+ (
+ IN PCONFIGURATION_COMPONENT EisaComponent
+ );
+
+BOOLEAN
+EisaPhysSlotCfg
+ (
+ IN ULONG BusNumber,
+ IN PCONFIGURATION_COMPONENT Controller,
+ IN ULONG AdapId
+ );
+
+BOOLEAN
+EisaVirSlotCfg
+ (
+ IN ULONG BusNumber,
+ IN PCONFIGURATION_COMPONENT Controller
+ );
+
+BOOLEAN
+EisaSlotCfg
+ (
+ IN ULONG BusNumber,
+ IN PCONFIGURATION_COMPONENT Controller,
+ IN UCHAR FunctionsNumber
+ );
+
+BOOLEAN
+EisaSlotCfgMem
+ (
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PUCHAR EisaFuncInfo
+ );
+
+BOOLEAN
+EisaSlotCfgIrq
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_INT_INFO pIntInfo,
+ IN PUCHAR EisaFuncInfo
+ );
+
+BOOLEAN
+EisaSlotCfgDma
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo,
+ IN PUCHAR EisaFuncInfo
+ );
+
+BOOLEAN
+EisaSlotCfgIni
+ (
+ IN PUCHAR EisaIoStart,
+ IN PUCHAR EisaFuncInfo,
+ OUT PBOOLEAN EnabAdapter
+ );
+
+VOID
+EisaSlotErrorLog
+ (
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN EISA_CFG_ERROR ErrorCode
+ );
+
+VOID
+EisaPathErrorLog
+ (
+ IN PCONFIGURATION_COMPONENT Controller,
+ IN EISA_CFG_ERROR ErrorCode
+ );
+
+VOID
+EisaStrErrorLog
+ (
+ IN PCHAR Str,
+ IN EISA_CFG_ERROR ErrorCode
+ );
+
+VOID
+EisaCheckpointFirstFase
+ (
+ IN EISA_CHECKPOINT Chk
+ );
+
+BOOLEAN
+EisaCheckpointFinalFase
+ (
+ IN EISA_CHECKPOINT Chk,
+ IN BOOLEAN Passed
+ );
+
+BOOLEAN
+EisaReadReadyId
+ (
+ IN PUCHAR EisaIoStart,
+ IN ULONG SlotNumber,
+ OUT PULONG AdapId
+ );
+
+VOID
+EisaReadId
+ (
+ IN PUCHAR EisaIoStart,
+ IN ULONG SlotNumber,
+ OUT PULONG AdapId
+ );
+
+BOOLEAN
+EisaMemIni
+ (
+ VOID
+ );
+
+VOID
+EisaDynMemIni
+ (
+ VOID
+ );
+
+PCONFIGURATION_COMPONENT
+FwGetChild
+ (
+ IN PCONFIGURATION_COMPONENT Component OPTIONAL
+ );
+
+PCONFIGURATION_COMPONENT
+FwGetPeer
+ (
+ IN PCONFIGURATION_COMPONENT Component
+ );
+
+PCONFIGURATION_COMPONENT
+FwAddChild
+ (
+ IN PCONFIGURATION_COMPONENT Component,
+ IN PCONFIGURATION_COMPONENT NewComponent,
+ IN PVOID ConfigurationData OPTIONAL
+ );
+
+PCONFIGURATION_COMPONENT
+FwGetComponent
+ (
+ IN PCHAR Pathname
+ );
+
+PCONFIGURATION_COMPONENT
+FwGetParent
+ (
+ IN PCONFIGURATION_COMPONENT Component
+ );
+
+VOID
+FwStallExecution
+ (
+ IN ULONG Seconds
+ );
+
+ARC_STATUS
+AllocateMemoryResources
+ (
+ IN OUT PFW_MD pBuffFwMd
+ );
+
+
+// ----------------------------------------------------------------------------
+// Declare General Function Prototypes
+// ----------------------------------------------------------------------------
+
+PCHAR
+FwToUpperStr
+ (
+ IN OUT PCHAR s
+ );
+
+PCHAR
+FwToLowerStr
+ (
+ IN OUT PCHAR s
+ );
+
+PCHAR
+FwGetPath
+ (
+ IN PCONFIGURATION_COMPONENT Component,
+ OUT PCHAR String
+ );
+
+VOID
+FwDelCfgTreeNode
+ (
+ IN PCONFIGURATION_COMPONENT pComp,
+ IN BOOLEAN Peer
+ );
+
+PCHAR
+FwGetMnemonic
+ (
+ IN PCONFIGURATION_COMPONENT Component
+ );
+
+BOOLEAN
+FwValidMnem
+ (
+ IN PCHAR Str
+ );
+
+ULONG
+Fw2UcharToUlongLSB
+ (
+ IN PUCHAR String
+ );
+
+ULONG
+Fw3UcharToUlongLSB
+ (
+ IN PUCHAR String
+ );
+
+ULONG
+Fw4UcharToUlongLSB
+ (
+ IN PUCHAR String
+ );
+
+ULONG
+Fw4UcharToUlongMSB
+ (
+ IN PUCHAR String
+ );
+
+PCHAR
+FwStoreStr
+ (
+ IN PCHAR Str
+ );
+
+
+// ----------------------------------------------------------------------------
+// GLOBAL: EISA configuration variables
+// ----------------------------------------------------------------------------
+
+
+// EISA buses info
+
+EISA_BUS_INFO EisaBusInfo[ EISA_BUSES ]; // eisa bus info pointers
+
+// descriptor pointers
+
+PFW_MD LogFwMdBase = NULL; // starting logical descriptors pointer
+PFW_MD VirFwMdBase = NULL; // starting virtual descriptors pointer
+PFW_MD pFwMdPool; // descriptors pool
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaIni:
+//
+// DESCRIPTION: This function does the eisa controller configuration.
+//
+// ARGUMENTS: none
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS: ErrorWord
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaIni
+ (
+ VOID
+ )
+{
+ // define local variables
+
+ PCONFIGURATION_COMPONENT pEisaComp; // eisa bus component
+ CHAR EisaMnemonic[MAX_MNEMONIC_LEN +1]; // to hold the eisa path
+ ULONG EisaBus; // eisa bus number
+ BOOLEAN IniOk; // EISA configuration bus status
+
+ PRINTDBG("EisaIni\n\r"); // DEBUG SUPPORT
+
+ //
+ // perform any general initialization
+ //
+
+ EisaGeneralIni();
+
+// NOTE: EisaMemIni not used on JAZZ.
+// if ( !EisaMemIni() )
+// {
+// EisaStrErrorLog("EISA Initialization", MemAllocError);
+// return;
+// }
+
+ //
+ // initialize and configure the eisa buses (one per loop)
+ //
+
+ for ( EisaBus = 0; EisaBus < EISA_BUSES; EisaBus++ )
+ {
+ //
+ // display message
+ //
+
+ FwPrint(EISA_INIT_MSG, EisaBus);
+
+ //
+ // eisa bus structures initialization
+ //
+
+ if ( !EisaBusStructIni( EisaBus ))
+ {
+ EisaStrErrorLog( EISA_BUS_MSG, MemAllocError);
+ return;
+ }
+
+ //
+ // eisa bus hardware test and initialization
+ //
+
+ if ( EisaBusInfo[ EisaBus ].Flags.Error = !EisaBusPod( EisaBus ))
+ {
+// ErrorWord |= E_HARDWARE_ERROR;
+ }
+
+ //
+ // check the EISA adapter component
+ //
+
+ IniOk = TRUE;
+ EisaCheckpointFirstFase( EisaCfg );
+ if ( !EisaCheckAdapterComponent( EisaBus, &pEisaComp ))
+ {
+ IniOk = FALSE;
+ }
+
+ //
+ // Return if no EISA information available.
+ //
+
+ if (pEisaComp == NULL) {
+ return;
+ }
+
+ //
+ // configure the bus if no hardware errors and configuration jumper not
+ // present.
+ //
+
+// NOTE: FlagWord is not used in JAZZ.
+// if (!EisaBusInfo[EisaBus].Flags.Error && !(FlagWord & F_CONFIG_JUMPER))
+ if (!EisaBusInfo[EisaBus].Flags.Error)
+ {
+ if ( !EisaBusCfg( pEisaComp ))
+ {
+ IniOk = FALSE;
+ }
+ }
+ EisaCheckpointFinalFase( EisaCfg, IniOk );
+
+ if ( IniOk != TRUE )
+ {
+// NOTE: Not used in JAZZ.
+// ErrorWord |= E_CONFIG_ERROR;
+ }
+
+ //
+ // store the POD initialization status
+ //
+
+ EisaBusInfo[ EisaBus ].Flags.IniDone = 1;
+ pEisaComp->Flags.Failed = EisaBusInfo[ EisaBus ].Flags.Error;
+
+ if (IniOk == TRUE) {
+ FwPrint(EISA_OK_MSG);
+ FwStallExecution(500000);
+ }
+ FwPrint(EISA_CRLF_MSG);
+ }
+
+ //
+ // Big Endian initialization
+ //
+
+// NOTE: BigEndian is not used on JAZZ.
+// BiEndianIni();
+
+ //
+ // EISA dynamic memory initializzation
+ //
+
+// NOTE: EisaDynMemIni not used on JAZZ.
+// EisaDynMemIni();
+
+ //
+ // OMF initialization: final phase
+ //
+
+// NOTE: EisaOmfIni not used on JAZZ.
+// EisaOmfIni();
+
+ //
+ // Write out the hardware id, JAZZ only. The first page of the EISA
+ // I/O control space is actually translated into a page of memory, where
+ // the hardware ID is stored.
+ //
+
+ *(PUCHAR)(EISA_EXTERNAL_IO_VIRTUAL_BASE + 0x0c80) = (('J' - 'A' + 1) << 2) +
+ (('A' - 'A' + 1) >> 3);
+ *(PUCHAR)(EISA_EXTERNAL_IO_VIRTUAL_BASE + 0x0c81) = (('A' - 'A' + 1) << 5) +
+ ('Z' - 'A' + 1);
+ *(PUCHAR)(EISA_EXTERNAL_IO_VIRTUAL_BASE + 0x0c82) = 0;
+ *(PUCHAR)(EISA_EXTERNAL_IO_VIRTUAL_BASE + 0x0c83) = 0;
+
+ //
+ // all done
+ //
+
+ return;
+}
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaGeneralIni:
+//
+// DESCRIPTION: This function performs general initialization
+// for the EISA buses.
+//
+// ARGUMENTS: none
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaGeneralIni
+ (
+ VOID
+ )
+{
+ PRINTDBG("EisaGeneralIni\n\r"); // DEBUG SUPPORT
+
+ //
+ // update system parameter block
+ //
+
+ SYSTEM_BLOCK->AdapterCount = 1;
+
+ SYSTEM_BLOCK->Adapter0Type = EisaAdapter;
+
+ SYSTEM_BLOCK->Adapter0Length = (ULONG)MaximumEisaRoutine * sizeof(ULONG);
+
+ SYSTEM_BLOCK->Adapter0Vector = (PVOID)(SYSTEM_BLOCK->VendorVector +
+ SYSTEM_BLOCK->VendorVectorLength);
+
+ //
+ // initialize EISA call back vectors
+ //
+
+ (PEISA_PROCESS_EOI_RTN)SYSTEM_BLOCK->Adapter0Vector
+ [ProcessEOIRoutine] = EisaProcessEndOfInterrupt;
+// [ProcessEOIRoutine] = FwpReservedRoutine;
+
+ (PEISA_TEST_INT_RTN)SYSTEM_BLOCK->Adapter0Vector
+ [TestIntRoutine] = EisaTestEisaInterrupt;
+// [TestIntRoutine] = FwpReservedRoutine;
+
+ (PEISA_REQ_DMA_XFER_RTN)SYSTEM_BLOCK->Adapter0Vector
+// [RequestDMARoutine] = EisaRequestEisaDmaTransfer;
+ [RequestDMARoutine] = FwpReservedRoutine;
+
+ (PEISA_ABORT_DMA_RTN)SYSTEM_BLOCK->Adapter0Vector
+// [AbortDMARoutine] = EisaAbortEisaDmaTransfer;
+ [AbortDMARoutine] = FwpReservedRoutine;
+
+ (PEISA_DMA_XFER_STATUS_RTN)SYSTEM_BLOCK->Adapter0Vector
+// [GetDMAStatusRoutine] = EisaGetEisaDmaTransferStatus;
+ [GetDMAStatusRoutine] = FwpReservedRoutine;
+
+ (PEISA_LOCK_RTN)SYSTEM_BLOCK->Adapter0Vector
+// [DoLockRoutine] = EisaDoLockedOperation;
+ [DoLockRoutine] = FwpReservedRoutine;
+
+ (PEISA_REQUEST_BUS_MASTER_RTN)SYSTEM_BLOCK->Adapter0Vector
+// [RequestBusMasterRoutine] = EisaRequestEisaBusMasterTransfer;
+ [RequestBusMasterRoutine] = FwpReservedRoutine;
+
+ (PEISA_RELEASE_BUS_MASTER_RTN)SYSTEM_BLOCK->Adapter0Vector
+// [ReleaseBusMasterRoutine] = EisaReleaseEisaBusMasterTransfer;
+ [ReleaseBusMasterRoutine] = FwpReservedRoutine;
+
+ (PEISA_REQUEST_CPU_TO_BUS_ACCESS_RTN)SYSTEM_BLOCK->Adapter0Vector
+// [RequestCpuAccessToBusRoutine] = EisaRequestCpuAccessToEisaBus;
+ [RequestCpuAccessToBusRoutine] = FwpReservedRoutine;
+
+ (PEISA_RELEASE_CPU_TO_BUS_ACCESS_RTN)SYSTEM_BLOCK->Adapter0Vector
+// [ReleaseCpuAccessToBusRoutine] = EisaReleaseCpuAccessToEisaBus;
+ [ReleaseCpuAccessToBusRoutine] = FwpReservedRoutine;
+
+ (PEISA_FLUSH_CACHE_RTN)SYSTEM_BLOCK->Adapter0Vector
+// [FlushCacheRoutine] = EisaFlushCache;
+ [FlushCacheRoutine] = FwpReservedRoutine;
+
+ (PEISA_INVALIDATE_CACHE_RTN)SYSTEM_BLOCK->Adapter0Vector
+// [InvalidateCacheRoutine] = EisaInvalidateCache;
+ [InvalidateCacheRoutine] = FwpReservedRoutine;
+
+ (PEISA_BEGIN_CRITICAL_SECTION_RTN)SYSTEM_BLOCK->Adapter0Vector
+ [BeginCriticalSectionRoutine] = EisaBeginCriticalSection;
+// [BeginCriticalSectionRoutine] = FwpReservedRoutine;
+
+ (PEISA_RESERVED_RTN)SYSTEM_BLOCK->Adapter0Vector
+ [ReservedRoutine] = NULL;
+
+ (PEISA_END_CRITICAL_SECTION_RTN)SYSTEM_BLOCK->Adapter0Vector
+ [EndCriticalSectionRoutine] = EisaEndCriticalSection;
+// [EndCriticalSectionRoutine] = FwpReservedRoutine;
+
+ (PEISA_GENERATE_TONE_RTN)SYSTEM_BLOCK->Adapter0Vector
+ [GenerateToneRoutine] = EisaGenerateTone;
+
+ (PEISA_FLUSH_WRITE_BUFFER_RTN)SYSTEM_BLOCK->Adapter0Vector
+// [FlushWriteBuffersRoutine] = EisaFlushWriteBuffers;
+ [FlushWriteBuffersRoutine] = FwpReservedRoutine;
+
+ (PEISA_YIELD_RTN)SYSTEM_BLOCK->Adapter0Vector
+// [YieldRoutine] = EisaYield;
+ [YieldRoutine] = FwpReservedRoutine;
+
+ (PEISA_STALL_PROCESSOR_RTN)SYSTEM_BLOCK->Adapter0Vector
+ [StallProcessorRoutine] = FwStallExecution;
+
+ //
+ // all done
+ //
+
+ return;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaBusStructIni:
+//
+// DESCRIPTION: This function builds all the required structures
+// for the specified EISA bus.
+//
+// ARGUMENTS: BusNumber EISA bus number
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES: This routine is hardware design dependent.
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaBusStructIni
+ (
+ IN ULONG BusNumber
+ )
+{
+
+ //
+ // define local variables
+ //
+
+ PVOID pInfo; // General pointer
+ PEISA_BUS_INFO pBusInfo; // EISA bus info pointer
+ PFW_MD pIoBusInfo; // I/O info pointer
+ PFW_MD pMemBusInfo; // Memory info pointer
+ PEISA_SLOTS_INFO pSlotsInfo; // Slots info pointer
+ PEISA_DMA_INFO pDmaInfo; // DMA info pointer
+ PEISA_INT_INFO pIntInfo; // INT info pointer
+ PEISA_PORT_INFO pPortInfo; // port info pointer
+ ULONG Index; // general index
+
+ PRINTDBG("EisaBusStructIni\n\r"); // DEBUG SUPPORT
+
+ //
+ // initialize variables
+ //
+
+ pBusInfo = &EisaBusInfo[ BusNumber ];
+ pBusInfo->Flags.IniDone = 0;
+
+ //
+ // first EISA bus
+ //
+
+ if ( BusNumber == 0 )
+ {
+ //
+ // perform any info structure initialization
+ //
+
+ if ((pInfo = (PVOID)FwAllocatePool( sizeof( FW_MD ) +
+ sizeof( FW_MD ) +
+ sizeof( EISA_SLOTS_INFO ) +
+ sizeof( EISA_DMA_INFO ) +
+ sizeof( EISA_INT_INFO ))) == NULL )
+ {
+ return FALSE;
+ }
+
+
+ //
+ // I/O bus info initialization
+ //
+
+ pBusInfo->IoBusInfo = pIoBusInfo = (PFW_MD)pInfo;
+
+ // set link and flags
+
+ pIoBusInfo->Link = NULL;
+ pIoBusInfo->Flags.Busy = 1;
+ pIoBusInfo->Counter = 1;
+
+ // set window size in 4k units
+
+ pIoBusInfo->PhysAddr = EISA_IO_PHYSICAL_BASE/PAGE_SIZE;
+ pIoBusInfo->PagOffs = 0;
+ pIoBusInfo->VirAddr = (PVOID)EISA_EXTERNAL_IO_VIRTUAL_BASE;
+ pIoBusInfo->Size = 64 * 1024;
+ pIoBusInfo->PagNumb = 64/4;
+
+ ((PFW_MD)pInfo)++;
+
+
+ //
+ // memory bus info initialization
+ //
+
+ pBusInfo->MemBusInfo = pMemBusInfo = (PFW_MD)pInfo;
+
+ // set link and flags
+
+ pMemBusInfo->Link = NULL;
+ pMemBusInfo->Flags.Busy = 0; // window busy flag
+ pMemBusInfo->Counter = 0;
+
+#ifdef KPW4010
+
+ // set size of window in 4k units
+
+ pMemBusInfo->PhysAddr = EISA_MEM_PHYSBASE_KPW4010; // #4kpages
+ pMemBusInfo->PagOffs = 0;
+ pMemBusInfo->VirAddr = (PVOID)EISA_VIR_MEM;
+ pMemBusInfo->Size = 0; // 4 Gbytes
+ pMemBusInfo->PagNumb = PAGES_IN_4G;
+
+ //
+ // Because the EISA memory space in some designs can reach
+ // 4Gbytes of length, it is not possible to map the entire area.
+ // The allocation of the TLB entries for this space is done at
+ // run time using the general calls to the TLB services.
+ //
+
+ pMemBusInfo->u.em.WinRelAddr = 0;
+ pMemBusInfo->u.em.WinRelAddrCtrl = NULL;
+ pMemBusInfo->u.em.WinShift = PAGE_4G_SHIFT;
+
+#else // KPW 4000
+
+ // set size of window in 4k units
+
+ pMemBusInfo->PhysAddr = EISA_MEMORY_PHYSICAL_BASE/PAGE_SIZE;
+ pMemBusInfo->PagOffs = 0;
+ pMemBusInfo->VirAddr = (PVOID)EISA_MEMORY_VIRTUAL_BASE;
+ pMemBusInfo->Size = PAGE_16M_SIZE;
+ pMemBusInfo->PagNumb = PAGE_16M_SIZE/PAGE_SIZE;
+
+ //
+ // Because the EISA memory space in some designs can reach
+ // 4Gbytes of length, it is not possible to map the entire area.
+ // The allocation of the TLB entries for this space is done at
+ // run time using the general calls to the TLB services.
+ //
+
+ pMemBusInfo->u.em.WinRelAddr = 0;
+ pMemBusInfo->u.em.WinRelAddrCtrl = (PVOID)EISA_LATCH_VIRTUAL_BASE;
+ pMemBusInfo->u.em.WinShift = PAGE_16M_SHIFT;
+
+#endif
+
+ ((PFW_MD)pInfo)++;
+
+
+ //
+ // slot info initialization
+ //
+
+ pBusInfo->SlotsInfo = pSlotsInfo = (PEISA_SLOTS_INFO)pInfo;
+ pSlotsInfo->PhysSlots = PHYS_0_SLOTS;
+ pSlotsInfo->VirSlots = VIR_0_SLOTS;
+ ((PEISA_SLOTS_INFO)pInfo)++;
+
+
+ //
+ // DMA info initialization
+ //
+
+ pBusInfo->DmaInfo = pDmaInfo = (PEISA_DMA_INFO)pInfo;
+ pDmaInfo->Flags.IniDone = 0;
+ ((PEISA_DMA_INFO)pInfo)++;
+
+
+ //
+ // PIC info initialization
+ //
+
+ pBusInfo->IntInfo = pIntInfo = (PEISA_INT_INFO)pInfo;
+ pIntInfo->Flags.IniDone = 0;
+ ((PEISA_INT_INFO)pInfo)++;
+
+
+ //
+ // port info initialization
+ //
+
+ pBusInfo->PortInfo = pPortInfo = (PEISA_PORT_INFO)pInfo;
+ pPortInfo->Flags.IniDone = 0;
+
+ }
+ else
+ {
+ //
+ // invalid bus number
+ //
+
+ return FALSE;
+ }
+
+ //
+ // all done
+ //
+
+ return TRUE;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaCheckAdapterComponent:
+//
+// DESCRIPTION: This function makes sure that there is an EISA adapter
+// component with the correct configuration data for the
+// specified EISA bus number. The routine uses the
+// following logic :
+//
+// if !(ARC component present)
+// {
+// add ARC component;
+// }
+// if (EISA bus component present)
+// {
+// if !(configuration data correct)
+// {
+// display error message;
+// delete EISA bus node;
+// add EISA bus component;
+// return FALSE;
+// }
+// }
+// else
+// {
+// add EISA bus component;
+// }
+// return TRUE;
+//
+// ARGUMENTS: BusNumber EISA bus number
+// pEisaComp address where to store the EISA
+// configuration pointer
+//
+// RETURN: FALSE The configuration tree was incorrect.
+// TRUE The configuration tree is correct.
+//
+// ASSUMPTIONS: The ARC component is present.
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaCheckAdapterComponent
+ (
+ IN ULONG BusNumber,
+ OUT PCONFIGURATION_COMPONENT *pEisaComp
+ )
+{
+ //
+ // define local variables
+ //
+
+ PCONFIGURATION_COMPONENT pComp;
+ CONFIGURATION_COMPONENT Comp;
+ EISA_ADAPTER_DETAILS ConfigData;
+ BOOLEAN CfgOk = TRUE;
+ CHAR EisaMnemonic[MAX_MNEMONIC_LEN +1];
+ PVOID IoStart;
+ ULONG IoSize;
+ ULONG Slots;
+
+ PRINTDBG("EisaCheckAdapterComponent\n\r"); // DEBUG SUPPORT
+
+ //
+ // initialize varables
+ //
+
+ sprintf( EisaMnemonic, "eisa(%lu)", BusNumber );
+ *pEisaComp = NULL;
+ IoStart = EisaBusInfo[ BusNumber ].IoBusInfo->VirAddr;
+ IoSize = EisaBusInfo[ BusNumber ].SlotsInfo->PhysSlots * 0x1000;
+ Slots = EisaBusInfo[ BusNumber ].SlotsInfo->VirSlots ?
+ EisaBusInfo[ BusNumber ].SlotsInfo->VirSlots + 16 :
+ EisaBusInfo[ BusNumber ].SlotsInfo->PhysSlots;
+
+ //
+ // if EISA adapter component is present, check its configuration data
+ //
+
+ if ((*pEisaComp = FwGetComponent(EisaMnemonic)) != NULL)
+ {
+ if ((*pEisaComp)->ConfigurationDataLength !=
+ sizeof(EISA_ADAPTER_DETAILS) ||
+ FwGetConfigurationData( (PVOID)&ConfigData, *pEisaComp ) ||
+ ConfigData.NumberOfSlots != Slots ||
+ ConfigData.IoStart != IoStart ||
+ ConfigData.IoSize != IoSize )
+ {
+ EisaPathErrorLog( *pEisaComp, CfgIncorrect );
+ FwDelCfgTreeNode( *pEisaComp, FALSE );
+ *pEisaComp = NULL;
+ CfgOk = FALSE;
+ }
+ }
+
+ //
+ // add EISA adapter component if not present
+ //
+
+ if ( *pEisaComp == NULL )
+ {
+ // get the root component pointer
+
+ if ((pComp = FwGetChild(NULL)) == NULL) {
+ return(FALSE);
+ }
+
+ // component structure
+
+ RtlZeroMemory( &Comp, sizeof(CONFIGURATION_COMPONENT));
+ Comp.Class = AdapterClass;
+ Comp.Type = EisaAdapter;
+ Comp.Version = ARC_VERSION;
+ Comp.Revision = ARC_REVISION;
+ Comp.Key = BusNumber;
+ Comp.ConfigurationDataLength = sizeof(EISA_ADAPTER_DETAILS);
+ Comp.IdentifierLength = sizeof("EISA");
+ Comp.Identifier = "EISA";
+
+ // configuration data structure
+
+ RtlZeroMemory( &ConfigData, sizeof(EISA_ADAPTER_DETAILS));
+// NOTE: ConfigDataHeader is not used in JAZZ.
+// ConfigData.ConfigDataHeader.Version = ARC_VERSION;
+// ConfigData.ConfigDataHeader.Revision = ARC_REVISION;
+// ConfigData.ConfigDataHeader.Type = NULL;
+// ConfigData.ConfigDataHeader.Vendor = NULL;
+// ConfigData.ConfigDataHeader.ProductName = NULL;
+// ConfigData.ConfigDataHeader.SerialNumber = NULL;
+ ConfigData.NumberOfSlots = Slots;
+ ConfigData.IoStart = IoStart;
+ ConfigData.IoSize = IoSize;
+
+ *pEisaComp = FwAddChild( pComp, &Comp, (PVOID)&ConfigData );
+ }
+
+ //
+ // return status
+ //
+
+ return CfgOk;
+}
+
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaBusCfg:
+//
+// DESCRIPTION: This function configures the slots of the specified
+// eisa bus.
+//
+// if we detect a "not-ready" board, we have to retry
+// reading the ID again and report a time-out error if
+// the ID is still not available after 100 msecs.
+// (according to the EISA specs, the board should be
+// ready within 100 msecs after reporting the "not-ready"
+// status). However, due to the slow init process of
+// the ESC-1, we need to go with the following algorithm:
+// - cfg the physical slots, marking the ones not ready.
+// - cfg the virtual slots
+// - go back to cfg the not-ready physical slots.
+// A time of 2 sec will be given to all these not-ready
+// slots : 200 loops of 10 msec. This period does not
+// include configuration time for any slot which now
+// comes up with a valid ID.
+//
+// ARGUMENTS: EisaComponent EISA component pointer
+//
+// RETURN: TRUE Configuration completed successfully
+// FALSE At least one configuration error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaBusCfg
+ (
+ IN PCONFIGURATION_COMPONENT EisaComponent
+ )
+{
+
+ //
+ // define local variables
+ //
+
+ BOOLEAN CfgOk = TRUE; // starting value: all fine
+ ULONG IdTimeoutFlags = 0; // eisa controllers in time-out
+ USHORT WaitTimeout=TIMEOUT_UNITS; // time to wait before aborting
+ PCONFIGURATION_COMPONENT FirstController; // first eisa controller
+ PCONFIGURATION_COMPONENT Controller; // eisa controller to configure
+ ULONG BusNumber; // eisa bus number
+ ULONG PhysSlots; // eisa physical slots
+ ULONG MaxSlots; // eisa last slot
+ ULONG SlotNumber; // slot number configured
+ PULONG pSlotCfgMap; // slot cfg map pointer
+ PUCHAR EisaIoStart; // i/o eisa starting space
+ ULONG AdapId; // eisa controller id
+
+ PRINTDBG("EisaBusCfg\n\r"); // DEBUG SUPPORT
+
+ //
+ // initialize same variables using the eisa component structure
+ //
+
+ BusNumber = EisaComponent->Key;
+ EisaIoStart = EisaBusInfo[ BusNumber ].IoBusInfo->VirAddr;
+ PhysSlots = EisaBusInfo[ BusNumber ].SlotsInfo->PhysSlots;
+ MaxSlots = EisaBusInfo[ BusNumber ].SlotsInfo->VirSlots + 16;
+ pSlotCfgMap = &EisaBusInfo[ BusNumber ].SlotsInfo->SlotCfgMap;
+ *pSlotCfgMap = 0;
+ FirstController = FwGetChild(EisaComponent);
+
+ //
+ // physical slot initialization : one loop per physical slot
+ //
+
+ for (SlotNumber=0; SlotNumber<PhysSlots; SlotNumber++)
+ {
+ // read eisa controller id
+
+ if (!EisaReadReadyId(EisaIoStart, SlotNumber, &AdapId))
+ {
+ IdTimeoutFlags |= 1<<SlotNumber;
+ continue;
+ }
+
+ // find the eisa controller for the specified slot
+
+ for (Controller = FirstController;
+ Controller!=NULL && Controller->Key!=SlotNumber;
+ Controller = FwGetPeer(Controller));
+
+ // skip cfg if empty slot; report an error if ARC cfg is missing
+
+ if (Controller==NULL)
+ {
+ if (AdapId!=NO_ADAP_ID)
+ {
+ EisaSlotErrorLog( BusNumber, SlotNumber, CfgMissing );
+ CfgOk = FALSE;
+ }
+ continue;
+ }
+
+ // one physical slot configuration
+
+ if (!EisaPhysSlotCfg(BusNumber, Controller, AdapId))
+ {
+ CfgOk = FALSE;
+ continue;
+ }
+
+ // set the "slot" bit to indicate configuration ok
+
+ *pSlotCfgMap |= 1<<SlotNumber;
+
+ // I/O function structures initialization
+
+// NOTE: EisaOmf is not supported in JAZZ.
+// EisaOmfCheck( BusNumber, Controller, AdapId );
+
+ }
+
+
+
+ //
+ // virtual slot initialization : one loop per virtual slot
+ //
+
+ for (SlotNumber=16; SlotNumber<MaxSlots; SlotNumber++)
+ {
+ // find the eisa controller for the specified slot
+
+ for (Controller = FirstController;
+ Controller!=NULL && Controller->Key!=SlotNumber;
+ Controller = FwGetPeer(Controller));
+
+ // if component not present, skip to next virtual slot
+
+ if (Controller==NULL)
+ {
+ continue;
+ }
+
+ // one virtual slot configuration
+
+ if(!EisaVirSlotCfg(BusNumber, Controller))
+ {
+ CfgOk = FALSE;
+ continue;
+ }
+
+ // set the "slot" bit to indicate configuration ok
+
+ *pSlotCfgMap |= 1<<SlotNumber;
+ }
+
+
+
+ //
+ // time-out slot initialization
+ //
+
+ while(IdTimeoutFlags && WaitTimeout--)
+ {
+ for ( SlotNumber = 0;
+ IdTimeoutFlags && SlotNumber < PHYS_0_SLOTS;
+ SlotNumber++ )
+ {
+ // check if the slot wasn't ready.
+
+ if ( !(IdTimeoutFlags & 1<<SlotNumber))
+ {
+ continue;
+ }
+
+ // read eisa controller id
+
+ if (!EisaReadReadyId(EisaIoStart, SlotNumber, &AdapId))
+ {
+ continue;
+ }
+ IdTimeoutFlags &= ~(1<<SlotNumber);
+
+ // find the eisa controller for the specified slot
+
+ for (Controller = FirstController;
+ Controller!=NULL && Controller->Key!=SlotNumber;
+ Controller = FwGetPeer(Controller));
+
+ // skip cfg if empty slot; report an error if ARC cfg is missing
+
+ if (Controller==NULL)
+ {
+ if (AdapId!=NO_ADAP_ID)
+ {
+ EisaSlotErrorLog(BusNumber, SlotNumber, CfgMissing);
+ CfgOk = FALSE;
+ }
+ continue;
+ }
+
+ // one physical slot configuration
+
+ if (!EisaPhysSlotCfg(BusNumber, Controller, AdapId))
+ {
+ CfgOk = FALSE;
+ continue;
+ }
+
+ // set the "slot" bit to indicate configuration ok
+
+ *pSlotCfgMap |= 1<<SlotNumber;
+
+ // I/O function structures initialization
+
+// NOTE: EisaOmf is not supported in JAZZ.
+// EisaOmfCheck( BusNumber, Controller, AdapId );
+ }
+
+ // if there are still some slots in time-out stall execution
+ // for 10 msec (10,000 usec).
+
+ if (IdTimeoutFlags)
+ {
+ FwStallExecution (10000l);
+ }
+ }
+
+ //
+ // if controllers in time-out, display error messages and set the
+ // failed bit within the associated "components".
+ //
+
+ if (IdTimeoutFlags)
+ {
+ for ( SlotNumber = 0; SlotNumber < PHYS_0_SLOTS; SlotNumber++ )
+ {
+ if ( IdTimeoutFlags & 1<<SlotNumber )
+ {
+ // display error message
+
+ EisaSlotErrorLog( BusNumber, SlotNumber, IdTimeout );
+
+ // find the eisa controller for the specified slot
+
+ for (Controller = FirstController;
+ Controller!=NULL && Controller->Key!=SlotNumber;
+ Controller = FwGetPeer(Controller));
+
+ // if component present, set failed bit
+
+ if (Controller != NULL)
+ {
+ Controller->Flags.Failed = 1;
+ }
+ }
+ }
+ CfgOk = FALSE;
+ }
+
+// //
+// // add a wild omf path name for the physical slots non configurated.
+// //
+//
+// for ( SlotNumber = 0; SlotNumber < PHYS_0_SLOTS; SlotNumber++ )
+// {
+// if ( !(*pSlotCfgMap & 1<<SlotNumber) )
+// {
+// EisaOtherOmfIni( EisaComponent, SlotNumber );
+// }
+// }
+
+ //
+ // return configuration status
+ //
+
+ return CfgOk;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaPhysSlotCfg:
+//
+// DESCRIPTION: This function configures the specified physical slot.
+//
+// ARGUMENTS: BusNumber EISA bus number
+// Controller eisa controller component pointer.
+// AdapId Eisa Id read from hardware.
+//
+//
+// RETURN: FALSE Error
+// TRUE All done
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaPhysSlotCfg
+ (
+ IN ULONG BusNumber,
+ IN PCONFIGURATION_COMPONENT Controller,
+ IN ULONG AdapId
+ )
+{
+ //
+ // define local variables
+ //
+
+ EISA_SLOT_INFO EisaSlotInfo; // pointer to first eisa info
+ EISA_CFG_ERROR ErrMessage = CfgNoErrCode; // eisa cfg error code
+
+ PRINTDBG("EisaPhysSlotCfg\n\r"); // DEBUG SUPPORT
+
+ //
+ // validate physical slot configuration
+ //
+
+ if (Controller->Flags.Failed)
+ {
+ ErrMessage = CfgDeviceFailed; // device failure
+ }
+
+ else if ( !(Controller->ConfigurationDataLength) )
+ {
+ ErrMessage = CfgMissing; // eisa configuration missing
+ }
+
+ else if (Controller->ConfigurationDataLength < EISA_SLOT_MIN_INFO)
+ {
+ ErrMessage = CfgIncorrect; // configuration length incorrect
+ }
+
+ else if (FwGetConfigurationDataIndex( (PVOID)&EisaSlotInfo,
+ Controller,
+ CONFIGDATAHEADER_SIZE,
+ EISA_SLOT_INFO_SIZE ))
+ {
+ ErrMessage = CfgIncorrect; // invalid component
+ }
+
+ else if (EisaSlotInfo.FunctionsNumber * EISA_FUNC_INFO_SIZE +
+ EISA_SLOT_MIN_INFO != Controller->ConfigurationDataLength)
+ {
+ ErrMessage = CfgIncorrect; // configuration length incorrect
+ }
+
+ else if (!(EisaSlotInfo.IdInfo & CFG_UNREADABLE_ID)^(AdapId != NO_ADAP_ID))
+ {
+ ErrMessage = CfgIdError; // wrong configuration
+ }
+
+ else if (AdapId != NO_ADAP_ID &&
+ AdapId != Fw4UcharToUlongMSB(&EisaSlotInfo.Id1stChar))
+ {
+ ErrMessage = CfgIdError; // wrong configuration
+ }
+
+ else if ((EisaSlotInfo.IdInfo & CFG_SLOT_MASK) != CFG_SLOT_EXP &&
+ (EisaSlotInfo.IdInfo & CFG_SLOT_MASK) != CFG_SLOT_EMB )
+ {
+ ErrMessage = CfgIncorrect; // wrong configuration
+ }
+
+ //
+ // if any error, dispaly error message and set the failed bit
+ //
+
+ if (ErrMessage != CfgNoErrCode)
+ {
+ EisaSlotErrorLog( BusNumber, Controller->Key, ErrMessage );
+ Controller->Flags.Failed = 1;
+ return FALSE;
+ }
+
+ //
+ // eisa adapter configuration
+ //
+
+ return( EisaSlotCfg( BusNumber,
+ Controller,
+ EisaSlotInfo.FunctionsNumber ));
+}
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaVirSlotCfg:
+//
+// DESCRIPTION: This function configures the specified virtual slot.
+//
+// ARGUMENTS: BusNumber EISA bus number
+// Controller eisa controller component pointer.
+//
+//
+// RETURN: FALSE Error
+// TRUE All done
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaVirSlotCfg
+ (
+ IN ULONG BusNumber,
+ IN PCONFIGURATION_COMPONENT Controller
+ )
+{
+ //
+ // define local variables
+ //
+
+ EISA_SLOT_INFO EisaSlotInfo; // pointer to first eisa info
+ EISA_CFG_ERROR ErrMessage = CfgNoErrCode; // eisa cfg error code
+
+ PRINTDBG("EisaVirSlotCfg\n\r"); // DEBUG SUPPORT
+
+ //
+ // validate virtual slot configuration
+ //
+
+ if (Controller->Flags.Failed)
+ {
+ ErrMessage = CfgDeviceFailed; // device failure
+ }
+
+ else if ( !(Controller->ConfigurationDataLength) )
+ {
+ ErrMessage = CfgMissing; // configuration missing
+ }
+
+ if (Controller->ConfigurationDataLength < EISA_SLOT_MIN_INFO)
+ {
+ ErrMessage = CfgIncorrect; // configuration length incorrect
+ }
+
+ else if (FwGetConfigurationDataIndex( (PVOID)&EisaSlotInfo,
+ Controller,
+ CONFIGDATAHEADER_SIZE,
+ EISA_SLOT_INFO_SIZE ))
+ {
+ ErrMessage = CfgIncorrect; // invalid component
+ }
+
+ else if (EisaSlotInfo.FunctionsNumber * EISA_FUNC_INFO_SIZE +
+ EISA_SLOT_MIN_INFO != Controller->ConfigurationDataLength)
+ {
+ ErrMessage = CfgIncorrect; // configuration length incorrect
+ }
+
+ else if ( !(EisaSlotInfo.IdInfo & CFG_UNREADABLE_ID) )
+ {
+ ErrMessage = CfgIdError; // wrong configuration
+ }
+
+ else if ( (EisaSlotInfo.IdInfo & CFG_SLOT_MASK) != CFG_SLOT_VIR)
+ {
+ ErrMessage = CfgIncorrect; // wrong configuration
+ }
+
+ //
+ // if any error, display error message and set the failed bit
+ //
+
+ if (ErrMessage != CfgNoErrCode)
+ {
+ EisaSlotErrorLog( BusNumber, Controller->Key, ErrMessage );
+ Controller->Flags.Failed = 1;
+ return FALSE;
+ }
+
+ //
+ // eisa adapter configuration
+ //
+
+ return( EisaSlotCfg( BusNumber,
+ Controller,
+ EisaSlotInfo.FunctionsNumber ));
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaSlotCfg:
+//
+// DESCRIPTION: This function configures the specified slot.
+//
+// ARGUMENTS: BusNumber EISA bus number
+// Controller Controller component pointer
+// FunctionsNumber Number of function to configure
+//
+// RETURN: TRUE Configuration done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaSlotCfg
+ (
+ IN ULONG BusNumber,
+ IN PCONFIGURATION_COMPONENT Controller,
+ IN UCHAR FunctionsNumber
+ )
+{
+ //
+ // define local variables
+ //
+
+ UCHAR FuncFlags; // function info flags
+ UCHAR Function; // current function number
+ BOOLEAN CfgOk = TRUE; // local configuration status
+ BOOLEAN EnabAdapter = TRUE; // adapter enable flag
+ PUCHAR EnabPort; // used to enable the adapter
+ PUCHAR EisaIoStart; // Eisa I/O virtual space
+ PEISA_DMA_INFO pDmaInfo; // DMA info pointer
+ PEISA_INT_INFO pIntInfo; // interrupts info pointer
+ BOOLEAN CfgMemOk = TRUE; // prevent multiple messages
+ BOOLEAN CfgIrqOk = TRUE; // " " "
+ BOOLEAN CfgDmaOk = TRUE; // " " "
+ BOOLEAN CfgIniOk = TRUE; // " " "
+ UCHAR EisaFuncInfo[ EISA_FUNC_INFO_SIZE ];
+ ULONG EisaFuncIndex;
+
+ PRINTDBG("EisaSlotCfg\n\r"); // DEBUG SUPPORT
+
+ //
+ // initialize variables
+ //
+
+ EisaIoStart = (PUCHAR)EisaBusInfo[ BusNumber ].IoBusInfo->VirAddr;
+ pDmaInfo = EisaBusInfo[ BusNumber ].DmaInfo;
+ pIntInfo = EisaBusInfo[ BusNumber ].IntInfo;
+ EisaFuncIndex = EISA_SLOT_MIN_INFO;
+
+ //
+ // one function per loop
+ //
+
+ for ( Function = 0;
+ Function < FunctionsNumber;
+ Function++, EisaFuncIndex += EISA_FUNC_INFO_SIZE )
+ {
+ //
+ // read function info
+ //
+
+ FwGetConfigurationDataIndex( (PVOID)EisaFuncInfo,
+ Controller,
+ EisaFuncIndex,
+ EISA_FUNC_INFO_SIZE );
+ //
+ // check if configuration complete, exit if not.
+ //
+
+ if ( EisaFuncInfo[ CFG_SLOT_INFO_OFS ] & CFG_INCOMPLETE )
+ {
+ EisaSlotErrorLog( BusNumber, Controller->Key, CfgIncomplete );
+ CfgOk = FALSE;
+ break;
+ }
+
+ // update eisa function flags
+
+ FuncFlags = EisaFuncInfo[ CFG_FN_INFO_OFS ];
+
+ // skip if free form function
+
+ if ( FuncFlags & CFG_FREE_FORM )
+ {
+ continue;
+ }
+
+ //
+ // check if there is any memory entry
+ //
+
+// NOTE: Eisa memory not supported on JAZZ.
+// if ( FuncFlags & CFG_MEM_ENTRY )
+// {
+// if ( !EisaSlotCfgMem( BusNumber, Controller->Key, EisaFuncInfo ) &&
+// CfgMemOk )
+// {
+// EisaSlotErrorLog( BusNumber, Controller->Key, CfgMemError );
+// CfgOk = CfgMemOk = FALSE;
+// }
+// }
+
+
+ //
+ // check if there is any interrupt entry
+ //
+
+ if ( FuncFlags & CFG_IRQ_ENTRY )
+ {
+ if (!EisaSlotCfgIrq( EisaIoStart, pIntInfo, EisaFuncInfo ) &&
+ CfgIrqOk )
+ {
+ EisaSlotErrorLog( BusNumber, Controller->Key, CfgIrqError );
+ CfgOk = CfgIrqOk = FALSE;
+ }
+ }
+
+
+ //
+ // check if there is any DMA entry
+ //
+
+ if ( FuncFlags & CFG_DMA_ENTRY )
+ {
+ if ( !EisaSlotCfgDma( EisaIoStart, pDmaInfo, EisaFuncInfo ) &&
+ CfgDmaOk )
+ {
+ EisaSlotErrorLog( BusNumber, Controller->Key, CfgDmaError );
+ CfgOk = CfgDmaOk = FALSE;
+ }
+ }
+
+
+ //
+ // check if there is any port init entry
+ //
+
+ if ( FuncFlags & CFG_INI_ENTRY )
+ {
+ if ( !EisaSlotCfgIni( EisaIoStart, EisaFuncInfo, &EnabAdapter ) &&
+ CfgIniOk )
+ {
+ EisaSlotErrorLog( BusNumber, Controller->Key, CfgIniError );
+ CfgOk = CfgIniOk = FALSE;
+ }
+ }
+ }
+
+ //
+ // if all fine, enable the adapter
+ //
+
+ if (CfgOk && EnabAdapter)
+ {
+ EnabPort=EisaIoStart+ Controller->Key*0x1000 +EXPANSION_BOARD_CTRL_BITS;
+ EisaOutUchar(EnabPort, EisaInUchar(EnabPort) | 0x01);
+ }
+
+ //
+ // return status of configuration process
+ //
+
+ return CfgOk;
+}
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaSlotCfgMem:
+//
+// DESCRIPTION: This function configures the eisa memory registers
+// based on info from NVRAM.
+//
+// ARGUMENTS: BusNumber EISA bus number.
+// SlotNumber EISA slot number.
+// EisaFuncInfo Function info pointer.
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+// NOTE: Eisa memory not supported on JAZZ.
+#if 0
+
+BOOLEAN
+EisaSlotCfgMem
+ (
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PUCHAR EisaFuncInfo
+ )
+{
+ //
+ // define local variables
+ //
+
+ BOOLEAN CfgOk = TRUE; // local configuration status
+ PUCHAR MemBlock; // start of DMA data buffer
+ USHORT Index = 0; // index within the memory block
+ PFW_MD pFwMd; // memory decriptor pointer
+ ULONG Addr; // address in 256 units
+ ULONG Size; // size in 1k units
+ ULONG WinSize, WinOffs; // EISA windows characteristic
+ PFW_MD pMemInfo; // EISA memory address space info
+
+ PRINTDBG("EisaSlotCfgMem\n\r"); // DEBUG SUPPORT
+
+ //
+ // initialize variables
+ //
+
+ pMemInfo = EisaBusInfo[ BusNumber ].MemBusInfo;
+ MemBlock = &EisaFuncInfo[ CFG_MEM_BLK_OFS ];
+
+ //
+ // one loop per each memory entry
+ //
+
+ do
+ {
+ //
+ // get a memory descriptor
+ //
+
+ if ( (pFwMd = GetFwMd()) == NULL )
+ {
+ EisaSlotErrorLog( BusNumber, SlotNumber, MemAllocError);
+ return FALSE;
+ }
+
+ //
+ // memory block start and length
+ //
+
+ Addr = Fw3UcharToUlongLSB( &MemBlock[Index + 2] );
+ Size = Fw2UcharToUlongLSB( &MemBlock[Index + 5] );
+
+ pFwMd->VirAddr = NULL;
+ pFwMd->PhysAddr = Addr >> 4;
+ pFwMd->PagOffs = (Addr << 8) & (PAGE_SIZE - 1);
+ pFwMd->Size = Size ? Size << 10 : 64*1024*1024 ;
+ pFwMd->PagNumb = (pFwMd->PagOffs + Size + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ pFwMd->Cache = FALSE;
+ pFwMd->u.m.BusNumber = BusNumber;
+ pFwMd->u.m.SlotNumber = SlotNumber;
+ pFwMd->u.m.Type = MemBlock[ Index ] & CFG_MEM_TYPE;
+
+ //
+ // check if the memory size fits within the EISA window
+ //
+
+ if ( pMemInfo->u.em.WinShift != PAGE_4G_SHIFT )
+ {
+ // window size < 4 Gbytes
+
+ WinSize = 1 << pMemInfo->u.em.WinShift;
+ WinOffs = (Addr << 8) & (WinSize - 1);
+ if ( WinSize - WinOffs < pFwMd->Size )
+ {
+ ReleaseFwMd( &pMemInfo->Link, pFwMd );
+ CfgOk = FALSE;
+ continue;
+ }
+ }
+
+ //
+ // link the memory descriptor
+ //
+
+ if ( LinkPhysFwMd( &pMemInfo->Link, pFwMd ) == NULL )
+ {
+ ReleaseFwMd( &pMemInfo->Link, pFwMd );
+ CfgOk = FALSE;
+ continue;
+ }
+ }
+ while ((MemBlock[Index]&CFG_MORE_ENTRY) && ((Index+=7)<CFG_MEM_BLK_LEN));
+
+ //
+ // check final index
+ //
+
+ if ( !(Index < CFG_MEM_BLK_LEN) )
+ {
+ CfgOk=FALSE;
+ }
+
+ //
+ // return configuration status
+ //
+
+ return CfgOk;
+}
+#endif // 0
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaSlotCfgIrq:
+//
+// DESCRIPTION: This function configures the interrupt registers
+// based on info from NVRAM.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pIntInfo interrupt info pointer
+// EisaFuncInfo function info pointer.
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaSlotCfgIrq
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_INT_INFO pIntInfo,
+ IN PUCHAR EisaFuncInfo
+ )
+{
+ //
+ // define local variables
+ //
+
+ BOOLEAN CfgOk = TRUE; // local configuration status
+ PUCHAR IrqBlock; // start of IRQ data buffer
+ USHORT Index = 0; // index within the IRQ block
+ USHORT IrqBit; // 0x1=IRQ0... 0x8000=IRQ15
+ UCHAR Register; // used to update the registers
+
+ PRINTDBG("EisaSlotCfgIrq\n\r"); // DEBUG SUPPORT
+
+ //
+ // initialize variables
+ //
+
+ IrqBlock = &EisaFuncInfo[ CFG_IRQ_BLK_OFS ];
+
+ //
+ // one loop per each IRQ entries
+ //
+
+ do
+ {
+ IrqBit = 1 << ( IrqBlock[ Index ] & CFG_IRQ_MASK ); // compute IRQ bit
+
+ //
+ // check shareable and edge/level trigger mode
+ //
+
+ if ( pIntInfo->IrqPresent & IrqBit )
+ {
+ //
+ // IRQ already used: check if it is shareabe
+ //
+
+ if ( !(pIntInfo->IrqShareable & IrqBit) )
+ {
+ CfgOk = FALSE;
+ continue;
+ }
+ else if ( !(IrqBlock[Index] & CFG_IRQ_SHARE) )
+ {
+ CfgOk = FALSE;
+ continue;
+ }
+
+ //
+ // IRQ is shareable: check if the levels are compatible
+ //
+
+ else if ( (pIntInfo->IrqLevel & IrqBit) &&
+ !(IrqBlock[Index] & CFG_IRQ_LEVEL) )
+ {
+ CfgOk=FALSE;
+ continue;
+ }
+ else if ( !(pIntInfo->IrqLevel & IrqBit) &&
+ (IrqBlock[Index] & CFG_IRQ_LEVEL) )
+ {
+ CfgOk=FALSE;
+ continue;
+ }
+ }
+ else
+ {
+ //
+ // new IRQ: check if the IRQ 0, 1, 2, 8 and 13 are configurated
+ // for edge triggered.
+ //
+
+ switch(IrqBit)
+ {
+ case (0x0001): // IRQ 0 only edge triggered
+ case (0x0002): // IRQ 1 " " "
+ case (0x0004): // IRQ 2 " " "
+ case (0x0100): // IRQ 8 " " "
+ case (0x2000): // IRQ 13 " " "
+
+ if (IrqBlock[Index] & CFG_IRQ_LEVEL)
+ {
+ CfgOk=FALSE;
+ continue;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ //
+ // set the present bit and update sharable and edge/level
+ // triggered variables
+ //
+
+ pIntInfo->IrqPresent |= IrqBit;
+
+ if (IrqBlock[Index] & CFG_IRQ_SHARE)
+ {
+ pIntInfo->IrqShareable |= IrqBit;
+ }
+
+ if (IrqBlock[Index] & CFG_IRQ_LEVEL)
+ {
+ pIntInfo->IrqLevel |= IrqBit;
+ }
+ }
+ while ((IrqBlock[Index]&CFG_MORE_ENTRY) && ((Index+=2)<CFG_IRQ_BLK_LEN));
+
+ //
+ // check final index
+ //
+
+ if ( !( Index < CFG_IRQ_BLK_LEN ) )
+ {
+ CfgOk=FALSE;
+ }
+
+ //
+ // initialize ELCR registers with new values.
+ //
+
+ Register = EisaInUchar(EisaIoStart + PIC1_ELCR);
+ Register &= ~(pIntInfo->IrqPresent);
+ Register |= pIntInfo->IrqLevel;
+ EisaOutUchar(EisaIoStart + PIC1_ELCR, Register);
+
+ Register = EisaInUchar(EisaIoStart + PIC2_ELCR);
+ Register &= ~(pIntInfo->IrqPresent >> BITSXBYTE);
+ Register |= pIntInfo->IrqLevel >> BITSXBYTE;
+ EisaOutUchar(EisaIoStart + PIC2_ELCR, Register);
+
+ //
+ // return configuration status
+ //
+
+ return CfgOk;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaSlotCfgDma:
+//
+// DESCRIPTION: This function configures the DMA registers
+// based on info from NVRAM.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pDmaInfo DMA info pointer
+// EisaFuncInfo function info pointer.
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaSlotCfgDma
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo,
+ IN PUCHAR EisaFuncInfo
+ )
+{
+ //
+ // define local variables
+ //
+
+ BOOLEAN CfgOk=TRUE; // local configuration status
+ PUCHAR DmaBlock; // start of DMA data buffer
+ USHORT Index=0; // index within the DMA block
+ UCHAR DmaNumber; // DMA under configuration
+ UCHAR Register; // used to update the registers
+
+ PRINTDBG("EisaSlotCfgDma\n\r"); // DEBUG SUPPORT
+
+ //
+ // initialize variables
+ //
+
+ DmaBlock = &EisaFuncInfo[ CFG_DMA_BLK_OFS ];
+
+ //
+ // one loop per each DMA entry
+ //
+
+ do
+ {
+ //
+ // skip if shareable. device drivers should init DMA, not ROM
+ //
+
+ // NOTE: the following code has been removed because all the
+ // EISA cards that share the same DMA channel have the
+ // same value in this register. This is guaranteed by
+ // the configuration utility.
+
+ //if ( DmaBlock[Index] & CFG_DMA_SHARED )
+ //{
+ // continue;
+ //}
+
+ //
+ // Program the specified DMA channel using the new info.
+ //
+
+ DmaNumber = DmaBlock[Index] & CFG_DMA_MASK;
+
+ // keep the "stop register" and "T-C" bits
+
+ Register = pDmaInfo->DmaExtReg[ DmaNumber ] & ~CFG_DMA_CFG_MASK;
+
+ // use the new timing and bit I/O selection
+
+ Register |= DmaBlock[Index+1] & CFG_DMA_CFG_MASK;
+
+ // update the register
+
+ if (DmaNumber < 4)
+ {
+ EisaOutUchar(EisaIoStart + DMA_EXTMODE03, Register);
+ }
+ else
+ {
+ EisaOutUchar(EisaIoStart + DMA_EXTMODE47, Register);
+ }
+
+ // This register value is used to validate the DMA requestes
+ // (see the "EisaRequestEisaDmaTransfer" function).
+ // The DMA channels used by more than one card have always the
+ // same value ( check with the configuration guys ).
+
+ pDmaInfo->DmaExtReg[ DmaNumber ] = Register;
+
+ }
+ while ((DmaBlock[Index]&CFG_MORE_ENTRY) && ((Index+=2)<CFG_DMA_BLK_LEN));
+
+ //
+ // check final index
+ //
+
+ if ( !(Index < CFG_DMA_BLK_LEN) )
+ {
+ CfgOk=FALSE;
+ }
+
+ //
+ // return configuration status
+ //
+
+ return CfgOk;
+}
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaSlotCfgIni:
+//
+// DESCRIPTION: This function configures the I/O port registers
+// based on info from NVRAM.
+//
+// ARGUMENTS: EisaIoStart Starting eisa I/O area.
+// EisaFuncInfo Function info pointer.
+// EnabAdapter Enable adapter flag pointer.
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaSlotCfgIni
+ (
+ IN PUCHAR EisaIoStart,
+ IN PUCHAR EisaFuncInfo,
+ OUT PBOOLEAN EnabAdapter
+ )
+{
+ //
+ // define local variables
+ //
+
+ BOOLEAN CfgOk = TRUE; // local configuration status
+ PUCHAR IniBlock; // start of init data buffer
+ USHORT Index = 0; // index within the init block
+ USHORT Next = 0; // index within the entry
+ USHORT IoPort; // I/O address port
+ UCHAR ByteValue; // used to init the registers
+ UCHAR ByteMask; //
+ USHORT ShortValue; // used to init the registers
+ USHORT ShortMask; //
+ ULONG WordValue; // used to init the registers
+ ULONG WordMask; //
+
+ PRINTDBG("EisaSlotCfgIni\n\r"); // DEBUG SUPPORT
+
+ // initialize variables
+
+ IniBlock = &EisaFuncInfo[CFG_INI_BLK_OFS];
+
+ //
+ // one loop per each init entries
+ //
+
+ do
+ {
+ // load the i/o address port
+
+ Next = 1;
+ IoPort = IniBlock[Index + Next++];
+ IoPort |= IniBlock[Index + Next++] << BITSXBYTE;
+
+ switch(IniBlock[Index] & CFG_INI_MASK)
+ {
+ //
+ // 8-bit I/O access
+ //
+
+ case(CFG_INI_BYTE):
+
+ ByteValue = IniBlock[Index + Next++];
+
+ if (IniBlock[Index] & CFG_INI_PMASK) // use the mask
+ {
+ ByteMask = IniBlock[Index + Next++];
+ ByteValue |= READ_REGISTER_UCHAR(EisaIoStart+IoPort) & ByteMask;
+ EISA_IO_DELAY;
+ }
+
+ if ((IoPort & 0x0FFF) == EXPANSION_BOARD_CTRL_BITS)
+ {
+ *EnabAdapter=FALSE;
+ }
+ WRITE_REGISTER_UCHAR(EisaIoStart+IoPort, ByteValue);
+ EISA_IO_DELAY;
+ break;
+
+ //
+ // 16-bit I/O access
+ //
+
+ case(CFG_INI_HWORD):
+
+ ShortValue = IniBlock[Index + Next++];
+ ShortValue |= IniBlock[Index + Next++] << BITSXBYTE;
+
+ if (IniBlock[Index] & CFG_INI_PMASK) // use the mask
+ {
+ ShortMask = IniBlock[Index + Next++];
+ ShortMask |= IniBlock[Index + Next++] << BITSXBYTE;
+ ShortValue |= READ_REGISTER_USHORT(EisaIoStart + IoPort) &
+ ShortMask;
+ EISA_IO_DELAY;
+ }
+
+ WRITE_REGISTER_USHORT(EisaIoStart + IoPort, ShortValue);
+ EISA_IO_DELAY;
+ break;
+
+ //
+ // 32-bit I/O access
+ //
+
+ case(CFG_INI_WORD):
+
+ WordValue = Fw4UcharToUlongLSB( &IniBlock[Index + Next] );
+ Next += 4;
+
+ if (IniBlock[Index]&CFG_INI_PMASK) // use the mask
+ {
+ WordMask = Fw4UcharToUlongLSB( &IniBlock[Index + Next] );
+ Next += 4;
+ WordValue |= READ_REGISTER_ULONG(EisaIoStart + IoPort) &
+ WordMask;
+ EISA_IO_DELAY;
+ }
+
+ WRITE_REGISTER_ULONG(EisaIoStart + IoPort, WordValue);
+ EISA_IO_DELAY;
+ break;
+
+ //
+ // error
+ //
+
+ default:
+ CfgOk=FALSE;
+ break;
+ }
+ }
+ while ((IniBlock[Index]&CFG_MORE_ENTRY) && ((Index+=Next)<CFG_INI_BLK_LEN));
+
+ //
+ // check final index
+ //
+
+ if ( !(Index < CFG_INI_BLK_LEN) )
+ {
+ CfgOk=FALSE;
+ }
+
+ //
+ // return configuration status
+ //
+
+ return CfgOk;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaSlotErrorLog:
+//
+// DESCRIPTION: This function displays the corresponding eisa
+// error message.
+//
+// ARGUMENTS: BusNumber BusNumber (not used)
+// SlotNumber Slot in error
+// ErrorCode Error number.
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaSlotErrorLog
+ (
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN EISA_CFG_ERROR ErrorCode
+ )
+{
+ PRINTDBG("EisaSlotErrorLog\n\r"); // DEBUG SUPPORT
+
+ // display the error message
+
+ FwPrint( EISA_ERROR_SLOT_MSG, SlotNumber, EisaCfgMessages[ErrorCode] );
+ FwMoveCursorToColumn( 37 );
+ FwPrint( EISA_ERROR1_MSG );
+ FwStallExecution(1500000);
+
+ // all done
+
+ return;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaPathErrorLog:
+//
+// DESCRIPTION: This function displays the corresponding eisa
+// error message.
+//
+// ARGUMENTS: Component Component in error.
+// ErrorCode Error number.
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaPathErrorLog
+ (
+ IN PCONFIGURATION_COMPONENT Controller,
+ IN EISA_CFG_ERROR ErrorCode
+ )
+{
+ CHAR Path[ MAX_DEVICE_PATH_LEN +1 ];
+
+ PRINTDBG("EisaPathErrorLog\n\r"); // DEBUG SUPPORT
+
+ EisaStrErrorLog( FwGetPath( Controller, Path ), ErrorCode );
+
+ return;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaStrErrorLog:
+//
+// DESCRIPTION: This function displays the corresponding eisa
+// error message.
+//
+// ARGUMENTS: Str String Message
+// ErrorCode Error number.
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaStrErrorLog
+ (
+ IN PCHAR Str,
+ IN EISA_CFG_ERROR ErrorCode
+ )
+{
+ PRINTDBG("EisaStrErrorLog\n\r"); // DEBUG SUPPORT
+
+ FwPrint( "\r\n %s %s ", Str, EisaCfgMessages[ErrorCode] );
+ if ( strlen(Str) + strlen(EisaCfgMessages[ErrorCode]) + 2 < 36 )
+ {
+ FwMoveCursorToColumn( 37 );
+ }
+ FwPrint( EISA_ERROR1_MSG );
+ FwStallExecution(1500000);
+
+ return;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaCheckpointFirstFase:
+//
+// DESCRIPTION: This function displays the specified checkpoint
+// number on the internal LED and sends it to the
+// parallel port.
+//
+// ARGUMENTS: Chk checkpoint number
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaCheckpointFirstFase
+ (
+ IN EISA_CHECKPOINT Chk
+ )
+{
+ ULONG TestFlags;
+
+ PRINTDBG("EisaCheckpointFirstFase\n\r"); // DEBUG SUPPORT
+
+ TestFlags = ( (ULONG)EisaCheckpointInfo[ Chk ].SubLed << 28 ) +
+ ( (ULONG)EisaCheckpointInfo[ Chk ].Led << 24 ) +
+ ( (ULONG)EisaCheckpointInfo[ Chk ].SubPar << 8 ) +
+ ( (ULONG)EisaCheckpointInfo[ Chk ].Par );
+
+// NOTE: The parallel port test flag support is not used on JAZZ.
+// DisplayOnParallelPort( TestFlags );
+
+ return;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaCheckpointFinalFase:
+//
+// DESCRIPTION: This function returns the value of the specified
+// real-time clock internal address.
+//
+// ARGUMENTS: Chk checkpoint number
+// Passed pass or fail
+//
+// RETURN: Repeat = TRUE repeat checkpoint
+// = FALSE continue
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaCheckpointFinalFase
+ (
+ IN EISA_CHECKPOINT Chk,
+ IN BOOLEAN Passed
+ )
+{
+ ULONG TestFlags;
+
+ PRINTDBG("EisaCheckpointFinalFase\n\r"); // DEBUG SUPPORT
+
+ if ( Passed )
+ {
+ EisaCheckpointInfo[ Chk ].Flags &= ~0x01; // all fine
+ EisaCheckpointInfo[ Chk ].Flags &= ~0x08; // no message
+ }
+ else
+ {
+ EisaCheckpointInfo[ Chk ].Flags |= 0x01; // error
+
+ if ( EisaCheckpointInfo[ Chk ].Flags & 0x08 ) // display message
+ {
+ FwPrint( "%s", EisaCheckpointInfo[ Chk ].Msg );
+ FwStallExecution(1500000);
+ }
+ }
+
+ TestFlags = (( (ULONG)EisaCheckpointInfo[ Chk ].SubLed << 28 ) +
+ ( (ULONG)EisaCheckpointInfo[ Chk ].Led << 24 ) +
+ ( (ULONG)EisaCheckpointInfo[ Chk ].Flags << 16 ) +
+ ( (ULONG)EisaCheckpointInfo[ Chk ].SubPar << 8 ) +
+ ( (ULONG)EisaCheckpointInfo[ Chk ].Par ));
+
+// TEMPTEMP: Changed until we get the EvaluateTestResult routine from Olivetti.
+// return EvaluateTestResult( TestFlags ) == ESUCCESS ? FALSE : TRUE;
+
+ return(FALSE); // Never repeat.
+}
+
+
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaReadReadyId:
+//
+// DESCRIPTION: This function reads the eisa id of the specified
+// slot.
+//
+// ARGUMENTS: EisaIoStart Starting eisa I/O address.
+// SlotNumber Eisa slot number.
+// AdapId Eisa ID returned.
+//
+// RETURN: FALSE Time-out error
+// TRUE Valid adapter Id
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaReadReadyId
+ (
+ IN PUCHAR EisaIoStart,
+ IN ULONG SlotNumber,
+ OUT PULONG AdapId
+ )
+{
+ // define local variables
+
+ BOOLEAN Ready=TRUE;
+
+ PRINTDBG("EisaReadReadyId\n\r"); // DEBUG SUPPORT
+
+
+ //
+ // read adapter id
+ //
+
+ EisaReadId(EisaIoStart, SlotNumber, AdapId);
+
+
+ //
+ // check if adapter id is ready
+ //
+
+ if ( *AdapId & NO_ADAP_ID )
+ {
+ *AdapId = NO_ADAP_ID; // empty slot
+ }
+ else if ((*AdapId & WAIT_ADAP_ID) == WAIT_ADAP_ID)
+ {
+ Ready = FALSE; // adapter not ready
+ }
+
+ return Ready;
+}
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaReadId:
+//
+// DESCRIPTION: This function reads the eisa id of the specified
+// slot.
+//
+// ARGUMENTS: EisaIoStart Starting eisa I/O address.
+// SlotNumber Eisa slot number.
+// AdapId Eisa ID returned.
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaReadId
+ (
+ IN PUCHAR EisaIoStart,
+ IN ULONG SlotNumber,
+ OUT PULONG AdapId
+ )
+{
+ // define local variables
+
+ PUCHAR AdapIdPort; // eisa I/O ID port
+ PUCHAR RefreshPort; // eisa refresh port
+ UCHAR RefreshStatus; // eisa refresh status (port 61h)
+ ULONG Retry; // # retry
+
+ PRINTDBG("EisaReadId\n\r"); // DEBUG SUPPORT
+
+ // initialize variables
+
+ AdapIdPort = EisaIoStart + SlotNumber * 0x1000 + EISA_PRODUCT_ID;
+ RefreshPort = EisaIoStart + EISA_SYS_CTRL_PORTB;
+
+ // wait for the end of a refresh cycle (bit 4 of port 61h toggles)
+
+ for ( Retry = EISA_RFR_RETRY,
+ RefreshStatus = READ_REGISTER_UCHAR(RefreshPort) & EISA_REFRESH;
+
+ Retry &&
+ RefreshStatus == (READ_REGISTER_UCHAR(RefreshPort) & EISA_REFRESH);
+
+ Retry-- );
+
+ // write 0xFF to the adapter ID port
+
+ EisaOutUchar(AdapIdPort, 0xFF);
+
+ // read adapter id
+
+ *AdapId = EisaInUchar(AdapIdPort++);
+ *AdapId = *AdapId << BITSXBYTE | EisaInUchar(AdapIdPort++);
+ *AdapId = *AdapId << BITSXBYTE | EisaInUchar(AdapIdPort++);
+ *AdapId = *AdapId << BITSXBYTE | EisaInUchar(AdapIdPort++);
+
+ // all done, return.
+
+ return;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaMemIni:
+//
+// DESCRIPTION: This function allocates memory for the descriptor
+// pool and computes the top address and the length
+// of a physical contiguous memory block to be used as
+// OMF device drivers and dynamic memory pool.
+// Note that only the memory really used will be
+// allocated.
+//
+// ARGUMENTS: none
+//
+// RETURN: TRUE all done
+// FALSE memory initialization error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS: pFwMdPool // descriptor pool
+// MemorySize // memory size in Mbytes
+// EisaPoolSize // # bytes really used
+// EisaFreeTop // top of free mem
+// EisaDynMemSize // dynamic memory size (bytes)
+// EisaFreeBytes // free bytes left
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+// NOTE: Not used for JAZZ.
+#if 0
+
+BOOLEAN
+EisaMemIni
+ (
+ VOID
+ )
+{
+ FW_MD BuffFwMd;
+ PVOID Dummy;
+
+ PRINTDBG("EisaMemIni\n\r"); // DEBUG SUPPORT
+
+ //
+ // allocate descriptor pool
+ //
+
+ if ( (pFwMdPool = (PFW_MD)FwAllocatePool( sizeof(FW_MD)*FW_MD_POOL ))
+ == NULL )
+ {
+ return FALSE;
+ }
+
+ //
+ // set all the necessary TLB entries to map the whole system memory
+ //
+
+ RtlZeroMemory( &BuffFwMd, sizeof(FW_MD));
+ BuffFwMd.Size = 256 << 20;
+ BuffFwMd.PagNumb = 256 << (20 - PAGE_SHIFT);
+ BuffFwMd.Cache = TRUE;
+
+ if ( AllocateMemoryResources( &BuffFwMd ) != ESUCCESS )
+ {
+ return FALSE;
+ }
+
+ //
+ // compute OMF device drivers and dynamic memory pool area
+ //
+
+ EisaPoolSize = EisaDynMemSize = EISA_DYN_MEM_SIZE;
+
+ if ( MemorySize >= 16 )
+ {
+ //
+ // we don't use the memory above 16Mbytes because in this way we
+ // can use this logic in a machine without translation registers
+ // (logical I/O to physical) for the ISA boards which have a
+ // transfer range of 24 bits (16Mbytes).
+ //
+
+ EisaFreeTop = EISA_FREE_TOP_16;
+ EisaFreeBytes = EISA_FREE_BYTES_16;
+ }
+ else if ( MemorySize >= 12 )
+ {
+ EisaFreeTop = EISA_FREE_TOP_12;
+ EisaFreeBytes = EISA_FREE_BYTES_12;
+ }
+ else if ( MemorySize >= 8 )
+ {
+ EisaFreeTop = EISA_FREE_TOP_8;
+ EisaFreeBytes = EISA_FREE_BYTES_8;
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ EisaFreeBytes -= EisaDynMemSize;
+
+ return TRUE;
+}
+
+#endif // 0
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaDynMemIni:
+//
+// DESCRIPTION: This function allocates the requested space for the
+// the dynamic memory allocation.
+//
+// ARGUMENTS: none
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS: EisaFreeTop top of free mem
+// EisaDynMemSize dynamic memory size (bytes)
+// EisaPoolSize EISA pool size (bytes)
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+// NOTE: Not used for JAZZ.
+#if 0
+
+VOID
+EisaDynMemIni
+ (
+ VOID
+ )
+{
+ //
+ // define local variables
+ //
+
+ ULONG BytesToPage; // bytes left to make a page
+ PHEADER pHdr; // memory descriptor header ptr
+ PVOID Buffer; // data area
+
+ PRINTDBG("EisaDynMemIni\n\r"); // DEBUG SUPPORT
+
+ //
+ // align the dynamic memory buffer on a page boundary
+ //
+
+ BytesToPage = PAGE_SIZE - (EisaDynMemSize & ((1 << PAGE_SHIFT) - 1));
+ EisaDynMemSize += BytesToPage;
+ EisaPoolSize += BytesToPage;
+ EisaFreeTop -= EisaDynMemSize;
+
+ //
+ // initialize first memory descriptor
+ //
+
+ pHdr = (PHEADER)EisaFreeTop;
+ Buffer = (PVOID)(pHdr + 1);
+ pHdr->m.id = Buffer;
+ pHdr->m.size = EisaDynMemSize/sizeof(HEADER);
+ EisaFreeMemory( Buffer );
+
+ return;
+}
+
+#endif // 0
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: FwGetPath:
+//
+// DESCRIPTION: This function builds the path name for the specified
+// component.
+//
+// ARGUMENTS: Component Component pointer.
+// Str Path name pointer.
+//
+// RETURN: Str Path name pointer.
+//
+// ASSUMPTIONS: The string must be large enoungh to hold the
+// requested path name.
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+PCHAR
+FwGetPath
+ (
+ IN PCONFIGURATION_COMPONENT Component,
+ OUT PCHAR Str
+ )
+{
+ PCONFIGURATION_COMPONENT pComp;
+
+ PRINTDBG("FwGetPath\n\r"); // DEBUG SUPPORT
+
+ if ( (pComp = FwGetParent( Component )) != NULL )
+ {
+ FwGetPath( pComp, Str);
+ strcat( Str, FwGetMnemonic( Component ) );
+ sprintf( Str + strlen( Str ), "(%lu)", Component->Key);
+ }
+ else
+ {
+ *Str = '\0';
+ }
+ return Str;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: FwDelCfgTreeNode:
+//
+// DESCRIPTION: This function removes from the configuration tree
+// the specified component and all its children.
+//
+// ARGUMENTS: pComp component pointer.
+// Peer = TRUE delete all its peers.
+// = FALSE delete just this branch.
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+VOID
+FwDelCfgTreeNode
+ (
+ IN PCONFIGURATION_COMPONENT pComp,
+ IN BOOLEAN Peer
+ )
+{
+ //
+ // define local variables
+ //
+
+ PCONFIGURATION_COMPONENT NextComp;
+
+ PRINTDBG("FwDelCfgTreeNode\n\r"); // DEBUG SUPPORT
+
+ //
+ // check for a child
+ //
+
+ if ( (NextComp = FwGetChild( pComp )) != NULL )
+ {
+ FwDelCfgTreeNode( NextComp, TRUE );
+ }
+
+ //
+ // check for a peer.
+ //
+
+ if ( Peer && (NextComp = FwGetPeer( pComp )) != NULL )
+ {
+ FwDelCfgTreeNode( NextComp, TRUE );
+ }
+
+ //
+ // this is a leaf, delete it
+ //
+
+ FwDeleteComponent( pComp );
+
+ //
+ // all done
+ //
+
+ return;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: FwGetMnemonic:
+//
+// DESCRIPTION: This function stores the mnemonic name for the
+// requested component type.
+//
+// ARGUMENTS: Component Component pointer.
+//
+// RETURN: Str Mnemonic pointer
+//
+// ASSUMPTIONS: none
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+PCHAR
+FwGetMnemonic
+ (
+ IN PCONFIGURATION_COMPONENT Component
+ )
+{
+ PRINTDBG("FwGetMnemonic\n\r"); // DEBUG SUPPORT
+
+ return MnemonicTable[Component->Type];
+}
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: FwValidMnem:
+//
+// DESCRIPTION: This function validates the specified mnemonic.
+// If the mnemonic is valid, a TURE value is returned,
+// otherwise a FALSE is returned.
+//
+// ARGUMENTS: Str Mnemonic pointer
+//
+// RETURN: FALSE Mnemonic incorrect
+// TRUE Mnemonic correct
+//
+// ASSUMPTIONS: none
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+FwValidMnem
+ (
+ IN PCHAR Str
+ )
+{
+ // define local variables
+
+ CONFIGURATION_TYPE CfgType;
+
+ PRINTDBG("FwValidMnem\n\r"); // DEBUG SUPPORT
+
+ // check the mnemonic table
+
+ for ( CfgType = ArcSystem;
+ CfgType < MaximumType && strcmp( MnemonicTable[ CfgType ], Str );
+ CfgType++ );
+
+ return CfgType < MaximumType ? TRUE : FALSE;
+}
+
+
+
+// ----------------------------------------------------------------------------
+// GLOBAL: I/O functions variables
+// ----------------------------------------------------------------------------
+
+PCHAR AsciiBlock; // pointer the ASCII block
+ULONG AsciiBlockLength = 0; // length of the ASCII block
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: FwStoreStr:
+//
+// DESCRIPTION: This function stores the specified string within
+// the ASCII block. The NULL pointer is returned if
+// there isn't space available for the string.
+//
+// ARGUMENTS: Str String pointer
+//
+// RETURN: Str String pointer
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+PCHAR
+FwStoreStr
+ (
+ IN PCHAR Str
+ )
+{
+
+ PRINTDBG("FwStoreStr\n\r"); // DEBUG SUPPORT
+
+ // if not enough space, allocate new ASCII block
+
+ if ( AsciiBlockLength < strlen( Str ) + 1 )
+ {
+ if((AsciiBlock = (PUCHAR)FwAllocatePool(ASCII_BLOCK_SIZE)) == NULL)
+ {
+ return NULL;
+ }
+ }
+
+ // store the string and update the pointers.
+
+ Str = strcpy( AsciiBlock, Str );
+ AsciiBlock += strlen( Str ) + 1;
+ AsciiBlockLength = ASCII_BLOCK_SIZE - (strlen( Str ) + 1);
+
+ // all done, return the new string pointer
+
+ return Str;
+}
diff --git a/private/ntos/fw/mips/eisaintr.c b/private/ntos/fw/mips/eisaintr.c
new file mode 100644
index 000000000..176d9f639
--- /dev/null
+++ b/private/ntos/fw/mips/eisaintr.c
@@ -0,0 +1,298 @@
+// ----------------------------------------------------------------------------
+// Copyright (c) 1992 Olivetti
+//
+// File: eisaintr.c
+//
+// Description: EISA code interrupt related routines
+// ----------------------------------------------------------------------------
+//
+
+#include "fwp.h"
+#include "oli2msft.h"
+#include "arceisa.h"
+#include "inc.h"
+#include "string.h"
+#include "debug.h"
+
+
+extern EISA_BUS_INFO EisaBusInfo[];
+
+
+
+
+// ----------------------------------------------------------------------------
+// Declare Function Prototypes
+// ----------------------------------------------------------------------------
+
+
+VOID
+EisaBeginCriticalSection
+ (
+ IN VOID
+ );
+
+VOID
+EisaEndCriticalSection
+ (
+ IN VOID
+ );
+
+ARC_STATUS
+EisaProcessEndOfInterrupt
+ (
+ IN ULONG BusNumber,
+ IN USHORT Irq
+ );
+
+BOOLEAN_ULONG
+EisaTestEisaInterrupt
+ (
+ IN ULONG BusNumber,
+ IN USHORT Irq
+ );
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// General Function Prototypes
+// ----------------------------------------------------------------------------
+
+ULONG
+StatusReg
+ (
+ IN ULONG,
+ IN ULONG
+ );
+
+
+
+
+// ----------------------------------------------------------------------------
+// General : Begin/End Critical Setction functions
+// ----------------------------------------------------------------------------
+
+
+ULONG NestedCounter = 0 ; // nested conter;
+ULONG StatusRegBuff = 0 ; // used to store the old ints status
+ // bits 31-16 Reserved (0)
+ // bits 15- 8 Specific interrupt mask
+ // bits 7- 1 Reserved (0)
+ // bit 0 General Interrupt mask
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaBeginCriticalSection:
+//
+// DESCRIPTION: This function disables all the hardware interrupts
+// except for the EISA NMI interrupt. The old interrupt
+// status is saved for "EisaEndCriticalSection" routine.
+//
+// ARGUMENTS: none
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaBeginCriticalSection
+ (
+ IN VOID
+ )
+{
+ // Disable interrupts (except for the EISA NMI) and save the old interrupt
+ // status only if no previous calls to this routine were made.
+ // The first argument is "&" and the second is "|" with the status
+ // register.
+
+ if ( !NestedCounter++ )
+ {
+ StatusRegBuff = StatusReg(~STATUS_INT_MASK, STATUS_EISA_NMI+STATUS_IE);
+ }
+
+ // all done
+
+ return;
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaEndCriticalSection:
+//
+// DESCRIPTION: This function restores the hardware interrupt status
+// at the CPU level as it was before calling the
+// "EisaBeginCriticalSection" function.
+//
+// ARGUMENTS: none
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaEndCriticalSection
+ (
+ IN VOID
+ )
+{
+ // Restore the interrupts status only if NestedCounter equals zero.
+ // The first argument is "&" and the second is "|" with the status
+ // register.
+
+ if ( !--NestedCounter )
+ {
+ StatusReg(~STATUS_INT_MASK, StatusRegBuff & STATUS_INT_MASK);
+ }
+
+ // all done
+
+ return;
+}
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaProcessEndOfInterrupt:
+//
+// DESCRIPTION: Because the EISA interrupts are masked at PIC
+// (8259A) level, this routine function doesn't need
+// to do anything.
+// It doesn't matter if the interrupt channel is level
+// or edge triggered, when the interrupt sources goes
+// away, the corrisponding bit within the interrupt
+// request register (IRR) is cleared.
+//
+// ARGUMENTS: BusNumber EISA bus number
+// Irq IRQ to process
+//
+// RETURN: ESUCCESS All done
+//
+// ASSUMPTIONS: none
+//
+// CALLS: none
+//
+// GLOBALS: none
+//
+// NOTES: none
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+EisaProcessEndOfInterrupt
+ (
+ IN ULONG BusNumber,
+ IN USHORT Irq
+ )
+{
+ // Return all done.
+
+ return ESUCCESS;
+}
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaTestEisaInterrupt:
+//
+// DESCRIPTION: This function checks if there is an interrupt pending
+// on the specified IRQ.
+//
+// ARGUMENTS: BusNumber EISA bus number
+// Irq IRQ to process
+//
+// RETURN: TRUE Interrupt is pending
+// FALSE Interrupt is not pending
+//
+// ASSUMPTIONS: none
+//
+// CALLS: none
+//
+// GLOBALS: none
+//
+// NOTES: none
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN_ULONG
+EisaTestEisaInterrupt
+ (
+ IN ULONG BusNumber,
+ IN USHORT Irq
+ )
+{
+ // define local variables
+
+ BOOLEAN_ULONG IntPending = FALSE; // assume no interrupt is pending
+ PUCHAR PicPort; // PIC virtual address
+ UCHAR PicMask; // to check the requested IRQ
+
+ // check the IRQ only if the input parameters are valid
+
+// if ( EisaCheckBusNumber( BusNumber ) == ESUCCESS && Irq <= IRQ15 )
+ if ( Irq <= IRQ15 )
+ {
+ // load the virtual address of the specified EISA I/O bus and
+ // build the mask for checking the specified IRQ.
+
+ PicPort = EisaBusInfo[ BusNumber ].IoBusInfo->VirAddr;
+
+ if ( Irq < IRQ8 )
+ {
+ PicPort += PIC1; // the IRQ is on the 1st PIC
+ PicMask = 1 << Irq; // set the mask
+ }
+ else
+ {
+ PicPort += PIC2; // the IRQ is on the 2nd PIC
+ PicMask = 1 << (Irq - IRQ8); // set the mask
+ }
+
+ // to check the spcified IRQ we need to send first an OCW3 command
+ // to the PIC to request the interrupt request register (IRR).
+
+ WRITE_REGISTER_UCHAR( PicPort, OCW3_IRR );
+
+ EISA_IO_DELAY;
+
+ if ( READ_REGISTER_UCHAR(PicPort) & PicMask )
+ {
+ IntPending = TRUE; // interrupt is pending
+ }
+ }
+ // return the specified IRQ status
+
+ return IntPending;
+}
+
+
+
+
+
diff --git a/private/ntos/fw/mips/eisamisc.c b/private/ntos/fw/mips/eisamisc.c
new file mode 100644
index 000000000..b35d3e110
--- /dev/null
+++ b/private/ntos/fw/mips/eisamisc.c
@@ -0,0 +1,213 @@
+// ----------------------------------------------------------------------------
+// Copyright (c) 1992 Olivetti
+//
+// File: eisamisc.c
+//
+// Description: Miscellaneous EISA routines.
+// ----------------------------------------------------------------------------
+//
+
+#include "fwp.h"
+#include "oli2msft.h"
+#include "arceisa.h"
+#include "inc.h"
+#include "string.h"
+#include "debug.h"
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: Fw2UcharToUlongLSB:
+//
+// DESCRIPTION: This function converts 2 uchars to an ulong.
+//
+// ARGUMENTS: String String holding 2 uchars:
+//
+// String[0] LSB
+// String[1] MSB
+//
+// RETURN: ULONG corrisponding ulong value:
+//
+// 0 +
+// 0 +
+// String[1] << 8 +
+// String[0]
+//
+//
+//
+// ASSUMPTIONS: none
+//
+// CALLS: none
+//
+// GLOBALS: none
+//
+// NOTES: none
+// ----------------------------------------------------------------------------
+//
+
+ULONG
+Fw2UcharToUlongLSB
+ (
+ IN PUCHAR String
+ )
+{
+ PRINTDBG("Fw2UcharToUlongLSB\n\r"); // DEBUG SUPPORT
+
+ return ((ULONG)(String[1]) << BITSXBYTE) + (ULONG)(String[0]);
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: Fw3UcharToUlongLSB:
+//
+// DESCRIPTION: This function converts 3 uchars to an ulong.
+//
+// ARGUMENTS: String String holding 3 uchars:
+//
+// String[0] LSB
+// String[1] 2nd
+// String[2] MSB
+//
+// RETURN: ULONG corrisponding ulong value:
+//
+// 0 +
+// String[2] << 16 +
+// String[1] << 8 +
+// String[0]
+//
+//
+//
+// ASSUMPTIONS: none
+//
+// CALLS: none
+//
+// GLOBALS: none
+//
+// NOTES: none
+// ----------------------------------------------------------------------------
+//
+
+ULONG
+Fw3UcharToUlongLSB
+ (
+ IN PUCHAR String
+ )
+{
+ PRINTDBG("Fw2UcharToUlongLSB\n\r"); // DEBUG SUPPORT
+
+ return ((ULONG)(String[2]) << 2*BITSXBYTE) +
+ ((ULONG)(String[1]) << BITSXBYTE) +
+ (ULONG)(String[0]);
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: Fw4UcharToUlongLSB:
+//
+// DESCRIPTION: This function converts 4 uchars to an ulong.
+//
+// ARGUMENTS: String String holding 4 uchars:
+//
+// String[0] LSB
+// String[1] 2nd
+// String[2] 3rd
+// String[3] MSB
+//
+// RETURN: ULONG corrisponding ulong value:
+//
+// String[3] << 24 +
+// String[2] << 16 +
+// String[1] << 8 +
+// String[0]
+//
+//
+//
+// ASSUMPTIONS: none
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ULONG
+Fw4UcharToUlongLSB
+ (
+ IN PUCHAR String
+ )
+{
+ PRINTDBG("Fw4UcharToUlongLSB\n\r"); // DEBUG SUPPORT
+
+ return ((ULONG)(String[3]) << 3*BITSXBYTE) +
+ ((ULONG)(String[2]) << 2*BITSXBYTE) +
+ ((ULONG)(String[1]) << BITSXBYTE) +
+ (ULONG)(String[0]);
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: Fw4UcharToUlongMSB:
+//
+// DESCRIPTION: This function converts 4 uchars to an ulong.
+//
+// ARGUMENTS: String String holding 4 uchars:
+//
+// String[0] MSB
+// String[1] 3rd
+// String[2] 2nd
+// String[3] LSB
+//
+// RETURN: ULONG corrisponding ulong value:
+//
+// String[0] << 24 +
+// String[1] << 16 +
+// String[2] << 8 +
+// String[3]
+//
+//
+//
+// ASSUMPTIONS: none
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ULONG
+Fw4UcharToUlongMSB
+ (
+ IN PUCHAR String
+ )
+{
+ PRINTDBG("Fw4UcharToUlongMSB\n\r"); // DEBUG SUPPORT
+
+ return ((ULONG)(String[0]) << 3*BITSXBYTE) +
+ ((ULONG)(String[1]) << 2*BITSXBYTE) +
+ ((ULONG)(String[2]) << BITSXBYTE) +
+ (ULONG)(String[3]);
+}
+
+
+
+
diff --git a/private/ntos/fw/mips/eisapod.c b/private/ntos/fw/mips/eisapod.c
new file mode 100644
index 000000000..466035cb0
--- /dev/null
+++ b/private/ntos/fw/mips/eisapod.c
@@ -0,0 +1,3675 @@
+// ----------------------------------------------------------------------------
+// Copyright (c) 1992 Olivetti
+//
+// File: eisapod.c
+//
+// Description:
+// ----------------------------------------------------------------------------
+//
+
+#include "fwp.h"
+#include "oli2msft.h"
+#include "arceisa.h"
+#include "inc.h"
+#include "string.h"
+#include "debug.h"
+#include "eisastr.h"
+
+extern EISA_BUS_INFO EisaBusInfo[];
+
+
+// ----------------------------------------------------------------------------
+// Define Function Prototypes
+// ----------------------------------------------------------------------------
+
+BOOLEAN
+EisaBusPod
+ (
+ IN ULONG BusNumber
+ );
+
+BOOLEAN
+EisaIntPod
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_INT_INFO pIntInfo
+ );
+
+VOID
+EisaPicIni
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_INT_INFO pIntInfo
+ );
+
+BOOLEAN
+EisaPicRegTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_INT_INFO pIntInfo
+ );
+
+BOOLEAN
+EisaClearPendingInts
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_INT_INFO pIntInfo
+ );
+
+BOOLEAN
+EisaDmaPod
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ );
+
+BOOLEAN
+EisaDmaMaskTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ );
+
+BOOLEAN
+EisaDmaPageTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ );
+
+BOOLEAN
+EisaDmaAddressTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ );
+
+BOOLEAN
+EisaDmaCountTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ );
+
+BOOLEAN
+EisaDmaStopTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ );
+
+VOID
+EisaDmaIni
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ );
+
+BOOLEAN
+EisaOtherPod
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_PORT_INFO pPortInfo
+ );
+
+BOOLEAN
+EisaNmiTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_PORT_INFO pPortInfo
+ );
+
+BOOLEAN
+EisaNmiHandlerTest
+ (
+ IN ULONG Couse
+ );
+
+BOOLEAN
+EisaNmiHandler
+ (
+ IN ULONG Couse
+ );
+
+VOID
+EisaParityError
+ (
+ IN PUCHAR EisaIoStart
+ );
+
+VOID
+EisaIoChkError
+ (
+ IN PUCHAR EisaIoStart,
+ IN ULONG Slots
+ );
+
+VOID
+EisaBusTimeoutError
+ (
+ IN PUCHAR EisaIoStart,
+ IN ULONG Slots
+ );
+
+VOID
+EisaSlaveTimeoutError
+ (
+ IN PUCHAR EisaIoStart,
+ IN ULONG Slots
+ );
+
+BOOLEAN
+EisaRefreshTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_PORT_INFO pPortInfo
+ );
+
+BOOLEAN
+EisaPort61Test
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_PORT_INFO pPortInfo
+ );
+
+BOOLEAN
+EisaTimer1Test
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_PORT_INFO pPortInfo
+ );
+
+BOOLEAN
+EisaTimer2Test
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_PORT_INFO pPortInfo
+ );
+
+
+
+// ----------------------------------------------------------------------------
+// Define EISA Function Prototypes
+// ----------------------------------------------------------------------------
+
+VOID
+EisaClearPendingInt
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_INT_INFO pIntInfo,
+ IN USHORT Irq
+ );
+
+UCHAR
+EisaAckInt
+ (
+ IN PEISA_INT_INFO pIntInfo
+ );
+
+VOID
+EisaSendSpecificEoi
+ (
+ IN PUCHAR EisaIoStart,
+ IN USHORT Irq
+ );
+
+VOID
+EisaDisableParityIoCheck
+ (
+ IN PUCHAR EisaIoStart
+ );
+
+VOID
+EisaEnableParityIoCheck
+ (
+ IN PUCHAR EisaIoStart
+ );
+
+VOID
+EisaDisableInt
+ (
+ VOID
+ );
+
+VOID
+EisaDisableNmi
+ (
+ IN PUCHAR EisaIoStart
+ );
+
+VOID
+EisaEnableNmi
+ (
+ IN PUCHAR EisaIoStart
+ );
+
+BOOLEAN
+EisaCheckReg
+ (
+ IN PUCHAR Port,
+ IN UCHAR DataMask
+ );
+
+BOOLEAN
+EisaCheckDeepReg
+ (
+ IN PUCHAR Port
+ );
+
+UCHAR
+EisaReadRtc
+ (
+ IN PUCHAR EisaIoStart,
+ IN ULONG RtcIndex
+ );
+
+VOID
+EisaOutUchar
+ (
+ IN PUCHAR Addr,
+ IN UCHAR Value
+ );
+
+UCHAR
+EisaInUchar
+ (
+ IN PUCHAR Addr
+ );
+
+
+
+// ----------------------------------------------------------------------------
+// Define Global Variables
+// ----------------------------------------------------------------------------
+
+EISA_DMA_REGS_TEST EisaDmaRegsTest[ EISA_DMAS ] =
+ {
+ { DMA_ADDR_0, DMA_PAGE_0, DMA_HPAGE_0,
+ DMA_COUNT_0, DMA_HCOUNT_0, DMA_STOP_0 },
+ { DMA_ADDR_1, DMA_PAGE_1, DMA_HPAGE_1,
+ DMA_COUNT_1, DMA_HCOUNT_1, DMA_STOP_1 },
+ { DMA_ADDR_2, DMA_PAGE_2, DMA_HPAGE_2,
+ DMA_COUNT_2, DMA_HCOUNT_2, DMA_STOP_2 },
+ { DMA_ADDR_3, DMA_PAGE_3, DMA_HPAGE_3,
+ DMA_COUNT_3, DMA_HCOUNT_3, DMA_STOP_3 },
+ { DMA_ADDR_4, DMA_PAGE_RFR, 0,
+ DMA_COUNT_4, 0, 0 },
+ { DMA_ADDR_5, DMA_PAGE_5, DMA_HPAGE_5,
+ DMA_COUNT_5, DMA_HCOUNT_5, DMA_STOP_5 },
+ { DMA_ADDR_6, DMA_PAGE_6, DMA_HPAGE_6,
+ DMA_COUNT_6, DMA_HCOUNT_6, DMA_STOP_6 },
+ { DMA_ADDR_7, DMA_PAGE_7, DMA_HPAGE_7,
+ DMA_COUNT_7, DMA_HCOUNT_7, DMA_STOP_7 }
+ };
+
+EISA_DMA_CTRL_TEST EisaDmaCtrlTest[ 2 ] =
+ {
+ {DMA_MASK_CLR03, DMA_MASKS03, DMA_1MASK03, DMA_MASK_STAT03, DMA_CHAIN03},
+ {DMA_MASK_CLR47, DMA_MASKS47, DMA_1MASK47, DMA_MASK_STAT47, DMA_CHAIN47}
+ };
+
+
+BOOLEAN EisaNmiFlag; // for NMI testing
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaBusPod:
+//
+// DESCRIPTION: This function initializes the hardware of the
+// specified EISA bus.
+//
+// ARGUMENTS: BusNumber EISA bus number
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaBusPod
+ (
+ IN ULONG BusNumber
+ )
+{
+ //
+ // define local variables
+ //
+
+ BOOLEAN IniOk = TRUE; // initialization status
+ PEISA_DMA_INFO pDmaInfo; // DMA info pointer
+ PEISA_INT_INFO pIntInfo; // INT info pointer
+ PEISA_PORT_INFO pPortInfo; // PORT info pointer
+ PUCHAR EisaIoStart; // EISA I/O virtual address
+
+ PRINTDBG("EisaBusPod\n\r"); // DEBUG SUPPORT
+
+ //
+ // initialize variables
+ //
+
+ pDmaInfo = EisaBusInfo[ BusNumber ].DmaInfo;
+ pIntInfo = EisaBusInfo[ BusNumber ].IntInfo;
+ pPortInfo = EisaBusInfo[ BusNumber ].PortInfo;
+// EisaIoStart = EisaBusInfo[ BusNumber ].IoBusInfo->VirAddr;
+ EisaIoStart = EISA_IO_VIRTUAL_BASE; // TEMPTEMP
+
+ //
+ // perform any PIC testing and initialization
+ //
+
+ if ( !EisaIntPod( EisaIoStart, pIntInfo ) )
+ {
+ IniOk = FALSE;
+ }
+
+ //
+ // perform any DMA testing and initialization
+ //
+
+ if ( !EisaDmaPod( EisaIoStart, pDmaInfo ) )
+ {
+ IniOk = FALSE;
+ }
+
+ //
+ // perform any other port testing and initialization
+ //
+
+ if ( !EisaOtherPod( EisaIoStart, pPortInfo ) )
+ {
+ IniOk = FALSE;
+ }
+
+ //
+ // return status
+ //
+
+ return IniOk;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaIntPod:
+//
+// DESCRIPTION: This function tests and initializes the PIC for the
+// specified EISA bus.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pIntInfo Interrupt info pointer
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaIntPod
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_INT_INFO pIntInfo
+ )
+{
+ PRINTDBG("EisaIntPod\n\r"); // DEBUG SUPPORT
+
+ //
+ // if ini already done, return status
+ //
+
+ if ( pIntInfo->Flags.IniDone )
+ {
+ return (BOOLEAN)(pIntInfo->Flags.Error);
+ }
+ pIntInfo->Flags.Error = 1; // be pessimistic
+
+ //
+ // first part of checkpoint
+ //
+
+ EisaCheckpointFirstFase( EisaPic );
+
+ //
+ // disable EISA PICs interrupt chain
+ //
+
+ EisaDisableInt();
+
+
+ do
+ {
+ //
+ // initialize PICs
+ //
+
+ EisaPicIni( EisaIoStart, pIntInfo );
+
+ //
+ // test registers
+ //
+
+ if ( !EisaPicRegTest( EisaIoStart, pIntInfo ));
+
+ //
+ // clear any pending interrupt
+ //
+
+ else if ( !EisaClearPendingInts( EisaIoStart, pIntInfo ));
+
+ //
+ // all done
+ //
+
+ else
+ {
+ pIntInfo->IrqPresent = 0;
+ pIntInfo->IrqShareable = 0;
+ pIntInfo->IrqLevel = 0;
+ pIntInfo->Flags.Error = 0;
+ }
+ }
+ while ( EisaCheckpointFinalFase( EisaPic,
+ pIntInfo->Flags.Error ? FALSE : TRUE ));
+
+ //
+ // return to caller
+ //
+
+ pIntInfo->Flags.IniDone = 1;
+ return !(BOOLEAN)(pIntInfo->Flags.Error);
+}
+
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaPicIni:
+//
+// DESCRIPTION: This function initializes the PICs of the specified
+// EISA bus.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pIntInfo Interrupt info pointer
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaPicIni
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_INT_INFO pIntInfo
+ )
+{
+ PUCHAR Pic1Port1, Pic1Port2, Pic2Port1, Pic2Port2;
+
+
+ PRINTDBG("EisaPicIni\n\r"); // DEBUG SUPPORT
+
+ //
+ // initialize variables
+ //
+
+ Pic1Port1 = EisaIoStart + PIC1;
+ Pic1Port2 = EisaIoStart + PIC1 + 1;
+ Pic2Port1 = EisaIoStart + PIC2;
+ Pic2Port2 = EisaIoStart + PIC2 + 1;
+
+ //
+ // Initialize the EISA interrupt controller. There are two cascaded
+ // interrupt controllers, each of which must initialized with 4 initialize
+ // control words.
+ //
+
+ EisaOutUchar( Pic1Port1, 0x11 );
+ EisaOutUchar( Pic2Port1, 0x11 );
+
+ //
+ // The second intitialization control word sets the iterrupt vector to
+ // 0-15.
+ //
+
+ EisaOutUchar( Pic1Port2, 0x00 );
+ EisaOutUchar( Pic2Port2, 0x08 );
+
+ //
+ // The thrid initialization control word set the controls for slave mode.
+ // The master ICW3 uses bit position and the slave ICW3 uses a numberic.
+ //
+
+ EisaOutUchar( Pic1Port2, 0x04 );
+ EisaOutUchar( Pic2Port2, 0x02 );
+
+ //
+ // The fourth initialization control word is used to specify normal
+ // end-of-interrupt mode and not special-fully-nested mode.
+ //
+
+ EisaOutUchar( Pic1Port2, 0x01 );
+ EisaOutUchar( Pic2Port2, 0x01 );
+
+ //
+ // Mask all the interrupts.
+ //
+
+ EisaOutUchar( Pic1Port2, 0xFF );
+ EisaOutUchar( Pic2Port2, 0xFF );
+
+ //
+ // set all interrupts to edge sensitive
+ //
+
+ EisaOutUchar( EisaIoStart + PIC1_ELCR, 0 );
+ EisaOutUchar( EisaIoStart + PIC2_ELCR, 0 );
+
+ return;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaPicRegTest:
+//
+// DESCRIPTION: This function performs a test on the PIC registers.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pIntInfo Interrupt info pointer
+//
+// RETURN: TRUE all correct
+// FALSE error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaPicRegTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_INT_INFO pIntInfo
+ )
+{
+ //
+ // initialize variables
+ //
+
+ BOOLEAN RegOk = FALSE; // be pessimistic
+
+ PRINTDBG("EisaPicRegTest\n\r"); // DEBUG SUPPORT
+
+ //
+ // check mask of 1st PIC
+ //
+
+ if ( !EisaCheckReg( EisaIoStart + PIC1_MASK, 0xFF ));
+
+ //
+ // check mask of 2nd PIC
+ //
+
+ else if ( !EisaCheckReg( EisaIoStart + PIC2_MASK, 0xFF ));
+
+ //
+ // check ELCR 1, but skip bits 0, 1 and 2 (they are reserved)
+ //
+
+ else if ( !EisaCheckReg( EisaIoStart + PIC1_ELCR, 0xF8 ));
+
+ //
+ // check ELCR 2, but skip bits 0 and 5 (they are reserved)
+ //
+
+ else if ( !EisaCheckReg( EisaIoStart + PIC2_ELCR, 0xDE ));
+
+ //
+ // if we got here, everything is fine
+ //
+
+ else
+ {
+ EisaOutUchar( EisaIoStart + PIC1_MASK, 0xFF );
+ EisaOutUchar( EisaIoStart + PIC2_MASK, 0xFF );
+ EisaOutUchar( EisaIoStart + PIC1_ELCR, 0 );
+ EisaOutUchar( EisaIoStart + PIC2_ELCR, 0 );
+ RegOk = TRUE;
+ }
+
+ return RegOk;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaClearPendingInts:
+//
+// DESCRIPTION: This function cleares any pending interrupt at
+// the CPU level.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pIntInfo Interrupt info pointer
+//
+// RETURN: TRUE all correct
+// FALSE error
+//
+// ASSUMPTIONS: interrupts disabled, PIC lines masked and
+// all the IRQ lines are edge triggered.
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaClearPendingInts
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_INT_INFO pIntInfo
+ )
+{
+ //
+ // initialize variables
+ //
+
+ UCHAR Irr; // interrupt request register
+ UCHAR Isr; // interrupt service register
+ USHORT Irq; // interrupt level
+ PUCHAR PicPort; // I/O address
+
+ PRINTDBG("EisaClearPendingInts\n\r"); // DEBUG SUPPORT
+
+ //--------------------------------------------------
+ // send a specific EOI for each in service interrupt
+ //--------------------------------------------------
+
+ //
+ // read ISR PIC1
+ //
+
+ PicPort = EisaIoStart + PIC1;
+ EisaOutUchar( PicPort, OCW3_ISR );
+ Isr = EisaInUchar( PicPort );
+
+ //
+ // send SEOI for each interrupt that was in service
+ //
+
+ for ( Irq=IRQ0; Isr; Irq++, Isr >>= 1 )
+ {
+ //
+ // check if this IRQ was in service
+ //
+
+ if ( !(Isr & 0x1) )
+ {
+ continue;
+ }
+
+ //
+ // send a specific and of interrupt
+ //
+
+ EisaSendSpecificEoi( EisaIoStart, Irq );
+ }
+
+ //
+ // read ISR PIC2
+ //
+
+ PicPort = EisaIoStart + PIC2;
+ EisaOutUchar( PicPort, OCW3_ISR );
+ Isr = EisaInUchar( PicPort );
+
+ //
+ // send SEOI for each interrupt that was in service
+ //
+
+ for ( Irq=IRQ8; Isr; Irq++, Isr >>= 1 )
+ {
+ //
+ // check if this IRQ was in service
+ //
+
+ if ( !(Isr & 0x1) )
+ {
+ continue;
+ }
+
+ //
+ // send a specific and of interrupt
+ //
+
+ EisaSendSpecificEoi( EisaIoStart, Irq );
+ }
+
+ //--------------------------------------------------
+ // reset all the pending interrupt in the EISA bus
+ //--------------------------------------------------
+
+ //
+ // read IRR PIC1
+ //
+
+ PicPort = EisaIoStart + PIC1;
+ EisaOutUchar( PicPort, OCW3_IRR );
+
+ // don't play with IRQ 0, 1 and 2
+
+ Irr = EisaInUchar( PicPort ) & 0xF8;
+
+ //
+ // clear any PIC1 pending interrupt
+ //
+
+ for ( Irq=IRQ0; Irr; Irq++, Irr >>= 1 )
+ {
+ //
+ // check if this IRQ was pending
+ //
+
+ if ( !(Irr & 0x1) )
+ {
+ continue;
+ }
+
+ //
+ // reset the specified IRQ
+ //
+
+ EisaClearPendingInt( EisaIoStart, pIntInfo, Irq );
+ }
+
+ //
+ // read IRR PIC2
+ //
+
+ PicPort = EisaIoStart + PIC2;
+ EisaOutUchar( PicPort, OCW3_IRR );
+
+ // don't play with IRQ 8
+
+ Irr = EisaInUchar( PicPort ) & 0xFE;
+
+ //
+ // clear any PIC1 pending interrupt
+ //
+
+ for ( Irq=IRQ8; Irr; Irq++, Irr >>= 1 )
+ {
+ //
+ // check if this IRQ was pending
+ //
+
+ if ( !(Irr & 0x1) )
+ {
+ continue;
+ }
+
+ //
+ // reset the specifed IRQ
+ //
+
+ EisaClearPendingInt( EisaIoStart, pIntInfo, Irq );
+ }
+
+ //----------------------------------------------------
+ // error if it is possible to acknowledge an interrupt
+ //----------------------------------------------------
+
+ EisaAckInt( pIntInfo );
+
+ //
+ // read the ISR
+ //
+
+ PicPort = EisaIoStart + PIC1;
+ EisaOutUchar( PicPort, OCW3_ISR );
+
+ return EisaInUchar( PicPort ) ? FALSE : TRUE;
+}
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaDmaPod:
+//
+// DESCRIPTION: This function tests and initializes the DMA for the
+// specified EISA bus.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pDmaInfo DMA info pointer
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaDmaPod
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ )
+{
+ PRINTDBG("EisaDmaPod\n\r"); // DEBUG SUPPORT
+
+ //
+ // if ini already done, return status
+ //
+
+ if ( pDmaInfo->Flags.IniDone )
+ {
+ return (BOOLEAN)(pDmaInfo->Flags.Error);
+ }
+ pDmaInfo->Flags.Error = 1; // be pessimistic
+
+
+ do
+ {
+ //
+ // first part of checkpoint
+ //
+
+ EisaCheckpointFirstFase( EisaDma );
+
+ //
+ // Clear the DMA controllers and disable all the channels.
+ //
+
+ EisaOutUchar( EisaIoStart + DMA_MASTER_CLR03, 0);
+ EisaOutUchar( EisaIoStart + DMA_COMMAND03, 4); // Set channel 0-3 disable
+ EisaOutUchar( EisaIoStart + DMA_MASTER_CLR47, 0);
+ EisaOutUchar( EisaIoStart + DMA_COMMAND47, 4); // Set channel 4-7 disable
+
+ //
+ // check mask register
+ //
+
+ if ( !EisaDmaMaskTest( EisaIoStart, pDmaInfo ));
+
+ //
+ // check the low and high page
+ //
+
+ else if ( !EisaDmaPageTest( EisaIoStart, pDmaInfo ));
+
+ //
+ // check the base/current address register
+ //
+
+ else if ( !EisaDmaAddressTest( EisaIoStart, pDmaInfo ));
+
+ //
+ // check the count register
+ //
+
+ else if ( !EisaDmaCountTest( EisaIoStart, pDmaInfo ));
+
+ //
+ // check stop register
+ //
+
+ else if ( !EisaDmaStopTest( EisaIoStart, pDmaInfo ));
+
+ //
+ // if we got here everything is fine
+ //
+
+ else
+ {
+ EisaDmaIni( EisaIoStart, pDmaInfo );
+ pDmaInfo->Flags.Error = 0;
+ }
+ }
+ while ( EisaCheckpointFinalFase( EisaDma,
+ pDmaInfo->Flags.Error ? FALSE : TRUE ));
+ //
+ // return to caller
+ //
+
+ pDmaInfo->Flags.IniDone = 1;
+ return !(BOOLEAN)(pDmaInfo->Flags.Error);
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaDmaMaskTest:
+//
+// DESCRIPTION: This function tests the mask register.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pDmaInfo DMA info pointer
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES: if any error, all DMA channels will be masked.
+// if no error, all DMA channels will be masked except
+// for channel 4 which is used to cascade the two DMA
+// controllers.
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaDmaMaskTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ )
+{
+ //
+ // define local variables
+ //
+
+ UCHAR DmaIndex; // DMA channel within controller
+ ULONG DmaCtrl = 0; // DMA controller
+ PUCHAR Clear, MaskAll, Mask, MaskStatus; // port address
+ BOOLEAN CheckOk = TRUE; // check status
+
+ PRINTDBG("EisaDmaMaskTest\n\r"); // DEBUG SUPPORT
+
+ //
+ // one loop per DMA controller
+ //
+
+ do
+ {
+ //
+ // initialize port values
+ //
+
+ Clear = EisaIoStart + EisaDmaCtrlTest[ DmaCtrl ].Clear;
+ MaskAll = EisaIoStart + EisaDmaCtrlTest[ DmaCtrl ].MaskAll;
+ Mask = EisaIoStart + EisaDmaCtrlTest[ DmaCtrl ].Mask;
+ MaskStatus = EisaIoStart + EisaDmaCtrlTest[ DmaCtrl ].MaskStatus;
+
+ //
+ // test mask clear register
+ //
+
+ EisaOutUchar( Clear, 0x00 );
+ if ( EisaInUchar( MaskStatus ) & 0xF )
+ {
+ CheckOk = FALSE;
+ break;
+ }
+
+ //
+ // now set all the mask bits
+ //
+
+ EisaOutUchar( MaskAll, 0x0F );
+ if ( (EisaInUchar( MaskStatus ) & 0x0F) != 0x0F )
+ {
+ CheckOk = FALSE;
+ break;
+ }
+
+ //
+ // now test each single mask bit
+ //
+
+ for ( DmaIndex=0; DmaIndex < 4; DmaIndex++ )
+ {
+ //
+ // clear single bit
+ //
+
+ EisaOutUchar( Mask, DmaIndex );
+ if ( EisaInUchar( MaskStatus ) & (1 << DmaIndex))
+ {
+ CheckOk = FALSE;
+ break;
+ }
+
+ //
+ // set single bit
+ //
+
+ EisaOutUchar( Mask, 0x04 | DmaIndex );
+ if ( !(EisaInUchar( MaskStatus ) & (1 << DmaIndex)))
+ {
+ CheckOk = FALSE;
+ break;
+ }
+ }
+ }
+ while( CheckOk && !DmaCtrl++ );
+
+ //
+ // return check status
+ //
+
+ EisaOutUchar( EisaIoStart + DMA_MASKS03, 0x0F );
+ EisaOutUchar( EisaIoStart + DMA_MASKS47, CheckOk ? 0x0E : 0x0F );
+
+ return CheckOk;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaDmaPageTest:
+//
+// DESCRIPTION: This function tests the low and high pages.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pDmaInfo DMA info pointer
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES: The low and high page registers will be left in
+// the power-on state of 0x00.
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaDmaPageTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ )
+{
+ //
+ // define local variables
+ //
+
+ ULONG DmaChannel; // # of DMA channel
+ PUCHAR Port1, Port2; // general I/O ports
+ BOOLEAN CheckOk = TRUE; // check status
+
+ PRINTDBG("EisaDmaPageTest\n\r"); // DEBUG SUPPORT
+
+ //
+ // one loop per DMA channel
+ //
+
+ for ( DmaChannel = 0; DmaChannel < EISA_DMAS; DmaChannel++ )
+ {
+
+ Port1 = EisaIoStart + EisaDmaRegsTest[ DmaChannel ].LowPage;
+ Port2 = EisaIoStart + EisaDmaRegsTest[ DmaChannel ].HighPage;
+
+ //
+ // check high page address
+ //
+
+ if ( DmaChannel != 4 )
+ {
+ EisaOutUchar( Port2, 0xFF );
+
+ if ( !EisaCheckReg( Port2, 0xFF ) )
+ {
+ //
+ // error
+ //
+
+ CheckOk = FALSE;
+ break;
+ }
+ }
+
+ //
+ // check low page register
+ //
+
+ EisaOutUchar( Port1, 0x00 );
+
+ if ( !EisaCheckReg( Port1, 0xFF ) )
+ {
+ //
+ // error
+ //
+
+ CheckOk = FALSE;
+ break;
+ }
+
+ //
+ // check if high reg has been cleared writing to low reg
+ //
+
+ if ( DmaChannel != 4 && EisaInUchar( Port2 ) != 0 )
+ {
+ //
+ // error
+ //
+
+ CheckOk = FALSE;
+ break;
+ }
+ }
+
+ //
+ // return check status
+ //
+
+ return CheckOk;
+}
+
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaDmaAddressTest:
+//
+// DESCRIPTION: This function tests the address register.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pDmaInfo DMA info pointer
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES: The address registers will be left in the power-on
+// state of 0x0000.
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaDmaAddressTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ )
+{
+ //
+ // define local variables
+ //
+
+ ULONG DmaChannel; // # of DMA channel
+ PUCHAR Port1, Port2; // general I/O ports
+ BOOLEAN CheckOk = TRUE; // check status
+
+ PRINTDBG("EisaDmaAddressTest\n\r"); // DEBUG SUPPORT
+
+ //
+ // reset the internal DMA pointers
+ //
+
+ EisaOutUchar( EisaIoStart + DMA_FF_CLR03, 0x00 );
+ EisaOutUchar( EisaIoStart + DMA_FF_CLR47, 0x00 );
+
+ //
+ // one loop per DMA channel
+ //
+
+ for ( DmaChannel = 0; DmaChannel < EISA_DMAS; DmaChannel++ )
+ {
+ //
+ // load high and address register addresses
+ //
+
+ Port1 = EisaIoStart + EisaDmaRegsTest[ DmaChannel ].Address;
+ Port2 = EisaIoStart + EisaDmaRegsTest[ DmaChannel ].HighPage;
+
+ //
+ // write a value different from zero in high page
+ //
+
+ if ( DmaChannel != 4 )
+ {
+ EisaOutUchar( Port2, 0xFF );
+ }
+
+ //
+ // check word register using one 8 bit port
+ //
+
+ if ( !EisaCheckDeepReg( Port1 ) )
+ {
+ //
+ // error
+ //
+
+ CheckOk = FALSE;
+ break;
+ }
+
+ //
+ // initialize register
+ //
+
+ EisaOutUchar( Port1, 0x00 );
+ EisaOutUchar( Port1, 0x00 );
+
+ //
+ // check if high reg has been cleared writing to low reg
+ //
+
+ if ( DmaChannel != 4 && EisaInUchar( Port2 ) != 0 )
+ {
+ //
+ // error
+ //
+
+ CheckOk = FALSE;
+ break;
+ }
+ }
+
+ //
+ // return check status
+ //
+
+ return CheckOk;
+}
+
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaDmaCountTest:
+//
+// DESCRIPTION: This function tests the count register.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pDmaInfo DMA info pointer
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES: The count registers will be left in the power-on
+// state of 0x00 (high) and 0xFFFF (low).
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaDmaCountTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ )
+{
+ //
+ // define local variables
+ //
+
+ ULONG DmaChannel; // # of DMA channel
+ PUCHAR Port1, Port2; // general I/O ports
+ BOOLEAN CheckOk = TRUE; // check status
+
+ PRINTDBG("EisaDmaCountTest\n\r"); // DEBUG SUPPORT
+
+ //
+ // reset the internal DMA pointers
+ //
+
+ EisaOutUchar( EisaIoStart + DMA_FF_CLR03, 0x00 );
+ EisaOutUchar( EisaIoStart + DMA_FF_CLR47, 0x00 );
+
+ //
+ // one loop per DMA channel
+ //
+
+ for ( DmaChannel = 0; DmaChannel < EISA_DMAS; DmaChannel++ )
+ {
+ //
+ // load high and address register addresses
+ //
+
+ Port1 = EisaIoStart + EisaDmaRegsTest[ DmaChannel ].LowCount;
+ Port2 = EisaIoStart + EisaDmaRegsTest[ DmaChannel ].HighCount;
+
+ //
+ // check high count register
+ //
+
+ if ( DmaChannel != 4 )
+ {
+ EisaOutUchar( Port2, 0xFF );
+
+ if ( !EisaCheckReg( Port2, 0xFF ) )
+ {
+ //
+ // error
+ //
+
+ CheckOk = FALSE;
+ break;
+ }
+ }
+
+ //
+ // check word register using one 8 bit port
+ //
+
+ if ( !EisaCheckDeepReg( Port1 ) )
+ {
+ //
+ // error
+ //
+
+ CheckOk = FALSE;
+ break;
+ }
+
+ //
+ // initialize register
+ //
+
+ EisaOutUchar( Port1, 0xFF );
+ EisaOutUchar( Port1, 0xFF );
+
+ //
+ // check if high reg has been cleared writing to low reg
+ //
+
+ if ( DmaChannel != 4 && EisaInUchar( Port2 ) != 0 )
+ {
+ //
+ // error
+ //
+
+ CheckOk = FALSE;
+ break;
+ }
+ }
+
+ //
+ // return check status
+ //
+
+ return CheckOk;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaDmaStopTest:
+//
+// DESCRIPTION: This function tests the stop register.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pDmaInfo DMA info pointer
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES: The count registers will be left in the power-on
+// state of 0xFFFFFC.
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaDmaStopTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ )
+{
+ //
+ // define local variables
+ //
+
+ ULONG DmaChannel; // # of DMA channel
+ PUCHAR Stop; // general I/O ports
+ BOOLEAN CheckOk = TRUE; // check status
+
+ PRINTDBG("EisaDmaStopTest\n\r"); // DEBUG SUPPORT
+
+ //
+ // one loop per DMA channel
+ //
+
+ for ( DmaChannel = 0; DmaChannel < EISA_DMAS; DmaChannel++ )
+ {
+
+ Stop = EisaIoStart + EisaDmaRegsTest[ DmaChannel ].Stop;
+
+ //
+ // check high page address
+ //
+
+ if ( DmaChannel != 4 )
+ {
+ //
+ // initialize stop registers and test them
+ //
+
+ EisaOutUchar( Stop, 0x00 );
+ EisaOutUchar( Stop+1, 0x00 );
+ EisaOutUchar( Stop+2, 0x00 );
+
+ if ( !EisaCheckReg( Stop, 0xFC ) ||
+ !EisaCheckReg( Stop+1, 0xFF ) ||
+ !EisaCheckReg( Stop+2, 0xFF ) )
+ {
+ //
+ // error
+ //
+
+ CheckOk = FALSE;
+ break;
+ }
+ }
+ }
+
+ //
+ // return check status
+ //
+
+ return CheckOk;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaDmaIni:
+//
+// DESCRIPTION: This function initializes the DMA controllers of
+// the specified EISA bus.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pDmaInfo DMA info pointer
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaDmaIni
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_DMA_INFO pDmaInfo
+ )
+{
+ //
+ // define local variables
+ //
+
+ ULONG Index; // general index
+ ULONG DmaCtrl = 0; // DMA controller
+ UCHAR Reg = 0; // DMA command Register
+ PUCHAR Port; // general port
+
+ PRINTDBG("EisaDmaIni\n\r"); // DEBUG SUPPORT
+
+ //-----------------------------------------------------------------
+ //
+ // set command registers for fixed priotiry, DREQ active high,
+ // DACK# active low and channels enabled
+ //
+
+ EisaOutUchar( EisaIoStart + DMA_COMMAND03, Reg );
+ EisaOutUchar( EisaIoStart + DMA_COMMAND47, Reg );
+
+ //-----------------------------------------------------------------
+ //
+ // initialize mode register for channel 4. The other channels will
+ // be initializated during the EisaRequestDmaTransfer functions.
+ //
+
+ EisaOutUchar( EisaIoStart + DMA_MODE47, 0xC0 );
+
+ //-----------------------------------------------------------------
+ //
+ // disable the chaining mode
+ //
+
+ do
+ {
+ //
+ // load the controller port address
+ //
+
+ Port = EisaIoStart + EisaDmaCtrlTest[ DmaCtrl ].Chain;
+
+ //
+ // disable chaining mode
+ //
+
+ for ( Index = 0; Index < 4 ; Index++ )
+ {
+ EisaOutUchar( Port, 0x00 );
+ }
+ }
+ while( !DmaCtrl++ );
+
+ //-----------------------------------------------------------------
+ //
+ // initialize DMA structures
+ //
+
+ for ( Index = 0; Index < EISA_DMAS; Index++ )
+ {
+ pDmaInfo->DmaFlags[ Index ].Busy = 0;
+ pDmaInfo->DmaFlags[ Index ].Tc = 0;
+
+ // stop enabled, T-C output, ISA compatible,
+ // 8 bit I/O byte count and DMA channel
+ // (see DMA configuration).
+
+ pDmaInfo->DmaExtReg[ Index ] = Index < 4 ? Index : Index - 4;
+ }
+
+ //
+ // all done
+ //
+
+ return;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaOtherPod:
+//
+// DESCRIPTION: This function tests and initializes all the general
+// ports of the EISA bus.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pPortInfo port info pointer
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaOtherPod
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_PORT_INFO pPortInfo
+ )
+{
+ //
+ // define local variables
+ //
+
+ BOOLEAN ChkOk;
+
+ PRINTDBG("EisaOtherPod\n\r"); // DEBUG SUPPORT
+
+ //
+ // if ini already done, return status
+ //
+
+ if ( pPortInfo->Flags.IniDone )
+ {
+ return (BOOLEAN)(pPortInfo->Flags.Error);
+ }
+ pPortInfo->Flags.Error = 0;
+
+ //
+ // check and initialize NMI
+ //
+
+ do
+ {
+ EisaCheckpointFirstFase( EisaNmi );
+ if ( !( ChkOk = EisaNmiTest( EisaIoStart, pPortInfo )))
+ {
+ pPortInfo->Flags.Error = 1;
+ }
+ }
+ while ( EisaCheckpointFinalFase( EisaNmi, ChkOk ));
+
+ //
+ // check and initialize refresh
+ //
+
+ do
+ {
+ EisaCheckpointFirstFase( EisaRefresh );
+ if ( !( ChkOk = EisaRefreshTest( EisaIoStart, pPortInfo )))
+ {
+ pPortInfo->Flags.Error = 1;
+ }
+ }
+ while ( EisaCheckpointFinalFase( EisaRefresh, ChkOk ));
+
+ //
+ // check and initialize port 61
+ //
+
+ do
+ {
+ EisaCheckpointFirstFase( EisaPort61 );
+ if ( !( ChkOk = EisaPort61Test( EisaIoStart, pPortInfo )))
+ {
+ pPortInfo->Flags.Error = 1;
+ }
+ }
+ while ( EisaCheckpointFinalFase( EisaPort61, ChkOk ));
+
+ //
+ // check and initialize timer1
+ //
+
+ do
+ {
+ EisaCheckpointFirstFase( EisaTimer1 );
+ if ( !( ChkOk = EisaTimer1Test( EisaIoStart, pPortInfo )))
+ {
+ pPortInfo->Flags.Error = 1;
+ }
+ }
+ while ( EisaCheckpointFinalFase( EisaTimer1, ChkOk ));
+
+ //
+ // check and initialize timer2
+ //
+
+ do
+ {
+ EisaCheckpointFirstFase( EisaTimer2 );
+ if ( !( ChkOk = EisaTimer2Test( EisaIoStart, pPortInfo )))
+ {
+ pPortInfo->Flags.Error = 1;
+ }
+ }
+ while ( EisaCheckpointFinalFase( EisaTimer2, ChkOk ));
+
+ //
+ // return check status
+ //
+
+ pPortInfo->Flags.IniDone = 1;
+ return !(BOOLEAN)(pPortInfo->Flags.Error);
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaNmiTest:
+//
+// DESCRIPTION: This function tests and initializes the EISA NMI.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pPortInfo port info pointer
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS: EisaNmiFlag
+//
+// NOTES: if any error, the NMI will be disabled (real-time clock)
+// if no error, the NMI will be left enabled but with all
+// the NMI sources disabled.
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaNmiTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_PORT_INFO pPortInfo
+ )
+{
+ PRINTDBG("EisaNmiTest\n\r"); // DEBUG SUPPORT
+
+ // NOTE: NMI test is disabled for JAZZ.
+#if 0
+ //
+ // install an NMI interrupt handler
+ //
+
+ EisaNmiFlag = FALSE;
+
+ FwInstallIntVector( EISA_NMI_VECTOR, EisaNmiHandlerTest );
+
+ //----------------------------------------------------------------
+ //
+ // disable all the NMI sources
+ // (using the extended NMI status and contrl port and system control port B)
+ //
+
+ EisaOutUchar( EisaIoStart + EISA_SYS_EXT_NMI, 0x00 );
+
+ //
+ // note that the following operation clears any pending parity or I/O check
+ // errors.
+ //
+
+ EisaDisableParityIoCheck( EisaIoStart );
+ EisaEnableNmi( EisaIoStart );
+
+ //
+ // ... wait.
+ //
+
+ ArcEisaStallProcessor( EISA_WAIT_NMI_TEST );
+ EisaDisableNmi( EisaIoStart );
+
+ //
+ // return error if an hot EISA NMI
+ //
+
+ if ( EisaNmiFlag )
+ {
+ return FALSE;
+ }
+
+
+ //----------------------------------------------------------------
+ //
+ // enable all the NMI sources used by the fw
+ //
+
+ EisaOutUchar( EisaIoStart + EISA_SYS_EXT_NMI, EISA_ENABLE_NMI_32 );
+ EisaEnableParityIoCheck( EisaIoStart );
+ EisaEnableNmi( EisaIoStart );
+
+ //
+ // ... wait
+ //
+
+ ArcEisaStallProcessor( EISA_WAIT_NMI_TEST );
+ EisaDisableNmi( EisaIoStart );
+
+ //
+ // return error if an hot EISA NMI
+ //
+
+ if ( EisaNmiFlag )
+ {
+ return FALSE;
+ }
+
+
+ //----------------------------------------------------------------
+ //
+ // enable NMI I/O port and NMI; and force one to come
+ //
+
+ EisaOutUchar( EisaIoStart + EISA_SYS_EXT_NMI, EISA_ENABLE_NMI_IO );
+ EisaEnableNmi( EisaIoStart );
+ EisaOutUchar( EisaIoStart + EISA_SW_NMI_PORT, 0x00 );
+
+ //
+ // ... wait
+ //
+
+ ArcEisaStallProcessor( EISA_WAIT_NMI_TEST );
+ EisaDisableNmi( EisaIoStart );
+
+ //
+ // return an error if not NMI
+ //
+
+ if ( !EisaNmiFlag )
+ {
+ return FALSE;
+ }
+
+ //
+ // enable the NMI and all the NMI sources used by fw
+ // ( the software NMI will be disabled )
+ //
+
+ FwInstallIntVector( EISA_NMI_VECTOR, EisaNmiHandler );
+
+ EisaOutUchar( EisaIoStart + EISA_SYS_EXT_NMI, EISA_ENABLE_NMI_32 );
+ EisaEnableNmi( EisaIoStart );
+
+ //
+ // return
+ //
+
+#endif // 0
+ return TRUE;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaNmiHandlerTest:
+//
+// DESCRIPTION: This function is the NMI handler during the NMI test.
+//
+// ARGUMENTS: Cause R4000 cause register
+//
+// RETURN: TRUE interrupt recognized
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS: EisaNmi
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaNmiHandlerTest
+ (
+ IN ULONG Couse
+ )
+{
+ PRINTDBG("EisaNmiHandlerTest\n\r"); // DEBUG SUPPORT
+ StatusReg( ~STATUS_EISA_NMI, (ULONG)0 );
+ EisaNmiFlag = TRUE;
+ return TRUE;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaNmiHandler:
+//
+// DESCRIPTION: This function handles the EISA NMI.
+// An NMI can be caused by :
+//
+// 1) System/Adapter board memory parity error
+// ( port 61h bit 7 set )
+// 2) Adapter I/O channel check error
+// ( port 61h bit 6 set )
+// 3) Fail-Safe Timer (channle 2 or the interval Timer 2)
+// ( port 461h bit 7 set ) - NOT CHECKED *
+// 4) DMA bus timeout error
+// ( port 461h bit 6 set )
+// 5) Write to NMI port 462h
+// ( port 461h bit 5 set ) - NOT CHECKED *
+// 6) Coprocessor exception interrupt - NOT CHECKED *
+//
+// An error message will be displayed indicating the
+// cause of the error and the system will halt.
+// The only allowed operation after an NMI is to reset
+// the machine.
+//
+// * The firmware doesn't enable these NMI sources.
+//
+// ARGUMENTS: Cause R4000 cause register
+//
+// RETURN: TRUE interrupt recognized
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS: EisaBusInfo
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaNmiHandler
+ (
+ IN ULONG Couse
+ )
+{
+ //
+ // define local variables
+ //
+
+ PUCHAR EisaIoStart; // eisa I/O virtual address
+ UCHAR NmiData, ExtNmiData; // NMI status
+ ULONG BusNumber = 0; // eisa bus number
+ ULONG Slots; // # slots
+ BOOLEAN NmiPresent; // NMI source status
+
+ PRINTDBG("EisaNmiHandler\n\r"); // DEBUG SUPPORT
+
+ //
+ // disable NMI at CPU level
+ //
+
+ StatusReg( ~STATUS_EISA_NMI, (ULONG)0 );
+
+ //
+ // clear screen and display message
+ //
+
+ FwClearScreen();
+ FwPrint(EISA_HOT_NMI_MSG);
+ EisaCheckpointFirstFase( EisaHotNmi );
+
+ do
+ {
+ //
+ // print eisa bus number
+ //
+
+ FwPrint( EISA_BUS_NUMBER_MSG , BusNumber );
+
+ //
+ // initialize variables
+ //
+
+ EisaIoStart = EisaBusInfo[ BusNumber ].IoBusInfo->VirAddr;
+ Slots = EisaBusInfo[ BusNumber ].SlotsInfo->PhysSlots;
+ NmiPresent = FALSE;
+
+ //
+ // read NMI status
+ //
+
+ NmiData = EisaInUchar( EisaIoStart + EISA_SYS_CTRL_PORTB );
+ ExtNmiData = EisaInUchar( EisaIoStart + EISA_SYS_EXT_NMI );
+
+ //
+ // check if there is a parity error
+ //
+
+ if ( NmiData & EISA_PARITY_STATUS )
+ {
+ EisaParityError( EisaIoStart );
+ NmiPresent = TRUE;
+ }
+
+ //
+ // check if there is a I/O channel check
+ //
+
+ if ( NmiData & EISA_IOCHK_STATUS )
+ {
+ EisaIoChkError( EisaIoStart, Slots );
+ NmiPresent = TRUE;
+ }
+
+ //
+ // check if there is a DMA or bus master timeout error
+ //
+
+ if ( ExtNmiData & EISA_NMI_32_STATUS )
+ {
+ if ( ExtNmiData & EISA_NMI_32_CAUSE )
+ {
+ EisaBusTimeoutError( EisaIoStart, Slots );
+ }
+ else
+ {
+ EisaSlaveTimeoutError( EisaIoStart, Slots );
+ }
+ NmiPresent = TRUE;
+ }
+
+ //
+ // if no NMI for this bus, display "no problem"
+ //
+
+ if ( !NmiPresent )
+ {
+ FwPrint(EISA_NMI_NOT_FOUND_MSG);
+ }
+ }
+ while( ++BusNumber < EISA_BUSES );
+
+ //
+ // print final message and hang
+ //
+
+ EisaCheckpointFinalFase( EisaHotNmi, FALSE );
+ while(1); // just to be sure
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaParityError:
+//
+// DESCRIPTION: This function displays the error message and
+// returns to the caller without do any other thing.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaParityError
+ (
+ IN PUCHAR EisaIoStart
+ )
+{
+ PRINTDBG("EisaParityError\n\r"); // DEBUG SUPPORT
+
+ FwPrint(EISA_PARITY_ERROR_MSG , ASCII_CSI );
+
+ return;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaIoChkError:
+//
+// DESCRIPTION: This function tries to find the slot in error.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// Slots # slots
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaIoChkError
+ (
+ IN PUCHAR EisaIoStart,
+ IN ULONG Slots
+ )
+{
+ //
+ // define local variabls
+ //
+
+ ULONG AdapId; // adapter ID
+ PUCHAR ExpCtrl; // expansion board ctrl addr
+ UCHAR CtrlBits; // port value
+
+ PRINTDBG("EisaIoChkError\n\r"); // DEBUG SUPPORT
+
+ //
+ // display first message
+ //
+
+ FwPrint(EISA_IO_CHECK_ERROR_MSG , ASCII_CSI);
+
+ //
+ // check all slots starting from the last one
+ //
+
+ while( --Slots )
+ {
+ //
+ // check if there is an adapter with a readable ID
+ //
+
+ if ( !EisaReadReadyId( EisaIoStart, Slots, &AdapId ) ||
+ AdapId == NO_ADAP_ID )
+ {
+ continue;
+ }
+
+ ExpCtrl = EisaIoStart + 0x1000 * Slots + EXPANSION_BOARD_CTRL_BITS;
+
+ //
+ // test the IOCHKERR bit of the Expansion Board Contrl Bits.
+ // the IOCHKERR bit can be read to determine if an expansion
+ // board has a pending error. The expansion board indicates a
+ // pending error by setting IOCHKERR, clearing the ENABLE bit
+ // and entering the disabled state.
+ //
+ // note: because the EISA expansion boards are not required to
+ // support this port, we need the following simple
+ // assumption: this I/O port is not supported if the value
+ // read from it is 0xFF.
+ //
+
+ if ((CtrlBits = EisaInUchar( ExpCtrl )) != 0xFF )
+ {
+ if ( CtrlBits & EISA_IOCHKERR )
+ {
+ break;
+ }
+ }
+ }
+
+ //
+ // print final message
+ //
+
+ if ( !Slots )
+ {
+ FwPrint( EISA_IO_CHECK_NOT_SUP_MSG ); // slot not found
+ }
+ else
+ {
+ FwPrint(EISA_IN_SLOT_MSG , Slots ); // slot in error
+ }
+
+ //
+ // all done, exit
+ //
+
+ return;
+}
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaBusTimeoutError:
+//
+// DESCRIPTION: This function displays the bus master number in error.
+// If a 32-bit bus master tries to hold the bus beyond
+// the BUS limit (8 usec if BCLK = 8 MHz), the ISP will
+// assert the NMI and RSTDRV signals togheter.
+// The RSTDRV signal will remain aserted until the NMI has
+// been reset by plsing bit 3 of I/O port 461h.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// Slots # slots
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaBusTimeoutError
+ (
+ IN PUCHAR EisaIoStart,
+ IN ULONG Slots
+ )
+{
+ //
+ // define local variables
+ //
+
+ UCHAR Status; // 32-bit bus master status
+ ULONG BusMaster = 0; // bus master number in error
+ PUCHAR ExtNmi; // extended NMI control
+
+ PRINTDBG("EisaBusTimeoutError\n\r"); // DEBUG SUPPORT
+
+ //
+ // find the bus master group in error
+ //
+
+ if ( ~(Status = EisaInUchar(EisaIoStart+EISA_BUSMASTER_LSTATUS)) & 0xFF )
+ {
+ BusMaster = 1;
+ }
+ else if ( ~(Status = (EisaInUchar(EisaIoStart+EISA_BUSMASTER_HSTATUS) |
+ 0x80)) & 0xFF )
+ {
+ BusMaster = 9;
+ }
+
+ //
+ // find the bus master number in error and display it
+ //
+
+ FwPrint( EISA_BUS_MASTER_MSG, ASCII_CSI );
+
+ if ( BusMaster )
+ {
+ for (; Status & 1; Status >>= 1, BusMaster++ );
+ FwPrint(EISA_TIMEOUT_MSG , BusMaster );
+ }
+ else
+ {
+ FwPrint(EISA_TIMEOUT2_MSG ); // bus master not found
+ }
+
+ //
+ // reset NMI
+ //
+
+ ExtNmi = EisaIoStart + EISA_SYS_EXT_NMI;
+ EisaOutUchar( ExtNmi, EisaInUchar( ExtNmi ) & ~EISA_ENABLE_NMI_32 );
+
+ //
+ // all done
+ //
+
+ return;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaSlaveTimeoutError:
+//
+// DESCRIPTION: This function displays an error message.
+// If a memory slave extends a cycle long enough that
+// CMD# is active for more than 256 BCLKs (32usec if
+// BCLK = 8MHz), the ISP will assert the NMI and RSTDRV
+// signals togheter.
+// The RSTDRV signal will remain aserted until the NMI has
+// been reset by plsing bit 3 of I/O port 461h.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// Slots # slots
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaSlaveTimeoutError
+ (
+ IN PUCHAR EisaIoStart,
+ IN ULONG Slots
+ )
+{
+ //
+ // define local variables
+ //
+
+ PUCHAR ExtNmi; // extended NMI control
+
+ PRINTDBG("EisaSlaveTimeoutError\n\r"); // DEBUG SUPPORT
+
+ //
+ // display the error message
+ //
+
+ FwPrint(EISA_SLAVE_TIMEOUT_MSG , ASCII_CSI );
+
+ //
+ // reset NMI
+ //
+
+ ExtNmi = EisaIoStart + EISA_SYS_EXT_NMI;
+ EisaOutUchar( ExtNmi, EisaInUchar( ExtNmi ) & ~EISA_ENABLE_NMI_32 );
+
+ //
+ // all done
+ //
+
+ return;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaRefreshTest:
+//
+// DESCRIPTION: This function tests and initializes the EISA refresh.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pPortInfo port info pointer
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES: the refresh will be left enabled.
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaRefreshTest
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_PORT_INFO pPortInfo
+ )
+{
+ //
+ // define local variables
+ //
+
+ BOOLEAN CheckOk = FALSE; // checking status
+ ULONG Retry; // # retry
+ PUCHAR Port; // general I/O port
+
+ PRINTDBG("EisaRefreshTest\n\r"); // DEBUG SUPPORT
+
+ //
+ // clear refresh pages
+ //
+
+ EisaOutUchar( EisaIoStart + DMA_PAGE_RFR, 0x00 );
+ EisaOutUchar( EisaIoStart + DMA_HPAGE_RFR, 0x00 );
+
+ //
+ // start timer 1, counter 1
+ //
+
+ EisaOutUchar( EisaIoStart + EISA_TIMER1_CTRL, 0x54 );
+ EisaOutUchar( EisaIoStart + EISA_TIMER1_COUNTER1, EISA_RFR_COUNT );
+
+ //
+ // check if refresh bit in the system control port B is toggling
+ //
+
+ Port = EisaIoStart + EISA_SYS_CTRL_PORTB;
+
+ for ( CheckOk = FALSE, Retry = EISA_RFR_RETRY; Retry; Retry-- )
+ {
+ //
+ // check if refresh bit is set
+ //
+
+ if ( READ_REGISTER_UCHAR( Port ) & EISA_REFRESH )
+ {
+ //
+ // yes, exit loop
+ //
+
+ CheckOk = TRUE;
+ break;
+ }
+ }
+
+ //
+ // if time-out, exit with error
+ //
+
+ if ( !Retry )
+ {
+ return FALSE;
+ }
+
+ //
+ // check if refresh bit in the system control port B is toggling
+ //
+
+ for ( CheckOk = FALSE, Retry = EISA_RFR_RETRY; Retry; Retry-- )
+ {
+ //
+ // check if refresh bit is cleared
+ //
+
+ if ( !(READ_REGISTER_UCHAR( Port ) & EISA_REFRESH) )
+ {
+ //
+ // yes, exit loop
+ //
+
+ CheckOk = TRUE;
+ break;
+ }
+ }
+
+ //
+ // return check status
+ //
+
+ return CheckOk;
+}
+
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaPort61Test:
+//
+// DESCRIPTION: This function tests and initializes the system
+// control port B.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pPortInfo port info pointer
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS: NMI has already been tested.
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES: The parity and the I/O channel check, The speaker gate
+// and speaker timer will be left disabled.
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaPort61Test
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_PORT_INFO pPortInfo
+ )
+{
+ //
+ // define local variables
+ //
+
+ PUCHAR Port; // genearl I/O port
+ BOOLEAN CheckOk = TRUE; // check status
+
+ PRINTDBG("EisaPort61Test\n\r"); // DEBUG SUPPORT
+
+ Port = EisaIoStart + EISA_SYS_CTRL_PORTB;
+
+ //
+ // gate signal for speaker timer
+ //
+
+ EisaOutUchar( Port, EISA_SPEAKER_GATE );
+ if ( (EisaInUchar( Port ) & 0x0F) != EISA_SPEAKER_GATE )
+ {
+ CheckOk = FALSE;
+ }
+
+ //
+ // speaker timer contrl
+ //
+
+ if ( CheckOk )
+ {
+ EisaOutUchar( Port, EISA_SPEAKER_TIMER);
+ if ( (EisaInUchar( Port ) & 0x0F) != EISA_SPEAKER_TIMER )
+ {
+ CheckOk = FALSE;
+ }
+ }
+
+ //
+ // parity bit
+ //
+
+ if ( CheckOk )
+ {
+ EisaOutUchar( Port, EISA_PARITY_OFF);
+ if ( (EisaInUchar( Port ) & 0x0F) != EISA_PARITY_OFF )
+ {
+ CheckOk = FALSE;
+ }
+ }
+
+ //
+ // I/O channel check
+ //
+
+ if ( CheckOk )
+ {
+ EisaOutUchar( Port, EISA_IOCHK_OFF );
+ if ( (EisaInUchar( Port ) & 0x0F) != EISA_IOCHK_OFF )
+ {
+ CheckOk = FALSE;
+ }
+ }
+
+ //
+ // initialize port 61h.
+ //
+
+ EisaOutUchar( Port, 0x00 );
+
+ //
+ // return check status
+ //
+
+ return CheckOk;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaTimer1Test:
+//
+// DESCRIPTION: This function tests only the counter 2 of
+// timer 1 (speaker).
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pPortInfo port info pointer
+//
+// RETURN: TRUE All done
+// FALSE Error
+//
+// ASSUMPTIONS: NMI has already been tested.
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES: The functions stops timer1 counter0, turns off the
+// timer1 counter2 gate and disable the speaker output.
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaTimer1Test
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_PORT_INFO pPortInfo
+ )
+{
+ //
+ // define local variables
+ //
+
+ BOOLEAN CheckOk = FALSE; // check status
+ PUCHAR Ctrl, Port, Port61; // genearl I/O ports
+
+ PRINTDBG("EisaTimer1Test\n\r"); // DEBUG SUPPORT
+
+ //
+ // initialize variables
+ //
+
+ Ctrl = EisaIoStart + EISA_TIMER1_CTRL;
+ Port = EisaIoStart + EISA_TIMER1_COUNTER2;
+ Port61 = EisaIoStart + EISA_SYS_CTRL_PORTB;
+
+ //
+ // disable timer1 counter2 gate, speaker output
+ //
+
+ EisaOutUchar( Port61, 0x00 );
+
+ //
+ // program timer 1, counter 2 (speaker) in 16-bit count, mode 0
+ //
+
+ EisaOutUchar( Ctrl, 0xB0 );
+ EisaOutUchar( Port, 0x00 );
+ EisaOutUchar( Port, 0x80 );
+
+ //
+ // check register
+ //
+
+ if ( !(EisaCheckDeepReg( Port )));
+
+ //
+ // check speaker output. It must be low otherwise there is an error
+ //
+
+ else if ( EisaInUchar( Port61 ) & EISA_SPEAKER_OUT );
+
+ //
+ // enable speaker gate to enable the counter, wait for some time and
+ // check if speaker output is high, if not error out
+ //
+
+ else
+ {
+ //
+ // enable speaker gate
+ //
+
+ EisaOutUchar( Port61, EISA_SPEAKER_GATE );
+
+ //
+ // wait 40msec = ~ ( 0x8000 / 1.193 Mhz ) + something
+ //
+
+// NOTE: Wait longer for JAZZ.
+// ArcEisaStallProcessor( 40 * 1000 );
+ ArcEisaStallProcessor( 160 * 1000 );
+
+ //
+ // check speaker output
+ //
+
+ if ( EisaInUchar( Port61 ) & EISA_SPEAKER_OUT )
+ {
+ //
+ // initialize timer1 counter2 in 16-bit , mode 3
+ //
+
+ // EisaOutUchar( Ctrl, 0xB6 );
+ // EisaOutUchar( Port,
+ // (UCHAR)( EISA_SPEAKER_CLOCK/EISA_SPEAKER_FREQ ));
+ // EisaOutUchar( Port,
+ // (UCHAR)( (EISA_SPEAKER_CLOCK/EISA_SPEAKER_FREQ) >> 8 ));
+
+ //
+ // all done
+ //
+
+ CheckOk = TRUE;
+ }
+ }
+
+ //
+ // disable speaker gate, speaker output
+ //
+
+ EisaOutUchar( Port61, 0x00 );
+
+ //
+ // stop timer1 counter0 sending the control word without the count value
+ //
+
+ EisaOutUchar( Ctrl, 0x30 );
+
+ //
+ // all done, exit
+ //
+
+ return CheckOk;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaTimer2Test:
+//
+// DESCRIPTION: This function stops the timer2 counter0 (Fail-safe).
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pPortInfo port info pointer
+//
+// RETURN: TRUE All done
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaTimer2Test
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_PORT_INFO pPortInfo
+ )
+{
+ PRINTDBG("EisaTimer2Test\n\r"); // DEBUG SUPPORT
+
+ //
+ // stop timer2 counter0 sending the control word without the count value
+ //
+
+ EisaOutUchar( EisaIoStart + EISA_TIMER2_CTRL, 0x30 );
+
+ //
+ // all done, exit
+ //
+
+ return TRUE;
+}
+
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaClearPendingInt:
+//
+// DESCRIPTION: This function cleares the specified pending interrupt.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pIntInfo interrupt info pointer
+// Irq IRQ to reset
+//
+// RETURN: none
+//
+// ASSUMPTIONS: none
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaClearPendingInt
+ (
+ IN PUCHAR EisaIoStart,
+ IN PEISA_INT_INFO pIntInfo,
+ IN USHORT Irq
+ )
+{
+ //
+ // define local variables
+ //
+
+ PUCHAR PicMask1, PicMask2; // I/O port address
+
+ PRINTDBG("EisaClearPendingInt\n\r"); // DEBUG SUPPORT
+
+ //
+ // initialize variables
+ //
+
+ PicMask1 = EisaIoStart + PIC1_MASK;
+ PicMask2 = EisaIoStart + PIC2_MASK;
+
+ //
+ // unmask the specified IRQ
+ //
+
+ if ( Irq > IRQ7 )
+ {
+ EisaOutUchar( PicMask1, (UCHAR)(~(1 << IRQ2)));
+ EisaOutUchar( PicMask2, (UCHAR)(~(1 << (Irq % 8))));
+ }
+ else
+ {
+ EisaOutUchar( PicMask1, (UCHAR)(~(1 << Irq )));
+ }
+
+ //
+ // acknowledge the interrupt
+ //
+
+ EisaAckInt( pIntInfo );
+
+ //
+ // mask off all the IRQ lines
+ //
+
+ EisaOutUchar( PicMask1, 0xFF );
+ EisaOutUchar( PicMask2, 0xFF );
+
+ //
+ // and send a specific EOF
+ //
+
+ EisaSendSpecificEoi( EisaIoStart, Irq );
+
+ return;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaIntAck:
+//
+// DESCRIPTION: This function acknowledges the highest priority
+// interrupt.
+//
+// ARGUMENTS: pIntInfo interrupt info pointer (not used)
+//
+// RETURN: Int interrupt acknowledged.
+//
+// ASSUMPTIONS: none
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+UCHAR
+EisaAckInt
+ (
+ IN PEISA_INT_INFO pIntInfo
+ )
+{
+ UCHAR Int;
+
+ PRINTDBG("EisaAckInt\n\r"); // DEBUG SUPPORT
+
+ Int = READ_REGISTER_UCHAR( EISA_INT_ACK_ADDR );
+ EISA_IO_DELAY;
+
+ return Int;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaSendSpecificEoi:
+//
+// DESCRIPTION: This function sends a specific EOI to the spcified
+// IRQ line.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// Irq IRQ to reset
+//
+// RETURN: none
+//
+// ASSUMPTIONS: none
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaSendSpecificEoi
+ (
+ IN PUCHAR EisaIoStart,
+ IN USHORT Irq
+ )
+{
+ //
+ // define local variables
+ //
+
+ PUCHAR PicPort1, PicPort2;
+
+ PRINTDBG("EisaSendSpecificEoi\n\r"); // DEBUG SUPPORT
+
+ //
+ // initialize local variables
+ //
+
+ PicPort1 = EisaIoStart + PIC1;
+ PicPort2 = EisaIoStart + PIC2;
+
+ //
+ // send a specific EOI
+ //
+
+ if ( Irq > IRQ7 )
+ {
+ EisaOutUchar( PicPort2, OCW2_SEOI | ( Irq % 8 ));
+ EisaOutUchar( PicPort1, OCW2_SEOI | IRQ2 );
+ }
+ else
+ {
+ EisaOutUchar( PicPort1, OCW2_SEOI | Irq );
+ }
+
+ return;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaDisableParityIoCheck:
+//
+// DESCRIPTION: This function disables the partiy and I/O check NMIs.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+//
+// RETURN: none
+//
+// ASSUMPTIONS: none
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaDisableParityIoCheck
+ (
+ IN PUCHAR EisaIoStart
+ )
+{
+ PRINTDBG("EisaDisableParityIoCheck\n\r"); // DEBUG SUPPORT
+
+ EisaOutUchar( EisaIoStart + EISA_SYS_CTRL_PORTB,
+ ( EisaInUchar( EisaIoStart + EISA_SYS_CTRL_PORTB ) |
+ EISA_PARITY_OFF | EISA_IOCHK_OFF ) & 0x0F );
+
+ return;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaEnableParityIoCheck:
+//
+// DESCRIPTION: This function enables the partiy and I/O check NMIs.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+//
+// RETURN: none
+//
+// ASSUMPTIONS: none
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaEnableParityIoCheck
+ (
+ IN PUCHAR EisaIoStart
+ )
+{
+ PRINTDBG("EisaEnableParityIoCheck\n\r"); // DEBUG SUPPORT
+
+ EisaOutUchar( EisaIoStart + EISA_SYS_CTRL_PORTB,
+ ( EisaInUchar( EisaIoStart + EISA_SYS_CTRL_PORTB ) &
+ ~(EISA_PARITY_OFF | EISA_IOCHK_OFF)) & 0x0F );
+
+ return;
+}
+
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaDisableInt:
+//
+// DESCRIPTION: The function disables the EISA interrupts at CPU
+// level.
+//
+// ARGUMENTS: none
+//
+// RETURN: none
+//
+// ASSUMPTIONS: none
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaDisableInt
+ (
+ VOID
+ )
+{
+ PRINTDBG("EisaDisableInt\n\r"); // DEBUG SUPPORT
+ StatusReg( ~STATUS_EISA, (ULONG)0 );
+ return;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaDisableNmi:
+//
+// DESCRIPTION: The function disables the NMI using the real-time
+// clock port.
+//
+// ARGUMENTS: none
+//
+// RETURN: none
+//
+// ASSUMPTIONS: none
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaDisableNmi
+ (
+ IN PUCHAR EisaIoStart
+ )
+{
+ PRINTDBG("EisaDisableNmi\n\r"); // DEBUG SUPPORT
+
+ //
+ // at real-time clock address port
+ //
+
+ EisaOutUchar(EisaIoStart+EISA_RTC_CTRL, EISA_DISABLE_NMI+RTC_C_REG);
+ READ_REGISTER_UCHAR( RTC_VIRTUAL_BASE );
+
+ return;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaEnableNmi:
+//
+// DESCRIPTION: The function enables the NMI line.
+// The following ports are used :
+//
+// . real-time clock ctrl port
+// . CPU status register port
+//
+// ARGUMENTS: none
+//
+// RETURN: none
+//
+// ASSUMPTIONS: none
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaEnableNmi
+ (
+ IN PUCHAR EisaIoStart
+ )
+{
+ PRINTDBG("EisaEnableNmi\n\r"); // DEBUG SUPPORT
+
+ //
+ // at real-time clock address port
+ //
+ EisaReadRtc( EisaIoStart, RTC_C_REG );
+
+
+// NOTE: this code has been removed because of a R4000 CPU bug.
+//
+// //
+// // at interrupt enable register
+// //
+//
+// EisaBeginCriticalSection();
+// WRITE_REGISTER_UCHAR(INT_ENABLE_ADDR, READ_REGISTER_UCHAR(INT_ENABLE_ADDR) | 0x08);
+// EisaEndCriticalSection();
+//
+
+ //
+ // at CPU level
+ //
+ StatusReg( (ULONG)-1, STATUS_EISA_NMI + STATUS_IE );
+ return;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaCheckReg:
+//
+// DESCRIPTION: This function performs read/write test on an 8 bit
+// I/O port using the following patterns: FFh, AAh, 55h
+// and 00h. The original part value is restored before
+// returning.
+//
+// ARGUMENTS: Port port address
+// DataMask mask for test pattern to compare with
+// data
+//
+// RETURN: TRUE test completed successfully
+// FALSE error
+//
+// ASSUMPTIONS: none
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaCheckReg
+ (
+ IN PUCHAR Port,
+ IN UCHAR DataMask
+ )
+{
+ //
+ // define local variables
+ //
+
+ BOOLEAN CompOk = TRUE;
+ UCHAR Save, Program;
+
+ PRINTDBG("EisaCheckReg\n\r"); // DEBUG SUPPORT
+
+ //
+ // save original value
+ //
+
+ Save = EisaInUchar( Port );
+
+ //
+ // one loop per each value
+ //
+
+ for ( Program = 0; ; Program += 0x55 )
+ {
+ //
+ // write port, read it back and compare values
+ //
+
+ EisaOutUchar( Port, Program );
+
+ if ((EisaInUchar( Port ) & DataMask) != (Program & DataMask))
+ {
+ //
+ // error, value are not the same
+ //
+
+ CompOk = FALSE;
+ break;
+ }
+
+ //
+ // exit loop if last value
+ //
+
+ if ( Program == 0xFF )
+ {
+ break;
+ }
+ }
+
+ //
+ // restore original value before returning
+ //
+
+ EisaOutUchar( Port, Save );
+
+ return CompOk;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaCheckDeepReg:
+//
+// DESCRIPTION: This function checks the 2x8bit registers.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// pDmaInfo DMA info pointer
+//
+// RETURN: TRUE check completed successfully
+// FALSE error
+//
+// ASSUMPTIONS: The internal pointer has already been resetted.
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+EisaCheckDeepReg
+ (
+ IN PUCHAR Port
+ )
+{
+ //
+ // define local variables
+ //
+
+ UCHAR LSave, HSave, Program, LCheck, HCheck;
+ BOOLEAN CompOk = TRUE;
+
+ PRINTDBG("EisaCheckDeepReg\n\r"); // DEBUG SUPPORT
+
+ //
+ // save original value
+ //
+
+ LSave = EisaInUchar( Port );
+ HSave = EisaInUchar( Port );
+
+ //
+ // one loop per each value
+ //
+
+ for ( Program = 0; ; Program += 0x55 )
+ {
+ //
+ // write port and read it back
+ //
+
+ EisaOutUchar( Port, Program );
+ EisaOutUchar( Port, Program );
+
+ EISA_IO_DELAY; //
+ EISA_IO_DELAY; // for the timer chip
+ EISA_IO_DELAY; //
+
+ LCheck = EisaInUchar( Port );
+ HCheck = EisaInUchar( Port );
+
+ //
+ // check the read values
+ //
+
+ if ( LCheck != Program || HCheck != Program )
+ {
+ //
+ // error, value are not the same
+ //
+
+ CompOk = FALSE;
+ break;
+ }
+
+ //
+ // exit loop if last value
+ //
+
+ if ( Program == 0xFF )
+ {
+ break;
+ }
+ }
+
+ //
+ // restore the original value
+ //
+
+ EisaOutUchar( Port, LSave );
+ EisaOutUchar( Port, HSave );
+
+ return CompOk;
+}
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaReadRtc:
+//
+// DESCRIPTION: This function returns the value of the specified
+// real-time clock internal address.
+//
+// ARGUMENTS: EisaIoStart EISA I/O virtual address
+// RtcIndex index within the RTC
+//
+// RETURN: Value register value
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+UCHAR
+EisaReadRtc
+ (
+ IN PUCHAR EisaIoStart,
+ IN ULONG RtcIndex
+ )
+{
+ UCHAR Value;
+
+ PRINTDBG("EisaReadRtc\n\r"); // DEBUG SUPPORT
+
+// NOTE: CriticalSection is not supported on JAZZ.
+// EisaBeginCriticalSection();
+ EisaOutUchar( EisaIoStart + EISA_RTC_CTRL, RtcIndex );
+ Value = READ_REGISTER_UCHAR( RTC_VIRTUAL_BASE );
+// EisaEndCriticalSection();
+
+ return Value;
+}
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaOutUchar:
+//
+// DESCRIPTION: This function writes an uchar within the EISA I/O
+// space and delays before returning.
+//
+// ARGUMENTS: Addr Address where the value has to be
+// write to.
+// Value Value to write
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+VOID
+EisaOutUchar
+ (
+ IN PUCHAR Addr,
+ IN UCHAR Value
+ )
+{
+// PRINTDBG("EisaOutUchar\n\r"); // DEBUG SUPPORT
+
+ WRITE_REGISTER_UCHAR( Addr, Value );
+ EISA_IO_DELAY;
+
+ return;
+}
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: EisaInUchar:
+//
+// DESCRIPTION: This function reads an uchar from the EISA I/O
+// space and delays before returning.
+//
+// ARGUMENTS: Addr Address where the value has to be
+// read from.
+//
+// RETURN: none
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+//
+// ----------------------------------------------------------------------------
+//
+
+UCHAR
+EisaInUchar
+ (
+ IN PUCHAR Addr
+ )
+{
+ UCHAR Value;
+
+// PRINTDBG("EisaInUchar\n\r"); // DEBUG SUPPORT
+
+ Value = READ_REGISTER_UCHAR( Addr );
+ EISA_IO_DELAY;
+
+ return Value;
+}
+
+
diff --git a/private/ntos/fw/mips/eisastr.h b/private/ntos/fw/mips/eisastr.h
new file mode 100644
index 000000000..5244d9ba4
--- /dev/null
+++ b/private/ntos/fw/mips/eisastr.h
@@ -0,0 +1,37 @@
+
+//
+// Common strings.
+//
+extern PCHAR EISA_OK_MSG;
+extern PCHAR EISA_CRLF_MSG;
+extern PCHAR EISA_ERROR1_MSG;
+
+//
+// Eisa strings.
+//
+
+// ----------------------------------------------------------------------------
+// GLOBAL: EISA error messages
+// ----------------------------------------------------------------------------
+//
+// 1 2 3 4 5 6 7
+// 01234567890123456789012345678901234567890123456789012345678901234567890
+
+extern PCHAR EisaCfgMessages[];
+
+extern EISA_CHECKPOINT_INFO EisaCheckpointInfo[];
+
+extern PCHAR EISA_INIT_MSG;
+extern PCHAR EISA_BUS_MSG;
+extern PCHAR EISA_ERROR_SLOT_MSG;
+extern PCHAR EISA_HOT_NMI_MSG;
+extern PCHAR EISA_BUS_NUMBER_MSG;
+extern PCHAR EISA_NMI_NOT_FOUND_MSG;
+extern PCHAR EISA_PARITY_ERROR_MSG;
+extern PCHAR EISA_IO_CHECK_ERROR_MSG;
+extern PCHAR EISA_IO_CHECK_NOT_SUP_MSG;
+extern PCHAR EISA_IN_SLOT_MSG;
+extern PCHAR EISA_BUS_MASTER_MSG;
+extern PCHAR EISA_TIMEOUT_MSG;
+extern PCHAR EISA_TIMEOUT2_MSG;
+extern PCHAR EISA_SLAVE_TIMEOUT_MSG;
diff --git a/private/ntos/fw/mips/eisausa.c b/private/ntos/fw/mips/eisausa.c
new file mode 100644
index 000000000..9dd159367
--- /dev/null
+++ b/private/ntos/fw/mips/eisausa.c
@@ -0,0 +1,99 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ eisausa.c
+
+Abstract:
+
+ This module contains the eisa english strings.
+
+Author:
+
+ David M. Robinson (davidro) 21-May-1993
+
+
+Revision History:
+
+
+--*/
+
+#include "ntos.h"
+#include "oli2msft.h"
+#include "inc.h"
+
+//
+// Common strings.
+//
+
+PCHAR EISA_OK_MSG = "OK.";
+PCHAR EISA_CRLF_MSG = "\r\n";
+PCHAR EISA_ERROR1_MSG = "Error";
+
+//
+// Eisa strings.
+//
+
+// ----------------------------------------------------------------------------
+// GLOBAL: EISA error messages
+// ----------------------------------------------------------------------------
+//
+// 1 2 3 4 5 6 7
+// 01234567890123456789012345678901234567890123456789012345678901234567890
+
+PCHAR EisaCfgMessages[] = {
+ "Invalid Message",
+ "ID Timeout",
+ "ID Configuration",
+ "Missing Configuration",
+ "Incomplete Configuration",
+ "Configuration",
+ "Failed Bit Set",
+ "Memory Configuration",
+ "IRQ Configuration",
+ "DMA Configuration",
+ "Port Configuration",
+ "OMF ROM",
+ "OMF",
+ "Out of Memory",
+ "Too Many Devices"
+};
+
+// ----------------------------------------------------------------------------
+// GLOBAL: EISA Checkpoint matrix
+// ----------------------------------------------------------------------------
+//
+// 1 2 3 4 5 6 7
+// 1234567890123456789012345678901234567890123456789012345678901234567890
+
+
+EISA_CHECKPOINT_INFO EisaCheckpointInfo[] = {
+ // Descriptions Flags Par SubPar Led SubLed
+
+ { "Interrupt Controller (PIC)", 0x08, 0x20, 0x00, 0xE, 0x00 },
+ { "Direct Memory Access (DMA)", 0x08, 0x21, 0x00, 0xE, 0x01 },
+ { "Non Maskable Interrupt (NMI)", 0x0A, 0x22, 0x00, 0xE, 0x02 },
+ { "Memory Refresh", 0x08, 0x23, 0x00, 0xE, 0x03 },
+ { "System Control Port B", 0x08, 0x24, 0x00, 0xE, 0x04 },
+ { "Timer 1", 0x08, 0x25, 0x00, 0xE, 0x05 },
+ { "Timer 2", 0x08, 0x26, 0x00, 0xE, 0x06 },
+ { NULL, 0x04, 0x27, 0x00, 0xE, 0x07 },
+ { NULL, 0x02, 0x30, 0x00, 0xF, 0x00 }
+};
+
+PCHAR EISA_INIT_MSG = " EISA Bus %lu Initialization In Progress...";
+PCHAR EISA_BUS_MSG = "EISA Bus";
+PCHAR EISA_ERROR_SLOT_MSG = "\r\n Slot(%lu) %s";
+PCHAR EISA_HOT_NMI_MSG = "Hot NMI Detected\n\r";
+PCHAR EISA_BUS_NUMBER_MSG = "\n\rEISA Bus %lu : ";
+PCHAR EISA_NMI_NOT_FOUND_MSG = "NMI not found\n\r";
+PCHAR EISA_PARITY_ERROR_MSG = "\r%c16CParity Error\r\n";
+PCHAR EISA_IO_CHECK_ERROR_MSG = "\r%c16CI/O Check Error";
+PCHAR EISA_IO_CHECK_NOT_SUP_MSG = ", IOCHKERR not supported\n\r";
+PCHAR EISA_IN_SLOT_MSG = " in Slot %lu\n\r";
+PCHAR EISA_BUS_MASTER_MSG = "\r%c16CBus Master ";
+PCHAR EISA_TIMEOUT_MSG = "%lu Timeout\n\r";
+PCHAR EISA_TIMEOUT2_MSG = "? Timeout\n\r";
+PCHAR EISA_SLAVE_TIMEOUT_MSG = "\r%c16CSlave Timeout\n\r";
diff --git a/private/ntos/fw/mips/fwentry.c b/private/ntos/fw/mips/fwentry.c
new file mode 100644
index 000000000..9a04f2b27
--- /dev/null
+++ b/private/ntos/fw/mips/fwentry.c
@@ -0,0 +1,57 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ fwentry.c
+
+Abstract:
+
+ This module just jumps to the selftest code.
+
+Author:
+
+ Lluis Abello (lluis) 03-Jan-1991
+
+Environment:
+
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+
+VOID
+FwSelftest(
+ IN ULONG Cause,
+ IN ULONG Arg1
+ );
+
+
+VOID
+FwEntry (
+ IN ULONG Cause,
+ IN ULONG Arg1
+ )
+
+/*++
+
+Routine Description:
+
+ This routine jumps to the selftest code.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FwSelftest(Cause,Arg1);
+}
diff --git a/private/ntos/fw/mips/fwio.c b/private/ntos/fw/mips/fwio.c
new file mode 100644
index 000000000..7b66eb5e4
--- /dev/null
+++ b/private/ntos/fw/mips/fwio.c
@@ -0,0 +1,1327 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ fwio.c
+
+Abstract:
+
+ This module implements the ARC firmware I/O operations for a MIPS
+ R3000 or R3000 Jazz system.
+
+Author:
+
+ David N. Cutler (davec) 14-May-1991
+
+
+Revision History:
+
+ Lluis Abello (lluis) 20-Jun-1991
+
+--*/
+
+#include "fwp.h"
+#include "string.h"
+#include "fwstring.h"
+
+
+//
+// Define file table.
+//
+
+BL_FILE_TABLE BlFileTable[BL_FILE_TABLE_SIZE];
+
+#define DEVICE_DEVICE 0xDEAD
+
+extern BL_DEVICE_ENTRY_TABLE OmfEntryTable;
+extern BL_DEVICE_ENTRY_TABLE OmfFileEntryTable;
+
+//
+// Declare the table of opened devices.
+//
+OPENED_PATHNAME_ENTRY OpenedPathTable[SIZE_OF_OPENED_PATHNAME_TABLE];
+
+//
+// Declare the table of opened drivers.
+//
+DRIVER_LOOKUP_ENTRY DeviceLookupTable[SIZE_OF_LOOKUP_TABLE];
+
+//
+// Define data structure for the file system structure context.
+//
+
+typedef union _FILE_SYSTEM_STRUCTURE {
+ FAT_STRUCTURE_CONTEXT FatContext;
+ ULONG Tmp;
+} FILE_SYSTEM_STRUCTURE, *PFILE_SYSTEM_STRUCTURE;
+
+typedef struct _FS_POOL_ENTRY {
+ BOOLEAN InUse;
+ FILE_SYSTEM_STRUCTURE Fs;
+} FS_POOL_ENTRY, *PFS_POOL_ENTRY;
+
+#define FS_POOL_SIZE 8
+PFS_POOL_ENTRY FileSystemStructurePool;
+
+//
+// Declare local procedures
+//
+
+VOID
+FiFreeFsStructure(
+ IN PFILE_SYSTEM_STRUCTURE PFs
+ );
+
+PVOID
+FiAllocateFsStructure(
+ VOID
+ );
+
+
+ARC_STATUS
+FiGetFileTableEntry(
+ OUT PULONG Entry
+ );
+
+PFAT_STRUCTURE_CONTEXT
+FiAllocateFatStructure(
+ VOID
+ );
+
+
+VOID
+HalFlushIoBuffers (
+ IN PMDL Mdl,
+ IN BOOLEAN ReadOperation,
+ IN BOOLEAN DmaOperation
+ )
+
+/*++
+
+Routine Description:
+
+ This function flushes the I/O buffer specified by the memory descriptor
+ list from the data cache on the current processor.
+
+Arguments:
+
+ Mdl - Supplies a pointer to a memory descriptor list that describes the
+ I/O buffer location.
+
+ ReadOperation - Supplies a boolean value that determines whether the I/O
+ operation is a read into memory.
+
+ DmaOperation - Supplies a boolean value that determines whether the I/O
+ operation is a DMA operation.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG CacheSegment;
+ ULONG Length;
+ ULONG Offset;
+ KIRQL OldIrql;
+ PULONG PageFrame;
+ ULONG Source;
+
+ //
+ // The Jazz R4000 uses a write back data cache and, therefore, must be
+ // flushed on reads and writes.
+ //
+ // Raise IRQL to dispatch level to prevent a context switch.
+ //
+
+// KeRaiseIrql(DISPATCH_LEVEL, &OldIrql);
+
+ //
+ // If the length of the I/O operation is greater than the size of the
+ // data cache, then sweep the entire data cache. Otherwise, export or
+ // purge individual pages from the data cache as appropriate.
+ //
+
+ Offset = Mdl->ByteOffset & PCR->DcacheAlignment;
+
+#if DBG
+
+// if (ReadOperation != FALSE) {
+// if (Offset != 0) {
+// DbgPrint("\n*** CAUTION *** unaliged transfer - proceed at your own risk\n");
+// DbgBreakPoint();
+// }
+// }
+
+#endif
+
+ Length = (Mdl->ByteCount +
+ PCR->DcacheAlignment + Offset) & ~PCR->DcacheAlignment;
+
+ if ((Length > PCR->FirstLevelDcacheSize) &&
+ (Length > PCR->SecondLevelDcacheSize)) {
+
+ //
+ // If the I/O operation is a DMA operation, or the I/O operation is
+ // not a DMA operation and the I/O operation is a page read operation,
+ // then sweep (index/writeback/invalidate) the entire data cache.
+ //
+
+ if ((DmaOperation != FALSE) ||
+ ((DmaOperation == FALSE) &&
+ (ReadOperation != FALSE) &&
+ ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0))) {
+ HalSweepDcache();
+ }
+
+ //
+ // If the I/O operation is a page read, then sweep (index/invalidate)
+ // the entire instruction cache.
+ //
+
+ if ((ReadOperation != FALSE) &&
+ ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0)) {
+ HalSweepIcache();
+ }
+
+ } else {
+
+ //
+ // Export or purge the specified pages from the data cache and
+ // instruction caches as appropriate.
+ //
+ // Compute the number of pages to flush and the starting MDL page
+ // frame address.
+ //
+
+ Offset = Mdl->ByteOffset & ~PCR->DcacheAlignment;
+ PageFrame = (PULONG)(Mdl + 1);
+ Source = ((ULONG)(Mdl->StartVa) & 0xfffff000) | Offset;
+
+ //
+ // Export or purge the specified page segments from the data and
+ // instruction caches as appropriate.
+ //
+
+ do {
+ if (Length >= (PAGE_SIZE - Offset)) {
+ CacheSegment = PAGE_SIZE - Offset;
+
+ } else {
+ CacheSegment = Length;
+ }
+
+ if (ReadOperation == FALSE) {
+
+ //
+ // The I/O operation is a write and the data only needs to
+ // to be copied back into memory if the operation is also
+ // a DMA operation.
+ //
+
+ if (DmaOperation != FALSE) {
+ HalExportDcachePage((PVOID)Source, *PageFrame, CacheSegment);
+ }
+
+ } else {
+
+ //
+ // If the I/O operation is a DMA operation, then purge the
+ // data cache. Otherwise, is the I/O operation is a page read
+ // operation, then export the data cache.
+ //
+
+ //
+ // This has been to flush rather than purge the D cache on DMA
+ // operations. The ARC firmware allows non-aligned reads, and
+ // the purge operation can destroy information that is in the
+ // same cache line as the DMA.
+ //
+
+ if (DmaOperation != FALSE) {
+// HalPurgeDcachePage((PVOID)Source, *PageFrame, CacheSegment);
+ HalFlushDcachePage((PVOID)Source, *PageFrame, CacheSegment);
+
+ } else if ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0) {
+ HalExportDcachePage((PVOID)Source, *PageFrame, CacheSegment);
+ }
+
+ //
+ // If the I/O operation is a page read, then the instruction
+ // cache must be purged.
+ //
+
+ if ((Mdl->MdlFlags & MDL_IO_PAGE_READ) != 0) {
+// HalPurgeIcachePage((PVOID)Source, *PageFrame, CacheSegment);
+ HalFlushDcachePage((PVOID)Source, *PageFrame, CacheSegment);
+ }
+ }
+
+ PageFrame += 1;
+ Length -= CacheSegment;
+ Offset = 0;
+ Source += CacheSegment;
+ } while(Length != 0);
+ }
+
+ //
+ // Lower IRQL to its previous value.
+ //
+
+// KeLowerIrql(OldIrql);
+ return;
+}
+
+
+ARC_STATUS
+FwGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Finfo
+ )
+
+/*++
+
+Routine Description:
+
+ This function gets the file information for the specified FileId.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Finfo - Supplies a pointer to where the File Informatino is stored.
+
+Return Value:
+
+ If the specified file is open then this routine dispatches to the
+ File routine.
+ Otherwise, returns an unsuccessful status.
+
+--*/
+
+{
+
+ if (BlFileTable[FileId].Flags.Open == 1) {
+ return (BlFileTable[FileId].DeviceEntryTable->GetFileInformation)(FileId,
+ Finfo);
+ } else {
+ return EACCES;
+ }
+}
+
+ARC_STATUS
+FwSetFileInformation (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ )
+
+/*++
+
+Routine Description:
+
+ This function sets the file attributes for the specified FileId.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ AttributeFlags - Supply the attributes to be set for the file.
+ AttributeMask
+
+Return Value:
+
+ If the specified file is open and is not a device then this routine
+ dispatches to the file system routine.
+ Otherwise, returns an unsuccessful status.
+
+--*/
+
+{
+
+ if ((BlFileTable[FileId].Flags.Open == 1) &&
+ (BlFileTable[FileId].DeviceId != DEVICE_DEVICE)) {
+ return (BlFileTable[FileId].DeviceEntryTable->SetFileInformation)(FileId,
+ AttributeFlags,
+ AttributeMask);
+ } else {
+ return EACCES;
+ }
+}
+
+
+ARC_STATUS
+FwMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+FwRead (
+ IN ULONG FileId,
+ OUT PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ This function reads from a file or a device that is open.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that receives the data
+ read.
+
+ Length - Supplies the number of bytes that are to be read.
+
+ Count - Supplies a pointer to a variable that receives the number of
+ bytes actually transfered.
+
+Return Value:
+
+ If the specified file is open for read, then a read is attempted
+ and the status of the operation is returned. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+
+ //
+ // If the file is open for read, then attempt to read from it. Otherwise
+ // return an access error.
+ //
+
+ if ((BlFileTable[FileId].Flags.Open == 1) &&
+ (BlFileTable[FileId].Flags.Read == 1)) {
+ return (BlFileTable[FileId].DeviceEntryTable->Read)(FileId,
+ Buffer,
+ Length,
+ Count);
+
+ } else {
+ return EACCES;
+ }
+}
+
+ARC_STATUS
+FwGetReadStatus (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+
+ //
+ // If the file is open for read, then call the call the specific routine.
+ // Otherwise return an access error.
+
+ if ((BlFileTable[FileId].Flags.Open == 1) &&
+ (BlFileTable[FileId].Flags.Read == 1)) {
+
+ //
+ // Make sure there is a valid GetReadStatus entry.
+ //
+
+ if (BlFileTable[FileId].DeviceEntryTable->GetReadStatus != NULL) {
+ return(BlFileTable[FileId].DeviceEntryTable->GetReadStatus)(FileId);
+ } else {
+ return(EACCES);
+ }
+
+ } else {
+ return EACCES;
+ }
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+FwSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+ If the specified file is open, then a seek is attempted and
+ the status of the operation is returned. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+
+ //
+ // If the file is open, then attempt to seek on it. Otherwise return an
+ // access error.
+ //
+
+ if (BlFileTable[FileId].Flags.Open == 1) {
+ return (BlFileTable[FileId].DeviceEntryTable->Seek)(FileId,
+ Offset,
+ SeekMode);
+ } else {
+ return EACCES;
+ }
+}
+
+ARC_STATUS
+FwWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ This function writes to a file or a device that is open.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer that contains the data
+ to write.
+
+ Length - Supplies the number of bytes that are to be written.
+
+ Count - Supplies a pointer to a variable that receives the number of
+ bytes actually transfered.
+
+Return Value:
+
+ If the specified file is open for write, then a write is attempted
+ and the status of the operation is returned. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+ //
+ // If the file is open for write, then attempt to write to it. Otherwise
+ // return an access error.
+ //
+
+ if ((BlFileTable[FileId].Flags.Open == 1) &&
+ (BlFileTable[FileId].Flags.Write == 1)) {
+ return (BlFileTable[FileId].DeviceEntryTable->Write)(FileId,
+ Buffer,
+ Length,
+ Count);
+
+ } else {
+ return EACCES;
+ }
+}
+
+
+ARC_STATUS
+FwGetDirectoryEntry (
+ IN ULONG FileId,
+ OUT PDIRECTORY_ENTRY Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ This function reads from a file the requested number of directory entries.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a pointer to the buffer to receive the directory
+ entries.
+
+ Length - Supplies the number of directory entries to be read.
+
+ Count - Supplies a pointer to a variable that receives the number of
+ directory entries actually read..
+
+Return Value:
+
+ If the specified file is open for read, then a read is attempted
+ and the status of the operation is returned. Otherwise, return an
+ unsuccessful status.
+
+--*/
+{
+ //
+ // If the file is open for read, then call the call the specific routine.
+ // Otherwise return an access error.
+ //
+
+ if ((FileId < BL_FILE_TABLE_SIZE) &&
+ (BlFileTable[FileId].Flags.Open == 1) &&
+ (BlFileTable[FileId].Flags.Read == 1) &&
+ (BlFileTable[FileId].DeviceId != DEVICE_DEVICE)) {
+
+ //
+ // Check to make sure a GetDirectoryEntry routine exists
+ //
+
+ if (BlFileTable[FileId].DeviceEntryTable->GetDirectoryEntry != NULL) {
+ return (BlFileTable[FileId].DeviceEntryTable->GetDirectoryEntry)
+ (FileId, Buffer, Length, Count);
+ }
+ } else {
+ return EBADF;
+ }
+}
+
+
+ARC_STATUS
+FwClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes a file or a device if it's open.
+ The DeviceId field indicates if the FileId is a device
+ (it has the value DEVICE_DEVICE) or is a file.
+ When closing a file, after the file is closed the
+ reference counter for the device is decremented and if zero
+ the device is also closed and the device name removed from
+ the table of opened devices.
+ If FileId specifies a device, the reference counter is
+ decremented and if zero the device is closed and the device
+ name removed from the table of opened devices.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+Return Value:
+
+ If the specified file is open, then a close is attempted and
+ the status of the operation is returned. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+ ULONG DeviceId;
+ ARC_STATUS Status;
+ if (BlFileTable[FileId].Flags.Open == 1) {
+ //
+ // Check if closing a file or a device
+ //
+ if (BlFileTable[FileId].DeviceId == DEVICE_DEVICE) {
+ //
+ // Decrement reference counter, if it's zero call the device
+ // close routine.
+ //
+ OpenedPathTable[FileId].ReferenceCounter--;
+ if (OpenedPathTable[FileId].ReferenceCounter == 0) {
+ //
+ // Remove the name of the device from the table of opened devices.
+ //
+ OpenedPathTable[FileId].DeviceName[0] = '\0';
+
+ //
+ // Call the device specific close routine.
+ //
+ Status = (BlFileTable[FileId].DeviceEntryTable->Close)(FileId);
+
+ //
+ // If the device has a file system, free the memory used for
+ // the STRUCTURE_CONTEXT.
+ //
+ if (BlFileTable[FileId].StructureContext != NULL) {
+ FiFreeFsStructure(BlFileTable[FileId].StructureContext);
+ }
+ return Status;
+ } else {
+ return ESUCCESS;
+ }
+ } else {
+ //
+ // Close the file
+ //
+ DeviceId= BlFileTable[FileId].DeviceId;
+ Status = (BlFileTable[FileId].DeviceEntryTable->Close)(FileId);
+ if (Status) {
+ return Status;
+ }
+
+ //
+ // Close also the device
+ //
+ return FwClose(DeviceId);
+ }
+ } else {
+ return EACCES;
+ }
+}
+
+ARC_STATUS
+FwOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This function opens the file specified by OpenPath.
+ If the device portion of the pathanme is already opened, it reuses
+ the fid. Otherwise it looks for a driver able to handle this
+ device and logs the opened device so that it can be reused.
+
+Arguments:
+
+ OpenPath - ARC compliant pathname of the device/file to be opened.
+ OpenMode - Supplies the mode in wich the file is opened.
+ FileId - Pointer to a variable that receives the fid for this
+ pathname.
+
+Return Value:
+
+ If the file is successfully opened returns ESUCCESS otherwise
+ returns an unsuccessfull status.
+
+--*/
+
+{
+ ULONG i;
+ ULONG DeviceId;
+ PCHAR FileName ;
+ PCHAR TempString1;
+ PCHAR TempString2;
+ ARC_STATUS Status;
+ CHAR DeviceName[80];
+ PVOID TmpStructureContext;
+ OPEN_MODE DeviceOpenMode;
+ BOOLEAN OmfProtocol;
+
+ //
+ // Split OpenPath into DeviceName and FileName.
+ // Search for the last ')'
+ //
+ FileName = OpenPath;
+ for (TempString1 = OpenPath; *TempString1; TempString1++) {
+ if ( *TempString1 == ')') {
+ FileName = TempString1+1;
+ }
+ }
+ if (FileName == OpenPath) {
+ return ENODEV;
+ }
+
+ //
+ // Extract the device pathname, convert it to lower case and
+ // put zeros where the "key" is not specified.
+ //
+ TempString1=DeviceName;
+ for (TempString2=OpenPath;TempString2 != FileName ;TempString2++) {
+ //
+ // If about to copy ')' and previous char was '('
+ // put a zero in between.
+ //
+ if (((*TempString2 == ')') && (*(TempString1-1)) == '(')){
+ *TempString1++ = '0';
+ }
+ *TempString1++ = tolower(*TempString2);
+ }
+ *TempString1 = '\0';
+
+ //
+ // Translate the open mode to its equivalent for devices.
+ //
+ DeviceOpenMode = OpenMode;
+
+ if (FileName[0] == '\0') {
+ //
+ // On an attempt to open a device with an invalid OpenMode
+ // return an error.
+ //
+ if (OpenMode > ArcOpenReadWrite) {
+ return EINVAL;
+ }
+ } else {
+
+ //
+ // A file is being open, set the right Open Mode for the device.
+ //
+ if (OpenMode > ArcOpenReadOnly) {
+ DeviceOpenMode = ArcOpenReadWrite;
+ }
+ }
+
+ //
+ // Check for OMF protocol.
+ //
+
+ if ( strstr(DeviceName, ")omf(0)" ) != NULL ) {
+ OmfProtocol = TRUE;
+ } else {
+ OmfProtocol = FALSE;
+ }
+
+ //
+ // Search for a matching entry in the table of opened devices.
+ //
+ for (DeviceId = 0;DeviceId < SIZE_OF_OPENED_PATHNAME_TABLE;DeviceId++) {
+ if (strcmp(DeviceName,OpenedPathTable[DeviceId].DeviceName)==0) {
+ //
+ // device already opened. Check that it's also opened in
+ // the same mode.
+ //
+ if ((DeviceOpenMode != ArcOpenWriteOnly) && (BlFileTable[DeviceId].Flags.Read != 1)) {
+ continue;
+ }
+ if ((DeviceOpenMode != ArcOpenReadOnly) && (BlFileTable[DeviceId].Flags.Write != 1)) {
+ continue;
+ }
+ //
+ // If opened for the same Mode then just increment reference counter.
+ //
+ OpenedPathTable[DeviceId].ReferenceCounter++;
+ Status = ESUCCESS;
+ break;
+ }
+ }
+ if (DeviceId == SIZE_OF_OPENED_PATHNAME_TABLE) {
+
+ //
+ // Device not opened. Look for a driver that handles this device.
+ //
+
+ if ( OmfProtocol ) {
+
+ //
+ // omf protocol, let the omf software layer validate the path.
+ // Get a free entry in the file table for the device.
+ //
+
+ if ( Status = FiGetFileTableEntry( &DeviceId ) ) {
+ return Status;
+ }
+
+ BlFileTable[DeviceId].DeviceEntryTable = &OmfEntryTable;
+
+ } else {
+
+ for (i=0;i < SIZE_OF_LOOKUP_TABLE; i++) {
+ if (DeviceLookupTable[i].DevicePath == NULL) {
+
+ //
+ // Driver not found
+ //
+
+ return ENODEV;
+ }
+ if (strstr(DeviceName,DeviceLookupTable[i].DevicePath) == DeviceName) {
+
+ //
+ // Get a free entry in the file table for the device.
+ //
+
+ if (Status = FiGetFileTableEntry(&DeviceId)) {
+ return Status;
+ }
+
+ //
+ // Set the dispatch table in the file table.
+ //
+
+ BlFileTable[DeviceId].DeviceEntryTable = DeviceLookupTable[i].DispatchTable;
+ break;
+ }
+ }
+
+ //
+ // if end of table, drive not found
+ //
+
+ if ( i == SIZE_OF_LOOKUP_TABLE )
+ {
+ return ENODEV;
+ }
+ }
+
+ //
+ // Call the device specific open routine. Use the DeviceName instead of
+ // the OpenPath so that the drivers always see a lowercase name.
+ //
+
+ Status = (BlFileTable[DeviceId].DeviceEntryTable->Open)(DeviceName,
+ DeviceOpenMode,
+ &DeviceId);
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ //
+ // if the device was successfully opened. Log this device name
+ // and initialize the file table.
+ //
+
+ strcpy(OpenedPathTable[DeviceId].DeviceName,DeviceName);
+ OpenedPathTable[DeviceId].ReferenceCounter = 1;
+
+ //
+ // Set flags in file table.
+ //
+
+ BlFileTable[DeviceId].Flags.Open = 1;
+
+ if (DeviceOpenMode != ArcOpenWriteOnly) {
+ BlFileTable[DeviceId].Flags.Read = 1;
+ }
+ if (DeviceOpenMode != ArcOpenReadOnly) {
+ BlFileTable[DeviceId].Flags.Write = 1;
+ }
+
+ //
+ // Mark this entry in the file table as a device itself.
+ //
+
+ BlFileTable[DeviceId].DeviceId = DEVICE_DEVICE;
+ BlFileTable[DeviceId].StructureContext = NULL;
+ }
+
+ //
+ // If we get here the device was successfully open and DeviceId contains
+ // the entry in the file table for this device.
+ //
+
+ if (FileName[0]) {
+
+ //
+ // Get an entry for the file.
+ //
+
+ if (Status=FiGetFileTableEntry(FileId)) {
+ FwClose( DeviceId );
+ return Status;
+
+ //
+ // check if "omf" file system
+ //
+
+ } else if ( OmfProtocol ) {
+ BlFileTable[ *FileId ].DeviceEntryTable = &OmfFileEntryTable;
+
+ //
+ // Check if the device has a recognized file system on it. If not
+ // present, allocate a structure context.
+ //
+
+ } else if (((TmpStructureContext = BlFileTable[DeviceId].StructureContext) == NULL) &&
+ ((TmpStructureContext = FiAllocateFsStructure()) == NULL)) {
+ FwClose( DeviceId );
+ return EMFILE;
+
+ //
+ // Check for FAT filesystem.
+ //
+
+ } else if ((BlFileTable[*FileId].DeviceEntryTable =
+ IsFatFileStructure(DeviceId,TmpStructureContext))
+ != NULL) {
+ BlFileTable[DeviceId].StructureContext = TmpStructureContext;
+
+ //
+ // Check for CD filesystem.
+ //
+
+ } else if ((BlFileTable[*FileId].DeviceEntryTable =
+ IsCdfsFileStructure(DeviceId,TmpStructureContext))
+ != NULL) {
+ BlFileTable[DeviceId].StructureContext = TmpStructureContext;
+
+ } else {
+
+ FiFreeFsStructure(TmpStructureContext);
+ FwClose(DeviceId);
+ FwPrint(FW_FILESYSTEM_NOT_REQ_MSG);
+ return EIO;
+ }
+
+ //
+ // Set the DeviceId in the file table.
+ //
+
+ BlFileTable[*FileId].DeviceId = DeviceId;
+
+ //
+ // Copy the pointer to FatStructureContext from the device entry
+ // to the file entry.
+ //
+
+ BlFileTable[*FileId].StructureContext = BlFileTable[DeviceId].StructureContext;
+ Status = (BlFileTable[*FileId].DeviceEntryTable->Open)(FileName,
+ OpenMode,
+ FileId);
+
+
+ //
+ // If the file could not be opened. Then close the device and
+ // return the error
+ //
+
+ if (Status != ESUCCESS) {
+ FiFreeFsStructure(TmpStructureContext);
+ FwClose(DeviceId);
+ return Status;
+ }
+ } else {
+
+ //
+ // No file specified return the fid for the device.
+ //
+ *FileId = DeviceId;
+ return Status;
+ }
+}
+
+ARC_STATUS
+FiGetFileTableEntry(
+ OUT PULONG Entry
+ )
+
+/*++
+
+Routine Description:
+
+ This function looks for an unused entry in the FileTable.
+
+Arguments:
+
+ Entry - Pointer to the variable that gets an index for the file table.
+
+Return Value:
+
+ Returns ESUCCESS if a free entry is found
+ or EMFILE if no entry is available.
+
+--*/
+
+{
+ ULONG Index;
+ for (Index=0;Index < BL_FILE_TABLE_SIZE;Index++) {
+ if (BlFileTable[Index].Flags.Open == 0) {
+ *Entry = Index;
+ return ESUCCESS;
+ }
+ }
+ return EMFILE;
+}
+ ULONG
+FiGetFreeLookupEntry (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks for the first available entry in the device
+ lookup table, that is the entry where DevicePath is NULL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the Index of the first free entry of the DeviceLookupTable
+ or SIZE_OF_LOOKUP_TABLE is the table is full.
+
+
+--*/
+
+{
+ULONG Index;
+ //
+ // Search for the first free entry in the Lookup table
+ //
+ for (Index=0;Index < SIZE_OF_LOOKUP_TABLE;Index++) {
+ if (DeviceLookupTable[Index].DevicePath == NULL) {
+ break;
+ }
+ }
+ return Index;
+}
+
+VOID
+FwIoInitialize1(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the file table used by the firmware to
+ export I/O functions to client programs loaded from the system
+ partition, initializes the I/O entry points in the firmware
+ transfer vector and initializes the display driver.
+
+ Note: This routine is caleld at phase 1 initialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG Index;
+ //
+ // Initialize the I/O entry points in the firmware transfer vector.
+ //
+
+ (PARC_CLOSE_ROUTINE)SYSTEM_BLOCK->FirmwareVector[CloseRoutine] = FwClose;
+ (PARC_MOUNT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[MountRoutine] = FwMount;
+ (PARC_OPEN_ROUTINE)SYSTEM_BLOCK->FirmwareVector[OpenRoutine] = FwOpen;
+ (PARC_READ_ROUTINE)SYSTEM_BLOCK->FirmwareVector[ReadRoutine] = FwRead;
+ (PARC_READ_STATUS_ROUTINE)SYSTEM_BLOCK->FirmwareVector[ReadStatusRoutine] =
+ FwGetReadStatus;
+ (PARC_SEEK_ROUTINE)SYSTEM_BLOCK->FirmwareVector[SeekRoutine] = FwSeek;
+ (PARC_WRITE_ROUTINE)SYSTEM_BLOCK->FirmwareVector[WriteRoutine] = FwWrite;
+ (PARC_GET_FILE_INFO_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetFileInformationRoutine] = FwGetFileInformation;
+ (PARC_SET_FILE_INFO_ROUTINE)SYSTEM_BLOCK->FirmwareVector[SetFileInformationRoutine] = FwSetFileInformation;
+ (PARC_GET_DIRECTORY_ENTRY_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetDirectoryEntryRoutine] = FwGetDirectoryEntry;
+
+ //
+ // Initialize the file table.
+ //
+
+ for (Index = 0; Index < BL_FILE_TABLE_SIZE; Index += 1) {
+ BlFileTable[Index].Flags.Open = 0;
+ }
+
+ //
+ // Initialize the driver lookup table.
+ //
+ for (Index=0;Index < SIZE_OF_LOOKUP_TABLE;Index++) {
+ DeviceLookupTable[Index].DevicePath = NULL;
+ }
+
+ //
+ // Initialize the table of opened devices.
+ //
+ for (Index = 0;Index < SIZE_OF_OPENED_PATHNAME_TABLE;Index++) {
+ OpenedPathTable[Index].DeviceName[0]='\0';
+ }
+
+ //
+ // Call the Display driver initialization routine
+ //
+ DisplayInitialize(&DeviceLookupTable[0],
+ SIZE_OF_LOOKUP_TABLE);
+ return;
+}
+
+VOID
+FwIoInitialize2(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls the device driver initialization routines.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Index;
+
+ //
+ // Call the Keyboard driver initialization routine
+ //
+ if ((Index=FiGetFreeLookupEntry()) == SIZE_OF_LOOKUP_TABLE) {
+ FwPrint(FW_NOT_ENOUGH_ENTRIES_MSG);
+ } else {
+ KeyboardInitialize(&DeviceLookupTable[Index],
+ SIZE_OF_LOOKUP_TABLE-Index);
+ }
+
+#ifndef DUO
+ //
+ // Look for first free entry and call
+ // floppy driver initialization routine
+ //
+ if ((Index=FiGetFreeLookupEntry()) == SIZE_OF_LOOKUP_TABLE) {
+ FwPrint(FW_NOT_ENOUGH_ENTRIES_MSG);
+ } else {
+ FloppyInitialize(&DeviceLookupTable[Index],
+ SIZE_OF_LOOKUP_TABLE-Index);
+ }
+
+#endif
+
+ //
+ // Call the mini-port driver initialization routine.
+ //
+
+ DriverEntry(NULL);
+
+ //
+ // Call the scsi driver initialization routine
+ //
+ if ((Index=FiGetFreeLookupEntry()) == SIZE_OF_LOOKUP_TABLE) {
+ FwPrint(FW_NOT_ENOUGH_ENTRIES_MSG);
+ } else {
+ HardDiskInitialize(&DeviceLookupTable[Index],
+ SIZE_OF_LOOKUP_TABLE-Index);
+ }
+
+ //
+ // Call the serial port driver initialization routine
+ //
+ if ((Index=FiGetFreeLookupEntry()) == SIZE_OF_LOOKUP_TABLE) {
+ FwPrint(FW_NOT_ENOUGH_ENTRIES_MSG);
+ } else {
+ SerialInitialize(&DeviceLookupTable[Index],
+ SIZE_OF_LOOKUP_TABLE-Index);
+ }
+
+ //
+ // Pre allocate memory for the File system structures.
+ //
+
+ FileSystemStructurePool =
+ FwAllocatePool(sizeof(FS_POOL_ENTRY) * FS_POOL_SIZE);
+
+ return;
+}
+
+ PVOID
+FiAllocateFsStructure(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a File System structure
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns a pointer to the Allocated File System structure or NULL.
+
+--*/
+
+{
+
+ PFS_POOL_ENTRY TmpPointer,Last;
+
+ TmpPointer = FileSystemStructurePool;
+
+ Last = FileSystemStructurePool+FS_POOL_SIZE;
+ do {
+ if (TmpPointer->InUse == FALSE) {
+ TmpPointer->InUse = TRUE;
+ return &TmpPointer->Fs;
+ }
+ TmpPointer++;
+ } while (TmpPointer != Last);
+ return NULL;
+}
+ VOID
+FiFreeFsStructure(
+ IN PFILE_SYSTEM_STRUCTURE PFs
+ )
+
+/*++
+
+Routine Description:
+
+ This routine frees a File System structure previously allocated.
+
+Arguments:
+
+ PFs pointer to the file system structure to free.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CONTAINING_RECORD(PFs, FS_POOL_ENTRY, Fs)->InUse = FALSE;
+ return;
+}
diff --git a/private/ntos/fw/mips/fwload.c b/private/ntos/fw/mips/fwload.c
new file mode 100644
index 000000000..43c74cfd5
--- /dev/null
+++ b/private/ntos/fw/mips/fwload.c
@@ -0,0 +1,1043 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ fwload.c
+
+Abstract:
+
+ This module implements the ARC software loadable functions.
+
+Author:
+
+ Lluis Abello (lluis) 19-Sep-1991
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#include "string.h"
+#include "ntimage.h"
+#include "selftest.h"
+#include "fwstring.h"
+
+extern BOOLEAN FirstLoadedProgram;
+
+VOID
+FwpRestart(
+ );
+
+//
+// Declare external variables.
+//
+
+extern BOOLEAN BreakAfterLoad;
+
+#define MAX_ARGUMENT (512 - sizeof(ULONG) - 16*sizeof(PUCHAR))
+typedef struct _SAVED_ARGUMENTS {
+ ULONG Argc;
+ PUCHAR Argv[16];
+ UCHAR Arguments[MAX_ARGUMENT];
+} SAVED_ARGUMENTS, *PSAVED_ARGUMENTS;
+
+//
+// Static variables.
+//
+
+PSAVED_ARGUMENTS PSavedArgs;
+ULONG FwTemporaryStack;
+ULONG FwActualBasePage;
+ULONG FwPageCount;
+BOOLEAN MatchedReflo;
+
+ARC_STATUS
+FwExecute(
+ IN PCHAR Path,
+ IN ULONG Argc,
+ IN PCHAR Argv[],
+ IN PCHAR Envp[]
+ );
+
+
+//
+// s_flags values
+//
+
+#define STYP_REG 0x00000000
+#define STYP_TEXT 0x00000020
+#define STYP_INIT 0x80000000
+#define STYP_RDATA 0x00000100
+#define STYP_DATA 0x00000040
+#define STYP_LIT8 0x08000000
+#define STYP_LIT4 0x10000000
+#define STYP_SDATA 0x00000200
+#define STYP_SBSS 0x00000080
+#define STYP_BSS 0x00000400
+#define STYP_LIB 0x40000000
+#define STYP_UCODE 0x00000800
+#define S_NRELOC_OVFL 0x20000000
+
+//
+// Section numbers for local relocation entries
+//
+
+#define R_SN_TEXT 1
+#define R_SN_INIT 7
+#define R_SN_RDATA 2
+#define R_SN_DATA 3
+#define R_SN_SDATA 4
+#define R_SN_SBSS 5
+#define R_SN_BSS 6
+#define R_SN_LIT8 8
+#define R_SN_LIT4 9
+#define R_SN_MAX 10
+
+typedef struct _MIPS_RELOCATION_TYPE {
+ ULONG SymbolIndex:24;
+ ULONG Reserved:3;
+ ULONG Type:4;
+ ULONG External:1;
+} MIPS_RELOCATION_TYPE, *PMIPS_RELOCATION_TYPE;
+
+typedef struct _MIPS_RELOCATION_ENTRY {
+ ULONG VirtualAddress;
+ MIPS_RELOCATION_TYPE Type;
+} MIPS_RELOCATION_ENTRY, *PMIPS_RELOCATION_ENTRY;
+
+typedef struct _MIPS_SYMBOLIC_HEADER {
+ SHORT Magic;
+ SHORT VersionStamp;
+ ULONG NumOfLineNumberEntries;
+ ULONG BytesForLineNumberEntries;
+ ULONG PointerToLineNumberEntries;
+ ULONG NumOfDenseNumbers;
+ ULONG PointerToDenseNumbers;
+ ULONG NumOfProcedures;
+ ULONG PointerToProcedures;
+ ULONG NumOfLocalSymbols;
+ ULONG PointerToLocalSymbols;
+ ULONG NumOfOptimizationEntries;
+ ULONG PointerToOptimizationEntries;
+ ULONG NumOfAuxSymbols;
+ ULONG PointerToAuxSymbols;
+ ULONG NumOfLocalStrings;
+ ULONG PointerToLocalStrings;
+ ULONG NumOfExternalStrings;
+ ULONG PointerToExternalStrings;
+ ULONG NumOfFileDescriptors;
+ ULONG PointerToFileDescriptors;
+ ULONG NumOfRelativeFileDescriptors;
+ ULONG PointerToRelativeFileDescriptors;
+ ULONG NumOfExternalSymbols;
+ ULONG PointerToExternalSymbols;
+} MIPS_SYMBOLIC_HEADER, *PMIPS_SYMBOLIC_HEADER;
+
+typedef struct _MIPS_LOCAL_SYMBOL {
+ ULONG IndexToSymbolString;
+ ULONG Value;
+ ULONG Type:6;
+ ULONG StorageClass:5;
+ ULONG Reserved:1;
+ ULONG Index:20;
+} MIPS_LOCAL_SYMBOL, *PMIPS_LOCAL_SYMBOL;
+
+//
+// Types for external symbols
+//
+#define EST_NIL 0
+#define EST_GLOBAL 1
+#define EST_STATIC 2
+#define EST_PARAM 3
+#define EST_LOCAL 4
+#define EST_LABEL 5
+#define EST_PROC 6
+#define EST_BLOCK 7
+#define EST_END 8
+#define EST_MEMBER 9
+#define EST_TYPEDEF 10
+#define EST_FILE 11
+#define EST_STATICPROC 14
+#define EST_CONSTANT 15
+
+//
+// Storage class for external symbols
+//
+#define ESSC_NIL 0
+#define ESSC_TEXT 1
+#define ESSC_DATA 2
+#define ESSC_BSS 3
+#define ESSC_REGISTER 4
+#define ESSC_ABS 5
+#define ESSC_UNDEFINED 6
+#define ESSC_BITS 8
+#define ESSC_DBX 9
+#define ESSC_REGIMAX 10
+#define ESSC_INFO 11
+#define ESSC_USER_STRUCT 12
+#define ESSC_SDATA 13
+#define ESSC_SBSS 14
+#define ESSC_SRDATA 15
+#define ESSC_VAR 16
+#define ESSC_COMMON 17
+#define ESSC_SCOMMON 18
+#define ESSC_VARREGISTER 19
+#define ESSC_VARIANT 20
+#define ESSC_SUNDEFINED 21
+#define ESSC_INIT 22
+
+typedef struct _MIPS_EXTERNAL_SYMBOL {
+ USHORT Reserved;
+ USHORT PointerToFileDescriptor;
+ MIPS_LOCAL_SYMBOL Symbol;
+} MIPS_EXTERNAL_SYMBOL, *PMIPS_EXTERNAL_SYMBOL;
+
+typedef struct _SECTION_RELOCATION_ENTRY {
+ ULONG FixupValue;
+ ULONG PointerToRelocations;
+ USHORT NumberOfRelocations;
+} SECTION_RELOCATION_ENTRY, *PSECTION_RELOCATION_ENTRY;
+
+typedef
+VOID
+(*PTRANSFER_ROUTINE) (
+ IN ULONG Argc,
+ IN PCHAR Argv[],
+ IN PCHAR Envp[]
+ );
+
+ARC_STATUS
+FwRelocateImage (
+ IN ULONG FileId,
+ PSECTION_RELOCATION_ENTRY RelocationTable
+ );
+
+VOID
+FwGenerateDescriptor (
+ IN PFW_MEMORY_DESCRIPTOR MemoryDescriptor,
+ IN MEMORY_TYPE MemoryType,
+ IN ULONG BasePage,
+ IN ULONG PageCount
+ );
+
+
+ARC_STATUS
+FwLoad (
+ IN PCHAR ImagePath,
+ IN ULONG TopAddress,
+ OUT PULONG EntryAddress,
+ OUT PULONG LowAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine attempts to load the specified file from the specified
+ device.
+
+Arguments:
+
+ ImagePath - Supplies a pointer to the path of the file to load.
+
+ TopAddress - Supplies the top address of a region of memory into which
+ the file is to be loaded.
+
+ EntryAddress - Supplies a pointer to a variable to receive the entry point
+ of the image, if defined.
+
+ LowAddress - Supplies a pointer to a variable to receive the low address
+ of the loaded file.
+
+Return Value:
+
+ ESUCCESS is returned if the specified image file is loaded
+ successfully. Otherwise, an unsuccessful status is returned
+ that describes the reason for failure.
+
+--*/
+
+{
+ SECTION_RELOCATION_ENTRY RelocationTable[R_SN_MAX];
+ ULONG ActualBase;
+ ULONG SectionBase;
+ ULONG SectionOffset;
+ ULONG SectionIndex;
+ ULONG Count;
+ PIMAGE_FILE_HEADER FileHeader;
+ ULONG FileId;
+ ULONG Index;
+ UCHAR LocalBuffer[SECTOR_SIZE+64];
+ PUCHAR LocalPointer;
+ ULONG NumberOfSections;
+ PIMAGE_OPTIONAL_HEADER OptionalHeader;
+ PIMAGE_SECTION_HEADER SectionHeader;
+ ARC_STATUS Status;
+ LARGE_INTEGER SeekPosition;
+ ULONG SectionFlags;
+
+ //
+ // Zero The relocation table
+ //
+ RtlZeroMemory((PVOID)RelocationTable,sizeof(RelocationTable));
+
+ //
+ // Align the buffer on a Dcache line size.
+ //
+
+ LocalPointer = (PVOID) ((ULONG) ((PCHAR) LocalBuffer + KeGetDcacheFillSize() - 1)
+ & ~(KeGetDcacheFillSize() - 1));
+
+ //
+ // Set the image start address to null.
+ //
+
+ *EntryAddress = 0;
+
+ //
+ // Attempt to open the load file.
+ //
+
+ Status = ArcOpen(ImagePath, ArcOpenReadOnly, &FileId);
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+
+ //
+ // Read the image header from the file.
+ //
+
+ Status = ArcRead(FileId, LocalPointer, SECTOR_SIZE, &Count);
+ if (Status != ESUCCESS) {
+ ArcClose(FileId);
+ return Status;
+ }
+
+ //
+ // Get a pointer to the file header and begin processing it.
+ //
+
+ FileHeader = (PIMAGE_FILE_HEADER)LocalPointer;
+ OptionalHeader =
+ (PIMAGE_OPTIONAL_HEADER)(LocalPointer + sizeof(IMAGE_FILE_HEADER));
+ SectionHeader =
+ (PIMAGE_SECTION_HEADER)(LocalPointer + sizeof(IMAGE_FILE_HEADER) +
+ FileHeader->SizeOfOptionalHeader);
+
+ //
+ // If the image file is not the specified type, then return bad image
+ // type status.
+ //
+
+ if (!((FileHeader->Machine == IMAGE_FILE_MACHINE_R3000) ||
+ (FileHeader->Machine == IMAGE_FILE_MACHINE_R4000)) ||
+ ((FileHeader->Characteristics & IMAGE_FILE_EXECUTABLE_IMAGE) == 0)) {
+ ArcClose(FileId);
+ return EBADF;
+ }
+
+ //
+ // If the image cannot be relocated, set the ActualBase to the code base,
+ // and compute the image size by subtracting the code base from the data
+ // base plus the size of the data. If the image can be relocated,
+ // set ActualBase to the TopAddress minus the image size, and compute the
+ // image size by adding the size of the code, initialized data, and
+ // uninitialized data.
+ //
+
+ NumberOfSections = FileHeader->NumberOfSections;
+
+ if ((FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) != 0) {
+ ActualBase = OptionalHeader->BaseOfCode;
+ FwPageCount = (OptionalHeader->BaseOfData + OptionalHeader->SizeOfInitializedData) -
+ ActualBase;
+ } else {
+ FwPageCount = OptionalHeader->SizeOfCode +
+ OptionalHeader->SizeOfInitializedData +
+ OptionalHeader->SizeOfUninitializedData;
+
+ ActualBase = (TopAddress - FwPageCount) & ~(PAGE_SIZE - 1);
+ }
+
+ //
+ // Convert ActualBasePage and PageCount to be in units of pages instead of
+ // bytes.
+ //
+
+ FwActualBasePage = (ActualBase & 0x1fffffff) >> PAGE_SHIFT;
+
+ if (strcmp((PCHAR)&SectionHeader[NumberOfSections - 1].Name, ".debug") == 0) {
+ NumberOfSections -= 1;
+ FwPageCount -= SectionHeader[NumberOfSections].SizeOfRawData;
+ }
+ FwPageCount = (FwPageCount + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ *LowAddress = ActualBase | KSEG0_BASE;
+
+ //
+ // Return the entry address to the caller.
+ //
+
+ *EntryAddress = ((ActualBase | KSEG0_BASE) +
+ (OptionalHeader->AddressOfEntryPoint - OptionalHeader->BaseOfCode)
+ );
+
+
+ //
+ // Scan through the sections and either read them into memory or clear
+ // the memory as appropriate.
+ //
+
+ SectionOffset = 0;
+ for (Index = 0; Index < NumberOfSections; Index += 1) {
+
+ //
+ // Compute the destination address for the current section.
+ //
+ if ((FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) != 0) {
+ SectionBase = SectionHeader->VirtualAddress | KSEG0_BASE;
+ } else {
+ SectionBase = ActualBase + SectionOffset;
+ //
+ // Store the section relocation information in the table.
+ //
+ SectionFlags = SectionHeader->Characteristics;
+ if (SectionFlags & STYP_TEXT) {
+ SectionIndex = R_SN_TEXT;
+ } else if (SectionFlags & STYP_INIT) {
+ SectionIndex = R_SN_INIT;
+ } else if (SectionFlags & STYP_RDATA) {
+ SectionIndex = R_SN_RDATA;
+ } else if (SectionFlags & STYP_DATA) {
+ SectionIndex = R_SN_DATA;
+ } else if (SectionFlags & STYP_SDATA) {
+ SectionIndex = R_SN_SDATA;
+ } else if (SectionFlags & STYP_SBSS) {
+ SectionIndex = R_SN_SBSS;
+ } else if (SectionFlags & STYP_BSS) {
+ SectionIndex = R_SN_BSS;
+ } else {
+ VenPrint(FW_UNKNOWN_SECTION_TYPE_MSG);
+ return EBADF;
+ }
+ RelocationTable[SectionIndex].PointerToRelocations = SectionHeader->PointerToRelocations;
+ RelocationTable[SectionIndex].NumberOfRelocations = SectionHeader->NumberOfRelocations;
+ RelocationTable[SectionIndex].FixupValue = SectionBase - SectionHeader->VirtualAddress;
+ }
+
+ //
+ // If the section is code, initialized data, or other, then read
+ // the code or data into memory.
+ //
+
+ if ((SectionHeader->Characteristics &
+ (STYP_TEXT | STYP_INIT | STYP_RDATA | STYP_DATA | STYP_SDATA)) != 0) {
+
+ SeekPosition.LowPart = SectionHeader->PointerToRawData;
+ SeekPosition.HighPart = 0;
+ Status = ArcSeek(FileId,
+ &SeekPosition,
+ SeekAbsolute);
+
+ if (Status != ESUCCESS) {
+ break;
+ }
+
+ Status = ArcRead(FileId,
+ (PVOID)SectionBase,
+ SectionHeader->SizeOfRawData,
+ &Count);
+
+ if (Status != ESUCCESS) {
+ break;
+ }
+
+ //
+ // Set the offset of the next section
+ //
+ SectionOffset += SectionHeader->SizeOfRawData;
+
+ //
+ // If the section is uninitialized data, then zero the specifed memory.
+ //
+
+ } else if ((SectionHeader->Characteristics & (STYP_BSS | STYP_SBSS)) != 0) {
+
+ RtlZeroMemory((PVOID)(SectionBase), SectionHeader->SizeOfRawData);
+
+ //
+ // Set the offset of the next section
+ //
+
+ SectionOffset += SectionHeader->SizeOfRawData;
+
+ }
+
+ SectionHeader += 1;
+ }
+
+ //
+ // If code has to be relocated do so.
+ //
+ if ((FileHeader->Characteristics & IMAGE_FILE_RELOCS_STRIPPED) == 0) {
+ Status=FwRelocateImage(FileId,RelocationTable);
+
+ //
+ // Flush the data cache.
+ //
+
+ HalSweepDcache();
+ }
+ //
+ // Close file and return completion status.
+ //
+ ArcClose(FileId);
+ if (Status == ESUCCESS) {
+
+ //
+ // Flush the instruction cache.
+ //
+
+ HalSweepIcache();
+
+ }
+ return Status;
+}
+
+ARC_STATUS
+FwRelocateImage (
+ IN ULONG FileId,
+ PSECTION_RELOCATION_ENTRY RelocationTable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine relocates an image file that was not loaded into memory
+ at the prefered address.
+
+Arguments:
+
+ FileId - Supplies the file identifier for the image file.
+
+ RelocationTable - Supplies a pointer to a table of section relocation info.
+
+Return Value:
+
+ ESUCCESS is returned in the scan is successful. Otherwise, return an
+ unsuccessful status.
+
+--*/
+
+{
+
+ PULONG FixupAddress;
+ PUSHORT FixupAddressHi;
+ ULONG FixupValue;
+ ULONG Index,Section;
+ ULONG Count;
+ ULONG NumberOfRelocations;
+ PMIPS_RELOCATION_ENTRY RelocationEntry;
+ UCHAR LocalBuffer[SECTOR_SIZE+64];
+ PUCHAR LocalPointer;
+ ULONG Offset;
+ ARC_STATUS Status;
+ MIPS_EXTERNAL_SYMBOL MipsExternalSymbol;
+ ULONG PointerToSymbolicHeader;
+ ULONG PointerToExternalSymbols;
+ ULONG NumberOfExternalSymbols;
+ LARGE_INTEGER SeekPosition;
+ BOOLEAN MatchedReflo;
+
+ //
+ // Align the buffer on a Dcache line size.
+ //
+
+ LocalPointer = (PVOID) ((ULONG) ((PCHAR) LocalBuffer + KeGetDcacheFillSize() - 1)
+ & ~(KeGetDcacheFillSize() - 1));
+
+ //
+ // Read the File Header To find out where the symbols are.
+ //
+
+ SeekPosition.LowPart = 0;
+ SeekPosition.HighPart = 0;
+
+ if ((Status = ArcSeek(FileId,&SeekPosition,SeekAbsolute)) != ESUCCESS) {
+ return Status;
+ }
+
+ if ((Status = ArcRead(FileId,LocalPointer,SECTOR_SIZE,&Count)) != ESUCCESS) {
+ return Status;
+ }
+
+ PointerToSymbolicHeader = ((PIMAGE_FILE_HEADER)LocalPointer)->PointerToSymbolTable;
+ // SizeOfSymbolicHeader = ((PIMAGE_FILE_HEADER)LocalPointer)->NumberOfSymbols;
+
+ //
+ // Read the symbolic haeder to find out where the external symbols are.
+ //
+
+ SeekPosition.LowPart = PointerToSymbolicHeader;
+
+ if ((Status = ArcSeek(FileId,&SeekPosition ,SeekAbsolute)) != ESUCCESS) {
+ return Status;
+ }
+
+ if ((Status = ArcRead(FileId,LocalPointer,SECTOR_SIZE,&Count)) != ESUCCESS) {
+ return Status;
+ }
+
+ PointerToExternalSymbols = ((PMIPS_SYMBOLIC_HEADER)LocalPointer)->PointerToExternalSymbols;
+ NumberOfExternalSymbols = ((PMIPS_SYMBOLIC_HEADER)LocalPointer)->NumOfExternalSymbols;
+
+
+ //
+ // Read the relocation table for each section.
+ //
+
+ MatchedReflo = FALSE;
+ for (Section=0; Section < R_SN_MAX; Section++) {
+ NumberOfRelocations = RelocationTable[Section].NumberOfRelocations;
+ for (Index = 0; Index < NumberOfRelocations; Index ++) {
+ if ((Index % (SECTOR_SIZE/sizeof(MIPS_RELOCATION_ENTRY))) == 0) {
+ //
+ // read a sector worth of relocation entries.
+ //
+ SeekPosition.LowPart = RelocationTable[Section].PointerToRelocations+Index*sizeof(MIPS_RELOCATION_ENTRY);
+ ArcSeek(FileId,
+ &SeekPosition,
+ SeekAbsolute);
+
+ Status = ArcRead(FileId,
+ LocalPointer,
+ SECTOR_SIZE,
+ &Count);
+ if (Status != ESUCCESS) {
+ return Status;
+ }
+ RelocationEntry = (PMIPS_RELOCATION_ENTRY)LocalPointer;
+ }
+
+ //
+ // Get the address for the fixup.
+ //
+
+ FixupAddress = (PULONG)(RelocationEntry->VirtualAddress +
+ RelocationTable[Section].FixupValue);
+ //
+ // Apply the fixup.
+ //
+
+ if (RelocationEntry->Type.External == 0) {
+
+ //
+ // If the relocation is internal, SymbolIndex
+ // supplies the number of the section containing the symbol.
+ // Compute the Offset for that section.
+ //
+
+ Offset = RelocationTable[RelocationEntry->Type.SymbolIndex].FixupValue;
+ } else {
+
+ // sprintf(Message,"External Relocation at:%lx\r\n",FixupAddress);
+ // VenPrint(Message);
+ //
+ // This is an external reference. Read the symbol table.
+ //
+
+ SeekPosition.LowPart = PointerToExternalSymbols+
+ RelocationEntry->Type.SymbolIndex*sizeof(MIPS_EXTERNAL_SYMBOL);
+ if ((Status =
+ ArcSeek(FileId,
+ &SeekPosition,
+ SeekAbsolute)) != ESUCCESS) {
+ return Status;
+ }
+
+ if ((Status = ArcRead(FileId,
+ &MipsExternalSymbol,
+ sizeof(MIPS_EXTERNAL_SYMBOL),
+ &Count)) != ESUCCESS) {
+ return Status;
+ }
+
+ //
+ // Check that the value of the symbol is an address.
+ //
+
+ Offset = MipsExternalSymbol.Symbol.Value;
+
+ if ((MipsExternalSymbol.Symbol.StorageClass == ESSC_TEXT) ||
+ (MipsExternalSymbol.Symbol.StorageClass == ESSC_DATA)) {
+ Offset+= RelocationTable[Section].FixupValue;
+ } else {
+ return EBADF;
+ }
+ }
+
+ switch (RelocationEntry->Type.Type) {
+
+ //
+ // Absolute - no fixup required.
+ //
+
+ case IMAGE_REL_MIPS_ABSOLUTE:
+ break;
+
+ //
+ // Word - (32-bits) relocate the entire address.
+ //
+
+ case IMAGE_REL_MIPS_REFWORD:
+
+ *FixupAddress += (ULONG)Offset;
+ break;
+
+ //
+ // Adjust high - (16-bits) relocate the high half of an
+ // address and adjust for sign extension of low half.
+ //
+
+ case IMAGE_REL_MIPS_JMPADDR:
+
+ FixupValue = ((*FixupAddress)&0x03fffff) + (Offset >> 2);
+ *FixupAddress = (*FixupAddress & 0xfc000000) | (FixupValue & 0x03fffff);
+ break;
+
+ case IMAGE_REL_MIPS_REFHI:
+
+ //
+ // Save the address and go to get REF_LO paired with this one
+ //
+
+ FixupAddressHi = (PSHORT)FixupAddress;
+ MatchedReflo = TRUE;
+ break;
+
+ //
+ // Low - (16-bit) relocate high part too.
+ //
+
+ case IMAGE_REL_MIPS_REFLO:
+
+ if (MatchedReflo) {
+ FixupValue = (ULONG)(LONG)((*FixupAddressHi) << 16) +
+ *(PSHORT)FixupAddress +
+ Offset;
+
+ //
+ // Fix the High part
+ //
+
+ *FixupAddressHi = (SHORT)((FixupValue + 0x8000) >> 16);
+ MatchedReflo = FALSE;
+ } else {
+ FixupValue = *(PSHORT)FixupAddress + Offset;
+ }
+
+ //
+ // Fix the lower part.
+ //
+
+ *(PUSHORT)FixupAddress = (USHORT)(FixupValue & 0xffff);
+ break;
+
+ //
+ // Illegal - illegal relocation type.
+ //
+
+ default :
+ VenPrint(FW_UNKNOWN_RELOC_TYPE_MSG);
+ return EBADF;
+
+ }
+ RelocationEntry++;
+ }
+ }
+ return ESUCCESS;
+}
+//
+//ARC_STATUS
+//FwInvoke(
+// IN ULONG ExecAddr,
+// IN ULONG StackAddr,
+// IN ULONG Argc,
+// IN PCHAR Argv[],
+// IN PCHAR Envp[]
+// )
+//
+///*++
+//
+//Routine Description:
+//
+// This routine invokes a loaded program.
+//
+//Arguments:
+//
+// ExecAddr - Supplies the address of the routine to call.
+//
+// StackAddr - Supplies the address to which the stack pointer is set.
+//
+// Argc, Argv, Envp - Supply the arguments and endvironment to pass to
+// Loaded program.
+//
+//
+//Return Value:
+//
+// ESUCCESS is returned if the address is valid.
+// EFAULT indicates an invalid addres.
+//
+//--*/
+//
+//{
+// //
+// // Check for aligned address.
+// //
+// if ((ExecAddr & 0x3) == 0) {
+// ((PTRANSFER_ROUTINE)ExecAddr)(Argc, Argv, Envp);
+// return ESUCCESS;
+// } else {
+// return EFAULT;
+// }
+//}
+
+
+VOID
+FwCopyArguments(
+ IN ULONG Argc,
+ IN PCHAR Argv[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies the supplied arguments into the Fw
+ space.
+
+Arguments:
+
+ Argc, Argv, - Supply the arguments to be copied.
+
+
+Return Value:
+
+ ESUCCESS is returned if the arguments were successfully copied.
+ EFAULT if there is not enough room for them.
+
+--*/
+
+{
+ PUCHAR Source,Destination;
+ ULONG Arg;
+
+ PSavedArgs->Argc = Argc;
+ Destination = &PSavedArgs->Arguments[0];
+ for (Arg = 0; Arg < Argc; Arg++) {
+ Source = Argv[Arg];
+ PSavedArgs->Argv[Arg] = Destination;
+ while(*Destination++ = *Source++) {
+ }
+ }
+}
+
+
+ARC_STATUS
+FwPrivateExecute(
+ IN PCHAR Path,
+ IN ULONG Argc,
+ IN PCHAR Argv[],
+ IN PCHAR Envp[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine loads and invokes a program.
+ FwExecute sets the right stack pointer and calls this routine which
+ does all the work. When this routine returns (after the loaded
+ program has been executed) the stack is restored to the Fw stack
+ and control is returned to the firmware.
+ Therefore a loaded program that executes another program does not
+ get control back once the executed program is finished.
+
+Arguments:
+
+ Path - Supplies a pointer to the path of the file to load.
+
+ Argc, Argv, Envp - Supply the arguments and endvironment to pass to
+ Loaded program.
+
+
+Return Value:
+
+ ESUCCESS is returned if the address is valid.
+ EFAULT indicates an invalid addres.
+
+--*/
+
+{
+
+ PULONG TransferRoutine;
+ ULONG BottomAddress;
+ ARC_STATUS Status;
+ PMEMORY_DESCRIPTOR MemoryDescriptor;
+ PFW_MEMORY_DESCRIPTOR FwMemoryDescriptor;
+ CHAR TempPath[256];
+
+ //
+ // Copy the Arguments to a safe place as they can be in the
+ // running program space which can be overwritten by the program
+ // about to be loaded.
+ //
+ FwCopyArguments(Argc,Argv);
+ strcpy(TempPath, Path);
+
+ //
+ // Reinitialize the memory descriptors
+ //
+ FwResetMemory();
+
+ //
+ // Look for a piece of free memory.
+ //
+ MemoryDescriptor = ArcGetMemoryDescriptor(NULL);
+ while (MemoryDescriptor != NULL){
+
+ //
+ // If the memory is at least 4 megabytes and is free attempt to
+ // load the program.
+ //
+
+ if ((MemoryDescriptor->MemoryType == MemoryFree) &&
+ (MemoryDescriptor->PageCount >= 1024)) {
+
+ //
+ // Set the top address to the top of the descriptor.
+ //
+
+ Status = FwLoad(TempPath,
+ ((MemoryDescriptor->BasePage +
+ MemoryDescriptor->PageCount) << PAGE_SHIFT) | KSEG0_BASE,
+ (PULONG)&TransferRoutine,
+ &BottomAddress);
+
+ if (Status == ESUCCESS) {
+
+ //
+ // Find the actual area of memory that was used, and generate a
+ // descriptor for it.
+ //
+
+ MemoryDescriptor = ArcGetMemoryDescriptor(NULL);
+ while (MemoryDescriptor != NULL){
+ if ((MemoryDescriptor->MemoryType == MemoryFree) &&
+ (FwActualBasePage >= MemoryDescriptor->BasePage) &&
+ ((FwActualBasePage + FwPageCount) <=
+ (MemoryDescriptor->BasePage + MemoryDescriptor->PageCount))) {
+ break;
+ }
+
+ MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor);
+ }
+
+ if (MemoryDescriptor != NULL) {
+ FwMemoryDescriptor = CONTAINING_RECORD(MemoryDescriptor,
+ FW_MEMORY_DESCRIPTOR,
+ MemoryEntry);
+
+ FwGenerateDescriptor(FwMemoryDescriptor,
+ MemoryLoadedProgram,
+ FwActualBasePage,
+ FwPageCount);
+ }
+
+#ifdef DUO
+ //
+ // Set the boot task to be run by processor B and
+ // wake him up.
+ //
+ {
+ PPROCESSOR_B_TASK_VECTOR TaskVector;
+ if (FirstLoadedProgram) {
+ FirstLoadedProgram = FALSE;
+ TaskVector = (PPROCESSOR_B_TASK_VECTOR)&ProcessorBTask;
+ TaskVector->Routine = (PPROCESSOR_TASK_ROUTINE)FwpRestart;
+ TaskVector->Data = 0;
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
+ }
+
+ }
+#endif
+
+ if (BreakAfterLoad == TRUE) {
+ DbgBreakPoint();
+ }
+
+ Status = FwInvoke((ULONG)TransferRoutine,
+ BottomAddress,
+ PSavedArgs->Argc,
+ PSavedArgs->Argv,
+ Envp
+ );
+#ifdef DUO
+ //
+ // The Invoked program returned or it could not be loaded.
+ // Issue another IP interrupt to processor B to notify him to
+ // give up the boot process.
+ // Wait for an IP interrupt from B which indicates processor B
+ // is back into it's main loop.
+ //
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
+ WaitForIpInterrupt(500);
+#endif
+ return Status;
+
+ }
+
+ if (Status != ENOMEM) {
+ return Status;
+ }
+ }
+ MemoryDescriptor = ArcGetMemoryDescriptor(MemoryDescriptor);
+ }
+ return ENOMEM;
+}
+
+VOID
+FwLoadInitialize(
+ IN VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the firmware load services.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ (PARC_LOAD_ROUTINE)SYSTEM_BLOCK->FirmwareVector[LoadRoutine] = FwLoad;
+ (PARC_INVOKE_ROUTINE)SYSTEM_BLOCK->FirmwareVector[InvokeRoutine] = FwInvoke;
+ (PARC_EXECUTE_ROUTINE)SYSTEM_BLOCK->FirmwareVector[ExecuteRoutine] = FwExecute;
+ FwTemporaryStack = (ULONG) FwAllocatePool(0x3000) + 0x2FD0;
+ PSavedArgs = (PSAVED_ARGUMENTS) FwAllocatePool(sizeof(SAVED_ARGUMENTS));
+}
diff --git a/private/ntos/fw/mips/fwp.h b/private/ntos/fw/mips/fwp.h
new file mode 100644
index 000000000..2c4eb9387
--- /dev/null
+++ b/private/ntos/fw/mips/fwp.h
@@ -0,0 +1,659 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ fwp.h
+
+Abstract:
+
+ This module contains extensions to the firmware.h header file.
+
+Author:
+
+ David M. Robinson (davidro) 29-Aug-1991
+
+Revision History:
+
+--*/
+
+#ifndef _FWP_
+#define _FWP_
+
+#include "bldr.h"
+#include "firmware.h"
+#include "kbdmouse.h"
+#ifndef DUO
+#include "jazzdef.h"
+#include "jazzprom.h"
+#include "jazzdma.h"
+#else
+#include "duodef.h"
+#include "duoprom.h"
+#include "duodma.h"
+#endif
+
+
+//
+// TEMPTEMP Temporary defines.
+//
+
+#define SECONDARY_CACHE_SIZE (1 << 20)
+#define SECONDARY_CACHE_INVALID 0x0
+#define SECONDARY_CACHE_DIRTY_EXCLUSIVE 0x5
+#define TAGLO_SSTATE 0xA
+
+//
+// Current version and revision numbers.
+//
+
+#define ARC_VERSION 1
+#define ARC_REVISION 2
+
+
+//
+// Define the firmware vendor specific entry point numbers.
+//
+
+typedef enum _VENDOR_ENTRY {
+ AllocatePoolRoutine,
+ StallExecutionRoutine,
+ PrintRoutine,
+ SetDisplayAttributesRoutine,
+ OutputCharacterRoutine,
+ ScrollVideoRoutine,
+ BootRestartRoutine,
+ MaximumVendorRoutine
+ } VENDOR_ENTRY;
+
+//
+// Define vendor specific routine types.
+//
+
+typedef
+PVOID
+(*PVEN_ALLOCATE_POOL_ROUTINE) (
+ IN ULONG NumberOfBytes
+ );
+
+typedef
+VOID
+(*PVEN_STALL_EXECUTION_ROUTINE) (
+ IN ULONG Microseconds
+ );
+
+typedef
+ULONG
+(*PVEN_PRINT_ROUTINE) (
+ IN PCHAR Format,
+ ...
+ );
+
+typedef
+VOID
+(*PVEN_SET_DISPLAY_ATTRIBUTES_ROUTINE) (
+ IN ULONG ForegroundColor,
+ IN ULONG BackgroundColor,
+ IN BOOLEAN HighIntensity,
+ IN BOOLEAN Underscored,
+ IN BOOLEAN ReverseVideo,
+ IN ULONG CharacterWidth,
+ IN ULONG CharacterHeight
+ );
+
+typedef
+VOID
+(*PVEN_OUTPUT_CHARACTER_ROUTINE) (
+ IN PVOID Character,
+ IN ULONG Row,
+ IN ULONG Column
+ );
+
+typedef
+VOID
+(*PVEN_SCROLL_VIDEO_ROUTINE) (
+ VOID
+ );
+
+typedef
+VOID
+(*PVEN_BOOT_RESTART_ROUTINE) (
+ IN PRESTART_BLOCK RestartBlock
+ );
+
+//
+// Define vendor specific prototypes.
+//
+
+PVOID
+FwAllocatePool (
+ IN ULONG NumberOfBytes
+ );
+
+VOID
+FwStallExecution (
+ IN ULONG Microseconds
+ );
+
+ULONG
+FwPrint (
+ IN PCHAR Format,
+ ...
+ );
+
+VOID
+FwSetDisplayAttributes (
+ IN ULONG ForegroundColor,
+ IN ULONG BackgroundColor,
+ IN BOOLEAN HighIntensity,
+ IN BOOLEAN Underscored,
+ IN BOOLEAN ReverseVideo,
+ IN ULONG CharacterWidth,
+ IN ULONG CharacterHeight
+ );
+
+VOID
+FwOutputCharacter (
+ IN PVOID Character,
+ IN ULONG Row,
+ IN ULONG Column
+ );
+
+VOID
+FwScrollVideo (
+ VOID
+ );
+
+//
+// Define vendor specific functions.
+//
+#define VenRestartBlock(RestartBlock) \
+ ((PVEN_BOOT_RESTART_ROUTINE)(SYSTEM_BLOCK->VendorVector[BootRestartRoutine])) \
+ ((RestartBlock))
+
+#define VenAllocatePool(NumberOfBytes) \
+ ((PVEN_ALLOCATE_MEMORY_ROUTINE)(SYSTEM_BLOCK->VendorVector[AllocatePoolRoutine])) \
+ ((NumberOfBytes))
+
+#define VenStallExecution(Microseconds) \
+ ((PVEN_STALL_EXECUTION_ROUTINE)(SYSTEM_BLOCK->VendorVector[StallExecutionRoutine])) \
+ ((Microseconds))
+
+#define VenPrint(x) \
+ ((PVEN_PRINT_ROUTINE)(SYSTEM_BLOCK->VendorVector[PrintRoutine])) \
+ ((x))
+
+#define VenPrint1(x,y) \
+ ((PVEN_PRINT_ROUTINE)(SYSTEM_BLOCK->VendorVector[PrintRoutine])) \
+ ((x), (y))
+
+#define VenPrint2(x,y,z) \
+ ((PVEN_PRINT_ROUTINE)(SYSTEM_BLOCK->VendorVector[PrintRoutine])) \
+ ((x), (y), (z))
+
+#define VenSetDisplayAttributes(ForegroundColor, BackgroundColor, HighIntensity, Underscored, ReverseVideo, CharacterWidth, CharacterHeight) \
+ ((PVEN_SET_DISPLAY_ATTRIBUTES_ROUTINE)(SYSTEM_BLOCK->VendorVector[SetDisplayAttributesRoutine])) \
+ ((ForegroundColor), (BackgroundColor), (HighIntensity), \
+ (Underscored), (ReverseVideo), (CharacterWidth), (CharacterHeight))
+
+#define VenOutputCharacter(Character, Row, Column) \
+ ((PVEN_OUTPUT_CHARACTER_ROUTINE)(SYSTEM_BLOCK->VendorVector[OutputCharacterRoutine])) \
+ ((Character), (Row), (Column))
+
+#define VenScrollVideo() \
+ ((PVEN_SCROLL_VIDEO_ROUTINE)(SYSTEM_BLOCK->VendorVector[ScrollVideoRoutine])) ()
+
+
+//
+// Define the Lookup table. At initialization, the driver must fill this table
+// with the device pathnames it can handle.
+//
+
+typedef struct _DRIVER_LOOKUP_ENTRY {
+ PCHAR DevicePath;
+ PBL_DEVICE_ENTRY_TABLE DispatchTable;
+} DRIVER_LOOKUP_ENTRY, *PDRIVER_LOOKUP_ENTRY;
+
+#define SIZE_OF_LOOKUP_TABLE BL_FILE_TABLE_SIZE
+
+extern DRIVER_LOOKUP_ENTRY DeviceLookupTable[SIZE_OF_LOOKUP_TABLE];
+
+//
+// Define the Device Pathname. This table is indexed with the FileId.
+// FwOpen tries to match the OpenPath with the entries in this table, and
+// if it finds a match it increments the reference counter. If it doesn't
+// find a match it tries to match an entry in the DRIVER_LOOKUP_TABLE
+// and then calls the Open routine of that driver.
+//
+
+#define SIZE_OF_ARC_DEVICENAME 64
+
+typedef struct _OPENED_PATHNAME_ENTRY {
+ ULONG ReferenceCounter;
+ CHAR DeviceName[SIZE_OF_ARC_DEVICENAME];
+} OPENED_PATHNAME_ENTRY, *POPENED_PATHNAME_ENTRY;
+
+#define SIZE_OF_OPENED_PATHNAME_TABLE BL_FILE_TABLE_SIZE
+
+extern OPENED_PATHNAME_ENTRY OpenedPathTable[SIZE_OF_OPENED_PATHNAME_TABLE];
+
+//
+// Driver initialization routines.
+//
+
+VOID
+FwInitializeMemory(
+ IN VOID
+ );
+
+VOID
+FwResetMemory(
+ IN VOID
+ );
+
+VOID
+DisplayInitialize(
+ IN OUT PDRIVER_LOOKUP_ENTRY LookupTableEntry,
+ IN ULONG Entries
+ );
+
+VOID
+KeyboardInitialize(
+ IN OUT PDRIVER_LOOKUP_ENTRY LookupTableEntry,
+ IN ULONG Entries
+ );
+
+VOID
+SerialInitialize(
+ IN OUT PDRIVER_LOOKUP_ENTRY LookupTableEntry,
+ IN ULONG Entries
+ );
+
+VOID
+HardDiskInitialize(
+ IN OUT PDRIVER_LOOKUP_ENTRY LookupTable,
+ IN ULONG Entries
+ );
+
+VOID
+FloppyInitialize(
+ IN OUT PDRIVER_LOOKUP_ENTRY LookupTableEntry,
+ IN ULONG Entries
+ );
+
+
+
+//
+// Define the private configuration packet structure, which contains a
+// configuration component as well as pointers to the component's parent,
+// peer, child, and configuration data.
+//
+
+typedef struct _CONFIGURATION_PACKET {
+ CONFIGURATION_COMPONENT Component;
+ struct _CONFIGURATION_PACKET *Parent;
+ struct _CONFIGURATION_PACKET *Peer;
+ struct _CONFIGURATION_PACKET *Child;
+ PVOID ConfigurationData;
+} CONFIGURATION_PACKET, *PCONFIGURATION_PACKET;
+
+//
+// The compressed configuration packet structure used to store configuration
+// data in NVRAM.
+//
+
+typedef struct _COMPRESSED_CONFIGURATION_PACKET {
+ UCHAR Parent;
+ UCHAR Class;
+ UCHAR Type;
+ UCHAR Flags;
+ ULONG Key;
+ UCHAR Version;
+ UCHAR Revision;
+ USHORT ConfigurationDataLength;
+ USHORT Identifier;
+ USHORT ConfigurationData;
+} COMPRESSED_CONFIGURATION_PACKET, *PCOMPRESSED_CONFIGURATION_PACKET;
+
+//
+// Defines for Identifier index.
+//
+
+#define NO_CONFIGURATION_IDENTIFIER 0xFFFF
+
+//
+// Defines for the volatile and non-volatile configuration tables.
+//
+
+#define NUMBER_OF_ENTRIES 40
+#define LENGTH_OF_IDENTIFIER (1024 - (40*16) - 8)
+#define LENGTH_OF_DATA 2048
+#define LENGTH_OF_ENVIRONMENT 1024
+#define LENGTH_OF_EISA_DATA 2044
+
+#define MAXIMUM_ENVIRONMENT_VALUE 256
+
+//
+// The volatile configuration table structure.
+//
+
+typedef struct _CONFIGURATION {
+ CONFIGURATION_PACKET Packet[NUMBER_OF_ENTRIES];
+ UCHAR Identifier[LENGTH_OF_IDENTIFIER];
+ UCHAR Data[LENGTH_OF_DATA];
+ UCHAR EisaData[LENGTH_OF_EISA_DATA];
+} CONFIGURATION, *PCONFIGURATION;
+
+//
+// The non-volatile configuration table structure.
+//
+
+typedef struct _NV_CONFIGURATION {
+
+ //
+ // First Page
+ //
+
+ COMPRESSED_CONFIGURATION_PACKET Packet[NUMBER_OF_ENTRIES];
+ UCHAR Identifier[LENGTH_OF_IDENTIFIER];
+ UCHAR Data[LENGTH_OF_DATA];
+ UCHAR Checksum1[4];
+ UCHAR Environment[LENGTH_OF_ENVIRONMENT];
+ UCHAR Checksum2[4];
+
+ //
+ // Second Page
+ //
+
+ UCHAR EisaData[LENGTH_OF_EISA_DATA];
+ UCHAR Checksum3[4];
+
+} NV_CONFIGURATION, *PNV_CONFIGURATION;
+
+//
+// Define identifier index, data index, pointer to configuration table.
+//
+
+extern ULONG IdentifierIndex;
+extern ULONG DataIndex;
+extern ULONG EisaDataIndex;
+extern PCONFIGURATION Configuration;
+
+//
+// Non-volatile ram layout.
+//
+
+#define NVRAM_CONFIGURATION NVRAM_VIRTUAL_BASE
+#define NVRAM_SYSTEM_ID (NVRAM_VIRTUAL_BASE + 0x00002000)
+
+//
+// Memory size. The MctadrRev2 is used to interpret the memory size value
+// in the configuration register.
+//
+
+extern ULONG MemorySize;
+#define MEMORY_SIZE (MemorySize << 20)
+extern BOOLEAN MctadrRev2;
+
+//
+// Memory layout.
+//
+
+#define FW_POOL_BASE 0x807ed000
+#define FW_POOL_SIZE 0xf000
+
+//
+// Define special character values. TEMPTEMP These should go somewhere else.
+//
+
+#define ASCII_NUL 0x00
+#define ASCII_BEL 0x07
+#define ASCII_BS 0x08
+#define ASCII_HT 0x09
+#define ASCII_LF 0x0A
+#define ASCII_VT 0x0B
+#define ASCII_FF 0x0C
+#define ASCII_CR 0x0D
+#define ASCII_CSI 0x9B
+#define ASCII_ESC 0x1B
+#define ASCII_SYSRQ 0x80
+
+//
+// Define screen colors.
+//
+
+typedef enum _ARC_SCREEN_COLOR {
+ ArcColorBlack,
+ ArcColorRed,
+ ArcColorGreen,
+ ArcColorYellow,
+ ArcColorBlue,
+ ArcColorMagenta,
+ ArcColorCyan,
+ ArcColorWhite,
+ MaximumArcColor
+ } ARC_SCREEN_COLOR;
+
+//
+// Define video board types for Jazz.
+//
+
+typedef enum _JAZZ_VIDEO_TYPE {
+ JazzVideoG300,
+ JazzVideoG364,
+ JazzVideoVxl,
+ Reserved3,
+ Reserved4,
+ Reserved5,
+ Reserved6,
+ Reserved7,
+ Reserved8,
+ Reserved9,
+ ReservedA,
+ ReservedB,
+ ReservedC,
+ ReservedD,
+ ReservedE,
+ ReservedF,
+ MipsVideoG364,
+ MaximumJazzVideo
+ } JAZZ_VIDEO_TYPE, *PJAZZ_VIDEO_TYPE;
+
+
+
+//
+// Define firmware routine prototypes.
+//
+
+VOID
+FwIoInitialize1 (
+ VOID
+ );
+
+VOID
+FwIoInitialize2 (
+ VOID
+ );
+
+BOOLEAN
+FwGetPathMnemonicKey(
+ IN PCHAR OpenPath,
+ IN PCHAR Mnemonic,
+ OUT PULONG Key
+ );
+
+PCHAR
+FwEnvironmentLoad(
+ VOID
+ );
+
+VOID
+FwPrintVersion (
+ VOID
+ );
+
+ARC_STATUS
+DisplayBootInitialize(
+ VOID
+ );
+
+ARC_STATUS
+FwGetVideoData (
+ OUT PMONITOR_CONFIGURATION_DATA MonitorData
+ );
+
+VOID
+FwSetVideoData (
+ IN PMONITOR_CONFIGURATION_DATA MonitorData
+ );
+
+VOID
+FwTerminationInitialize(
+ IN VOID
+ );
+
+VOID
+FwHalt(
+ IN VOID
+ );
+
+VOID
+FwMonitor(
+ IN ULONG
+ );
+
+VOID
+FwExceptionInitialize(
+ IN VOID
+ );
+
+VOID
+ResetSystem (
+ IN VOID
+ );
+
+
+VOID
+FwpFreeStub(
+ IN PVOID Buffer
+ );
+
+typedef enum _GETSTRING_ACTION {
+ GetStringSuccess,
+ GetStringEscape,
+ GetStringUpArrow,
+ GetStringDownArrow,
+ GetStringMaximum
+} GETSTRING_ACTION, *PGETSTRING_ACTION;
+
+GETSTRING_ACTION
+FwGetString(
+ OUT PCHAR String,
+ IN ULONG StringLength,
+ IN PCHAR InitialString OPTIONAL,
+ IN ULONG CurrentRow,
+ IN ULONG CurrentColumn
+ );
+
+ARC_STATUS
+FwConfigurationCheckChecksum (
+ VOID
+ );
+
+ARC_STATUS
+FwEnvironmentCheckChecksum (
+ VOID
+ );
+
+VOID
+FwpReservedRoutine(
+ VOID
+ );
+
+VOID
+FwWaitForKeypress(
+ VOID
+ );
+
+VOID
+JzShowTime (
+ BOOLEAN First
+ );
+
+VOID
+JxBmp (
+ VOID
+ );
+
+LONG
+JxDisplayMenu (
+ IN PCHAR Choices[],
+ IN ULONG NumberOfChoices,
+ IN LONG DefaultChoice,
+ IN ULONG CurrentLine
+ );
+
+BOOLEAN
+FwGetVariableSegment (
+ IN ULONG SegmentNumber,
+ IN OUT PCHAR Segment
+ );
+
+ARC_STATUS
+FwSetVariableSegment (
+ IN ULONG SegmentNumber,
+ IN PCHAR VariableName,
+ IN OUT PCHAR Segment
+ );
+
+ARC_STATUS
+JzAddProcessor (
+ IN ULONG ProcessorNumber
+ );
+
+//
+// Print macros.
+//
+
+extern BOOLEAN DisplayOutput;
+extern BOOLEAN SerialOutput;
+extern BOOLEAN FwConsoleInitialized;
+extern BOOLEAN SetupIsRunning;
+
+ULONG
+FwPrint (
+ PCHAR Format,
+ ...
+ );
+
+#define FwClearScreen() \
+ FwPrint("%c2J", ASCII_CSI)
+
+#define FwSetScreenColor(FgColor, BgColor) \
+ FwPrint("%c3%dm", ASCII_CSI, (UCHAR)FgColor); \
+ FwPrint("%c4%dm", ASCII_CSI, (UCHAR)BgColor)
+
+#define FwSetScreenAttributes( HighIntensity, Underscored, ReverseVideo ) \
+ FwPrint("%c0m", ASCII_CSI); \
+ if (HighIntensity) { \
+ FwPrint("%c1m", ASCII_CSI); \
+ } \
+ if (Underscored) { \
+ FwPrint("%c4m", ASCII_CSI); \
+ } \
+ if (ReverseVideo) { \
+ FwPrint("%c7m", ASCII_CSI); \
+ }
+
+#define FwSetPosition( Row, Column ) \
+ FwPrint("%c%d;%dH", ASCII_CSI, (Row + 1), (Column + 1))
+
+#define FwMoveCursorLeft(Spaces) \
+ FwPrint ("%c%dD", ASCII_CSI, Spaces)
+
+#define FwMoveCursorToColumn(Spaces) \
+ FwPrint( "\r" ); \
+ if ( Spaces > 1 ) \
+ FwPrint( "%c%dC", ASCII_CSI, Spaces - 1)
+#endif // _FWP_
diff --git a/private/ntos/fw/mips/fwprint.c b/private/ntos/fw/mips/fwprint.c
new file mode 100644
index 000000000..2307152e5
--- /dev/null
+++ b/private/ntos/fw/mips/fwprint.c
@@ -0,0 +1,84 @@
+// TITLE("Debug Support Functions")
+//++
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// fwprint.c
+//
+// Abstract:
+//
+// This module implements functions to support debugging NT.
+//
+// Author:
+//
+// Steven R. Wood (stevewo) 3-Aug-1989
+//
+// Environment:
+//
+// Any mode.
+//
+// Revision History:
+//
+//--
+
+#include "fwp.h"
+#include <stdarg.h>
+#include "string.h"
+
+//
+// Define variable argument list parameters.
+//
+
+BOOLEAN DisplayOutput;
+BOOLEAN SerialOutput;
+BOOLEAN FwConsoleInitialized = FALSE;
+
+
+ULONG
+FwPrint (
+ PCHAR Format,
+ ...
+ )
+
+{
+
+ va_list arglist;
+ UCHAR Buffer[256];
+ ULONG Count;
+ ULONG Index;
+ ULONG Length;
+
+ //
+ // Format the output into a buffer and then print it.
+ //
+
+ va_start(arglist, Format);
+ Length = vsprintf(Buffer, Format, arglist);
+
+ if (FwConsoleInitialized) {
+
+ FwWrite( ARC_CONSOLE_OUTPUT, Buffer, Length, &Count);
+
+ } else {
+
+ if (SerialOutput) {
+ for ( Index = 0 ; Index < Length ; Index++ ) {
+ if (Buffer[Index] == ASCII_CSI) {
+ SerialBootWrite(ASCII_ESC, COMPORT2_VIRTUAL_BASE);
+ SerialBootWrite('[', COMPORT2_VIRTUAL_BASE);
+ } else {
+ SerialBootWrite(Buffer[Index],COMPORT2_VIRTUAL_BASE);
+ }
+ }
+ }
+
+ if (DisplayOutput) {
+ DisplayWrite( ARC_CONSOLE_OUTPUT, Buffer, Length, &Count);
+ }
+ }
+
+ va_end(arglist);
+ return 0;
+}
diff --git a/private/ntos/fw/mips/fwsignal.c b/private/ntos/fw/mips/fwsignal.c
new file mode 100644
index 000000000..e46107212
--- /dev/null
+++ b/private/ntos/fw/mips/fwsignal.c
@@ -0,0 +1,617 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ fwsignal.c
+
+Abstract:
+
+ This module implements the ARC firmware Signal Handling Functions.
+
+Author:
+
+ Lluis Abello (lluis) 24-Sep-1991
+
+--*/
+
+#include "fwp.h"
+#include "iodevice.h"
+#ifdef DUO
+#include "duoint.h"
+#else
+#include "jazzint.h"
+#endif
+
+//
+// Define Signal types
+//
+
+typedef
+VOID
+(*SIGNALHANDLER)(
+ IN LONG
+ );
+
+#define SIGINT (0)
+#define SIGDefault (SIGNALHANDLER)(0)
+#define SIGIgnore (SIGNALHANDLER)(1)
+
+typedef
+SIGNALHANDLER
+(*PARC_SIGNAL_ROUTINE) (
+ IN LONG Sig,
+ IN SIGNALHANDLER Handler
+ );
+
+typedef struct _R4000_CAUSE_REGISTER {
+ ULONG Zero1:2;
+ ULONG ExcCode:5;
+ ULONG Zero2:1;
+ ULONG IP:8;
+ ULONG Zero3:12;
+ ULONG CE:2;
+ ULONG Zero4:1;
+ ULONG BD:1;
+} R4000_CAUSE_REGISTER, *PR4000_CAUSE_REGISTER;
+
+VOID
+SIGINTIgnore(
+ IN LONG Sig
+ );
+
+extern KEYBOARD_BUFFER KbdBuffer;
+extern PVOID MonitorExceptionHandler;
+volatile BOOLEAN DeviceInterruptFlag;
+SIGNALHANDLER SIGINTHandler = (SIGNALHANDLER)SIGINTIgnore;
+
+//
+// Keyboard static variables.
+//
+
+BOOLEAN KbdCtrl = FALSE;
+BOOLEAN Scan0xE0 = FALSE;
+
+// 1111 1 1111122222222 2 2333333333344 4 44444445555 5 5 55
+// Character # 234567890123 4 5678901234567 8 9012345678901 2 34567890123 4 5 67
+PCHAR NormalLookup = "1234567890-=\b\0qwertyuiop[]\n\0asdfghjkl;'`\0\\zxcvbnm,./\0\0\0 ";
+PCHAR ShiftedLookup = "!@#$%^&*()_+\b\0QWERTYUIOP{}\n\0ASDFGHJKL:\"~\0\|ZXCVBNM<>?\0\0\0 ";
+
+extern BOOLEAN FwLeftShift;
+extern BOOLEAN FwRightShift;
+extern BOOLEAN FwControl;
+extern BOOLEAN FwAlt;
+extern BOOLEAN FwCapsLock;
+
+
+VOID
+SIGINTIgnore(
+ IN LONG Sig
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the Signal Ignore. It gets called when
+ a SIGINT signal raises and SIGIgnore was associated.
+
+Arguments:
+
+ ??
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ return;
+}
+
+
+SIGNALHANDLER
+FwSignal(
+ IN LONG Sig,
+ IN SIGNALHANDLER Handler
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the ARC firmware signal routine.
+ It associates the supplied Handler with the Signal.
+
+Arguments:
+
+ Sig - Signal number (Only SIGINT is defined).
+
+ Handler - Handler to call when the signal rises.
+
+Return Value:
+
+ Returns the address of any previous handler routine associated
+ with this signal.
+
+--*/
+
+{
+ SIGNALHANDLER Tmp;
+ Tmp=SIGINTHandler;
+ if (Handler == SIGDefault) {
+ SIGINTHandler = (SIGNALHANDLER)MonitorExceptionHandler;
+ return Tmp;
+ }
+ if (Handler == SIGIgnore) {
+ SIGINTHandler = (SIGNALHANDLER)SIGINTIgnore;
+ return Tmp;
+ }
+ SIGINTHandler = Handler;
+ return Tmp;
+}
+
+
+
+ARC_STATUS
+FwWaitForDeviceInterrupt(
+ USHORT InterruptMask,
+ ULONG Timeout
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to wait for an specific I/O device interrupt.
+ It sets a boolean to FALSE
+ enables the device interrupt in the interrupt enable register
+ Polls the boolean until becomes true.
+ Returns to the caller.
+
+ When the Inerrupt handler detects an interrupt which is not
+ the keyboard interrupt sets the boolean to true and disables all
+ the I/O device interrupts except the keyboard in the interrupt
+ enable register.
+
+ To guarantee that the interrupt received is the expected one
+ the argument InterruptMask must have only one bit set.
+ It's not possible to wait for a keyboard interrupt.
+
+
+Arguments:
+
+ InterruptMask - Mask to enable the device interrupt in the
+ interrupt enable register.
+
+ Timeout - a timeout value in seconds. Note that a timeout of 0 gives an
+ actual timeout of between 0 and 1, a timeout of 1 gives an actual
+ timeout of between 1 and 2, and so on.
+
+Return Value:
+
+ ESUCCESS if the interrupt occurs, EIO if a timeout occurs. It doesn't
+ return until the requested interrupt occurs.
+
+--*/
+
+{
+ ULONG Time1, Time2;
+
+ //
+ // set flag to FALSE
+ //
+
+ DeviceInterruptFlag = FALSE;
+
+ //
+ // Enable requested interrupt plus keyboard interrupt.
+ //
+
+ InterruptMask |= (1 << (KEYBOARD_VECTOR - DEVICE_VECTORS - 1));
+ WRITE_REGISTER_USHORT(&((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Enable,
+ InterruptMask);
+ //
+ // wait until flag becomes TRUE.
+ //
+
+ Time1 = FwGetRelativeTime();
+ while (DeviceInterruptFlag == FALSE) {
+ Time2 = FwGetRelativeTime();
+ if ((Time2 - Time1) > (Timeout + 1)) {
+ return(EIO);
+ }
+ }
+ return ESUCCESS;
+}
+
+
+VOID
+StoreKeyboardChar(
+ IN UCHAR Character
+ )
+/*++
+
+Routine Description:
+
+ This routine stores the given character into the circular
+ buffer if there is enough room. Otherwise the character is lost.
+
+Arguments:
+
+ Character - Supplies the translated scan code to store into the buffer
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Store scan code in buffer if there is room.
+ //
+ if (((KbdBuffer.WriteIndex+1) % KBD_BUFFER_SIZE) != KbdBuffer.ReadIndex) {
+ KbdBuffer.WriteIndex = (KbdBuffer.WriteIndex+1) % KBD_BUFFER_SIZE;
+ KbdBuffer.Buffer[KbdBuffer.WriteIndex] = Character;
+ }
+}
+
+
+VOID
+TranslateScanCode(
+ IN UCHAR Scan
+ )
+
+/*++
+
+Routine Description:
+
+ This routine translates the given keyboard scan code into an
+ ASCII character and puts it in the circular buffer.
+
+Arguments:
+
+ Scan - Supplies the scan code read from the keyboard.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR FwControlCharacter=0;
+ UCHAR FwFunctionCharacter;
+ BOOLEAN MakeCode;
+ UCHAR Char;
+
+ //
+ // Check 0xE0, which introduces a two key sequence.
+ //
+
+ if (Scan == 0xE0) {
+ Scan0xE0 = TRUE;
+ return;
+ }
+ if (Scan0xE0 == TRUE) {
+ //
+ // Check for PrintScrn (used as SysRq, also found in its true Alt
+ // form below).
+ //
+ if (Scan == KEY_PRINT_SCREEN) {
+ StoreKeyboardChar(ASCII_SYSRQ);
+ Scan0xE0 = FALSE;
+ return;
+ }
+ }
+
+ //
+ // Look for scan codes that indicate shift, control, or alt keys. Bit 7
+ // of scan code indicates upward or downward keypress.
+ //
+ MakeCode = !(Scan & 0x80);
+ switch (Scan & 0x7F) {
+
+ case KEY_LEFT_SHIFT:
+ FwLeftShift = MakeCode;
+ return;
+
+ case KEY_RIGHT_SHIFT:
+ FwRightShift = MakeCode;
+ return;
+
+ case KEY_CONTROL:
+ FwControl = MakeCode;
+ return;
+
+ case KEY_ALT:
+ FwAlt = MakeCode;
+ return;
+
+ default:
+ break;
+
+ }
+
+ //
+ // The rest of the keys only do something on make.
+ //
+
+ if (MakeCode) {
+
+ //
+ // Check for control keys.
+ //
+
+ switch (Scan) {
+
+ case KEY_UP_ARROW:
+ FwControlCharacter = 'A';
+ break;
+
+ case KEY_DOWN_ARROW:
+ FwControlCharacter = 'B';
+ break;
+
+ case KEY_RIGHT_ARROW:
+ FwControlCharacter = 'C';
+ break;
+
+ case KEY_LEFT_ARROW:
+ FwControlCharacter = 'D';
+ break;
+
+ case KEY_HOME:
+ FwControlCharacter = 'H';
+ break;
+
+ case KEY_END:
+ FwControlCharacter = 'K';
+ break;
+
+ case KEY_PAGE_UP:
+ FwControlCharacter = '?';
+ break;
+
+ case KEY_PAGE_DOWN:
+ FwControlCharacter = '/';
+ break;
+
+ case KEY_INSERT:
+ FwControlCharacter = '@';
+ break;
+
+ case KEY_DELETE:
+ FwControlCharacter = 'P';
+ break;
+
+ case KEY_SYS_REQUEST:
+ StoreKeyboardChar(ASCII_SYSRQ);
+ return;
+
+ case KEY_ESC:
+ StoreKeyboardChar(ASCII_ESC);
+ return;
+
+ case KEY_CAPS_LOCK:
+ FwCapsLock = !FwCapsLock;
+ return;
+
+ case KEY_F1:
+ FwControlCharacter = 'O';
+ FwFunctionCharacter = 'P';
+ break;
+
+ case KEY_F2:
+ FwControlCharacter = 'O';
+ FwFunctionCharacter = 'Q';
+ break;
+
+ case KEY_F3:
+ FwControlCharacter = 'O';
+ FwFunctionCharacter = 'w';
+ break;
+
+ case KEY_F4:
+ FwControlCharacter = 'O';
+ FwFunctionCharacter = 'x';
+ break;
+
+ case KEY_F5:
+ FwControlCharacter = 'O';
+ FwFunctionCharacter = 't';
+ break;
+
+ case KEY_F6:
+ FwControlCharacter = 'O';
+ FwFunctionCharacter = 'u';
+ break;
+
+ case KEY_F7:
+ FwControlCharacter = 'O';
+ FwFunctionCharacter = 'q';
+ break;
+
+ case KEY_F8:
+ FwControlCharacter = 'O';
+ FwFunctionCharacter = 'r';
+ break;
+
+ case KEY_F9:
+ FwControlCharacter = 'O';
+ FwFunctionCharacter = 'p';
+ break;
+
+ case KEY_F10:
+ FwControlCharacter = 'O';
+ FwFunctionCharacter = 'M';
+ break;
+
+// case KEY_F11:
+// FwControlCharacter = 'O';
+// FwFunctionCharacter = 'A';
+// break;
+//
+// case KEY_F12:
+// FwControlCharacter = 'O';
+// FwFunctionCharacter = 'B';
+// break;
+
+ default:
+ Char = 0;
+
+ //
+ // Check to see if the scan code corresponds to an ASCII
+ // character.
+ //
+
+ if (((Scan >= 16) && (Scan <= 25)) ||
+ ((Scan >= 30) && (Scan <= 38)) ||
+ ((Scan >= 44) && (Scan <= 50))) {
+ if (((FwLeftShift || FwRightShift) && !FwCapsLock) ||
+ (!(FwLeftShift || FwRightShift) && FwCapsLock)) {
+ Char = ShiftedLookup[Scan - 2];
+ } else {
+ Char = NormalLookup[Scan - 2];
+ }
+ } else {
+ if ((Scan > 1) && (Scan < 58)) {
+
+ //
+ // Its ASCII but not alpha, so don't shift on CapsLock.
+ //
+
+ if (FwLeftShift || FwRightShift) {
+ Char = ShiftedLookup[Scan - 2];
+ } else {
+ Char = NormalLookup[Scan - 2];
+ }
+ }
+ }
+
+ //
+ // If a character, store it in buffer.
+ //
+
+ if (Char) {
+ StoreKeyboardChar(Char);
+ return;
+ }
+ break;
+ }
+ if (FwControlCharacter) {
+ StoreKeyboardChar(ASCII_CSI);
+ StoreKeyboardChar(FwControlCharacter);
+ if (FwControlCharacter == 'O') {
+ StoreKeyboardChar(FwFunctionCharacter);
+ }
+ return;
+ }
+ }
+}
+
+
+BOOLEAN
+FwInterruptHandler(
+ IN R4000_CAUSE_REGISTER Cause
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called when an interrupt occurs.
+ Only device interrupts are handled.
+ In a Keyboard interrupt, it reads the scan code and puts it
+ in a buffer. If a Ctrl C sequence is detected it raises SIGINT.
+
+Arguments:
+
+ Cause - R4000 cause register.
+
+Return Value:
+
+ FALSE If the exception could not be handled.
+ TRUE Otherwise.
+
+--*/
+
+{
+
+ UCHAR IntP;
+ UCHAR ScanCode;
+ volatile USHORT TmpShort;
+
+ //
+ // Ignore EISA and TIMER interrupts. TEMPTEMP
+ //
+
+ if (!(Cause.IP & ~((1 << 4) | (1 << 6)))) {
+ return(TRUE);
+ }
+
+ if (Cause.IP != (1 << 3)) { // if not device interrupt
+ return FALSE; // exit
+ }
+ IntP = READ_REGISTER_UCHAR(INTERRUPT_SOURCE);
+
+ //
+ // if the interrupt is not from the keyboard,
+ // set the Boolean to tell that a device interrupt ocurred and
+ // disable all I/O device interrupts except keyboard.
+ //
+ if (IntP != KEYBOARD_DEVICE) {
+ DeviceInterruptFlag = TRUE;
+ WRITE_REGISTER_USHORT(&((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Enable,
+ (1 << (KEYBOARD_VECTOR - DEVICE_VECTORS - 1)));
+
+ //
+ // Read register to synchronize write.
+ //
+ TmpShort = READ_REGISTER_USHORT(&((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Enable);
+ return TRUE;
+ }
+
+ //
+ // Wait 10 microseconds in case we have a slow keyboard controller that posts the interrupt
+ // before the character is ready.
+ //
+
+ FwStallExecution(10);
+
+ //
+ // Handle the keyboard interrupt.
+ //
+ while (READ_REGISTER_UCHAR(&KEYBOARD_READ->Status) & KBD_OBF_MASK == 0) {
+ }
+ ScanCode = READ_REGISTER_UCHAR(&KEYBOARD_READ->Data);
+
+ switch (ScanCode) {
+
+ //
+ // Ctrl Make
+ //
+ case 0x1D: KbdCtrl = TRUE;
+ break;
+ //
+ // Ctrl Break
+ //
+ case 0x9D: KbdCtrl = FALSE;
+ break;
+ //
+ // C
+ //
+ case 0x2E: if (KbdCtrl) {
+ (SIGINTHandler)(SIGINT);
+ }
+ break;
+ }
+
+ //
+ // Translate the scan code.
+ //
+ TranslateScanCode(ScanCode);
+ return TRUE;
+}
diff --git a/private/ntos/fw/mips/fwstring.h b/private/ntos/fw/mips/fwstring.h
new file mode 100644
index 000000000..3285da9af
--- /dev/null
+++ b/private/ntos/fw/mips/fwstring.h
@@ -0,0 +1,131 @@
+
+//
+// Common strings.
+//
+
+extern PCHAR FW_OK_MSG;
+extern PCHAR FW_CRLF_MSG;
+extern PCHAR FW_ERROR1_MSG;
+extern PCHAR FW_ERROR2_MSG;
+
+//
+// Firmware strings.
+//
+
+extern PCHAR FW_NOT_ENOUGH_ENTRIES_MSG;
+extern PCHAR FW_FILESYSTEM_NOT_REQ_MSG;
+extern PCHAR FW_UNKNOWN_SECTION_TYPE_MSG;
+extern PCHAR FW_UNKNOWN_RELOC_TYPE_MSG;
+extern PCHAR FW_START_MSG;
+extern PCHAR FW_RUN_A_PROGRAM_MSG;
+extern PCHAR FW_RUN_SETUP_MSG;
+extern PCHAR FW_ACTIONS_MSG;
+extern PCHAR FW_USE_ARROW_MSG;
+extern PCHAR FW_USE_ENTER_MSG;
+extern PCHAR FW_AUTOBOOT_MSG;
+extern PCHAR FW_BREAKPOINT_MSG;
+extern PCHAR FW_OFF_MSG;
+extern PCHAR FW_ON_MSG;
+extern PCHAR FW_DEBUGGER_CONNECTED_MSG;
+extern PCHAR FW_PROGRAM_TO_RUN_MSG;
+extern PCHAR FW_PATHNAME_NOT_DEF_MSG;
+extern PCHAR FW_PRESS_ANY_KEY_MSG;
+extern PCHAR FW_ERROR_CODE_MSG;
+extern PCHAR FW_PRESS_ANY_KEY2_MSG;
+extern PCHAR FW_INITIALIZING_MSG;
+extern PCHAR FW_CONSOLE_IN_ERROR_MSG;
+extern PCHAR FW_CONSOLE_IN_ERROR2_MSG;
+extern PCHAR FW_CONSOLE_OUT_ERROR_MSG;
+extern PCHAR FW_CONSOLE_OUT_ERROR2_MSG;
+extern PCHAR FW_SPIN_DISKS_MSG;
+extern PCHAR FW_SYSTEM_HALT_MSG;
+
+extern PCHAR FW_NVRAM_MSG[];
+#define FW_NVRAM_MSG_SIZE 4
+
+extern PCHAR FW_VIDEO_MSG[];
+#define FW_VIDEO_MSG_SIZE 8
+
+extern PCHAR FW_ERROR_MSG[];
+
+//
+// Monitor Strings.
+//
+
+extern PCHAR MON_INVALID_ARGUMENT_COUNT_MSG;
+extern PCHAR MON_UNALIGNED_ADDRESS_MSG;
+extern PCHAR MON_INVALID_VALUE_MSG;
+extern PCHAR MON_INVALID_REGISTER_MSG;
+extern PCHAR MON_NOT_VALID_ADDRESS_MSG;
+extern PCHAR MON_INVALID_ADDRESS_RANGE_MSG;
+extern PCHAR MON_FORMAT1_MSG;
+extern PCHAR MON_JAZZ_MONITOR_MSG;
+extern PCHAR MON_PRESS_H_MSG;
+extern PCHAR MON_NMI_MSG;
+extern PCHAR MON_CACHE_ERROR_MSG;
+extern PCHAR MON_EXCEPTION_MSG;
+extern PCHAR MON_PROCESSOR_B_EXCEPTION;
+extern PCHAR MON_PROCESSOR_A_EXCEPTION;
+extern PCHAR MON_BUS_PARITY_ERROR;
+extern PCHAR MON_ECC_ERROR_MSG;
+extern PCHAR MON_MEM_ECC_FAILED_MSG;
+extern PCHAR MON_MEM_PARITY_FAILED_MSG;
+extern PCHAR MON_CACHE_ERROR_EPC_MSG;
+extern PCHAR MON_CACHE_ERROR_REG_MSG;
+extern PCHAR MON_PARITY_DIAG_MSG;
+extern PCHAR MON_PROCESSOR_B_MSG;
+extern PCHAR MON_NO_RETURN_MSG;
+extern PCHAR MON_RESET_MACHINE_MSG;
+extern PCHAR MON_UNRECOGNIZED_COMMAND_MSG;
+
+extern PCHAR MON_HELP_TABLE[];
+#define MON_HELP_SIZE 15
+
+//
+// Selftest strings.
+//
+
+extern PCHAR ST_HANG_MSG;
+extern PCHAR ST_PROCESSOR_B_MSG;
+extern PCHAR ST_NMI_MSG;
+extern PCHAR ST_INVALID_ADDRESS_MSG;
+extern PCHAR ST_IO_CACHE_ADDRESS_MSG;
+extern PCHAR ST_KEYBOARD_ERROR_MSG;
+extern PCHAR ST_ENABLE_PROCESSOR_B_MSG;
+extern PCHAR ST_TIMEOUT_PROCESSOR_B_MSG;
+extern PCHAR ST_PROCESSOR_B_DISABLED_MSG;
+extern PCHAR ST_PROCESSOR_B_NOT_PRESENT_MSG;
+extern PCHAR ST_ZEROING_MEMORY_MSG;
+extern PCHAR ST_MEMORY_TEST_MSG;
+extern PCHAR ST_MEMORY_ERROR_MSG;
+extern PCHAR ST_TEST_MSG;
+extern PCHAR ST_MEMORY_CONTROLLER_MSG;
+extern PCHAR ST_INTERRUPT_CONTROLLER_MSG;
+extern PCHAR ST_KEYBOARD_CONTROLLER_MSG;
+extern PCHAR ST_ERROR_MSG;
+extern PCHAR ST_KEYBOARD_NOT_PRESENT_MSG;
+extern PCHAR ST_SERIAL_LINE_MSG;
+extern PCHAR ST_PARALLEL_PORT_MSG;
+extern PCHAR ST_FLOPPY_MSG;
+extern PCHAR ST_SCSI_MSG;
+extern PCHAR ST_ETHERNET_MSG;
+extern PCHAR ST_ETHERNET_ADDRESS_MSG;
+extern PCHAR ST_ETHERNET_LOOPBACK_MSG;
+extern PCHAR ST_ISP_MSG;
+extern PCHAR ST_RTC_MSG;
+extern PCHAR ST_ARC_MULTIBOOT_MSG;
+extern PCHAR ST_COPYRIGHT_MSG;
+
+//
+// Sonic test strings.
+//
+
+extern PCHAR ST_RECEIVED_MSG;
+
+//
+// Stubs strings.
+//
+
+extern PCHAR ST_BUGCHECK_MSG;
+extern PCHAR ST_ASSERT_MSG;
+extern PCHAR ST_UNIMPLEMENTED_ROUTINE_MSG;
diff --git a/private/ntos/fw/mips/fwtime.c b/private/ntos/fw/mips/fwtime.c
new file mode 100644
index 000000000..3720e2bcf
--- /dev/null
+++ b/private/ntos/fw/mips/fwtime.c
@@ -0,0 +1,172 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ fwtime.c
+
+Abstract:
+
+ This module implements the ARC firmware time operations.
+
+Author:
+
+ David M. Robinson (davidro) 19-Aug-1991
+
+
+Revision History:
+
+
+--*/
+
+#include "fwp.h"
+#include "jxhalp.h"
+
+//
+// Static data.
+//
+
+TIME_FIELDS FwTime;
+ULONG Seconds;
+ULONG FwDays;
+
+//
+// Define global data used to locate the EISA control space and the realtime
+// clock registers.
+//
+
+PVOID HalpEisaControlBase;
+PVOID HalpRealTimeClockBase;
+
+
+ARC_STATUS
+FwTimeInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the time routine addresses.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ESUCCESS is returned.
+
+--*/
+{
+
+ //
+ // Initialize the time routine addresses in the system
+ // parameter block.
+ //
+
+ (PARC_GET_TIME_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetTimeRoutine] =
+ FwGetTime;
+ (PARC_GET_RELATIVE_TIME_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetRelativeTimeRoutine] =
+ FwGetRelativeTime;
+
+ //
+ // Initialize pointers that the HAL routines use to access the RTC. Note
+ // that these routines are linked with the firmware and so this does not
+ // affect the actual HAL.
+ //
+
+ HalpEisaControlBase = (PVOID)EISA_IO_VIRTUAL_BASE;
+ HalpRealTimeClockBase = (PVOID)RTC_VIRTUAL_BASE;
+
+ //
+ // Initialize static data.
+ //
+
+ Seconds = 0;
+ FwDays = 0;
+
+ return ESUCCESS;
+}
+
+PTIME_FIELDS
+FwGetTime (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns a time structure filled in with the current
+ time read from the RTC.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns a pointer to a time structure. If the time information is
+ valid, valid data is returned, otherwise all fields are returned as zero.
+
+--*/
+
+{
+ if (!HalQueryRealTimeClock(&FwTime)) {
+ FwTime.Year = 0;
+ FwTime.Month = 0;
+ FwTime.Day = 0;
+ FwTime.Hour = 0;
+ FwTime.Minute = 0;
+ FwTime.Second = 0;
+ FwTime.Milliseconds = 0;
+ FwTime.Weekday = 0;
+ }
+ return &FwTime;
+}
+
+
+ULONG
+FwGetRelativeTime (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns a ULONG which increases at a rate of one per second.
+ This routine must be called at least once per day for the number to maintain
+ an accurate count.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns a pointer to a ULONG. If the time information is valid, valid
+ data is returned, otherwise a zero is returned.
+
+--*/
+
+{
+ TIME_FIELDS Time;
+ ULONG TempTime;
+
+ TempTime = Seconds;
+ if (HalQueryRealTimeClock(&Time)) {
+ Seconds = ((FwDays * 24 + Time.Hour) * 60 + Time.Minute) * 60 + Time.Second;
+ if (Seconds < TempTime) {
+ FwDays++;
+ Seconds += 24 * 60 * 60;
+ }
+ } else {
+ Seconds = 0;
+ }
+ return Seconds;
+}
+
diff --git a/private/ntos/fw/mips/fwtrap.s b/private/ntos/fw/mips/fwtrap.s
new file mode 100644
index 000000000..cb73aaf0f
--- /dev/null
+++ b/private/ntos/fw/mips/fwtrap.s
@@ -0,0 +1,655 @@
+#if defined(JAZZ) && defined(R4000)
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ fw4trap.s
+
+Abstract:
+
+ This module contains the fw exception handling functions.
+
+Author:
+
+ Lluis Abello (lluis) 4-Sep-91
+
+--*/
+
+//
+// include header file
+//
+#include <ksmips.h>
+#include <selfmap.h>
+
+
+.data
+//
+// Declare the table where to store the processor registers.
+// also align it so that we can store doubles.
+//
+.align 4
+ALTERNATE_ENTRY(RegisterTable)
+ .space RegisterTableSize
+ALTERNATE_ENTRY(EndRegisterTable)
+.text
+.set noat
+.set noreorder
+
+
+ SBTTL("User TLB dispatcher")
+/*++
+
+Routine Description:
+
+ This routine gets control on a User TLB Miss exception.
+ It reads the TLB Miss handler address from the System
+ Parameter Block and jumps to it.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+ LEAF_ENTRY(FwTbMissStartAddress)
+ li k0,KSEG0_BASE
+ lw k0,0x1018(k0)// Load address of UTLB handler
+ nop
+ jal k1,k0 // jump to handler saving return
+ nop // address in k1
+ mtc0 k0,epc // Handler returns return address in K0
+ nop // 2 cycle hazard
+ nop //
+ eret // restore from exception
+ nop
+ ALTERNATE_ENTRY(FwTbMissEndAddress)
+ .end FwTbMissStartAddress
+
+
+ SBTTL("General Exception dispatcher")
+/*++
+
+Routine Description:
+
+ This routine gets control on a General exception.
+ It reads the General exception handler address from the System
+ Parameter Block and jumps to it.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+ LEAF_ENTRY(FwGeneralExceptionStartAddress)
+
+ li k0,KSEG0_BASE
+ lw k0,0x1014(k0)// Load address of GE handler
+ nop
+ jal k1,k0 // jump to handler saving return
+ nop // address in k1
+ mtc0 k0,epc // Handler returns return address in K0
+ nop // 2 cycle hazard
+ nop //
+ eret // restore from exception
+ nop
+ ALTERNATE_ENTRY(FwGeneralExceptionEndAddress)
+
+ .end FwGeneralExceptionStartAddress
+
+
+ SBTTL("CacheError Exception dispatcher")
+/*++
+
+Routine Description:
+
+ This routine gets control on a cache error exception.
+ It jumps to the Monitor exception handler.
+ It gets copied to address 0xA0000100
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+ LEAF_ENTRY(FwCacheErrorExceptionStartAddress)
+
+ la k0,CacheExceptionMonitorEntry // load address of Monitor entry
+ li k1,KSEG1_BASE // convert address to non cached
+ or k0,k0,k1 //
+ j k0
+ nop
+
+ ALTERNATE_ENTRY(FwCacheErrorExceptionEndAddress)
+ .end FwCacheErrorExceptionStartAddress
+
+ SBTTL("Firmware Exception intialize")
+/*++
+
+Routine Description:
+
+ This routine copies the User TLB dispatcher and
+ the General Exception dispatcher to the R4000 vector
+ addresses.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+//
+// Copy the TB miss and general exception dispatchers to low memory.
+//
+ NESTED_ENTRY(FwExceptionInitialize,4, zero)
+ subu sp,sp,4 // decrement stack pointer
+ sw ra,0(sp) // save ra
+ la t2,FwTbMissStartAddress // get user TB miss start address
+ la t3,FwTbMissEndAddress // get user TB miss end address
+ li t4,KSEG1_BASE // get copy address
+10: lw t5,0(t2) // copy code to low memory
+ addu t2,t2,4 // advance copy pointers
+ sw t5,0(t4) //
+ bne t2,t3,10b // if ne, more to copy
+ addu t4,t4,4 //
+
+ la t2,FwGeneralExceptionStartAddress // get general exception start address
+ la t3,FwGeneralExceptionEndAddress // get general exception end address
+ li t4,KSEG1_BASE + 0x180 // get copy address
+20: lw t5,0(t2) // copy code to low memory
+ addu t2,t2,4 // advance copy pointers
+ sw t5,0(t4) //
+ bne t2,t3,20b // if ne, more to copy
+ addu t4,t4,4 //
+
+ la t2,FwCacheErrorExceptionStartAddress // get cache error exception start address
+ la t3,FwCacheErrorExceptionEndAddress // get cache error exception end address
+ li t4,KSEG1_BASE + 0x100 // get copy address
+30: lw t5,0(t2) // copy code to low memory
+ addu t2,t2,4 // advance copy pointers
+ sw t5,0(t4) //
+ bne t2,t3,30b // if ne, more to copy
+ addu t4,t4,4 //
+
+ //
+ // Set the Monitor exception handler address in the vector.
+ //
+ li t0,KSEG0_BASE
+ la t1,FwExceptionHandler
+ sw t1,0x1014(t0) // Init GE vector
+ sw t1,0x1018(t0) // Init UTLB vector
+
+ jal HalSweepIcache // sweep the instruction cache
+ nop
+ jal HalSweepDcache // sweep the data cache
+ nop
+
+ //
+ // Clear the BEV in the psr and enable IO device interrupts
+ //
+ li t0,(1<<PSR_CU1) | (1 << PSR_IE) | (1<< (PSR_INTMASK+3))
+ mtc0 t0,psr // set new psr.
+ nop //
+ nop //
+ nop //
+ lw ra,0(sp) // load return address
+ addiu sp,sp,4 // restore stack pointer
+ j ra // return to caller
+ nop
+ .end FwExceptionInitialize
+
+
+ SBTTL("Monitor Exception Handler")
+/*++
+
+Routine Description:
+
+ This routine implements the exception handler for
+ the monitor.
+
+Arguments:
+
+ k1 specifies the caller source in the following way:
+
+ - If k1 contains a word aligned address. The exception is
+ either a UTLB or a GE. The cause register supplies the cause
+ of the exception.
+
+ - Otherwise k1 contains a value that identifies the caller.
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+ LEAF_ENTRY(FwExceptionHandler)
+ mfc0 k0,cause // read cause register
+ nop
+ andi k0,k0,R4000_XCODE_MASK // isolate cause of exception
+ bne k0,zero,10f // if not interrupt go to Monitor
+ nop
+ subu sp,sp,FwFrameSize // decrement state pointer
+ sw k1,FwFrameK1(sp) // save volatile state
+ sw ra,FwFrameRa(sp) // save volatile state
+ sw a0,FwFrameA0(sp) // save volatile state
+ sw a1,FwFrameA1(sp) // save volatile state
+ sw a2,FwFrameA2(sp) // save volatile state
+ sw a3,FwFrameA3(sp) // save volatile state
+ sw v0,FwFrameV0(sp) // save volatile state
+ sw v1,FwFrameV1(sp) // save volatile state
+ sw t0,FwFrameT0(sp) // save volatile state
+ sw t1,FwFrameT1(sp) // save volatile state
+ sw t2,FwFrameT2(sp) // save volatile state
+ sw t3,FwFrameT3(sp) // save volatile state
+ sw t4,FwFrameT4(sp) // save volatile state
+ sw t5,FwFrameT5(sp) // save volatile state
+ sw t6,FwFrameT6(sp) // save volatile state
+ sw t7,FwFrameT7(sp) // save volatile state
+ sw t8,FwFrameT8(sp) // save volatile state
+ sw t9,FwFrameT9(sp) // save volatile state
+ mfc0 a0,cause // read cause register
+ mfc0 a1,psr // read psr.
+ sw AT,FwFrameAT(sp) // save volatile state
+ jal FwInterruptHandler // call c routine
+ and a0,a0,a1 // mask IM to clear disabled interrupts.
+
+ move k0,v0 // save return value in k0
+ lw k1,FwFrameK1(sp) // restore volatile state
+ lw ra,FwFrameRa(sp) // restore volatile state
+ lw a0,FwFrameA0(sp) // restore volatile state
+ lw a1,FwFrameA1(sp) // restore volatile state
+ lw a2,FwFrameA2(sp) // restore volatile state
+ lw a3,FwFrameA3(sp) // restore volatile state
+ lw v0,FwFrameV0(sp) // restore volatile state
+ lw v1,FwFrameV1(sp) // restore volatile state
+ lw t0,FwFrameT0(sp) // restore volatile state
+ lw t1,FwFrameT1(sp) // restore volatile state
+ lw t2,FwFrameT2(sp) // restore volatile state
+ lw t3,FwFrameT3(sp) // restore volatile state
+ lw t4,FwFrameT4(sp) // restore volatile state
+ lw t5,FwFrameT5(sp) // restore volatile state
+ lw t6,FwFrameT6(sp) // restore volatile state
+ lw t7,FwFrameT7(sp) // restore volatile state
+ lw t8,FwFrameT8(sp) // restore volatile state
+ lw t9,FwFrameT9(sp) // restore volatile state
+ lw AT,FwFrameAT(sp) // save volatile state
+ beq k0,zero,10f // if routine returned false do not return
+ addiu sp,sp,FwFrameSize // restore stack pointer
+ mfc0 k0,epc // get return address
+ nop
+ j k1 // return to caller
+ nop //
+//
+// Control reaches here if an exception other than an interrupt occurred
+// or if the interrupt handler returned false meaning that it didn't
+// know how to handle the interrupt exception.
+//
+// At this time no state has been destroyed and register k1 still contains
+// the address where to return.
+//
+10:
+ addiu k0,k0,-XCODE_BREAKPOINT // substract breakpoint code
+ beq k0,zero,10f // if eq Bp exception, call KD unconditionally
+ la k0,KdInstalled // load address of boolean
+ lbu k0,0(k0) // read boolean
+ beq k0,zero,MonitorExceptionHandler // if false go to the monitor
+ nop // otherwise
+10: j KiGeneralException // go to the debugger.
+ nop
+ //
+ // This is the entry point when the monitor is called.
+ // Set k1 to 3 to tell the Monitor than can execute a j ra
+ // to quit.
+ //
+ ALTERNATE_ENTRY(FwMonitor)
+ b MonitorExceptionHandler
+ li k1,3 // set k1 to 3 to indicate we don't get
+ nop // here because of an exception
+ // The monitor returns to ra which points
+ // to where we got called from.
+
+ ALTERNATE_ENTRY(CacheExceptionMonitorEntry)
+ la k0,RegisterTable // get address of table.
+ or k0,k0,k1 // set it non cached.
+ b MonitorEntry // go to monitor
+ ori k1,zero,CACHE_EXCEPTION // set flag to tell that parity error occurred
+
+ ALTERNATE_ENTRY(MonitorExceptionHandler)
+ //
+ // Save the registers.
+ //
+ la k0,RegisterTable // get address of table.
+
+ ALTERNATE_ENTRY(MonitorEntry)
+
+ sw zero,zeroRegTable(k0)
+ sw AT,atRegTable(k0)
+ sw v0,v0RegTable(k0)
+ sw v1,v1RegTable(k0)
+ sw a0,a0RegTable(k0)
+ sw a1,a1RegTable(k0)
+ sw a2,a2RegTable(k0)
+ sw a3,a3RegTable(k0)
+ sw t0,t0RegTable(k0)
+ sw t1,t1RegTable(k0)
+ sw t2,t2RegTable(k0)
+ sw t3,t3RegTable(k0)
+ sw t4,t4RegTable(k0)
+ sw t5,t5RegTable(k0)
+ sw t6,t6RegTable(k0)
+ sw t7,t7RegTable(k0)
+ sw s0,s0RegTable(k0)
+ sw s1,s1RegTable(k0)
+ sw s2,s2RegTable(k0)
+ sw s3,s3RegTable(k0)
+ sw s4,s4RegTable(k0)
+ sw s5,s5RegTable(k0)
+ sw s6,s6RegTable(k0)
+ sw s7,s7RegTable(k0)
+ sw t8,t8RegTable(k0)
+ sw t9,t9RegTable(k0)
+ sw k0,k0RegTable(k0)
+ sw k1,k1RegTable(k0)
+ sw gp,gpRegTable(k0)
+ sw sp,spRegTable(k0)
+ sw s8,s8RegTable(k0)
+ sw ra,raRegTable(k0)
+
+ //
+ // Store coprocessor1 registers.
+ //
+ cfc1 v0,fsr
+ sdc1 f0,f0RegTable(k0)
+ sdc1 f2,f2RegTable(k0)
+ sdc1 f4,f4RegTable(k0)
+ sdc1 f6,f6RegTable(k0)
+ sdc1 f8,f8RegTable(k0)
+ sdc1 f10,f10RegTable(k0)
+ sdc1 f12,f12RegTable(k0)
+ sdc1 f14,f14RegTable(k0)
+ sdc1 f16,f16RegTable(k0)
+ sdc1 f18,f18RegTable(k0)
+ sdc1 f20,f20RegTable(k0)
+ sdc1 f22,f22RegTable(k0)
+ sdc1 f24,f24RegTable(k0)
+ sdc1 f26,f26RegTable(k0)
+ sdc1 f28,f28RegTable(k0)
+ sdc1 f30,f30RegTable(k0)
+ sw v0,fsrRegTable(k0)
+ //
+ // Store cop0 registers.
+ //
+ mfc0 v1,index
+ mfc0 v0,random
+ sw v1,indexRegTable(k0)
+ sw v0,randomRegTable(k0)
+ mfc0 v1,entrylo0
+ nop
+ mfc0 v0,entrylo1
+ sw v1,entrylo0RegTable(k0)
+ sw v0,entrylo1RegTable(k0)
+ mfc0 v1,context
+ mfc0 v0,pagemask
+ sw v1,contextRegTable(k0)
+ sw v0,pagemaskRegTable(k0)
+ mfc0 v1,wired
+ mfc0 v0,badvaddr
+ sw v1,wiredRegTable(k0)
+ sw v0,badvaddrRegTable(k0)
+ mfc0 v1,count
+ mfc0 v0,entryhi
+ sw v1,countRegTable(k0)
+ sw v0,entryhiRegTable(k0)
+ mfc0 v1,compare
+ mfc0 v0,psr
+ sw v1,compareRegTable(k0)
+ sw v0,psrRegTable(k0)
+ mfc0 v1,cause
+ mfc0 v0,epc
+ sw v1,causeRegTable(k0)
+ sw v0,epcRegTable(k0)
+ mfc0 v1,prid
+ mfc0 v0,config
+ sw v1,pridRegTable(k0)
+ sw v0,configRegTable(k0)
+ mfc0 v1,lladdr
+ mfc0 v0,watchlo
+ sw v1,lladdrRegTable(k0)
+ sw v0,watchloRegTable(k0)
+ mfc0 v1,watchhi
+ mfc0 v0,ecc
+ sw v1,watchhiRegTable(k0)
+ sw v0,eccRegTable(k0)
+ mfc0 v1,cacheerr
+ mfc0 v0,taglo
+ sw v1,cacheerrorRegTable(k0)
+ sw v0,tagloRegTable(k0)
+ mfc0 v1,taghi
+ mfc0 v0,errorepc
+ sw v1,taghiRegTable(k0)
+ sw v0,errorepcRegTable(k0)
+ li k0,CACHE_EXCEPTION
+ bne k0,k1,10f // check if parity exception
+ la k0,Monitor // Set address where to return
+ li t0,KSEG1_BASE // convert it to non cached
+ or k0,k0,t0 //
+ mtc0 k0,errorepc // set in errorepc
+ li sp, RAM_TEST_STACK_ADDRESS | KSEG1_BASE
+ andi a0,k1,0x3 // pass caller source in a0 just 2 bits.
+ eret // jump to the monitor and leave exception level
+10:
+ la k0,Monitor // Set address where to
+ mtc0 k0,epc // return from the exception.
+ li k0,0x3
+ beq k0,k1,10f // if k1=3 do not change sp
+ andi a0,k1,0x3 // pass caller source in a0 just 2 bits.
+ li sp,RAM_TEST_STACK_ADDRESS // set the stack pointer.
+ eret // jump to the monitor and leave exception level
+10: j Monitor
+
+ .end MonitorExceptionHandler
+/*++
+ARC_STATUS
+FwInvoke(
+ IN ULONG ExecAddr,
+ IN ULONG StackAddr,
+ IN ULONG Argc,
+ IN PCHAR Argv[],
+ IN PCHAR Envp[]
+ )
+
+
+Routine Description:
+
+ This routine invokes a loaded program.
+
+Arguments:
+
+ ExecAddr - Supplies the address of the routine to call.
+
+ StackAddr - Supplies the address to which the stack pointer is set.
+
+ Argc, Argv, Envp - Supply the arguments and endvironment to pass to
+ Loaded program.
+
+ The stack pointer is saved in register s0 so that when the loaded
+ program returns, the old stack pointer can be restored.
+
+ In addition, the value stored in InvokeSavedSp is read and if zero,
+ this is the first loaded program, thus the current stack pointer
+ is the firmware stack pointer and it is saved in order to
+ be able to restore the Firmware stack pointer when a loaded program
+ calls ReturnFromMain.
+
+Return Value:
+
+ ESUCCESS is returned if the address is valid.
+ EFAULT indicates an invalid addres.
+
+--*/
+
+{
+ NESTED_ENTRY(FwInvoke,0x20,zero)
+
+ subu sp,sp,0x20 // allocate room in the stack.
+ sw ra,0x1C(sp) // save ra
+ sw s0,0x18(sp) // save s0
+ move v1,a0 // save address of routine to call
+ andi v0,v1,0x3 // check for alignment.
+ bne v0,zero,20f // if not aligned return error.
+ li v0,6 // set EFAULT = 6 a return value.
+ move a0,a2 // move argc to first argument
+ move s0,sp // save stack pointer in s0
+ lw a2,0x30(sp) // load Envp argument into second.
+ move sp,a1 // set new stack pointer.
+ subu sp,sp,0x10 // make room for arguments.
+ jal v1 // call program
+ move a1,a3 // move argv to right argument
+//
+// If loaded program returns, s0 has the previous stack pointer.
+//
+ move sp,s0 // set old stack pointer.
+ move v0,zero // set ESUCCESS as return value.
+ lw ra,0x1C(sp) // restore ra
+ lw s0,0x18(sp) // restore s0
+20:
+ j ra // return to caller
+ addiu sp,sp,0x20 // restore sp.
+ .end FwInvoke
+
+
+ SBTTL("FwExecute")
+/*++
+
+Routine Description:
+
+ This routine is the entry point for the Execute service.
+
+ It behaves in two different ways depending on where it is
+ called from:
+
+ 1) If it's called from the Firmware it saves the stack pointer
+ in a fixed location and then saves all the saved registers
+ in the stack. This is the stack that will be used to restore
+ the saved state when returning to the firmware.
+
+ 2) If called from a loaded program the program to be loaded
+ and executed can overwrite the current program and it's
+ stack, therefore a temporary stack is set.
+
+Arguments:
+
+ a0 IN PCHAR Path,
+ a1 IN ULONG Argc,
+ a2 IN PCHAR Argv[],
+ a3 IN PCHAR Envp[]
+
+Return Value:
+
+ ARC_STATUS returned by FwPrivateExecute.
+ Always returns to the Firmware.
+
+--*/
+ LEAF_ENTRY(FwExecute)
+ la t0, FwSavedSp // load address where to save Fw SP
+ lw t1, 0(t0) // read saved stack
+ beq t1, zero,CallFromFw // if zero first call from Fw.
+ nop
+//
+// A loaded program wants to be replaced by another program
+// therefore the current stack and state will be trashed and a
+// new temporary stack needs to be set.
+//
+ la t0, FwTemporaryStack // load address of Fw temporary stack
+ lw sp, 0(t0) // load Tmp Stack value.
+ jal FwPrivateExecute // go to do the job
+ nop
+//
+// if the program returns it's caller is gone, therefore
+// we restore the initiali fw stack and returned to the
+// firmware instead.
+//
+ la t0, FwSavedSp // get address of saved stack
+ lw sp, 0(t0) // restore saved stack.
+ b RestoreFwState // go to restore state
+ nop
+
+CallFromFw:
+ subu sp,sp,0x30 // make room in the stack
+ sw sp, 0(t0) // save new stack
+ sw ra, 0x4(sp) // save also return address
+ sw s0, 0x8(sp) // save state that must be preserved.
+ sw s1, 0xC(sp)
+ sw s2, 0x10(sp)
+ sw s3, 0x14(sp)
+ sw s4, 0x18(sp)
+ sw s5, 0x1C(sp)
+ sw s6, 0x20(sp)
+ sw s7, 0x24(sp)
+ sw s8, 0x28(sp)
+ jal FwPrivateExecute // go to do the job
+ sw gp, 0x2C(sp) // save global pointer
+
+RestoreFwState:
+ lw ra, 0x4(sp) // restore ra
+ lw s0, 0x8(sp) // restore Fw state
+ lw s1, 0xC(sp)
+ lw s2, 0x10(sp)
+ lw s3, 0x14(sp)
+ lw s4, 0x18(sp)
+ lw s5, 0x1C(sp)
+ lw s6, 0x20(sp)
+ lw s7, 0x24(sp)
+ lw s8, 0x28(sp)
+ lw gp, 0x2C(sp)
+ j ra // return to Firmware.
+ addu sp,sp,0x30 // restore sp.
+
+ .end FwExecute
+
+
+ SBTTL("Termination Functions")
+/*++
+
+Routine Description:
+
+ This routine implements the Firmware ReturnFromMain
+ termination function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ returns to where the program was called from.
+
+--*/
+ ALTERNATE_ENTRY(FwReturnFromMain)
+ la t0,FwSavedSp // get address where SP was saved
+ lw sp,0(t0) // set old stack pointer.
+ b RestoreFwState
+ move v0,zero // set ESUCCESS as return value.
+
+ .end FwReturnFromMain
+
+#endif // defined(JAZZ) && defined(R4000)
diff --git a/private/ntos/fw/mips/fwusa.c b/private/ntos/fw/mips/fwusa.c
new file mode 100644
index 000000000..7c0b5bd38
--- /dev/null
+++ b/private/ntos/fw/mips/fwusa.c
@@ -0,0 +1,209 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ fwusa.c
+
+Abstract:
+
+ This module contains the fw english strings.
+
+Author:
+
+ David M. Robinson (davidro) 21-May-1993
+
+
+Revision History:
+
+
+--*/
+
+#include "ntos.h"
+
+//
+// Common strings.
+//
+
+PCHAR FW_OK_MSG = "...OK.";
+PCHAR FW_CRLF_MSG = "\r\n";
+PCHAR FW_ERROR1_MSG = "Error";
+PCHAR FW_ERROR2_MSG = "\r\n Error: ";
+
+//
+// Firmware strings.
+//
+
+PCHAR FW_NOT_ENOUGH_ENTRIES_MSG = "Error: Not enough entries in the lookup table.\n";
+PCHAR FW_FILESYSTEM_NOT_REQ_MSG = "File system not recognized.\r\n";
+PCHAR FW_UNKNOWN_SECTION_TYPE_MSG = "Unknown section type\r\n";
+PCHAR FW_UNKNOWN_RELOC_TYPE_MSG = "Relocator: Unknown relocation type\r\n";
+PCHAR FW_START_MSG = "Start ";
+PCHAR FW_RUN_A_PROGRAM_MSG = "Run a program";
+PCHAR FW_RUN_SETUP_MSG = "Run setup";
+PCHAR FW_ACTIONS_MSG = " Actions:\r\n";
+PCHAR FW_USE_ARROW_MSG = " Use the arrow keys to select.\r\n";
+PCHAR FW_USE_ENTER_MSG = " Press Enter to choose.\r\n";
+PCHAR FW_AUTOBOOT_MSG = " Seconds until auto-boot, select another option to override:\r\n";
+PCHAR FW_BREAKPOINT_MSG = " Press D to toggle the breakpoint action after image load, currently: ";
+PCHAR FW_OFF_MSG = "OFF";
+PCHAR FW_ON_MSG = "ON ";
+PCHAR FW_DEBUGGER_CONNECTED_MSG = " SysRq was pressed and the debugger is now connected.";
+PCHAR FW_PROGRAM_TO_RUN_MSG = "Program to run: ";
+PCHAR FW_PATHNAME_NOT_DEF_MSG = " Pathname is not defined";
+PCHAR FW_PRESS_ANY_KEY_MSG = "\n\r Press any key to continue...\n\r";
+PCHAR FW_ERROR_CODE_MSG = "Error code = %d";
+PCHAR FW_PRESS_ANY_KEY2_MSG = ", press any key to continue";
+PCHAR FW_INITIALIZING_MSG = "\r\n Initializing firmware...";
+PCHAR FW_CONSOLE_IN_ERROR_MSG = "\r\n Error: Firmware could not open StandardIn\r\n";
+PCHAR FW_CONSOLE_IN_ERROR2_MSG = "\r\n Error: Fid for StandardIn device is not zero\r\n";
+PCHAR FW_CONSOLE_OUT_ERROR_MSG = "\r\n Error: Firmware could not open StandardOut\r\n";
+PCHAR FW_CONSOLE_OUT_ERROR2_MSG = "\r\n Error: Fid for StandardOut device is not one\r\n";
+PCHAR FW_SPIN_DISKS_MSG = " Spinning up disks";
+PCHAR FW_SYSTEM_HALT_MSG = "System Halted.";
+
+PCHAR FW_NVRAM_MSG[] = {
+ "º WARNING: NVRAM is out of date or not º",
+ "º initialized. Run a setup º",
+ "º program to correct. Press º",
+ "º any key to continue. º"
+};
+
+PCHAR FW_VIDEO_MSG[] = {
+ "º WARNING: The video board is attempting to change º",
+ "º the monitor settings. Press 'Y' to º",
+ "º accept, any other key to decline. º",
+ "º º",
+ "º Old Settings New Settings º",
+ "º Board Type º",
+ "º Screen Width º",
+ "º Screen Height º"
+};
+
+
+//
+// Error messages
+//
+
+PCHAR FW_ERROR_MSG[] = {
+ "Argument list is too long",
+ "Access violation",
+ "Resource temporarily unavailable",
+ "Bad image file type",
+ "Device is busy",
+ "Fault occured",
+ "Invalid argument",
+ "Device error",
+ "File is a directory",
+ "Too many open files",
+ "Too many links",
+ "Name is too long",
+ "Invalid device name",
+ "The file or device does not exist",
+ "Execute format error",
+ "Not enough memory",
+ "File is not a directory",
+ "Inappropriate control operation",
+ "Media not loaded",
+ "Read-only file system"
+};
+
+//
+// Monitor Strings.
+//
+
+PCHAR MON_INVALID_ARGUMENT_COUNT_MSG = "Invalid number of arguments.\r\n";
+PCHAR MON_UNALIGNED_ADDRESS_MSG = "Unaligned address.\r\n";
+PCHAR MON_INVALID_VALUE_MSG = " is not a valid value.\r\n";
+PCHAR MON_INVALID_REGISTER_MSG = " is not a valid register name.\r\n";
+PCHAR MON_NOT_VALID_ADDRESS_MSG = " is not a valid address.\r\n";
+PCHAR MON_INVALID_ADDRESS_RANGE_MSG = "Invalid address range.\r\n";
+PCHAR MON_FORMAT1_MSG = " %s=%08lx";
+PCHAR MON_JAZZ_MONITOR_MSG = "\r\nJazz Monitor. Version ";
+PCHAR MON_PRESS_H_MSG = "Press H for help, Q to quit.\r\n";
+PCHAR MON_NMI_MSG = "NMI";
+PCHAR MON_CACHE_ERROR_MSG = "Cache Error";
+PCHAR MON_EXCEPTION_MSG = " exception occurred.\r\n";
+PCHAR MON_PROCESSOR_B_EXCEPTION = "Exception taken by processor B.\r\n";
+PCHAR MON_PROCESSOR_A_EXCEPTION = "Exception taken by processor A.\r\n";
+PCHAR MON_BUS_PARITY_ERROR = "Error occurred on SysAd bus. No more information is available.\r\n";
+PCHAR MON_ECC_ERROR_MSG = "System ECC Error\r\nEpc= %08lx\r\n";
+PCHAR MON_MEM_ECC_FAILED_MSG = "Memory Failed Address = %08lx\r\nECC Diagnostic = %08lx-%08lx\r\n";
+PCHAR MON_MEM_PARITY_FAILED_MSG = "Memory Failed Address = %08lx\r\nParity Diagnostic = %08lx-%08lx\r\n";
+PCHAR MON_CACHE_ERROR_EPC_MSG = "CacheError = %08lx\r\nErrorepc= %08lx\r\n";
+PCHAR MON_CACHE_ERROR_REG_MSG = "CacheError Register = %08lx\r\n";
+PCHAR MON_PARITY_DIAG_MSG = "ParityDiag = %08lx-%08lx\r\n";
+PCHAR MON_PROCESSOR_B_MSG = "Processor B is not enabled\r\n";
+PCHAR MON_NO_RETURN_MSG = "No place to return.\r\n";
+PCHAR MON_RESET_MACHINE_MSG = "Reset the machine?";
+PCHAR MON_UNRECOGNIZED_COMMAND_MSG = "Unrecognized command.\r\n";
+
+PCHAR MON_HELP_TABLE[] = {
+ "A - list available devices",
+ "D[type] <range> - dump memory",
+ "E[type] [<address> [<value>]] - enter",
+ "F <range> <list> - fill",
+ "H or ? - Print this message",
+ "I[type] - input",
+ "O[type] [<address> [<value>]] - output",
+ "Q - quit",
+ "R [<reg>] - dump register",
+#ifdef DUO
+ "S swap processors",
+#endif
+ "Z <range> - zero memory",
+ "",
+ "[type] = b (byte), w - (word), d - (double)",
+ "<range> = <start address> (Note: end = start + 128)",
+ " <start address> <end address>",
+ " <start address> l <count>"
+ };
+
+//
+// Selftest strings.
+//
+
+PCHAR ST_HANG_MSG = "\r\n Self-test failed.";
+PCHAR ST_PROCESSOR_B_MSG = "Processor B ";
+PCHAR ST_NMI_MSG = "Non Maskable Interrupt Occurred.\r\nErrorEpc = 0x%08lx\r\n";
+PCHAR ST_INVALID_ADDRESS_MSG = "Invalid Address = 0x%08lx\r\n";
+PCHAR ST_IO_CACHE_ADDRESS_MSG = "IO Cache address = 0x%08lx\r\n";
+PCHAR ST_KEYBOARD_ERROR_MSG = " Keyboard error.\r\n";
+PCHAR ST_ENABLE_PROCESSOR_B_MSG = " Enabling processor B.";
+PCHAR ST_TIMEOUT_PROCESSOR_B_MSG = " Timeout waiting for processor B start up.\r\n";
+PCHAR ST_PROCESSOR_B_DISABLED_MSG = " Processor B is disabled.\r\n";
+PCHAR ST_PROCESSOR_B_NOT_PRESENT_MSG = " Processor B not present.\r\n";
+PCHAR ST_MEMORY_TEST_MSG = " Memory test KB.";
+PCHAR ST_MEMORY_ERROR_MSG = "\r\n Memory Error.";
+PCHAR ST_TEST_MSG = "\r\n Testing ";
+PCHAR ST_MEMORY_CONTROLLER_MSG = "Memory Controller";
+PCHAR ST_INTERRUPT_CONTROLLER_MSG = "Interrupt Controller";
+PCHAR ST_KEYBOARD_CONTROLLER_MSG = "Keyboard Controller";
+PCHAR ST_ERROR_MSG = "...Error.";
+PCHAR ST_KEYBOARD_NOT_PRESENT_MSG = "Keyboard not present.";
+PCHAR ST_SERIAL_LINE_MSG = "Serial Line";
+PCHAR ST_PARALLEL_PORT_MSG = "Parallel Port";
+PCHAR ST_FLOPPY_MSG = "Floppy Controller";
+PCHAR ST_SCSI_MSG = "SCSI Controller";
+PCHAR ST_ETHERNET_MSG = "Ethernet Controller";
+PCHAR ST_ETHERNET_ADDRESS_MSG = "\r\n Ethernet Station Address: ";
+PCHAR ST_ETHERNET_LOOPBACK_MSG = "\r\n Ethernet Loopback test";
+PCHAR ST_ISP_MSG = "ISP";
+PCHAR ST_RTC_MSG = "RTC";
+PCHAR ST_ARC_MULTIBOOT_MSG = " ARC Multiboot Version %d\r\n";
+PCHAR ST_COPYRIGHT_MSG = " Copyright (c) 1993 Microsoft Corporation\r\n";
+
+//
+// Sonic test strings.
+//
+
+PCHAR ST_RECEIVED_MSG = "Received.";
+
+//
+// Stubs strings.
+//
+
+PCHAR ST_BUGCHECK_MSG = "\r\n*** BugCheck (%lx) ***";
+PCHAR ST_ASSERT_MSG = "\r\n*** Assertion failed";
+PCHAR ST_UNIMPLEMENTED_ROUTINE_MSG = "\r\nERROR: Unimplemented or reserved routine was called.\r\n";
diff --git a/private/ntos/fw/mips/inc.h b/private/ntos/fw/mips/inc.h
new file mode 100644
index 000000000..2cffce2fd
--- /dev/null
+++ b/private/ntos/fw/mips/inc.h
@@ -0,0 +1,883 @@
+
+
+///////////////////////////////////////////////////////////////////////////////
+// General definitions
+///////////////////////////////////////////////////////////////////////////////
+
+
+#define WORD_2P2 2 // 2^2 = 4 bytes
+#define HALFWORD_2P2 1 // 2^1 = 2 bytes
+#define BYTE_2P2 0 // 2^0 = 1 bytes
+#define BITSXBYTE 8 // 8 bits = 1 byte
+
+#define ASCII_BLOCK_SIZE 512 // ASCII block size
+
+#define MIN(x,y) ((x) > (y) ? (y) : (x)) // minimum number
+
+
+#define INSTRUCTION_DELAY 10 // nsec for each instruction
+ // using 50MHZ externl clock
+#define MAX_DCACHE_LINE_SIZE 32 // max bytes per Data cache line
+
+#define UNMAPPED_SIZE (512*1024*1024) // 512 Mbytes of unmapped space
+
+#define PAGE_4G_SHIFT 32 // 2^32 = 4Gbytes
+#define PAGE_32M_SHIFT 25 // 2^25 = 32Mbytes
+#define PAGE_32M_SIZE (1 << PAGE_32M_SHIFT) // 32 Mbytes
+#define PAGE_16M_SHIFT 24 // 2^24 = 16Mbytes
+#define PAGE_16M_SIZE (1 << PAGE_16M_SHIFT) // 16 Mbytes
+#define PAGE_8M_SHIFT 23 // 2^23 = 8Mbytes
+#define PAGE_8M_SIZE (1 << PAGE_8M_SHIFT) // 8 Mbytes
+#define PAGE_4M_SHIFT 22 // 2^22 = 4Mbytes
+#define PAGE_4M_SIZE (1 << PAGE_4M_SHIFT) // 4 Mbytes
+#define PAGE_2M_SHIFT 21 // 2^21 = 2Mbytes
+#define PAGE_2M_SIZE (1 << PAGE_2M_SHIFT) // 2 Mbytes
+#define PAGE_1M_SHIFT 20 // 2^20 = 1Mbyte
+#define PAGE_1M_SIZE (1 << PAGE_1M_SHIFT) // 1 Mbyte
+#define PAGE_MAX_SHIFT PAGE_16M_SHIFT // max TLB page shift.
+#define PAGE_MAX_SIZE (1 << PAGE_MAX_SHIFT) // max TLB page (one entry)
+#define PAGES_IN_4G (1 << (PAGE_4G_SHIFT - PAGE_SHIFT)) // # 4k in 4Gbytes
+#define PAGES_IN_16M (1 << (PAGE_16M_SHIFT - PAGE_SHIFT)) // # 4k in 16Mbytes
+#define PAGES_IN_1M (1 << (PAGE_1M_SHIFT - PAGE_SHIFT)) // # 4k in 1Mbyte
+
+//#define HIT_WRITEBACK_D 0x19 // hit write back 1st cache
+//#define HIT_WRITEBACK_SD 0x1B // hit write back 2nd cache
+
+#define EISA_LATCH_VIRTUAL_BASE (DEVICE_VIRTUAL_BASE + 0xE000)
+#define EISA_LOCK_VIRTUAL_BASE (DEVICE_VIRTUAL_BASE + 0xE800)
+#define EISA_INT_ACK_ADDR (DEVICE_VIRTUAL_BASE + 0x238)
+#define INT_ENABLE_ADDR (DEVICE_VIRTUAL_BASE + 0xE8)
+
+//
+// coff image info structure
+//
+
+typedef struct _IMAGE_FLAGS
+ {
+ ULONG Exec : 1;
+ ULONG Reloc : 1;
+
+ } IMAGE_FLAGS, *PIMAGE_FLAGS;
+
+
+typedef struct _IMAGE_INFO
+ {
+ IMAGE_FLAGS Flags; // image characteristic
+ ULONG ImageBase; // base address
+ ULONG ImageSize; // in 4k units
+
+ } IMAGE_INFO, *PIMAGE_INFO;
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// General function prototypes
+///////////////////////////////////////////////////////////////////////////////
+
+PCHAR
+FwToUpperStr
+ (
+ IN OUT PCHAR s
+ );
+
+PCHAR
+FwToLowerStr
+ (
+ IN OUT PCHAR s
+ );
+
+PCHAR
+FwGetPath
+ (
+ IN PCONFIGURATION_COMPONENT Component,
+ OUT PCHAR String
+ );
+
+PCHAR
+FwGetMnemonic
+ (
+ IN PCONFIGURATION_COMPONENT Component
+ );
+
+BOOLEAN
+FwValidMnem
+ (
+ IN PCHAR Str
+ );
+
+ULONG
+Fw4UcharToUlongLSB
+ (
+ IN PUCHAR String
+ );
+
+
+ULONG
+Fw4UcharToUlongMSB
+ (
+ IN PUCHAR String
+ );
+
+PCHAR
+FwStoreStr
+ (
+ IN PCHAR Str
+ );
+
+BOOLEAN
+FwGetNumMnemonicKey
+ (
+ IN PCHAR Path,
+ IN UCHAR KeyNumber,
+ IN PULONG Key
+ );
+
+BOOLEAN
+FwGetMnemonicKey
+ (
+ IN PCHAR Path,
+ IN PCHAR Mnemonic,
+ IN PULONG Key
+ );
+
+BOOLEAN
+FwGetNextMnemonic
+ (
+ IN PCHAR Path,
+ IN PCHAR Mnemonic,
+ OUT PCHAR NextMnemonic
+ );
+
+BOOLEAN
+FwGetMnemonicPath
+ (
+ IN PCHAR Path,
+ IN PCHAR Mnemonic,
+ OUT PCHAR MnemonicPath
+ );
+
+BOOLEAN
+FwGetEisaId
+ (
+ IN PCHAR PathName,
+ OUT PCHAR EisaId,
+ OUT PUCHAR IdInfo
+ );
+
+VOID
+FwUncompressEisaId
+ (
+ IN PUCHAR CompEisaId,
+ OUT PUCHAR UncompEisaId
+ );
+
+BOOLEAN
+FwGetEisaBusIoCpuAddress
+ (
+ IN PCHAR EisaPath,
+ OUT PVOID *IoBusAddress
+ );
+
+BOOLEAN
+GetNextPath
+ (
+ IN OUT PCHAR *PPathList,
+ OUT PCHAR PathTarget
+ );
+
+//PDRIVER_STRATEGY
+//FwGetStrategy
+// (
+// IN PCHAR Path
+// );
+
+ARC_STATUS
+FwGetImageInfo
+ (
+ IN PCHAR ImagePath,
+ OUT PIMAGE_INFO pImageInfo
+ );
+
+PCONFIGURATION_COMPONENT
+FwGetControllerComponent
+ (
+ IN PCHAR Path
+ );
+
+PCONFIGURATION_COMPONENT
+FwGetPeripheralComponent
+ (
+ IN PCHAR Path
+ );
+
+PCHAR
+FwGetControllerMnemonic
+ (
+ IN PCHAR Path
+ );
+
+PCHAR
+FwGetPeripheralMnemonic
+ (
+ IN PCHAR Path
+ );
+
+BOOLEAN
+FwSizeToShift
+ (
+ IN ULONG Size,
+ OUT ULONG Shift
+ );
+
+ARC_STATUS
+FwGetImageInfo
+ (
+ IN PCHAR ImagePath,
+ OUT PIMAGE_INFO pImageInfo
+ );
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// EISA configuration
+///////////////////////////////////////////////////////////////////////////////
+
+
+
+#define NO_ADAP_ID 0x80000000 // adapter id not present
+#define WAIT_ADAP_ID 0x70000000 // adapter not ready yet
+#define TIMEOUT_UNITS 200 // 200 units of 10msec
+
+
+typedef struct _EISA_SLOT_INFO
+ {
+ UCHAR IdInfo;
+ UCHAR MajorRevLevel;
+ UCHAR MinorRevLevel;
+ UCHAR LSByteChecksum;
+ UCHAR MSByteChecksum;
+ UCHAR FunctionsNumber;
+ UCHAR FunctionInfo;
+ UCHAR Id1stChar;
+ UCHAR Id2ndChar;
+ UCHAR Id3rdChar;
+ UCHAR Id4thChar;
+ } EISA_SLOT_INFO, *PEISA_SLOT_INFO;
+
+
+#define ID_DIGIT_SIZE 4 // # of bits
+#define ID_CHAR_SIZE 5 // # of bits
+#define ID_DIGIT_MASK ((1<<ID_DIGIT_SIZE)-1) // field size
+#define ID_CHAR_MASK ((1<<ID_CHAR_SIZE)-1) // field size
+#define EISA_SLOT_INFO_SIZE sizeof(EISA_SLOT_INFO)
+#define EISA_FUNC_INFO_SIZE 320 // fixed length
+
+#define EISA_SLOT_MIN_INFO ( CONFIGDATAHEADER_SIZE + EISA_SLOT_INFO_SIZE )
+
+//
+// EISA configuration data extensions
+//
+
+typedef struct _EISA_ADAPTER_DETAILS
+ {
+ CONFIGDATAHEADER ConfigDataHeader;
+ ULONG NumberOfSlots;
+ PVOID IoStart;
+ ULONG IoSize;
+ } EISA_ADAPTER_DETAILS, *PEISA_ADAPTER_DETAILS;
+
+
+
+//
+// EISA_FUNC_INFO block offsets
+//
+
+#define CFG_ID_INFO_OFS 0x04 // offset to Id info byte
+#define CFG_SLOT_INFO_OFS 0x05 // offset to slot info byte
+#define CFG_FN_INFO_OFS 0x22 // offset to function info byte
+#define CFG_ASC_BLK_OFS 0x23 // offset to ASCII data block
+#define CFG_MEM_BLK_OFS 0x73 // offset to mem cfg data block
+#define CFG_IRQ_BLK_OFS 0xB2 // offset to IRQ cfg data block
+#define CFG_DMA_BLK_OFS 0xC0 // offset to DMA cfg data block
+#define CFG_PRT_BLK_OFS 0xC8 // offset to port I/O data block
+#define CFG_INI_BLK_OFS 0x104 // offset to port init data block
+
+#define CFG_FREE_BLK_OFS 0x73 // offset of free form cfg data block
+
+//
+// EISA_FUNC_INFO block lengths
+//
+
+#define CFG_ASC_BLK_LEN 80 // length of ASCII data block
+#define CFG_MEM_BLK_LEN 63 // length of mem cfg data block
+#define CFG_IRQ_BLK_LEN 14 // length of IRQ cfg data block
+#define CFG_DMA_BLK_LEN 8 // length of DMA cfg data block
+#define CFG_PRT_BLK_LEN 60 // length of port I/O data block
+#define CFG_INI_BLK_LEN 60 // length of port init data block
+
+#define CFG_FREE_BLK_LEN 205 // length of free form cfg data block
+
+//
+// ID info byte layout
+//
+
+#define CFG_DUPLICATE_ID 0x80 // more IDs with the same value
+#define CFG_UNREADABLE_ID 0x40 // the ID is not readable
+#define CFG_SLOT_MASK 0x30 // slot mask
+#define CFG_SLOT_EXP 0x00 // expansion slot
+#define CFG_SLOT_EMB 0x10 // embedded slot
+#define CFG_SLOT_VIR 0x20 // virtual slot
+
+//
+// slot info byte layout
+//
+
+#define CFG_INCOMPLETE 0x80 // configuration is incomplete
+#define CFG_EISA_IOCHKERR 0x02 // support for EISA IOCHKERR signal
+#define CFG_EISA_ENABLE 0x01 // support for disable feature
+
+//
+// function information byte layout
+//
+
+#define CFG_FN_DISABLED 0x80 // function is disabled
+#define CFG_FREE_FORM 0x40 // free-form data
+#define CFG_INI_ENTRY 0x20 // port init entry(s) exists
+#define CFG_PRT_ENTRY 0x10 // port range entry(s) exists
+#define CFG_DMA_ENTRY 0x08 // DMA entry(s) exists
+#define CFG_IRQ_ENTRY 0x04 // IRQ entry(s) exists
+#define CFG_MEM_ENTRY 0x02 // memory entry(s) exists
+#define CFG_ASC_ENTRY 0x01 // type/subtype entry follows
+
+#define CFG_MORE_ENTRY 0x80 // more mem/DMA/int/port entries
+
+//
+// memory configuration byte layout
+//
+
+#define CFG_MEM_RW 0x01 // memory is read/write
+#define CFG_MEM_CACHE 0x02 // enable caching of memory
+#define CFG_MEM_WRBACK 0x04 // cache is write-back
+#define CFG_MEM_TYPE 0x18 // memory type mask
+#define CFG_MEM_SYS 0x00 // base or extended
+#define CFG_MEM_EXP 0x08 // expanded
+#define CFG_MEM_VIR 0x10 // virtual
+#define CFG_MEM_OTHER 0x18 // other
+
+//
+// interrupt configuration byte layout
+//
+
+#define CFG_IRQ_SHARE 0x40 // IRQ is sharable
+#define CFG_IRQ_LEVEL 0x20 // IRQ is level triggered
+#define CFG_IRQ_MASK 0x0F // IRQ mask
+
+//
+// DMA configuration byte layout
+//
+
+#define CFG_DMA_SHARED 0x40 // DMA has to be chared
+#define CFG_DMA_MASK 0x07 // DMA mask
+#define CFG_DMA_CFG_MASK 0x3C // used to mask off the reserved bits
+#define CFG_DMA_TIM_MASK 0x30 // timing mode bits mask
+#define CFG_DMA_ADD_MASK 0x0C // addressing mode bits mask
+
+//
+// init configuration byte layout
+//
+
+#define CFG_INI_PMASK 0x04 // Port value or port and mask value
+#define CFG_INI_MASK 0x03 // Type of access (byte, word or dword)
+#define CFG_INI_BYTE 0x00 // Byte address (8-bit)
+#define CFG_INI_HWORD 0x01 // HalfWord address (16-bit)
+#define CFG_INI_WORD 0x02 // Word address (32-bit)
+
+
+//
+// eisa cfg errors
+//
+
+typedef enum _EISA_CFG_ERROR
+ {
+ CfgNoErrCode,
+ IdTimeout,
+ CfgIdError,
+ CfgMissing,
+ CfgIncomplete,
+ CfgIncorrect,
+ CfgDeviceFailed,
+ CfgMemError,
+ CfgIrqError,
+ CfgDmaError,
+ CfgIniError,
+ OmfRomError,
+ OmfError,
+ MemAllocError,
+ TooManyDeviceError,
+ MaximumValue
+ } EISA_CFG_ERROR;
+
+
+//
+// eisa pod messages index
+//
+
+typedef enum _EISA_CHECKPOINT
+ {
+ EisaPic,
+ EisaDma,
+ EisaNmi,
+ EisaRefresh,
+ EisaPort61,
+ EisaTimer1,
+ EisaTimer2,
+ EisaCfg,
+ EisaHotNmi,
+ EisaPodMaxMsg
+
+ } EISA_CHECKPOINT;
+
+//
+// define pod structure
+//
+
+typedef struct _EISA_CHECKPOINT_INFO
+ {
+ PCHAR Msg; // pod message
+ UCHAR Flags; // control flags
+ // bit 0 = error
+ // bit 1 = fatal
+ // bit 2 = configuration
+ // bit 3 = display pass/error message
+ UCHAR Par; // PARALLEL test number
+ UCHAR SubPar; // PARALLEL subtest number
+ UCHAR Led; // LED test number
+ UCHAR SubLed; // LED subtest number
+
+ } EISA_CHECKPOINT_INFO, *PEISA_CHECKPOINT_INFO;
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// EISA I/O ports
+///////////////////////////////////////////////////////////////////////////////
+
+//
+// PIC
+//
+
+#define PIC1 0x20 // 1st PIC address (0-7 IRQs)
+#define PIC1_MASK 0x21 // 1st PIC mask port (0-7 IRQs)
+#define PIC1_ELCR 0x4D0 // 1st Edge/Level Control Register
+
+#define PIC2 0xA0 // 2nd PIC address (8-15 IRQs)
+#define PIC2_MASK 0xA1 // 2nd PIC mask port (8-15 IRQs)
+#define PIC2_ELCR 0x4D1 // 2nd Edge/Level Control Register
+
+#define EISA_IRQS 16 // # IRQ lines
+
+#define IRQ0 0x00 // 1st IRQ (1st PIC)
+#define IRQ1 0x01 // 2nd IRQ (1st PIC)
+#define IRQ2 0x02 // 3th IRQ (1st PIC)
+#define IRQ3 0x03 // 4th IRQ (1st PIC)
+#define IRQ4 0x04 // 5th IRQ (1st PIC)
+#define IRQ5 0x05 // 6th IRQ (1st PIC)
+#define IRQ6 0x06 // 7th IRQ (1st PIC)
+#define IRQ7 0x07 // 8th IRQ (1st PIC)
+#define IRQ8 0x08 // 9th IRQ (2nd PIC)
+#define IRQ9 0x09 // 10th IRQ (2nd PIC)
+#define IRQ10 0x0A // 11th IRQ (2nd PIC)
+#define IRQ11 0x0B // 12th IRQ (2nd PIC)
+#define IRQ12 0x0C // 13th IRQ (2nd PIC)
+#define IRQ13 0x0D // 14th IRQ (2nd PIC)
+#define IRQ14 0x0E // 15th IRQ (2nd PIC)
+#define IRQ15 0x0F // 16th IRQ (2nd PIC)
+
+#define OCW3_IRR 0x0A // OCW3 command to read the IRR
+#define OCW3_ISR 0x0B // OCW3 command to read the ISR
+#define OCW2_EOI 0x20 // OCW2 non specific EOI
+#define OCW2_SEOI 0x60 // OCW2 specific EOI mask
+
+
+
+//
+// DMA
+//
+
+
+#define EISA_DMAS 8 // # of DMA channels
+
+#define DMA_COUNT_0 0x01 // 16-bit count register
+#define DMA_COUNT_1 0x03 // 16-bit count register
+#define DMA_COUNT_2 0x05 // 16-bit count register
+#define DMA_COUNT_3 0x07 // 16-bit count register
+#define DMA_COUNT_4 0x0C2 // 16-bit count register
+#define DMA_COUNT_5 0x0C6 // 16-bit count register
+#define DMA_COUNT_6 0x0CA // 16-bit count register
+#define DMA_COUNT_7 0x0CE // 16-bit count register
+
+#define DMA_HCOUNT_0 0x0401 // I/O address high word count reg.
+#define DMA_HCOUNT_1 0x0403 // I/O address high word count reg.
+#define DMA_HCOUNT_2 0x0405 // I/O address high word count reg.
+#define DMA_HCOUNT_3 0x0407 // I/O address high word count reg.
+#define DMA_HCOUNT_5 0x04C6 // I/O address high word count reg.
+#define DMA_HCOUNT_6 0x04CA // I/O address high word count reg.
+#define DMA_HCOUNT_7 0x04CE // I/O address high word count reg.
+
+#define DMA_ADDR_0 0x00 // 16-bit address register
+#define DMA_ADDR_1 0x02 // 16-bit address register
+#define DMA_ADDR_2 0x04 // 16-bit address register
+#define DMA_ADDR_3 0x06 // 16-bit address register
+#define DMA_ADDR_4 0x0C0 // 16-bit address register
+#define DMA_ADDR_5 0x0C4 // 16-bit address register
+#define DMA_ADDR_6 0x0C8 // 16-bit address register
+#define DMA_ADDR_7 0x0CC // 16-bit address register
+
+#define DMA_PAGE_0 0x087 // 8-bit address, low page
+#define DMA_PAGE_1 0x083 // 8-bit address, low page
+#define DMA_PAGE_2 0x081 // 8-bit address, low page
+#define DMA_PAGE_3 0x082 // 8-bit address, low page
+#define DMA_PAGE_RFR 0x08F // DMA lo page register refresh
+#define DMA_PAGE_5 0x08B // 8-bit address, low page
+#define DMA_PAGE_6 0x089 // 8-bit address, low page
+#define DMA_PAGE_7 0x08A // 8-bit address, low page
+
+#define DMA_HPAGE_0 0x0487 // I/O address, high page
+#define DMA_HPAGE_1 0x0483 // I/O address, high page
+#define DMA_HPAGE_2 0x0481 // I/O address, high page
+#define DMA_HPAGE_3 0x0482 // I/O address, high page
+#define DMA_HPAGE_RFR 0x048F // DMA hi page register refresh
+#define DMA_HPAGE_5 0x048B // I/O address, high page
+#define DMA_HPAGE_6 0x0489 // I/O address, high page
+#define DMA_HPAGE_7 0x048A // I/O address, high page
+
+#define DMA_STOP_0 0x04E0 // stop register
+#define DMA_STOP_1 0x04E4 // stop register
+#define DMA_STOP_2 0x04E8 // stop register
+#define DMA_STOP_3 0x04EC // stop register
+#define DMA_STOP_5 0x04F4 // stop register
+#define DMA_STOP_6 0x04F8 // stop register
+#define DMA_STOP_7 0x04FC // stop register
+
+// channels 0 to 3
+
+#define DMA_STATUS03 0x08 // status register
+#define DMA_COMMAND03 0x08 // command register
+#define DMA_REQUEST03 0x09 // request register
+#define DMA_1MASK03 0x0A // set/clear one mask reg
+#define DMA_MODE03 0x0B // 6-bit write mode register
+#define DMA_FF_CLR03 0x0C // clear byte pointer flip/flop
+#define DMA_TEMP 0x0D // 8-bit read temporary register
+#define DMA_MASTER_CLR03 0x0D // master clear reg
+#define DMA_MASK_CLR03 0x0E // clear all mask reg bits
+#define DMA_MASKS03 0x0F // write all mask reg bits
+#define DMA_MASK_STAT03 0x0F // mask status register
+#define DMA_CHAIN03 0x040A // chaining mode register
+#define DMA_EXTMODE03 0x040B // extended mode register
+
+// channels 4 to 7
+
+#define DMA_STATUS47 0x0D0 // status register
+#define DMA_COMMAND47 0x0D0 // command register
+#define DMA_REQUEST47 0x0D2 // request register
+#define DMA_1MASK47 0x0D4 // set/clear one mask reg
+#define DMA_MODE47 0x0D6 // 6-bit write mode register
+#define DMA_FF_CLR47 0x0D8 // clear byte pointer flip/flop
+#define DMA_MASTER_CLR47 0x0DA // master clear reg
+#define DMA_MASK_CLR47 0x0DC // clear all mask reg bits
+#define DMA_MASKS47 0x0DE // write all mask reg bits
+#define DMA_MASK_STAT47 0x0DE // mask status register
+#define DMA_CHAIN47 0x04D4 // chaining mode register
+#define DMA_EXTMODE47 0x04D6 // extended mode register
+
+typedef struct _EISA_DMA_REGS_TEST
+ {
+ USHORT Address; // address register
+ USHORT LowPage; // low page register
+ USHORT HighPage; // high page register
+ USHORT LowCount; // low count register
+ USHORT HighCount; // high count register
+ USHORT Stop; // stop count register
+
+ } EISA_DMA_REGS_TEST, *PEISA_DMA_REGS_TEST;
+
+typedef struct _EISA_DMA_CTRL_TEST
+ {
+ USHORT Clear; // clear mask register
+ USHORT MaskAll; // set global mask register
+ USHORT Mask; // set single mask register
+ USHORT MaskStatus; // status mask register
+ USHORT Chain; // chaining register
+
+ } EISA_DMA_CTRL_TEST, *PEISA_DMA_CTRL_TEST;
+
+//
+// Option Boards
+//
+
+
+#define EISA_PRODUCT_ID 0xC80 // word
+#define EXPANSION_BOARD_CTRL_BITS 0xC84 // byte
+#define EISA_IOCHKERR 0x02 // IOCHKERR bit
+#define EISAROMBIT 0x08 // ARC ROM bit
+#define ROMINDEX 0xCB0 // word
+#define ROMREAD 0xCB4 // word
+
+
+//
+// General ports
+//
+
+#define EISA_TIMER1_CTRL 0x43 // interval timer1 ctrl port
+#define EISA_TIMER1_COUNTER0 0x40 // timer1 counter 0
+#define EISA_TIMER1_COUNTER1 0x41 // timer1 counter 1
+#define EISA_TIMER1_COUNTER2 0x42 // timer1 counter 2
+#define EISA_RFR_COUNT 0x12 // refresh count ~15usec
+#define EISA_SPEAKER_CLOCK 1193000 // timer1 counter2 clock
+#define EISA_SPEAKER_FREQ 896 // fw speaker frequence in Hz
+#define EISA_SPEAKER_MAX_FREQ EISA_SPEAKER_CLOCK
+#define EISA_SPEAKER_MIN_FREQ (EISA_SPEAKER_CLOCK/0xFFFF + 1)
+
+#define EISA_TIMER2_CTRL 0x4B // interval timer2 ctrl port
+#define EISA_TIMER2_COUNTER0 0x48 // timer2 counter 0
+#define EISA_TIMER2_COUNTER2 0x4A // timer2 counter 2
+
+// the meaning of EISA_RFR_RETRY is as follow :
+// 35usec ( 15usec * 2) = 35*1000 nsec
+// 3 instructions = read, test, jump (the worst case)
+
+#define EISA_RFR_RETRY ((35*1000)/(3*INSTRUCTION_DELAY))
+
+#define EISA_SYS_CTRL_PORTB 0x61 // System Control Port B
+
+#define EISA_SPEAKER_GATE 0x01 // gate signal for speaker timer
+#define EISA_SPEAKER_TIMER 0x02 // speaker timer on
+#define EISA_PARITY_OFF 0x04 // parity error disabled
+#define EISA_IOCHK_OFF 0x08 // I/O channel check disabled
+#define EISA_REFRESH 0x10 // refresh bit ( bit 4 )
+#define EISA_SPEAKER_OUT 0x20 // speaker output
+#define EISA_IOCHK_STATUS 0x40 // IOCHK# asserted
+#define EISA_PARITY_STATUS 0x80 // parity error
+
+#define EISA_RTC_CTRL 0x70 // real time clock address
+#define EISA_DISABLE_NMI 0x80 // disable nmi bit
+#define RTC_A_REG 0x0A // status reg a
+#define RTC_B_REG 0x0B // status reg b
+#define RTC_C_REG 0x0C // status reg c
+#define RTC_D_REG 0x0D // status reg d
+
+#define EISA_SYS_EXT_NMI 0x461 // ext NMI control and bus reset
+#define EISA_SW_NMI_PORT 0x462 // software NMI generation port
+#define EISA_BUSMASTER_LSTATUS 0x464 // 32-bit bus master status low
+#define EISA_BUSMASTER_HSTATUS 0x465 // 32-bit bus master status high
+
+#define EISA_BUS_RESET 0x01 // bus reset asserted bit
+#define EISA_ENABLE_NMI_IO 0x02 // NMI I/O port bit
+#define EISA_ENABLE_NMI_SAFE 0x04 // Fail-safe NMI bit
+#define EISA_ENABLE_NMI_32 0x08 // 32-bit bus timeout
+#define EISA_NMI_32_CAUSE 0x10 // 0=slave 1=bus master timeout
+#define EISA_NMI_IO_STATUS 0x20 // NMI I/O port status bit
+#define EISA_NMI_32_STATUS 0x40 // 32-bit bus timeout
+#define EISA_NMI_SAFE_STATUS 0x80 // Fail-save NMI status bit
+#define EISA_WAIT_NMI_TEST 500 // usec.
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// Map Descriptor
+//
+// The following map descriptor is used to describe a specific region in
+// memory mapped through an entry/entries within the TLB (CPU) or within
+// the logical to physical table (bus master).
+///////////////////////////////////////////////////////////////////////////////
+
+
+#define TLB_FW_RES 0x00000020 // 0x20 (even + odd)
+#define TLB_BE_SPT 0x0000001C // TLB entry for the BE SPT
+#define BE_SPT_VIR_ADDR 0x70000000 // BE SPT virtual address
+#define TLB_USER 0x0000001E // user TLB entry (0-based)
+#define USER_VIR_ADDR 0x00000000 // user virtual address
+#define TLB_EISA_START TLB_FW_RES // TLB base for EISA descript.
+#define TLB_EISA_END 0x00000060 // last available TLB + 1
+#define TLB_EISA_NUMB TLB_EISA_END - TLB_EISA_START
+#define EISA_VIR_MEM 0x02000000 // start EISA mem virtual addr.
+#define EISA_MEM_BLOCKS 30 // max memory descriptors
+#define BUS_MASTERS 25 // max bus masters number
+
+#define FW_MD_POOL (BUS_MASTERS + TLB_EISA_NUMB + EISA_MEM_BLOCKS)
+
+
+
+typedef struct _FW_MD_FLAGS
+ {
+ ULONG Busy : 1;
+ } FW_MD_FLAGS, *PFW_MD_FLAGS;
+
+typedef struct _LOG_CONTEXT
+ {
+ ULONG LogAddr; // starting logical address
+ ULONG LogNumb; // # entries to map transfer
+ ULONG LogLimit; // logical limit
+ ULONG LogShift; // page shift (0xC=4k, 2^0xC=4k)
+ PVOID BuffVir; // virtual address buffer
+ } LOG_CONTEXT, *PLOG_CONTEXT;
+
+typedef struct _MEM_CONTEXT
+ {
+ //ULONG BusType; // memory bus type
+ ULONG BusNumber; // key of bus type
+ ULONG SlotNumber; // slot number if applicable
+ ULONG Type; // memory type
+ } MEM_CONTEXT, *PMEM_CONTEXT;
+
+typedef struct _EMEM_CONTEXT
+ {
+ ULONG WinRelAddr; // EISA
+ ULONG WinShift; // window size
+ PVOID WinRelAddrCtrl; // window ctrl port (vir.addr.)
+ } EMEM_CONTEXT, PEMEM_CONTEXT;
+
+typedef struct _FW_MD
+ {
+
+ // general fields
+
+ struct _FW_MD * Link; // next entry
+ FW_MD_FLAGS Flags; // map entry flags
+ ULONG Counter; // # entities sharing this entry
+
+ // physical and virtual address (size of page fixed to 4k)
+
+ ULONG PhysAddr; // physical address (4k)
+ ULONG PagOffs; // page offset (within 4k)
+ PVOID VirAddr; // virtual address
+ ULONG Size; // buffer size in bytes
+ ULONG PagNumb; // buffer in 4k pages
+ BOOLEAN Cache; // cache status
+
+ // private section
+
+ union
+ {
+ LOG_CONTEXT l; // logical context
+ MEM_CONTEXT m; // physical memory context
+ EMEM_CONTEXT em; // EISA memory space
+ } u;
+ } FW_MD, *PFW_MD;
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// EISA buses defines
+///////////////////////////////////////////////////////////////////////////////
+
+
+#define EISA_BUSES 1 // number of eisa buses
+
+#ifdef KPW4010
+#define PHYS_0_SLOTS 6 // physical slots (max number)
+#else
+#define PHYS_0_SLOTS 5 // physical slots (max number)
+#endif
+
+#define VIR_0_SLOTS 16 // virtual slots (max number )
+// NOTE: Wait longer for JAZZ.
+//#define EISA_IO_DELAY FwStallExecution(1); // to define !
+#define EISA_IO_DELAY FwStallExecution(4); // to define !
+
+
+// note: the following structs have to be half word aligned
+
+typedef struct _EISA_POD_FLAGS
+ {
+ ULONG IniDone : 1; // POD initialization done
+ ULONG Error : 1; // POD status
+
+ } EISA_POD_FLAGS, *PEISA_POD_FLAGS;
+
+
+typedef struct _EISA_SLOTS_INFO
+ {
+ ULONG PhysSlots; // # of physical slots
+ ULONG VirSlots; // # of virtual slots
+ ULONG SlotCfgMap; // one bit x slot; 1 = slot ok
+
+ } EISA_SLOTS_INFO, *PEISA_SLOTS_INFO;
+
+
+typedef struct _EISA_DMA_FLAGS
+ {
+ UCHAR Busy : 1; // DMA channel busy flag
+ UCHAR Tc : 1; // Terminal count reached
+
+ } EISA_DMA_FLAGS, *PEISA_DMA_FLAGS;
+
+
+typedef struct _EISA_DMA_INFO
+ {
+ EISA_POD_FLAGS Flags; // POD flags
+ EISA_DMA_FLAGS DmaFlags[ EISA_DMAS ]; // DMA status
+ UCHAR DmaExtReg[ EISA_DMAS ]; // DMA extended reg.
+ ULONG TransferAddress[ EISA_DMAS ]; // Logical addresses
+
+ } EISA_DMA_INFO, *PEISA_DMA_INFO;
+
+
+typedef struct _EISA_INT_INFO
+ {
+ EISA_POD_FLAGS Flags; // POD flags
+ USHORT IrqPresent; // IRQ present (1 bit per IRQ)
+ USHORT IrqShareable; // IRQ shareable (1 bit per IRQ)
+ USHORT IrqLevel; // IRQ level (1 bit per IRQ)
+
+ } EISA_INT_INFO, *PEISA_INT_INFO;
+
+
+typedef struct _EISA_PORT_INFO
+ {
+ EISA_POD_FLAGS Flags; // POD flags
+
+ } EISA_PORT_INFO, *PEISA_PORT_INFO;
+
+
+typedef struct _EISA_BUS_INFO
+ {
+ EISA_POD_FLAGS Flags; // Bus Flags
+ PFW_MD IoBusInfo; // EISA I/O bus info
+ PFW_MD MemBusInfo; // EISA memory bus info
+ PEISA_SLOTS_INFO SlotsInfo; // physical slots info
+ PEISA_DMA_INFO DmaInfo; // DMA info struct pointer
+ PEISA_INT_INFO IntInfo; // Interrupts info struct point.
+ PEISA_PORT_INFO PortInfo; // Interrupts info struct point.
+
+ } EISA_BUS_INFO, *PEISA_BUS_INFO;
+
+
+
+
+
+///////////////////////////////////////////////////////////////////////////////
+// EISA call back support
+///////////////////////////////////////////////////////////////////////////////
+
+
+#define STATUS_INT_MASK 0x0000FF01 // Hardware Interrupt Mask
+#define STATUS_IE 0x00000001 // Interrupts enable bit
+#define STATUS_SW0 0x00000100 // Software interrupt
+#define STATUS_SW1 0x00000200 // Software interrupt
+#define STATUS_MCT_ADR 0x00000400 // MCT_ADR interrupt
+#define STATUS_DEVICE 0x00000800 // I/O device interrupt
+#define STATUS_EISA 0x00001000 // EISA device interrupt
+#define STATUS_EISA_NMI 0x00002000 // EISA NMI interrupt
+#define STATUS_EX_TIMER 0x00004000 // Interval timer interrupt
+#define STATUS_IN_TIMER 0x00008000 // Internal timer interrupt
+#define EISA_VECTOR 0x04 // EISA device interrupt vector
+#define EISA_NMI_VECTOR 0x05 // EISA NMI interrupt vector
+
+
+
diff --git a/private/ntos/fw/mips/ioaccess.h b/private/ntos/fw/mips/ioaccess.h
new file mode 100644
index 000000000..e6db7c06b
--- /dev/null
+++ b/private/ntos/fw/mips/ioaccess.h
@@ -0,0 +1,79 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ ioaccess.h
+
+Abstract:
+
+ This file contains the definitions to read and write IO registers.
+
+Author:
+
+ Lluis Abello (lluis) 1-May-91
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#ifndef _IOACCESS
+#define _IOACCESS
+//
+// I/O space read and write macros.
+//
+#ifdef R4000
+#undef READ_REGISTER_UCHAR
+#undef READ_REGISTER_USHORT
+#undef READ_REGISTER_ULONG
+#undef WRITE_REGISTER_UCHAR
+#undef WRITE_REGISTER_USHORT
+#undef WRITE_REGISTER_ULONG
+// #define READ_REGISTER_UCHAR(x) NtReadByte(x)
+// #define READ_REGISTER_USHORT(x) NtReadShort(x)
+// #define READ_REGISTER_ULONG(x) NtReadLong(x)
+// #define WRITE_REGISTER_UCHAR(x, y) NtFlushByteBuffer(x,y)
+// #define WRITE_REGISTER_USHORT(x, y) NtFlushShortBuffer(x,y)
+// #define WRITE_REGISTER_ULONG(x, y) NtFlushLongBuffer(x,y)
+#define READ_REGISTER_UCHAR(x) *(volatile UCHAR * const)(x)
+#define READ_REGISTER_USHORT(x) *(volatile USHORT * const)(x)
+#define READ_REGISTER_ULONG(x) *(volatile ULONG * const)(x)
+
+#define WRITE_REGISTER_UCHAR(x, y) *(volatile UCHAR * const)(x) = y
+#define WRITE_REGISTER_USHORT(x, y) *(volatile USHORT * const)(x) = y
+#define WRITE_REGISTER_ULONG(x, y) *(volatile ULONG * const)(x) = y
+
+#endif //R4000
+
+#ifdef R3000
+#undef READ_REGISTER_UCHAR
+#undef READ_REGISTER_USHORT
+#undef READ_REGISTER_ULONG
+#undef WRITE_REGISTER_UCHAR
+#undef WRITE_REGISTER_USHORT
+#undef WRITE_REGISTER_ULONG
+
+#define READ_REGISTER_UCHAR(x) \
+ *(volatile UCHAR * const)(x)
+
+#define READ_REGISTER_USHORT(x) \
+ *(volatile USHORT * const)(x)
+
+#define READ_REGISTER_ULONG(x) \
+ *(volatile ULONG * const)(x)
+
+#define WRITE_REGISTER_UCHAR(x, y) \
+ *(volatile UCHAR * const)(x) = y; FlushWriteBuffer()
+
+#define WRITE_REGISTER_USHORT(x, y) \
+ *(volatile USHORT * const)(x) = y; FlushWriteBuffer()
+
+#define WRITE_REGISTER_ULONG(x, y) \
+ *(volatile ULONG * const)(x) = y; FlushWriteBuffer()
+#endif //R3000
+#endif //_IOACCESS
diff --git a/private/ntos/fw/mips/ioaccess.s b/private/ntos/fw/mips/ioaccess.s
new file mode 100644
index 000000000..4dae043be
--- /dev/null
+++ b/private/ntos/fw/mips/ioaccess.s
@@ -0,0 +1,119 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ioaccess.s
+
+Abstract:
+
+ This module contains routines to read and write to mapped addresses.
+ These are workarrounds for the R4000 bugs.
+
+Author:
+
+ Lluis Abello (lluis) 15-May-91
+
+Environment:
+
+ ROM Selftest.
+
+Notes:
+
+--*/
+#include "ksmips.h"
+ .text
+ .set noreorder
+ .set noat
+#ifdef R4000
+LEAF_ENTRY(NtFlushByteBuffer)
+ nop
+ nop
+ sb a1,0(a0)
+ nop
+ nop
+ j ra
+ nop
+ .end
+LEAF_ENTRY(NtFlushShortBuffer)
+ nop
+ nop
+ sh a1,0(a0)
+ nop
+ nop
+ j ra
+ nop
+ .end
+LEAF_ENTRY(NtFlushLongBuffer)
+ nop
+ nop
+ sw a1,0(a0)
+ nop
+ nop
+ j ra
+ nop
+ .end
+
+LEAF_ENTRY(NtReadByte)
+ lbu v0,0(a0)
+ nop
+ nop
+ j ra
+ nop
+ .end
+LEAF_ENTRY(NtReadShort)
+ lhu v0,0(a0)
+ nop
+ nop
+ j ra
+ nop
+ .end
+LEAF_ENTRY(NtReadLong)
+ lw v0,0(a0)
+ nop
+ nop
+ j ra
+ nop
+ .end
+#endif
+#ifdef R3000
+
+
+ SBTTL("Flush Write Buffer")
+//++
+//
+// NTSTATUS
+// NtFlushWriteBuffer (
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function flushes the write buffer on the current processor.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// STATUS_SUCCESS.
+//
+//--
+
+ LEAF_ENTRY(FlushWriteBuffer)
+
+ .set noreorder
+ .set noat
+ nop // four nop's are required
+ nop //
+ nop //
+ nop //
+10: //
+ bc0f 10b // if false, write buffer not empty
+ nop
+ j ra // return
+
+ .end FlushWritebuffer
+#endif
diff --git a/private/ntos/fw/mips/iodevice.h b/private/ntos/fw/mips/iodevice.h
new file mode 100644
index 000000000..43f6d04d6
--- /dev/null
+++ b/private/ntos/fw/mips/iodevice.h
@@ -0,0 +1,376 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ iodevice.h
+
+Abstract:
+
+ This module contains definitions to access the
+ IO devices in the jazz system.
+
+Author:
+
+ Lluis Abello (lluis) 03-Jan-1991
+
+Environment:
+
+
+Revision History:
+
+--*/
+#ifndef _IODEVICE_
+#define _IODEVICE_
+
+#ifndef DUO
+#include <jazzprom.h>
+#include <jazzdef.h>
+#else
+#include <duoprom.h>
+#include <duodef.h>
+#endif
+
+#include <jazzserp.h>
+#include <eisa.h> // for the isp interrupt controller init.
+#include <jazzrtc.h>
+
+#ifndef DUO
+#include <ncr53c94.h>
+#else
+#include <ncrc700.h>
+
+#define SCSI_READ_UCHAR(ChipAddr,Register) \
+ (READ_REGISTER_UCHAR (&((ChipAddr)->Register)))
+
+#define SCSI_READ_USHORT(ChipAddr,Register) \
+ (READ_REGISTER_USHORT (&((ChipAddr)->Register)))
+
+#define SCSI_READ_ULONG(ChipAddr,Register) \
+ (READ_REGISTER_ULONG (&((ChipAddr)->Register)))
+
+#define SCSI_WRITE_UCHAR(ChipAddr,Register, Value) \
+ WRITE_REGISTER_UCHAR(&((ChipAddr)->Register), (Value))
+
+#define SCSI_WRITE_USHORT(ChipAddr, Register, Value) \
+ WRITE_REGISTER_USHORT(&((ChipAddr)->Register), (Value))
+
+#define SCSI_WRITE_ULONG(ChipAddr, Register, Value) \
+ WRITE_REGISTER_ULONG(&((ChipAddr)->Register), (Value))
+
+#endif
+
+ARC_STATUS
+FwWaitForDeviceInterrupt(
+ USHORT InterruptMask,
+ ULONG Timeout
+ );
+
+//
+// COM controller register pointer definitions.
+//
+#define SP1_READ ((volatile PSP_READ_REGISTERS) COMPORT1_VIRTUAL_BASE)
+#define SP1_WRITE ((volatile PSP_WRITE_REGISTERS)COMPORT1_VIRTUAL_BASE)
+
+#define SP2_READ ((volatile PSP_READ_REGISTERS) COMPORT2_VIRTUAL_BASE)
+#define SP2_WRITE ((volatile PSP_WRITE_REGISTERS)COMPORT2_VIRTUAL_BASE)
+
+//
+// PARALLEL port write registers.
+//
+typedef struct _PARALLEL_WRITE_REGISTERS {
+ UCHAR Data;
+ UCHAR Invalid;
+ UCHAR Control;
+ } PARALLEL_WRITE_REGISTERS, * PPARALLEL_WRITE_REGISTERS;
+
+//
+// PARALLEL port read Registers
+//
+
+typedef struct _PARALLEL_READ_REGISTERS {
+ UCHAR Data;
+ UCHAR Status;
+ UCHAR Control;
+ } PARALLEL_READ_REGISTERS,* PPARALLEL_READ_REGISTERS;
+
+//
+// PARALLEL controller register pointer definitions.
+//
+
+#define PARALLEL_READ ((volatile PPARALLEL_READ_REGISTERS) PARALLEL_VIRTUAL_BASE)
+#define PARALLEL_WRITE ((volatile PPARALLEL_WRITE_REGISTERS)PARALLEL_VIRTUAL_BASE)
+
+//
+// FLOPPY read registers.
+//
+
+typedef struct _FLOPPY_READ_REGISTERS {
+ UCHAR StatusA;
+ UCHAR StatusB;
+ UCHAR DigitalOutput;
+ UCHAR Reserved1;
+ UCHAR MainStatus;
+ UCHAR Fifo;
+ UCHAR Reserved2;
+ UCHAR DigitalInput;
+ } FLOPPY_READ_REGISTERS, * PFLOPPY_READ_REGISTERS;
+
+//
+// FLOPPY write registers.
+//
+
+typedef struct _FLOPPY_WRITE_REGISTERS {
+ UCHAR StatusA;
+ UCHAR StatusB;
+ UCHAR DigitalOutput;
+ UCHAR Reserved1;
+ UCHAR DataRateSelect;
+ UCHAR Fifo;
+ UCHAR Reserved2;
+ UCHAR ConfigurationControl;
+ } FLOPPY_WRITE_REGISTERS, * PFLOPPY_WRITE_REGISTERS ;
+
+//
+// FLOPPY controller register pointer definitions.
+//
+
+
+#define FLOPPY_READ ((volatile PFLOPPY_READ_REGISTERS)FLOPPY_VIRTUAL_BASE)
+#define FLOPPY_WRITE ((volatile PFLOPPY_WRITE_REGISTERS)FLOPPY_VIRTUAL_BASE)
+
+//
+// SOUND controller register pointer definitions.
+//
+typedef struct _SOUND_REGISTERS {
+ USHORT Control;
+ USHORT Mode;
+} SOUND_REGISTERS,* PSOUND_REGISTERS;
+
+typedef struct _SOUND_CONTROL {
+ USHORT SoundEnable : 1;
+ USHORT Direction : 1;
+ USHORT ChannelInUse : 1;
+ USHORT Reserved1 : 11;
+ USHORT TerminalCountInterrupt : 1;
+ USHORT DeviceInterrupt : 1;
+} SOUND_CONTROL, *PSOUND_CONTROL;
+
+#define DIRECTION_ACQUISITION 0
+#define DIRECTION_PLAYBACK 1
+
+#define CHANNEL2_IN_USE 0
+#define CHANNEL3_IN_USE 1
+
+typedef struct _SOUND_MODE {
+ USHORT Frequency : 2;
+ USHORT Reserved1 : 1;
+ USHORT Resolution : 1;
+ USHORT Reserved2 : 1;
+ USHORT NumberOfChannels : 1;
+ USHORT Reserved3 : 10;
+} SOUND_MODE, *PSOUND_MODE;
+
+#define CHANNEL_MONO 0
+#define CHANNEL_STEREO 1
+
+#define RESOLUTION_16BIT 1
+#define RESOLUTION_8BIT 0
+
+#define FREQUENCY_11KHZ 0
+#define FREQUENCY_22KHZ 1
+#define FREQUENCY_44KHZ 2
+#define FREQUENCY_DISABLED 3
+
+#define SOUND_CONTROL ((volatile PSOUND_REGISTERS) SOUND_VIRTUAL_BASE)
+
+
+//
+// cursor controller register pointer definitions.
+//
+
+#define CURSOR_CONTROLLER ((volatile PCURSOR_REGISTERS) (VIDEO_CURSOR_VIRTUAL_BASE))
+#define VIDEO_CONTROLLER ((volatile PVIDEO_REGISTERS) (VIDEO_CONTROL_VIRTUAL_BASE))
+
+//
+// KEYBOARD write registers.
+//
+typedef struct _KEYBOARD_WRITE_REGISTERS {
+ UCHAR Data;
+ UCHAR Command;
+ } KEYBOARD_WRITE_REGISTERS, * PKEYBOARD_WRITE_REGISTERS;
+
+//
+// KEYBOARD read Registers
+//
+
+typedef struct _KEYBOARD_READ_REGISTERS {
+ UCHAR Data;
+ UCHAR Status;
+ } KEYBOARD_READ_REGISTERS, * PKEYBOARD_READ_REGISTERS;
+
+//
+// KEYBOARD controller register pointer definitions.
+//
+#define KEYBOARD_READ ((volatile PKEYBOARD_READ_REGISTERS) KEYBOARD_VIRTUAL_BASE)
+#define KEYBOARD_WRITE ((volatile PKEYBOARD_WRITE_REGISTERS) KEYBOARD_VIRTUAL_BASE)
+
+//
+// Keyboard circular buffer type definition.
+//
+#define KBD_BUFFER_SIZE 32
+
+typedef struct _KEYBOARD_BUFFER {
+ volatile UCHAR Buffer[KBD_BUFFER_SIZE];
+ volatile UCHAR ReadIndex;
+ volatile UCHAR WriteIndex;
+} KEYBOARD_BUFFER, *PKEYBOARD_BUFFER;
+
+
+#define TIME_OUT 0xdead
+
+//
+// SONIC registers definition.
+//
+typedef struct _SONIC_REGISTER { // Structure to align the registers
+ USHORT Reg;
+ USHORT Fill;
+ } SONIC_REGISTER;
+
+typedef struct _SONIC_REGISTERS {
+ SONIC_REGISTER Command; // 0
+ SONIC_REGISTER DataConfiguration; // 1
+ SONIC_REGISTER ReceiveControl; // 2
+ SONIC_REGISTER TransmitControl; // 3
+ SONIC_REGISTER InterruptMask; // 4
+ SONIC_REGISTER InterruptStatus; // 5
+ SONIC_REGISTER UTDA; // 6
+ SONIC_REGISTER CTDA; // 7
+ SONIC_REGISTER InternalTPS; // 8
+ SONIC_REGISTER InternalTFC; // 9
+ SONIC_REGISTER InternalTSA0; // A
+ SONIC_REGISTER InternalTSA1; // B
+ SONIC_REGISTER InternalTFS; // C
+ SONIC_REGISTER URDA; // D
+ SONIC_REGISTER CRDA; // E
+ SONIC_REGISTER InternalCRBA0; // F
+ SONIC_REGISTER InternalCRBA1; //10
+ SONIC_REGISTER InternalRWBC0; //11
+ SONIC_REGISTER InternalRBWC1; //12
+ SONIC_REGISTER EOBC; //13
+ SONIC_REGISTER URRA; //14
+ SONIC_REGISTER RSA; //15
+ SONIC_REGISTER REA; //16
+ SONIC_REGISTER RRP; //17
+ SONIC_REGISTER RWP; //18
+ SONIC_REGISTER InternalTRBA0; //19
+ SONIC_REGISTER InternalTRBA1; //1A
+ SONIC_REGISTER InternalTBWC0; //1B
+ SONIC_REGISTER InternalTBWC1; //1C
+ SONIC_REGISTER InternalADDR0; //1D
+ SONIC_REGISTER InternalADDR1; //1E
+ SONIC_REGISTER InternalLLFA; //1F
+ SONIC_REGISTER InternalTTDA; //20
+ SONIC_REGISTER CamEntryPtr; //21
+ SONIC_REGISTER CamAddrPort2; //22
+ SONIC_REGISTER CamAddrPort1; //23
+ SONIC_REGISTER CamAddrPort0; //24
+ SONIC_REGISTER CamEnable; //25
+ SONIC_REGISTER CamDscrPtr; //26
+ SONIC_REGISTER CamDscrCount; //27
+ SONIC_REGISTER SiliconRevision; //28
+ SONIC_REGISTER WatchdogTimer0; //29
+ SONIC_REGISTER WatchdogTimer1; //2A
+ SONIC_REGISTER ReceiveSequenceCounter; //2B
+ SONIC_REGISTER CrcErrorTally; //2C
+ SONIC_REGISTER FaeTally; //2D
+ SONIC_REGISTER MissedPacketTally; //2E
+ SONIC_REGISTER InternalMDT; //2F
+// registers 30 to 3F are Test registers and must not be accessed
+// registers nammed "internal" must not be accessed either.
+ } SONIC_REGISTERS, * PSONIC_REGISTERS;
+
+//
+// SONIC register pointer definitions.
+//
+
+#define SONIC ((volatile PSONIC_REGISTERS) NET_VIRTUAL_BASE)
+
+ //
+// NVRAM address definitions.
+//
+#define NVRAM_PAGE0 NVRAM_VIRTUAL_BASE
+#define NVRAM_PAGE1 (NVRAM_VIRTUAL_BASE+0x1000)
+#define NVRAM_PAGE2 (NVRAM_VIRTUAL_BASE+0x2000)
+
+#define READ_ONLY_DISABLE_WRITE 0x6 // clear lower bit of Security register.
+
+//
+// EISA Stuff
+// ***** temp **** this should be replaced by the definition in
+// "ntos\inc\eisa.h" as soon as it is complete.
+//
+
+typedef struct _EISA {
+ UCHAR Dma1Ch0Address; //0x00
+ UCHAR Dma1Ch0Count; //0x01
+ UCHAR Dma1Ch1Address; //0x02
+ UCHAR Dma1Ch1Count; //0x03
+ UCHAR Dma1Ch2Address; //0x04
+ UCHAR Dma1Ch2Count; //0x05
+ UCHAR Dma1Ch3Address; //0x06
+ UCHAR Dma1Ch3Count; //0x07
+ UCHAR Dma1StatusCommand; //0x08
+ UCHAR Dma1Request; //0x09
+ UCHAR Dma1SingleMask; //0x0a
+ UCHAR Dma1Mode; //0x0b
+ UCHAR Dma1ClearBytePointer; //0x0c
+ UCHAR Dma1MasterClear; //0x0d
+ UCHAR Dma1ClearMask; //0x0e
+ UCHAR Dma1AllMask; //0x0f
+ ULONG Fill01; //0x10-13
+ ULONG Fill02; //0x14-17
+ ULONG Fill03; //0x18-1b
+ ULONG Fill04; //0x1c-1f
+ UCHAR Int1Control; //0x20
+ UCHAR Int1Mask; //0x21
+ USHORT Fill10; //0x22-23
+ ULONG Fill11; //0x24
+ ULONG Fill12; //0x28
+ ULONG Fill13; //0x2c
+ ULONG Fill14; //0x30
+ ULONG Fill15; //0x34
+ ULONG Fill16; //0x38
+ ULONG Fill17; //0x3c
+ UCHAR IntTimer1SystemClock; //0x40
+ UCHAR IntTimer1RefreshRequest; //0x41
+ UCHAR IntTimer1SpeakerTone; //0x42
+ UCHAR IntTimer1CommandMode; //0x43
+ ULONG Fill20; //0x44
+ UCHAR IntTimer2FailsafeClock; //0x48
+ UCHAR IntTimer2Reserved; //0x49
+ UCHAR IntTimer2CPUSpeeedCtrl; //0x4a
+ UCHAR IntTimer2CommandMode; //0x4b
+ ULONG Fill30; //0x4c
+ ULONG Fill31; //0x50
+ ULONG Fill32; //0x54
+ ULONG Fill33; //0x58
+ ULONG Fill34; //0x5c
+ UCHAR Fill35; //0x60
+ UCHAR NMIStatus; //0x61
+ UCHAR Fill40; //0x62
+ UCHAR Fill41; //0x63
+ ULONG Fill42; //0x64
+ ULONG Fill43; //0x68
+ ULONG Fill44; //0x6c
+ UCHAR NMIEnable; //0x70
+ }EISA, * PEISA;
+
+#define ISP ((volatile PEISA) EISA_IO_VIRTUAL_BASE)
+
+#define EISA_CONTROL ((volatile PEISA_CONTROL) EISA_IO_VIRTUAL_BASE)
+
+#endif // _IODEVICE_
+
+
diff --git a/private/ntos/fw/mips/j3inter.s b/private/ntos/fw/mips/j3inter.s
new file mode 100644
index 000000000..db9ae9f63
--- /dev/null
+++ b/private/ntos/fw/mips/j3inter.s
@@ -0,0 +1,372 @@
+#if defined(JAZZ) && defined(R3000)
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ j3inter.s
+
+Abstract:
+
+ This module contains the interrupt dispatcher and various interrupt
+ routines for the selftest. The exception dispatcher resides in rom
+ because the BEV bit in the psr is set.
+
+Author:
+
+ Lluis Abello (lluis) 8-May-91
+
+Environment:
+
+ Executes in kernal mode.
+
+
+Revision History:
+
+
+--*/
+#include "led.h"
+#include "ksmips.h"
+#include "trap.h"
+#include "interupt.h"
+#include "jzconfig.h"
+#include "dmaregs.h"
+#include <jazzprom.h>
+//
+// PROM entry point definitions.
+// Define base address of prom entry vector and prom entry macro.
+//
+#define PROM_BASE (KSEG1_BASE | 0x1fc00000)
+#define PROM_ENTRY(x) (PROM_BASE + ((x) * 8))
+
+
+#define PutLedDisplay PROM_ENTRY(14)
+ .globl TimerTicks
+ .data
+InterruptTable: // vector of 8 interrupt handler pointers
+ .word 0:8 // initialy set to zero.
+DeviceIntTable: // vector of 10 device interrupt handler pointers
+ .word 0:10 // initialy set to zero.
+InterruptNotExpectedMsg:
+ .ascii "\r\nInterrupt not expected.\r\n\0"
+#define IntOffset 12
+TimerTicks: // Counter of timer ticks. Decremented by Timer interrupt handler.
+ .word 0
+.text
+ .set noreorder
+ .set noat
+//
+//++
+//ConnectInterrupts
+//
+// Routine Description:
+//
+// This routine initializes the interrupt table with pointers to
+// the interrupt handlers.
+//
+// Handlers for the following interrupts are installed:
+// MCT_ADR Interval Timer
+// Sonic
+// Video
+// Sound
+//
+// It also enables interrupts.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(ConnectInterrupts)
+ //
+ // Initialize the interrupt dispatch table
+ //
+ la t0,InterruptTable // get address of table
+ la t1,DeviceInt // address of routine
+ sw t1,DEVICE_INT*4(t0) // store in table
+ la t1,IntervalTimerInt // get address of routine
+ sw t1,TIMER_INT*4(t0) // store it in table
+ //
+ // Initialize the device interrupt dispatch table
+ //
+ la t0,DeviceIntTable // get address of table
+ la t1,SonicInterrupt // address of handler
+ sw t1,INTR_SRC_LAN(t0) // store in table
+ la t1,VideoInterrupt // address of handler
+ sw t1,INTR_SRC_VIDEO(t0) // store in table
+// la t1,SoundInterrupt // address of handler
+// sw t1,INTR_SRC_SOUND(t0) // store in table
+ //
+ // Initialize the exception dispatch table
+ //
+ li t0,EXCEPTION_JUMP_TABLE // lookup table
+ la t1,InterruptDispatcher // address of interrupt disp
+ sw t1,EXCEPTION_INT(t0) // write in proper entry.
+
+ //
+ // Enable interrupts.
+ //
+ li t0,(1<< PSR_BEV)+(1<<PSR_IEC)+(INT_MASK<<PSR_INTMASK)
+ mtc0 t0,psr
+ nop
+ j ra
+ nop
+ .end ConnectInterrupts
+
+
+//++
+// InterruptDispatcher
+//
+// Routine Description:
+//
+// This routine is called as a result of an interrupt
+// It looks in the interrupt dispatch table for a handler and
+// jumps to it if it founds any.
+// This routine is called from rom. The interrupt handler executes
+// a 'j ra' to go back to the rom code which will execute the rfe.
+//
+//
+//
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+//--
+
+ LEAF_ENTRY (InterruptDispatcher)
+ subu sp,sp,IntFrameSize // make room in the stack
+ sw t0,IntFrameT0(sp) // save temporay registers
+ sw t1,IntFrameT1(sp)
+ sw t2,IntFrameT2(sp)
+ sw t3,IntFrameT3(sp)
+ sw t4,IntFrameT4(sp)
+ sw t5,IntFrameT5(sp)
+ sw t6,IntFrameT6(sp)
+ sw t7,IntFrameT7(sp)
+ sw t8,IntFrameT8(sp)
+ sw t9,IntFrameT9(sp)
+ sw AT,IntFrameAT(sp)
+ sw a0,IntFrameA0(sp)
+ sw a1,IntFrameA1(sp)
+ sw a2,IntFrameA2(sp)
+ sw a3,IntFrameA3(sp)
+ sw v0,IntFrameV0(sp)
+ sw v1,IntFrameV1(sp)
+ sw ra,IntFrameRa(sp)
+ mfc0 t1,cause // get cause register
+ mfc0 t2,psr // get psr register
+ la t0,InterruptTable // get address of interrupt table.
+ and t2,t2,t1 // and them to discard disabled interrupts
+ li t3,0x20 // Index of table
+CheckNextInt:
+ andi t4,t2,(1<<15) // check for interrupt starting with higher priority
+ bne t4,zero,JumpToInterrupt //
+ subu t3,t3,0x4 // Next table index
+ bne t3,zero,CheckNextInt
+ sll t2,t2,1 // shift IntPend field to check next
+JumpToInterrupt: // t3 has the interrupt index
+ addu t0,t0,t3 // add offset to table
+ lw t0,0(t0) // get routine address
+ nop
+ bne t0,zero,GoToHandler
+ nop
+ jal HandlerForNoHandlers
+ ori a0,t3,0xC0 // a0 has the encoded interrupt number
+ j ExitInterrupt
+ nop
+GoToHandler:
+ jal t0
+ nop
+ExitInterrupt:
+ li k0,GOTO_EPC // tell dispatcher to return normally
+ lw ra,IntFrameRa(sp) // restore stack
+ lw t0,IntFrameT0(sp) // restore temporay registers
+ lw t1,IntFrameT1(sp)
+ lw t2,IntFrameT2(sp)
+ lw t3,IntFrameT3(sp)
+ lw t4,IntFrameT4(sp)
+ lw t5,IntFrameT5(sp)
+ lw t6,IntFrameT6(sp)
+ lw t7,IntFrameT7(sp)
+ lw t8,IntFrameT8(sp)
+ lw t9,IntFrameT9(sp)
+ lw AT,IntFrameAT(sp)
+ lw a0,IntFrameA0(sp)
+ lw a1,IntFrameA1(sp)
+ lw a2,IntFrameA2(sp)
+ lw a3,IntFrameA3(sp)
+ lw v0,IntFrameV0(sp)
+ lw v1,IntFrameV1(sp)
+ j ra // return to rom exception dispatch
+ addu sp,sp,IntFrameSize // restore stack
+ .end InterruptDispatcher
+
+//
+//++
+//DeviceInt
+//
+// Routine Description:
+//
+// This routine is called as a result of a Hardware Interrupt 1
+// This is a device interrupt. The routine reads the interrupt
+// source register sand dispatches to the proper interrupt handler
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(DeviceInt)
+ li t0,INTERRUPT_VIRTUAL_BASE // address of interrupt source reg
+ lbu a0,0(t0) // read interrupt
+ la t0, DeviceIntTable // base address of dispatch table.
+ addu t0,t0,a0 // add offset to base
+ lw t0,0(t0) // read handler address
+ nop
+ beq t0,zero,HandlerForNoHandlers// hang diplay something in the led
+ nop
+ j t0 // go to routine.
+ nop
+ .end DeviceInt
+
+
+//++
+//VideoInterrupt
+//
+// Routine Description:
+//
+// This routine is called as a result of a video interrupt.
+// It does nothing is just here no to take a video interrupt as
+// an error.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(VideoInterrupt)
+ j ra // return to caller.
+ nop
+ .end VideoInterrupt
+
+//
+//++
+//IntervalTimerInt
+//
+// Routine Description:
+//
+// This routine is called as a result of a Hardware Interrupt 4
+// This is an Interval timer interrupt. The routine decrements a counter
+// used for timeout.
+// A test that needs timeout facilites must set the number of milliseconds
+// into the TimerTicks variable and poll it until it's zero.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(IntervalTimerInt)
+ la t5,TimerTicks // get address of counter
+ lw t2,0(t5) // read counter
+ li t1,DMA_VIRTUAL_BASE // base address of MCTADR
+ beq t2,zero,NoDecrement
+ lw t1,DmaIntervalTimer(t1) // read register to clear int.
+ addiu t2,t2,-1 // decrement counter by one
+NoDecrement:
+ j ra // return to caller.
+ sw t2,0(t5) // store new counter value
+ .end IntervalTimerInt
+
+//
+//++
+//HandlerForNoHandlers
+//
+// Routine Description:
+//
+// This routine is called when an interrupt is received and no handler
+// as been set for it.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HandlerForNoHandlers)
+ srl t0,a0,4 // get second digit
+ andi t0,t0,0xF
+ slti t1,t0,10
+ bne t1,zero,10f // branch if 0-9
+ addiu t0,t0,0x30 // addjust value
+ addiu t0,t0,0x41-0x30-10 // readjust value if A-F
+10:
+ andi t1,a0,0xF // get less significant digit
+ slti t2,t1,10
+ bne t2,zero,10f // branch if 0-9
+ addiu t1,t1,0x30 // addjust value
+ addiu t1,t1,0x41-0x30-10 // readjust value if A-F
+10:
+ la a0,InterruptNotExpectedMsg // get message address
+ sb t0,IntOffset(a0) // write 1st digit interrupt#
+ jal FwPrint // display error
+ sb t1,IntOffset+1(a0) // write 2nd digit interrupt#
+ li t0,PutLedDisplay // get address of led
+ lui a0,LED_BLINK
+ jal t0
+ ori a0,a0,LED_NOT_INTERRUPT
+ .end HandlerForNoHandlers
+//
+//++
+//DisableInterrupt
+//
+// Routine Description:
+//
+// This routine disables interrupts. By clearing the IEc bit in the psr
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(DisableInterrupts)
+ li t0,(1<< PSR_BEV)
+ mtc0 t0,psr
+ j ra
+ nop
+ .end DisableInterrupts
+#endif //JAZZ && R3000
diff --git a/private/ntos/fw/mips/j3reset.s b/private/ntos/fw/mips/j3reset.s
new file mode 100644
index 000000000..40e7c488d
--- /dev/null
+++ b/private/ntos/fw/mips/j3reset.s
@@ -0,0 +1,1818 @@
+#if defined(JAZZ) && defined(R3000)
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ j3reset.s
+
+Abstract:
+
+ This module is the start of the boot code. This code will
+ be the first run upon reset. It contains the self-test and
+ initialization.
+
+Author:
+
+ Lluis Abello (lluis) 8-Jan-91
+
+Environment:
+
+ Executes in kernal mode.
+
+Notes:
+
+ ***** IMPORTANT *****
+
+ This module must be linked such that it resides in the
+ first page of the rom.
+
+Revision History:
+
+
+ Some code is stolen from johncoop's "reset.s"
+
+--*/
+//
+// include header file
+//
+
+#include "ksmips.h"
+#include <jazzprom.h>
+#include "selfmap.h"
+#include "led.h"
+#include "jzconfig.h"
+#include "dmaregs.h"
+#include "ioaccess.h"
+
+#define PROM_BASE (KSEG1_BASE | 0x1fc00000)
+#define PROM_ENTRY(x) (PROM_BASE + ((x) * 8))
+
+//
+// redifne bal to be a relative branch and link instead of jal as it's
+// defined in kxmips.h
+// The cpp will issue a redefinition warning message.
+//
+#define bal bgezal zero,
+#define DMA_CHANNEL_GAP 0x20 // distance beetwen DMA channels
+
+//
+// create a small sdata section.
+//
+
+.sdata
+.space 4
+
+
+.text
+.set noreorder
+.set noat
+
+
+ .globl ResetVector
+ResetVector:
+
+/*++
+
+Routine Description:
+
+ This routine will provide the jump vectors located
+ at the targets of the processor exception vectors.
+ This routine must be located at the start of ROM which
+ is the location of the reset vector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+
+ //
+ // this instruction must be loaded at location 0 in the
+ // rom. This will appear as BFC00000 to the processor
+ //
+
+ b ResetException
+ nop
+
+ //
+ // This is the jump table for rom routines that other
+ // programs can call. They are placed here so that they
+ // will be unlikely to move.
+ //
+
+ //
+ // This becomes PROM_ENTRY(2) as defined in ntmips.h
+ //
+
+ .align 4
+
+ li k0,MONITOR_LINK_ADDRESS // la k0,MonitorReInit
+ li k1,GLOBAL_DATA_BASE
+ j k0
+ sw $31,0x7C(k1) // save return address
+
+ //
+ // This becomes PROM_ENTRYS(12,13)
+ //
+
+ .align 6
+ nop // entry 8
+ nop
+ nop // entry 9
+ nop
+ b TlbInit // entry 10
+ nop
+
+ nop // entry 11
+ nop
+GetCharJumpInstruction:
+ b GetCharJumpInstruction // entry 12
+ nop
+PutCharJumpInstruction:
+ b PutCharJumpInstruction // entry 13
+ nop
+ b PutLedDisplay // entry 14
+ nop
+GetLineJumpInstruction:
+ b GetLineJumpInstruction // entry 15
+ nop
+PutLineJumpInstruction:
+ b PutLineJumpInstruction // entry 16
+ nop
+ // .word BitMapPointers-LINK_ADDRESS+KSEG0_BASE // entry 17 address of BitmapPointers
+
+nop_opcode: nop // nop opcode to test the icache
+ j ra // return opcode
+
+
+ //
+ // these next vectors should be loaded at BFC00100,BFC00180,
+ // They are for the TLBmiss, and
+ // common exceptions respectively.
+ //
+
+ .align 8
+UserTlbMiss:
+ //
+ // checks if exception occurred in the tlbtest
+ //
+ mfc0 k1,epc // we enter this routine a
+ la k0,TlbTestBegin // load the start address of the
+ // TlbTest code likely to fail
+
+ slt k0,k1,k0 // check if exception happend
+ bne k0,zero,NormalException // on a smaller address
+ la k0,TlbTestEnd // load the end address of the
+ // TlbTest code likely to fail
+ slt k0,k0,k1 // and check if exception happend
+ bne k0,zero,NormalException // on a bigger address
+ nop
+ lui a1,LED_BLINK //
+ bal PutLedDisplay //
+ or a0,a1,a0 //
+
+NormalException:
+ la k0,ExceptionDispatch //
+ mfc0 k1,cause // read cause register
+ j k0 // go to Dispatcher
+ andi k1,k1,0xFF // just execcode field from cause reg.
+ .align 7
+ mfc0 k1,cause // get cause
+ li k0,KSEG1_BASE //
+ sw k1,0(k0) // write cause reg to phys address zero
+ la k0,ExceptionDispatch // get address of Dispatcher
+ j k0 // go to dispatcher
+ andi k1,k1,0xFF // just execcode field from cause reg.
+
+.align 4
+ALTERNATE_ENTRY(MemoryRoutines) // The test code is copied from here to EndMemoryRoutines
+ // into memory to run it cached.
+/*++
+VOID
+WriteAddressTest(
+ StartAddress
+ Size
+ Xor pattern
+ )
+Routine Description:
+
+ This routine will store the address of each location xored with
+ the Pattern into each location.
+
+Arguments:
+
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+ a2 - supplies the pattern to Xor with.
+
+ Note: the values of the arguments are preserved.
+
+Return Value:
+
+ This routine returns no value.
+--*/
+ALTERNATE_ENTRY(MemoryTest) // The monitor calls this
+ LEAF_ENTRY(WriteAddressTest)
+ add t1,a0,a1 // t1 = last address.
+ xor t0,a0,a2 // t0 value to write
+ move t2,a0 // t2=current address
+writeaddress:
+ sw t0,0(t2) // store
+ addiu t2,t2,4 // compute next address
+ xor t0,t2,a2 // next pattern
+ sw t0,0(t2)
+ addiu t2,t2,4 // compute next address
+ xor t0,t2,a2 // next pattern
+ sw t0,0(t2)
+ addiu t2,t2,4 // compute next address
+ xor t0,t2,a2 // next pattern
+ sw t0,0(t2)
+ addiu t2,t2,4 // compute next address
+ bne t2,t1, writeaddress // check for end condition
+ xor t0,t2,a2 // value to write
+ j ra
+ nop
+ .end WriteAddressTest
+ /*++
+VOID
+WriteNoXorAddressTest(
+ StartAddress
+ Size
+ )
+Routine Description:
+
+ This routine will store the address of each location
+ into each location.
+
+Arguments:
+
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+
+ Note: the values of the arguments are preserved.
+
+Return Value:
+
+ This routine returns no value.
+--*/
+ LEAF_ENTRY(WriteNoXorAddressTest)
+ add t1,a0,a1 // t1 = last address.
+ addiu t1,t1,-4
+ move t2,a0 // t2=current address
+writenoXoraddress:
+ sw t2,0(t2) // store first address
+ addiu t2,t2,4 // compute next address
+ sw t2,0(t2) // store first address
+ addiu t2,t2,4 // compute next address
+ sw t2,0(t2) // store first address
+ addiu t2,t2,4 // compute next address
+ sw t2,0(t2) // store
+ bne t2,t1, writenoXoraddress // check for end condition
+ addiu t2,t2,4 // compute next address
+ j ra
+ nop
+ .end WriteNoXorAddressTest
+ /*++
+VOID
+CheckAddressTest(
+ StartAddress
+ Size
+ Xor pattern
+ LedDisplayValue
+ )
+Routine Description:
+
+ This routine will check that each location contains it's address
+ xored with the Pattern as written by WriteAddressTest.
+
+ Note: the values of the arguments are preserved.
+
+Arguments:
+
+ This routine will check that each location contains it's address
+ xored with the Pattern as written by WriteAddressTest. The memory
+ is read cached or non cached according to the address specified by a0.
+ Write address test writes allways KSEG1_ADR=KSEG1_ADR ^ KSEG1_XOR
+ if a0 is in KSEG0 to read the data cached, then the XOR_PATTERN
+ Must be such that:
+ KSEG0_ADR ^ KSEG0_XOR = KSEG1_ADR ^ KSEG1_XOR
+ Examples:
+
+ If XorPattern with which WriteAddressTest was called is KSEG1_PAT
+ and the XorPattern this routine needs is KSEG0_PAT:
+ KSEG1_XOR Written KSEG0_XOR So that
+ 0x00000000 0xA0 0x20000000 0x80 ^ 0x20 = 0xA0
+ 0xFFFFFFFF 0x5F 0xDFFFFFFF 0x80 ^ 0xDF = 0x5F
+ 0x01010101 0xA1 0x21010101 0x80 ^ 0x21 = 0xA1
+
+ Note: the values of the arguments are preserved.
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+ a2 - supplies the pattern to Xor with.
+ a3 - suplies the value to display in the led in case of failure
+
+Return Value:
+
+ This routine returns no value.
+ It will hang displaying the test number if it finds an error
+ and not configured in loop on error.
+
+--*/
+ LEAF_ENTRY(CheckAddressTest)
+ move t3,a0 // t3 first address.
+ add t2,t3,a1 // last address.
+checkaddress:
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail
+ addiu t3,t3,4 // compute next address
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail
+ addiu t3,t3,4 // compute next address
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail
+ addiu t3,t3,4 // compute next address
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail // check last one.
+ addiu t3,t3,4 // compute next address
+ bne t3,t2, checkaddress // check for end condition
+ move v0,zero // set return value to zero.
+ j ra // return a zero to the caller
+PatternFail:
+ //
+ // check if we are in loop on error
+ //
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register
+ lb t0,0(t0) // read register value.
+ li t1,LOOP_ON_ERROR_MASK // get value to compare
+ andi t0,DIAGNOSTIC_MASK // mask diagnostic bits.
+ li v0,PROM_ENTRY(14) // load address of PutLedDisplay
+ beq t1,t0,10f // brnach if loop on error.
+ move s8,a0 // save register a0
+ lui t0,LED_BLINK // get LED blink code
+ jal v0 // Blink LED and hang.
+ or a0,a3,t0 // pass a3 as argument in a0
+10:
+ lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code
+ jal v0 // Set LOOP ON ERROR on LED
+ or a0,a3,t0 // pass a3 as argument in a0
+ b CheckAddressTest // Loop back to test again.
+ move a0,s8 // restoring arguments.
+ .end CheckAddressTest
+ /*++
+VOID
+CheckNoXorAddressTest(
+ StartAddress
+ Size
+ LedDisplayValue
+ )
+Routine Description:
+
+ This routine will check that each location contains it's address
+ xored with the Pattern as written by WriteAddressTest.
+
+Arguments:
+
+ Note: the values of the arguments are preserved.
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+ a2 - supplies the pattern to Xor with.
+ a3 - suplies the value to display in the led in case of failure
+
+Return Value:
+
+ This routine returns no value.
+ It will hang displaying the test number if it finds an error.
+--*/
+ LEAF_ENTRY(CheckNoXorAddressTest)
+ addiu t3,a0,-4 // t3 first address-4
+ add t2,a0,a1 // last address.
+ addiu t2,t2,-8 // adjust
+ move t1,t3 // get copy of t3 just for first check
+checkaddressNX:
+ bne t1,t3,PatternFailNX
+ lw t1,4(t3) // load from first location
+ addiu t3,t3,4 // compute next address
+ bne t1,t3,PatternFailNX
+ lw t1,4(t3) // load from next location
+ addiu t3,t3,4 // compute next address
+ bne t1,t3,PatternFailNX
+ lw t1,4(t3) // load from next location
+ addiu t3,t3,4 // compute next address
+ bne t1,t3,PatternFailNX // check
+ lw t1,4(t3) // load from next location
+ bne t3,t2, checkaddressNX // check for end condition
+ addiu t3,t3,4 // compute next address
+
+ bne t1,t3,PatternFailNX // check last
+ nop
+ j ra // return a zero to the caller
+ move v0,zero //
+PatternFailNX:
+ //
+ // check if we are in loop on error
+ //
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register
+ lb t0,0(t0) // read register value.
+ li t1,LOOP_ON_ERROR_MASK // get value to compare
+ andi t0,DIAGNOSTIC_MASK // mask diagnostic bits.
+ li v0,PROM_ENTRY(14) // load address of PutLedDisplay
+ beq t1,t0,10f // brnach if loop on error.
+ move s8,a0 // save register a0
+ lui t0,LED_BLINK // get LED blink code
+ jal v0 // Blink LED and hang.
+ or a0,a3,t0 // pass a3 as argument in a0
+10:
+ lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code
+ jal v0 // Set LOOP ON ERROR on LED
+ or a0,a3,t0 // pass a3 as argument in a0
+ b CheckNoXorAddressTest // Loop back to test again.
+ move a0,s8 // restoring arguments.
+ .end CheckNoXorAddressTest
+
+ .globl ResetException
+ResetException:
+ .globl _start
+_start:
+/*++
+
+Routine Description:
+
+ This is the handler for the reset exception. It first checks the cause
+ of the exception. If it is an NMI, then control is passed to the
+ exception dispatch routine. Otherwise the machine is initialized.
+
+ 1. Invalidate TLB, and clear coprocessor 0 cause register
+ 2. Map the diagnostic LED, and MCT_ADR control register, zero remaining TLB
+ 3. Test the processor
+ 4. Test the reset state of address chip and then initialize values.
+ 5. Map all of rom, and begin executing code in virtual address space.
+ 6. Perform checksum of ROM
+ 7. Test a small portion of memory. (Test code run from ROM)
+ 8. Test the TLB
+ 9. Copy memory test routines to memory so they can execute faster there.
+ 10. flush and initialize dcache.
+ 11. Test a larger section of memory. (Test code run uncached from memory)
+ 12. Flush and initialize icache.
+ 13. Initialize TlbMiss handler routine.
+ 14. Test Video Memory
+ 15. Copy Selftest image from rom to memory, and call.
+ 16. Copy monitor image from rom to memory, and jump.
+
+Note:
+ This routine must be loaded into the first page of rom.
+ Any routines that are called before jumping to virtual
+ addresses must also be loaded into the first page of rom.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+ //
+ // Initialize cause and status registers.
+ //
+ li t0,(1 << PSR_BEV)
+ mtc0 t0,psr
+ mtc0 zero,cause
+
+ //
+ // Map the 7 segment display
+ //
+MapDisplay:
+ li t0,LED_LO
+ li t1,LED_HI
+ mtc0 t0,entrylo
+ mtc0 t1,entryhi
+ mtc0 zero,index
+ nop
+ tlbwi
+ //
+ // Map also the MCTADR
+ //
+ li t0,(1<<INDEX_INDEX) // tlb index entry 1
+ mtc0 t0,index
+ li t1,DEVICE_LO //
+ li t2,DEVICE_HI //
+ mtc0 t1,entrylo
+ mtc0 t2,entryhi
+ addiu t0,t0,(1<<INDEX_INDEX) // compute next index
+ tlbwi
+
+//
+// Zero the remaining TLB entries.
+//
+ li t1,64*(1<<INDEX_INDEX) // load last tlb index
+ mtc0 zero,entrylo // clear entrylo - Invalid entry
+ li t2,RESV_HI // get VPN on a reserved space
+zerotlb:
+ mtc0 t2,entryhi // clear entryhi
+ mtc0 t0,index // set index
+ addiu t0,t0,(1<<INDEX_INDEX) // compute next index
+ tlbwi
+ bne t0,t1,zerotlb //
+ addiu t2,PAGE_SIZE
+
+ //
+ // Turn off the LED and display that Processor test is starting.
+ //
+ bal PutLedDisplay
+ ori a0,zero,LED_BLANK
+ bal PutLedDisplay
+ ori a0,zero,LED_PROCESSOR_TEST
+//
+// test the processor. Test uses all registers and almost all the instructions
+//
+ProcessorTest:
+ lui a0,0x1234 // a0=0x12340000
+ ori a1,a0,0x4321 // a1=0x12344321
+ add a2,zero,a0 // a2=0x12340000
+ addiu a3,zero,-0x4321 // a3=0xFFFFBCDF
+ subu AT,a2,a3 // AT=0x12344321
+ bne a1,AT,ProcessorError // branch if don't match
+ andi v0,a3,0xFFFF // v0=0x0000BCDF
+ ori v1,v0,0xFFFF // v1=0x0000FFFF
+ sll t0,v1,16 // t0=0xFFFF0000
+ xor t1,t0,v1 // t1=0xFFFFFFFF
+ sra t2,t0,16 // t2=0xFFFFFFFF
+ beq t1,t2,10f // if eq good
+ srl t3,t0,24 // t3=0x000000FF
+ j ProcessorError // if wasn't eq error.
+10: sltu s0,t0,v1 // S0=0 because t0 > v1
+ bgtz s0,ProcessorError // if s0 > zero error
+ or t4,AT,v0 // t4=X
+ bltz s0,ProcessorError // if s0 < zero error
+ nor t5,v0,AT // t5=~X
+ and t6,t4,t5 // t6=0
+ bltzal t6,ProcessorError // if t6 < 0 error. Load ra in any case
+ nop
+RaAddress:
+ la t7,RaAddress- LINK_ADDRESS + RESET_VECTOR // get expected address in ra
+ bne ra,t7,ProcessorError // error if don't mach
+ ori s1,zero,0x100 // load constant
+ mult s1,t3 // 0x100*0xFF
+ mfhi s3 // s3=0
+ mflo s2 // s2=0xFF00
+ blez s3,10f // branch if correct
+ sll s4,t3,zero // move t3 into s4
+ addiu s4,100 // change value in s4 to produce an error
+10: divu s5,s2,s4 // divide 0xFF00/0xFF
+ nop
+ nop
+ mfhi s6 // remainder s6=0
+ bne s5,s1,ProcessorError
+ nop
+ blez s6,10f // branch if no error
+ nop
+ j ProcessorError
+10: sub s7,s5,s4 // s7=1
+ mthi s7
+ mtlo AT
+ xori gp,s5,0x2566 // gp=0x2466
+ move s0,sp // save sp for now
+ srl sp,gp,s7 // sp=0x1233
+ mflo s8 // s8=0x12344321
+ mfhi k0 // k0=1
+ ori k1,zero,16 // k1=16
+ sra k1,s8,k1 // k1=0x1234
+ add AT,sp,k0 // AT=0x1234
+ bne k1,AT,ProcessorError // branch on error
+ nop
+
+//
+// Processor test passed if code gets this far
+// Continuue with test of address chip.
+//
+ b MctadrTest
+
+//
+// processor error routine
+//
+
+ProcessorError:
+ lui a0,LED_BLINK // blink also means that
+ bal PutLedDisplay // the routine hangs.
+ ori a0,LED_PROCESSOR_TEST // displaying this value.
+
+ /*++
+VOID
+PutLedDisplay(
+ a0 - display value.
+ )
+Routine Description:
+
+ This routine will display in the LED the value specified as argument
+ a0.
+
+ This routine must reside in the first page of ROM because it is
+ called before mapping the rom.
+
+Arguments:
+
+ a0 value to display.
+
+Return Value:
+
+ None.
+
+--*/
+ LEAF_ENTRY(PutLedDisplay)
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // load address of display
+LedBlinkLoop:
+ srl t1,a0,16 // get upper bits of a0 in t1
+ srl t3,a0,4 // get test number
+ li t4,LED_LOOP_ERROR //
+ bne t1,t4, DisplayTestID
+ andi t3,t3,0xF // clear other bits.
+ ori t3,t3,LED_DECIMAL_POINT // Set decimal point
+DisplayTestID:
+ li t4,LED_BLINK // check if need to hung
+ beq t1,t4, ShowSubtestID
+ sb t3,0(t0) // write test ID to led.
+ j ra // return to caller.
+ nop
+ShowSubtestID:
+ li t2,LED_DELAY_LOOP // get delay value.
+TestWait:
+ bne t2,zero,TestWait // loop until zero
+ addiu t2,t2,-1 // decrrement counter
+ li t3,LED_DECIMAL_POINT+LED_BLANK //
+ sb t3,0(t0) // write decimal point
+ li t2,LED_DELAY_LOOP/2 // get delay value.
+DecPointWait:
+ bne t2,zero,DecPointWait // loop until zero
+ addiu t2,t2,-1 // decrement counter
+ andi t3,a0,0xF // get subtest number
+ sb t3,0(t0) // write subtest in LED
+ li t2,LED_DELAY_LOOP // get delay value.
+SubTestWait:
+ bne t2,zero,SubTestWait // loop until zero
+ addiu t2,t2,-1 // decrrement counter
+ b LedBlinkLoop // go to it again
+ nop
+ .end PutLedDisplay
+
+/*++
+VOID
+ZeroMemory(
+ ULONG StartAddress
+ ULONG Size
+ );
+Routine Description:
+
+ This routine will zero a range of memory.
+
+Arguments:
+
+ a0 - supplies start of memory
+ a1 - supplies length of memory in bytes
+
+Return Value:
+
+ None.
+
+--*/
+ LEAF_ENTRY(ZeroMemory)
+ add a1,a1,a0 // Compute End address
+ addiu a1,a1,-4 //
+ZeroMemoryLoop:
+ sw zero,0(a0) // zero memory.
+ bne a0,a1,ZeroMemoryLoop // loop until done.
+ addiu a0,a0,4
+ j ra // return
+ nop
+ ALTERNATE_ENTRY(ZeroMemoryEnd)
+ nop
+ .end ZeroMemory
+
+ LEAF_ENTRY(R3000CacheInit)
+/*++
+
+Routine Description:
+
+ This routine will flush the R3000 caches. This is done
+ by setting the isolate cache bit in the status register
+ and then doing partial stores to the cache.
+ This routine should be called with the swapcache bit set
+ to flush the icache.
+ This entire routine should run uncached.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+ //
+ // save status register and then
+ // set isolation bit. This means that operations will
+ // not actually go to memory.
+ //
+ mfc0 t1,psr // get psr
+ li t0,(1 << PSR_ISC) // set isolate cache bit
+ or t0,t1,t0 // or them together
+ mtc0 t0,psr // disable interrupts, isolate cache.
+ nop // wait for data cache isolation
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+ //
+ // by writing partials the caches are invalidated.
+ // these writes don't actually go to memory because
+ // cache is isolated.
+ // write to all cache lines.
+ //
+
+ li t0,KSEG0_BASE // physical address for flushing
+ li t4,DATA_CACHE_SIZE // load size of cache.
+ add t4,t0,t4 // value for end of loop condition
+flushcacheloop:
+ sb zero,0(t0) // flush cache block
+ sb zero,4(t0)
+ sb zero,8(t0)
+ sb zero,12(t0)
+ sb zero,16(t0)
+ sb zero,20(t0)
+ sb zero,24(t0)
+ addu t0,t0,32 // advance flush pointer
+ sltu t1,t0,t4 // check if end of cache.
+ bne zero,t1,flushcacheloop // if ne, more to flush
+ sb zero,-4(t0)
+ nop // wait for store oper. to clear pipe
+ nop
+ nop
+ nop
+ li t0,(1 << PSR_BEV)
+ nop
+ mtc0 t0,psr // unisolate and swap caches back
+ nop // wait for caches to swap back
+ nop
+ nop
+ j ra // return.
+ nop
+ .end R3000CacheInit
+
+ LEAF_ENTRY(R3000ICacheTest)
+/*++
+
+Routine Description:
+
+ This routine will write the Icache with nops plus a return opcode
+ and execute them.
+ This entire routine should run uncached.
+
+Arguments:
+
+ a0 - nop opcode
+ a1 - j ra opcode
+
+Return Value:
+
+ None.
+
+--*/
+
+//
+// Copy nops to memory plus a return opcode, and jump to execute them in cached
+// space.
+//
+
+
+ li t0,KSEG1_BASE+MEMTEST_SIZE // start of tested memory
+ li t1,INSTRUCTION_CACHE_SIZE-4 // size filled with nop opcodes
+ add t1,t1,t0 // last address.
+WriteNop:
+ sw a0,0(t0) // write nop opcode
+ bne t0,t1,WriteNop // check if last
+ addiu t0,t0,4
+ li t1,KSEG0_BASE+MEMTEST_SIZE // address of wirtten nops in cached space
+ j t1 // go to execute cached
+ sw a1,-8(t0) // store return opcode the return
+ // opcode will return to the caller
+ // leave a nop in the delay slot
+ .end R3000ICacheTest
+ /*++
+VOID
+DataCopy(
+ ULONG SourceAddress
+ ULONG DestinationAddress
+ ULONG Length
+ );
+Routine Description:
+
+ This routine will copy data from one location to another
+ Source, destination, and length must be word aligned.
+
+Arguments:
+
+ a0 - supplies source of data
+ a1 - supplies destination of data
+ a2 - supplies length of data in bytes
+
+Return Value:
+
+ None.
+--*/
+ LEAF_ENTRY(DataCopy)
+ add a2,a2,a0 // get last address
+CopyLoop:
+ lw t5,0(a0) // get source of data
+ addiu a0,a0,4 // increment source pointer
+ sw t5,0(a1) // put to dest.
+ bne a0,a2,CopyLoop // loop until address=last address
+ addiu a1,a1,4 // increment destination pointer
+ j ra // return
+ nop
+ALTERNATE_ENTRY(EndMemoryRoutines)
+ nop
+ .end DataCopy
+//++
+//
+// VOID
+// FlushWriteBuffer (
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function flushes the write buffer on the current processor.
+// this routine does the same that NtFlushWriteBuffer except that it
+// doesn't return any value. It's intended to be called just
+// from this module.
+//
+// It must reside in the first page of the ROM.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(FlushWriteBuffer)
+ .set noreorder
+ .set noat
+ nop // four nop's are required
+ nop //
+ nop //
+ nop //
+10: //
+ bc0f 10b // if false, write buffer not empty
+ nop //
+ j ra // return
+ nop
+ .end FlushWritebuffer
+
+RomRemoteSpeedValues:
+ //
+ // This table contains the default values for the remote speed regs.
+ //
+ .byte REMSPEED1 // ethernet
+ .byte REMSPEED2 // SCSI
+ .byte REMSPEED3 // Floppy
+ .byte REMSPEED4 // RTC
+ .byte REMSPEED5 // Kbd/Mouse
+ .byte REMSPEED6 // Serial port
+ .byte 7 // New dev
+ .byte REMSPEED8 // Parallel
+ .byte REMSPEED9 // NVRAM
+ .byte REMSPEED10 // Int src reg
+ .byte REMSPEED11 // PROM
+ .byte REMSPEED12 // Sound
+ .byte 7 // New dev
+ .byte REMSPEED14 // External Eisa latch
+ .align 4
+
+
+
+
+MctadrTest:
+
+//
+// Test the mctadr registers.
+//
+ bal PutLedDisplay
+ ori a0,zero,LED_MCTADR_RESET
+
+//
+// check chip reset values
+//
+
+MctadrReset:
+ li t0,DEVICE_VIRTUAL_BASE // Get base address of MCTADR
+ lw v0,DmaConfiguration(t0) // Check Config reset value
+ li t1,CONFIG_RESET //
+ bne v0,t1,MctadrResetError
+ lw v0,DmaInvalidAddress(t0)
+ lw v1,DmaTranslationBase(t0)
+ bne v0,zero,MctadrResetError// Check LFAR reset value
+ lw v0,DmaTranslationLimit(t0)
+ bne v1,zero,MctadrResetError// Check Ttable base reset value
+ lw v1,DmaRemoteFailedAddress(t0)
+ bne v0,zero,MctadrResetError// Check TT limit reset value
+ lw v0,DmaMemoryFailedAddress(t0)
+ bne v1,zero,MctadrResetError// Check RFAR reset value
+ lw v1,DmaByteMask(t0)
+ bne v0,zero,MctadrResetError// Check MFAR reset value
+ addiu t1,t0,DmaRemoteSpeed0 // address of REM_SPEED 0
+ bne v1,zero,MctadrResetError// Check TT_BMASK reset value
+ addiu t2,t0,DmaRemoteSpeed15 // address of REM_SPEED 15
+ lw v0,0(t1) // read register
+ li t3,REMSPEED_RESET //
+ addiu t1,t1,8 // next register address.
+NextRemSpeed:
+ bne v0,t3,MctadrResetError // Check Rem speed reg reset value
+ lw v0,0(t1) // read next rem speed
+ bne t1,t2,NextRemSpeed
+ addiu t1,t1,8 // next register address.
+ bne v0,t3,MctadrResetError // Check last Rem speed reg reset value
+
+ addiu t1,t0,DmaChannel0Mode // address of CHAN0MODE register
+ addiu t2,t0,DmaChannel7Address// address of DMA_CHAN7ADDR (last reg)
+ lw v0,0(t1) // read register
+ addiu t1,t1,8 // next register address.
+NextChannelReg:
+ bne v0,zero,MctadrResetError// Check channel reg reset value
+ lw v0,0(t1) // read next channel
+ bne t1,t2,NextChannelReg
+ addiu t1,t1,8 // next register address.
+ bne v0,zero,MctadrResetError// Checklast channel reg reset value
+ lw v0,DmaInterruptSource(t0) // read DMA Channel interrupt
+ lw v1,DmaErrortype(t0) // read eisa/ethernet error reg
+ bne v0,zero,MctadrResetError// check Intpend
+ lw v0,DmaRefreshRate(t0)
+ bne v1,zero,MctadrResetError// check Eisa error type reset value
+ li t1,REFRRATE_RESET
+ bne v0,t1,MctadrResetError // check Refresh rate reset value
+ lw v0,DmaSystemSecurity(t0)
+ li t1,SECURITY_RESET
+ bne v0,t1,MctadrResetError // check Security reg reset value
+ lw v0,DmaInterruptAcknowledge(t0) // read register but don't check
+//
+// now perform a register test
+//
+ bal PutLedDisplay
+ ori a0,zero,LED_MCTADR_REG // Next test Led value
+MctadrReg:
+//
+// Check the data path between R4K and Mctadr by writing to Byte mask reg.
+//
+ li t0,DEVICE_VIRTUAL_BASE
+ sw zero,DmaCacheMaintenance(t0) // select cache block zero.
+ li t1,1
+ sw t1,DmaLogicalTag(t0) // Set LFN=zero, Offset=0 , Direction=READ from memory, Valid
+ li t2,0x55555555
+ bal FlushWriteBuffer
+ sw t2,DmaByteMask(t0) // write patten to Byte mask
+ lw v0,DmaByteMask(t0) // read Byte mask
+ sw t1,DmaPhysicalTag(t0) // PFN=0 and Valid
+ bne v0,t2,MctadrRegError //
+ addu t2,t2,t2 // t1=0xAAAAAAAA
+ bal FlushWriteBuffer
+ sw t2,DmaByteMask(t0) // write patten to Byte mask
+ lw v0,DmaByteMask(t0) // read Byte mask
+ li t2,0xFFFFFFFF // expected value
+ bne v0,t2,MctadrRegError // Check byte mask
+ li a0,0xA0000000 // get memory address zero.
+ bal FlushWriteBuffer
+ sw zero,0(a0) // write address zero -> flushes buffers
+ lw v0,DmaByteMask(t0) // read Byte mask
+
+//
+//Initialize mem config to 64MB and Write to some registers
+//
+ li t1,0x17F
+ sw t1,DmaConfiguration(t0) // Init Global Config
+ li t2,0x1555000 //
+ sw t2,DmaTranslationBase(t0)// write to TT BASE
+ li t4,MEMORY_REFRESH_RATE
+ sw t4,DmaRefreshRate(t0) // Initialize REFRESH RATE
+ li t3,0x5550
+ bal FlushWriteBuffer
+ sw t3,DmaTranslationLimit(t0) // write to TT_limit
+ lw v0,DmaConfiguration(t0) // READ GLOBAL CONFIG
+ lw v1,DmaTranslationBase(t0) // read TT BASE
+ bne v0,t1,MctadrRegError // check GLOBAL CONFIG
+ lw v0,DmaTranslationLimit(t0) // read TT_limit
+ bne v1,t2,MctadrRegError // check TT-BASE
+ lw v1,DmaRefreshRate(t0) // Read REFRESH RATE
+ bne v0,t3,MctadrRegError // check TT-LIMIT
+ li t1,0x2AAA000
+ bne v1,t4,MctadrRegError // check REFRESH RATE
+ li t2,0xAAA0
+ sw t1,DmaTranslationBase(t0) // write to TT BASE
+ bal FlushWriteBuffer
+ sw t2,DmaTranslationLimit(t0) // write to TT_limit
+ lw v0,DmaTranslationBase(t0) // read TT BASE
+ lw v1,DmaTranslationLimit(t0) // read TT_limit
+ bne v0,t1,MctadrRegError // check TT-BASE
+ li t1,TT_BASE_ADDRESS // Init translation table base address
+ sw t1,DmaTranslationBase(t0) // Init TT BASE
+ bne v1,t2,MctadrRegError // check TT-LIMIT
+ sw zero,DmaTranslationLimit(t0) // clear TT-limit
+//
+// Initialize remote speed registers.
+//
+ addiu t1,t0,DmaRemoteSpeed1 // address of REM_SPEED 1
+ la a1,RomRemoteSpeedValues - LINK_ADDRESS + RESET_VECTOR //
+ addiu t2,a1,14 // addres of last value
+WriteNextRemSpeed:
+ lbu v0,0(a1) // load init value for rem speed
+ addiu a1,a1,1 // compute next address
+ sw v0,0(t1) // write to rem speed reg
+ bne a1,t2,WriteNextRemSpeed // check for end condition
+ addiu t1,t1,8 // next register address
+ bal FlushWriteBuffer
+ addiu a1,t2,-14 // address of first value for rem speed register
+ addiu t1,t0,DmaRemoteSpeed1 // address of REM_SPEED 1
+ lbu v1,0(a1) // read expected value
+CheckNextRemSpeed:
+ lw v0,0(t1) // read register
+ addiu a1,a1,1 // address of next value
+ bne v0,v1,MctadrRegError // check register
+ addiu t1,t1,8 // address of next register
+ bne a1,t2,CheckNextRemSpeed // check for end condition
+ lbu v1,0(a1) // read expected value
+//
+// Now test the DMA channel registers
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,8*DMA_CHANNEL_GAP // last address of channel regs
+ li a0,0x15 // Mode
+ li a1,0x2 // enable
+ li a2,0xAAAAA // byte count
+ li a3,0x555555 // address
+WriteNextChannel:
+ sw a0,0(t1) // write mode
+ sw a1,0x8(t1) // write enable
+ sw a2,0x10(t1) // write byte count
+ sw a3,0x18(t1) // write address
+ addiu t1,t1,DMA_CHANNEL_GAP // compute address of next channel
+ addiu a2,a2,1 // change addres
+ bne t1,t2,WriteNextChannel
+ addiu a3,a3,-1 // change Byte count
+ bal FlushWriteBuffer // flush
+//
+// Check channel regs.
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,8*DMA_CHANNEL_GAP // last address of channel regs
+ li a2,0xAAAAA // byte count
+ li a3,0x555555 // address
+CheckNextChannel:
+ lw t4,0x0(t1) // read mode
+ lw t5,0x8(t1) // read enable
+ bne t4,a0,MctadrRegError // check mode
+ lw t4,0x10(t1) // read byte count
+ bne t5,a1,MctadrRegError // check enable
+ lw t5,0x18(t1) // read address
+ bne t4,a2,MctadrRegError // check abyte count
+ addiu a2,a2,1 // next expected byte count
+ bne t5,a3,MctadrRegError // check address
+ addiu t1,t1,DMA_CHANNEL_GAP // next channel address
+ bne t1,t2,CheckNextChannel
+ addiu a3,a3,-1
+//
+// Now do a second test on DMA channel registers
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,8*DMA_CHANNEL_GAP // last address of channel regs
+ li a0,0x2A // Mode
+ li a2,0x55555 // byte count
+ li a3,0xAAAAAA // address
+WriteNextChannel2:
+ sw a0,0(t1) // write mode
+ sw a2,0x10(t1) // write byte count
+ sw a3,0x18(t1) // write address
+ addiu t1,t1,DMA_CHANNEL_GAP // compute address of next channel
+ addiu a2,a2,1 // change addres
+ bne t1,t2,WriteNextChannel2
+ addiu a3,a3,-1 // change Byte count
+ bal FlushWriteBuffer // flush
+//
+// Check channel regs.
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,8*DMA_CHANNEL_GAP // last address of channel regs
+ li a2,0x55555 // byte count
+ li a3,0xAAAAAA // address
+CheckNextChannel2:
+ lw t4,0x0(t1) // read mode
+ lw t5,0x10(t1) // read byte count
+ bne t4,a0,MctadrRegError // check mode
+ lw t4,0x18(t1) // read address
+ bne t5,a2,MctadrRegError // check abyte count
+ addiu a2,a2,1 // next expected byte count
+ bne t4,a3,MctadrRegError // check address
+ addiu t1,t1,DMA_CHANNEL_GAP // next channel address
+ bne t1,t2,CheckNextChannel2
+ addiu a3,a3,-1
+//
+// Now zero the channel registers
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,8*DMA_CHANNEL_GAP // last address of channel regs
+ZeroChannelRegs:
+ addiu t1,t1,8
+ bne t1,t2,ZeroChannelRegs
+ sw zero,-8(t1) // clear reg
+ bal FlushWriteBuffer // flush
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,8*DMA_CHANNEL_GAP // last address of channel regs
+CheckZeroedChannelRegs:
+ lw a0,0(t1)
+ addiu t1,t1,8 // next channel
+ bne a0,zero,MctadrRegError // check
+ nop
+ bne t1,t2,CheckZeroedChannelRegs
+ nop
+//
+// Address chip test passed if code reaches this point
+// Skip over error case routines.
+//
+ b MapROM // go for the ROM Checksum
+
+//
+// Address chip error routines.
+//
+
+MctadrRegError:
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register
+ lb t0,0(t0) // read register value.
+ li t1,LOOP_ON_ERROR_MASK // get value to compare
+ andi t0,DIAGNOSTIC_MASK // mask diagnostic bits.
+ li v0,PROM_ENTRY(14) // load address of PutLedDisplay
+ beq t1,t0,10f // branch if loop on error.
+ ori a0,zero,LED_MCTADR_REG // load LED display value.
+ lui t0,LED_BLINK // get LED blink code
+ jal v0 // Blink LED and hang.
+ or a0,a0,t0 // pass argument in a0
+10:
+ lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code
+ jal v0 // Set LOOP ON ERROR on LED
+ or a0,a0,t0 // pass argument in a0
+ b MctadrReg
+ nop
+MctadrResetError:
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register
+ lb t0,0(t0) // read register value.
+ li t1,LOOP_ON_ERROR_MASK // get value to compare
+ andi t0,DIAGNOSTIC_MASK // mask diagnostic bits.
+ li v0,PROM_ENTRY(14) // load address of PutLedDisplay
+ beq t1,t0,10f // branch if loop on error.
+ ori a0,zero,LED_MCTADR_RESET // load LED display value.
+ lui t0,LED_BLINK // get LED blink code
+ jal v0 // Blink LED and hang.
+ or a0,a0,t0 // pass argument in a0
+10:
+ lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code
+ jal v0 // Set LOOP ON ERROR on LED
+ or a0,a0,t0 // pass argument in a0
+ b MctadrReset
+ nop
+
+//
+// Map the rom into the TLB so can run from virtual address space.
+//
+MapROM:
+ bal PutLedDisplay
+ ori a0,zero,LED_ROM_CHECKSUM
+//
+// initialize the TLB to map the whole ROM. This takes 16 or 32 entries.
+//
+ li t0,ROM_LO // entry lo
+ li t1,ROM_HI // entry hi
+ li t2,(1<<INDEX_INDEX) // first index
+ li t3,ROM_TLB_ENTRIES*(1<<INDEX_INDEX) // last index
+RomTlbLoop:
+ mtc0 t2,index
+ mtc0 t0,entrylo
+ mtc0 t1,entryhi
+ addiu t0,PAGE_SIZE // compute next entry lo
+ addiu t1,PAGE_SIZE // compute next entry hi
+ tlbwi // write tlb entry
+ bne t2,t3,RomTlbLoop // check for end of loop
+ addiu t2,(1<<INDEX_INDEX) // compute next index
+
+//
+// now go to the virtual address instead of using the page
+// 1FC00000 that is mapped by the address chip.
+//
+ la t0,Virtual
+ j t0
+ nop
+Virtual:
+//
+// Perform a ROM Checksum.
+//
+ li a0,PROM_VIRTUAL_BASE // address of PROM
+ li t0,ROM_SIZE-8
+ add a1,a0,t0 // end of loop address
+ move t0,zero // init sum register
+RomCheckSum:
+ lw t1,0(a0) // fetch word
+ lw t2,4(a0) // fetch second word
+ addu t0,t0,t1 // calculate checksum
+ addiu a0,a0,8 // compute next address
+ bne a0,a1,RomCheckSum // check end of loop condition
+ addu t0,t0,t2 // calculate checksum
+ lw t1,0(a0) // fetch last word
+ lw t2,4(a0) // fetch expected checksum value
+ addu t0,t0,t1 // calculate checksum
+//
+// if test passes, jump to next part of initialization code.
+//
+ beq t2,t0,TestMemory // Go if calculated checksum is correct
+ lui a0,LED_BLINK // otherwise hang
+ bal PutLedDisplay // by calling PutLedDisplay
+ ori a0,a0,LED_ROM_CHECKSUM // blinking the test number
+
+
+
+//
+// Test the first portion of the memory. Code is fetched from the PROM
+//
+TestMemory:
+ bal PutLedDisplay // call PutLedDisplay to show that
+ ori a0,zero,LED_MEMORY_TEST_1 // Mem test is starting
+
+//
+// Call memory test routine to test small portion of memory.
+// a0 is start of tested memory. a1 is length in bytes to test
+//
+ li a0,KSEG1_BASE // start of mem test test
+ ori a1,zero,MEMTEST_SIZE // length to test in bytes
+ bal WriteNoXorAddressTest
+ move a2,zero // xor pattern zero
+ lui a3,LED_BLINK
+ bal CheckNoXorAddressTest
+ ori a3,LED_MEMORY_TEST_1 // set LED blink in case of Error
+ nop
+//
+// Do the same flipping all bits
+//
+ bal WriteAddressTest
+ li a2,-1 // Xor pattern = FFFFFFFF
+ bal CheckAddressTest
+ nop
+//
+// Do the same flipping some bits to be sure parity bits are flipped in each byte
+//
+ lui a2,0x0101
+ bal WriteAddressTest
+ ori a2,a2,0x0101 // Xor pattern = 01010101
+ bal CheckAddressTest
+ nop
+//
+// Now test the tlb by writing to the tested memory
+//
+//
+// Perform a tlb test. Entries 0-16 are used to map the LED and the ROM the
+// rest are invalid.
+//
+ bal PutLedDisplay // call PutLedDisplay to show that
+ ori a0,zero,LED_TLB_TEST // TLB test is starting
+ li t0,(ROM_TLB_ENTRIES+1)*(1<<INDEX_INDEX) // index of first available entry
+ li t1,TLB_TEST_HI // address in user space
+ li t2,TLB_TEST_LO
+ li t3,KSEG1_BASE | TLB_TEST_PHYS// Kseg1 address of the
+ // same place as the mapped addresses
+ sw t1,0(t3) // store word
+ li t5,64*(1<<INDEX_INDEX) // last index
+ mtc0 t2,entrylo
+NextEntry:
+ mtc0 t0,index
+ mtc0 t1,entryhi
+ nop
+ tlbwi
+TlbTestBegin: // Start of block where tlb misses
+ nop // are not allowed.
+ lw t4,0(t1) // load address from address
+ addiu t0,(1<<INDEX_INDEX) // compute next index
+ bne t4,t1, TlbError //
+ addiu t4,t1,PAGE_SIZE // compute next virtual address
+ sw t4,0(t1) // write next address in address
+ bne t0,t5,NextEntry // check for tlb full
+ move t1,t4 // copy virtual address to map
+TlbTestEnd: // End of block where tlb misses are forbiden
+
+//
+// TLB test passed. If there had been an error, there would have been
+// a trap, and the trap would have jumped to the following TlbError routine.
+// Test passed if code got to here. Go initialize caches.
+//
+ b InitCaches
+ nop
+
+//
+// TLB test failure routine.
+//
+
+TlbError:
+ lui a0,LED_BLINK // if error hang
+ bal PutLedDisplay // while displaying
+ ori a0,LED_TLB_TEST // the test number
+
+
+
+// .globl TlbReInit
+//TlbReInit:
+// la t0,TlbInit - LINK_ADDRESS + RESET_VECTOR
+// j t0
+// nop
+
+ .globl TlbInit
+TlbInit:
+/*++
+
+Routine Description:
+
+ This routine will initialize the TLB for virtual addressing. There
+ will be 6 basic mappings initially until the operating system sets up a
+ full virtual address mapping. Mapped items will include and the virtual
+ mapping will be:
+ main memory A0000000 - A0800000 (uncached)
+ main memory 80000000 - 80800000 (cached)
+ note that these will not be actual entries because they
+ automatically get mapped as kseg[1:0]
+ I/O device E0000000 - E00FFFFF
+ Intr src reg E0100000 - E0100FFF
+ video cntr E0200000 - E0203FFF
+ video memory E0800000 - E0FFFFFF
+ prom space E1000000 - E100FFFF
+ eisa i/o space E2000000 - E2FFFFFF
+ eisa mem space E3000000 - E3FFFFFF
+ reserved E4000000 -
+
+ All other unused TLB entries will be marked invalid using addresses
+ from the reserved region.
+
+ The general algorithm for loading a cache entry is as follows:
+ Load Hi register with virtual address and protection bits.
+ Load Lo[1:0] register with Physical address and protection bits.
+ Load mask register with range of bits to compare with TLB tag.
+ Load Index register to point to TLB entry.
+ Store with a PLBWI instruction.
+
+Note:
+
+ This routine must be loaded in the first page of the rom.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Revision History:
+
+ Added R3000 stuff. Use 16 entries to map 64K of rom and another
+ 16 entries to map I/O space. Next five entries will be used for
+ video controllers, and tlb miss handler will use only entry #37.
+
+
+
+--*/
+
+
+//
+// Prom space
+//
+ li t0,ROM_LO //entrylo
+ li t2,ROM_HI //entryhi
+ li t4,(ROM_TLB_ENTRIES << INDEX_INDEX) // loop count
+ move t5,zero // first index
+rom_tlb:
+ mtc0 t0,entrylo // store entry lo
+ mtc0 t2,entryhi // store entry high
+ mtc0 t5,index // store index
+ addiu t0,t0,(1 << ENTRYLO_PFN) // increment for next page
+ tlbwi // store tlb entry
+ addiu t5,t5,(1<<INDEX_INDEX) // next index
+ bne t4,t5,rom_tlb // exit loop when whole rom mapped
+ addiu t2,t2,(1 << ENTRYHI_VPN) // increment for next page
+//
+// I/O Device space
+//
+ li t0,DEVICE_LO //entrylo
+ li t2,DEVICE_HI //entryhi
+ li t4,((DEVICE_TLB_ENTRIES+ROM_TLB_ENTRIES)<<INDEX_INDEX) // last index
+device_tlb:
+ mtc0 t0,entrylo // store entry lo
+ mtc0 t2,entryhi // store entry high
+ mtc0 t5,index // store index
+ addiu t0,t0,(1 << ENTRYLO_PFN) // increment for next page
+ tlbwi // store tlb entry
+ addiu t5,t5,(1<<INDEX_INDEX) // next index
+ bne t4,t5,device_tlb // exit loop when whole rom mapped
+ addiu t2,t2,(1 << ENTRYHI_VPN) // increment for next page
+//
+// Interrupt source register space
+//
+ li t0,PROC_LO //entrylo
+ li t2,PROC_HI //entryhi
+ mtc0 t0,entrylo // store entry lo
+ mtc0 t2,entryhi // store entry high
+ mtc0 t5,index // store index
+ addiu t5,t5,(1<<INDEX_INDEX) // compute next index
+ tlbwi // store tlb entry
+
+//
+// video register space
+//
+
+ li t0,VID_LO //entrylo
+ li t2,VID_HI //entryhi
+ mtc0 t0,entrylo // store entry lo
+ mtc0 t2,entryhi // store entry high
+ mtc0 t5,index // store index
+ addiu t5,t5,(1<<INDEX_INDEX) // next index
+ tlbwi // store tlb entry
+//
+// cursor register space
+//
+ li t0,CURSOR_LO //entrylo
+ li t2,CURSOR_HI //entryhi
+ mtc0 t0,entrylo // store entry lo
+ mtc0 t2,entryhi // store entry high
+ mtc0 t5,index // store index
+ addiu t5,t5,(1<<INDEX_INDEX) // next free
+ tlbwi // store tlb entry
+//
+// Map the two first pages of video memory to avoid taking traps when
+// displaying on the first line of the screen
+//
+ li t0,VIDMEM_LO //entrylo
+ li t2,VIDMEM_HI //entryhi
+ mtc0 t0,entrylo // store entry lo
+ mtc0 t2,entryhi // store entry high
+ mtc0 t5,index // store index
+ addiu t0,t0,(1 << ENTRYLO_PFN) // second page phys
+ tlbwi // store tlb entry
+ addiu t2,t2,(1 << ENTRYHI_VPN) // second page virt
+ addiu t5,t5,(1<<INDEX_INDEX)
+ mtc0 t0,entrylo
+ mtc0 t2,entryhi
+ mtc0 t5,index
+ addiu t5,t5,(1<<INDEX_INDEX)
+ tlbwi // store tlb entry
+//
+// zero the rest of the unused entries.
+#define RESV ((1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_N))
+ li t0,RESV //entrylo
+ li t2,((RESV_VIRT >> 12) << ENTRYHI_VPN) //entryhi
+ li t4,(64 << INDEX_INDEX) // last entry
+zero_tlb:
+ mtc0 t0,entrylo // store entry lo
+ mtc0 t2,entryhi // store entry high
+ mtc0 t5,index // store index
+ addiu t0,t0,(1 << ENTRYLO_PFN) // increment for next page
+ tlbwi // store tlb entry
+ addiu t5,t5,(1<<INDEX_INDEX)
+ bne t5,t4,zero_tlb
+ addiu t2,t2,(1 << ENTRYHI_VPN) // increment for next page
+ j ra
+ nop
+
+InitCaches:
+//
+// Copy routines to the tested memory at the same offset
+// from the beginning of memory that they are from the beginning of ROM
+// These are, Memory Tests, Zero Memory, PutLedDisplay and DataCopy
+//
+// calculate arguments for DataCopy call
+// a0 is source of data, a1 is dest, a2 is length in bytes
+//
+ la a0,MemoryRoutines // source
+ la a1,MemoryRoutines-LINK_ADDRESS+KSEG1_BASE // destination location
+ la t2,EndMemoryRoutines // end
+ bal DataCopy
+ sub a2,t2,a0 // length of code
+
+//
+// Call Cache initialization routine, run it from memory
+// different routines for R4000 and R3000
+//
+ bal PutLedDisplay
+ ori a0,zero,LED_CACHE_INIT
+ la s1,R3000CacheInit-LINK_ADDRESS+KSEG1_BASE
+ jal s1 // flush data cache
+ li s0, ((1 << PSR_SWC) | (1 << PSR_BEV)) // set bit to swap ic
+ mtc0 s0,psr // and bev
+ nop
+ jal s1 // flush icache
+ nop
+//
+// call routine now in non cached memory to test bigger portion of memory
+//
+ bal PutLedDisplay // display that memory test
+ ori a0,zero,LED_WRITE_MEMORY_2 // is starting
+ li a0,KSEG1_BASE+MEMTEST_SIZE // start of memory to write non cached
+ li a1,ROM_SIZE+STACK_SIZE // test the memory needed to copy the code
+ // to memory and for the stack
+ la s1,WriteNoXorAddressTest-LINK_ADDRESS+KSEG1_BASE // address of routine in memory
+ jal s1 // Write and therefore init mem.
+ move a2,zero // xor pattern
+ la s2,CheckNoXorAddressTest-LINK_ADDRESS+KSEG1_BASE // address of routine in memory
+ jal s2 // Check written memory
+ ori a3,zero,LED_READ_MEMORY_2 // load LED value if memory test fails
+ la s1,WriteAddressTest-LINK_ADDRESS+KSEG1_BASE // address of routine in memory
+ li a0,KSEG0_BASE+MEMTEST_SIZE // start of memory now cached
+ li a2,0xDFFFFFFF // to flipp all bits
+ jal s1 // Write second time now cached.
+ la s2,CheckAddressTest-LINK_ADDRESS+KSEG1_BASE // address of routine in memory
+ jal s2 // check also cached.
+ nop
+ lui a2,0x0101
+ jal s1 // Write third time cached.
+ ori a2,a2,0x0101 // flipping some bits
+ jal s2 // check also cached.
+ nop
+//
+// if we come back, the piece of memory is tested and therefore initialized.
+// The Dcache is also tested.
+// Perform the Icache test now.
+//
+ bal PutLedDisplay // display that the icache test
+ ori a0,zero,LED_ICACHE // is starting
+ la t0,nop_opcode // get address of nop instruction
+ lw a0,0(t0) // fetch nop opcode
+ la t1,R3000ICacheTest-LINK_ADDRESS+KSEG1_BASE // Address of routine in memory
+ jal t1
+ lw a1,4(t0) // fetch j ra opcode.
+//
+// Flush the Icache so that when we run the copy routine cached we
+// don't execute the nops again.
+//
+ li s0, ((1 << PSR_SWC) | (1 << PSR_BEV)) // set bit to swap ic
+ mtc0 s0,psr // and bev
+ la s1,R3000CacheInit-LINK_ADDRESS+KSEG1_BASE
+ jal s1 // flush data cache
+ nop
+//
+// Now Put the entry point of the TLBMiss exception to be able to
+// access the video Memory
+//
+ bal PutLedDisplay // display that the VideoMemory
+ ori a0,zero,LED_VIDEOMEM // is being tested.
+ li t0,EXCEPTION_JUMP_TABLE // base address of table
+ la t1,TLBMiss // address of TLB Miss handler
+ sw t1,8(t0) // use it in User TLB Miss
+ sw t1,12(t0) // and the other TLB exception
+ la t0,TlbInit - LINK_ADDRESS + RESET_VECTOR
+ jal t0 // Init the TLB runing at the ResetVector Page
+ nop
+ bal SizeMemory // Go to size the memory
+ nop // If we return, the global config
+ // is set to the proper configuration.
+//
+// SELFCOPY
+// load addresses to copy and jump to copy in memory routine.
+//
+ bal PutLedDisplay // Display That SelfCopy Starts
+ ori a0,zero,LED_SELFCOPY //
+ la s0,DataCopy-LINK_ADDRESS+KSEG0_BASE// address of copy routine in cached space
+ la a0,end // end of this file = begining of
+ // next.
+ li a1,RAM_TEST_DESTINATION_ADDRESS // destination is linked address.
+ andi t0,a0,0xFFFF // get offset of code address
+ li a2,ROM_SIZE // load size of prom
+ subu a2,a2,t0 // size to copy is rest of prom.
+ jal s0 // jump to copy
+ nop
+ li t0,RAM_TEST_LINK_ADDRESS // load address of code.
+//
+// Initialize the stack to the first page of memory and Call Rom tests
+// if the stack grows to much it will overwrite the MemoryTest routine
+// and PutLedDisplay...
+//
+ li sp,RAM_TEST_STACK_ADDRESS-16 // init stack
+ jal t0 // jump to code in memory
+ nop
+99:
+ b 99b // hang if we get here.
+ nop //
+/*++
+SizeMemory(
+ );
+Routine Description:
+
+ This routine sizes the memory and writes the proper value into
+ the GLOBAL CONFIG register.
+
+ The way memory is sized is the following:
+ The global config is ALREADY set to 64MB
+ for each bank base address i.e 48,32,16,0 MB
+ ID0 is written to offset 0 from base of bank
+ ID4 is written to offseet 4MB from base of bank
+ Data is read from offset 0 then:
+ if ID4 is found the SIMMs at the current bank are 1MB SIMMs
+ and 4MB wrapped to 0MB.
+ if ID0 is found at offset 0 and ID4 is found at offset 4MB,
+ then SIMMs at bank are 4Mb SIMMs.
+ if data does not match or a parity exception is taken
+ then memory is not present in that bank.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the installed memory is inconsistent, does not return
+ and the LED flashes A.E
+
+--*/
+#define MEM_ID0 0x0A0A0A0A
+#define MEM_ID4 0xF5F5F5F5
+ LEAF_ENTRY(SizeMemory)
+ .set noat
+ .set noreorder
+ li t0,EXCEPTION_JUMP_TABLE // get base address of table
+ la t1,DBEHandler // get DBE handler address
+ sw t1,XCODE_DATA_BUS_ERROR(t0) // Install handler in table
+ li t0,0xA3000000 // get address 48MB
+ li t1,MEM_ID0 // get ID0
+ li t2,0xA3400000 // get address 52MB
+ li t3,MEM_ID4 // get ID4
+ li s0,3 // counts how many banks left to check
+ move t8,zero // t8 stores the present banks
+ move t9,zero // t9 stores the size of the banks
+SizeBank:
+ move a1,zero // set current bank to 1 MB by default
+ sw t1,0x0(t0) // fill whole memory line at base of bank
+ sw t1,0x4(t0)
+ sw t1,0x8(t0)
+ sw t1,0xC(t0)
+ sw t3,0x0(t2) // fill whole memory line at base of bank + 4MB
+ sw t3,0x4(t2)
+ sw t3,0x8(t2)
+ sw t3,0xC(t2)
+ //
+ // Check written data
+ //
+ move v1,zero // init v1 to zero
+ .align 4 // align address so that Parity Handler
+ // can easily determine if it happened here
+ExpectedDBE:
+ lw t4,0x0(t0) // read whole memory line.
+ lw t5,0x4(t0) // the four words must be identical
+ lw t6,0x8(t0) //
+ lw t7,0xC(t0) //
+DBEReturnAddress:
+ bne v1,zero,10f // if v1!=0 Parity exception occurred.
+ move a0,zero // tells that bank not present
+ bne t4,t5,10f // check for consistency
+ nop
+ bne t4,t6,10f // check for consistency
+ nop //
+ bne t4,t7,10f // check for consistency
+ nop //
+ beq t4,t3,10f // If ID4 is found at PA 0
+ li a0,0x1 // bank is present and SIMMS are 1 MB
+ bne t4,t1,10f // if neither ID4 nor ID0 is found
+ move a0,zero // no memory in bank
+ li a0,0x1 // bank is present and SIMMS
+ // look like they are 4 MB
+ //
+ // ID written at Address 0 has been correctly checked
+ // Now check the ID written at address 4MB
+ //
+ lw t4,0x0(t2) // read whole memory line.
+ lw t5,0x4(t2) // the four words must be identical
+ bne t3,t4,10f // check for consistency
+ lw t6,0x8(t2) //
+ bne t3,t5,10f // check for consistency
+ lw t7,0xC(t2) //
+ bne t3,t6,10f // check for consistency
+ nop //
+ bne t3,t7,10f // check for consistency
+ nop
+ li a1,0x1 // If all matches SIMMs are 4MB
+10: //
+ // a0 has the value 0 if no memory in bank 1 if memory in bank
+ // a1 has the value 0 if 1MB SIMMS 1 if 4MB SIMMS
+ //
+ or t8,t8,a0 // accummulate present banks
+ or t9,t9,a1 // accummulate size of banks
+ //
+ // Check if last bank
+ //
+ beq s0,zero,Done
+ //
+ // Now set addresses to check next bank
+ //
+ li AT,0x01000000 // load 16MB
+ subu t0,t0,AT // substract to base address
+ subu t2,t2,AT // substract to base address + 4MB
+ sll t8,t8,1 // make room for next bank
+ sll t9,t9,1 // make room for next bank
+ b SizeBank // go to size next memory bank
+ addiu s0,s0,-1 // substract one to the num of banks left
+Done: //
+ // t8 has the present banks in bits 3-0 for banks 3-0
+ // t9 has the size of the banks in bits 3-2 and 1-0
+ //
+ // Check that memory is present in bank zero
+ //
+ andi t0,t8,1
+ beq t0,zero,WrongMemory
+
+ sll t8,t8,2 // shift bank enable bits to bits 5-2
+ andi t9,t9,0x3 // get rid of bits 2-3
+ or t8,t9,t8 // or size of banks with present banks
+ ori v0,t8,0x340 // Set Video RAM size map PROM bit and init timer.
+ li t0,DEVICE_VIRTUAL_BASE // Get base address of MCTADR
+ sw v0,DmaConfiguration(t0) // Store computed Config
+ j ra // return to caller.
+ nop
+WrongMemory:
+ //
+ // Control reaches here if the memory can't be sized.
+ //
+ lui a0,LED_BLINK // Hang
+ bal PutLedDisplay // blinking the error code
+ ori a0,a0,LED_WRONG_MEMORY // in the LED
+ .end SizeMemory
+/*++
+DBEHandler();
+Routine Description:
+
+ This routine is called as a result of a DBE
+ It checks if the exception occurred while sizing the memory
+ if this is the case, it sets v0=1 and returns to the right
+ place.
+
+ If the exception occurred somewhere else, returns to WrongMemory
+ where the error code is displayed in the LED.
+
+Arguments:
+
+ This routine does not preserve the contents of v1
+
+Return Value:
+
+ Returns to the right place to avoid taking the exception again
+
+--*/
+ LEAF_ENTRY(DBEHandler)
+ li k0,DEVICE_VIRTUAL_BASE // get base address of MCTADR
+ lw k1,DmaInterruptSource(k0) // read Interrupt pending register
+ li k0,(1<<8) // mask to test bit 8
+ and k1,k0,k1 // test for parity error
+ beq k1,k0,ParityError // branch if parity error
+ li k0,DEVICE_VIRTUAL_BASE // get base address of MCTADR
+ lw k1,DmaInvalidAddress(k0) // read lfar to clear error
+ b NotExpectedReturn // return
+ nop
+ParityError:
+ lw k1,DmaMemoryFailedAddress(k0) // read MFAR to clear bit 8
+ lw k1,DmaParityDiagnosticLow(k0) // clear error in parity diag reg.
+ mfc0 k0,epc // get address of exception
+ li k1,0xFFFFFFF0 // mask to align address of exception
+ and k0,k1,k0 // align epc
+ la k1,ExpectedDBE // get address where exception is expected
+ beq k0,k1,ExpectedReturn// if equal return
+ nop
+NotExpectedReturn:
+ la k0,WrongMemory // set return address
+ j ra // return to dispatcher
+ nop // which will restore ra and return to K0
+ExpectedReturn:
+ la k0,DBEReturnAddress // set return address
+ j ra // return to dispatcher which will restore ra and return to K0
+ addiu v1,zero,1 // set v1 to 1 to signal exception occurred
+ .end DBEHandler
+
+#endif //JAZZ && R3000
diff --git a/private/ntos/fw/mips/j3trap.s b/private/ntos/fw/mips/j3trap.s
new file mode 100644
index 000000000..2e4f7fabe
--- /dev/null
+++ b/private/ntos/fw/mips/j3trap.s
@@ -0,0 +1,288 @@
+#if defined(JAZZ) && defined(R3000)
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ j3trap.s
+
+Abstract:
+
+ This module will handle exceptions
+ It will save the state of the processor, check jump table
+ to see if it should dispatch somewhere, and then return to
+ monitor.
+
+Author:
+
+ John Cooper (johncoop) 4-Oct-90
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+//
+// include header file
+//
+
+#include "ksmips.h"
+#include "selfmap.h"
+#include "led.h"
+#define PROM_BASE (KSEG1_BASE | 0x1fc00000)
+#define PROM_ENTRY(x) (PROM_BASE + ((x) * 8))
+
+.set noat
+.set noreorder
+.text
+
+
+
+ .globl ExceptionDispatch
+ExceptionDispatch:
+/*++
+
+Routine Description:
+
+ This routine will use a lookup table based on the exception
+ cause, to call an exception handler. If the value in
+ lookup table is zero, the state of the machine is saved,
+ and control is passed to monitor.
+ The return value of the exception handler indicates where
+ control should go when the exception condition is cleared.
+
+Arguments:
+
+ K1 - Contains the cause register.
+
+Return Value:
+
+ None.
+
+--*/
+ //
+ // Need to save return address before calling an exec. handler.
+ //
+
+ li k0,GLOBAL_DATA_BASE // base of saved state
+ sw ra, 0x7C(k0) // save ra
+
+ //
+ // Get jump vector from lookup table based on cause.
+ // Call handler if value is non-zero
+ //
+ li k0,EXCEPTION_JUMP_TABLE // base of jump table
+ addu k0,k0,k1 // add offset to base
+ lw k1,0(k0) // get jump vector from tbl
+ li k0,GOTO_MONITOR // go back to monitor by default
+ beq k1,zero,ExceptionReturn // go save state and call mon.
+ li ra,COMMONEXCEPTION // load this value into ra.
+ // this will get passed as
+ // argument to MonitorInit()
+ // which will then print a message
+ // saying a COMMONEXCEPTION occured.
+ // COMMON EXCEPTION is an unaligned #.
+ // if k1 != zero the jal reloads ra
+ jal k1 // with the right value.
+ nop // control will pass to the
+ // Exception Return routine next.
+ // return value from handler
+ // should be returned in k0.
+ // this is passed as argument
+ // to ExceptionReturn.
+
+ .globl ExceptionReturn
+ExceptionReturn:
+
+/*++
+
+Routine Description:
+
+ This routine will restore any registers that have been modified
+ by the trap handler. Control is then passed back to one
+ of three places. Either the monitor, the location stored in the
+ EPC, or the value supplied in the argumnet k0.
+
+Arguments:
+
+ k0 - supplies indication of where to go after clearing exception.
+ if bits [1:0] are 00B then go to location indicated
+ in k0. if bits [1:0] are GOTO_MONITOR, then control
+ is passed to MonitorReInit(). if bits are GOTO_EPC then
+ control is returned to location where exception occured.
+
+Return Value:
+
+ None.
+
+--*/
+
+
+ //
+ // Return value from exec. handler is in k0.
+ // if low bits are 00, then return to value in k0
+ // if low bits are 01, then return to Err PC
+ // if low bits are 10, then return to monitor
+ //
+ andi k1,k0,3 // k1 = k0 & 3
+ beq k1,zero,returntok0 // go if return code is 0
+ andi k1,k0,GOTO_EPC // k1 = k0 & 1
+ bne k1,zero,returntoEPC // if bit1=1 then GOTO_EPC
+ andi k1,k0,GOTO_MONITOR // k1 = k0 & 2
+ bne k1,zero,returntomonitor // if bit2=1 then GOTO_MONITOR
+ nop
+ b returntomonitor // default return action
+ nop
+returntok0:
+
+ //
+ // restore value to ra
+ //
+
+ li k1,GLOBAL_DATA_BASE // base of saved state
+ lw ra, 0x7C(k1) // restore ra
+
+ //
+ // return to value in k0 when clearing exception condition
+ // do this by putting k0 in EPC
+ //
+ j k0 // return to k0
+ rfe // restore pre-exc state
+returntoEPC:
+
+ //
+ // restore value to ra
+ //
+
+ li k1,GLOBAL_DATA_BASE // base of saved state
+
+ //
+ // return to location where exeception was caused
+ //
+ mfc0 k0,epc // get return PC from cop0
+ lw ra, 0x7C(k1) // restore ra
+ j k0 // jump to (EPC)
+ rfe // clear exception condition
+
+returntomonitor:
+
+ //
+ // return to monitor by calling MonitorReInit()
+ //
+ //li k0,MONITOR_LINK_ADDRESS
+ //j k0
+ //rfe // restore pre-exc state
+ li k0,PROM_ENTRY(14)
+ lui a0,LED_BLINK
+ jal k0
+ ori a0,a0,0xFC
+
+ .globl TLBMiss
+TLBMiss:
+
+/*++
+
+Routine Description:
+
+ This routine will modifiy the TLB when a miss occurs.
+ It will take the failed virtual address and place it
+ in the TLB as a physical address. This will make
+ a one to one mapping between virtual and physical.
+ If the address is E2000000 - E3FFFFFF, then routine
+ will subtract off 52000000 for eisa spaces.
+ This routine is only expected to be used for the R3000
+
+ Note that the control from the exception vector is passed
+ to the dispatch routine. The dispatch routine calls this
+ routine - control is passed back to the dispatch routine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+ //
+ // load bad virtual address - the address that missed in TLB
+ //
+
+ mfc0 k0,badvaddr
+
+ //
+ // mask out page offset to get virtual page number.
+ // offset differs in size between R4000 and R3000
+ //
+
+ li k1,0xFFFFF000
+
+ and k0,k0,k1
+
+ //
+ // store bad virtual address in the EntryHi register to
+ //
+
+ mtc0 k0,entryhi
+
+ //
+ // check if value is between E2000000 - E3FFFFFF
+ // set bits in range (01FFFFFF) and compare to E3FFFFFF
+ //
+
+ li k1,0x01FFFFFF
+ or k0,k0,k1
+ li k1,0xE3FFFFFF
+
+ bne k1,k0,noteisa
+
+ //
+ // subtract off 52000000
+ //
+
+ mfc0 k0,entryhi
+ li k1,0x52000000
+ sub k0,k0,k1
+ nop
+
+noteisa:
+ //
+ // set non-cached, dirty, valid, and global bits
+ //
+ //
+
+ li k1,(1<<ENTRYLO_D) + (1<<ENTRYLO_V) + (1<<ENTRYLO_G) + (1<<ENTRYLO_N)
+ or k0,k0,k1
+ mtc0 k0,entrylo
+
+ //
+ // set index to 63 to write the 63 entry. always replace this
+ // entry to preserve all the other entries.
+ //
+
+ li k0,(63<<INDEX_INDEX)
+ mtc0 k0,index
+ nop
+
+ //
+ // write the tlb entry.
+ //
+
+ tlbwi
+ nop
+
+ //
+ // return from exception - tell dispatch to go to EPC
+ //
+
+ j ra
+ li k0,GOTO_EPC
+
+#endif // R3000 && JAZZ
diff --git a/private/ntos/fw/mips/j4cache.s b/private/ntos/fw/mips/j4cache.s
new file mode 100644
index 000000000..fccf7d98d
--- /dev/null
+++ b/private/ntos/fw/mips/j4cache.s
@@ -0,0 +1,669 @@
+// TITLE("Cache Flush")
+//++
+//
+// Copyright (c) 1991 Microsoft Corporation
+//
+// Module Name:
+//
+// j4cache.s
+//
+// Abstract:
+//
+// This module implements the code necessary for cache operations on
+// a MIPS R4000.
+//
+// Author:
+//
+// David N. Cutler (davec) 19-Dec-1991
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+#include "halmips.h"
+
+//
+// Define cache operations constants.
+//
+
+#define COLOR_BITS (7 << PAGE_SHIFT) // color bit (R4000 - 8kb cache)
+#define COLOR_MASK (0x7fff) // color mask (R4000 - 8kb cache)
+#define FLUSH_BASE 0xfffe0000 // flush base address
+#define PROTECTION_BITS ((1 << ENTRYLO_V) | (1 << ENTRYLO_D)) //
+
+ SBTTL("Export Data From Data Cache")
+//++
+//
+// VOID
+// HalExportDcachePage (
+// IN PVOID Color,
+// IN ULONG PageFrame,
+// IN ULONG Length
+// )
+//
+// Routine Description:
+//
+// This function exports (hit/writeback) up to a page of data from the
+// data cache.
+//
+// Arguments:
+//
+// Color (a0) - Supplies the starting virtual address and color of the
+// data that is exported.
+//
+// PageFrame (a1) - Supplies the page frame number of the page that
+// is exported.
+//
+// Length (a2) - Supplies the length of the region in the page that is
+// exported.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalExportDcachePage)
+
+ .set noreorder
+ .set noat
+ lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy
+ and a0,a0,COLOR_MASK // isolate color and offset bits
+ li t0,FLUSH_BASE // get base flush address
+ or t0,t0,a0 // compute color virtual address
+ sll t1,a1,ENTRYLO_PFN // shift page frame into position
+ or t1,t1,PROTECTION_BITS // merge protection bits
+ or t1,t1,v0 // merge cache policy
+ and a0,a0,0x1000 // isolate TB entry index
+ beql zero,a0,10f // if eq, first entry
+ move t2,zero // set second page table entry
+ move t2,t1 // set second page table entry
+ move t1,zero // set first page table entry
+10: mfc0 t3,wired // get TB entry index
+ lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size
+ lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size
+ bnel zero,v0,15f // if ne, second level cache present
+ move t4,v0 // set flush block size
+ .set at
+ .set reorder
+
+//
+// Export data from the data cache.
+//
+
+15: DISABLE_INTERRUPTS(t5) // disable interrupts
+
+ .set noreorder
+ .set noat
+ mfc0 t6,entryhi // get current PID and VPN2
+ srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
+ sll t7,t7,ENTRYHI_VPN2 //
+ and t6,t6,0xff << ENTRYHI_PID // isolate current PID
+ or t7,t7,t6 // merge PID with VPN2 of virtual address
+ mtc0 t7,entryhi // set VPN2 and PID for probe
+ mtc0 t1,entrylo0 // set first PTE value
+ mtc0 t2,entrylo1 // set second PTE value
+ mtc0 t3,index // set TB index value
+ nop // fill
+ tlbwi // write TB entry - 3 cycle hazzard
+ subu t6,t4,1 // compute block size minus one
+ and t7,t0,t6 // compute offset in block
+ addu a2,a2,t6 // round up to next block
+ addu a2,a2,t7 //
+ nor t6,t6,zero // complement block size minus one
+ and a2,a2,t6 // truncate length to even number
+ beq zero,a2,30f // if eq, no blocks to export
+ and t8,t0,t6 // compute starting virtual address
+ addu t9,t8,a2 // compute ending virtual address
+ bne zero,v0,40f // if ne, second level cache present
+ subu t9,t9,t4 // compute ending loop address
+
+//
+// Export the primary data cache only.
+//
+
+20: cache HIT_WRITEBACK_D,0(t8) // invalidate cache block
+ bne t8,t9,20b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+30: ENABLE_INTERRUPTS(t5)
+
+ j ra // return
+
+
+//
+// Export the primary and secondary data caches.
+//
+
+ .set noreorder
+ .set noat
+40: cache HIT_WRITEBACK_SD,0(t8) // invalidate cache block
+ bne t8,t9,40b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+ ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ j ra // return
+
+ .end HalExportDcachePage
+
+ SBTTL("Flush Data Cache Page")
+//++
+//
+// VOID
+// HalFlushDcachePage (
+// IN PVOID Color,
+// IN ULONG PageFrame,
+// IN ULONG Length
+// )
+//
+// Routine Description:
+//
+// This function flushes (hit/writeback/invalidate) up to a page of data
+// from the data cache.
+//
+// Arguments:
+//
+// Color (a0) - Supplies the starting virtual address and color of the
+// data that is flushed.
+//
+// PageFrame (a1) - Supplies the page frame number of the page that
+// is flushed.
+//
+// Length (a2) - Supplies the length of the region in the page that is
+// flushed.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalFlushDcachePage)
+
+ .set noreorder
+ .set noat
+ lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy
+ and a0,a0,COLOR_MASK // isolate color and offset bits
+ li t0,FLUSH_BASE // get base flush address
+ or t0,t0,a0 // compute color virtual address
+ sll t1,a1,ENTRYLO_PFN // shift page frame into position
+ or t1,t1,PROTECTION_BITS // merge protection bits
+ or t1,t1,v0 // merge cache policy
+ and a0,a0,0x1000 // isolate TB entry index
+ beql zero,a0,10f // if eq, first entry
+ move t2,zero // set second page table entry
+ move t2,t1 // set second page table entry
+ move t1,zero // set first page table entry
+10: mfc0 t3,wired // get TB entry index
+ lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size
+ lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size
+ bnel zero,v0,15f // if ne, second level cache present
+ move t4,v0 // set flush block size
+ .set at
+ .set reorder
+
+//
+// Flush a page from the data cache.
+//
+
+15: DISABLE_INTERRUPTS(t5) // disable interrupts
+
+ .set noreorder
+ .set noat
+ mfc0 t6,entryhi // get current PID and VPN2
+ srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
+ sll t7,t7,ENTRYHI_VPN2 //
+ and t6,t6,0xff << ENTRYHI_PID // isolate current PID
+ or t7,t7,t6 // merge PID with VPN2 of virtual address
+ mtc0 t7,entryhi // set VPN2 and PID for probe
+ mtc0 t1,entrylo0 // set first PTE value
+ mtc0 t2,entrylo1 // set second PTE value
+ mtc0 t3,index // set TB index value
+ nop // fill
+ tlbwi // write TB entry - 3 cycle hazzard
+ subu t6,t4,1 // compute block size minus one
+ and t7,t0,t6 // compute offset in block
+ addu a2,a2,t6 // round up to next block
+ addu a2,a2,t7 //
+ nor t6,t6,zero // complement block size minus one
+ and a2,a2,t6 // truncate length to even number
+ beq zero,a2,30f // if eq, no blocks to flush
+ and t8,t0,t6 // compute starting virtual address
+ addu t9,t8,a2 // compute ending virtual address
+ bne zero,v0,40f // if ne, second level cache present
+ subu t9,t9,t4 // compute ending loop address
+
+//
+// Flush the primary data cache only.
+//
+
+20: cache HIT_WRITEBACK_INVALIDATE_D,0(t8) // invalidate cache block
+ bne t8,t9,20b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+30: ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ j ra // return
+
+//
+// Flush the primary and secondary data caches.
+//
+
+ .set noreorder
+ .set noat
+40: cache HIT_WRITEBACK_INVALIDATE_SD,0(t8) // invalidate cache block
+ bne t8,t9,40b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+ ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ j ra // return
+
+ .end HalFlushDcachePage
+
+ SBTTL("Purge Data Cache Page")
+//++
+//
+// VOID
+// HalPurgeDcachePage (
+// IN PVOID Color,
+// IN ULONG PageFrame,
+// IN ULONG Length
+// )
+//
+// Routine Description:
+//
+// This function purges (hit/invalidate) up to a page of data from the
+// data cache.
+//
+// Arguments:
+//
+// Color (a0) - Supplies the starting virtual address and color of the
+// data that is purged.
+//
+// PageFrame (a1) - Supplies the page frame number of the page that
+// is purged.
+//
+// Length (a2) - Supplies the length of the region in the page that is
+// purged.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalPurgeDcachePage)
+
+ .set noreorder
+ .set noat
+ lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy
+ and a0,a0,COLOR_MASK // isolate color bits
+ li t0,FLUSH_BASE // get base flush address
+ or t0,t0,a0 // compute color virtual address
+ sll t1,a1,ENTRYLO_PFN // shift page frame into position
+ or t1,t1,PROTECTION_BITS // merge protection bits
+ or t1,t1,v0 // merge cache policy
+ and a0,a0,0x1000 // isolate TB entry index
+ beql zero,a0,10f // if eq, first entry
+ move t2,zero // set second page table entry
+ move t2,t1 // set second page table entry
+ move t1,zero // set first page table entry
+10: mfc0 t3,wired // get TB entry index
+ lw v0,KiPcr + PcSecondLevelDcacheFillSize(zero) // get 2nd fill size
+ lw t4,KiPcr + PcFirstLevelDcacheFillSize(zero) // get 1st fill size
+ bnel zero,v0,15f // if ne, second level cache present
+ move t4,v0 // set purge block size
+ .set at
+ .set reorder
+
+//
+// Purge data from the data cache.
+//
+
+15: DISABLE_INTERRUPTS(t5) // disable interrupts
+
+ .set noreorder
+ .set noat
+ mfc0 t6,entryhi // get current PID and VPN2
+ srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
+ sll t7,t7,ENTRYHI_VPN2 //
+ and t6,t6,0xff << ENTRYHI_PID // isolate current PID
+ or t7,t7,t6 // merge PID with VPN2 of virtual address
+ mtc0 t7,entryhi // set VPN2 and PID for probe
+ mtc0 t1,entrylo0 // set first PTE value
+ mtc0 t2,entrylo1 // set second PTE value
+ mtc0 t3,index // set TB index value
+ nop // fill
+ tlbwi // write TB entry - 3 cycle hazzard
+ subu t6,t4,1 // compute block size minus one
+ and t7,t0,t6 // compute offset in block
+ addu a2,a2,t6 // round up to next block
+ addu a2,a2,t7 //
+ nor t6,t6,zero // complement block size minus one
+ and a2,a2,t6 // truncate length to even number
+ beq zero,a2,30f // if eq, no blocks to purge
+ and t8,t0,t6 // compute starting virtual address
+ addu t9,t8,a2 // compute ending virtual address
+ bne zero,v0,40f // if ne, second level cache present
+ subu t9,t9,t4 // compute ending loop address
+
+//
+// Purge the primary data cache only.
+//
+
+20: cache HIT_INVALIDATE_D,0(t8) // invalidate cache block
+ bne t8,t9,20b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+30: ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ j ra // return
+
+//
+// Purge the primary and secondary data caches.
+//
+
+ .set noreorder
+ .set noat
+40: cache HIT_INVALIDATE_SD,0(t8) // invalidate cache block
+ bne t8,t9,40b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+ ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ j ra // return
+
+ .end HalPurgeDcachePage
+
+ SBTTL("Purge Instruction Cache Page")
+//++
+//
+// VOID
+// HalPurgeIcachePage (
+// IN PVOID Color,
+// IN ULONG PageFrame,
+// IN ULONG Length
+// )
+//
+// Routine Description:
+//
+// This function purges (hit/invalidate) up to a page fo data from the
+// instruction cache.
+//
+// Arguments:
+//
+// Color (a0) - Supplies the starting virtual address and color of the
+// data that is purged.
+//
+// PageFrame (a1) - Supplies the page frame number of the page that
+// is purged.
+//
+// Length (a2) - Supplies the length of the region in the page that is
+// purged.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalPurgeIcachePage)
+
+ .set noreorder
+ .set noat
+ lw v0,KiPcr + PcAlignedCachePolicy(zero) // get cache policy
+ and a0,a0,COLOR_MASK // isolate color bits
+ li t0,FLUSH_BASE // get base flush address
+ or t0,t0,a0 // compute color virtual address
+ sll t1,a1,ENTRYLO_PFN // shift page frame into position
+ or t1,t1,PROTECTION_BITS // merge protection bits
+ or t1,t1,v0 // merge cache policy
+ and a0,a0,0x1000 // isolate TB entry index
+ beql zero,a0,10f // if eq, first entry
+ move t2,zero // set second page table entry
+ move t2,t1 // set second page table entry
+ move t1,zero // set first page table entry
+10: mfc0 t3,wired // get TB entry index
+ lw v0,KiPcr + PcSecondLevelIcacheFillSize(zero) // get 2nd fill size
+ lw t4,KiPcr + PcFirstLevelIcacheFillSize(zero) // get 1st fill size
+ bnel zero,v0,15f // if ne, second level cache present
+ move t4,v0 // set purge block size
+ .set at
+ .set reorder
+
+//
+// Purge data from the instruction cache.
+//
+
+15: DISABLE_INTERRUPTS(t5) // disable interrupts
+
+ .set noreorder
+ .set noat
+ mfc0 t6,entryhi // get current PID and VPN2
+ srl t7,t0,ENTRYHI_VPN2 // isolate VPN2 of virtual address
+ sll t7,t7,ENTRYHI_VPN2 //
+ and t6,t6,0xff << ENTRYHI_PID // isolate current PID
+ or t7,t7,t6 // merge PID with VPN2 of virtual address
+ mtc0 t7,entryhi // set VPN2 and PID for probe
+ mtc0 t1,entrylo0 // set first PTE value
+ mtc0 t2,entrylo1 // set second PTE value
+ mtc0 t3,index // set TB index value
+ nop // fill
+ tlbwi // write TB entry - 3 cycle hazzard
+ subu t6,t4,1 // compute block size minus one
+ and t7,t0,t6 // compute offset in block
+ addu a2,a2,t6 // round up to next block
+ addu a2,a2,t7 //
+ nor t6,t6,zero // complement block size minus one
+ and a2,a2,t6 // truncate length to even number
+ beq zero,a2,30f // if eq, no blocks to purge
+ and t8,t0,t6 // compute starting virtual address
+ addu t9,t8,a2 // compute ending virtual address
+ bne zero,v0,40f // if ne, second level cache present
+ subu t9,t9,t4 // compute ending loop address
+
+//
+// Purge the primary instruction cache only.
+//
+
+20: cache HIT_INVALIDATE_I,0(t8) // invalidate cache block
+ bne t8,t9,20b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+30: ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ j ra // return
+
+//
+// Purge the primary and secondary instruction caches.
+//
+
+ .set noreorder
+ .set noat
+40: cache HIT_INVALIDATE_SI,0(t8) // invalidate cache block
+ bne t8,t9,40b // if ne, more blocks to invalidate
+ addu t8,t8,t4 // compute next block address
+ .set at
+ .set reorder
+
+ ENABLE_INTERRUPTS(t5) // enable interrupts
+
+ j ra // return
+
+ .end HalPurgeIcachePage
+
+ SBTTL("Sweep Data Cache")
+//++
+//
+// VOID
+// HalSweepDcache (
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function sweeps (index/writeback/invalidate) the entire data cache.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalSweepDcache)
+
+ lw t0,KiPcr + PcFirstLevelDcacheSize(zero) // get data cache size
+ lw t1,KiPcr + PcFirstLevelDcacheFillSize(zero) // get block size
+ li a0,KSEG0_BASE // set starting index value
+ addu a1,a0,t0 // compute ending cache address
+ subu a1,a1,t1 // compute ending block address
+
+//
+// Sweep the primary data cache.
+//
+
+#if defined(_DUO_)
+
+ DISABLE_INTERRUPTS(t2) // disable interrupts
+
+ .set noreorder
+ .set noat
+10: lw zero,0(a0) // force writeback with load
+ nop // fill
+ nop // fill
+ nop // fill
+ cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // invalidate on index
+ bne a0,a1,10b // if ne, more to invalidate
+ addu a0,a0,t1 // compute address of next block
+
+#else
+
+ .set noreorder
+ .set noat
+10: cache INDEX_WRITEBACK_INVALIDATE_D,0(a0) // writeback/invalidate on index
+ bne a0,a1,10b // if ne, more to invalidate
+ addu a0,a0,t1 // compute address of next block
+
+#endif
+
+ .set at
+ .set reorder
+
+ lw t0,KiPcr + PcSecondLevelDcacheSize(zero) // get data cache size
+ lw t1,KiPcr + PcSecondLevelDcacheFillSize(zero) // get block size
+ beq zero,t1,30f // if eq, no second level cache
+ li a0,KSEG0_BASE // set starting index value
+ addu a1,a0,t0 // compute ending cache address
+ subu a1,a1,t1 // compute ending block address
+
+//
+// Sweep the secondary data cache.
+//
+
+ .set noreorder
+ .set noat
+20: cache INDEX_WRITEBACK_INVALIDATE_SD,0(a0) // writeback/invalidate on index
+ bne a0,a1,20b // if ne, more to invalidate
+ addu a0,a0,t1 // compute address of next block
+ .set at
+ .set reorder
+
+#if defined(_DUO_)
+
+ ENABLE_INTERRUPTS(t2) // enable interrupts
+
+#endif
+
+30: j ra // return
+
+ .end HalSweepDcache
+
+
+ SBTTL("Sweep Instruction Cache")
+//++
+//
+// VOID
+// HalSweepIcache (
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function sweeps (index/invalidate) the entire instruction cache.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalSweepIcache)
+
+ lw t0,KiPcr + PcSecondLevelIcacheSize(zero) // get instruction cache size
+ lw t1,KiPcr + PcSecondLevelIcacheFillSize(zero) // get fill size
+ beq zero,t1,20f // if eq, no second level cache
+ li a0,KSEG0_BASE // set starting index value
+ addu a1,a0,t0 // compute ending cache address
+ subu a1,a1,t1 // compute ending block address
+
+//
+// Sweep the secondary instruction cache.
+//
+
+ .set noreorder
+ .set noat
+10: cache INDEX_INVALIDATE_SI,0(a0) // invalidate cache line
+ bne a0,a1,10b // if ne, more to invalidate
+ addu a0,a0,t1 // compute address of next block
+ .set at
+ .set reorder
+
+20: lw t0,KiPcr + PcFirstLevelIcacheSize(zero) // get instruction cache size
+ lw t1,KiPcr + PcFirstLevelIcacheFillSize(zero) // get fill size
+ li a0,KSEG0_BASE // set starting index value
+ addu a1,a0,t0 // compute ending cache address
+ subu a1,a1,t1 // compute ending block address
+
+//
+// Sweep the primary instruction cache.
+//
+
+ .set noreorder
+ .set noat
+30: cache INDEX_INVALIDATE_I,0(a0) // invalidate cache line
+ bne a0,a1,30b // if ne, more to invalidate
+ addu a0,a0,t1 // compute address of next block
+ .set at
+ .set reorder
+
+ j ra // return
+
+ .end HalSweepIcache
diff --git a/private/ntos/fw/mips/j4inter.s b/private/ntos/fw/mips/j4inter.s
new file mode 100644
index 000000000..45072f85a
--- /dev/null
+++ b/private/ntos/fw/mips/j4inter.s
@@ -0,0 +1,514 @@
+#if defined(JAZZ) && defined(R4000)
+
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ j4inter.s
+
+Abstract:
+
+ This module contains the interrupt dispatcher and various interrupt
+ routines for the selftest. The exception dispatcher resides in rom
+ because the BEV bit in the psr is set.
+
+Author:
+
+ Lluis Abello (lluis) 8-May-91
+
+Environment:
+
+ Executes in kernal mode.
+
+
+Revision History:
+
+
+--*/
+#include "led.h"
+#include "ksmips.h"
+#include "selfmap.h"
+#include "dmaregs.h"
+
+#ifdef DUO
+#include <duoprom.h>
+#else
+#include <jazzprom.h>
+#endif
+
+//
+// PROM entry point definitions.
+// Define base address of prom entry vector and prom entry macro.
+//
+#define PROM_BASE (KSEG1_BASE | 0x1fc00000)
+#define PROM_ENTRY(x) (PROM_BASE + ((x) * 8))
+
+#define PutLedDisplay PROM_ENTRY(14)
+#ifdef DUO
+//
+// Interrupt indexes in the cause register
+//
+#define SOFT0_INT 0 // software int 0
+#define SOFT1_INT 1 // software int 1
+#define DMA_INT 2 // hardware int 0
+#define DEVICE_INT 3 // hardware int 1
+#define EISA_INT 4 // hardware int 2
+#define TIMER_INT 5 // hardware int 3
+#define IP_INT 6 // hardware int 4
+#define R400_TIMER_INT 7 // hardware int 5
+
+#else
+
+//
+// Interrupt indexes in the cause register
+//
+#define SOFT0_INT 0 // software int 0
+#define SOFT1_INT 1 // software int 1
+#define DMA_INT 2 // hardware int 0
+#define DEVICE_INT 3 // hardware int 1
+#define EISA_INT 4 // hardware int 2
+#define EISA_NMI_INT 5 // hardware int 3
+#define TIMER_INT 6 // hardware int 4
+#define R400_TIMER_INT 7 // hardware int 5
+
+#endif
+//
+// Interrupt mask, to enable just the desired interrupts.
+//
+
+#define INT_MASK ((1<<TIMER_INT) | (1<<DEVICE_INT))
+
+//
+// Stack frame offset definitions.
+//
+#define IntFrameT0 0x4
+#define IntFrameT1 0x8
+#define IntFrameT2 0xC
+#define IntFrameT3 0x10
+#define IntFrameT4 0x14
+#define IntFrameT5 0x18
+#define IntFrameT6 0x1C
+#define IntFrameT7 0x20
+#define IntFrameT8 0x24
+#define IntFrameT9 0x28
+#define IntFrameAT 0x2C
+#define IntFrameRa 0x30
+#define IntFrameA0 0x34
+#define IntFrameA1 0x38
+#define IntFrameA2 0x3C
+#define IntFrameA3 0x40
+#define IntFrameV0 0x44
+#define IntFrameV1 0x48
+#define IntFrameSize 0x50
+
+
+ .data
+FwSavedK1Address:
+ .space 4 // address where to save exception return address.
+InterruptTable: // vector of 8 interrupt handler pointers
+ .word 0:8 // initialy set to zero.
+DeviceIntTable: // vector of 10 device interrupt handler pointers
+ .word 0:10 // initialy set to zero.
+InterruptNotExpectedMsg:
+ .ascii "Interrupt not expected.\r\n\0"
+#define IntOffset 10
+.globl TimerTicks
+TimerTicks: // Counter of timer ticks. Decremented by TimerInterrupt handler.
+ .word 0
+
+ .text
+ .set noreorder
+ .set noat
+//
+//++
+//ConnectInterrupts
+//
+// Routine Description:
+//
+// This routine initializes the interrupt table with pointers to
+// the interrupt handlers.
+//
+// Handlers for the following interrupts are installed:
+// MCT_ADR Interval Timer
+// Sonic
+// Video
+//
+// It also enables interrupts.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(ConnectInterrupts)
+//
+// Initialize the interrupt dispatch table
+//
+ la t0,InterruptTable // get address of table
+ la t1,DeviceInt // address of routine
+ sw t1,DEVICE_INT*4(t0) // store in table
+ la t1,IntervalTimerInt // get address of routine
+ sw t1,TIMER_INT*4(t0) // store it in table
+ la t1,R4000TimerInt // get address of routine
+ sw t1,R400_TIMER_INT*4(t0) // store it in table
+//
+// Initialize the device interrupt dispatch table
+//
+ la t0,DeviceIntTable // get address of table
+ la t1,SonicInterrupt // address of handler
+ sw t1,ETHERNET_DEVICE(t0) // store in table
+ la t1,VideoInterrupt // address of handler
+ sw t1,VIDEO_DEVICE(t0) // store in table
+//
+// Initialize the exception dispatch table
+//
+ li t0,KSEG1_BASE // lookup table
+ la t1,SelftestExceptionHandler // address of Exception Handler
+ sw t1,0x1014(t0)// write in firmware vector
+
+//
+// read the interrupt pending register a few times to clear
+// interrupts.
+//
+ li t0,INTERRUPT_VIRTUAL_BASE
+ lbu zero,0(t0)
+ lbu zero,0(t0)
+ lbu zero,0(t0)
+//
+// Enable interrupts.
+//
+
+ li t0,(1<< PSR_BEV)+(1<<PSR_IE)+(INT_MASK<<PSR_INTMASK)+(1 << PSR_CU1)
+ mtc0 t0,psr
+ nop
+ nop
+ nop
+ j ra // return to caller
+ nop
+ .end ConnectInterrupts
+ //++
+// SelftestExceptionHandler
+//
+// Routine Description:
+//
+// This routine is called as a result of an exception
+// If the exception is an interrupt it calls the interrupt handler
+// otherwise it jumps to the monitor.
+// This routine is called using the firmware exception handling convection.
+// It must return to k1 and put the address where to return from
+// the exception in k0.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+ LEAF_ENTRY (SelftestExceptionHandler)
+ la k0,FwSavedK1Address //
+ sw k1,0(k0) // save fw return address
+ mfc0 k0,cause // get cause register
+ li k1,R4000_XCODE_MASK // get mask to extract cause of exception
+ and k0,k1 // get cause of exception
+ beq k0,zero,10f // if 0 is an interrupt.
+ la k0,MonitorExceptionHandler // otherwise
+ j k0 // Jump to the Monitor
+ ori k1,zero,COMMON_EXCEPTION // signal that a common exception occurred.
+10:
+ la k0,InterruptDispatcher // call interrupt dispatcher
+ j k0
+ nop
+ ALTERNATE_ENTRY(ExceptionReturn)
+ la k0,FwSavedK1Address //
+ lw k1,0(k0) // load fw return address
+ mfc0 k0,epc // set address where to return from exception
+ j k1 // jump to firmware
+ nop
+ .end SelftestExceptionHandler
+
+ //++
+// InterruptDispatcher
+//
+// Routine Description:
+//
+// This routine is called as a result of an interrupt
+// It looks in the interrupt dispatch table for a handler and
+// jumps to it if it founds any.
+// This routine is called from rom. The interrupt handler must return
+// to k1 and put the address where to return from the exception in k0.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+ LEAF_ENTRY (InterruptDispatcher)
+ subu sp,sp,IntFrameSize // make room in the stack
+ sw t0,IntFrameT0(sp) // save temporay registers
+ sw t1,IntFrameT1(sp)
+ sw t2,IntFrameT2(sp)
+ sw t3,IntFrameT3(sp)
+ sw t4,IntFrameT4(sp)
+ sw t5,IntFrameT5(sp)
+ sw t6,IntFrameT6(sp)
+ sw t7,IntFrameT7(sp)
+ sw t8,IntFrameT8(sp)
+ sw t9,IntFrameT9(sp)
+ sw AT,IntFrameAT(sp)
+ sw a0,IntFrameA0(sp)
+ sw a1,IntFrameA1(sp)
+ sw a2,IntFrameA2(sp)
+ sw a3,IntFrameA3(sp)
+ sw v0,IntFrameV0(sp)
+ sw v1,IntFrameV1(sp)
+ sw ra,IntFrameRa(sp)
+ mfc0 t1,cause // get cause register
+ mfc0 t2,psr // get psr register
+ la t0,InterruptTable // get address of interrupt table.
+ and t2,t2,t1 // and them to discard disabled interrupts
+ li t3,0x20 // Index for dispatch table
+CheckNextInt:
+ andi t4,t2,(1<<15) // check for interrupt starting
+ bne t4,zero,JumpToInterrupt // with higher priority
+ subu t3,t3,0x4 // Next table index
+ bne t3,zero,CheckNextInt
+ sll t2,t2,1 // shift IntPend field to check next
+JumpToInterrupt: // t3 has the interrupt index
+ addu t0,t0,t3 // add offset to table
+ lw t0,0(t0) // get routine address
+ nop
+ bne t0,zero,GoToHandler
+ nop
+ jal HandlerForNoHandlers
+ ori a0,t3,0xC0 // a0 has the encoded interrupt number
+ j ExitInterrupt
+ nop
+GoToHandler:
+ jal t0
+ nop
+ExitInterrupt:
+ lw ra,IntFrameRa(sp) // restore stack
+ lw t0,IntFrameT0(sp) // restore temporay registers
+ lw t1,IntFrameT1(sp)
+ lw t2,IntFrameT2(sp)
+ lw t3,IntFrameT3(sp)
+ lw t4,IntFrameT4(sp)
+ lw t5,IntFrameT5(sp)
+ lw t6,IntFrameT6(sp)
+ lw t7,IntFrameT7(sp)
+ lw t8,IntFrameT8(sp)
+ lw t9,IntFrameT9(sp)
+ lw AT,IntFrameAT(sp)
+ lw a0,IntFrameA0(sp)
+ lw a1,IntFrameA1(sp)
+ lw a2,IntFrameA2(sp)
+ lw a3,IntFrameA3(sp)
+ lw v0,IntFrameV0(sp)
+ lw v1,IntFrameV1(sp)
+ b ExceptionReturn // branch to return from exception
+ addu sp,sp,IntFrameSize // restore stack
+ .end InterruptDispatcher
+ //
+//++
+//DeviceInt
+//
+// Routine Description:
+//
+// This routine is called as a result of a Hardware Interrupt 1
+// This is a device interrupt. The routine reads the interrupt
+// source register and dispatches to the proper interrupt handler
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+ LEAF_ENTRY(DeviceInt)
+ li t0,INTERRUPT_VIRTUAL_BASE // address of interrupt source reg
+ lbu a0,0(t0) // read interrupt
+ la t0, DeviceIntTable // base address of dispatch table.
+ addu t0,t0,a0 // add offset to base
+ lw t0,0(t0) // read handler address
+ nop
+ beq t0,zero,HandlerForNoHandlers// hang diplay something in the led
+ nop
+ j t0 // go to routine.
+ nop
+ .end DeviceInt
+
+ //++
+//VideoInterrupt
+//
+// Routine Description:
+//
+// This routine is called as a result of a video interrupt.
+// It does nothing is just here no to take a video interrupt as
+// an error.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+ LEAF_ENTRY(VideoInterrupt)
+ j ra // return to caller.
+ nop
+ .end VideoInterrupt
+ //
+//++
+//IntervalTimerInt
+//
+// Routine Description:
+//
+// This routine is called as a result of a Hardware Interrupt 4
+// This is an MCTADR IntervalTimer interrupt. The routine decrements
+// a counter used for timeouts during the self-test.
+// A test that needs timeout facilites must set the number of milliseconds
+// into the TimerTicks variable and poll it until it's zero.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+ LEAF_ENTRY(IntervalTimerInt)
+ la t5,TimerTicks // get address of counter
+ lw t2,0(t5) // read counter
+ li t1,DMA_VIRTUAL_BASE // base address of MCTADR
+ beq t2,zero,NoDecrement
+#ifdef DUO
+ lw t1,DmaTimerInterruptAcknowledge(t1)
+#else
+ lw t1,DmaIntervalTimer(t1) // read register to clear int.
+#endif
+ addiu t2,t2,-1 // decrement counter by one
+NoDecrement:
+ sw t2,0(t5) // store new counter value
+ j ra // return to caller.
+ nop
+ .end IntervalTimerInt
+ //
+//++
+//R4000 TimerInt
+//
+// Routine Description:
+//
+// This routine is called as a result of an R4000 timer Interrupt
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+ LEAF_ENTRY(R4000TimerInt)
+ li t0,1000
+ mtc0 t0,compare // clear interrupt
+ j ra // return to caller.
+ nop
+ .end R4000TimerInt
+//
+//++
+//HandlerForNoHandlers
+//
+// Routine Description:
+//
+// This routine is called when an interrupt is received and no handler
+// has been set for it.
+// It displays a message and then hangs blinking the error code
+// in the LED.
+//
+// Arguments:
+//
+// a0 has the interrupt value.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HandlerForNoHandlers)
+ srl t0,a0,4 // get second digit
+ andi t0,t0,0xF
+ slti t1,t0,10
+ bne t1,zero,10f // branch if 0-9
+ addiu t0,t0,0x30 // addjust value
+ addiu t0,t0,0x41-0x30-10 // readjust value if A-F
+10:
+ andi t1,a0,0xF // get less significant digit
+ slti t2,t1,10
+ bne t2,zero,10f // branch if 0-9
+ addiu t1,t1,0x30 // addjust value
+ addiu t1,t1,0x41-0x30-10 // readjust value if A-F
+10:
+ la a0,InterruptNotExpectedMsg // get message address
+ sb t0,IntOffset(a0) // write to digit interrupt #
+ sb t1,IntOffset+1(a0) // into message
+ li a1,0 // column 0
+ jal FwPrint // display error
+ li a2,1 // row 0
+ li t0,PutLedDisplay // get address of led
+ lui a0,LED_BLINK
+ jal t0
+ ori a0,a0,LED_NOT_INTERRUPT
+ .end HandlerForNoHandlers
+//
+//++
+//DisableInterrupt
+//
+// Routine Description:
+//
+// This routine disables interrupts. By clearing the IEc bit in the psr
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(DisableInterrupts)
+ li t0,(1<< PSR_BEV) | (1 << PSR_CU1)
+ mtc0 t0,psr
+ nop
+ nop
+ nop
+ nop
+ j ra
+ nop
+ .end DisableInterrupts
+#endif //R4000 && JAZZ
diff --git a/private/ntos/fw/mips/j4reset.h b/private/ntos/fw/mips/j4reset.h
new file mode 100644
index 000000000..4a543dc5c
--- /dev/null
+++ b/private/ntos/fw/mips/j4reset.h
@@ -0,0 +1,115 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ j4reset.h
+
+Abstract:
+
+ This module defines various parameters for the reset module.
+
+Author:
+
+ Lluis Abello (lluis) 10-Jan-1991
+
+Revision History:
+
+--*/
+
+#ifndef _J4RESET_
+#define _J4RESET_
+
+//TEMPTEMP
+#define SECONDARY_CACHE_SIZE (1 << 20)
+#define SECONDARY_CACHE_INVALID 0x0
+#define TAGLO_SSTATE 0xA
+#define INDEX_FILL_I 0x14 // ****** temp ****** this must be moved to kxmips.h
+#define HIT_WRITEBACK_I 0x18 // ****** temp ****** this must be moved to kxmips.h
+
+//
+// redefine bal to be a relative branch and link instead of jal as it's
+// defined in kxmips.h. This allows calling routines when running in either
+// ROM_VIRT Addresses or ResetVector Addresses.
+// The cpp will issue a redefinition warning message.
+//
+#define bal bgezal zero,
+
+//
+// #define MCTADR register values.
+//
+
+//
+// Mctadr register reset values.
+//
+#ifndef DUO
+#define CONFIG_RESET_MCTADR_REV1 0x104
+#define CONFIG_RESET_MCTADR_REV2 0x410
+#define REMSPEED_RESET 0x7
+#define REFRRATE_RESET 0x18186
+#define SECURITY_RESET 0x7
+#else
+#define CONFIG_RESET_MP_ADR_REV1 0x4
+#define REMSPEED_RESET 0x7
+#define REFRRATE_RESET 0x18186
+#define SECURITY_RESET 0x7
+#endif
+
+//
+// Define remspeed registers.
+//
+#ifndef DUO
+#define REMSPEED0 7 // reserved
+#define REMSPEED1 0 // Ethernet
+#define REMSPEED2 1 // scsi
+#define REMSPEED3 2 // floppy
+#define REMSPEED4 7 // rtc
+#define REMSPEED5 3 // kbd/mouse
+#define REMSPEED6 2 // serial 1
+#define REMSPEED7 2 // serial 2
+#define REMSPEED8 2 // parallel
+#define REMSPEED9 4 // nvram
+#define REMSPEED10 1 // interrupt src
+#define REMSPEED11 2 // PROM (should be 4)
+#define REMSPEED12 1 // sound
+#define REMSPEED13 7 // new device
+#define REMSPEED14 1 // EISA latch
+#define REMSPEED15 1 // led
+#else
+#define REMSPEED0 7 // reserved
+#define REMSPEED1 0 // Ethernet
+#define REMSPEED2 0 // scsi
+#define REMSPEED3 0 // scsi
+#define REMSPEED4 7 // rtc
+#define REMSPEED5 3 // kbd/mouse
+#define REMSPEED6 2 // serial 1
+#define REMSPEED7 2 // serial 2
+#define REMSPEED8 2 // parallel
+#define REMSPEED9 4 // nvram
+#define REMSPEED10 3 // interrupt src
+#define REMSPEED11 3 // PROM (should be 4)
+#define REMSPEED12 7 // new device
+#define REMSPEED13 7 // new device
+#define REMSPEED14 1 // LED
+#endif
+
+
+//
+// Define the refresh rate. This value is 32/50th of the the reset value
+// because we are currently running at 32MHz
+//
+#ifndef DUO
+#define MEMORY_REFRESH_RATE 0x18186
+#else
+#define MEMORY_REFRESH_RATE 0x38186
+#endif
+
+
+#define PROM_BASE (KSEG1_BASE | 0x1fc00000)
+#define PROM_ENTRY(x) (PROM_BASE + ((x) * 8))
+
+#define DMA_CHANNEL_GAP 0x20 // distance beetwen DMA channels
+
+
+#endif // _J4RESET_
diff --git a/private/ntos/fw/mips/j4reset.s b/private/ntos/fw/mips/j4reset.s
new file mode 100644
index 000000000..388c6d26b
--- /dev/null
+++ b/private/ntos/fw/mips/j4reset.s
@@ -0,0 +1,2598 @@
+#if defined(JAZZ) && defined(R4000) && !defined(DUO)
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ j4reset.s
+
+Abstract:
+
+ This module is the start of the prom code. This code will
+ be the first run upon reset. It contains the self-test and
+ initialization.
+
+Author:
+
+ Lluis Abello (lluis) 8-Jan-91
+
+Environment:
+
+ Executes in kernal mode.
+
+Notes:
+
+ ***** IMPORTANT *****
+
+ This module must be linked such that it resides in the
+ first page of the rom.
+
+Revision History:
+
+ Some code stolen from johncoop's "reset.s"
+
+--*/
+//
+// include header file
+//
+#include <ksmips.h>
+#include <jazzprom.h>
+#include "dmaregs.h"
+#include "selfmap.h"
+#include "led.h"
+#include "j4reset.h"
+
+//TEMPTEMP
+
+#define COPY_ENTRY 6
+
+.text
+.set noreorder
+.set noat
+
+
+ ALTERNATE_ENTRY(ResetVector)
+/*++
+
+Routine Description:
+
+ This routine will provide the jump vectors located
+ at the targets of the processor exception vectors.
+
+ N.B. This routine must be located at the start of ROM which
+ is the location of the reset vector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+//
+// this instruction must be loaded at location 0 in the
+// rom. This will appear as BFC00000 to the processor
+//
+ ori zero,zero,0xffff // this is a dummy instruction to
+ // fix a bug where the first byte
+ // fetched from the PROM is wrong
+ b ResetException
+ nop
+
+//
+// This is the jump table for rom routines that other
+// programs can call. They are placed here so that they
+// will be unlikely to move.
+//
+//
+// This becomes PROM_ENTRY(2) as defined in ntmips.h
+//
+ .align 4
+ nop
+//
+// Entries 4 to 7 are used for the ROM Version and they
+// must be zero in this file.
+//
+
+//
+// This becomes PROM_ENTRYS(8,9...)
+//
+ .align 6
+ nop // entry 8
+ nop
+ nop // entry 9
+ nop
+ b TlbInit // entry 10
+ nop
+ nop // entry 11
+ nop
+ nop // entry 12
+ nop
+ nop // entry 13
+ nop
+ b PutLedDisplay // entry 14
+ nop
+ nop // entry 15
+ nop
+ nop // entry 16
+ nop
+
+RomRemoteSpeedValues:
+//
+// This table contains the default values for the remote speed regs.
+//
+ .byte REMSPEED1 // ethernet
+ .byte REMSPEED2 // SCSI
+ .byte REMSPEED3 // Floppy
+ .byte REMSPEED4 // RTC
+ .byte REMSPEED5 // Kbd/Mouse
+ .byte REMSPEED6 // Serial port 1
+ .byte REMSPEED7 // Serial port 2
+ .byte REMSPEED8 // Parallel
+ .byte REMSPEED9 // NVRAM
+ .byte REMSPEED10 // Int src reg
+ .byte REMSPEED11 // PROM
+ .byte REMSPEED12 // Sound
+ .byte REMSPEED13 // New dev
+ .byte REMSPEED14 // External Eisa latch
+ .byte REMSPEED15 // LED
+
+ .align 4
+
+//
+// New TLB Entries can be added to the following table
+// The format of the table is:
+// entryhi; entrylo0; entrylo1; pagemask
+//
+#define TLB_HI 0
+#define TLB_LO0 4
+#define TLB_LO1 8
+#define TLB_MASK 12
+
+TlbEntryTable:
+ .word ((PROM_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((PROM_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (2 << ENTRYLO_C)
+#ifdef PROM256
+ .word (1 << ENTRYLO_G) // set global bit even if page not used
+ .word (PAGEMASK_256KB << PAGEMASK_PAGEMASK)
+#endif
+#ifdef PROM128
+ .word (((PROM_PHYSICAL_BASE+0x10000) >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_64KB << PAGEMASK_PAGEMASK)
+#endif
+#ifdef PROM64
+ .word (1 << ENTRYLO_G) // set global bit even if page not used
+ .word (PAGEMASK_64KB << PAGEMASK_PAGEMASK)
+#endif
+//
+// I/O Device space non-cached, valid, dirty
+//
+ .word ((DEVICE_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((DEVICE_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (1 << ENTRYLO_G) // set global bit even if page not used
+ .word (PAGEMASK_64KB << PAGEMASK_PAGEMASK)
+//
+// Interrupt source register space
+// non-cached - read/write
+//
+ .word ((INTERRUPT_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((INTERRUPT_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_D) + (1 << ENTRYLO_V) + (2 << ENTRYLO_C)
+ .word (1 << ENTRYLO_G) // set global bit even if page not used
+ .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK)
+//
+// video control 2MB non-cached read/write.
+//
+ .word ((VIDEO_CONTROL_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((VIDEO_CONTROL_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((VIDEO_CONTROL_PHYSICAL_BASE+0x100000) >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_1MB << PAGEMASK_PAGEMASK)
+//
+// extended video control 2MB non-cached read/write.
+//
+ .word ((EXTENDED_VIDEO_CONTROL_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((EXTENDED_VIDEO_CONTROL_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((EXTENDED_VIDEO_CONTROL_PHYSICAL_BASE+0x100000) >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_1MB << PAGEMASK_PAGEMASK)
+//
+// video memory space 8Mb non-cached read/write
+//
+ .word ((VIDEO_MEMORY_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((VIDEO_MEMORY_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((VIDEO_MEMORY_PHYSICAL_BASE+0x400000) >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_4MB << PAGEMASK_PAGEMASK)
+//
+// EISA I/O 16Mb non-cached read/write
+// EISA MEM 16Mb non-cached read/write
+//
+ .word ((EISA_IO_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((EISA_IO_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word ((0x100000) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_16MB << PAGEMASK_PAGEMASK)
+//
+// EISA I/O page 0 non-cached read/write
+// EISA I/O page 1 non-cached read/write
+//
+ .word ((EISA_EXTERNAL_IO_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((0 >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((EISA_IO_PHYSICAL_BASE + 1 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK)
+//
+// EISA I/O page 2 non-cached read/write
+// EISA I/O page 3 non-cached read/write
+//
+ .word (((EISA_EXTERNAL_IO_VIRTUAL_BASE + 2 * PAGE_SIZE) >> 13) << ENTRYHI_VPN2)
+ .word (((EISA_IO_PHYSICAL_BASE + 2 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((EISA_IO_PHYSICAL_BASE + 3 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK)
+//
+// EISA I/O page 4 non-cached read/write
+// EISA I/O page 5 non-cached read/write
+//
+ .word (((EISA_EXTERNAL_IO_VIRTUAL_BASE + 4 * PAGE_SIZE) >> 13) << ENTRYHI_VPN2)
+ .word (((EISA_IO_PHYSICAL_BASE + 4 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((EISA_IO_PHYSICAL_BASE + 5 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK)
+//
+// EISA I/O page 6 non-cached read/write
+// EISA I/O page 7 non-cached read/write
+//
+ .word (((EISA_EXTERNAL_IO_VIRTUAL_BASE + 6 * PAGE_SIZE) >> 13) << ENTRYHI_VPN2)
+ .word (((EISA_IO_PHYSICAL_BASE + 6 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((EISA_IO_PHYSICAL_BASE + 7 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK)
+//
+// EISA I/O pages 8,9,a,b non-cached read/write
+// EISA I/O pages c,d,e,f non-cached read/write
+//
+ .word (((EISA_EXTERNAL_IO_VIRTUAL_BASE + 8 * PAGE_SIZE) >> 13) << ENTRYHI_VPN2)
+ .word (((EISA_IO_PHYSICAL_BASE + 8 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (((EISA_IO_PHYSICAL_BASE + 12 * PAGE_SIZE) >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_16KB << PAGEMASK_PAGEMASK)
+//
+// Map PCR for kernel debugger.
+//
+ .word ((PCR_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word (1 << ENTRYLO_G) // set global bit even if page not used
+ .word ((PCR_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (2 << ENTRYLO_C)
+ .word (PAGEMASK_4KB << PAGEMASK_PAGEMASK)
+//
+// Map 64KB of memory for the video prom code&data cached.
+//
+ .word ((VIDEO_PROM_CODE_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ .word ((VIDEO_PROM_CODE_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (1 << ENTRYLO_D) + (3 << ENTRYLO_C)
+ .word (1 << ENTRYLO_G) // set global bit even if page not used
+ .word (PAGEMASK_64KB << PAGEMASK_PAGEMASK)
+TlbEntryEnd:
+ .byte 0
+
+
+//
+// these next vectors should be loaded at BFC00200,BFC00300,
+// and BFC00380. They are for the TLBmiss, cache_error, and
+// common exceptions respectively.
+//
+ .align 9
+ LEAF_ENTRY(UserTlbMiss200)
+UserTlbMiss:
+ li k0,KSEG1_BASE
+ lw k0,0x1018(k0) // Load address of UTBMiss handler
+ nop
+ jal k1,k0 // jump to handler saving return
+ nop // address in k1
+ mtc0 k0,epc // Handler returns return address in K0
+ nop // 2 cycle Hazard
+ nop
+ eret // restore from exception
+ .end UserTlbMiss200
+
+
+ LEAF_ENTRY(TlbInit)
+/*++
+
+Routine Description:
+
+ This routine will initialize the TLB for virtual addressing.
+ It sets the TLB according to a table of TLB entries.
+ Mapping:
+ I/O device E0000000 - E00FFFFF
+ Intr src reg E0100000 - E0100FFF
+ video cntr E0200000 - E0203FFF
+ video memory 40000000 - 40200000
+ prom space E1000000 - E100FFFF
+ eisa i/o space E2000000 - E2FFFFFF
+ eisa mem space E3000000 - E3FFFFFF
+ reserved E4000000 -
+
+ All other unused TLB entries will be zeroed and therefore invalidated.
+
+ N.B. This routine must be loaded in the first page of the rom and must
+ be called using BFC00XXXX addresses.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+Revision History:
+
+--*/
+//
+// zero the whole TLB
+//
+ mtc0 zero,entrylo0 // tag data to store
+ mtc0 zero,entrylo1
+ li t0,KSEG0_BASE // set entry hi
+ mtc0 t0,entryhi
+ mtc0 zero,pagemask
+ move s0,zero // tlb entry index
+ li t0, 48 // get last index (TB_SIZE)
+ mtc0 s0,index // entry pointer
+tlbzeroloop:
+ addiu s0,s0,1<<INDEX_INDEX // increment counter
+ tlbwi // store it
+ bne s0,t0,tlbzeroloop // loop if less than max entries
+ mtc0 s0,index // entry pointer
+
+//
+// Get address and boundary of Table
+//
+ la t1, TlbEntryTable - LINK_ADDRESS + RESET_VECTOR
+ la t2, TlbEntryEnd - LINK_ADDRESS + RESET_VECTOR
+ li s0, COPY_ENTRY+1 // tlb entry index
+10:
+ lw t3, TLB_HI(t1) // get entryhi
+ lw t4, TLB_LO0(t1) // get entrylo0
+ lw t5, TLB_LO1(t1) // get entrylo1
+ lw t6, TLB_MASK(t1) // get pagemask
+ mtc0 t3,entryhi // write entryhi
+ mtc0 t4,entrylo0 // write entrylo0
+ mtc0 t5,entrylo1 // write entrylo1
+ mtc0 t6,pagemask // write pagemask
+ mtc0 s0,index // write index
+ addiu s0,s0,1 // compute index for next tlb entry
+ tlbwi // write tlb entry
+ addiu t1,t1,16 // set pointer to next entry
+ bne t1,t2,10b // if not last go for next
+
+ li t0,TRANSFER_VECTOR // get address of transfer vector
+ sw s0,4(t0) // set next free TB entry index
+ j ra
+ nop
+ .end TlbInit
+
+ParityError:
+//
+// Copy the firmware from PROM to memory.
+//
+//
+// Copy the firmware.
+//
+ la s0,Decompress-LINK_ADDRESS+KSEG1_BASE
+ // address of decompression routine in cached space
+ la a0,end // end of this file is start of selftest
+ li a1,RAM_TEST_DESTINATION_ADDRESS
+ // destination is uncached link address.
+ jal s0 // jump to decompress
+ nop
+//
+// Initialize the stack to the low memory and Call Rom tests.
+//
+ li t0,RAM_TEST_DESTINATION_ADDRESS // address of copied code
+ li sp,RAM_TEST_STACK_ADDRESS | KSEG1_BASE // init stack non cached
+ move a1,s5 // Pass cacheerr register as 2nd arg
+ jal t0 // jump to self-test in memory
+ li a0,3 // pass cause of exception as argument.
+
+//
+// This becomes the entry point of a Cache Error Exception.
+// It should be located at address BFC00300
+//
+ .align 8
+/*++
+ParityHandler();
+Routine Description:
+
+ This routine is called as a result of a Cache Error exception.
+ Changes KSEG0 coherency to non cached in the config register.
+ Reinitializes the TLB.
+ Copies the firmware to memory and jumps to it.
+ A message is printed.
+
+Arguments:
+
+ This routine doesn't preserve state.
+
+Return Value:
+
+ None.
+
+--*/
+ LEAF_ENTRY(ParityHandler300)
+ //
+ // Should save state.
+ //
+ li k0,(1<<PSR_BEV) | (1 << PSR_CU1) | (1<<PSR_ERL)
+ mtc0 k0,psr // Clear interrupt bit while ERL still set
+ nop
+ li k0,(1<<PSR_BEV) | (1 << PSR_CU1)
+ nop
+ mtc0 k0,psr // Clear ERL bit
+ nop
+ bal TlbInit // reinitialize the tlb
+ mfc0 s5,cacheerr // Load cache error register
+ bal PutLedDisplay
+ ori a0,zero,LED_PARITY //
+ mfc0 k0,config // get config register
+ li k1,~(7 << CONFIG_K0) // mask to clear Kseg0 coherency bits
+ and k0,k0,k1 // clear bits
+ ori k0,(2 << CONFIG_K0) // make kseg0 non cached
+ mtc0 k0,config //
+//
+// Copy the copy routines to memory
+//
+ la a0,MemoryRoutines // source
+ la a1,MemoryRoutines-LINK_ADDRESS+KSEG1_BASE // destination location
+ la t2,EndMemoryRoutines // end
+ bal DataCopy // copy code to memory
+ subu a2,t2,a0 // length of code
+ b ParityError
+ nop
+ .end ParityHandler300
+//
+// This becomes the entry point of a General Exception.
+// It should be located at address BFC00380
+//
+ .align 7
+ LEAF_ENTRY(GeneralException380)
+ li k0,KSEG1_BASE
+ lw k0,0x1014(k0) // Load address of GE handler
+ nop
+ jal k1,k0 // jump to handler saving return
+ nop // address in k1
+ mtc0 k0,epc // Handler returns return address in K0
+ nop // 2 cycle Hazard
+ nop
+ eret // restore from exception
+ nop
+ .end GeneralException380
+
+ ALTERNATE_ENTRY(ResetException)
+ ALTERNATE_ENTRY(_start)
+/*++
+
+Routine Description:
+
+ This is the handler for the reset exception. It first checks the cause
+ of the exception. If it is an NMI, then control is passed to the
+ exception dispatch routine. Otherwise the machine is initialized.
+
+ The basic are:
+ 1) Map the I/O devices.
+ 2) Test the processor.
+ 3) Test the MCTADR
+ 4) Map ROM. Perform a ROM checksum.
+ 5) Test a portion of Memory
+ 6) Test TLB
+ 7) Copy routines to memory
+ 8) Initialize caches
+ 9) Initialize stack for C language calls and other stack operations
+ 10) Copy selftest and firmware code to memory and jump to it.
+
+ N.B. This routine must be loaded into the first page of rom.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+//
+// Initialize the TLB.
+//
+
+ bal TlbInit // reinitialize the tlb
+ nop
+//
+// Check cause of exception, if SR bit in PSR is set treat it as a soft reset
+// or an NMI, otherwise it's a cold reset.
+//
+ mfc0 k0,psr // get cause register
+ li k1,(1<<PSR_SR) // bit indicates soft reset.
+ mtc0 zero,watchlo // initialize the watch
+ mtc0 zero,watchhi // address registers
+ and k1,k1,k0 // mask PSR with SR bit
+ li k0,(1<<PSR_BEV) | (1 << PSR_CU1) | (1<<PSR_ERL)
+ mtc0 k0,psr // Clear interrupt bit while ERL still set
+ nop
+ beq k1,zero,ResetCPU // go if cold reset
+ li k0,(1<<PSR_BEV) | (1 << PSR_CU1)
+ nop
+ mtc0 k0,psr // Clear ERL bit
+ li k0,DMA_VIRTUAL_BASE // load base address of MCT_ADR
+ lw k1,DmaInterruptSource(k0) // Read the interrupt source register.
+ nop
+ andi k0,k1,(1<<11) // test for NMI
+ bne k0,zero,20f // if bit set this is an NMI
+ nop // otherwise is a softreset.
+
+ b SoftReset // jump to soft reset
+ ori s5,zero,1 // set s5 to tell that selftest can be skipped
+
+20:
+ //
+ // Nmi Handler jump to firmware to print message.
+ //
+
+ bal PutLedDisplay // set a dash in the LED
+ ori a0,zero,LED_NMI //
+
+ //
+ // Copy the copy routines to memory
+ //
+
+ la a0,MemoryRoutines // source
+ la a1,MemoryRoutines-LINK_ADDRESS+KSEG1_BASE // destination location
+ la t2,EndMemoryRoutines // end
+ bal DataCopy // copy code to memory
+ sub a2,t2,a0 // length of code
+
+ la t2,InvalidateICache-LINK_ADDRESS+KSEG1_BASE // non-cached space
+ jal t2 // Invalidate the instruction cache
+ nop
+ la k0,NMI // Join common code
+ mfc0 s6,errorepc // get error epc
+ j k0 // running at PROM Vaddress.
+ li s5,2 // indicate exception is NMI.
+
+ResetCPU:
+ move s5,zero // clear s5 to indicate cold reset
+SoftReset:
+//
+// Initialize PSR to BEV and COP1 enabled. It's important to clear ERL since
+// the ErrorEPC is undefined and further exceptions will set ERL or EXL
+// according to the nature of the exception.
+//
+ li k0,(1<<PSR_BEV) | (1 << PSR_CU1)
+ mtc0 k0,psr
+ nop
+ nop
+
+//
+// If there is no secondary cache or the secondary cache block size is greater
+// than 16 bytes, set the primary instruction cache block size to
+// 32 bytes, otherwise set to 16 bytes.
+//
+
+ mfc0 t0,config
+ li t1, (1 << CONFIG_IB) + (0 << CONFIG_DB) + (0 << CONFIG_CU) + \
+ (3 << CONFIG_K0)
+
+ srl t2,t0,CONFIG_SC // check for secondary cache
+ and t2,t2,1 // isolate the bit
+ bne t2,zero,10f // if none, block size stays 32 bytes
+ srl t2,t0,CONFIG_SB // check secondary cache block size
+ and t2,t2,3 // isolate the bit
+ bne t2,zero,10f // if not 16 bytes, size stays 32 bytes
+ nop
+
+ li t1, (0 << CONFIG_IB) + (0 << CONFIG_DB) + (0 << CONFIG_CU) + \
+ (3 << CONFIG_K0)
+10:
+ li t2, 0xFFFFFFC0
+ and t0,t0,t2 // clear soft bits in config
+ or t0,t0,t1 // set soft bits in config
+ mtc0 t0,config
+ nop
+ nop
+
+ bal PutLedDisplay // BLANK the LED
+ ori a0,zero,LED_BLANK<<TEST_SHIFT
+
+//
+// now go to the virtual address instead of using the page
+// 1FC00000 that is mapped by the address chip.
+//
+ la t0,Virtual
+ j t0
+ nop
+Virtual:
+
+ beq s5,1,SkipProcessorTest // Skip processor test if softreset
+ nop
+ bal PutLedDisplay // Show processor test is staring
+ ori a0,zero,LED_PROCESSOR_TEST
+ bal ProcessorTest // Test the processor
+ nop
+ move s5,zero // clear s5 to indicate cold reset
+
+SkipProcessorTest:
+ bal PutLedDisplay // Show MCT_ADR reset test is starting
+ ori a0,zero,LED_MCTADR_RESET
+ bal MctadrResetTest
+ nop
+
+ bal PutLedDisplay // Show MCT_ADR register test is starting
+ ori a0,zero,LED_MCTADR_REG
+ bal MctadrRegisterTest
+ nop
+
+ beq s5,1,SkipRomChecksum // Skip checksum if softreset
+ nop
+//
+// Perform a ROM Checksum.
+//
+ bal PutLedDisplay // Display in the LED that
+ ori a0,zero,LED_ROM_CHECKSUM // ROM Checksum is being executed
+ li a0,PROM_VIRTUAL_BASE // address of PROM
+ li t0,ROM_SIZE
+ add a1,a0,t0 // end of loop address
+ move t0,zero // init sum register
+
+RomCheckSum:
+ lw t1,0(a0) // fetch word
+ lw t2,4(a0) // fetch second word
+ addu t0,t0,t1 // calculate checksum add from ofs 0
+ lw t1,8(a0)
+ addu t0,t0,t2 // calculate checksum add from ofs 4
+ lw t2,0xC(a0)
+ addu t0,t0,t1 // calculate checksum add from ofs 8
+ addiu a0,a0,16 // compute next address
+ bne a0,a1,RomCheckSum // check end of loop condition
+ addu t0,t0,t2 // calculate checksum add from ofs c
+
+//
+// if test passes, jump to next part of initialization code.
+//
+ beq t0,zero,TestMemory // Branch if calculated checksum is correct
+ move s5,zero // clear s5 this tells to run selftest
+ lui a0,LED_BLINK // otherwise hang
+ bal PutLedDisplay // by calling PutLedDisplay
+ ori a0,a0,LED_ROM_CHECKSUM // blinking the test number
+
+SkipRomChecksum:
+TestMemory:
+ bal PutLedDisplay // call PutLedDisplay to show that
+ ori a0,zero,LED_MEMORY_TEST_1 // Mem test is starting
+//
+// Call memory test routine to test small portion of memory.
+// a0 is start of tested memory. a1 is length in bytes to test
+//
+//
+// Disable Parity exceptions for the first memory test. Otherwise
+// if something is wrong with the memory we jump to the moon.
+//
+ li t0, (1<<PSR_DE) | (1 << PSR_CU1) | (1 << PSR_BEV)
+ mtc0 t0,psr
+ nop
+ li a0,KSEG1_BASE // start of mem test
+ ori a1,zero,MEMTEST_SIZE // length to test in bytes
+ ctc1 zero,fsr // clear floating status
+ nop
+ bal WriteNoXorAddressTest
+ move a2,zero // xor pattern zero
+ bal CheckNoXorAddressTest
+ ori a3,zero,LED_MEMORY_TEST_1 // set Test/Subtest ID
+//
+// Do the same flipping all bits
+//
+ bal WriteAddressTest
+ li a2,-1 // Xor pattern = FFFFFFFF
+ bal CheckAddressTest
+ nop
+//
+// Do the same flipping some bits to be sure parity bits are flipped in each byte
+//
+ lui a2,0x0101
+ bal WriteAddressTest
+ ori a2,a2,0x0101 // Xor pattern = 01010101
+ bal CheckAddressTest
+ nop
+
+ bal SizeMemory // start by sizing the memory.
+ nop //
+
+//
+// The next step is to copy a number of routines to memory so they can
+// be executed more quickly. Calculate the arguments for DataCopy call:
+// a0 is source of data, a1 is dest, a2 is length in bytes
+//
+ la a0,MemoryRoutines // source
+ la a1,MemoryRoutines-LINK_ADDRESS+KSEG1_BASE // destination location
+ la t2,EndMemoryRoutines // end
+ bal DataCopy // copy code to memory
+ sub a2,t2,a0 // length of code
+
+//
+// Call cache initialization routine in non-cached memory
+//
+ bal PutLedDisplay // display that cache init
+ ori a0,zero,LED_CACHE_INIT // is starting
+ la s1,R4000CacheInit-LINK_ADDRESS+KSEG1_BASE // non-cached address
+ jal s1 // initialize caches
+ nop
+
+//
+// call routine now in cached memory to test bigger portion of memory
+//
+ bal PutLedDisplay // display that memory test
+ ori a0,zero,LED_WRITE_MEMORY_2 // is starting
+ li a0,KSEG1_BASE+MEMTEST_SIZE // start of memory to write non cached
+ li a1,FW_TOP_ADDRESS-MEMTEST_SIZE // test the memory needed to copy the code
+ // to memory, the stack and the video prom.
+ la s1,WriteNoXorAddressTest-LINK_ADDRESS+KSEG0_BASE // address of routine in memory cached
+ jal s1 // Write and therefore init mem.
+ move a2,zero // xor pattern
+ la s2,CheckNoXorAddressTest-LINK_ADDRESS+KSEG0_BASE // address of routine in memory
+ jal s2 // Check written memory
+ ori a3,zero,LED_READ_MEMORY_2 // load LED value if memory test fails
+ la s1,WriteAddressTest-LINK_ADDRESS+KSEG0_BASE // address of routine cached
+ li a0,KSEG0_BASE+MEMTEST_SIZE // start of memory now cached
+ li a2,0xDFFFFFFF // to flipp all bits
+ jal s1 // Write second time now cached.
+ la s2,CheckAddressTest-LINK_ADDRESS+KSEG0_BASE // address of routine in memory
+ jal s2 // check also cached.
+ nop
+ lui a2,0x0101
+ jal s1 // Write third time cached.
+ ori a2,a2,0x0101 // flipping some bits
+ jal s2 // check also cached.
+ nop
+//
+// if we come back, the piece of memory is tested and therefore initialized.
+//
+
+//
+// If an NMI occurred. s5 contains the erorrepc.
+// the Tlb has already been initialized and the I cache flushed.
+// Copy the firmware to memory and display a message from there.
+//
+
+NMI:
+//
+// Invalidate the data caches so that the firmware can be copied to
+// noncached space without a conflict.
+//
+
+ bal InvalidateDCache
+ nop
+ bal InvalidateSCache
+ nop
+
+//
+// Copy the firmware.
+//
+ la s0,Decompress-LINK_ADDRESS+KSEG0_BASE
+ // address of decompression routine in cached space
+ la a0,end // end of this file is start of selftest
+ li a1,RAM_TEST_DESTINATION_ADDRESS
+ // destination is uncached link address.
+ jal s0 // jump to decompress
+ nop
+ bal InvalidateICache // Invalidate the instruction cache
+ nop
+
+//
+// Zero the memory up to the firmware.
+//
+ li t0,KSEG0_BASE // start of memory to zero
+ li t1,RAM_TEST_LINK_ADDRESS // at the start of the firmware.
+ mtc1 zero,f0 // zero f0
+ mtc1 zero,f1 // zero f1
+ZeroFirst:
+ addi t0,8 // increment by a doubleword
+ bne t0,t1,ZeroFirst // branch if not done
+ sdc1 f0,-8(t0) // write doubleword
+
+//
+// Flush the data cache
+//
+ bal FlushDCache
+ nop
+
+//
+// Initialize the stack to the low memory and Call Rom tests.
+//
+ li t0,RAM_TEST_LINK_ADDRESS // address of copied code
+ li sp,RAM_TEST_STACK_ADDRESS // init stack
+ move a1,s6
+ jal t0 // jump to self-test in memory
+ move a0,s5 // pass cause of exception as argument.
+99:
+ b 99b // hang if we get here.
+ nop //
+
+
+//
+// Routines between MemoryRoutines and EndMemoryRoutines are copied
+// into memory to run them cached.
+//
+
+ .align 4 // Align it to 16 bytes boundary so that
+ ALTERNATE_ENTRY(MemoryRoutines) // DataCopy doesn't need to check alignments
+/*++
+VOID
+PutLedDisplay(
+ a0 - display value.
+ )
+Routine Description:
+
+ This routine will display in the LED the value specified as argument
+ a0.
+
+ bits [31:16] specify the mode.
+ bits [7:4] specify the Test number.
+ bits [3:0] specify the Subtest number.
+
+ The mode can be:
+
+ LED_NORMAL Display the Test number
+ LED_BLINK Loop displaying Test - Dot - Subtest
+ LED_LOOP_ERROR Display the Test number with the dot iluminated
+
+ N.B. This routine must reside in the first page of ROM because it is
+ called before mapping the rom!!
+
+Arguments:
+
+ a0 value to display.
+
+ Note: The value of the argument is preserved
+
+Return Value:
+
+ If a0 set to LED_BLINK does not return.
+
+--*/
+ LEAF_ENTRY(PutLedDisplay)
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // load address of display
+LedBlinkLoop:
+ srl t1,a0,16 // get upper bits of a0 in t1
+ srl t3,a0,4 // get test number
+ li t4,LED_LOOP_ERROR //
+ bne t1,t4, DisplayTestID
+ andi t3,t3,0xF // clear other bits.
+ ori t3,t3,LED_DECIMAL_POINT // Set decimal point
+DisplayTestID:
+ li t4,LED_BLINK // check if need to hung
+ sb t3,0(t0) // write test ID to led.
+ beq t1,t4, ShowSubtestID
+ nop
+ j ra // return to caller.
+ nop
+
+ShowSubtestID:
+ li t2,LED_DELAY_LOOP // get delay value.
+TestWait:
+ bne t2,zero,TestWait // loop until zero
+ addiu t2,t2,-1 // decrement counter
+ li t3,LED_DECIMAL_POINT+LED_BLANK
+ sb t3,0(t0) // write decimal point
+ li t2,LED_DELAY_LOOP/2 // get delay value.
+DecPointWait:
+ bne t2,zero,DecPointWait // loop until zero
+ addiu t2,t2,-1 // decrement counter
+ andi t3,a0,0xF // get subtest number
+ sb t3,0(t0) // write subtest in LED
+ li t2,LED_DELAY_LOOP // get delay value.
+SubTestWait:
+ bne t2,zero,SubTestWait // loop until zero
+ addiu t2,t2,-1 // decrement counter
+ b LedBlinkLoop // go to it again
+ nop
+ .end PutLedDisplay
+
+ LEAF_ENTRY(InvalidateICache)
+/*++
+
+Routine Description:
+
+ This routine invalidates the contents of the instruction cache.
+
+ The instruction cache is invalidated by writing an invalid tag to
+ each cache line, therefore nothing is written back to memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+//
+// invalid state
+//
+ mfc0 t5,config // read config register
+ li t0,(PRIMARY_CACHE_INVALID << TAGLO_PSTATE)
+ mtc0 t0,taglo // set tag registers to invalid
+ mtc0 zero,taghi
+
+ srl t0,t5,CONFIG_IC // compute instruction cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li t6,1 //
+ sll t6,t6,t0 // t6 = I cache size
+ srl t0,t5,CONFIG_IB // compute instruction cache line size
+ and t0,t0,1 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = I cache line size
+//
+// store tag to all icache lines
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t0,t1,t6 // get last index address
+ subu t0,t0,t7
+WriteICacheTag:
+ cache INDEX_STORE_TAG_I,0(t1) // store tag in Instruction cache
+ bne t1,t0,WriteICacheTag // loop
+ addu t1,t1,t7 // increment index
+ j ra
+ nop
+ .end InvalidateICache
+
+
+ LEAF_ENTRY(InvalidateDCache)
+/*++
+
+Routine Description:
+
+ This routine invalidates the contents of the D cache.
+
+ Data cache is invalidated by writing an invalid tag to each cache
+ line, therefore nothing is written back to memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+//
+// invalid state
+//
+ mfc0 t5,config // read config register for cache size
+ li t0, (PRIMARY_CACHE_INVALID << TAGLO_PSTATE)
+ mtc0 t0,taglo // set tag to invalid
+ mtc0 zero,taghi
+ srl t0,t5,CONFIG_DC // compute data cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li t6,1 //
+ sll t6,t6,t0 // t6 = data cache size
+ srl t0,t5,CONFIG_DB // compute data cache line size
+ and t0,t0,1 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = data cache line size
+
+//
+// store tag to all Dcache
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t2,t1,t6 // add cache size
+ subu t2,t2,t7 // adjust for cache line size.
+WriteDCacheTag:
+ cache INDEX_STORE_TAG_D,0(t1) // store tag in Data cache
+ bne t1,t2,WriteDCacheTag // loop
+ addu t1,t1,t7 // increment index by cache line
+ j ra
+ nop
+ .end InvalidateDCache
+
+
+ LEAF_ENTRY(FlushDCache)
+/*++
+
+Routine Description:
+
+ This routine flushes the whole contents of the Dcache
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+ mfc0 t5,config // read config register
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ srl t0,t5,CONFIG_DC // compute data cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li t6,1 //
+ sll t6,t6,t0 // t6 = data cache size
+ srl t0,t5,CONFIG_DB // compute data cache line size
+ and t0,t0,1 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = data cache line size
+ addu t0,t1,t6 // compute last index address
+ subu t0,t0,t7
+FlushDCacheTag:
+ cache INDEX_WRITEBACK_INVALIDATE_D,0(t1) // Invalidate data cache
+ bne t1,t0,FlushDCacheTag // loop
+ addu t1,t1,t7 // increment index
+
+//
+// check for a secondary cache.
+//
+
+ li t1,(1 << CONFIG_SC)
+ and t0,t5,t1
+ bne t0,zero,10f // if non-zero no secondary cache
+
+ li t6,SECONDARY_CACHE_SIZE // t6 = secondary cache size
+ srl t0,t5,CONFIG_SB // compute secondary cache line size
+ and t0,t0,3 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = secondary cache line size
+//
+// invalidate all secondary lines
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t0,t1,t6 // get last index address
+ subu t0,t0,t7
+FlushSDCacheTag:
+ cache INDEX_WRITEBACK_INVALIDATE_SD,0(t1) // invalidate secondary cache
+ bne t1,t0,FlushSDCacheTag // loop
+ addu t1,t1,t7 // increment index
+10:
+ j ra
+ nop
+ .end FlushDCache
+
+
+ LEAF_ENTRY(InvalidateSCache)
+/*++
+
+Routine Description:
+
+ This routine invalidates the contents of the secondary cache.
+
+ The secondary cache is invalidated by writing an invalid tag to
+ each cache line, therefore nothing is written back to memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+ mfc0 t5,config // read config register
+
+//
+// check for a secondary cache.
+//
+
+ li t1,(1 << CONFIG_SC)
+ and t0,t5,t1
+ bne t0,zero,NoSecondaryCache // if non-zero no secondary cache
+
+ li t0,(SECONDARY_CACHE_INVALID << TAGLO_SSTATE)
+ mtc0 t0,taglo // set tag registers to invalid
+ mtc0 zero,taghi
+
+ li t6,SECONDARY_CACHE_SIZE // t6 = secondary cache size
+ srl t0,t5,CONFIG_SB // compute secondary cache line size
+ and t0,t0,3 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = secondary cache line size
+//
+// store tag to all secondary lines
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t0,t1,t6 // get last index address
+ subu t0,t0,t7
+WriteSICacheTag:
+ cache INDEX_STORE_TAG_SD,0(t1) // store tag in secondary cache
+ bne t1,t0,WriteSICacheTag // loop
+ addu t1,t1,t7 // increment index
+
+NoSecondaryCache:
+ j ra
+ nop
+ .end InvalidateSCache
+
+
+ LEAF_ENTRY(InitDataCache)
+/*++
+
+Routine Description:
+
+ This routine initializes the data fields of the primary and
+ secondary data caches.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+ mfc0 t5,config // read config register
+
+//
+// check for a secondary cache.
+//
+
+ li t1,(1 << CONFIG_SC)
+ and t0,t5,t1
+ bne t0,zero,NoSecondaryCache1 // if non-zero no secondary cache
+
+ li t6,SECONDARY_CACHE_SIZE // t6 = secondary cache size
+ srl t0,t5,CONFIG_SB // compute secondary cache line size
+ and t0,t0,3 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = secondary cache line size
+//
+// store tag and data to all secondary lines
+//
+ mtc1 zero,f0 // zero f0
+ mtc1 zero,f1 // zero f1
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t0,t1,t6 // get last index address
+ subu t0,t0,t7
+ andi t4,t7,16 // isolate secondary cache line size
+WriteSCacheDe:
+ cache CREATE_DIRTY_EXCLUSIVE_SD,0(t1) // store tag in secondary cache
+ nop // MIPS does this
+ bne t4,zero,10f //
+ sdc1 f0,0(t1) // write
+ sdc1 f0,16(t1) // write
+ sdc1 f0,24(t1) // write
+10: sdc1 f0,8(t1) // write
+ bne t1,t0,WriteSCacheDe // loop
+ addu t1,t1,t7 // increment index
+//
+// Flush the primary data cache to the secondary cache
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ srl t0,t5,CONFIG_DC // compute data cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li t6,1 //
+ sll t6,t6,t0 // t6 = data cache size
+ srl t0,t5,CONFIG_DB // compute data cache line size
+ and t0,t0,1 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = data cache line size
+ addu t0,t1,t6 // compute last index address
+ subu t0,t0,t7
+FlushPDCacheTag:
+ cache INDEX_WRITEBACK_INVALIDATE_D,0(t1) // Invalidate data cache
+ bne t1,t0,FlushPDCacheTag // loop
+ addu t1,t1,t7 // increment index
+
+ j ra // return
+ nop
+
+NoSecondaryCache1:
+
+ srl t0,t5,CONFIG_DC // compute data cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li t6,1 //
+ sll t6,t6,t0 // t6 = data cache size
+ srl t0,t5,CONFIG_DB // compute data cache line size
+ and t0,t0,1 //
+ li t7,16 //
+ sll t7,t7,t0 // t7 = data cache line size
+
+//
+// create dirty exclusive to all Dcache
+//
+ mtc1 zero,f0 // zero f0
+ mtc1 zero,f1 // zero f1
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t2,t1,t6 // add cache size
+ subu t2,t2,t7 // adjust for cache line size.
+WriteDCacheDe:
+ cache CREATE_DIRTY_EXCLUSIVE_D,0(t1) // store tag in Data cache
+ nop
+ sdc1 f0,0(t1) // write
+ sdc1 f0,8(t1) // write
+ bne t1,t2,WriteDCacheDe // loop
+ addu t1,t1,t7 // increment index by cache line
+
+ j ra // return
+ nop
+ .end InitDataCache
+
+ LEAF_ENTRY(R4000CacheInit)
+/*++
+
+Routine Description:
+
+ This routine will initialize the cache tags and data for the
+ primary data cache, primary instruction cache, and the secondary cache
+ (if present).
+
+ Subroutines are called to invalidate all of the tags in the
+ instruction and data caches.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+ move s0,ra // save ra.
+
+//
+// Disable Cache Error exceptions.
+//
+
+ li t0, (1<<PSR_DE) | (1 << PSR_CU1) | (1 << PSR_BEV)
+ mtc0 t0,psr
+
+//
+// Invalidate the caches
+//
+
+ bal InvalidateICache
+ nop
+
+ bal InvalidateDCache
+ nop
+
+ bal InvalidateSCache
+ nop
+
+//
+// Initialize the data cache(s)
+//
+
+ bal InitDataCache
+ nop
+
+//
+// Fill the Icache, all icache lines
+//
+
+ mfc0 t5,config // read config register
+ nop
+ srl t0,t5,CONFIG_IC // compute instruction cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li s1,1 //
+ sll s1,s1,t0 // s1 = I cache size
+ srl t0,t5,CONFIG_IB // compute instruction cache line size
+ and t0,t0,1 //
+ li s2,16 //
+ sll s2,s2,t0 // s2 = I cache line size
+
+ICacheStart:
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t0,t1,s1 // add I cache size
+ subu t0,t0,s2 // sub line size.
+FillICache:
+ cache INDEX_FILL_I,0(t1) // Fill I cache from memory
+ bne t1,t0,FillICache // loop
+ addu t1,t1,s2 // increment index
+
+//
+// Invalidate the caches again
+//
+ bal InvalidateICache
+ nop
+
+ bal InvalidateDCache
+ nop
+
+ bal InvalidateSCache
+ nop
+
+//
+// Enable cache error exception.
+//
+ li t1, (1 << PSR_CU1) | (1 << PSR_BEV)
+ mtc0 t1,psr
+ nop
+ nop
+ nop
+ move ra,s0 // move return address back to ra
+ j ra // return from routine
+ nop
+ .end R4000CacheInit
+
+
+/*++
+VOID
+WriteAddressTest(
+ StartAddress
+ Size
+ Xor pattern
+ )
+Routine Description:
+
+ This routine will store the address of each location xored with
+ the Pattern into each location.
+
+Arguments:
+
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+ a2 - supplies the pattern to Xor with.
+
+ Note: the values of the arguments are preserved.
+
+Return Value:
+
+ This routine returns no value.
+--*/
+ LEAF_ENTRY(WriteAddressTest)
+ add t1,a0,a1 // t1 = last address.
+ xor t0,a0,a2 // t0 value to write
+ move t2,a0 // t2=current address
+writeaddress:
+ sw t0,0(t2) // store
+ addiu t2,t2,4 // compute next address
+ xor t0,t2,a2 // next pattern
+ sw t0,0(t2)
+ addiu t2,t2,4 // compute next address
+ xor t0,t2,a2 // next pattern
+ sw t0,0(t2)
+ addiu t2,t2,4 // compute next address
+ xor t0,t2,a2 // next pattern
+ sw t0,0(t2)
+ addiu t2,t2,4 // compute next address
+ bne t2,t1, writeaddress // check for end condition
+ xor t0,t2,a2 // value to write
+ j ra
+ nop
+ .end WriteAddressTest
+
+/*++
+VOID
+WriteNoXorAddressTest(
+ StartAddress
+ Size
+ )
+Routine Description:
+
+ This routine will store the address of each location
+ into each location.
+
+Arguments:
+
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+
+ Note: the values of the arguments are preserved.
+
+Return Value:
+
+ This routine returns no value.
+--*/
+ LEAF_ENTRY(WriteNoXorAddressTest)
+ nop
+ nop
+ nop
+ nop
+ add t1,a0,a1 // t1 = last address.
+ addiu t1,t1,-4
+ move t2,a0 // t2=current address
+writenoXoraddress:
+ sw t2,0(t2) // store first address
+ addiu t2,t2,4 // compute next address
+ sw t2,0(t2) // store first address
+ addiu t2,t2,4 // compute next address
+ sw t2,0(t2) // store first address
+ addiu t2,t2,4 // compute next address
+ sw t2,0(t2) // store
+ bne t2,t1, writenoXoraddress // check for end condition
+ addiu t2,t2,4 // compute next address
+ j ra
+ nop
+ .end WriteNoXorAddressTest
+
+
+/*++
+VOID
+CheckAddressTest(
+ StartAddress
+ Size
+ Xor pattern
+ LedDisplayValue
+ )
+Routine Description:
+
+
+ This routine will check that each location contains it's address
+ xored with the Pattern as written by WriteAddressTest. The memory
+ is read cached or non cached according to the address specified by a0.
+ if WriteAddressTest used a KSEG1_ADR to write the data and this
+ routine is called to read KSEG0_ADR in order to read the data cached,
+ then the XOR_PATTERN Must be such that:
+
+ KSEG0_ADR ^ KSEG0_XOR = KSEG1_ADR ^ KSEG1_XOR
+
+ Examples:
+
+ If XorPattern with which WriteAddressTest was called is KSEG1_XOR
+ then the XorPattern this routine needs is KSEG0_XOR:
+
+ KSEG1_XOR Written KSEG0_XOR So that
+ 0x00000000 0xA00000000 0x20000000 0x8000000 ^ 0x2000000 = 0xA0000000
+ 0xFFFFFFFF 0x5F0000000 0xDFFFFFFF 0x8000000 ^ 0xDF00000 = 0x5F000000
+ 0x01010101 0xA10000000 0x21010101 0x8000000 ^ 0x2100000 = 0xA1000000
+
+ This allows to write non cached to initialize memory and check the same
+ data trough cached addresses.
+
+Arguments:
+
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+ a2 - supplies the pattern to Xor with.
+ a3 - suplies the value to display in the led in case of failure
+
+ Note: the values of the arguments are preserved.
+
+Return Value:
+
+ Returns a zero if no error is found.
+
+ If errors are found, this routine behaves different depending
+ on where the caller resides:
+ - If the caller is executing in KSEG0 or KSEG1 returns 1
+ - If the caller is executing im ROM_VIRT addresses the
+ routine hangs blinking the LED or looping if the loop on error
+ bit is set in the config register.
+
+--*/
+ LEAF_ENTRY(CheckAddressTest)
+ move t3,a0 // t3 first address.
+ add t2,t3,a1 // last address.
+checkaddress:
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail
+ addiu t3,t3,4 // compute next address
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail
+ addiu t3,t3,4 // compute next address
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail
+ addiu t3,t3,4 // compute next address
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail // check last one.
+ addiu t3,t3,4 // compute next address
+ bne t3,t2, checkaddress // check for end condition
+ move v0,zero // set return value to zero.
+ j ra // return a zero to the caller
+
+PatternFail:
+ //
+ // check if we are in loop on error
+ //
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register
+ lb t0,0(t0) // read register value.
+ li t1,LOOP_ON_ERROR_MASK // get value to compare
+ andi t0,DIAGNOSTIC_MASK // mask diagnostic bits.
+ li v0,PROM_ENTRY(14) // load address of PutLedDisplay
+ beq t1,t0,10f // brnach if loop on error.
+ move s8,a0 // save register a0
+ lui t0,LED_BLINK // get LED blink code
+ jal v0 // Blink LED and hang.
+ or a0,a3,t0 // pass a3 as argument in a0
+10:
+ lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code
+ jal v0 // Set LOOP ON ERROR on LED
+ or a0,a3,t0 // pass a3 as argument in a0
+ b CheckAddressTest // Loop back to test again.
+ move a0,s8 // restoring arguments.
+ .end CheckAddressTest
+
+/*++
+VOID
+CheckNoXorAddressTest(
+ StartAddress
+ Size
+ not used
+ LedDisplayValue
+ )
+Routine Description:
+
+ This routine will check that each location contains it's address.
+ as written by WriteNoXorAddressTest.
+
+Arguments:
+
+ Note: the values of the arguments are preserved.
+
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+ a2 - Not used
+ a3 - suplies the value to display in the led in case of failure
+
+Return Value:
+
+ This routine returns no value.
+ The routine hangs blinking the LED or looping if the loop on error
+ bit is set in the config register.
+--*/
+ LEAF_ENTRY(CheckNoXorAddressTest)
+ addiu t3,a0,-4 // t3 first address-4
+ add t2,a0,a1 // last address.
+ addiu t2,t2,-8 // adjust
+ move t1,t3 // get copy of t3 just for first check
+checkaddressNX:
+ bne t1,t3,PatternFailNX
+ lw t1,4(t3) // load from first location
+ addiu t3,t3,4 // compute next address
+ bne t1,t3,PatternFailNX
+ lw t1,4(t3) // load from next location
+ addiu t3,t3,4 // compute next address
+ bne t1,t3,PatternFailNX
+ lw t1,4(t3) // load from next location
+ addiu t3,t3,4 // compute next address
+ bne t1,t3,PatternFailNX // check
+ lw t1,4(t3) // load from next location
+ bne t3,t2, checkaddressNX // check for end condition
+ addiu t3,t3,4 // compute next address
+ bne t1,t3,PatternFailNX // check last
+ nop
+ j ra // return a zero to the caller
+ move v0,zero //
+PatternFailNX:
+ //
+ // check if we are in loop on error
+ //
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register
+ lb t0,0(t0) // read register value.
+ li t1,LOOP_ON_ERROR_MASK // get value to compare
+ andi t0,DIAGNOSTIC_MASK // mask diagnostic bits.
+ li v0,PROM_ENTRY(14) // load address of PutLedDisplay
+ beq t1,t0,10f // brnach if loop on error.
+ move s8,a0 // save register a0
+ lui t0,LED_BLINK // get LED blink code
+ jal v0 // Blink LED and hang.
+ or a0,a3,t0 // pass a3 as argument in a0
+10:
+ lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code
+ jal v0 // Set LOOP ON ERROR on LED
+ or a0,a3,t0 // pass a3 as argument in a0
+ b CheckNoXorAddressTest // Loop back to test again.
+ move a0,s8 // restoring arguments.
+ .end CheckNoXorAddressTest
+
+
+/*++
+VOID
+ZeroMemory(
+ ULONG StartAddress
+ ULONG Size
+ );
+Routine Description:
+
+ This routine will zero a range of memory.
+
+Arguments:
+
+ a0 - supplies start of memory
+ a1 - supplies length of memory in bytes
+
+Return Value:
+
+ None.
+
+--*/
+ LEAF_ENTRY(ZeroMemory)
+ add a1,a1,a0 // Compute End address
+ addiu a1,a1,-4 // adjust address
+ZeroMemoryLoop:
+ sw zero,0(a0) // zero memory.
+ bne a0,a1,ZeroMemoryLoop // loop until done.
+ addiu a0,a0,4 // compute next address
+ j ra // return
+ nop
+ ALTERNATE_ENTRY(ZeroMemoryEnd)
+ nop
+ .end ZeroMemory
+
+//++
+//
+//PULONG
+//Decompress(
+// IN PULONG InputImage,
+// IN PULONG OutputImage
+// )
+//
+//
+//Routine Description:
+//
+// This routine decompresses the input image.
+//
+//Arguments:
+//
+// InputImage (a0) - byte pointer to the image to be decompressed.
+// OutputImage (a1) - byte pointer to the area to write decompressed image.
+//
+// N.B. The first ULONG of the InputImage contains the decompressed length in bytes.
+// See romcomp.c for a description of method.
+//
+//Return Value:
+//
+// None.
+//
+//--
+
+.set reorder
+ LEAF_ENTRY(Decompress)
+
+ lw a2,(a0) // get the target size.
+ srl a2,a2,2 // get size of output in words/symbols.
+ addiu a0,a0,4 // address of next word
+ move a3,a1 // stash output image base
+
+//
+// Calculate the offset width from the size. Assume size > 2 ULONG.
+//
+#define SHORT_INDEX_WIDTH 10
+
+ li t8,1 // start at two
+ srl t0,a2,1 // offset must only span half the image.
+5:
+ addiu t8,t8,1 // next bit
+ srl t1,t0,t8 // shift off low bits
+ bgtz t1,5b // quit when we find the highest set bit.
+
+//
+// Set the symbol register bit count to zero so that on the first iteration of the loop we will
+// get the first symbol longword. Add one to the symbol count to allow for first loop entry.
+//
+
+ li t1,0 // number of valid bits
+ addiu a2,a2,1 // increment symbol count
+
+//
+// Loop, decompressing the data. There is always at least one bit in the register at this point.
+//
+
+10:
+
+//
+// Decrement the symbol count and exit the loop when done.
+//
+
+ addiu a2,a2,-1 // decrement symbol count
+ beq zero,a2,99f // return
+
+//
+// Load symbol register if it is empty.
+//
+
+ bne zero,t1,12f // check for lack of bits
+ lw t0,(a0) // get the next word
+ addiu a0,a0,4 // address of next word
+ li t1,32 // number of valid bits
+12:
+
+//
+// Test first bit of symbol
+//
+
+ andi t2,t0,0x1 // test the low bit
+ addiu t1,t1,-1 // decrement bit count
+ srl t0,t0,1 // shift symbol
+ bne zero,t1,20f // check for lack of bits
+ lw t0,(a0) // get the next word
+ addiu a0,a0,4 // address of next word
+ li t1,32 // number of valid bits
+20:
+ bne zero,t2,50f // if not zero then this is an index
+
+30:
+
+//
+// First bit of symbol is zero, this is the zero or unique case. Check the next bit.
+//
+
+ andi t2,t0,0x1 // test the low bit
+ addiu t1,t1,-1 // decrement bit count
+ srl t0,t0,1 // shift symbol
+ bne zero,t2,40f // if not zero then this is a unique word symbol
+
+//
+// This is the zero case. 0b00
+//
+
+ sw zero,(a1) // store the zero
+ addiu a1,a1,4 // increment the output image pointer
+ b 10b // go get the next symbol.
+
+//
+// The symbol is a unique word. 0b10. Get the next 32 bits and write them to the output.
+//
+// The symbol register contains 0 to 31 bits of the word to be written. Get the next
+// word, shift and merge it with the existing symbol to produce a complete word. The remainder
+// of the new word becomes the next symbol register contents.
+//
+// Note that since we read a new word we don't have to decrement the bit counter since it runs
+// mod 32.
+//
+
+40:
+ lw t3,(a0) // get next word
+ addiu a0,a0,4 // address of next word
+
+ sll t2,t3,t1 // shift it by the bit count
+ or t0,t0,t2 // put it in with the existing contents of the symbol register
+
+ sw t0,(a1) // store the word
+ addiu a1,a1,4 // increment the output image pointer
+
+ li t2,32 // get shift count for new word to make new symbol register
+ subu t2,t2,t1 //
+ srl t0,t3,t2 // new contents of symbol register. For bit count zero case
+ // this is a nop
+
+ b 10b // go get the next symbol.
+
+//
+// This is the index case. 0bX1. Now the next bit determines whether the offset is relative(1) or
+// absolute(0). Stash the next bit for when we use the offset.
+//
+
+50:
+ andi t4,t0,0x1 // get the relative/absolute bit
+ addiu t1,t1,-1 // decrement bit count
+ srl t0,t0,1 // shift symbol
+ bne zero,t1,55f // check for lack of bits
+ lw t0,(a0) // get the next word
+ addiu a0,a0,4 // address of next word
+ li t1,32 // number of valid bits
+55:
+
+//
+// Get the next bit. This tells us whether we have a long(0) or a short(1) index.
+//
+
+ andi t2,t0,0x1 // test the low bit
+ addiu t1,t1,-1 // decrement bit count
+ srl t0,t0,1 // shift symbol
+ bne zero,t1,60f // check for lack of bits
+ lw t0,(a0) // get the next word
+ addiu a0,a0,4 // address of next word
+ li t1,32 // number of valid bits
+60:
+ li t5,SHORT_INDEX_WIDTH // preload with short index width
+ bne zero,t2,70f // if not zero then this is a short index.
+ move t5,t8 // use long index width
+
+//
+// Get the index based on the width. If the currently available bits are less than the
+// number that we need then we must read another word.
+//
+70:
+ li t7,0 // zero the remainder
+ sub t2,t5,t1 // get difference between what we need and what we have
+ blez t2,75f // if we got what we need
+
+ lw t6,(a0) // get next word
+ addiu a0,a0,4 // address of next word
+ sll t7,t6,t1 // shift new bits into position
+ or t0,t0,t7 // move new bits into symbol register
+ srl t7,t6,t2 // adjust remainder
+ addiu t1,t1,32 // pre-bias the bit count for later decrement.
+
+75:
+ li t3,1 // grab a one
+ sll t3,t3,t5 // shift it by number of bits we will extract
+ addiu t3,t3,-1 // make a mask
+ and t2,t0,t3 // grab the index
+ sll t2,t2,2 // make it a byte index
+ srl t0,t0,t5 // shift out bits we used.
+ or t0,t0,t7 // merge in remainder if any.
+ sub t1,t1,t5 // decrement the bit count, correct regardless
+
+//
+// Use index to write output based on the absolute(0)/relative(1) bit.
+//
+80:
+ bne zero,t4,85f // test for the relative case.
+ addu t3,a3,t2 // address by absolute
+ b 87f // go move the word
+85:
+ subu t3,a1,t2 // address by relative
+
+//
+// Move the byte.
+//
+87:
+ lw t2,(t3) // get the word
+ sw t2,(a1) // store the word
+ addiu a1,a1,4 // increment output pointer
+ b 10b // go do next symbol
+
+//
+// Return
+//
+
+99:
+
+ j ra // return
+
+ .end Decompress
+.set noreorder
+
+/*++
+VOID
+DataCopy(
+ ULONG SourceAddress
+ ULONG DestinationAddress
+ ULONG Length
+ );
+Routine Description:
+
+ This routine will copy data from one location to another
+ Source, destination, and length must be dword aligned.
+
+Arguments:
+
+ a0 - supplies source of data
+ a1 - supplies destination of data
+ a2 - supplies length of data in bytes
+
+Return Value:
+
+ None.
+--*/
+
+ LEAF_ENTRY(DataCopy)
+ add a2,a2,a0 // get last address
+CopyLoop:
+ ldc1 f0,0(a0) // load 1st double word
+ ldc1 f2,8(a0) // load 2nd double word
+ addiu a0,a0,16 // increment source pointer
+ sdc1 f0,0(a1) // store 1st double word
+ sdc1 f2,8(a1) // store 2nd double word
+ bne a0,a2,CopyLoop // loop until address=last address
+ addiu a1,a1,16 // increment destination pointer
+ j ra // return
+ nop
+ .align 4 // Align it to 16 bytes boundary so that
+ ALTERNATE_ENTRY(EndMemoryRoutines) // DataCopy doesn't need to check alignments
+ nop
+ .end DataCopy
+
+/*++
+VOID
+ProcessorTest(
+ VOID
+ );
+
+Routine Description:
+
+ This routine tests the processor. Test uses all registers and almost all
+ the instructions.
+
+ N.B. This routine destroys the values in all of the registers.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None, but will hang flashing the led if an error occurs.
+
+--*/
+ LEAF_ENTRY(ProcessorTest)
+ lui a0,0x1234 // a0=0x12340000
+ ori a1,a0,0x4321 // a1=0x12344321
+ add a2,zero,a0 // a2=0x12340000
+ addiu a3,zero,-0x4321 // a3=0xFFFFBCDF
+ subu AT,a2,a3 // AT=0x12344321
+ bne a1,AT,ProcessorError // branch if no match match
+ andi v0,a3,0xFFFF // v0=0x0000BCDF
+ ori v1,v0,0xFFFF // v1=0x0000FFFF
+ sll t0,v1,16 // t0=0xFFFF0000
+ xor t1,t0,v1 // t1=0xFFFFFFFF
+ sra t2,t0,16 // t2=0xFFFFFFFF
+ beq t1,t2,10f // if eq good
+ srl t3,t0,24 // t3=0x000000FF
+ j ProcessorError // if wasn't eq error.
+10: sltu s0,t0,v1 // S0=0 because t0 > v1
+ bgtz s0,ProcessorError // if s0 > zero error
+ or t4,AT,v0 // t4=X
+ bltz s0,ProcessorError // if s0 < zero error
+ nor t5,v0,AT // t5=~X
+ and t6,t4,t5 // t6=0
+ move s0,ra // save ra in s0
+ bltzal t6,ProcessorError // if t6 < 0 error, load ra in case
+ nop
+RaAddress:
+ //la t7,RaAddress - LINK_ADDRESS + RESET_VECTOR // get expected address in ra
+ la t7,RaAddress // get expected address in ra
+ bne ra,t7,ProcessorError // error if don't match
+ move ra,s0 // put ra back
+ ori s1,zero,0x100 // load constant
+ mult s1,t3 // 0x100*0xFF
+ mfhi s3 // s3=0
+ mflo s2 // s2=0xFF00
+ blez s3,10f // branch if correct
+ sll s4,t3,zero // move t3 into s4
+ addiu s4,100 // change value in s4 to produce an error
+10: divu s5,s2,s4 // divide 0xFF00/0xFF
+ nop
+ nop
+ mfhi s6 // remainder s6=0
+ bne s5,s1,ProcessorError
+ nop
+ blez s6,10f // branch if no error
+ nop
+ j ProcessorError
+10: sub s7,s5,s4 // s7=1
+ mthi s7
+ mtlo AT
+ xori gp,s5,0x2566 // gp=0x2466
+ move s0,sp // save sp for now
+ srl sp,gp,s7 // sp=0x1233
+ mflo s8 // s8=0x12344321
+ mfhi k0 // k0=1
+ ori k1,zero,16 // k1=16
+ sra k1,s8,k1 // k1=0x1234
+ add AT,sp,k0 // AT=0x1234
+ bne k1,AT,ProcessorError // branch on error
+ nop
+#ifdef R4001
+ //
+ // Some extra stuff added to verify that the R4000 bug is fixed
+ // If it hangs a minus sign will be displayed in the LED
+ //
+ li t0,DIAGNOSTIC_VIRTUAL_BASE
+ li t1,0xB // value to display '-' in the LED
+ sw t1,0(t0) // write to the LED should be sb
+ lw t2,8(t0) // do something
+ sll t5,t0,t1 // 2 cycle instruction
+#endif
+ j ra // return
+ nop
+ProcessorError:
+ lui a0,LED_BLINK // blink also means that
+ bal PutLedDisplay // the routine hangs.
+ ori a0,LED_PROCESSOR_TEST // displaying this value.
+ .end ProcessorTest
+
+
+/*++
+VOID
+MctadrReset(
+ VOID
+ );
+
+Routine Description:
+
+ This routine tests the reset values of the MCT_ADR asic.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None, but will hang flashing the led if an error occurs.
+
+--*/
+ LEAF_ENTRY(MctadrResetTest)
+ move s0,ra // save return address.
+//
+// Test the mctadr reset values.
+//
+MctadrReset:
+ li t0,DMA_VIRTUAL_BASE // Get base address of MCTADR
+ lw v0,DmaConfiguration(t0) // Check Config reset value
+ li t1,CONFIG_RESET_MCTADR_REV1 // Check for REV1 ASIC, i.e. JAZZ
+ beq v0,t1,10f
+ li t1,CONFIG_RESET_MCTADR_REV2 // Check for REV2 ASIC, i.e. FIS/USION
+ bne v0,t1,MctadrResetError
+ lw v0,DmaRevisionLevel(t0) // Get revision level register
+ slti t1,v0,3 // Check for REV3 ASIC
+ bnez t1,5f // If not REV3 or greater, enable interrupts
+ nop
+ mfc0 t1,config // Get R4000 config register
+ srl t2,t1,CONFIG_SC // check for secondary cache
+ and t2,t2,1 // isolate the bit
+ beq t2,zero,5f // if secondary cache, enable interrupts
+ nop
+ b 10f // Fision with REV3 or greater, don't
+ nop // enable interrups over the bus
+
+5:
+ addiu t1,t0,DmaRemoteSpeed15 // DmaRemoteSpeed15 is the interrupt
+ // enable register in REV2
+ li v0,0x3f // MCTADR interrupt enable mask
+ sw v0,0(t1) // Enable interrupts in MCTADR
+
+10:
+ lw v0,DmaInvalidAddress(t0)
+ lw v1,DmaTranslationBase(t0)
+ bne v0,zero,MctadrResetError // Check LFAR reset value
+ lw v0,DmaTranslationLimit(t0)
+ bne v1,zero,MctadrResetError // Check Ttable base reset value
+ lw v1,DmaRemoteFailedAddress(t0)
+ bne v0,zero,MctadrResetError // Check TT limit reset value
+ lw v0,DmaMemoryFailedAddress(t0)
+ bne v1,zero,MctadrResetError // Check RFAR reset value
+ lw v1,DmaByteMask(t0)
+ bne v0,zero,MctadrResetError // Check MFAR reset value
+ addiu t1,t0,DmaRemoteSpeed0 // address of REM_SPEED 0
+ bne v1,zero,MctadrResetError // Check TT_BMASK reset value
+ addiu t2,t0,DmaRemoteSpeed14 // address of REM_SPEED 14
+ // Don't check 15 because this is
+ // the interrupt enable for REV2
+ lw v0,0(t1) // read register
+ li t3,REMSPEED_RESET //
+ addiu t1,t1,8 // next register address.
+NextRemSpeed:
+ bne v0,t3,MctadrResetError // Check Rem speed reg reset value
+ lw v0,0(t1) // read next rem speed
+ bne t1,t2,NextRemSpeed
+ addiu t1,t1,8 // next register address.
+ bne v0,t3,MctadrResetError // Check last Rem speed reg reset value
+ addiu t1,t0,DmaChannel0Mode // address of first channel register
+ addiu t2,t0,DmaChannel7Address // address of last channel register
+ lw v0,0(t1) // read register
+ addiu t1,t1,8 // next register address.
+NextChannelReg:
+ bne v0,zero,MctadrResetError // Check channel reg reset value
+ lw v0,0(t1) // read next channel
+ bne t1,t2,NextChannelReg
+ addiu t1,t1,8 // next register address.
+ bne v0,zero,MctadrResetError // Checklast channel reg reset value
+ lw v0,DmaInterruptSource(t0)// read DMA Channel interrupt
+ lw v1,DmaErrortype(t0) // read eisa/ethernet error reg
+ bne v0,zero,MctadrResetError // check Intpend
+ lw v0,DmaRefreshRate(t0)
+ bne v1,zero,MctadrResetError // check Eisa error type reset value
+ li t1,REFRRATE_RESET
+ bne v0,t1,MctadrResetError // check Refresh rate reset value
+ lw v0,DmaSystemSecurity(t0)
+ li t1,SECURITY_RESET
+ bne v0,t1,MctadrResetError // check Security reg reset value
+ lw v0,DmaInterruptAcknowledge(t0) // read register but don't check
+ j s0 // return to caller
+MctadrResetError:
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register
+ lb t0,0(t0) // read register value.
+ li t1,LOOP_ON_ERROR_MASK // get value to compare
+ andi t0,DIAGNOSTIC_MASK // mask diagnostic bits.
+ beq t1,t0,10f // branch if loop on error.
+ ori a0,zero,LED_MCTADR_RESET// load LED display value.
+ lui t0,LED_BLINK // get LED blink code
+ bal PutLedDisplay // Blink LED and hang.
+ or a0,a0,t0 // pass argument in a0
+10:
+ lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code
+ bal PutLedDisplay // Set LOOP ON ERROR on LED
+ or a0,a0,t0 // pass argument in a0
+ b MctadrReset
+ nop
+ .end MctadrResetTest
+
+
+/*++
+VOID
+MctadrRegisterTest(
+ VOID
+ );
+
+Routine Description:
+
+ This routine tests the MCT_ADR registers.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None, but will hang flashing the led if an error occurs.
+
+--*/
+ LEAF_ENTRY(MctadrRegisterTest)
+ move s0,ra // save return address.
+//
+// Check the data path between R4K and Mctadr by writing to Byte mask reg.
+//
+MctadrReg:
+ li t0,DMA_VIRTUAL_BASE
+ lw v0,DmaConfiguration(t0) // Check Config reset value
+ li t1,CONFIG_RESET_MCTADR_REV1 // Check for REV1 ASIC, i.e. JAZZ
+ beq v0,t1,10f
+ li t1,0x17F // For Jazz, 2Mb Video, 64 Mb Main
+ li t1,0x5fa // For FIS/USION, 2MB Video, 256 MBytes Main
+10:
+ sw t1,DmaConfiguration(t0) // Init Global Config
+ lw v0,DmaConfiguration(t0) // Read Configuration
+ nop
+ bne v0,t1,MctadrRegError // check GLOBAL CONFIG
+ sw zero,DmaCacheMaintenance(t0)// select cache block zero.
+ li t1,1
+ sw t1,DmaLogicalTag(t0) // Set LFN=zero, Offset=0 , Direction=READ from memory, Valid
+ li t2,0x55555555
+ sw t2,DmaByteMask(t0) // write pattern to Byte mask
+ lw v0,DmaByteMask(t0) // read Byte mask
+ sw t1,DmaPhysicalTag(t0) // PFN=0 and Valid
+ bne v0,t2,MctadrRegError //
+ addu t2,t2,t2 // t1=0xAAAAAAAA
+ sw t2,DmaByteMask(t0) // write patten to Byte mask
+ lw v0,DmaByteMask(t0) // read Byte mask
+ li t2,0xFFFFFFFF // expected value
+ bne v0,t2,MctadrRegError // Check byte mask
+ li a0,0xA0000000 // get memory address zero.
+ sw zero,0(a0) // write address zero -> flushes buffers
+ lw v0,DmaByteMask(t0) // read Byte mask
+ nop
+ bne v0,zero,MctadrRegError // Check byte mask was cleared.
+ li t4,MEMORY_REFRESH_RATE //
+ sw t4,DmaRefreshRate(t0) //
+ li t2,0x1555000 //
+ sw t2,DmaTranslationBase(t0) // write base of Translation Table
+ li t3,0x5550
+ sw t3,DmaTranslationLimit(t0) // write to TT_limit
+ lw v1,DmaTranslationBase(t0) // read TT Base
+ lw v0,DmaTranslationLimit(t0) // read TT_limit
+ bne v1,t2,MctadrRegError // check TT-BASE
+ lw v1,DmaRefreshRate(t0)
+ bne v0,t3,MctadrRegError // check TT-LIMIT
+ li t2,0xAAA0
+ bne v1,t4,MctadrRegError // check REFRESH Rate
+ li t1,0x2AAA000
+ sw t1,DmaTranslationBase(t0) // write to Translation Base
+ sw t2,DmaTranslationLimit(t0) // write to Translation Limit
+ lw v0,DmaTranslationBase(t0) // read TT Base
+ lw v1,DmaTranslationLimit(t0) // read TT limit
+ bne v0,t1,MctadrRegError // check TT Base
+ li t1, TT_BASE_ADDRESS // Init translation table base address
+ sw t1, DmaTranslationBase(t0) // Initialize TT Base
+ bne v1,t2,MctadrRegError // check TT Limit
+ nop
+ sw zero,DmaTranslationLimit(t0) // clear TT Limit
+//
+// Initialize remote speed registers.
+//
+ addiu t1,t0,DmaRemoteSpeed1 // address of REM_SPEED 1
+ la a1,RomRemoteSpeedValues - LINK_ADDRESS + RESET_VECTOR //
+ addiu t2,a1,14 // addres of last value
+WriteNextRemSpeed:
+ lbu v0,0(a1) // load init value for rem speed
+ addiu a1,a1,1 // compute next address
+ sw v0,0(t1) // write to rem speed reg
+ bne a1,t2,WriteNextRemSpeed // check for end condition
+ addiu t1,t1,8 // next register address
+ addiu a1,t2,-14 // address of first value for rem speed register
+ addiu t1,t0,DmaRemoteSpeed1 // address of REM_SPEED 1
+ lbu v1,0(a1) // read expected value
+CheckNextRemSpeed:
+ lw v0,0(t1) // read register
+ addiu a1,a1,1 // address of next value
+ bne v0,v1,MctadrRegError // check register
+ addiu t1,t1,8 // address of next register
+ bne a1,t2,CheckNextRemSpeed // check for end condition
+ lbu v1,0(a1) // read expected value
+//
+// Now test the DMA channel registers
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,8*DMA_CHANNEL_GAP // last address of channel regs
+ li a0,0x15 // Mode
+ li a1,0x2 // enable
+ li a2,0xAAAAA // byte count
+ li a3,0x555555 // address
+WriteNextChannel:
+ sw a0,0(t1) // write mode
+ sw a1,0x8(t1) // write enable
+ sw a2,0x10(t1) // write byte count
+ sw a3,0x18(t1) // write address
+ addiu t1,t1,DMA_CHANNEL_GAP // compute address of next channel
+ addiu a2,a2,1 // change addres
+ bne t1,t2,WriteNextChannel
+ addiu a3,a3,-1 // change Byte count
+//
+// Check channel regs.
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,8*DMA_CHANNEL_GAP // last address of channel regs
+ li a2,0xAAAAA // byte count
+ li a3,0x555555 // address
+CheckNextChannel:
+ lw t4,0x0(t1) // read mode
+ lw t5,0x8(t1) // read enable
+ bne t4,a0,MctadrRegError // check mode
+ lw t4,0x10(t1) // read byte count
+ bne t5,a1,MctadrRegError // check enable
+ lw t5,0x18(t1) // read address
+ bne t4,a2,MctadrRegError // check abyte count
+ addiu a2,a2,1 // next expected byte count
+ bne t5,a3,MctadrRegError // check address
+ addiu t1,t1,DMA_CHANNEL_GAP // next channel address
+ bne t1,t2,CheckNextChannel
+ addiu a3,a3,-1
+//
+// Now do a second test on DMA channel registers
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,8*DMA_CHANNEL_GAP // last address of channel regs
+ li a0,0x2A // Mode
+ li a2,0x55555 // byte count
+ li a3,0xAAAAAA // address
+WriteNextChannel2:
+ sw a0,0(t1) // write mode
+ sw a2,0x10(t1) // write byte count
+ sw a3,0x18(t1) // write address
+ addiu t1,t1,DMA_CHANNEL_GAP // compute address of next channel
+ addiu a2,a2,1 // change addres
+ bne t1,t2,WriteNextChannel2
+ addiu a3,a3,-1 // change Byte count
+//
+// Check channel regs.
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,8*DMA_CHANNEL_GAP // last address of channel regs
+ li a2,0x55555 // byte count
+ li a3,0xAAAAAA // address
+CheckNextChannel2:
+ lw t4,0x0(t1) // read mode
+ lw t5,0x10(t1) // read byte count
+ bne t4,a0,MctadrRegError // check mode
+ lw t4,0x18(t1) // read address
+ bne t5,a2,MctadrRegError // check abyte count
+ addiu a2,a2,1 // next expected byte count
+ bne t4,a3,MctadrRegError // check address
+ addiu t1,t1,DMA_CHANNEL_GAP // next channel address
+ bne t1,t2,CheckNextChannel2
+ addiu a3,a3,-1
+//
+// Now zero the channel registers
+//
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,8*DMA_CHANNEL_GAP // last address of channel regs
+ZeroChannelRegs:
+ addiu t1,t1,8
+ sw zero,-8(t1) // clear reg
+ bne t1,t2,ZeroChannelRegs
+ nop //R4KFIX
+ addiu t1,t0,DmaChannel0Mode // address of channel 0
+ addiu t2,t1,8*DMA_CHANNEL_GAP // last address of channel regs
+CheckZeroedChannelRegs:
+ lw a0,0(t1)
+ addiu t1,t1,8 // next channel
+ bne a0,zero,MctadrRegError // check
+ nop
+ bne t1,t2,CheckZeroedChannelRegs
+ nop
+ j s0 // return to caller.
+MctadrRegError:
+ li t0,DIAGNOSTIC_VIRTUAL_BASE // get base address of diag register
+ lb t0,0(t0) // read register value.
+ li t1,LOOP_ON_ERROR_MASK // get value to compare
+ andi t0,DIAGNOSTIC_MASK // mask diagnostic bits.
+ beq t1,t0,10f // branch if loop on error.
+ ori a0,zero,LED_MCTADR_REG // load LED display value.
+ lui t0,LED_BLINK // get LED blink code
+ bal PutLedDisplay // Blink LED and hang.
+ or a0,a0,t0 // pass argument in a0
+10:
+ lui t0,LED_LOOP_ERROR // get LED LOOP_ERROR code
+ bal PutLedDisplay // Set LOOP ON ERROR on LED
+ or a0,a0,t0 // pass argument in a0
+ b MctadrReg
+ nop
+ .end MctadrRegisterTest
+
+/*++
+SizeMemory(
+ );
+Routine Description:
+
+ This routine sizes the memory and writes the proper value into
+ the GLOBAL CONFIG register. The way memory is sized is the following:
+
+ For JAZZ:
+
+ The global config is ALREADY set to 64MB
+ for each bank base address i.e. 48,32,16,0 MB
+ ID0 is written to offset 0 from base of bank
+ ID4 is written to offset 4MB from base of bank
+ if ID4 is found at offset 0 the current bank has 1MB SIMMs.
+ if ID0 is found at offset 0 and ID4 is found at offset 4,
+ the current bank has 4MB SIMMs.
+ if data does not match or a parity exception is taken
+ then memory is not present in that bank.
+
+ For FIS/USION:
+
+ The global config is ALREADY set to 256MB
+ for each bank base address i.e. 192,128,64,0 MB
+ ID0 is written to offset 0 from base of bank
+ ID4 is written to offset 4MB from base of bank
+ ID20 is written to offset 20MB from base of bank
+ if ID20 is found at offset 0 the current bank has 1MB SIMMs.
+ if ID0 is found at offset 0 and ID20 is found at offset 4,
+ the current bank has 4MB SIMMs.
+ if ID0 is found at offset 0 and ID4 is found at offset 4
+ and ID20 is found at offset 20, the current bank has 16MB SIMMs.
+ if data does not match or a parity exception is taken
+ then memory is not present in that bank.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the installed memory is inconsistent, does not return
+ and the LED flashes A.E
+
+--*/
+#define MEM_ID0 0x0A0A0A0A
+#define MEM_ID4 0xF5F5F5F5
+#define MEM_ID20 0xA0A0A0A0
+
+ LEAF_ENTRY(SizeMemory)
+ .set noat
+ .set noreorder
+ li t0,DMA_VIRTUAL_BASE // Get base address of MCTADR
+ lw v0,DmaConfiguration(t0) // Check Config reset value
+ li t1,0x5fa // FIS/USION
+ beq v0,t1,Fission // Branch if 256 MByte config value found
+ li t0,0xA3000000 // get address 48MB
+ li t1,MEM_ID0 // get ID0
+ li t2,0xA3400000 // get address 52MB
+ li t3,MEM_ID4 // get ID4
+ li s0,3 // counts how many banks left to check
+ move t8,zero // t8 stores the present banks
+ move t9,zero // t9 stores the size of the banks
+SizeBank:
+ move a1,zero // set current bank to 1 MB by default
+ sw t1,0x0(t0) // fill whole memory line at base of bank
+ sw t1,0x4(t0)
+ sw t1,0x8(t0)
+ sw t1,0xC(t0)
+ sw t3,0x0(t2) // fill whole memory line at base of bank + 4MB
+ sw t3,0x4(t2)
+ sw t3,0x8(t2)
+ sw t3,0xC(t2)
+ //
+ // Check written2data
+ //
+ lw t4,0x0(t0) // read whole memory line.
+ lw t5,0x4(t0) // the four words must be identical
+ lw t6,0x8(t0) //
+ lw t7,0xC(t0) //
+ move a0,zero // tells that bank not present
+ bne t4,t5,10f // check for consistency
+ nop
+ bne t4,t6,10f // check for consistency
+ nop //
+ bne t4,t7,10f // check for consistency
+ nop //
+ beq t4,t3,10f // If ID4 is found at PA 0
+ li a0,0x1 // bank is present and SIMMS are 1 MB
+ bne t4,t1,10f // if neither ID4 nor ID0 is found we are in trouble
+ move a0,zero // no memory in bank
+ li a0,0x1 // bank is present and SIMMS
+ // look like they are 4 MB
+ //
+ // ID written at Address 0 has been correctly checked
+ // Now check the ID written at address 4MB
+ //
+ lw t4,0x0(t2) // read whole memory line.
+ lw t5,0x4(t2) // the four words must be identical
+ bne t3,t4,10f // check for consistency
+ lw t6,0x8(t2) //
+ bne t3,t5,10f // check for consistency
+ lw t7,0xC(t2) //
+ bne t3,t6,10f // check for consistency
+ nop //
+ bne t3,t7,10f // check for consistency
+ nop
+ li a1,0x1 // If all matches SIMMs are 4MB
+10: //
+ // a0 has the value 0 if no memory in bank 1 if memory in bank
+ // a1 has the value 0 if 1MB SIMMS 1 if 4MB SIMMS
+ //
+ or t8,t8,a0 // accummulate present banks
+ or t9,t9,a1 // accummulate size of banks
+ //
+ // Check if last bank
+ //
+ beq s0,zero,Done
+ //
+ // Now set addresses to check next bank
+ //
+ li AT,0x01000000 // load 16MB
+ subu t0,t0,AT // subtract to base address
+ subu t2,t2,AT // subtract to base address + 4MB
+ sll t8,t8,1 // make room for next bank
+ sll t9,t9,1 // make room for next bank
+ b SizeBank // go to size next memory bank
+ addiu s0,s0,-1 // subtract one to the num of banks left
+Done: //
+ // t8 has the present banks in bits 3-0 for banks 3-0
+ // t9 has the size of the banks in bits 3-2 and 1-0
+ //
+ // Check that memory is present in bank zero
+ //
+ andi t0,t8,1
+ beq t0,zero,WrongMemory
+
+ sll t8,t8,2 // shift bank enable bits to bits 5-2
+ andi t9,t9,0x3 // get rid of bits 2-3
+ or t8,t9,t8 // or size of banks with present banks
+ ori v0,t8,0x340 // Set Video RAM size and map PROM bits
+ li t0,DMA_VIRTUAL_BASE // Get base address of MCTADR
+ sw v0,DmaConfiguration(t0) // Store computed Config
+ j ra // return to caller.
+ nop
+
+Fission:
+ li t0,0xAC000000 // get address 196MB
+ li t1,MEM_ID0 // get ID0
+ li t2,0xAC400000 // get address 200MB
+ li t3,MEM_ID4 // get ID4
+ li t4,0xAD400000 // get address 216MB
+ li t5,MEM_ID20 // get ID20
+ li s0,3 // counts how many banks left to check
+ move t8,zero // t8 stores the present banks
+ move t9,zero // t9 stores the size of the banks
+FSizeBank:
+ move a1,zero // set current bank to 1 MB by default
+ sw t1,0x0(t0) // fill whole memory line at base of bank
+ sw t1,0x4(t0)
+ sw t1,0x8(t0)
+ sw t1,0xC(t0)
+ sw t3,0x0(t2) // fill whole memory line at base of bank + 4MB
+ sw t3,0x4(t2)
+ sw t3,0x8(t2)
+ sw t3,0xC(t2)
+ sw t5,0x0(t4) // fill whole memory line at base of bank + 20MB
+ sw t5,0x4(t4)
+ sw t5,0x8(t4)
+ sw t5,0xC(t4)
+ //
+ // Check written data
+ //
+ lw t6,0x0(t0) // read some of the memory line.
+ lw t7,0xC(t0) // the two words must be identical
+
+ move a0,zero // tells that bank not present
+ bne t6,t7,10f // check for consistency
+ nop
+ beq t6,t5,10f // If ID20 is found at 0MB
+ li a0,0x1 // bank is present and SIMMS are 1 MB
+ bne t6,t1,10f // if neither ID20 nor ID0 is found we are in trouble
+ move a0,zero // no memory in bank
+ li a0,0x1 // bank is present
+ //
+ // ID written at Address 0 has been correctly checked
+ // Now check the ID written at address 4MB
+ //
+ lw t6,0x0(t2) // read some of the memory line.
+ lw t7,0xC(t2) // the two words must be identical
+ nop
+ bne t6,t7,WrongMemory // check for consistency
+ nop
+ beq t6,t5,10f // If ID20 is found at 4MB
+ li a1,0x1 // bank is present and SIMMS are 4 MB
+ bne t6,t3,WrongMemory // if neither ID20 nor ID4 is found we are in trouble
+ nop
+ //
+ // ID written at Address 4MB has been correctly checked
+ // Now check the ID written at address 20MB
+ //
+ lw t6,0x0(t4) // read some of the memory line.
+ lw t7,0xC(t4) // the two words must be identical
+ nop
+ bne t6,t7,WrongMemory // check for consistency
+ nop
+ bne t6,t5,WrongMemory // if ID20 is not found we are in trouble
+ nop
+ li a1,0x2 // If all matches SIMMs are 16MB
+10: //
+ // a0 has the value 0 if no memory in bank, 1 if memory in bank
+ // a1 has the value 0 if 1MB SIMMS, 1 if 4MB SIMMS, 2 if 16MB SIMMS
+ //
+ or t8,t8,a0 // accummulate present banks
+ or t9,t9,a1 // accummulate size of banks
+ //
+ // Check if last bank
+ //
+ beq s0,zero,FDone
+ nop
+ //
+ // Now set addresses to check next bank
+ //
+
+ beq s0,2,Swizzle // swizzle banks
+ li AT,0x04000000 // load +64
+ li AT,-0x08000000 // load -128MB
+Swizzle:
+ addu t0,t0,AT // add to base address
+ addu t2,t2,AT // add to base address + 4MB
+ addu t4,t4,AT // add to base address + 20MB
+
+ sll t8,t8,1 // make room for next bank
+ sll t9,t9,2 // make room for next bank
+ b FSizeBank // go to size next memory bank
+ addiu s0,s0,-1 // subtract one to the num of banks left
+FDone: //
+ // t8 has the present banks in bits 3-0 for banks 3-0
+ // t9 has the size of the banks in bits 7:6, 5:4, 3:2, and 1:0
+ //
+ // Check that memory is present in bank zero
+ //
+ andi t0,t8,1
+ beq t0,zero,WrongMemory
+
+ sll t8,t8,4 // shift bank enable bits to bits 7-4
+ andi t9,t9,0xF // get rid of size bits 7-4
+ or t8,t9,t8 // or size of banks with present banks
+ ori v0,t8,0x500 // Set Video RAM size and map PROM bits
+ li t0,DMA_VIRTUAL_BASE // Get base address of MCTADR
+ ori v0,0x1000 // Enable timer interrupts for REV3 and
+ // greater ASICS
+ sw v0,DmaConfiguration(t0) // Store computed Config
+ j ra // return to caller.
+ nop
+WrongMemory:
+ //
+ // Control reaches here if the memory can't be sized.
+ //
+ lui a0,LED_BLINK // Hang
+ bal PutLedDisplay // blinking the error code
+ ori a0,a0,LED_WRONG_MEMORY // in the LED
+ .end SizeMemory
+
+#endif // JAZZ && R4000
diff --git a/private/ntos/fw/mips/j4start.s b/private/ntos/fw/mips/j4start.s
new file mode 100644
index 000000000..e2057fde3
--- /dev/null
+++ b/private/ntos/fw/mips/j4start.s
@@ -0,0 +1,756 @@
+#if defined(JAZZ) && defined(R4000)
+
+// TITLE("NT System Boot Startup")
+//++
+//
+// Copyright (c) 1991 Microsoft Corporation
+//
+// Module Name:
+//
+// j4start.s
+//
+// Abstract:
+//
+// This module gains control after the ROM selftest has executed.
+// Its function is to initialize the hardware for the ARC firmware.
+//
+// Author:
+//
+// David N. Cutler (davec) 22-Apr-1991
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+
+#ifndef DUO
+#include "jazzprom.h"
+#else
+#include "duoprom.h"
+#endif
+
+#include "dmaregs.h"
+
+#define PROM_BASE (EEPROM_VIRTUAL_BASE)
+#define PROM_ENTRY(x) (PROM_BASE + ((x) * 8))
+
+
+//TEMPTEMP
+#define SECONDARY_CACHE_SIZE (1 << 20)
+
+//
+// This definitions must match the restart block in arc.h
+//
+
+#define RstBlkSavedState 0x28 // Offset to saved state area
+#define RstBlkRestartAdr 0x10
+#define RstBlkBootStatus 0x1C
+
+#define RstBlkFltF0 RstBlkSavedState+0x000
+#define RstBlkFltF1 RstBlkSavedState+0x004
+#define RstBlkFltF2 RstBlkSavedState+0x008
+#define RstBlkFltF3 RstBlkSavedState+0x00C
+#define RstBlkFltF4 RstBlkSavedState+0x010
+#define RstBlkFltF5 RstBlkSavedState+0x014
+#define RstBlkFltF6 RstBlkSavedState+0x018
+#define RstBlkFltF7 RstBlkSavedState+0x01C
+#define RstBlkFltF8 RstBlkSavedState+0x020
+#define RstBlkFltF9 RstBlkSavedState+0x024
+#define RstBlkFltF10 RstBlkSavedState+0x028
+#define RstBlkFltF11 RstBlkSavedState+0x02C
+#define RstBlkFltF12 RstBlkSavedState+0x030
+#define RstBlkFltF13 RstBlkSavedState+0x034
+#define RstBlkFltF14 RstBlkSavedState+0x038
+#define RstBlkFltF15 RstBlkSavedState+0x03C
+#define RstBlkFltF16 RstBlkSavedState+0x040
+#define RstBlkFltF17 RstBlkSavedState+0x044
+#define RstBlkFltF18 RstBlkSavedState+0x048
+#define RstBlkFltF19 RstBlkSavedState+0x04C
+#define RstBlkFltF20 RstBlkSavedState+0x050
+#define RstBlkFltF21 RstBlkSavedState+0x054
+#define RstBlkFltF22 RstBlkSavedState+0x058
+#define RstBlkFltF23 RstBlkSavedState+0x05C
+#define RstBlkFltF24 RstBlkSavedState+0x060
+#define RstBlkFltF25 RstBlkSavedState+0x064
+#define RstBlkFltF26 RstBlkSavedState+0x068
+#define RstBlkFltF27 RstBlkSavedState+0x06C
+#define RstBlkFltF28 RstBlkSavedState+0x070
+#define RstBlkFltF29 RstBlkSavedState+0x074
+#define RstBlkFltF30 RstBlkSavedState+0x078
+#define RstBlkFltF31 RstBlkSavedState+0x07C
+#define RstBlkFsr RstBlkSavedState+0x080
+#define RstBlkIntAt RstBlkSavedState+0x084
+#define RstBlkIntV0 RstBlkSavedState+0x088
+#define RstBlkIntV1 RstBlkSavedState+0x08C
+#define RstBlkIntA0 RstBlkSavedState+0x090
+#define RstBlkIntA1 RstBlkSavedState+0x094
+#define RstBlkIntA2 RstBlkSavedState+0x098
+#define RstBlkIntA3 RstBlkSavedState+0x09C
+#define RstBlkIntT0 RstBlkSavedState+0x0A0
+#define RstBlkIntT1 RstBlkSavedState+0x0A4
+#define RstBlkIntT2 RstBlkSavedState+0x0A8
+#define RstBlkIntT3 RstBlkSavedState+0x0AC
+#define RstBlkIntT4 RstBlkSavedState+0x0B0
+#define RstBlkIntT5 RstBlkSavedState+0x0B4
+#define RstBlkIntT6 RstBlkSavedState+0x0B8
+#define RstBlkIntT7 RstBlkSavedState+0x0BC
+#define RstBlkIntS0 RstBlkSavedState+0x0C0
+#define RstBlkIntS1 RstBlkSavedState+0x0C4
+#define RstBlkIntS2 RstBlkSavedState+0x0C8
+#define RstBlkIntS3 RstBlkSavedState+0x0CC
+#define RstBlkIntS4 RstBlkSavedState+0x0D0
+#define RstBlkIntS5 RstBlkSavedState+0x0D4
+#define RstBlkIntS6 RstBlkSavedState+0x0D8
+#define RstBlkIntS7 RstBlkSavedState+0x0DC
+#define RstBlkIntT8 RstBlkSavedState+0x0E0
+#define RstBlkIntT9 RstBlkSavedState+0x0E4
+#define RstBlkIntK0 RstBlkSavedState+0x0E8
+#define RstBlkIntK1 RstBlkSavedState+0x0EC
+#define RstBlkIntGp RstBlkSavedState+0x0F0
+#define RstBlkIntSp RstBlkSavedState+0x0F4
+#define RstBlkIntS8 RstBlkSavedState+0x0F8
+#define RstBlkIntRa RstBlkSavedState+0x0FC
+#define RstBlkIntLo RstBlkSavedState+0x100
+#define RstBlkIntHi RstBlkSavedState+0x104
+#define RstBlkPsr RstBlkSavedState+0x108
+#define RstBlkFir RstBlkSavedState+0x10C
+
+//
+// Define Boot status bits.
+//
+#define BootStarted (1 << 0)
+#define BootFinished (1 << 1)
+#define RestartStarted (1 << 2)
+#define RestartFinished (1 << 3)
+#define PowerFailStarted (1 << 4)
+#define PowerFailFinished (1 << 5)
+#define ProcessorReady (1 << 6)
+#define ProcessorRunning (1 << 7)
+#define ProcessorStart (1 << 8)
+
+
+.extern TimerTicks 4
+
+
+ SBTTL("Map PCR Routine")
+//++
+//
+// Routine Description:
+//
+// This routine is executed by processor B. It moves the current mapping
+// for the PCR (set to processor A's PCR) to be two pages below it.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(ReMapPCR)
+ .set noreorder
+ .set noat
+
+ li t0,((PCR_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+ mtc0 t0,entryhi
+ nop // 3 cycle hazard
+ nop //
+ nop //
+ tlbp // probe tlb.
+ nop // 2 cycle hazard
+ nop //
+ mfc0 t1,index // get result of probe
+ nop // 1 cycle hazard
+ bltz t1,30f // branch if entry not in the tlb
+ move v0,zero // set return value to false
+ tlbr // read entry from the tb
+ nop // 3 cycle hazard
+ nop //
+ nop //
+ mfc0 t1,entrylo1 // get entry lo 1
+ nop
+ srl t2,t1,ENTRYLO_PFN // extract PFN
+ subu t2,t2,2 // substract two pages
+ sll t2,t2,ENTRYLO_PFN // shift back up
+ andi t1,t1,0x3F // keep page color
+ or t1,t2,t1 // merge with new PFN
+ mtc0 t1,entrylo1 //
+ nop // 1 cycle hazard
+ tlbwi // write updated entry in the tlb.
+ li v0,1 // set return value to true
+30:
+ j ra // return false
+ nop
+
+ .set reorder
+ .set at
+
+ .end ReMapPCR
+
+
+ SBTTL("Initialize PCR Routine")
+//++
+//
+// Routine Description:
+//
+// This routine initializes the PCR needed by the Hal funcions.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ NESTED_ENTRY(InitializePCR, 0x30, zero)
+
+ subu sp,sp,0x30 // allocate stack frame
+ sw ra,0x14(sp) // save return address
+ sw s0,0x18(sp) // save integer registers s0 - s4
+ sw s1,0x1C(sp) //
+ sw s2,0x20(sp) //
+ sw s3,0x24(sp) //
+ sw s4,0x28(sp) //
+#ifdef DUO
+//
+// Change the PCR mapping if processor B
+//
+ li t0,DMA_VIRTUAL_BASE // load DMA base
+ lw t0,DmaWhoAmI(t0) // read Who am I register
+ beq t0,zero,10f // branch if A
+ bal ReMapPCR // Processor B Changes the mapping
+
+10:
+#endif
+
+//
+// Compute the size of the primary data cache, the primary data cache line
+// size, the primary instruction cache, and the primary instruction cache
+// line size.
+//
+ .set noreorder
+ .set noat
+ mfc0 s4,config // get configuration data
+ mtc0 zero,pagemask // initialize the page mask register
+ mtc0 zero,watchlo // initialize the watch address register
+ mtc0 zero,watchhi //
+ mtc0 zero,wired // initialize the wired register
+ mtc0 zero,count // initialize the count register
+ mtc0 zero,compare // initialize the compare register
+ ctc1 zero,fsr // clear floating status
+ .set at
+ .set reorder
+
+ srl t0,s4,CONFIG_IC // compute instruction cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li s0,1 //
+ sll s0,s0,t0 //
+ srl t0,s4,CONFIG_IB // compute instruction cache line size
+ and t0,t0,1 //
+ li s1,16 //
+ sll s1,s1,t0 //
+ srl t0,s4,CONFIG_DC // compute data cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li s2,1 //
+ sll s2,s2,t0 //
+ srl t0,s4,CONFIG_DB // compute data cache line size
+ and t0,t0,1 //
+ li s3,16 //
+ sll s3,s3,t0 //
+
+//
+// Initialize the low memory transfer vector and next free TB index value.
+//
+
+ li t0,TRANSFER_VECTOR // get address of transfer vector
+ la t1,KiGeneralException // get address of trap handler
+ sw t1,0(t0) // set address of trap handler
+ // next free TB entry set in j4reset.s
+10:
+//
+// Zero the PCR page because it is read before it is written.
+//
+
+ li a0,PCR_VIRTUAL_BASE // set address of PCR
+ li a1,PAGE_SIZE // set size of area to zero
+ jal RtlZeroMemory // zero PCR
+
+//
+// Set the primary instruction size, the primary instruction cache line size,
+// the primary data cache size, and the primary data cache line size.
+//
+
+ li t1,KiPcr // get PCR address
+ sw s0,PcFirstLevelIcacheSize(t1) // set size of instruction cache
+ sw s1,PcFirstLevelIcacheFillSize(t1) // set line size of instruction cache
+ sw s2,PcFirstLevelDcacheSize(t1) // set size of data cache
+ sw s3,PcFirstLevelDcacheFillSize(t1) // set line size of data cache
+
+
+//
+// Compute the size of the secondary data cache, the secondary data cache line
+// size, the secondary instruction cache, and the secondary instruction cache
+// line size.
+//
+
+ li s0,0 // compute instruction cache size
+ li s1,0 // compute instruction cache line size
+ li s2,0 // data cache size if no secondary
+ li s3,0 // data cache line size if no secondary
+ li t1,(1 << CONFIG_SC)
+ and t0,s4,t1
+ bne t0,zero,10f // if non-zero no secondary cache
+ li s2,SECONDARY_CACHE_SIZE // compute data cache size
+ srl t0,s4,CONFIG_SB // compute data cache line size
+ and t0,t0,3 //
+ li s3,16 //
+ sll s3,s3,t0 //
+10:
+
+//
+// Set the secondary instruction size, the secondary instruction cache line size,
+// the secondary data cache size, and the secondary data cache line size.
+//
+
+ li t1,KiPcr // get PCR address
+ sw s0,PcSecondLevelIcacheSize(t1) // set size of instruction cache
+ sw s1,PcSecondLevelIcacheFillSize(t1) // set line size of instruction cache
+ sw s2,PcSecondLevelDcacheSize(t1) // set size of data cache
+ sw s3,PcSecondLevelDcacheFillSize(t1) // set line size of data cache
+
+//
+// Set the data cache fill size and alignment values.
+//
+
+ lw t2,PcSecondLevelDcacheSize(t1) // get second level dcache size
+
+ .set noreorder
+ .set noat
+ bnel zero,t2,5f // if ne, second level cache present
+ lw t2,PcSecondLevelDcacheFillSize(t1) // get second level fill size
+ lw t2,PcFirstLevelDcacheFillSize(t1) // get first level fill size
+ .set at
+ .set reorder
+
+5: subu t3,t2,1 // compute dcache alignment value
+ sw t2,PcDcacheFillSize(t1) // set dcache fill size
+ sw t3,PcDcacheAlignment(t1) // set dcache alignment value
+
+ lw ra,0x14(sp) // restore registers
+ lw s0,0x18(sp) //
+ lw s1,0x1C(sp) //
+ lw s2,0x20(sp) //
+ lw s3,0x24(sp) //
+ lw s4,0x28(sp) //
+ addu sp,sp,0x30 // deallocate stack frame
+ j ra // return
+ .end InitializePCR
+
+
+#ifndef DUO
+ SBTTL("Read Floppy Data From Fifo")
+//++
+//
+// Routine Description:
+//
+// This routine is called to read data from the floppy fifo.
+//
+// Arguments:
+//
+// Buffer (a0) - Supplies a pointer to the buffer that receives the data
+// read.
+//
+// Return Value:
+//
+// The number of bytes read is returned as the function value.
+//
+//--
+
+ LEAF_ENTRY(ReadFloppyFifo)
+
+ move v0,zero // clear number of bytes read
+ li t0,FLOPPY_VIRTUAL_BASE // set base address of floppy registers
+ li t1,0xc0 // set constant for dio and rqm bits
+
+//
+// Read data from floppy fifo.
+//
+
+ .set noreorder
+ .set noat
+10: lbu t2,4(t0) // read MSR register
+ nop //
+ and t3,t2,t1 // clear all but dio and rqm bits
+ bne t1,t3,10b // if ne, rqm and dio not both set
+ and t3,t2,0x20 // test nonDMA bit
+ beq zero,t3,20f // if eq, end of transfer
+ addu a0,a0,1 // increment the buffer address
+ addu v0,v0,1 // increment number of bytes read
+ lbu t2,5(t0) // read floppy fifo
+ b 10b //
+ sb t2,-1(a0) // store byte in buffer
+ .set at
+ .set reorder
+
+20: j ra // return
+
+ .end ReadFloppyFifo
+
+ SBTTL("Write Data to Floppy Fifo")
+//++
+//
+// Routine Description:
+//
+// This routine is called to write data to the floppy fifo.
+//
+// Arguments:
+//
+// Buffer (a0) - Supplies a pointer to the buffer that contains the data
+// to be written.
+//
+// Length (a1) - Supplies the number of bytes to be written to the fifo.
+//
+// Return Value:
+//
+// The number of bytes written is returned as the function value.
+//
+//--
+
+ LEAF_ENTRY(WriteFloppyFifo)
+
+ move v0,zero // clear number of bytes writen
+ li t0,FLOPPY_VIRTUAL_BASE // set base address of floppy registers
+ li t1,0x80 // set constant for dio and rqm bits
+//
+// Write data to floppy fifo.
+//
+
+ .set noreorder
+ .set noat
+ addu a1,a0,a1 // address of last byte to transfer.
+ lbu t5,0(a0) // read first byte to write to fifo
+10: lbu t2,4(t0) // read MSR register
+ nop //
+ andi t3,t2,0xc0 // clear all but dio and rqm bits
+ bne t1,t3,10b // if ne, rqm not set or dio set set
+ nop
+ addu a0,a0,1 // increment the buffer address
+ sb t5,5(t0) // write floppy fifo.
+ bne a0,a1,10b // if not last byte, send next
+ lbu t5,0(a0) // read next byte from buffer
+
+//
+// All bytes written to fifo. Wait until floppy controller empties it.
+//
+
+20: lbu t2,4(t0) // read MSR register
+ nop
+ andi t3,t2,0x20 // test nonDMA bit
+ bne t3,zero,20b // if neq, transfer not finished.
+ nop
+ .set at
+ .set reorder
+
+ j ra // return
+
+ .end WriteFloppyFifo
+
+#endif
+
+#ifdef DUO
+
+ SBTTL("Test for IP interrupt")
+//++
+//
+// Routine Desription:
+//
+// This routine reads the cause register and returns True
+// if the IP interrupt bit is set False otherwise
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+////
+//
+//
+//--
+
+ LEAF_ENTRY(IsIpInterruptSet)
+ .set noreorder
+ .set noat
+
+ mfc0 t0,cause // get cause register
+ li t1,1<<14 // mask to test IP interrupt
+ and t0,t1 // and them
+ beq t0,zero,20f // branch if not set
+ move v0,zero // set return value to False if no IP int
+ li t0,DMA_VIRTUAL_BASE // load DMA base
+ lw t0,DmaIpInterruptAcknowledge(t0)// read IP Ack register to clear it
+10:
+ mfc0 t0,cause // get cause register
+ li t1,1<<14 // mask to test IP interrupt
+ and t0,t1 // and them
+ bne t0,zero,10b // Keep looping if still set
+ li v0,1 // set return value to True
+20:
+ j ra // return to caller.
+ nop
+ .set reorder
+ .set at
+
+ .end IsIpInterruptSet
+
+ SBTTL("Wait for IP interrupt")
+//++
+//
+// Routine Desription:
+//
+// This routine waits for an IP interrupt by polling the cause register
+// When the IP interrupt occurs, it clears it and returns to the caller.
+//
+// Arguments:
+//
+// a0 Supplies a timeout period in milliseconds to wait for.
+//
+// The Loop takes about 12 internal cycles.
+// For an internal clock of 100MHz this is about 8192 loops
+// per millisecond.
+//
+//
+//
+// Return Value:
+//
+// zero if the Ip interrupt was not received in the specified timeout
+// period. One otherwise.
+//
+//
+//--
+
+ LEAF_ENTRY(WaitForIpInterrupt)
+ .set noreorder
+ .set noat
+
+ bne a0,zero,10f // if timeout specified count loops
+ sll a0,a0,13 // multiply millisecons by 8192 = Loop count
+
+5:
+ mfc0 t0,cause // get cause register
+ li t1,1<<14 // mask to test IP interrupt
+ // TMPTMP need symbolic definition
+ and t0,t1 // and them
+ beq t0,zero,5b // Keep looping if not set
+ nop
+ b 20f // go to clear interrupt
+ nop
+
+10:
+ mfc0 t0,cause // get cause register
+ li t1,1<<14 // mask to test IP interrupt
+ addiu a0,a0,-1 // decrement loop counter
+ beq a0,zero,40f // branch out of loop if Timeout
+ move v0,zero // set return value to zero
+ nop
+ and t0,t1 // and them
+ beq t0,zero,10b // Keep looping if not set
+ nop
+
+20:
+ li t0,DMA_VIRTUAL_BASE // load DMA base
+ lw t0,DmaIpInterruptAcknowledge(t0)// read IP Ack register to clear it
+30:
+ mfc0 t0,cause // get cause register
+ li t1,1<<14 // mask to test IP interrupt
+ and t0,t1 // and them
+ bne t0,zero,30b // Keep looping if still set
+ addiu v0,zero,1 // set return value to 1
+
+40:
+ j ra // return to the caller.
+ nop
+
+ .set reorder
+ .set at
+ .end WaitForIpInterrupt
+
+
+
+ SBTTL("Boot RestartProcessor")
+//++
+//
+// Routine Desription:
+//
+// This routine loads the Saved State Area of the RestartBlock
+// supplied by a0 into the processor and transfers execution to
+// the restart address.
+// This routine assumes that the supplied restart block is valid.
+//
+// Arguments:
+//
+// a0 PRESTART_BLOCK.
+//
+// Return Value:
+//
+// This routine does not return.
+//
+//--
+
+
+ LEAF_ENTRY(FwBootRestartProcessor)
+ .set noreorder
+ .set noat
+//
+// Cache is flushed by the caller.
+//
+// move s0,a0
+// la k0,HalSweepDcache
+// jal k0
+// nop
+// move a0,s0
+
+10:
+ lw t0,RstBlkBootStatus(a0) // read boot status
+ li t1,ProcessorStart // get boot start bit mask
+ and t0,t0,t1 // and them
+ bne t0,zero,30f // if set go to load restart block
+ nop
+
+//
+// Check if another IP interrupt was send to notify us to give up booting.
+//
+ mfc0 t0,cause // get cause register
+ li t1,1<<14 // mask to test IP interrupt
+ and t0,t1 // and them
+ beq t0,zero,Wait // branch if not set
+ li t0,DMA_VIRTUAL_BASE // load DMA base
+ lw t0,DmaIpInterruptAcknowledge(t0)// read IP Ack register to clear it
+15:
+ mfc0 t0,cause // get cause register
+ li t1,1<<14 // mask to test IP interrupt
+ and t0,t1 // and them
+ bne t0,zero,15b // Keep looping if still set
+ nop // return to the caller.
+ j ra //
+
+Wait:
+ li t0,0x10000 // load delay value
+20: //
+ bne t0,zero,20b // wait
+ addiu t0,t0,-1
+ b 10b
+ nop
+
+30:
+ move k0,a0 // put address of restart block in k0
+ lwc1 f0,RstBlkFltF0(k0) // Load floating registers
+ lwc1 f1,RstBlkFltF1(k0) // don't use double loads since
+ lwc1 f2,RstBlkFltF2(k0) // the alignment is not known.
+ lwc1 f3,RstBlkFltF3(k0) //
+ lwc1 f4,RstBlkFltF4(k0)
+ lwc1 f5,RstBlkFltF5(k0)
+ lwc1 f6,RstBlkFltF6(k0)
+ lwc1 f7,RstBlkFltF7(k0)
+ lwc1 f8,RstBlkFltF8(k0)
+ lwc1 f9,RstBlkFltF9(k0)
+ lwc1 f10,RstBlkFltF10(k0)
+ lwc1 f11,RstBlkFltF11(k0)
+ lwc1 f12,RstBlkFltF12(k0)
+ lwc1 f13,RstBlkFltF13(k0)
+ lwc1 f14,RstBlkFltF14(k0)
+ lwc1 f15,RstBlkFltF15(k0)
+ lwc1 f16,RstBlkFltF16(k0)
+ lwc1 f17,RstBlkFltF17(k0)
+ lwc1 f18,RstBlkFltF18(k0)
+ lwc1 f19,RstBlkFltF19(k0)
+ lwc1 f20,RstBlkFltF20(k0)
+ lwc1 f21,RstBlkFltF21(k0)
+ lwc1 f22,RstBlkFltF22(k0)
+ lwc1 f23,RstBlkFltF23(k0)
+ lwc1 f24,RstBlkFltF24(k0)
+ lwc1 f25,RstBlkFltF25(k0)
+ lwc1 f26,RstBlkFltF26(k0)
+ lwc1 f27,RstBlkFltF27(k0)
+ lwc1 f28,RstBlkFltF28(k0)
+ lwc1 f29,RstBlkFltF29(k0)
+ lwc1 f30,RstBlkFltF30(k0)
+ lwc1 f31,RstBlkFltF31(k0)
+
+ lw k1,RstBlkFsr(k0) // load fsr
+ ctc1 k1,fsr // transfer to coprocessor
+
+ lw AT,RstBlkIntAt(k0) // load integer registers
+ lw v0,RstBlkIntV0(k0)
+ lw v1,RstBlkIntV1(k0)
+ lw a0,RstBlkIntA0(k0)
+ lw a1,RstBlkIntA1(k0)
+ lw a2,RstBlkIntA2(k0)
+ lw a3,RstBlkIntA3(k0)
+ lw t0,RstBlkIntT0(k0)
+ lw t1,RstBlkIntT1(k0)
+ lw t2,RstBlkIntT2(k0)
+ lw t3,RstBlkIntT3(k0)
+ lw t4,RstBlkIntT4(k0)
+ lw t5,RstBlkIntT5(k0)
+ lw t6,RstBlkIntT6(k0)
+ lw t7,RstBlkIntT7(k0)
+ lw s0,RstBlkIntS0(k0)
+ lw s1,RstBlkIntS1(k0)
+ lw s2,RstBlkIntS2(k0)
+ lw s3,RstBlkIntS3(k0)
+ lw s4,RstBlkIntS4(k0)
+ lw s5,RstBlkIntS5(k0)
+ lw s6,RstBlkIntS6(k0)
+ lw s7,RstBlkIntS7(k0)
+ lw t8,RstBlkIntT8(k0)
+ lw t9,RstBlkIntT9(k0)
+ // Skip k0, k1
+ lw gp,RstBlkIntGp(k0)
+ lw sp,RstBlkIntSp(k0)
+ lw s8,RstBlkIntS8(k0)
+ lw ra,RstBlkIntRa(k0)
+ lw k1,RstBlkIntLo(k0) // load IntLo
+ mtlo k1 // move value to register
+ lw k1,RstBlkIntHi(k0) // load IntHi
+ mthi k1 // move value to register
+ lw k1,RstBlkPsr(k0) // load psr
+ mtc0 k1,psr // move to cop0
+ nop // fill for psr write 3 cycles hazard
+ lw k1,RstBlkFir(k0) // load epc
+ mtc0 k1,epc // move to cop0
+
+ lw k1,RstBlkIntK0(k0) // load k0 into k1
+ mtc0 k1,lladdr // save k0 in cop0 register
+
+ lw k1,RstBlkBootStatus(k0) // read boot status
+ ori k1,ProcessorRunning | BootStarted // Or in status bits.
+ sw k1,RstBlkBootStatus(k0) // write updated boot status
+
+ lw k1,RstBlkIntK1(k0) // load k1
+ lw k0,RstBlkFir(k0) // load restart address
+ j k0 // go to restart address
+ mfc0 k0,lladdr // restore k0 in delay slot.
+
+ALTERNATE_ENTRY(FwBootRestartProcessorEnd)
+ nop
+ .set reorder
+ .set at
+
+ .end RestartProcessor
+
+#endif // DUO
+
+#endif
diff --git a/private/ntos/fw/mips/jazzg364.c b/private/ntos/fw/mips/jazzg364.c
new file mode 100644
index 000000000..cf6aa048f
--- /dev/null
+++ b/private/ntos/fw/mips/jazzg364.c
@@ -0,0 +1,336 @@
+#if defined(JAZZ)
+
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ jazzG364.c
+
+cAbstract:
+
+ This module implements the video prom code for the Jazz G364 video board.
+
+Author:
+
+ Lluis Abello (lluis) 20-Jul-1992
+
+Environment:
+
+ Kernel mode.
+
+
+Revision History:
+
+ Thid code was moved from jxdisp.c
+
+--*/
+
+#include "fwp.h"
+#include "jazzvdeo.h"
+#include "jxvideo.h"
+#include "ioaccess.h"
+JAZZ_VIDEO_TYPE FwVideoType;
+
+MONITOR_CONFIGURATION_DATA DefaultMonitor = {
+ 0, // version :do not change
+ 0, // revision :do not change
+ 1280, // HorizontalResolution
+ 11832, // HorizontalDisplayTime
+ 1596, // HorizontalBackPorch
+ 587, // HorizontalFrontPorch
+ 1745, // HorizontalSync
+ 1024, // VerticalResolution
+ 28, // VerticalBackPorch
+ 1, // VerticalFrontPorch
+ 3, // VerticalSync
+ 0, // HorizontalScreenSize : do not change
+ 0 // VerticalScreenSize : do not change
+};
+
+#define G364_PALETTE_BLACK 0x000000
+#define G364_PALETTE_RED 0xB00000
+#define G364_PALETTE_GREEN 0x00B000
+#define G364_PALETTE_YELLOW 0xB0B000
+#define G364_PALETTE_BLUE 0x0000B0
+#define G364_PALETTE_MAGENTA 0xB000B0
+#define G364_PALETTE_CYAN 0x00B0B0
+#define G364_PALETTE_WHITE 0xB0B0B0
+#define G364_PALETTE_HI_BLACK 0x000000
+#define G364_PALETTE_HI_RED 0xFF0000
+#define G364_PALETTE_HI_GREEN 0x00FF00
+#define G364_PALETTE_HI_YELLOW 0xFFFF00
+#define G364_PALETTE_HI_BLUE 0x0000FF
+#define G364_PALETTE_HI_MAGENTA 0xFF00FF
+#define G364_PALETTE_HI_CYAN 0x00FFFF
+#define G364_PALETTE_HI_WHITE 0xFFFFFF
+
+ARC_STATUS
+InitializeG364 (
+ IN PVIDEO_VIRTUAL_SPACE VirtualAdr,
+ IN OUT PMONITOR_CONFIGURATION_DATA CurrentMonitor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the G364 video control registers, and clears the
+ video screen.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the video was initialized, ESUCCESS is returned, otherwise an error
+ code is returned.
+
+--*/
+
+{
+ ULONG ScreenUnitRate;
+ ULONG MultiplierValue;
+ ULONG HalfLineTime;
+ ULONG FrontPorch;
+ ULONG BackPorch;
+ ULONG HalfSync;
+ ULONG TransferDelay;
+ ULONG DmaDisplay;
+ ULONG DataLong;
+ ULONG Index;
+ PG364_VIDEO_REGISTERS VideoControl = (PG364_VIDEO_REGISTERS) (VirtualAdr->ControlVirtualBase + 0x80000);
+ PMONITOR_CONFIGURATION_DATA Monitor;
+ BOOLEAN UpdateMonitor;
+
+ //
+ // Determine if this is actually the G364 board.
+ //
+
+ if (READ_REGISTER_UCHAR((PUCHAR)(VirtualAdr->ControlVirtualBase)) == JazzVideoG364) {
+ FwVideoType = JazzVideoG364;
+ } else {
+ FwVideoType = MipsVideoG364;
+ }
+
+ //
+ // Reset the whole video board.
+ //
+
+ WRITE_REGISTER_UCHAR((PUCHAR)(VirtualAdr->ControlVirtualBase+0x180000),0);
+
+ Monitor = CurrentMonitor;
+ UpdateMonitor = FALSE;
+
+ //
+ // Check to see if the Monitor parameters are valid.
+ //
+
+ do {
+
+ //
+ // Determine the desired screen unit rate, in picoseconds (a screen unit is
+ // four pixels).
+ //
+
+ if ((Monitor->HorizontalDisplayTime != 0) && (Monitor->HorizontalResolution != 0)) {
+ ScreenUnitRate = (Monitor->HorizontalDisplayTime * 1000) * 4 / Monitor->HorizontalResolution;
+ } else {
+ continue;
+ }
+
+ if (ScreenUnitRate == 0) {
+ continue;
+ }
+
+ //
+ // Multiplier value is the oscillator period (in picoseconds) divided by
+ // the pixel rate.
+ //
+
+ if (FwVideoType == JazzVideoG364) {
+ MultiplierValue = 123077 / (ScreenUnitRate / 4);
+ if (MultiplierValue < 5 || MultiplierValue > 18) {
+ continue;
+ }
+ } else {
+ MultiplierValue = 200000 / (ScreenUnitRate / 4);
+ if (MultiplierValue < 5 || MultiplierValue > 29) {
+ continue;
+ }
+ }
+
+ break;
+
+ //
+ // If the while is executed, the parameters are not valid. Set UpdateMonitor
+ // and point to the default parameters, which are valid. Note that the
+ // "while" will evaluate TRUE because the value of (a,b) is the value of b.
+ //
+
+ } while (Monitor = &DefaultMonitor, UpdateMonitor = TRUE);
+
+ //
+ // Update the monitor parameters if necessary.
+ //
+
+ if (UpdateMonitor) {
+ CurrentMonitor->HorizontalResolution = DefaultMonitor.HorizontalResolution;
+ CurrentMonitor->HorizontalDisplayTime = DefaultMonitor.HorizontalDisplayTime;
+ CurrentMonitor->HorizontalBackPorch = DefaultMonitor.HorizontalBackPorch;
+ CurrentMonitor->HorizontalFrontPorch = DefaultMonitor.HorizontalFrontPorch;
+ CurrentMonitor->HorizontalSync = DefaultMonitor.HorizontalSync;
+ CurrentMonitor->VerticalResolution = DefaultMonitor.VerticalResolution;
+ CurrentMonitor->VerticalBackPorch = DefaultMonitor.VerticalBackPorch;
+ CurrentMonitor->VerticalFrontPorch = DefaultMonitor.VerticalFrontPorch;
+ CurrentMonitor->VerticalSync = DefaultMonitor.VerticalSync;
+ }
+
+ //
+ // write multiplier value
+ //
+
+ DataLong = 0;
+ ((PG364_VIDEO_BOOT)(&DataLong))->ClockSelect = 1;
+ ((PG364_VIDEO_BOOT)(&DataLong))->MicroPort64Bits = 1;
+ ((PG364_VIDEO_BOOT)(&DataLong))->Multiplier = MultiplierValue;
+ WRITE_REGISTER_ULONG(&VideoControl->Boot.Long, DataLong);
+
+ //
+ // Initialize the G364 control parameters.
+ //
+
+ DataLong = 0;
+
+ //
+ // If vertical front porch is 1, use tesselated sync, otherwise use normal sync.
+ //
+
+ if (Monitor->VerticalFrontPorch > 1) {
+ ((PG364_VIDEO_PARAMETERS)(&DataLong))->PlainSync = 1;
+ }
+ ((PG364_VIDEO_PARAMETERS)(&DataLong))->DelaySync = G364_DELAY_SYNC_CYCLES;
+ ((PG364_VIDEO_PARAMETERS)(&DataLong))->BitsPerPixel = EIGHT_BITS_PER_PIXEL;
+ ((PG364_VIDEO_PARAMETERS)(&DataLong))->AddressStep = G364_ADDRESS_STEP_INCREMENT;
+ ((PG364_VIDEO_PARAMETERS)(&DataLong))->DisableCursor = 1;
+ WRITE_REGISTER_ULONG(&VideoControl->Parameters.Long, DataLong);
+
+ //
+ // Initialize the G364 operational values.
+ //
+
+ HalfSync = (Monitor->HorizontalSync * 1000) / ScreenUnitRate / 2;
+ WRITE_REGISTER_ULONG(&VideoControl->HorizontalSync.Long, HalfSync );
+
+ BackPorch = (Monitor->HorizontalBackPorch * 1000) / ScreenUnitRate;
+ WRITE_REGISTER_ULONG(&VideoControl->BackPorch.Long, BackPorch );
+
+ WRITE_REGISTER_ULONG(&VideoControl->Display.Long, Monitor->HorizontalResolution / 4);
+
+ //
+ // The LineTime needs to be an even number of units, so calculate LineTime / 2
+ // and then multiply by two to program. ShortDisplay and BroadPulse also
+ // use LineTime / 2.
+ //
+
+ HalfLineTime = (Monitor->HorizontalSync + Monitor->HorizontalFrontPorch +
+ Monitor->HorizontalBackPorch + Monitor->HorizontalDisplayTime) * 1000 /
+ ScreenUnitRate / 2;
+
+ WRITE_REGISTER_ULONG(&VideoControl->LineTime.Long, HalfLineTime * 2);
+
+ FrontPorch = (Monitor->HorizontalFrontPorch * 1000) / ScreenUnitRate;
+ WRITE_REGISTER_ULONG(&VideoControl->ShortDisplay.Long,
+ HalfLineTime - ((HalfSync * 2) + BackPorch + FrontPorch));
+
+ WRITE_REGISTER_ULONG(&VideoControl->BroadPulse.Long, HalfLineTime - FrontPorch);
+
+ WRITE_REGISTER_ULONG(&VideoControl->VerticalSync.Long, Monitor->VerticalSync * 2);
+ WRITE_REGISTER_ULONG(&VideoControl->VerticalPreEqualize.Long, Monitor->VerticalFrontPorch * 2);
+ WRITE_REGISTER_ULONG(&VideoControl->VerticalPostEqualize.Long, 1 * 2);
+
+ WRITE_REGISTER_ULONG(&VideoControl->VerticalBlank.Long,
+ (Monitor->VerticalBackPorch - 1) * 2);
+
+ WRITE_REGISTER_ULONG(&VideoControl->VerticalDisplay.Long, Monitor->VerticalResolution * 2);
+
+ WRITE_REGISTER_ULONG(&VideoControl->LineStart.Long, LINE_START_VALUE);
+
+ //
+ // Transfer delay is 1.65 microseconds expressed in screen units, plus 1.
+ //
+
+ TransferDelay = (1650000 / ScreenUnitRate) + 1;
+
+ if (BackPorch <= TransferDelay) {
+ TransferDelay = BackPorch - 1;
+ }
+ WRITE_REGISTER_ULONG(&VideoControl->TransferDelay.Long, TransferDelay);
+
+ //
+ // DMA display (also known as MemInit) is 1024 (the length of the VRAM
+ // shift register) minus TransferDelay.
+ //
+
+ DmaDisplay = 1024 - TransferDelay;
+ WRITE_REGISTER_ULONG(&VideoControl->DmaDisplay.Long, DmaDisplay);
+
+ WRITE_REGISTER_ULONG(&VideoControl->PixelMask.Long, G364_PIXEL_MASK_VALUE);
+
+ //
+ // Set up the color map.
+ //
+
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_BLACK],
+ G364_PALETTE_BLACK);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_RED],
+ G364_PALETTE_RED);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_GREEN],
+ G364_PALETTE_GREEN);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_YELLOW],
+ G364_PALETTE_YELLOW);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_BLUE],
+ G364_PALETTE_BLUE);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_MAGENTA],
+ G364_PALETTE_MAGENTA);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_CYAN],
+ G364_PALETTE_CYAN);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_WHITE],
+ G364_PALETTE_WHITE);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_BLACK],
+ G364_PALETTE_HI_BLACK);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_RED],
+ G364_PALETTE_HI_RED);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_GREEN],
+ G364_PALETTE_HI_GREEN);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_YELLOW],
+ G364_PALETTE_HI_YELLOW);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_BLUE],
+ G364_PALETTE_HI_BLUE);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_MAGENTA],
+ G364_PALETTE_HI_MAGENTA);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_CYAN],
+ G364_PALETTE_HI_CYAN);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_WHITE],
+ G364_PALETTE_HI_WHITE);
+
+ //
+ // Enable the G364
+ //
+
+ ((PG364_VIDEO_PARAMETERS)(&DataLong))->EnableVideo = 1;
+ WRITE_REGISTER_ULONG(&VideoControl->Parameters.Long, DataLong);
+
+ //
+ // G364 C04 bug # 6:
+ // "The action of starting the VTG may cause the TopOfScreen register to become corrupted"
+ //
+
+ WRITE_REGISTER_ULONG(&VideoControl->TopOfScreen, 0);
+
+ return ESUCCESS;
+}
+
+#endif
diff --git a/private/ntos/fw/mips/jg364h.s b/private/ntos/fw/mips/jg364h.s
new file mode 100644
index 000000000..e34026168
--- /dev/null
+++ b/private/ntos/fw/mips/jg364h.s
@@ -0,0 +1,60 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ jg364.s
+
+Abstract:
+
+ This module contains the video prom header for JazzG364.
+ It must be placed starting at the first video rom location.
+
+Author:
+
+ Lluis Abello (lluis) 21-Jul-92
+
+Environment:
+
+
+
+Notes:
+
+ This module doesn't contain any code.
+ Data is in the text section, so that the linker puts it at the
+ begining.
+
+
+Revision History:
+
+
+
+--*/
+
+#include <ksmips.h>
+
+.text
+
+.byte 0x1 // Video Board ID
+.byte 8 // PROM_Stride
+.byte 1 // PROM_Width
+.byte 0x20 // PROM_Size = 32 4KB pages
+.ascii "Jazz"
+
+//
+// The following data corresponds to this structure.
+//
+//typedef struct _VIDEO_PROM_CONFIGURATION {
+// ULONG VideoMemorySize;
+// ULONG VideoControlSize;
+// ULONG CodeOffset;
+// ULONG CodeSize;
+// UCHAR IdentifierString[];
+//} VIDEO_PROM_CONFIGURATION; *PVIDEO_PROM_CONFIGURATION;
+
+.word 0x200000 // VideoMemorySize = 4MB
+.word 0x200000 // VideoControlSize = 4MB
+.word 0x200 // CodeOffset. Code starts at offset 200 from video prom
+.word 0x4000 // CodeSize 16K of code...
+.asciiz "Jazz G364"
diff --git a/private/ntos/fw/mips/jxbmp.c b/private/ntos/fw/mips/jxbmp.c
new file mode 100644
index 000000000..aaba50cbf
--- /dev/null
+++ b/private/ntos/fw/mips/jxbmp.c
@@ -0,0 +1,129 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ jxbmp.c
+
+Abstract:
+
+ This program outputs a BMP file to the screen.
+
+Author:
+
+ David M. Robinson (davidro) 7-July-1992
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#include "windef.h"
+#include "wingdi.h"
+#include "selfmap.h"
+
+#define VIDEO_MEMORY ((PUCHAR)VIDEO_MEMORY_VIRTUAL_BASE)
+
+//
+// External defines.
+//
+
+extern ULONG FwBmpHeight;
+extern ULONG FwBmpWidth;
+extern UCHAR FwBmp[];
+extern ULONG FwForegroundColor;
+extern ULONG FwBackgroundColor;
+extern ULONG DisplayWidth;
+extern ULONG FrameSize;
+
+
+
+VOID
+FwOutputBitmap (
+ PULONG Destination,
+ ULONG Width,
+ ULONG Height,
+ PUCHAR Bitmap
+ )
+
+/*++
+
+Routine Description:
+
+ This routine displays a bitmap on the video screen with the current
+ color and video attributes.
+
+Arguments:
+
+ Destination - The destination address (lower right corner) of the location
+ to display the bitmap.
+
+ Width - The width of the bitmap in pixels.
+
+ Height - The height of the bitmap in pixels.
+
+ Bitmap - A pointer to the bitmap.
+
+ Multiple - A scaling factor.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG I, J, K, L, M;
+ PUCHAR Pixel;
+ CHAR Color;
+
+ CHAR Character;
+ ULONG Count;
+
+
+ Pixel = (PUCHAR)(Destination) - Width;
+ Count = 0;
+
+ for ( I = 0 ; I < Height ; I++ ) {
+ for ( J = 0 ; J < Width ; J++ ) {
+ if (Count-- == 0) {
+ Count = (*Bitmap & 0x7f) - 1;
+ Color = (*Bitmap++ & 0x80) ? FwForegroundColor : FwBackgroundColor;
+ }
+ *Pixel++ = Color;
+ }
+ Pixel -= (DisplayWidth + Width);
+ }
+
+ return;
+}
+
+VOID
+JxBmp(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine reads a bitmap from the PROM and displays it on the screen.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PULONG Destination;
+
+ Destination = (PULONG)(VIDEO_MEMORY + FrameSize);
+
+ FwOutputBitmap(Destination, FwBmpWidth, FwBmpHeight, FwBmp);
+
+}
diff --git a/private/ntos/fw/mips/jxboot.c b/private/ntos/fw/mips/jxboot.c
new file mode 100644
index 000000000..f3a97f554
--- /dev/null
+++ b/private/ntos/fw/mips/jxboot.c
@@ -0,0 +1,1137 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ jxboot.c
+
+Abstract:
+
+ This module implements the first pass simple-minded boot program for
+ MIPS systems.
+
+Author:
+
+ David N. Cutler (davec) 7-Nov-1990
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "jzsetup.h"
+#ifdef DUO
+#include "duoint.h"
+#else
+#include "jazzint.h"
+#endif
+#include "fwstring.h"
+
+
+#define MAX_NUMBER_OF_ENVIRONMENT_VARIABLES 20
+
+//
+// Define local procedure prototypes.
+//
+
+VOID
+FwInstallKd(
+ IN VOID
+ );
+
+VOID
+KiTbMiss(
+ IN VOID
+ );
+
+//SIGNALHANDLER
+//FwSignal(
+// IN LONG Sig,
+// IN SIGNALHANDLER Handler
+// );
+
+VOID
+FwCheckNvram (
+ VOID
+ );
+
+//
+// Define external references.
+//
+
+extern PKDEBUG_ROUTINE KiDebugRoutine;
+extern PCHAR PathNameSerialPort0;
+extern PCHAR PathNameSerialPort1;
+extern ULONG ScsiDebug;
+extern MONITOR_CONFIGURATION_DATA MonitorData;
+extern PUCHAR IdentifierString;
+extern LONG FwRow;
+extern LONG FwColumn;
+
+//
+// Default console pathnames.
+//
+
+PCHAR PathNameMonitor = "multi()video()monitor()console()";
+PCHAR PathNameKeyboard = "multi()Key()keyboard()console()";
+
+//
+// Define external data required by the kernel debugger.
+//
+
+CCHAR KeNumberProcessors;
+ULONG KeNumberTbEntries;
+PKPRCB KiProcessorBlock[MAXIMUM_PROCESSORS];
+KPRCB Prcb;
+KPROCESS Process;
+KTHREAD Thread;
+ULONG KiFreezeFlag = 0;
+BOOLEAN KdInstalled = FALSE;
+LOADER_PARAMETER_BLOCK LoaderBlock;
+
+//
+// Define kernel data used by the Hal. Note that the Hal expects these as
+// exported variables, so define pointers.
+//
+
+ULONG DcacheFlushCount = 0;
+PULONG KeDcacheFlushCount = &DcacheFlushCount;
+ULONG IcacheFlushCount = 0;
+PULONG KeIcacheFlushCount = &IcacheFlushCount;
+
+//
+// Saved sp
+//
+
+ULONG FwSavedSp;
+
+//
+// Break into the debugger after loading the program.
+//
+
+BOOLEAN BreakAfterLoad = FALSE;
+
+//
+// Define if setup is running.
+//
+
+extern BOOLEAN SetupIsRunning;
+
+#ifdef DUO
+
+//
+// Booting OS variable. This is used by FwLoad to determine if processor B
+// should be pointed to the restart block.
+//
+
+BOOLEAN FirstLoadedProgram;
+
+#endif
+
+
+VOID
+FwBootSystem(
+ IN VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the main ARC firmware code. It displays the
+ boot menu and executes the selected commands.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None. It never returns.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ LONG Index;
+ UCHAR Character;
+ ULONG Count;
+ PCHAR LoadArgv[8];
+ ULONG ArgCount;
+ LONG DefaultChoice = 0;
+ CHAR PathName[128];
+ CHAR TempName[128];
+ PCHAR TempArgs;
+ CHAR SystemPartition[128];
+ CHAR Osloader[128];
+ CHAR OsloadPartition[128];
+ CHAR OsloadFilename[128];
+ CHAR OsloadOptions[128];
+ CHAR LoadIdentifier[128];
+ CHAR FwSearchPath[128];
+ BOOLEAN SecondaryBoot;
+ PCHAR Colon;
+ PCHAR EnvironmentValue;
+ PCHAR LoadEnvp[MAX_NUMBER_OF_ENVIRONMENT_VARIABLES];
+ BOOLEAN Timeout = TRUE;
+ LONG Countdown;
+ ULONG RelativeTime;
+ ULONG PreviousTime;
+ PCHAR Choices[7];
+ CHAR BootChoices[5][128];
+ ULONG NumberOfBootChoices;
+ ULONG NumberOfMenuChoices;
+ GETSTRING_ACTION Action;
+ BOOLEAN VariableFound;
+ PCONFIGURATION_COMPONENT Controller;
+ PCHAR ConsoleName;
+ ULONG Fid;
+
+ //
+ // Initialize value for the ALIGN_BUFFER macro.
+ //
+
+ BlDcacheFillSize = KeGetDcacheFillSize();
+
+ //
+ // Initialize the firmware servies.
+ //
+
+ FwInitialize(0);
+
+ //
+ // Check NVRAM and warn the user if bad.
+ //
+
+ FwCheckNvram();
+
+ while (TRUE) {
+
+ //
+ // Setup is not running.
+ //
+
+ SetupIsRunning = FALSE;
+
+ //
+ // Create the menu.
+ //
+
+ strcpy(SystemPartition,BootString[SystemPartitionVariable]);
+ strcpy(Osloader, BootString[OsLoaderVariable]);
+ strcpy(OsloadPartition, BootString[OsLoadPartitionVariable]);
+ strcpy(OsloadFilename, BootString[OsLoadFilenameVariable]);
+ strcpy(OsloadOptions, BootString[OsLoadOptionsVariable]);
+ strcpy(LoadIdentifier, BootString[LoadIdentifierVariable]);
+ strcpy(FwSearchPath, "FWSEARCHPATH");
+
+ for ( Index = 0 ; Index < 5 ; Index++ ) {
+
+ SecondaryBoot = FwGetVariableSegment(Index, SystemPartition);
+ SecondaryBoot = FwGetVariableSegment(Index, Osloader) || SecondaryBoot;
+ SecondaryBoot = FwGetVariableSegment(Index, OsloadPartition) || SecondaryBoot;
+ SecondaryBoot = FwGetVariableSegment(Index, OsloadFilename) || SecondaryBoot;
+ SecondaryBoot = FwGetVariableSegment(Index, OsloadOptions) || SecondaryBoot;
+ SecondaryBoot = FwGetVariableSegment(Index, LoadIdentifier) || SecondaryBoot;
+
+ if (LoadIdentifier[sizeof("LOADIDENTIFIER=") - 1] != 0) {
+ strcpy(BootChoices[Index], FW_START_MSG);
+ strcat(BootChoices[Index], &LoadIdentifier[sizeof("LOADIDENTIFIER=") - 1]);
+ } else {
+ strcpy(BootChoices[Index], FW_START_MSG);
+ strcat(BootChoices[Index], &OsloadPartition[sizeof("OsloadPartition=") - 1]);
+ strcat(BootChoices[Index], &OsloadFilename[sizeof("OsloadFilename=") - 1]);
+ }
+
+ Choices[Index] = BootChoices[Index];
+
+ if (!SecondaryBoot) {
+ break;
+ }
+ }
+
+ //
+ // Check to see if any boot selections were loaded.
+ //
+ if ((Index == 0) && (Osloader[sizeof("OSLOADER=") - 1] == 0)) {
+ NumberOfBootChoices = 0;
+ } else {
+ NumberOfBootChoices = Index < 5 ? Index + 1 : 5;
+ }
+ NumberOfMenuChoices = NumberOfBootChoices + 2;
+ Choices[NumberOfBootChoices] = FW_RUN_A_PROGRAM_MSG;
+ Choices[NumberOfBootChoices + 1] = FW_RUN_SETUP_MSG;
+
+ if (DefaultChoice >= NumberOfMenuChoices) {
+ DefaultChoice = NumberOfMenuChoices - 1;
+ }
+
+ //
+ // Display the menu.
+ //
+
+ FwSetScreenColor( ArcColorWhite, ArcColorBlue);
+ FwSetScreenAttributes( TRUE, FALSE, FALSE);
+ FwClearScreen();
+ FwSetPosition( 3, 0);
+ FwPrint(FW_ACTIONS_MSG);
+
+ for (Index = 0; Index < NumberOfMenuChoices ; Index++ ) {
+ FwSetPosition( Index + 5, 5);
+
+ if (Index == DefaultChoice) {
+ FwSetScreenAttributes( TRUE, FALSE, TRUE);
+ }
+
+ FwPrint(Choices[Index]);
+ FwSetScreenAttributes( TRUE, FALSE, FALSE);
+ }
+
+ FwSetPosition(NumberOfMenuChoices + 6, 0);
+ FwPrint(FW_USE_ARROW_MSG);
+ FwPrint(FW_USE_ENTER_MSG);
+ FwPrint(FW_CRLF_MSG);
+
+ //
+ // Display the bitmap.
+ //
+
+ FwSetScreenColor( ArcColorCyan, ArcColorBlue);
+ JxBmp();
+ FwSetScreenColor( ArcColorWhite, ArcColorBlue);
+
+ Countdown = 5;
+ if (Timeout &&
+ ((EnvironmentValue = FwGetEnvironmentVariable("Autoload")) != NULL)) {
+ if (tolower(*EnvironmentValue) == 'y') {
+ FwSetPosition(NumberOfMenuChoices + 11, 0);
+ FwPrint(FW_AUTOBOOT_MSG);
+ if ((EnvironmentValue = FwGetEnvironmentVariable("Countdown")) != NULL) {
+ Countdown = atoi(EnvironmentValue);
+ }
+ PreviousTime = FwGetRelativeTime();
+ } else {
+ Timeout = FALSE;
+ }
+ } else {
+ Timeout = FALSE;
+ }
+
+ BreakAfterLoad = FALSE;
+ Character = 0;
+ do {
+ if (FwGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
+ FwRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ switch (Character) {
+
+ case ASCII_ESC:
+ FwRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ if (Character != '[') {
+ break;
+ }
+
+ case ASCII_CSI:
+ FwRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ FwSetPosition( DefaultChoice + 5, 5);
+ FwPrint(Choices[DefaultChoice]);
+ switch (Character) {
+ case 'A':
+ case 'D':
+ DefaultChoice--;
+ if (DefaultChoice < 0) {
+ DefaultChoice = NumberOfMenuChoices-1;
+ }
+ break;
+ case 'B':
+ case 'C':
+ DefaultChoice++;
+ if (DefaultChoice == NumberOfMenuChoices) {
+ DefaultChoice = 0;
+ }
+ break;
+ case 'H':
+ DefaultChoice = 0;
+ break;
+ default:
+ break;
+ }
+ FwSetPosition( DefaultChoice + 5, 5);
+ FwSetScreenAttributes( TRUE, FALSE, TRUE);
+ FwPrint(Choices[DefaultChoice]);
+ FwSetScreenAttributes( TRUE, FALSE, FALSE);
+ continue;
+
+ case 'D':
+ case 'd':
+ FwSetPosition( NumberOfMenuChoices + 10, 0);
+ FwPrint(FW_BREAKPOINT_MSG);
+ BreakAfterLoad = !BreakAfterLoad;
+ if (!KdInstalled) {
+ FwInstallKd();
+ }
+ FwSetPosition( NumberOfMenuChoices + 10, strlen(FW_BREAKPOINT_MSG));
+ if (!BreakAfterLoad) {
+ FwPrint(FW_OFF_MSG);
+ } else {
+ FwSetScreenColor(ArcColorMagenta, ArcColorBlue);
+ FwPrint(FW_ON_MSG);
+ FwSetScreenColor(ArcColorWhite, ArcColorBlue);
+ }
+
+ break;
+
+ case 'K':
+ case 'k':
+ case ASCII_SYSRQ:
+ if (!KdInstalled) {
+ FwInstallKd();
+ }
+ FwSetPosition( NumberOfMenuChoices + 9, 0);
+ FwPrint(FW_DEBUGGER_CONNECTED_MSG);
+ DbgBreakPoint();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ //
+ // If default choice is nonzero and a timeout is active, remove
+ // the timeout.
+ //
+
+ if ((DefaultChoice != 0) && Timeout) {
+ Timeout = FALSE;
+ FwSetPosition(NumberOfMenuChoices + 11, 0);
+ FwPrint("\x9bK");
+ }
+
+ //
+ // Update the timeout value if active.
+ //
+
+ if (Timeout) {
+ RelativeTime = FwGetRelativeTime();
+ if (RelativeTime != PreviousTime) {
+ PreviousTime = RelativeTime;
+ FwSetPosition(NumberOfMenuChoices + 11, strlen(FW_AUTOBOOT_MSG) - 2);
+ FwPrint("\x9bK");
+ FwPrint("%d",Countdown--);
+ }
+ }
+
+ } while ((Character != '\n') && (Character != '\r') && (Countdown >= 0));
+
+ //
+ // Clear the choices.
+ //
+
+ for (Index = 0; Index < NumberOfMenuChoices ; Index++ ) {
+ FwSetPosition( Index + 5, 5);
+ FwPrint("%cK", ASCII_CSI);
+ }
+
+ //
+ // Boot.
+ //
+
+ if (DefaultChoice < NumberOfBootChoices) {
+
+ //
+ // Load up the chosen boot selection.
+ //
+
+ FwGetVariableSegment(DefaultChoice, SystemPartition);
+ FwGetVariableSegment(DefaultChoice, Osloader);
+ FwGetVariableSegment(DefaultChoice, OsloadPartition);
+ FwGetVariableSegment(DefaultChoice, OsloadFilename);
+ FwGetVariableSegment(DefaultChoice, OsloadOptions);
+
+ strcpy(PathName, &(Osloader[sizeof("OSLOADER=") - 1]));
+
+
+ //
+ // Run a program.
+ //
+
+ } else if (DefaultChoice == NumberOfBootChoices) {
+
+ //
+ // Get the name.
+ //
+
+ FwSetPosition( 5, 5);
+ FwPrint(FW_PROGRAM_TO_RUN_MSG);
+ do {
+ Action = FwGetString( TempName, sizeof(TempName),NULL,FwRow,FwColumn);
+ } while ((Action != GetStringEscape) && (Action != GetStringSuccess));
+
+ //
+ // If no program is specified, continue.
+ //
+
+ if (TempName[0] == 0) {
+ continue;
+ }
+
+ //
+ // Strip off any arguments.
+ //
+
+ if ((TempArgs = strchr(TempName, ' ')) != NULL) {
+ *TempArgs++ = 0;
+ } else {
+ TempArgs = "";
+ }
+
+ //
+ // If the name does not contain a "(", then assume it is not a full
+ // pathname.
+ //
+
+ if (strchr( TempName, '(') == NULL) {
+
+ //
+ // If the name contains a semicolon, look for an environment
+ // variable that defines the path.
+ //
+
+ if ((Colon = strchr( TempName, ':')) != NULL) {
+
+ for (Index = 0; TempName[Index] != ':' ; Index++ ) {
+ PathName[Index] = tolower(TempName[Index]);
+ }
+
+ PathName[Index++] = ':';
+ PathName[Index++] = 0;
+ EnvironmentValue = FwGetEnvironmentVariable(PathName);
+ VariableFound = FALSE;
+
+ if (EnvironmentValue != NULL) {
+ strcpy( PathName, EnvironmentValue);
+ VariableFound = TRUE;
+ } else if (!strcmp(PathName, "cd:")) {
+ for ( Index = 0 ; Index < 8 ; Index++ ) {
+ sprintf(PathName, "scsi(0)cdrom(%d)fdisk(0)", Index);
+ Controller = FwGetComponent(PathName);
+ if ((Controller != NULL) && (Controller->Type == FloppyDiskPeripheral)) {
+ VariableFound = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!VariableFound) {
+ FwSetPosition( 7, 0);
+ FwSetScreenColor(ArcColorCyan, ArcColorBlack);
+ FwPrint(FW_PATHNAME_NOT_DEF_MSG);
+ FwSetScreenColor(ArcColorWhite, ArcColorBlue);
+ FwRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ continue;
+ } else {
+ strcat( PathName, Colon + 1);
+ }
+
+ } else {
+
+ //
+ // Loop on the FWSEARCHPATH variable.
+ //
+
+ Index = 0;
+ VariableFound = FALSE;
+ do {
+ SecondaryBoot = FwGetVariableSegment(Index++, FwSearchPath);
+ strcpy(PathName, &(FwSearchPath[sizeof("FWSEARCHPATH=") - 1]));
+ strcat(PathName, TempName);
+ if (FwOpen(PathName, ArcOpenReadOnly, &Count) == ESUCCESS) {
+ VariableFound = TRUE;
+ FwClose(Count);
+ break;
+ } else {
+ strcat(PathName, ".exe");
+ if (FwOpen(PathName, ArcOpenReadOnly, &Count) == ESUCCESS) {
+ VariableFound = TRUE;
+ FwClose(Count);
+ break;
+ }
+ }
+ } while (SecondaryBoot);
+
+ if (!VariableFound) {
+ FwSetPosition( 7, 0);
+ FwSetScreenColor(ArcColorCyan, ArcColorBlack);
+ FwPrint(FW_ERROR_MSG[ENOENT - 1]);
+ FwSetScreenColor(ArcColorWhite, ArcColorBlue);
+ FwRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ continue;
+ }
+
+ }
+
+ } else {
+ strcpy( PathName, TempName);
+ }
+
+ //
+ // Run Setup.
+ //
+
+ } else {
+
+ FwClearScreen();
+ JzSetup();
+ continue;
+ }
+
+ FwClearScreen();
+ FwSetPosition( 0, 0);
+
+ //
+ // Get the entire environment.
+ //
+
+ LoadEnvp[0] = FwEnvironmentLoad();
+
+ //
+ // If the environment was loaded, fill out envp.
+ //
+
+ if (LoadEnvp[0] != NULL) {
+
+ Index = 0;
+
+ //
+ // While variables still exist, find the end of each and set
+ // the next envp value to point there. NOTE this will break
+ // if the last variable has only one null after it.
+ //
+
+ while (*LoadEnvp[Index]) {
+ Index++;
+ LoadEnvp[Index] = strchr(LoadEnvp[Index - 1],'\0') + 1;
+ }
+
+ //
+ // No more, set the last one to NULL.
+ //
+
+ LoadEnvp[Index] = NULL;
+ }
+
+ //
+ // If this is an automatic boot selection, load up the standard
+ // arguments, otherwise load up the command line arguments.
+ //
+
+ if (DefaultChoice < NumberOfBootChoices) {
+
+ LoadArgv[0] = PathName;
+ ArgCount = 1;
+
+ //
+ // Load up all the Argv parameters.
+ //
+
+ LoadArgv[1] = Osloader;
+ LoadArgv[2] = SystemPartition;
+ LoadArgv[3] = OsloadFilename;
+ LoadArgv[4] = OsloadPartition;
+ LoadArgv[5] = OsloadOptions;
+ LoadArgv[6] = "CONSOLEIN=";
+ LoadArgv[7] = "CONSOLEOUT=";
+
+ //
+ // Find console in and out by looking through the environment.
+ //
+
+ for ( --Index ; Index >= 0 ; Index-- ) {
+ for ( ArgCount = 6; ArgCount <= 7 ; ArgCount++ ) {
+ if (strstr(LoadEnvp[Index],LoadArgv[ArgCount]) == LoadEnvp[Index]) {
+ LoadArgv[ArgCount] = LoadEnvp[Index];
+ }
+ }
+ }
+ } else {
+
+ LoadArgv[0] = PathName;
+
+ //
+ // Look through the pathname for arguments, by zeroing out any
+ // spaces.
+ //
+
+ Index = 0;
+ ArgCount = 1;
+
+ while (TempArgs[Index] && (ArgCount < MAX_NUMBER_OF_ENVIRONMENT_VARIABLES)) {
+ if (TempArgs[Index] == ' ') {
+ TempArgs[Index] = 0;
+ } else {
+ if (TempArgs[Index - 1] == 0) {
+ LoadArgv[ArgCount++] = &TempArgs[Index];
+ }
+ }
+ Index++;
+ }
+ }
+
+ //
+ // Add a .exe extension if the file is not found in its current form.
+ //
+
+ if (FwOpen(PathName, ArcOpenReadOnly, &Count) == ESUCCESS) {
+ FwClose(Count);
+ } else {
+ strcat(PathName, ".exe");
+ }
+
+ //
+ // Attempt to load the specified file.
+ //
+
+ FwSavedSp = 0;
+
+#ifdef DUO
+ FirstLoadedProgram = TRUE;
+#endif
+
+ Status = FwExecute(PathName, ArgCount, LoadArgv, LoadEnvp);
+
+ //
+ // Close and reopen the console in case it was changed by the user.
+ //
+
+ FwClose(ARC_CONSOLE_INPUT);
+ FwClose(ARC_CONSOLE_OUTPUT);
+
+ if ((FwGetEnvironmentVariable("ConsoleOut") == NULL) ||
+ ((ConsoleName = FwGetEnvironmentVariable("ConsoleIn")) == NULL)){
+ ConsoleName=PathNameKeyboard;
+ }
+
+ FwOpen(ConsoleName,ArcOpenReadOnly,&Fid);
+
+ if ((FwGetEnvironmentVariable("ConsoleIn") == NULL) ||
+ ((ConsoleName = FwGetEnvironmentVariable("ConsoleOut")) == NULL)) {
+ ConsoleName=PathNameMonitor;
+ }
+
+ FwOpen(ConsoleName,ArcOpenWriteOnly,&Fid);
+
+ if (Status == ESUCCESS) {
+
+ //
+ // Pause if returning from a boot. This helps see osloader error
+ // messages.
+ //
+
+ if (DefaultChoice < NumberOfBootChoices) {
+ FwPrint(FW_PRESS_ANY_KEY_MSG);
+ FwRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ }
+
+ } else {
+ FwSetScreenColor(ArcColorCyan, ArcColorBlack);
+ FwPrint(FW_ERROR2_MSG);
+
+ if (Status <= EROFS) {
+ FwPrint(FW_ERROR_MSG[Status - 1]);
+ } else {
+ FwPrint(FW_ERROR_CODE_MSG, Status);
+ }
+
+ FwPrint(FW_PRESS_ANY_KEY2_MSG);
+ FwSetScreenColor(ArcColorWhite, ArcColorBlue);
+ FwRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ }
+ }
+}
+
+VOID
+FwCheckNvram (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks the NVRAM and warns the user if bad, also checks the
+ video parameters and updates the parameters if necessary.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ LONG Index;
+ UCHAR Character;
+ ULONG Count;
+ CHAR TempName[128];
+ PCONFIGURATION_COMPONENT Controller, Peripheral, TempComponent;
+ MONITOR_CONFIGURATION_DATA OldMonitor;
+ PCONFIGURATION_PACKET Packet;
+
+ //
+ // Check NVRAM and warn the user if bad.
+ //
+
+ if ((FwConfigurationCheckChecksum() != ESUCCESS) ||
+ (FwEnvironmentCheckChecksum() != ESUCCESS) ||
+ ((FwGetEnvironmentVariable(BootString[SystemPartitionVariable]) == NULL) &&
+ (FwGetEnvironmentVariable("Fwsearchpath") == NULL))) {
+
+ FwClearScreen();
+ FwSetScreenColor(ArcColorCyan, ArcColorBlack);
+ FwSetPosition(5,5);
+ FwPrint("ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»");
+ FwSetPosition(6,5);
+ for (Index = 0 ; Index < FW_NVRAM_MSG_SIZE ; Index++) {
+ FwPrint(FW_NVRAM_MSG[Index]);
+ FwSetPosition(7 + Index,5);
+ }
+ FwPrint("ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ");
+ FwSetScreenColor(ArcColorWhite, ArcColorBlue);
+ FwRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ } else {
+
+ //
+ // Set the monitor configuration data as it may have been changed
+ // during the initialization process.
+ //
+
+ Controller = FwGetComponent("multi()video()");
+ if (Controller != NULL) {
+ Peripheral = FwGetChild(Controller);
+ if (Peripheral != NULL) {
+
+ //
+ // If the Monitor configuration data has changed, prompt the
+ // user to see if it should really be changed.
+ //
+
+ if ((Peripheral->ConfigurationDataLength == sizeof(MONITOR_CONFIGURATION_DATA)) &&
+ (FwGetConfigurationData(&OldMonitor, Peripheral) == ESUCCESS)) {
+
+ for (Index = 0; Index < Peripheral->ConfigurationDataLength; Index++) {
+ if (((PUCHAR)&OldMonitor)[Index] != ((PUCHAR)&MonitorData)[Index]) {
+ break;
+ }
+ }
+
+ if (Index != Peripheral->ConfigurationDataLength) {
+ FwClearScreen();
+ FwSetScreenColor(ArcColorCyan, ArcColorBlack);
+ FwSetPosition(5,5);
+ FwPrint("ÉÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍ»");
+ FwSetPosition(6,5);
+ for (Index = 0 ; Index < FW_VIDEO_MSG_SIZE ; Index++) {
+ FwPrint(FW_VIDEO_MSG[Index]);
+ FwSetPosition(7 + Index,5);
+ }
+ FwPrint("ÈÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍÍͼ");
+ FwSetPosition(FW_VIDEO_MSG_SIZE + 3,25);
+ FwPrint(Controller->Identifier);
+ FwSetPosition(FW_VIDEO_MSG_SIZE + 3,45);
+ FwPrint(IdentifierString);
+ FwSetPosition(FW_VIDEO_MSG_SIZE + 4,27);
+ FwPrint("%d",OldMonitor.HorizontalResolution);
+ FwSetPosition(FW_VIDEO_MSG_SIZE + 4,47);
+ FwPrint("%d",MonitorData.HorizontalResolution);
+ FwSetPosition(FW_VIDEO_MSG_SIZE + 5,27);
+ FwPrint("%d",OldMonitor.VerticalResolution);
+ FwSetPosition(FW_VIDEO_MSG_SIZE + 5,47);
+ FwPrint("%d",MonitorData.VerticalResolution);
+ FwSetScreenColor(ArcColorWhite, ArcColorBlue);
+ FwRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+
+ if (tolower(Character) == 'y') {
+
+ //
+ // If the Video Controller identifier string has changed,
+ // update it.
+ //
+
+ if (strcmp(Controller->Identifier, IdentifierString) != 0) {
+ Controller->Identifier = IdentifierString;
+ Controller->IdentifierLength = strlen(IdentifierString) + 1;
+ }
+
+ //
+ // Update the monitor data.
+ //
+
+ Packet = CONTAINING_RECORD(Peripheral,
+ CONFIGURATION_PACKET,
+ Component);
+ Packet->ConfigurationData = &MonitorData;
+
+ sprintf(TempName, "%dx%d", MonitorData.HorizontalResolution,
+ MonitorData.VerticalResolution);
+ Peripheral->Identifier = TempName;
+ Peripheral->IdentifierLength = strlen(TempName) + 1;
+
+ //
+ // Reinitialize the configuration data, which
+ // stores the changes made.
+ //
+
+ FwSaveConfiguration();
+ }
+ } else {
+
+ //
+ // If the Video Controller identifier string has changed,
+ // update it.
+ //
+
+ if (strcmp(Controller->Identifier, IdentifierString) != 0) {
+ Controller->Identifier = IdentifierString;
+ Controller->IdentifierLength = strlen(IdentifierString) + 1;
+ FwSaveConfiguration();
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+VOID
+FwInitialize (
+ IN ULONG MemSize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the system parameter block which is located
+ in low memory. This structure contains the firmware entry vector and
+ the restart parameter block. This routine also initializes the io devices,
+ the configuration, and opens standard in/out.
+
+ Note: the system parameter block is initialized early in selftest.c so that
+ the video prom can update any required vendor entries.
+
+Arguments:
+
+ MemSize - Not Used. For compatibility with definitions in bldr\firmware.h
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Fid;
+ ULONG TTBase;
+ PCHAR ConsoleName;
+ UCHAR ExecutionFlags;
+ ULONG Index;
+ CHAR DiskPath[40];
+
+ FwPrint(FW_INITIALIZING_MSG);
+
+ //
+ // Initialize Signal vector. And set default signal.
+ //
+
+// (PARC_SIGNAL_ROUTINE)SYSTEM_BLOCK->FirmwareVector[SignalRoutine] = FwSignal;
+
+ //
+ // Initialize Vendor Must be done before Calling FwAllocatePool. Also
+ // initialize the system ID and time.
+ //
+
+ FwVendorInitialize();
+ FwSystemIdInitialize();
+ FwTimeInitialize();
+
+ //
+ // Initialize the DMA translation table base address and limit.
+ //
+
+ TTBase = (ULONG) FwAllocatePool(PAGE_SIZE);
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->TranslationBase.Long,TTBase);
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->TranslationLimit.Long, PAGE_SIZE);
+
+ //
+ // Initialize the Fw loadable services.
+ //
+
+ FwLoadInitialize();
+
+ //
+ // Disable the I/O device interrupts.
+ //
+
+ WRITE_REGISTER_USHORT(&((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Enable,0);
+
+ //
+ // Initialize the firmware exception handling.
+ // This also enables interrupts in the psr and clears BEV
+ //
+
+ FwExceptionInitialize();
+
+ //
+ // Initialize configuration and environment.
+ //
+
+ FwConfigurationInitialize();
+ FwEnvironmentInitialize();
+
+ //
+ // Initialize IO structures and display driver.
+ //
+
+ //
+ // TMPTMP
+ // Initialize the kernel debugger.
+ //
+// FwInstallKd();
+// DbgBreakPoint();
+
+ FwIoInitialize1();
+
+ //
+ // Initialize the I/O services.
+ //
+
+ FwIoInitialize2();
+
+ //
+ // Open the std in and out device. The path name should be taken
+ // from ConsoleIn and ConsoleOut environment variables.
+ //
+ // N.B. FwGetEnvironmentVariable can't be called again between the ConsoleName
+ // assignment and its use.
+ //
+
+ if (SerialOutput) {
+ ConsoleName=PathNameSerialPort1;
+ } else {
+ if ((FwGetEnvironmentVariable("ConsoleOut") == NULL) ||
+ ((ConsoleName = FwGetEnvironmentVariable("ConsoleIn")) == NULL)){
+ ConsoleName=PathNameKeyboard;
+ }
+ }
+
+ if (FwOpen(ConsoleName,ArcOpenReadOnly,&Fid) != ESUCCESS) {
+ FwPrint(FW_CONSOLE_IN_ERROR_MSG);
+ }
+
+ if (Fid != ARC_CONSOLE_INPUT) {
+ FwPrint(FW_CONSOLE_IN_ERROR2_MSG);
+ }
+
+ if (SerialOutput) {
+ ConsoleName=PathNameSerialPort1;
+ } else {
+ if ((FwGetEnvironmentVariable("ConsoleIn") == NULL) ||
+ ((ConsoleName = FwGetEnvironmentVariable("ConsoleOut")) == NULL)) {
+ ConsoleName=PathNameMonitor;
+ }
+ }
+
+ if (FwOpen(ConsoleName,ArcOpenWriteOnly,&Fid) != ESUCCESS) {
+ FwPrint(FW_CONSOLE_OUT_ERROR_MSG);
+ }
+
+ if (Fid != ARC_CONSOLE_OUTPUT) {
+ FwPrint(FW_CONSOLE_OUT_ERROR2_MSG);
+ }
+
+ FwConsoleInitialized = TRUE;
+
+ FwPrint(FW_OK_MSG);
+ FwPrint(FW_CRLF_MSG);
+
+ //
+ // initialize the EISA routines
+ //
+
+ EisaIni();
+
+
+ //
+ // Initialize the termination function entry points in the transfer vector
+ // N.B. Must be after EisaIni().
+ //
+
+ FwTerminationInitialize();
+
+ //
+ // Spin up all of the disks, if necessary.
+ //
+
+ FwPrint(FW_SPIN_DISKS_MSG);
+
+ for (Index = 0; Index < 8 ; Index++ ) {
+ FwPrint(".");
+ sprintf(DiskPath,"scsi(0)disk(%1d)rdisk(0)partition(0)", Index);
+ if (FwOpen(DiskPath,ArcOpenReadWrite,&Fid) == ESUCCESS) {
+ FwClose(Fid);
+ }
+ }
+ FwPrint(FW_OK_MSG);
+ FwPrint(FW_CRLF_MSG);
+
+ return;
+}
+
+VOID
+FwInstallKd(
+ IN VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine installs the kernel debugger exception handlers and
+ initializes it.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Initialize data structures used by the kernel debugger.
+ //
+
+ Prcb.Number = 0;
+ Prcb.CurrentThread = &Thread;
+ KiProcessorBlock[0] = &Prcb;
+ PCR->Prcb = &Prcb;
+ PCR->CurrentThread = &Thread;
+ Process.DirectoryTableBase[0] = 0xffffffff;
+ Process.DirectoryTableBase[1] = 0xffffffff;
+ Thread.ApcState.Process = &Process;
+ KeNumberProcessors = 1;
+ KeNumberTbEntries = 48;
+ LoaderBlock.LoadOptions = "DEBUG";
+
+ KdInitSystem(&LoaderBlock, FALSE);
+ KdInstalled = TRUE;
+}
diff --git a/private/ntos/fw/mips/jxconfig.c b/private/ntos/fw/mips/jxconfig.c
new file mode 100644
index 000000000..409086a03
--- /dev/null
+++ b/private/ntos/fw/mips/jxconfig.c
@@ -0,0 +1,1956 @@
+#if defined(JAZZ)
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxconfig.c
+
+Abstract:
+
+ This module implements the ARC firmware Configuration Query functions as
+ described in the Advanced Risc Computing Specification (Revision 1.00),
+ section 3.3.3.4, for a MIPS R3000 or R4000 Jazz system.
+
+Author:
+
+ David M. Robinson (davidro) 13-June-1991
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#include "string.h"
+#include "selftest.h"
+extern ULONG end;
+
+//
+// Define the ARC pathname mnemonics.
+//
+
+PCHAR MnemonicTable[] = {
+ "arc",
+ "cpu",
+ "fpu",
+ "pic",
+ "pdc",
+ "sic",
+ "sdc",
+ "sc",
+ "eisa",
+ "tc",
+ "scsi",
+ "dti",
+ "multi",
+ "disk",
+ "tape",
+ "cdrom",
+ "worm",
+ "serial",
+ "net",
+ "video",
+ "par",
+ "point",
+ "key",
+ "audio",
+ "other",
+ "rdisk",
+ "fdisk",
+ "tape",
+ "modem",
+ "monitor",
+ "print",
+ "pointer",
+ "keyboard",
+ "term",
+ "other"
+ };
+
+//
+// Function prototypes.
+//
+
+ARC_STATUS
+FwRestoreConfiguration (
+ VOID
+ );
+
+VOID
+FwConfigurationSetChecksum(
+ VOID
+ );
+
+ULONG
+FwZeroCompressLength (
+ IN ULONG DataLength,
+ IN PVOID ConfigurationData
+ );
+
+ULONG
+FwZeroCompress (
+ IN ULONG DataLength,
+ IN PVOID ConfigurationData,
+ OUT PVOID OutputBuffer
+ );
+
+VOID
+FwZeroDecompress (
+ IN PVOID InBuffer,
+ IN ULONG Index,
+ OUT PVOID ConfigurationData,
+ IN ULONG Length
+ );
+
+//
+// IdentifierIndex and DataIndex identify the next free locations in the
+// configuration identifier and data areas. Configuration points to the
+// allocated configuration area.
+//
+
+ULONG IdentifierIndex;
+ULONG DataIndex;
+ULONG EisaDataIndex;
+PCONFIGURATION Configuration;
+
+//
+// Boolean to keep checksum status of the NVRAM.
+//
+
+BOOLEAN NvramValid = FALSE;
+
+//
+// External data.
+//
+
+extern MONITOR_CONFIGURATION_DATA DefaultMonitor;
+
+
+VOID
+FwConfigurationInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the configuration area in memory, and the
+ configuration routine addresses.
+
+ Note: This routine is called at phase 1 initialization and
+ at this time nothing is available.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PCONFIGURATION_COMPONENT Processor, Child;
+ ULONG ProcessorNumber;
+ CHAR CpuPath[10];
+
+ //
+ // Initialize the configuration routine addresses in the system
+ // parameter block.
+ //
+
+ (PARC_GET_CHILD_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetChildRoutine] =
+ FwGetChild;
+ (PARC_GET_PARENT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetParentRoutine] =
+ FwGetParent;
+ (PARC_GET_PEER_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetPeerRoutine] =
+ FwGetPeer;
+ (PARC_ADD_CHILD_ROUTINE)SYSTEM_BLOCK->FirmwareVector[AddChildRoutine] =
+ FwAddChild;
+ (PARC_DELETE_COMPONENT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[DeleteComponentRoutine] =
+ FwDeleteComponent;
+ (PARC_GET_COMPONENT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetComponentRoutine] =
+ FwGetComponent;
+ (PARC_GET_DATA_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetDataRoutine] =
+ FwGetConfigurationData;
+ (PARC_SAVE_CONFIGURATION_ROUTINE)SYSTEM_BLOCK->FirmwareVector[SaveConfigurationRoutine] =
+ FwSaveConfiguration;
+
+ //
+ // Allocate a region to store the volatile configuration database.
+ //
+
+ Configuration = (PCONFIGURATION)FwAllocatePool(sizeof(CONFIGURATION));
+
+ //
+ // Initialize other static data.
+ //
+
+ IdentifierIndex = 0;
+ DataIndex = 0;
+ EisaDataIndex = 0;
+
+ if (FwRestoreConfiguration() == ESUCCESS) {
+
+ //
+ // Delete processor components.
+ //
+
+ for (ProcessorNumber = 0; ProcessorNumber < 2 ; ProcessorNumber++ ) {
+ sprintf(CpuPath,"cpu(%1d)", ProcessorNumber);
+ Processor = FwGetComponent(CpuPath);
+ if ((Processor != NULL) && (Processor->Type == CentralProcessor)) {
+ while ((Child = FwGetChild(Processor)) != NULL) {
+ FwDeleteComponent(Child);
+ }
+ FwDeleteComponent(Processor);
+ }
+ }
+
+ //
+ // Add the first processor.
+ //
+
+ JzAddProcessor(0);
+
+#ifdef DUO
+ //
+ // Add the second processor
+ //
+
+ ExecuteOnProcessorB((PPROCESSOR_TASK_ROUTINE)JzAddProcessor,1);
+#endif
+
+ FwSaveConfiguration();
+ }
+
+ return;
+}
+
+PCONFIGURATION_COMPONENT
+FwAddChild (
+ IN PCONFIGURATION_COMPONENT Component,
+ IN PCONFIGURATION_COMPONENT NewComponent,
+ IN PVOID ConfigurationData OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds a new component entry as a child of Component, including
+ an identifier string if the IdentifierLength field of NewComponent is
+ non-zero, and configuration data if the ConfigurationDataLength field of
+ NewComponent is non-zero and the ConfigurationData parameter is present.
+ If Component is NULL, the root component is being added.
+
+Arguments:
+
+ Component - Supplies a pointer to a configuration component.
+
+ NewComponent - Supplies a pointer to a new configuration component
+ to be added as a child of Component.
+
+ ConfigurationData - Supplies an optional pointer to a configuration
+ data buffer.
+
+Return Value:
+
+ Returns a pointer to the new configuration component entry. If the
+ create operation was unsuccessful, NULL is returned.
+
+--*/
+{
+ PCONFIGURATION_PACKET Packet;
+ PCONFIGURATION_PACKET ParentPacket;
+ ULONG Index;
+ PUCHAR String;
+ PUCHAR Data;
+ BOOLEAN Eisa;
+ ULONG DataLength;
+
+ //
+ // If Component is NULL and the new Class is system, the root component is
+ // being added, otherwise find the first free component entry.
+ //
+
+ if ((Component == NULL) && (NewComponent->Class == SystemClass)) {
+
+ Packet = &Configuration->Packet[0];
+
+ //
+ // TEMPTEMP If the root component is being added, clear all of the
+ // configuration area. This is a Hack, should be replaced by
+ // a good way to do this.
+ //
+
+ RtlZeroMemory(Configuration, sizeof(CONFIGURATION));
+ IdentifierIndex = 0;
+ DataIndex = 0;
+ EisaDataIndex = 0;
+
+ } else {
+
+ //
+ // If the configuration is not valid, return NULL.
+ //
+
+ if (!NvramValid) {
+ return(NULL);
+ }
+
+ Packet = &Configuration->Packet[1];
+
+ for ( Index = 1 ; Packet->Parent != NULL ; Index++ ) {
+
+ //
+ // If no more entries, return NULL. Since Index is 0 based
+ // subtract one from NUMBER_OF_ENTRIES for end check.
+ //
+
+ if (Index >= (NUMBER_OF_ENTRIES - 1)) {
+ return NULL;
+ }
+
+ Packet++;
+ }
+ }
+
+ //
+ // Check to see if the parent component is the eisa bus.
+ //
+
+ if ((Component != NULL) && (Component->Type == EisaAdapter)) {
+ Eisa = TRUE;
+ } else {
+ Eisa = FALSE;
+ }
+
+ //
+ // If there is not enough space for the new identifier string or the
+ // configuration data, return NULL.
+ //
+
+ if (IdentifierIndex + NewComponent->IdentifierLength >= LENGTH_OF_IDENTIFIER) {
+ return(NULL);
+ }
+
+ if (Eisa) {
+ DataLength = FwZeroCompressLength(NewComponent->ConfigurationDataLength,
+ ConfigurationData);
+
+ if (EisaDataIndex + DataLength >= LENGTH_OF_EISA_DATA) {
+ return(NULL);
+ }
+ } else {
+ if (DataIndex + NewComponent->ConfigurationDataLength >= LENGTH_OF_DATA) {
+ return(NULL);
+ }
+ }
+
+ //
+ // There is space for everything. Fill in new configuration entry first.
+ //
+
+ Packet->Component.Class = NewComponent->Class;
+ Packet->Component.Type = NewComponent->Type;
+ Packet->Component.Flags = NewComponent->Flags;
+ Packet->Component.Version = NewComponent->Version;
+ Packet->Component.Revision = NewComponent->Revision;
+ Packet->Component.Key = NewComponent->Key;
+ Packet->Component.AffinityMask = 0xffffffff;
+ Packet->Component.IdentifierLength = NewComponent->IdentifierLength;
+ Packet->Component.Identifier = &Configuration->Identifier[IdentifierIndex];
+
+ //
+ // If Component is NULL, this is the root component so the parent is NULL,
+ // otherwise find the parent packet.
+ //
+
+ if (Component == NULL) {
+ ParentPacket = NULL;
+ } else {
+ ParentPacket = CONTAINING_RECORD(Component,
+ CONFIGURATION_PACKET,
+ Component);
+ }
+
+ //
+ // Only copy configuration data length if configuration data is supplied.
+ //
+
+ if (ConfigurationData != NULL) {
+ Packet->Component.ConfigurationDataLength =
+ NewComponent->ConfigurationDataLength;
+ } else {
+ Packet->Component.ConfigurationDataLength = 0;
+ }
+
+ Packet->Parent = ParentPacket;
+
+ Packet->Child = NULL;
+
+ //
+ // Add identifer string.
+ //
+
+ String = NewComponent->Identifier;
+
+ for ( Index = 0 ; Index < NewComponent->IdentifierLength ; Index++ ) {
+ Configuration->Identifier[IdentifierIndex++] = *String++;
+ }
+
+ //
+ // Make sure identifier is zero terminated, if not add one.
+ //
+
+ if (Configuration->Identifier[IdentifierIndex - 1] != 0) {
+ Configuration->Identifier[IdentifierIndex++] = 0;
+ Packet->Component.IdentifierLength += 1;
+ }
+
+ //
+ // Copy configuration data.
+ //
+
+ if (Eisa) {
+ Packet->ConfigurationData = &Configuration->EisaData[EisaDataIndex];
+ EisaDataIndex += FwZeroCompress(NewComponent->ConfigurationDataLength,
+ ConfigurationData,
+ &Configuration->EisaData[EisaDataIndex]);
+ } else {
+ Data = (PUCHAR)ConfigurationData;
+ Packet->ConfigurationData = &Configuration->Data[DataIndex];
+ for ( Index = 0 ; Index < NewComponent->ConfigurationDataLength ; Index++ ) {
+ Configuration->Data[DataIndex++] = *Data++;
+ }
+ }
+
+ //
+ // Add the new component as the first child of Component, unless this is
+ // the root component.
+ //
+
+ if (Component == NULL) {
+ Packet->Peer = NULL;
+ } else {
+ Packet->Peer = ParentPacket->Child;
+ ParentPacket->Child = Packet;
+ }
+
+ return (&Packet->Component);
+}
+
+
+ARC_STATUS
+FwDeleteComponent (
+ IN PCONFIGURATION_COMPONENT Component
+ )
+
+/*++
+
+Routine Description:
+
+ This function deletes a component entry. If the entry has one or more
+ children, an error is returned, otherwise the entry is deleted. Deleting
+ the entry will implicitly delete the identifier string and the configuration
+ data.
+
+ Note that no attempt is made to compress the entry, identifier, or the
+ configuration data areas after an entry is deleted, as doing so would
+ potentially invalidate outstanding pointers.
+
+Arguments:
+
+ Component - Supplies a pointer to a configuration component.
+
+Return Value:
+
+ Returns ESUCCESS if the entry was successfully deleted, otherwise one of
+ the following error codes is returned.
+
+ EINVAL Component is not a valid configuration component, or the
+ configuration is not valid.
+
+ EACCES Component has children, and cannot be freed until they
+ are deleted.
+
+
+--*/
+{
+ PCONFIGURATION_PACKET Packet;
+ PCONFIGURATION_PACKET SearchPacket;
+
+ if (!NvramValid || (Component == NULL)) {
+ return EINVAL;
+ }
+
+ Packet = CONTAINING_RECORD(Component,
+ CONFIGURATION_PACKET,
+ Component);
+
+ //
+ // If Component's Parent field is NULL, return EINVAL.
+ //
+
+ if (Packet->Parent == NULL) {
+ return EINVAL;
+ }
+
+ //
+ // If Component has children, return EACCES.
+ //
+
+ if (Packet->Child != NULL) {
+ return EACCES;
+ }
+
+ //
+ // Find the entry that points to Component, and point it to
+ // Component's peer. If this is Component's parent, update the child
+ // pointer, otherwise this is a peer and update the peer pointer.
+ //
+
+ SearchPacket = Packet->Parent;
+
+ if (SearchPacket->Child == Packet) {
+ SearchPacket->Child = Packet->Peer;
+ } else {
+ SearchPacket = SearchPacket->Child;
+ while (SearchPacket->Peer != Packet) {
+ SearchPacket = SearchPacket->Peer;
+ }
+ SearchPacket->Peer = Packet->Peer;
+ }
+
+ //
+ // Delete Component by zeroing the parent pointer.
+ //
+
+ Packet->Parent = NULL;
+
+ return ESUCCESS;
+}
+
+
+PCONFIGURATION_COMPONENT
+FwGetComponent (
+ IN PCHAR Pathname
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches the configuration tree for the component that best
+ matches the Pathname string.
+
+Arguments:
+
+ Pathname - Supplies a string containing the pathname to search.
+
+Return Value:
+
+ Returns a pointer to the configuration component that best matches
+ pathname. The algorithm is to search for each component starting with
+ the first. When the string has been exhausted or no component matches the
+ current string section, then a pointer to the last successfully matched
+ component is returned. If the configuration information is not valid,
+ NULL is returned.
+
+--*/
+{
+ PCONFIGURATION_COMPONENT Component;
+ PCONFIGURATION_COMPONENT MatchComponent;
+ PCHAR PathString;
+ PCHAR MatchString;
+ PCHAR Token;
+ ULONG Key;
+
+ //
+ // If the configuration is not valid, return NULL.
+ //
+
+ if (!NvramValid) {
+ return(NULL);
+ }
+
+ PathString = Pathname;
+
+ //
+ // Get the the root component.
+ //
+
+ MatchComponent = FwGetChild(NULL);
+
+ //
+ // Repeat search for each new match component.
+ //
+
+ do {
+
+ //
+ // Get the first child of the current match component.
+ //
+
+ Component = FwGetChild( MatchComponent );
+
+ //
+ // Search each child of the current match component for the next match.
+ //
+
+ while ( Component != NULL ) {
+
+ //
+ // Reset Token to be the current position on the pathname.
+ //
+
+ Token = PathString;
+
+ MatchString = MnemonicTable[Component->Type];
+
+ //
+ // Compare strings.
+ //
+
+ while (*MatchString == tolower(*Token)) {
+ MatchString++;
+ Token++;
+ }
+
+ //
+ // Strings compare if the first mismatch is the terminator for
+ // each.
+ //
+
+ if ((*MatchString == 0) && (*Token == '(')) {
+
+ //
+ // Form key.
+ //
+
+ Key = 0;
+ Token++;
+ while ((*Token != ')') && (*Token != 0)) {
+ Key = (Key * 10) + *Token++ - '0';
+ }
+
+ //
+ // If the key matches the component matches, so update
+ // pointers and break.
+ //
+
+ if (Component->Key == Key) {
+ PathString = Token + 1;
+ MatchComponent = Component;
+ break;
+ }
+ }
+
+NextPeer:
+ Component = FwGetPeer( Component );
+ }
+
+ } while ((Component != NULL) && (*PathString != 0));
+
+ return MatchComponent;
+}
+
+PCONFIGURATION_COMPONENT
+FwGetChild (
+ IN PCONFIGURATION_COMPONENT Component OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ Returns a pointer to the configuration component for the first child of
+ Component. If Component is NULL, a pointer to the root configuration
+ component is returned.
+
+Arguments:
+
+ Component - Supplies an optional pointer to a configuration component.
+
+Return Value:
+
+ Returns a pointer to the configuration component for the first child of
+ Component. If Component has no children, this pointer will be NULL. If
+ Component is NULL, a pointer to the root configuration component is
+ returned. If the configuration is not valid, NULL is returned.
+
+--*/
+{
+ PCONFIGURATION_PACKET Packet;
+
+ //
+ // If the configuration is not valid, return NULL.
+ //
+
+ if (!NvramValid) {
+ return(NULL);
+ }
+
+
+ if (Component == NULL) {
+ return &Configuration->Packet[0].Component;
+ } else {
+ Packet = CONTAINING_RECORD(Component,
+ CONFIGURATION_PACKET,
+ Component);
+
+ return &((PCONFIGURATION_PACKET)(Packet->Child))->Component;
+ }
+}
+
+
+PCONFIGURATION_COMPONENT
+FwGetParent (
+ IN PCONFIGURATION_COMPONENT Component
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the parent of the named component.
+
+Arguments:
+
+ Component - Supplies a pointer to a configuration component.
+
+Return Value:
+
+ Returns a pointer to the configuration component for the parent of
+ Component. If Component has no parent NULL is returned (this is only
+ true for the root configuration component). If the configuration is
+ not valid, NULL is returned.
+
+--*/
+{
+ PCONFIGURATION_PACKET Packet;
+
+ //
+ // If the configuration is not valid, return NULL.
+ //
+
+ if (!NvramValid) {
+ return(NULL);
+ }
+
+ Packet = CONTAINING_RECORD(Component,
+ CONFIGURATION_PACKET,
+ Component);
+
+ if (Packet->Parent == NULL) {
+ return NULL;
+ } else {
+ return &((PCONFIGURATION_PACKET)(Packet->Parent))->Component;
+ }
+}
+
+
+PCONFIGURATION_COMPONENT
+FwGetPeer (
+ IN PCONFIGURATION_COMPONENT Component
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the peer of the named component.
+
+Arguments:
+
+ Component - Supplies a pointer to a configuration component.
+
+Return Value:
+
+ Returns a pointer to the configuration component for the next peer of
+ Component. If Component has no next peer, NULL is returned. If the
+ configuration is not valid, NULL is returned.
+
+--*/
+{
+ PCONFIGURATION_PACKET Packet;
+
+ //
+ // If the configuration is not valid, return NULL.
+ //
+
+ if (!NvramValid) {
+ return(NULL);
+ }
+
+ Packet = CONTAINING_RECORD(Component,
+ CONFIGURATION_PACKET,
+ Component);
+
+ if (Packet->Peer == NULL) {
+ return NULL;
+ } else {
+ return &((PCONFIGURATION_PACKET)(Packet->Peer))->Component;
+ }
+}
+
+
+ARC_STATUS
+FwGetConfigurationDataIndex
+ (
+ OUT PVOID ConfigurationData,
+ IN PCONFIGURATION_COMPONENT Component,
+ IN ULONG Index,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This functions returns the specified configuration data
+ associated with Component in the buffer supplied by
+ ConfigurationData. The max length of the data is stored
+ in the Component structure.
+
+Arguments:
+
+ ConfigurationData - Supplies a pointer to a buffer to receive the
+ configuration data.
+
+ Component - Supplies a pointer to a configuration component.
+
+ Index - Supplies an index within the configuration data.
+
+ Length - Supplies the number of bytes to read (see the
+ ConfigurationDataLength field within the Component for the max
+ value).
+
+Return Value:
+
+ If the configuration data is successfully copied into the buffer
+ provided by ConfigurationData, ESUCCESS is returned. Otherwise one of
+ the following error codes is returned.
+
+ EINVAL Component is not a valid configuration component or the
+ other arguments are invalid or the configuration is
+ not valid.
+
+--*/
+
+{
+ PCONFIGURATION_PACKET Packet;
+ ULONG DataSize;
+ PUCHAR SourceData;
+ PUCHAR DestinationData;
+
+ //
+ // If the configuration is not valid, return EINVAL.
+ //
+
+ if (!NvramValid) {
+ return(EINVAL);
+ }
+
+ DataSize = Component->ConfigurationDataLength;
+
+ //
+ // check the passing parameters
+ //
+
+ if ( DataSize == 0 || Index >= DataSize || DataSize - Index < Length ) {
+ return EINVAL;
+ }
+
+ Packet = CONTAINING_RECORD( Component, CONFIGURATION_PACKET, Component );
+
+ //
+ // If Component's Parent field is NULL, return EINVAL.
+ //
+
+ if (Packet->Parent == NULL) {
+ return EINVAL;
+ }
+
+ //
+ // If this is an eisa component, decompress the data, otherwise just copy it.
+ //
+
+ if (Packet->Parent->Component.Type == EisaAdapter) {
+ FwZeroDecompress(Packet->ConfigurationData,
+ Index,
+ ConfigurationData,
+ Length);
+
+ } else {
+ SourceData = (PUCHAR)Packet->ConfigurationData + Index;
+ DestinationData = ConfigurationData;
+
+ while ( Length-- )
+ {
+ *DestinationData++ = *SourceData++;
+ }
+ }
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+FwGetConfigurationData (
+ OUT PVOID ConfigurationData,
+ IN PCONFIGURATION_COMPONENT Component
+ )
+
+/*++
+
+Routine Description:
+
+ This functions returns the configuration data associated with Component
+ in the buffer supplied by ConfigurationData. The length of the data
+ is stored in the Component structure.
+
+Arguments:
+
+ ConfigurationData - Supplies a pointer to a buffer to receive the
+ configuration data.
+
+ Component - Supplies a pointer to a configuration component.
+
+Return Value:
+
+ If the configuration data is successfully copied into the buffer
+ provided by ConfigurationData, ESUCCESS is returned. Otherwise one of
+ the following error codes is returned.
+
+ EINVAL Component is not a valid configuration component, or the
+ configuration is invalid.
+
+--*/
+
+{
+ return(FwGetConfigurationDataIndex(ConfigurationData,
+ Component,
+ 0,
+ Component->ConfigurationDataLength));
+}
+
+
+
+ARC_STATUS
+FwSaveConfiguration (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stores all of the configuration entries into NVRAM,
+ including the associated identifier strings and configuration data.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns ESUCCESS if the save completed successfully, otherwise one of the
+ following error codes is returned.
+
+ ENOSPC Not enough space in the NVRAM to save all of the data.
+
+--*/
+
+{
+ ULONG EntryIndex;
+ ULONG Index;
+ PCONFIGURATION_PACKET Packet;
+ PCONFIGURATION_COMPONENT Component;
+ PNV_CONFIGURATION NvConfiguration;
+ COMPRESSED_CONFIGURATION_PACKET CompressedPacket;
+ USHORT NvIdentifierIndex;
+ USHORT NvDataIndex;
+ USHORT NvEisaDataIndex;
+ PUCHAR CompressedChars, NvChars, Data;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+ NvIdentifierIndex = 0;
+ NvDataIndex = 0;
+ NvEisaDataIndex = 0;
+
+ //
+ // Write each volatile packet into a compressed non-volatile packet,
+ // including the identifier string and the configuration data.
+ //
+
+ for ( EntryIndex = 0 ; EntryIndex < NUMBER_OF_ENTRIES ; EntryIndex++ ) {
+
+ //
+ // Get pointers to the volatile data.
+ //
+
+ Packet = (PCONFIGURATION_PACKET)&Configuration->Packet[EntryIndex];
+ Component = &Packet->Component;
+
+ //
+ // If this is not the root entry and the parent field is NULL, zero
+ // entry and skip to next.
+ //
+
+ if ((EntryIndex != 0) && (Packet->Parent == NULL)) {
+ NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex];
+ for ( Index = 0 ;
+ Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ;
+ Index++ ) {
+ WRITE_REGISTER_UCHAR( NvChars++, 0);
+ }
+ continue;
+ }
+
+ //
+ // Determine the parent and store as an index. Note that the index
+ // (Packet->Parent) is 1 based, to reserve the value 0 to mean no
+ // parent.
+ //
+
+ if (EntryIndex != 0) {
+ CompressedPacket.Parent =
+ (UCHAR)(Packet->Parent - &Configuration->Packet[0]) + 1;
+ } else {
+ CompressedPacket.Parent = 0;
+ }
+
+ //
+ // Fill in the rest of the fields. Version and ConfigurationDataLength will
+ // never be larger than USHORTS.
+ //
+
+ CompressedPacket.Class = (UCHAR)Component->Class;
+ CompressedPacket.Type = (UCHAR)Component->Type;
+ CompressedPacket.Version = (UCHAR)Component->Version;
+ CompressedPacket.Revision = (UCHAR)Component->Revision;
+ CompressedPacket.Key = Component->Key;
+ CompressedPacket.ConfigurationDataLength =
+ (USHORT)Component->ConfigurationDataLength;
+ CompressedPacket.ConfigurationData = 0;
+
+ //
+ // Make sure the top bit of the flag field is zero unless it's set
+ // to be eisa below.
+ //
+
+ CompressedPacket.Flags = *(PUCHAR)(&Component->Flags) & 0x7f;
+
+ //
+ // If the component has an identifier string, copy it to NVRAM,
+ // otherwise set the index to indicate no identifier.
+ //
+
+ if (Component->IdentifierLength != 0) {
+ CompressedPacket.Identifier = NvIdentifierIndex;
+ for ( Index = 0 ; Index < Component->IdentifierLength ; Index++ ) {
+ WRITE_REGISTER_UCHAR(
+ &NvConfiguration->Identifier[NvIdentifierIndex++],
+ Component->Identifier[Index]);
+ }
+ } else {
+ CompressedPacket.Identifier = NO_CONFIGURATION_IDENTIFIER;
+ }
+
+ //
+ // If the component has configuration data, copy it to NVRAM.
+ //
+
+ if (Component->ConfigurationDataLength != 0) {
+
+ //
+ // If the parent component is the eisa bus, copy until the end
+ // of the compressed data.
+ //
+
+ if (Packet->Parent->Component.Type == EisaAdapter) {
+ CompressedPacket.ConfigurationData = NvEisaDataIndex;
+ Data = (PUCHAR)Packet->ConfigurationData;
+ for ( Index = 0 ; TRUE ; Index++ ) {
+ WRITE_REGISTER_UCHAR( &NvConfiguration->EisaData[NvEisaDataIndex++],
+ *Data++);
+
+ //
+ // If we've written at least two bytes and the last two
+ // bytes were zero we're at the end.
+ //
+
+ if ((Index > 1) && (!*(Data - 1) && !*(Data - 2))) {
+ break;
+ }
+ }
+
+ //
+ // Set a flag to make it easier to determine that this is an
+ // Eisa component.
+ //
+
+ CompressedPacket.Flags |= 0x80;
+
+ } else {
+ CompressedPacket.ConfigurationData = NvDataIndex;
+ Data = (PUCHAR)Packet->ConfigurationData;
+ for ( Index = 0 ; Index < Component->ConfigurationDataLength ; Index++ ) {
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Data[NvDataIndex++],
+ *Data++);
+ }
+ }
+ }
+
+ //
+ // Write compressed packet to NVRAM.
+ //
+
+ CompressedChars = (PUCHAR)&CompressedPacket;
+ NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex];
+
+ for ( Index = 0 ;
+ Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ;
+ Index++ ) {
+ WRITE_REGISTER_UCHAR( NvChars++, *CompressedChars++);
+ }
+ }
+
+ //
+ // Zero the rest of the identifier and configuration data areas.
+ //
+
+ for ( Index = NvIdentifierIndex ; Index < LENGTH_OF_IDENTIFIER ; Index++ ) {
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Identifier[Index], 0);
+ }
+
+ for ( Index = NvDataIndex ; Index < LENGTH_OF_DATA ; Index++ ) {
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Data[Index] ,0);
+ }
+
+ for ( Index = NvEisaDataIndex ; Index < LENGTH_OF_EISA_DATA ; Index++ ) {
+ WRITE_REGISTER_UCHAR( &NvConfiguration->EisaData[Index] ,0);
+ }
+
+ //
+ // Write configuration data checksum.
+ //
+
+ FwConfigurationSetChecksum();
+
+ //
+ // Restore configuration information out of NVRAM. This acts to compress
+ // the identifier and configuration data areas if any deletes have been
+ // performed.
+ //
+
+ return FwRestoreConfiguration();
+}
+
+
+ARC_STATUS
+FwRestoreConfiguration (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine restores all of the configuration entries from NVRAM,
+ including the associated identifier strings and configuration data.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns ESUCCESS if the restore completed successfully, otherwise one of
+ the following error codes is returned.
+
+ EIO Invalid NVRAM checksum.
+
+--*/
+
+{
+ ULONG EntryIndex;
+ ULONG Index;
+ PCONFIGURATION_PACKET Packet;
+ PCONFIGURATION_COMPONENT Component;
+ PNV_CONFIGURATION NvConfiguration;
+ COMPRESSED_CONFIGURATION_PACKET CompressedPacket;
+ USHORT NvIdentifierIndex;
+ USHORT NvDataIndex;
+ USHORT NvEisaDataIndex;
+ PUCHAR CompressedChars, NvChars;
+ PCONFIGURATION_PACKET SearchPacket;
+ ULONG Long;
+
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+ NvIdentifierIndex = 0;
+ NvDataIndex = 0;
+ NvEisaDataIndex = 0;
+ IdentifierIndex = 0;
+ DataIndex = 0;
+ EisaDataIndex = 0;
+
+ //
+ // Check the checksum, return error if invalid.
+ //
+
+ if (FwConfigurationCheckChecksum() != ESUCCESS) {
+ return EIO;
+ }
+
+ //
+ // Clear the configuration area.
+ //
+
+ RtlZeroMemory(Configuration, sizeof(CONFIGURATION));
+
+ //
+ // Read each non-volatile compressed packet into a volatile packet,
+ // including the identifier string and the configuration data.
+ //
+
+ for ( EntryIndex = 0 ; EntryIndex < NUMBER_OF_ENTRIES ; EntryIndex++ ) {
+
+ //
+ // Read compressed packet from NVRAM.
+ //
+
+ CompressedChars = (PUCHAR)&CompressedPacket;
+ NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex];
+
+ for ( Index = 0 ;
+ Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ;
+ Index++ ) {
+ *CompressedChars++ = READ_REGISTER_UCHAR( NvChars++ );
+ }
+
+ //
+ // If this is not the root entry and the parent field is NULL,
+ // go to the next.
+ //
+
+ if ((EntryIndex != 0) && (CompressedPacket.Parent == 0)) {
+ continue;
+ }
+
+ //
+ // Get pointers to the volatile area.
+ //
+
+ Packet = (PCONFIGURATION_PACKET)&Configuration->Packet[EntryIndex];
+ Component = &Packet->Component;
+
+ //
+ // If not the root entry and the parent field is within range, fill
+ // in parent field (note that the parent index
+ // is 1 based, subtract 1 to get correct index). If the parent's child
+ // pointer is NULL, fill in with the current entry, otherwise follow
+ // the links and add the current entry as the last peer.
+ //
+
+ if ((EntryIndex != 0) && (CompressedPacket.Parent <= NUMBER_OF_ENTRIES)) {
+ Packet->Parent = &Configuration->Packet[CompressedPacket.Parent - 1];
+ SearchPacket = Packet->Parent;
+
+ if (SearchPacket->Child == NULL) {
+ SearchPacket->Child = Packet;
+ } else {
+ SearchPacket = SearchPacket->Child;
+ while ( SearchPacket->Peer != NULL ) {
+ SearchPacket = SearchPacket->Peer;
+ }
+ SearchPacket->Peer = Packet;
+ }
+ } else {
+ Packet->Parent = NULL;
+ }
+
+ //
+ // NULL current packet's child and peer pointers.
+ //
+
+ Packet->Child = NULL;
+ Packet->Peer = NULL;
+
+ //
+ // Fill in the rest of the fields.
+ //
+
+ Component->Class = (CONFIGURATION_CLASS)CompressedPacket.Class;
+ Component->Type = (CONFIGURATION_TYPE)CompressedPacket.Type;
+ Component->Flags.Failed = (CompressedPacket.Flags & 0x01) ? 1 : 0;
+ Component->Flags.ReadOnly = (CompressedPacket.Flags & 0x02) ? 1 : 0;
+ Component->Flags.Removable = (CompressedPacket.Flags & 0x04) ? 1 : 0;
+ Component->Flags.ConsoleIn = (CompressedPacket.Flags & 0x08) ? 1 : 0;
+ Component->Flags.ConsoleOut = (CompressedPacket.Flags & 0x10) ? 1 : 0;
+ Component->Flags.Input = (CompressedPacket.Flags & 0x20) ? 1 : 0;
+ Component->Flags.Output = (CompressedPacket.Flags & 0x40) ? 1 : 0;
+ Component->Version = (USHORT)CompressedPacket.Version;
+ Component->Revision = (USHORT)CompressedPacket.Revision;
+ Component->Key = CompressedPacket.Key;
+ Component->AffinityMask = 0xffffffff;
+ Component->ConfigurationDataLength =
+ (ULONG)CompressedPacket.ConfigurationDataLength;
+
+ //
+ // If the component has an identifier string, copy it to memory.
+ //
+
+ Index = 0;
+
+ if (CompressedPacket.Identifier != NO_CONFIGURATION_IDENTIFIER) {
+ Component->Identifier = &Configuration->Identifier[IdentifierIndex];
+ do {
+ Configuration->Identifier[IdentifierIndex++] =
+ READ_REGISTER_UCHAR(
+ &NvConfiguration->Identifier[NvIdentifierIndex] );
+ Index++;
+ } while ( READ_REGISTER_UCHAR(&NvConfiguration->Identifier[NvIdentifierIndex++] ) );
+ }
+
+ //
+ // Set identifier length field.
+ //
+
+ Component->IdentifierLength = Index;
+
+ //
+ // If the component has configuration data, copy it to memory.
+ //
+
+ if (Component->ConfigurationDataLength != 0) {
+
+ //
+ // If the eisa flag is set, only copy the compressed data.
+ //
+
+ if (CompressedPacket.Flags & 0x80) {
+ Packet->ConfigurationData = &Configuration->EisaData[EisaDataIndex];
+ for ( Index = 0 ; TRUE ; Index++ ) {
+ Configuration->EisaData[EisaDataIndex++] =
+ READ_REGISTER_UCHAR( &NvConfiguration->EisaData[NvEisaDataIndex++] );
+
+ //
+ // If at least two bytes have been written and the last
+ // two bytes are zero, we're at the end.
+ //
+
+ if ((Index > 1) &&
+ (!Configuration->EisaData[EisaDataIndex - 1] &
+ !Configuration->EisaData[EisaDataIndex - 2])) {
+ break;
+ }
+ }
+ } else {
+ Packet->ConfigurationData = &Configuration->Data[DataIndex];
+ for ( Index = 0 ; Index < Component->ConfigurationDataLength ; Index++ ) {
+ Configuration->Data[DataIndex++] =
+ READ_REGISTER_UCHAR( &NvConfiguration->Data[NvDataIndex++] );
+ }
+ }
+ }
+ }
+
+ return(ESUCCESS);
+}
+
+
+ARC_STATUS
+FwConfigurationCheckChecksum (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks the configuration checksum.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the checksum is good, ESUCCESS is returned, otherwise EIO is returned.
+
+--*/
+
+{
+ PUCHAR NvChars;
+ PNV_CONFIGURATION NvConfiguration;
+ ULONG Index;
+ ULONG Checksum1, Checksum2;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // Form checksum from NVRAM data.
+ //
+
+ Checksum1 = 0;
+ NvChars = (PUCHAR)NvConfiguration;
+
+ for ( Index = 0 ;
+ Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) * NUMBER_OF_ENTRIES +
+ LENGTH_OF_IDENTIFIER + LENGTH_OF_DATA;
+ Index++ ) {
+ Checksum1 += READ_REGISTER_UCHAR( NvChars++ );
+ }
+
+ //
+ // Reconstitute checksum and return error if no compare.
+ //
+
+ Checksum2 = (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum1[0] ) |
+ (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum1[1] ) << 8 |
+ (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum1[2] ) << 16 |
+ (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum1[3] ) << 24 ;
+
+ if (Checksum1 != Checksum2) {
+ NvramValid = FALSE;
+ return EIO;
+ }
+
+ //
+ // Repeat for the eisa data area.
+ //
+
+ Checksum1 = 0;
+ NvChars = (PUCHAR)NvConfiguration->EisaData;
+
+ for ( Index = 0 ;
+ Index < LENGTH_OF_EISA_DATA;
+ Index++ ) {
+ Checksum1 += READ_REGISTER_UCHAR( NvChars++ );
+ }
+
+ //
+ // Reconstitute checksum and return error if no compare.
+ //
+
+ Checksum2 = (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum3[0] ) |
+ (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum3[1] ) << 8 |
+ (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum3[2] ) << 16 |
+ (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum3[3] ) << 24 ;
+
+ if (Checksum1 != Checksum2) {
+ NvramValid = FALSE;
+ return EIO;
+ }
+
+ NvramValid = TRUE;
+ return(ESUCCESS);
+}
+
+VOID
+FwConfigurationSetChecksum (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the configuration checksum.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUCHAR NvChars;
+ PNV_CONFIGURATION NvConfiguration;
+ ULONG Index;
+ ULONG Checksum1;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // Form checksum from NVRAM data.
+ //
+
+ Checksum1 = 0;
+ NvChars = (PUCHAR)NvConfiguration;
+
+ for ( Index = 0 ;
+ Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) * NUMBER_OF_ENTRIES +
+ LENGTH_OF_IDENTIFIER + LENGTH_OF_DATA;
+ Index++ ) {
+ Checksum1 += READ_REGISTER_UCHAR( NvChars++ );
+ }
+
+ //
+ // Set checksum.
+ //
+
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum1[0], Checksum1);
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum1[1], Checksum1 >> 8);
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum1[2], Checksum1 >> 16);
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum1[3], Checksum1 >> 24);
+
+ //
+ // Repeat for the eisa data area.
+ //
+
+ Checksum1 = 0;
+ NvChars = (PUCHAR)NvConfiguration->EisaData;
+
+ for ( Index = 0 ;
+ Index < LENGTH_OF_EISA_DATA;
+ Index++ ) {
+ Checksum1 += READ_REGISTER_UCHAR( NvChars++ );
+ }
+
+ //
+ // Set checksum.
+ //
+
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum3[0], Checksum1);
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum3[1], Checksum1 >> 8);
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum3[2], Checksum1 >> 16);
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum3[3], Checksum1 >> 24);
+
+ NvramValid = TRUE;
+ return;
+
+}
+
+ARC_STATUS
+FwGetVideoData (
+ OUT PMONITOR_CONFIGURATION_DATA MonitorData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine finds the video board and monitor configuration data in the
+ NVRAM. Normally this information would be accessed through
+ FwGetConfigurationData, but the initialization code needs the video
+ information before the firmware routines have been initialized. If no
+ monitor data is found, then default data is returned.
+
+Arguments:
+
+ MonitorData - Supplies a pointer to a structure to receive the monitor
+ configuration data.
+
+Return Value:
+
+ Returns ESUCCESS if data was found and restored, otherwise returns one of
+ the following error codes.
+
+ EIO Invalid NVRAM checksum.
+
+ ENODEV Monitor data not found.
+
+ Note that in any event valid data is returned.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ ULONG EntryIndex;
+ ULONG Index;
+ COMPRESSED_CONFIGURATION_PACKET CompressedPacket;
+ PUCHAR CompressedChars;
+ PUCHAR NvChars;
+ PUCHAR Data;
+ PNV_CONFIGURATION NvConfiguration;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // Check configuration checksum, return error if not valid.
+ //
+
+ if (FwConfigurationCheckChecksum() != ESUCCESS){
+ Status = EIO;
+ } else {
+
+ //
+ // Search the NVRAM configuration entries for the monitor, skip
+ // the root entry.
+ //
+
+ for ( EntryIndex = 1 ; EntryIndex < NUMBER_OF_ENTRIES ; EntryIndex++ ) {
+
+ //
+ // Read compressed packet from NVRAM.
+ //
+
+ CompressedChars = (PUCHAR)&CompressedPacket;
+ NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex];
+
+ for ( Index = 0 ;
+ Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ;
+ Index++ ) {
+ *CompressedChars++ = READ_REGISTER_UCHAR( NvChars++ );
+ }
+
+ //
+ // If the parent field is not Null, and the packet is class Peripheral,
+ // type Monitor, this is the display.
+ //
+
+ if ((CompressedPacket.Parent != 0) &&
+ (CompressedPacket.Class == PeripheralClass) &&
+ (CompressedPacket.Type == MonitorPeripheral)) {
+ break;
+ }
+ }
+
+ //
+ // If we've fallen out of the loop the monitor was not found, return
+ // error.
+ //
+
+ if (EntryIndex == NUMBER_OF_ENTRIES) {
+ Status = ENODEV;
+ } else {
+
+ //
+ // If the configuration data length is the correct value, copy the data
+ // into the monitor data structure, otherwise return an error.
+ //
+
+ if (CompressedPacket.ConfigurationDataLength == sizeof(MONITOR_CONFIGURATION_DATA)) {
+ Data = (PUCHAR)MonitorData;
+ for ( DataIndex = CompressedPacket.ConfigurationData ;
+ DataIndex < (CompressedPacket.ConfigurationData +
+ CompressedPacket.ConfigurationDataLength) ;
+ DataIndex++ ) {
+ *Data++ = READ_REGISTER_UCHAR( &NvConfiguration->Data[DataIndex] );
+ }
+ Status = ESUCCESS;
+ } else {
+ Status = ENODEV;
+ }
+ }
+ }
+
+ if (Status != ESUCCESS) {
+ MonitorData->HorizontalResolution = DefaultMonitor.HorizontalResolution;
+ MonitorData->HorizontalDisplayTime = DefaultMonitor.HorizontalDisplayTime;
+ MonitorData->HorizontalBackPorch = DefaultMonitor.HorizontalBackPorch;
+ MonitorData->HorizontalFrontPorch = DefaultMonitor.HorizontalFrontPorch;
+ MonitorData->HorizontalSync = DefaultMonitor.HorizontalSync;
+ MonitorData->VerticalResolution = DefaultMonitor.VerticalResolution;
+ MonitorData->VerticalBackPorch = DefaultMonitor.VerticalBackPorch;
+ MonitorData->VerticalFrontPorch = DefaultMonitor.VerticalFrontPorch;
+ MonitorData->VerticalSync = DefaultMonitor.VerticalSync;
+ MonitorData->HorizontalScreenSize = DefaultMonitor.HorizontalScreenSize;
+ MonitorData->VerticalScreenSize = DefaultMonitor.VerticalScreenSize;
+ }
+
+ return(Status);
+}
+
+VOID
+FwSetVideoData (
+ IN PMONITOR_CONFIGURATION_DATA MonitorData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine stores the monitor configuration data in the
+ NVRAM. Normally this information would be accessed through
+ FwAddChild, but this routine allows this data to be set before the
+ configuration routines have been initialized.
+
+ N.B. This routine assumes the NVRAM has already been checked by
+ FwGetVideoData and is valid.
+
+Arguments:
+
+ MonitorData - Supplies a pointer to a structure containing the monitor
+ configuration data.
+
+Return Value:
+
+ None.
+
+
+--*/
+
+{
+ ARC_STATUS Status;
+ ULONG EntryIndex;
+ ULONG Index;
+ COMPRESSED_CONFIGURATION_PACKET CompressedPacket;
+ PUCHAR CompressedChars;
+ PUCHAR NvChars;
+ PUCHAR Data;
+ PNV_CONFIGURATION NvConfiguration;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // Search the NVRAM configuration entries for the monitor, skip
+ // the root entry.
+ //
+
+ for ( EntryIndex = 1 ; EntryIndex < NUMBER_OF_ENTRIES ; EntryIndex++ ) {
+
+ //
+ // Read compressed packet from NVRAM.
+ //
+
+ CompressedChars = (PUCHAR)&CompressedPacket;
+ NvChars = (PUCHAR)&NvConfiguration->Packet[EntryIndex];
+
+ for ( Index = 0 ;
+ Index < sizeof(COMPRESSED_CONFIGURATION_PACKET) ;
+ Index++ ) {
+ *CompressedChars++ = READ_REGISTER_UCHAR( NvChars++ );
+ }
+
+ //
+ // If the parent field is not Null, and the packet is class Peripheral,
+ // type Monitor, this is the display.
+ //
+
+ if ((CompressedPacket.Parent != 0) &&
+ (CompressedPacket.Class == PeripheralClass) &&
+ (CompressedPacket.Type == MonitorPeripheral)) {
+ break;
+ }
+ }
+
+ //
+ // Copy the data into the monitor data structure.
+ //
+
+ Data = (PUCHAR)MonitorData;
+ for ( DataIndex = CompressedPacket.ConfigurationData ;
+ DataIndex < (CompressedPacket.ConfigurationData +
+ CompressedPacket.ConfigurationDataLength) ;
+ DataIndex++ ) {
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Data[DataIndex], *Data++);
+ }
+
+ //
+ // Fix the checksum.
+ //
+
+ FwConfigurationSetChecksum();
+
+ return;
+}
+
+
+ULONG
+FwZeroCompressLength (
+ IN ULONG DataLength,
+ IN PVOID ConfigurationData
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the compressed length of a configuration data sample.
+
+Arguments:
+
+ DataLength - Supplies the uncompressed length of the data.
+
+ ConfigurationData - Supplies a pointer to the uncompressed configuration data.
+
+Return Value:
+
+ Returns the compressed length of the configuration data.
+
+--*/
+
+{
+ ULONG Index;
+ ULONG CompressedLength;
+ ULONG Zero;
+ PUCHAR In;
+
+ CompressedLength = 2;
+ Zero = 0;
+ In = ConfigurationData;
+
+ for (Index = 0; Index < DataLength ; Index++ ) {
+ if (*In++) {
+ CompressedLength++;
+ Zero = 0;
+ } else {
+ if (Zero++) {
+ if (Zero == 0x100) {
+ Zero = 1;
+ CompressedLength += 2;
+ }
+ } else {
+ CompressedLength += 2;
+ }
+ }
+ }
+ return(CompressedLength);
+}
+
+
+ULONG
+FwZeroCompress (
+ IN ULONG DataLength,
+ IN PVOID ConfigurationData,
+ OUT PVOID OutputBuffer
+ )
+
+/*++
+
+Routine Description:
+
+ This routine compresses configuration data.
+
+Arguments:
+
+ DataLength - Supplies the uncompressed length of the data.
+
+ ConfigurationData - Supplies a pointer to the uncompressed configuration data.
+
+ OutputBuffer - Supplies a pointer to the buffer to receive the compressed data.
+
+Return Value:
+
+ Returns the compressed length of the configuration data.
+
+--*/
+
+{
+ ULONG Index;
+ ULONG CompressedLength;
+ ULONG Zero;
+ PUCHAR In, Out;
+
+ In = (PUCHAR)ConfigurationData;
+ Out = (PUCHAR)OutputBuffer;
+ CompressedLength = 2;
+ Zero = 0;
+
+ for (Index = 0; Index < DataLength ; Index++ ) {
+ if (*In) {
+ if (Zero) {
+ Out++;
+ Zero = 0;
+ }
+ *Out++ = *In;
+ CompressedLength++;
+ } else {
+ if (Zero++) {
+ if (Zero == 0x100) {
+ *Out++ = 0xFF;
+ *Out++ = 0;
+ *Out = 1;
+ Zero = 1;
+ CompressedLength += 2;
+ } else {
+ *Out += 1;
+ }
+ } else {
+ *Out++ = 0;
+ *Out = 1;
+ CompressedLength += 2;
+ }
+ }
+ In++;
+ }
+
+ if (Zero) {
+ Out++;
+ }
+
+ *Out++ = 0;
+ *Out = 0;
+
+ return(CompressedLength);
+}
+
+
+VOID
+FwZeroDecompress (
+ IN PVOID InBuffer,
+ IN ULONG Index,
+ OUT PVOID ConfigurationData,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine compresses configuration data.
+
+Arguments:
+
+ InBuffer - Supplies a pointer to the compressed configuration data.
+
+ Index - Supplies the index into the uncompressed data to start returning.
+
+ ConfigurationData - Supplies a pointer to the output buffer.
+
+ Length - Supplies the length of data to uncompress.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG DecompressedLength;
+ ULONG Zero;
+ PUCHAR In, Out;
+ UCHAR OutChar;
+
+ if (InBuffer == NULL) {
+ return;
+ }
+
+ In = (PUCHAR)InBuffer;
+ Out = (PUCHAR)ConfigurationData;
+ DecompressedLength = 0;
+ Zero = 0;
+
+ while (DecompressedLength++ < Index + Length) {
+
+ if (Zero) {
+ Zero--;
+ } else if (*In) {
+ OutChar = *In++;
+ } else {
+ OutChar = 0;
+ Zero = *(++In) - 1;
+ In++;
+ }
+
+ if (DecompressedLength > Index) {
+ *Out++ = OutChar;
+ }
+
+ }
+
+}
+#endif
diff --git a/private/ntos/fw/mips/jxdisp.c b/private/ntos/fw/mips/jxdisp.c
new file mode 100644
index 000000000..1ab9ea555
--- /dev/null
+++ b/private/ntos/fw/mips/jxdisp.c
@@ -0,0 +1,2158 @@
+
+
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ jxdisp.c
+
+Abstract:
+
+ This module implements the video boot driver for the Jazz system.
+
+Author:
+
+ David M. Robinson (davidro) 24-Jul-1991
+
+Environment:
+
+ Kernel mode.
+
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#include "jazzvdeo.h"
+#include "jxvideo.h"
+#include "selfmap.h"
+#include "selftest.h"
+#include "string.h"
+
+ARC_STATUS
+InitializeG300 (
+ IN PMONITOR_CONFIGURATION_DATA GlobalMonitor
+ );
+
+ARC_STATUS
+InitializeG364 (
+ IN PMONITOR_CONFIGURATION_DATA GlobalMonitor
+ );
+
+VOID
+FillVideoMemory (
+ IN PUCHAR StartAddress,
+ IN ULONG SizeInBytes,
+ IN ULONG Pattern
+ );
+
+ARC_STATUS
+DisplayClose (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+DisplayMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ );
+
+ARC_STATUS
+DisplayOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ IN OUT PULONG FileId
+ );
+
+ARC_STATUS
+DisplayRead (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+DisplayGetReadStatus (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+DisplaySeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+DisplayWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+DisplayGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Finfo
+ );
+
+VOID FwVideoScroll(
+ PVOID StartAddress,
+ PVOID EndAddress,
+ PVOID Destination
+ );
+
+#define G300_PALETTE_BLACK 0x000000
+#define G300_PALETTE_RED 0x0000B0
+#define G300_PALETTE_GREEN 0x00B000
+#define G300_PALETTE_YELLOW 0x00B0B0
+#define G300_PALETTE_BLUE 0x900000
+#define G300_PALETTE_MAGENTA 0xB000B0
+#define G300_PALETTE_CYAN 0xB0B000
+#define G300_PALETTE_WHITE 0xB0B0B0
+#define G300_PALETTE_HI_BLACK 0x000000
+#define G300_PALETTE_HI_RED 0x0000FF
+#define G300_PALETTE_HI_GREEN 0x00FF00
+#define G300_PALETTE_HI_YELLOW 0x00FFFF
+#define G300_PALETTE_HI_BLUE 0xFF0000
+#define G300_PALETTE_HI_MAGENTA 0xFF00FF
+#define G300_PALETTE_HI_CYAN 0xFFFF00
+#define G300_PALETTE_HI_WHITE 0xFFFFFF
+
+#define G364_PALETTE_BLACK 0x000000
+#define G364_PALETTE_RED 0xB00000
+#define G364_PALETTE_GREEN 0x00B000
+#define G364_PALETTE_YELLOW 0xB0B000
+#define G364_PALETTE_BLUE 0x0000B0
+#define G364_PALETTE_MAGENTA 0xB000B0
+#define G364_PALETTE_CYAN 0x00B0B0
+#define G364_PALETTE_WHITE 0xB0B0B0
+#define G364_PALETTE_HI_BLACK 0x000000
+#define G364_PALETTE_HI_RED 0xFF0000
+#define G364_PALETTE_HI_GREEN 0x00FF00
+#define G364_PALETTE_HI_YELLOW 0xFFFF00
+#define G364_PALETTE_HI_BLUE 0x0000FF
+#define G364_PALETTE_HI_MAGENTA 0xFF00FF
+#define G364_PALETTE_HI_CYAN 0x00FFFF
+#define G364_PALETTE_HI_WHITE 0xFFFFFF
+
+//
+// Define virtual address of the video memory and control registers.
+//
+#define VIDEO_MEMORY ((PUCHAR)VIDEO_MEMORY_VIRTUAL_BASE)
+#define VIDEO_CONTROL ((PG300_VIDEO_REGISTERS)VIDEO_CONTROL_VIRTUAL_BASE)
+#define CURSOR_CONTROL ((PCURSOR_REGISTERS)VIDEO_CURSOR_VIRTUAL_BASE)
+
+
+//
+// Define and initialize device table.
+//
+
+BL_DEVICE_ENTRY_TABLE DisplayEntryTable = {
+ DisplayClose,
+ DisplayMount,
+ DisplayOpen,
+ DisplayRead,
+ DisplayGetReadStatus,
+ DisplaySeek,
+ DisplayWrite,
+ DisplayGetFileInformation,
+ (PARC_SET_FILE_INFO_ROUTINE)NULL,
+ (PRENAME_ROUTINE)NULL,
+ (PARC_GET_DIRECTORY_ENTRY_ROUTINE)NULL
+ };
+
+//
+// Static data.
+//
+
+ARC_DISPLAY_STATUS DisplayStatus;
+BOOLEAN ControlSequence;
+BOOLEAN EscapeSequence;
+BOOLEAN FontSelection;
+ULONG PCount;
+LONG FwColumn;
+LONG FwRow;
+BOOLEAN FwHighIntensity;
+BOOLEAN FwUnderscored;
+BOOLEAN FwReverseVideo;
+ULONG FwForegroundColor;
+ULONG FwBackgroundColor;
+PCHAR DisplayDevicePath = "multi(0)video(0)monitor(0)";
+ULONG DisplayWidth;
+ULONG DisplayText;
+ULONG FrameSize;
+ULONG ScrollLine;
+ULONG ScrollLength;
+LONG MaxRow;
+LONG MaxColumn;
+ULONG CharacterHeight;
+ULONG CharacterWidth;
+ULONG CharacterSize;
+PCHAR FwFont;
+ULONG FontIncrement;
+ULONG ColorTable[16] = { 0x00000000,
+ 0x0000000f,
+ 0x00000f00,
+ 0x00000f0f,
+ 0x000f0000,
+ 0x000f000f,
+ 0x000f0f00,
+ 0x000f0f0f,
+ 0x0f000000,
+ 0x0f00000f,
+ 0x0f000f00,
+ 0x0f000f0f,
+ 0x0f0f0000,
+ 0x0f0f000f,
+ 0x0f0f0f00,
+ 0x0f0f0f0f };
+
+#define CONTROL_SEQUENCE_MAX_PARAMETER 10
+LONG Parameter[CONTROL_SEQUENCE_MAX_PARAMETER];
+MONITOR_CONFIGURATION_DATA MonitorData;
+extern PUCHAR IdentifierString;
+
+MONITOR_CONFIGURATION_DATA DefaultMonitor = {
+ 0, // version : do not change
+ 0, // revision : do not change
+ 1280, // HorizontalResolution
+ 11832, // HorizontalDisplayTime
+ 1596, // HorizontalBackPorch
+ 587, // HorizontalFrontPorch
+ 1745, // HorizontalSync
+ 1024, // VerticalResolution
+ 28, // VerticalBackPorch
+ 1, // VerticalFrontPorch
+ 3, // VerticalSync
+ 0, // HorizontalScreenSize : do not change
+ 0 // VerticalScreenSize : do not change
+};
+
+
+#define FW_INVALID_CHARACTER 0xb1
+
+UCHAR LdUnicodeToAscii[128] = { 0xc4,0xb1,0xb3,0xb1,0xb1,0xb1,0xb1,0xb1,
+ 0xb1,0xb1,0xb1,0xb1,0xda,0xb1,0xb1,0xb1,
+ 0xbf,0xb1,0xb1,0xb1,0xc0,0xb1,0xb1,0xb1,
+ 0xd9,0xb1,0xb1,0xb1,0xc3,0xb1,0xb1,0xb1,
+ 0xb1,0xb1,0xb1,0xb1,0xb4,0xb1,0xb1,0xb1,
+ 0xb1,0xb1,0xb1,0xb1,0xc2,0xb1,0xb1,0xb1,
+ 0xb1,0xb1,0xb1,0xb1,0xc1,0xb1,0xb1,0xb1,
+ 0xb1,0xb1,0xb1,0xb1,0xc5,0xb1,0xb1,0xb1,
+ 0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+ 0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+ 0xcd,0xba,0xd5,0xd6,0xc9,0xb8,0xb7,0xbb,
+ 0xd4,0xd3,0xc8,0xbe,0xbd,0xbc,0xc6,0xc7,
+ 0xcc,0xb5,0xb6,0xb9,0xd1,0xd2,0xcb,0xcf,
+ 0xd0,0xca,0xd8,0xd7,0xce,0xb1,0xb1,0xb1,
+ 0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,
+ 0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1,0xb1 };
+
+
+//
+// Declare externally defined data.
+//
+
+extern UCHAR FwFont10x20[1];
+extern UCHAR FwFont8x12[1];
+
+
+//
+// Define routine prototypes.
+//
+
+VOID
+FwDisplayCharacter(
+ IN UCHAR Character
+ );
+
+VOID
+FwSetAllAttributes(
+ VOID
+ );
+
+
+ARC_STATUS
+DisplayGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Finfo
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns EINVAL as no FileInformation can be
+ returned for the Display driver.
+
+Arguments:
+
+ The arguments are not used.
+
+Return Value:
+
+ EINVAL is returned
+
+--*/
+
+{
+ return EINVAL;
+}
+
+ARC_STATUS
+DisplayClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes the file table entry specified by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+Return Value:
+
+ ESUCCESS is returned
+
+--*/
+
+{
+
+ BlFileTable[FileId].Flags.Open = 0;
+ return ESUCCESS;
+}
+
+ARC_STATUS
+DisplayMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ return EINVAL;
+}
+
+ARC_STATUS
+DisplayOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ IN OUT PULONG FileId
+ )
+/*++
+
+Routine Description:
+
+ This is the open routine for the display device.
+
+Arguments:
+
+ OpenPath - Supplies the pathname of the device to open.
+
+ OpenMode - Supplies the mode (read only, write only, or read write).
+
+ FileId - Supplies a free file identifier to use. If the device is already
+ open this parameter can be used to return the file identifier
+ already in use.
+
+Return Value:
+
+ If the open was successful, ESUCCESS is returned, otherwise an error code
+ is returned.
+
+--*/
+{
+ PCONSOLE_CONTEXT Context;
+
+ Context = &BlFileTable[*FileId].u.ConsoleContext;
+ if ( strstr(OpenPath, ")console(1)" ) != NULL ) {
+ Context->ConsoleNumber = 1;
+ } else {
+ Context->ConsoleNumber = 0;
+ }
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+DisplayRead (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ return(ESUCCESS);
+}
+
+
+ARC_STATUS
+DisplayGetReadStatus (
+ IN ULONG FileId
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+DisplayWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ This module implements the ARC firmware Console Output functions as
+ described in the Advanced Risc Computing Specification (Revision 1.00),
+ section 3.3.1.5.1 Basic Character Console, and section 3.3.1.5.2 Enhanced
+ Character Console for a MIPS R3000 or R4000 Jazz system.
+
+
+Arguments:
+
+ FileId - Supplies a file id.
+
+ Buffer - Supplies a pointer to a buffer containing the characters to
+ be displayed.
+
+ Length - Supplies the length of Buffer.
+
+ Count - Returns the count of the characters that were displayed.
+
+Return Value:
+
+ If the characters were successfully displayed, ESUCCESS is returned,
+ otherwise one of the following error codes is returned.
+
+ EBADF The file descriptor specified by FileId is invalid.
+
+ EIO An output error occurred.
+
+--*/
+
+{
+ PCONSOLE_CONTEXT Context;
+ ARC_STATUS Status;
+ PUCHAR String;
+ LONG ColumnEndPoint;
+ ULONG Index, Index2;
+ ULONG FGColor;
+ ULONG BGColor;
+ BOOLEAN Unicode;
+
+ Context = &BlFileTable[FileId].u.ConsoleContext;
+ if ( Context->ConsoleNumber == 1) {
+ if (Length & 1) {
+
+ //
+ // Length is not an even number of bytes, return an error.
+ //
+
+ return(EINVAL);
+ }
+ Unicode = TRUE;
+ } else {
+ Unicode = FALSE;
+ }
+
+ //
+ // Process each character in turn.
+ //
+
+ Status = ESUCCESS;
+ String = (PUCHAR)Buffer;
+
+ for ( *Count = 0 ;
+ *Count < Length ;
+ (*Count)++, String++ ) {
+
+ //
+ // Check for Unicode character.
+ //
+
+ if (Unicode) {
+ if (*Count & 1) {
+
+ //
+ // Skip the upper half of each character.
+ //
+
+ continue;
+ } else {
+ if (*(String + 1) == 0x25) {
+
+ //
+ // If a Unicode line drawing character, go ahead and display
+ // it.
+ //
+
+ if (*String <= 0x7f) {
+ FwDisplayCharacter(LdUnicodeToAscii[*String]);
+ } else {
+ FwDisplayCharacter(FW_INVALID_CHARACTER);
+ }
+
+ if (FwColumn < MaxColumn) {
+ FwColumn++;
+ }
+ continue;
+ } else {
+ if (*(String + 1) != 0) {
+
+ //
+ // Display an invalid character.
+ //
+
+ FwDisplayCharacter(FW_INVALID_CHARACTER);
+
+ if (FwColumn < MaxColumn) {
+ FwColumn++;
+ }
+ continue;
+ }
+ }
+ }
+ }
+
+ //
+ // If we're in the middle of a control sequence, continue scanning,
+ // otherwise process character.
+ //
+
+ if (ControlSequence) {
+
+ //
+ // If the character is a digit, update parameter value.
+ //
+
+ if ((*String >= '0') && (*String <= '9')) {
+ Parameter[PCount] = Parameter[PCount] * 10 + *String - '0';
+ continue;
+ }
+
+ //
+ // If we are in the middle of a font selection sequence, this
+ // character must be a 'D', otherwise reset control sequence.
+ //
+
+ if (FontSelection) {
+
+ //if (*String == 'D') {
+ //
+ // //
+ // // Other fonts not implemented yet.
+ // //
+ //
+ //} else {
+ //}
+
+ ControlSequence = FALSE;
+ FontSelection = FALSE;
+ continue;
+ }
+
+ switch (*String) {
+
+ //
+ // If a semicolon, move to the next parameter.
+ //
+
+ case ';':
+
+ PCount++;
+ if (PCount > CONTROL_SEQUENCE_MAX_PARAMETER) {
+ PCount = CONTROL_SEQUENCE_MAX_PARAMETER;
+ }
+ Parameter[PCount] = 0;
+ break;
+
+ //
+ // If a 'J', erase part or all of the screen.
+ //
+
+ case 'J':
+
+ switch (Parameter[0]) {
+
+ //
+ // Erase to end of the screen.
+ //
+
+ case 0:
+ //
+ // Clear to end of line by Writing char ' '
+ //
+ ColumnEndPoint = FwColumn;
+ while (FwColumn <= MaxColumn) {
+ FwDisplayCharacter(' ');
+ FwColumn++;
+ }
+ FwColumn = ColumnEndPoint;
+ if (FwRow+1 < MaxRow) {
+ //
+ // Zero the rest of the screen
+ //
+ FillVideoMemory((PUCHAR)(VIDEO_MEMORY + ((FwRow+1) * ScrollLine)),
+ FrameSize - ((FwRow+1) * ScrollLine),
+ FwBackgroundColor
+ );
+ }
+ break;
+
+ //
+ // Erase from the beginning of the screen.
+ //
+
+ case 1:
+ if (FwRow) {
+ FillVideoMemory((PUCHAR)(VIDEO_MEMORY),
+ (FwRow * ScrollLine),
+ FwBackgroundColor
+ );
+ }
+ ColumnEndPoint=FwColumn;
+ for (FwColumn=0; FwColumn < ColumnEndPoint; FwColumn++) {
+ FwDisplayCharacter(' ');
+ }
+ break;
+
+ //
+ // Erase entire screen.
+ //
+
+ default :
+ FillVideoMemory(VIDEO_MEMORY,
+ FrameSize,
+ FwBackgroundColor);
+ FwRow = 0;
+ FwColumn = 0;
+ break;
+ }
+
+ ControlSequence = FALSE;
+ break;
+
+ //
+ // If a 'K', erase part or all of the line.
+ //
+
+ case 'K':
+
+ switch (Parameter[0]) {
+
+ //
+ // Erase to end of the line.
+ //
+
+ case 0:
+ ColumnEndPoint = FwColumn;
+ FwColumn = MaxColumn + 1;
+ do {
+ FwColumn--;
+ FwDisplayCharacter(' ');
+ } while (FwColumn != ColumnEndPoint);
+ break;
+
+ //
+ // Erase from the beginning of the line.
+ //
+
+ case 1:
+ ColumnEndPoint = FwColumn;
+ FwColumn = -1;
+ do {
+ FwColumn++;
+ FwDisplayCharacter(' ');
+ } while (FwColumn != ColumnEndPoint);
+ break;
+
+ //
+ // Erase entire line.
+ //
+
+ default :
+ FwColumn = MaxColumn + 1;
+ do {
+ FwColumn--;
+ FwDisplayCharacter(' ');
+ } while (FwColumn != 0);
+ break;
+ }
+
+ ControlSequence = FALSE;
+ break;
+
+ //
+ // If a 'H', move cursor to position.
+ //
+
+ case 'H':
+
+ //
+ // Shift parameters to be 1 based.
+ //
+
+ if (Parameter[0] != 0) {
+ Parameter[0] -= 1;
+ }
+ if (Parameter[1] != 0) {
+ Parameter[1] -= 1;
+ }
+
+ FwRow = Parameter[0];
+ if (FwRow > MaxRow) {
+ FwRow = MaxRow;
+ }
+ FwColumn = Parameter[1];
+ if (FwColumn > MaxColumn) {
+ FwColumn = MaxColumn;
+ }
+
+ ControlSequence = FALSE;
+ break;
+
+ //
+ // If a 'A', move cursor up.
+ //
+
+ case 'A':
+
+ //
+ // A parameter of zero still means a cursor shift position of 1.
+ //
+
+ if (Parameter[0] == 0) {
+ Parameter[0] = 1;
+ }
+
+ if (Parameter[0] > FwRow) {
+ FwRow = 0;
+ } else {
+ FwRow -= Parameter[0];
+ }
+ ControlSequence = FALSE;
+ break;
+
+ //
+ // If a 'B', move cursor down.
+ //
+
+ case 'B':
+
+ //
+ // A parameter of zero still means a cursor shift position of 1.
+ //
+
+ if (Parameter[0] == 0) {
+ Parameter[0] = 1;
+ }
+
+ if (Parameter[0] + FwRow > MaxRow) {
+ FwRow = MaxRow;
+ } else {
+ FwRow += Parameter[0];
+ }
+ ControlSequence = FALSE;
+ break;
+
+ //
+ // If a 'C', move cursor right.
+ //
+
+ case 'C':
+
+ //
+ // A parameter of zero still means a cursor shift position of 1.
+ //
+
+ if (Parameter[0] == 0) {
+ Parameter[0] = 1;
+ }
+
+ if (Parameter[0] + FwColumn > MaxColumn) {
+ FwColumn = MaxColumn;
+ } else {
+ FwColumn += Parameter[0];
+ }
+ ControlSequence = FALSE;
+ break;
+
+ //
+ // If a 'D', move cursor left.
+ //
+
+ case 'D':
+
+ //
+ // A parameter of zero still means a cursor shift position of 1.
+ //
+
+ if (Parameter[0] == 0) {
+ Parameter[0] = 1;
+ }
+
+ if (Parameter[0] > FwColumn) {
+ FwColumn = 0;
+ } else {
+ FwColumn -= Parameter[0];
+ }
+ ControlSequence = FALSE;
+ break;
+
+ //
+ // If a ' ', could be a FNT selection command.
+ //
+
+ case ' ':
+ FontSelection = TRUE;
+ break;
+
+ //
+ // If a 'm', Select Graphics Rendition command.
+ //
+
+ case 'm':
+
+ //
+ // Select action based on each parameter.
+ //
+
+ for ( Index = 0 ; Index <= PCount ; Index++ ) {
+ switch (Parameter[Index]) {
+
+ //
+ // Attributes off.
+ //
+
+ case 0:
+ FwHighIntensity = FALSE;
+ FwUnderscored = FALSE;
+ FwReverseVideo = FALSE;
+ break;
+
+ //
+ // High Intensity.
+ //
+
+ case 1:
+ FwHighIntensity = TRUE;
+ break;
+
+ //
+ // Underscored.
+ //
+
+ case 4:
+ FwUnderscored = TRUE;
+ break;
+
+ //
+ // Reverse Video.
+ //
+
+ case 7:
+ FwReverseVideo = TRUE;
+ break;
+
+ //
+ // Font selection, not implemented yet.
+ //
+
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ break;
+
+ //
+ // Foreground Color.
+ //
+
+ case 30:
+ case 31:
+ case 32:
+ case 33:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ FwForegroundColor = Parameter[Index] - 30;
+ break;
+
+ //
+ // Background Color.
+ //
+
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ FwBackgroundColor = Parameter[Index] - 40;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ //
+ // Recompute color table.
+ //
+
+ if (FwReverseVideo) {
+ FGColor = FwBackgroundColor;
+ BGColor = FwForegroundColor + (FwHighIntensity ? 0x08 : 0 );
+ } else {
+ FGColor = FwForegroundColor + (FwHighIntensity ? 0x08 : 0 );
+ BGColor = FwBackgroundColor;
+ }
+
+ for ( Index2 = 0 ; Index2 < 16 ; Index2++ ) {
+ ColorTable[Index2] = ((Index2 & 8) ? FGColor : BGColor ) << 24 |
+ ((Index2 & 4) ? FGColor : BGColor ) << 16 |
+ ((Index2 & 2) ? FGColor : BGColor ) << 8 |
+ ((Index2 & 1) ? FGColor : BGColor ) ;
+ }
+
+ ControlSequence = FALSE;
+ FwSetAllAttributes();
+ break;
+
+ default:
+ ControlSequence = FALSE;
+ break;
+ }
+
+ //
+ // This is not a control sequence, check for escape sequence
+ //
+
+ } else {
+
+ //
+ // If escape sequence, check for control sequence, otherwise
+ // process single character.
+ //
+
+ if (EscapeSequence) {
+ //
+ // Check for '[', means control sequence, any other following
+ // character is ignored.
+ //
+
+ if (*String == '[') {
+
+ ControlSequence = TRUE;
+
+ //
+ // Initialize first parameter.
+ //
+
+ PCount = 0;
+ Parameter[0] = 0;
+ }
+ EscapeSequence = FALSE;
+
+ //
+ // This is not a control or escape sequence, process single character.
+ //
+
+ } else {
+
+ //
+ // Check for special characters.
+ //
+
+ switch (*String) {
+
+ //
+ // Control sequence.
+ //
+
+ case ASCII_CSI:
+ ControlSequence = TRUE;
+
+ //
+ // Initialize first parameter.
+ //
+
+ PCount = 0;
+ Parameter[0] = 0;
+ break;
+
+ //
+ // Check for escape sequence.
+ //
+
+ case ASCII_ESC:
+ EscapeSequence = TRUE;
+ break;
+
+ //
+ // Vertical tab/Form feed Line feed.
+ //
+
+ case ASCII_LF:
+ case ASCII_VT:
+ case ASCII_FF:
+ if (FwRow == MaxRow) {
+ VenScrollVideo();
+ } else {
+ FwRow++;
+ }
+
+ break;
+
+ //
+ // Carriage return.
+ //
+
+ case ASCII_CR:
+ FwColumn = 0;
+ break;
+
+ //
+ // NUL, no action.
+ //
+
+ case ASCII_NUL:
+ break;
+
+ //
+ // Ring bell, not implemented yet.
+ //
+
+ case ASCII_BEL:
+ break;
+
+ //
+ // Backspace.
+ //
+
+ case ASCII_BS:
+ if (FwColumn != 0) {
+ FwColumn--;
+ }
+ break;
+
+ //
+ // Horizontal tab.
+ //
+
+ case ASCII_HT:
+ FwColumn = ((FwColumn / 8) + 1) * 8;
+ if (FwColumn > MaxColumn) {
+ FwColumn = MaxColumn;
+ }
+ break;
+ default:
+ FwDisplayCharacter(*String);
+ if (FwColumn < MaxColumn) {
+ FwColumn++;
+ }
+
+ break;
+ }
+ }
+ }
+ }
+ return Status;
+}
+
+ARC_STATUS
+DisplaySeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ ESUCCESS is returned.
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+ARC_STATUS
+DisplayBootInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the video control registers, and clears the
+ video screen.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the video was initialized, ESUCCESS is returned, otherwise an error
+ code is returned.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ JAZZ_VIDEO_TYPE VideoType;
+
+ //
+ // Initialize the firmware routines.
+ //
+
+ (PARC_TEST_UNICODE_CHARACTER_ROUTINE)SYSTEM_BLOCK->FirmwareVector[TestUnicodeCharacterRoutine] =
+ FwTestUnicodeCharacter;
+
+ (PARC_GET_DISPLAY_STATUS_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetDisplayStatusRoutine] =
+ FwGetDisplayStatus;
+
+
+
+ //
+ // Initialize the vendor routines that might be changed by the video prom.
+ //
+
+ (PVEN_SET_DISPLAY_ATTRIBUTES_ROUTINE)SYSTEM_BLOCK->VendorVector[SetDisplayAttributesRoutine] =
+ FwSetDisplayAttributes;
+
+ (PVEN_OUTPUT_CHARACTER_ROUTINE)SYSTEM_BLOCK->VendorVector[OutputCharacterRoutine] =
+ FwOutputCharacter;
+
+ (PVEN_SCROLL_VIDEO_ROUTINE)SYSTEM_BLOCK->VendorVector[ScrollVideoRoutine] =
+ FwScrollVideo;
+
+ //
+ // Get the monitor configuration data.
+ //
+
+ FwGetVideoData(&MonitorData);
+
+ //
+ // Try to initialize G300.
+ //
+
+ Status = ESUCCESS;
+ if (InitializeG300(&MonitorData) == ESUCCESS) {
+ IdentifierString = "Jazz G300";
+ } else {
+
+ //
+ // G300 did not initialize properly, try a video PROM.
+ //
+
+ if (InitializeVideoFromProm(&MonitorData) == ESUCCESS) {
+ } else {
+
+ //
+ // There is no valid video PROM, try for a G364 without a video
+ // PROM.
+ //
+
+ if (InitializeG364(&MonitorData) == ESUCCESS) {
+
+ //
+ // Determine which G364 video board is installed.
+ //
+
+ VideoType = READ_REGISTER_UCHAR((PUCHAR)0xe0200000);
+
+ switch (VideoType) {
+ case JazzVideoG364:
+ IdentifierString = "Jazz G364";
+ break;
+ case MipsVideoG364:
+ IdentifierString = "Mips G364";
+ break;
+ default:
+ IdentifierString = "Unknown";
+ break;
+ }
+
+ } else {
+
+ //
+ // No valid video initialization was found.
+ //
+
+ Status = EINVAL;
+ IdentifierString = "Unknown";
+ }
+ }
+ }
+
+ //
+ // Initialize static data.
+ //
+
+ ControlSequence = FALSE;
+ EscapeSequence = FALSE;
+ FontSelection = FALSE;
+ FwColumn = 0;
+ FwRow = 0;
+ FwHighIntensity = FALSE;
+ FwUnderscored = FALSE;
+ FwReverseVideo = FALSE;
+
+ //
+ // Initialize static data.
+ //
+
+ FwForegroundColor = FW_COLOR_HI_WHITE;
+ FwBackgroundColor = FW_COLOR_BLACK;
+ DisplayWidth = MonitorData.HorizontalResolution;
+ FrameSize = (DisplayWidth * MonitorData.VerticalResolution);
+
+ if (DisplayWidth >= 800) {
+ CharacterWidth = 10;
+ CharacterHeight = 20;
+ FwFont = FwFont10x20;
+ FontIncrement = (DisplayWidth - CharacterWidth) / sizeof(USHORT);
+ } else {
+ CharacterWidth = 8;
+ CharacterHeight = 12;
+ FwFont = FwFont8x12;
+ FontIncrement = (DisplayWidth - CharacterWidth) / sizeof(ULONG);
+ }
+ CharacterSize = (CharacterHeight * ((CharacterWidth+7) / 8));
+
+ ScrollLine = (DisplayWidth * CharacterHeight);
+ ScrollLength = (ScrollLine * ((MonitorData.VerticalResolution / CharacterHeight) - 1));
+ MaxRow = ((MonitorData.VerticalResolution / CharacterHeight) - 1);
+ MaxColumn = ((DisplayWidth / CharacterWidth) - 1);
+
+ //
+ // Initialize the console context value for the display output so writes
+ // to the screen will work before the console is opened.
+ //
+
+ BlFileTable[ARC_CONSOLE_OUTPUT].u.ConsoleContext.ConsoleNumber = 0;
+
+ FillVideoMemory(VIDEO_MEMORY,FrameSize,FwBackgroundColor);
+
+ //
+ // Initialize the attributes.
+ //
+
+ FwSetAllAttributes();
+
+ return Status;
+}
+
+
+
+ARC_STATUS
+InitializeG300 (
+ IN OUT PMONITOR_CONFIGURATION_DATA GlobalMonitor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the G300 video control registers, and clears the
+ video screen.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the video was initialized, ESUCCESS is returned, otherwise an error
+ code is returned.
+
+--*/
+
+{
+ ULONG ScreenUnitRate;
+ ULONG MultiplierValue;
+ ULONG HalfLineTime;
+ ULONG FrontPorch;
+ ULONG ShortDisplay;
+ ULONG BackPorch;
+ ULONG HalfSync;
+ ULONG TransferDelay;
+ ULONG DmaDisplay;
+ ULONG DataLong;
+ ULONG i;
+ PG300_VIDEO_REGISTERS VideoControl = VIDEO_CONTROL;
+ PCURSOR_REGISTERS CursorControl = CURSOR_CONTROL;
+ PMONITOR_CONFIGURATION_DATA CurrentMonitor;
+ BOOLEAN UpdateMonitor;
+
+ CurrentMonitor = GlobalMonitor;
+ UpdateMonitor = FALSE;
+
+ //
+ // Check to see if the Monitor parameters are valid.
+ //
+
+ do {
+
+ //
+ // Determine the desired screen unit rate, in picoseconds (a screen unit is
+ // four pixels).
+ //
+
+ if ((CurrentMonitor->HorizontalDisplayTime != 0) && (CurrentMonitor->HorizontalResolution != 0)) {
+ ScreenUnitRate = (CurrentMonitor->HorizontalDisplayTime * 1000) * 4 / CurrentMonitor->HorizontalResolution;
+ } else {
+ continue;
+ }
+
+ if (ScreenUnitRate == 0) {
+ continue;
+ }
+
+ //
+ // Multiplier value is the oscillator period (in picoseconds) divided by
+ // the pixel rate.
+ //
+
+ MultiplierValue = 123077 / (ScreenUnitRate / 4);
+
+ if (MultiplierValue < 5 || MultiplierValue > 18) {
+ continue;
+ }
+
+ break;
+
+ //
+ // If the while is executed, the parameters are not valid. Set UpdateMonitor
+ // and point to the default parameters, which are valid. Note that the
+ // "while" will evaluate TRUE because the value of (a,b) is the value of b.
+ //
+
+ } while (CurrentMonitor = &DefaultMonitor, UpdateMonitor = TRUE);
+
+ //
+ // Initialize the G300B boot register value.
+ //
+
+ DataLong = 0;
+ ((PG300_VIDEO_BOOT)(&DataLong))->Multiplier = MultiplierValue;
+ ((PG300_VIDEO_BOOT)(&DataLong))->ClockSelect = 1;
+ WRITE_REGISTER_ULONG(&VideoControl->Boot.Long, DataLong);
+
+ //
+ // Wait a few cycles until the pll stabilizes.
+ //
+
+ FwStallExecution(200);
+
+ //
+ // Disable the G300B display controller.
+ //
+
+ DataLong = 0;
+ ((PG300_VIDEO_PARAMETERS)(&DataLong))->PlainWave = 1;
+ WRITE_REGISTER_ULONG(&VideoControl->Parameters.Long, DataLong);
+
+ //
+ // Determine if this is actually the G300 board.
+ //
+
+ WRITE_REGISTER_UCHAR((PUCHAR)0xe0200000,0);
+ if (READ_REGISTER_UCHAR((PUCHAR)0xe0200000) != JazzVideoG300) {
+ return ENODEV;
+ }
+
+ //
+ // Update the monitor parameters if necessary.
+ //
+
+ if (UpdateMonitor) {
+ GlobalMonitor->HorizontalResolution = DefaultMonitor.HorizontalResolution;
+ GlobalMonitor->HorizontalDisplayTime = DefaultMonitor.HorizontalDisplayTime;
+ GlobalMonitor->HorizontalBackPorch = DefaultMonitor.HorizontalBackPorch;
+ GlobalMonitor->HorizontalFrontPorch = DefaultMonitor.HorizontalFrontPorch;
+ GlobalMonitor->HorizontalSync = DefaultMonitor.HorizontalSync;
+ GlobalMonitor->VerticalResolution = DefaultMonitor.VerticalResolution;
+ GlobalMonitor->VerticalBackPorch = DefaultMonitor.VerticalBackPorch;
+ GlobalMonitor->VerticalFrontPorch = DefaultMonitor.VerticalFrontPorch;
+ GlobalMonitor->VerticalSync = DefaultMonitor.VerticalSync;
+ }
+
+ //
+ // Initialize the G300B operational values.
+ //
+
+ HalfSync = (CurrentMonitor->HorizontalSync * 1000) / ScreenUnitRate / 2;
+ WRITE_REGISTER_ULONG(&VideoControl->HorizonalSync.Long, HalfSync );
+
+ BackPorch = (CurrentMonitor->HorizontalBackPorch * 1000) / ScreenUnitRate;
+ WRITE_REGISTER_ULONG(&VideoControl->BackPorch.Long, BackPorch );
+
+ WRITE_REGISTER_ULONG(&VideoControl->Display.Long, CurrentMonitor->HorizontalResolution / 4);
+
+ //
+ // The LineTime needs to be an even number of units, so calculate LineTime / 2
+ // and then multiply by two to program. ShortDisplay and BroadPulse also
+ // use LineTime / 2.
+ //
+
+ HalfLineTime = (CurrentMonitor->HorizontalSync + CurrentMonitor->HorizontalFrontPorch +
+ CurrentMonitor->HorizontalBackPorch + CurrentMonitor->HorizontalDisplayTime) * 1000 /
+ ScreenUnitRate / 2;
+
+ WRITE_REGISTER_ULONG(&VideoControl->LineTime.Long, HalfLineTime * 2);
+
+ FrontPorch = (CurrentMonitor->HorizontalFrontPorch * 1000) / ScreenUnitRate;
+ ShortDisplay = HalfLineTime - ((HalfSync * 2) + BackPorch + FrontPorch);
+ WRITE_REGISTER_ULONG(&VideoControl->ShortDisplay.Long, ShortDisplay);
+
+ WRITE_REGISTER_ULONG(&VideoControl->BroadPulse.Long, HalfLineTime - FrontPorch);
+
+ WRITE_REGISTER_ULONG(&VideoControl->VerticalSync.Long, CurrentMonitor->VerticalSync * 2);
+
+ WRITE_REGISTER_ULONG(&VideoControl->VerticalBlank.Long,
+ (CurrentMonitor->VerticalFrontPorch + CurrentMonitor->VerticalBackPorch -
+ (CurrentMonitor->VerticalSync * 2)) * 2);
+
+ WRITE_REGISTER_ULONG(&VideoControl->VerticalDisplay.Long, CurrentMonitor->VerticalResolution * 2);
+
+ WRITE_REGISTER_ULONG(&VideoControl->LineStart.Long, LINE_START_VALUE);
+
+ //
+ // TransferDelay must be less than BackPorch and ShortDisplay. Note: When
+ // 50 MHz chips are everywhere, TransferDelay should have a maximum value
+ // to minimize the graphics overhead.
+ //
+
+ if (BackPorch < ShortDisplay) {
+ TransferDelay = BackPorch - 1;
+ } else {
+ TransferDelay = ShortDisplay - 1;
+ }
+
+ WRITE_REGISTER_ULONG(&VideoControl->TransferDelay.Long, TransferDelay);
+
+ //
+ // DMA display (also known as MemInit) is 1024 (the length of the VRAM
+ // shift register) minus TransferDelay.
+ //
+
+ DmaDisplay = 1024 - TransferDelay;
+ WRITE_REGISTER_ULONG(&VideoControl->DmaDisplay.Long, DmaDisplay);
+
+ WRITE_REGISTER_ULONG(&VideoControl->PixelMask.Long, G300_PIXEL_MASK_VALUE);
+
+ //
+ // Set up the color map.
+ //
+
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_BLACK],
+ G300_PALETTE_BLACK);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_RED],
+ G300_PALETTE_RED);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_GREEN],
+ G300_PALETTE_GREEN);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_YELLOW],
+ G300_PALETTE_YELLOW);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_BLUE],
+ G300_PALETTE_BLUE);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_MAGENTA],
+ G300_PALETTE_MAGENTA);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_CYAN],
+ G300_PALETTE_CYAN);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_WHITE],
+ G300_PALETTE_WHITE);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_BLACK],
+ G300_PALETTE_HI_BLACK);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_RED],
+ G300_PALETTE_HI_RED);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_GREEN],
+ G300_PALETTE_HI_GREEN);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_YELLOW],
+ G300_PALETTE_HI_YELLOW);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_BLUE],
+ G300_PALETTE_HI_BLUE);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_MAGENTA],
+ G300_PALETTE_HI_MAGENTA);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_CYAN],
+ G300_PALETTE_HI_CYAN);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_WHITE],
+ G300_PALETTE_HI_WHITE);
+
+ //
+ // Initialize the G300B control parameters.
+ //
+
+ DataLong = 0;
+ ((PG300_VIDEO_PARAMETERS)(&DataLong))->EnableVideo = 1;
+ ((PG300_VIDEO_PARAMETERS)(&DataLong))->PlainWave = 1;
+ ((PG300_VIDEO_PARAMETERS)(&DataLong))->SeparateSync = 1;
+ ((PG300_VIDEO_PARAMETERS)(&DataLong))->DelaySync = G300_DELAY_SYNC_CYCLES;
+ ((PG300_VIDEO_PARAMETERS)(&DataLong))->BlankOutput = 1;
+ ((PG300_VIDEO_PARAMETERS)(&DataLong))->BitsPerPixel = EIGHT_BITS_PER_PIXEL;
+ ((PG300_VIDEO_PARAMETERS)(&DataLong))->AddressStep = 2;
+ WRITE_REGISTER_ULONG(&VideoControl->Parameters.Long, DataLong);
+
+ //
+ // Disable the cursor parts.
+ //
+
+ WRITE_REGISTER_USHORT(&CursorControl->AddressPointer0.Short,0);
+ WRITE_REGISTER_USHORT(&CursorControl->AddressPointer1.Short,0);
+
+ //
+ // Clear cursor control.
+ //
+
+ for (i=0;i<13;i++) {
+ WRITE_REGISTER_USHORT(&CursorControl->CursorControl.Short,0);
+ }
+
+ //
+ // Clear Cursor Memory
+ //
+
+ for (i=0;i<512;i++) {
+ WRITE_REGISTER_USHORT(&CursorControl->CursorMemory.Short,0);
+ }
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+InitializeG364 (
+ IN OUT PMONITOR_CONFIGURATION_DATA GlobalMonitor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the G364 video control registers, and clears the
+ video screen.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the video was initialized, ESUCCESS is returned, otherwise an error
+ code is returned.
+
+--*/
+
+{
+ ULONG ScreenUnitRate;
+ ULONG MultiplierValue;
+ ULONG HalfLineTime;
+ ULONG FrontPorch;
+ ULONG BackPorch;
+ ULONG HalfSync;
+ ULONG TransferDelay;
+ ULONG DmaDisplay;
+ ULONG DataLong;
+ PG364_VIDEO_REGISTERS VideoControl = (PG364_VIDEO_REGISTERS) (VIDEO_CONTROL_VIRTUAL_BASE + 0x80000);
+ PMONITOR_CONFIGURATION_DATA CurrentMonitor;
+ BOOLEAN UpdateMonitor;
+ JAZZ_VIDEO_TYPE FwVideoType;
+
+ //
+ // Determine if this is actually the G364 board.
+ //
+
+ if (READ_REGISTER_UCHAR((PUCHAR)(VIDEO_CONTROL_VIRTUAL_BASE)) == JazzVideoG364) {
+ FwVideoType = JazzVideoG364;
+ } else {
+ FwVideoType = MipsVideoG364;
+ }
+
+ //
+ // Reset the whole video board.
+ //
+
+ WRITE_REGISTER_UCHAR((PUCHAR)(VIDEO_CONTROL_VIRTUAL_BASE+0x180000),0);
+
+ CurrentMonitor = GlobalMonitor;
+ UpdateMonitor = FALSE;
+
+ //
+ // Check to see if the Monitor parameters are valid.
+ //
+
+ do {
+
+ //
+ // Determine the desired screen unit rate, in picoseconds (a screen unit is
+ // four pixels).
+ //
+
+ if ((CurrentMonitor->HorizontalDisplayTime != 0) && (CurrentMonitor->HorizontalResolution != 0)) {
+ ScreenUnitRate = (CurrentMonitor->HorizontalDisplayTime * 1000) * 4 / CurrentMonitor->HorizontalResolution;
+ } else {
+ continue;
+ }
+
+ if (ScreenUnitRate == 0) {
+ continue;
+ }
+
+ //
+ // Multiplier value is the oscillator period (in picoseconds) divided by
+ // the pixel rate.
+ //
+
+ if (FwVideoType == JazzVideoG364) {
+ MultiplierValue = 123077 / (ScreenUnitRate / 4);
+ if (MultiplierValue < 5 || MultiplierValue > 18) {
+ continue;
+ }
+ } else {
+ MultiplierValue = 200000 / (ScreenUnitRate / 4);
+ if (MultiplierValue < 5 || MultiplierValue > 29) {
+ continue;
+ }
+ }
+
+
+ break;
+
+ //
+ // If the while is executed, the parameters are not valid. Set UpdateMonitor
+ // and point to the default parameters, which are valid. Note that the
+ // "while" will evaluate TRUE because the value of (a,b) is the value of b.
+ //
+
+ } while (CurrentMonitor = &DefaultMonitor, UpdateMonitor = TRUE);
+
+ //
+ // Update the monitor parameters if necessary.
+ //
+
+ if (UpdateMonitor) {
+ GlobalMonitor->HorizontalResolution = DefaultMonitor.HorizontalResolution;
+ GlobalMonitor->HorizontalDisplayTime = DefaultMonitor.HorizontalDisplayTime;
+ GlobalMonitor->HorizontalBackPorch = DefaultMonitor.HorizontalBackPorch;
+ GlobalMonitor->HorizontalFrontPorch = DefaultMonitor.HorizontalFrontPorch;
+ GlobalMonitor->HorizontalSync = DefaultMonitor.HorizontalSync;
+ GlobalMonitor->VerticalResolution = DefaultMonitor.VerticalResolution;
+ GlobalMonitor->VerticalBackPorch = DefaultMonitor.VerticalBackPorch;
+ GlobalMonitor->VerticalFrontPorch = DefaultMonitor.VerticalFrontPorch;
+ GlobalMonitor->VerticalSync = DefaultMonitor.VerticalSync;
+ }
+
+ //
+ // write multiplier value
+ //
+
+ DataLong = 0;
+ ((PG364_VIDEO_BOOT)(&DataLong))->ClockSelect = 1;
+ ((PG364_VIDEO_BOOT)(&DataLong))->MicroPort64Bits = 1;
+ ((PG364_VIDEO_BOOT)(&DataLong))->Multiplier = MultiplierValue;
+ WRITE_REGISTER_ULONG(&VideoControl->Boot.Long, DataLong);
+
+ //
+ // Initialize the G364 control parameters.
+ //
+
+ DataLong = 0;
+
+ //
+ // If vertical front porch is 1, use tesselated sync, otherwise use normal sync.
+ //
+
+ if (CurrentMonitor->VerticalFrontPorch > 1) {
+ ((PG364_VIDEO_PARAMETERS)(&DataLong))->PlainSync = 1;
+ }
+ ((PG364_VIDEO_PARAMETERS)(&DataLong))->DelaySync = G364_DELAY_SYNC_CYCLES;
+ ((PG364_VIDEO_PARAMETERS)(&DataLong))->BitsPerPixel = EIGHT_BITS_PER_PIXEL;
+ ((PG364_VIDEO_PARAMETERS)(&DataLong))->AddressStep = G364_ADDRESS_STEP_INCREMENT;
+ ((PG364_VIDEO_PARAMETERS)(&DataLong))->DisableCursor = 1;
+ WRITE_REGISTER_ULONG(&VideoControl->Parameters.Long, DataLong);
+
+ //
+ // Initialize the G364 operational values.
+ //
+
+ HalfSync = (CurrentMonitor->HorizontalSync * 1000) / ScreenUnitRate / 2;
+ WRITE_REGISTER_ULONG(&VideoControl->HorizontalSync.Long, HalfSync );
+
+ BackPorch = (CurrentMonitor->HorizontalBackPorch * 1000) / ScreenUnitRate;
+ WRITE_REGISTER_ULONG(&VideoControl->BackPorch.Long, BackPorch );
+
+ WRITE_REGISTER_ULONG(&VideoControl->Display.Long, CurrentMonitor->HorizontalResolution / 4);
+
+ //
+ // The LineTime needs to be an even number of units, so calculate LineTime / 2
+ // and then multiply by two to program. ShortDisplay and BroadPulse also
+ // use LineTime / 2.
+ //
+
+ HalfLineTime = (CurrentMonitor->HorizontalSync + CurrentMonitor->HorizontalFrontPorch +
+ CurrentMonitor->HorizontalBackPorch + CurrentMonitor->HorizontalDisplayTime) * 1000 /
+ ScreenUnitRate / 2;
+
+ WRITE_REGISTER_ULONG(&VideoControl->LineTime.Long, HalfLineTime * 2);
+
+ FrontPorch = (CurrentMonitor->HorizontalFrontPorch * 1000) / ScreenUnitRate;
+ WRITE_REGISTER_ULONG(&VideoControl->ShortDisplay.Long,
+ HalfLineTime - ((HalfSync * 2) + BackPorch + FrontPorch));
+
+ WRITE_REGISTER_ULONG(&VideoControl->BroadPulse.Long, HalfLineTime - FrontPorch);
+
+ WRITE_REGISTER_ULONG(&VideoControl->VerticalSync.Long, CurrentMonitor->VerticalSync * 2);
+ WRITE_REGISTER_ULONG(&VideoControl->VerticalPreEqualize.Long, CurrentMonitor->VerticalFrontPorch * 2);
+ WRITE_REGISTER_ULONG(&VideoControl->VerticalPostEqualize.Long, 1 * 2);
+
+ WRITE_REGISTER_ULONG(&VideoControl->VerticalBlank.Long,
+ (CurrentMonitor->VerticalBackPorch - 1) * 2);
+
+ WRITE_REGISTER_ULONG(&VideoControl->VerticalDisplay.Long, CurrentMonitor->VerticalResolution * 2);
+
+ WRITE_REGISTER_ULONG(&VideoControl->LineStart.Long, LINE_START_VALUE);
+
+ //
+ // Transfer delay is 1.65 microseconds expressed in screen units, plus 1.
+ //
+
+ TransferDelay = (1650000 / ScreenUnitRate) + 1;
+
+ if (BackPorch <= TransferDelay) {
+ TransferDelay = BackPorch - 1;
+ }
+ WRITE_REGISTER_ULONG(&VideoControl->TransferDelay.Long, TransferDelay);
+
+ //
+ // DMA display (also known as MemInit) is 1024 (the length of the VRAM
+ // shift register) minus TransferDelay.
+ //
+
+ DmaDisplay = 1024 - TransferDelay;
+ WRITE_REGISTER_ULONG(&VideoControl->DmaDisplay.Long, DmaDisplay);
+
+ WRITE_REGISTER_ULONG(&VideoControl->PixelMask.Long, G364_PIXEL_MASK_VALUE);
+
+ //
+ // Set up the color map.
+ //
+
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_BLACK],
+ G364_PALETTE_BLACK);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_RED],
+ G364_PALETTE_RED);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_GREEN],
+ G364_PALETTE_GREEN);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_YELLOW],
+ G364_PALETTE_YELLOW);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_BLUE],
+ G364_PALETTE_BLUE);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_MAGENTA],
+ G364_PALETTE_MAGENTA);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_CYAN],
+ G364_PALETTE_CYAN);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_WHITE],
+ G364_PALETTE_WHITE);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_BLACK],
+ G364_PALETTE_HI_BLACK);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_RED],
+ G364_PALETTE_HI_RED);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_GREEN],
+ G364_PALETTE_HI_GREEN);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_YELLOW],
+ G364_PALETTE_HI_YELLOW);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_BLUE],
+ G364_PALETTE_HI_BLUE);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_MAGENTA],
+ G364_PALETTE_HI_MAGENTA);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_CYAN],
+ G364_PALETTE_HI_CYAN);
+ WRITE_REGISTER_ULONG(&VideoControl->ColorMapData[FW_COLOR_HI_WHITE],
+ G364_PALETTE_HI_WHITE);
+
+ //
+ // Enable the G364
+ //
+
+ ((PG364_VIDEO_PARAMETERS)(&DataLong))->EnableVideo = 1;
+ WRITE_REGISTER_ULONG(&VideoControl->Parameters.Long, DataLong);
+
+ //
+ // G364 C04 bug # 6:
+ // "The action of starting the VTG may cause the TopOfScreen register to become corrupted"
+ //
+
+ WRITE_REGISTER_ULONG(&VideoControl->TopOfScreen, 0);
+
+ return ESUCCESS;
+}
+
+
+
+
+VOID
+DisplayInitialize (
+ IN OUT PDRIVER_LOOKUP_ENTRY LookupTableEntry,
+ IN ULONG Entries
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the video entry in the driver lookup table.
+
+Arguments:
+
+ LookupTableEntry - Supplies a pointer to the first free location in the
+ driver lookup table.
+
+ Entries - Supplies the number of free entries in the driver lookup table.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Initialize the driver lookup table, and increment the pointer.
+ //
+
+ LookupTableEntry->DevicePath = DisplayDevicePath;
+ LookupTableEntry->DispatchTable = &DisplayEntryTable;
+
+ return;
+}
+
+VOID
+FwDisplayCharacter (
+ IN UCHAR Character
+ )
+
+/*++
+
+Routine Description:
+
+ This routine displays a single character on the video screen at the current
+ cursor location with the current color and video attributes. It finds the
+ font bitmap and calls VenOutputCharacter to actually do the display.
+
+Arguments:
+
+ Character - Supplies the character to be displayed.
+
+ LineDrawCharacter - If true the current character is a line drawing character.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ VenOutputCharacter((PVOID)&FwFont[(Character - 1) * CharacterSize],
+ FwRow,
+ FwColumn);
+ return;
+}
+
+VOID
+FwOutputCharacter (
+ IN PVOID Character,
+ IN ULONG Row,
+ IN ULONG Column
+ )
+
+/*++
+
+Routine Description:
+
+ This routine displays a single character on the video screen at the current
+ cursor location with the current color and video attributes. It assumes
+ the character locations are word aligned.
+
+Arguments:
+
+ Character - Supplies the character to be displayed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR DataByte;
+ PULONG Destination;
+ PUSHORT ShortDestination;
+ ULONG I;
+
+ Destination = (PULONG)(VIDEO_MEMORY +
+ (Row * ScrollLine) + (Column * CharacterWidth));
+
+ if (CharacterWidth == 10) {
+ ShortDestination = (PUSHORT)Destination;
+
+ for (I = 0; I < CharacterHeight; I += 1) {
+ DataByte = *((PUCHAR)Character)++;
+ *ShortDestination++ = (USHORT)ColorTable[DataByte & 0x03];
+ *ShortDestination++ = (USHORT)ColorTable[(DataByte >> 2) & 0x03];
+ *ShortDestination++ = (USHORT)ColorTable[(DataByte >> 4) & 0x03];
+ *ShortDestination++ = (USHORT)ColorTable[(DataByte >> 6) & 0x03];
+ DataByte = *((PUCHAR)Character)++;
+ *ShortDestination++ = (USHORT)ColorTable[DataByte & 0x03];
+ ShortDestination += FontIncrement;
+
+ }
+ } else {
+ for (I = 0; I < CharacterHeight; I += 1) {
+ DataByte = *((PUCHAR)Character)++;
+ *Destination++ = ColorTable[DataByte & 0x0f];
+ *Destination++ = ColorTable[DataByte >> 4];
+ Destination += FontIncrement;
+ }
+ }
+
+ return;
+}
+
+VOID
+FwScrollVideo (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scrolls the display up one line.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG SaveColumn;
+
+ //
+ // Call the assembly language routine to do the actual scroll.
+ //
+
+ FwVideoScroll((PVOID)(VIDEO_MEMORY + ScrollLine),
+ (PVOID)(VIDEO_MEMORY + ScrollLine + ScrollLength),
+ (PVOID)VIDEO_MEMORY);
+
+ SaveColumn = FwColumn;
+
+ //
+ // Set the bottom line to be the background color.
+ //
+
+ for (FwColumn = MaxColumn ;
+ FwColumn >= 0 ;
+ FwColumn-- ) {
+ FwDisplayCharacter(' ');
+ }
+
+ FwColumn = SaveColumn;
+ return;
+}
+
+VOID
+FwSetDisplayAttributes (
+ IN ULONG ForegroundColor,
+ IN ULONG BackgroundColor,
+ IN BOOLEAN HighIntensity,
+ IN BOOLEAN Underscored,
+ IN BOOLEAN ReverseVideo,
+ IN ULONG CharacterWidth,
+ IN ULONG CharacterHeight
+ )
+
+/*++
+
+Routine Description:
+
+ This is a dummy routine that can be replaced by the video prom.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ return;
+}
+
+VOID
+FwSetAllAttributes (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls the vendor routine to set all of the screen attributes.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ VenSetDisplayAttributes(FwForegroundColor,
+ FwBackgroundColor,
+ FwHighIntensity,
+ FwUnderscored,
+ FwReverseVideo,
+ CharacterWidth,
+ CharacterHeight
+ );
+
+ return;
+}
+
+ARC_STATUS
+FwTestUnicodeCharacter (
+ IN ULONG FileId,
+ IN WCHAR UnicodeCharacter
+ )
+/*++
+
+Routine Description:
+
+ This routine checks for the existence of a valid glyph corresponding to
+ UnicodeCharacter.
+
+Arguments:
+
+ FileId - Supplies the FileId of the output device.
+
+ UnicodeCharacter - Supplies the UNICODE character to be tested.
+
+Return Value:
+
+ If writing UnicodeCharacter to the device specified by FileId would
+ result in the display of a valid glyph on the output device, then
+ ESUCCESS is returned. If the device does not support the character,
+ the EINVAL is returned.
+
+--*/
+{
+ if (((UnicodeCharacter >= ' ') && (UnicodeCharacter <= '~')) ||
+ ((UnicodeCharacter >= 0x2500) && (UnicodeCharacter <= 0x257f))) {
+ return(ESUCCESS);
+ } else {
+ return(EINVAL);
+ }
+}
+
+
+PARC_DISPLAY_STATUS
+FwGetDisplayStatus (
+ IN ULONG FileId
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ DisplayStatus.CursorXPosition = FwColumn + 1;
+ DisplayStatus.CursorYPosition = FwRow + 1;
+ DisplayStatus.CursorMaxXPosition = MaxColumn + 1;
+ DisplayStatus.CursorMaxYPosition = MaxRow + 1;
+ DisplayStatus.ForegroundColor = FwForegroundColor;
+ DisplayStatus.BackgroundColor = FwBackgroundColor;
+ DisplayStatus.HighIntensity = FwHighIntensity;
+ DisplayStatus.Underscored = FwUnderscored;
+ DisplayStatus.ReverseVideo = FwReverseVideo;
+
+ return(&DisplayStatus);
+}
diff --git a/private/ntos/fw/mips/jxenvir.c b/private/ntos/fw/mips/jxenvir.c
new file mode 100644
index 000000000..50738f922
--- /dev/null
+++ b/private/ntos/fw/mips/jxenvir.c
@@ -0,0 +1,502 @@
+#if defined(JAZZ)
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxenvir.c
+
+Abstract:
+
+ This module implements the ARC firmware Environment Variable functions as
+ described in the Advanced Risc Computing Specification (Revision 1.00),
+ section 3.3.3.11, for a MIPS R3000 or R4000 Jazz system.
+
+Author:
+
+ David M. Robinson (davidro) 13-June-1991
+
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+//
+// Static data.
+//
+
+UCHAR OutputString[MAXIMUM_ENVIRONMENT_VALUE];
+PCHAR VolatileEnvironment;
+
+//
+// Routine prototypes.
+//
+
+VOID
+FwEnvironmentSetChecksum (
+ VOID
+ );
+
+ARC_STATUS
+FwFindEnvironmentVariable (
+ IN PCHAR Variable,
+ OUT PULONG VariableIndex,
+ OUT PULONG ValueIndex
+ );
+
+
+VOID
+FwEnvironmentInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the environment routine addresses.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Allocate enough memory to load the environment for loaded programs.
+ //
+
+ VolatileEnvironment = FwAllocatePool(LENGTH_OF_ENVIRONMENT);
+
+ //
+ // Initialize the environment routine addresses in the system
+ // parameter block.
+ //
+
+ (PARC_GET_ENVIRONMENT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetEnvironmentRoutine] =
+ FwGetEnvironmentVariable;
+ (PARC_SET_ENVIRONMENT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[SetEnvironmentRoutine] =
+ FwSetEnvironmentVariable;
+
+ return;
+}
+
+
+VOID
+FwEnvironmentSetChecksum (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the environment area checksum.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUCHAR NvChars;
+ PNV_CONFIGURATION NvConfiguration;
+ ULONG Index;
+ ULONG Checksum;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // Form checksum from NVRAM data.
+ //
+
+ Checksum = 0;
+ NvChars = (PUCHAR)&NvConfiguration->Environment[0];
+
+ for ( Index = 0 ;
+ Index < LENGTH_OF_ENVIRONMENT;
+ Index++ ) {
+ Checksum += READ_REGISTER_UCHAR( NvChars++ );
+ }
+
+ //
+ // Write environment checksum.
+ //
+
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum2[0],
+ (UCHAR)(Checksum & 0xFF));
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum2[1],
+ (UCHAR)((Checksum >> 8) & 0xFF));
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum2[2],
+ (UCHAR)((Checksum >> 16) & 0xFF));
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Checksum2[3],
+ (UCHAR)(Checksum >> 24));
+}
+
+
+PCHAR
+FwGetEnvironmentVariable (
+ IN PCHAR Variable
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches (not case sensitive) the non-volatile ram for
+ Variable, and if found returns a pointer to a zero terminated string that
+ contains the value, otherwise a NULL pointer is returned.
+
+
+Arguments:
+
+ Variable - Supplies a zero terminated string containing an environment
+ variable.
+
+Return Value:
+
+ If successful, returns a zero terminated string that is the value of
+ Variable, otherwise NULL is returned.
+
+--*/
+
+{
+ PNV_CONFIGURATION NvConfiguration;
+ ULONG VariableIndex;
+ ULONG ValueIndex;
+ ULONG Outdex;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // If checksum is wrong, or the variable can't be found, return NULL.
+ //
+
+ if ((FwEnvironmentCheckChecksum() != ESUCCESS) ||
+ (FwFindEnvironmentVariable(Variable, &VariableIndex, &ValueIndex) != ESUCCESS)) {
+ return NULL;
+ }
+
+ //
+ // Copy value to an output string, break on zero terminator or string max.
+ //
+
+ for ( Outdex = 0 ; Outdex < (MAXIMUM_ENVIRONMENT_VALUE - 1) ; Outdex++ ) {
+ if (NvConfiguration->Environment[ValueIndex] == 0) {
+ break;
+ }
+ OutputString[Outdex] =
+ READ_REGISTER_UCHAR( &NvConfiguration->Environment[ValueIndex++] );
+ }
+
+ //
+ // Zero terminate string, and return.
+ //
+
+ OutputString[Outdex] = 0;
+ return OutputString;
+}
+
+
+ARC_STATUS
+FwSetEnvironmentVariable (
+ IN PCHAR Variable,
+ IN PCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets Variable (not case sensitive) to Value.
+
+Arguments:
+
+ Variable - Supplies a zero terminated string containing an environment
+ variable.
+
+ Value - Supplies a zero terminated string containing an environment
+ variable value.
+
+Return Value:
+
+ Returns ESUCCESS if the set completed successfully, otherwise one of
+ the following error codes is returned.
+
+ ENOSPC No space in NVRAM for set operation.
+
+ EIO Invalid Checksum.
+
+--*/
+
+{
+ PNV_CONFIGURATION NvConfiguration;
+ ULONG VariableIndex;
+ ULONG ValueIndex;
+ ULONG TopOfEnvironment;
+ PCHAR String;
+ ULONG Count;
+ CHAR Char;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // If checksum is wrong, return EIO;
+ //
+
+ if (FwEnvironmentCheckChecksum() != ESUCCESS) {
+ return EIO;
+ }
+
+ //
+ // Determine the top of the environment space by looking for the first
+ // non-null character from the top.
+ //
+
+ TopOfEnvironment = LENGTH_OF_ENVIRONMENT - 1;
+ while (READ_REGISTER_UCHAR( &NvConfiguration->Environment[--TopOfEnvironment]) == 0) {
+ if (TopOfEnvironment == 0) {
+ break;
+ }
+ }
+
+ //
+ // Adjust TopOfEnvironment to the first new character, unless environment
+ // space is empty.
+ //
+
+ if (TopOfEnvironment != 0) {
+ TopOfEnvironment += 2;
+ }
+
+ //
+ // Check to see if the variable already has a value.
+ //
+
+ Count = LENGTH_OF_ENVIRONMENT - TopOfEnvironment;
+
+ if (FwFindEnvironmentVariable(Variable, &VariableIndex, &ValueIndex) == ESUCCESS) {
+
+ //
+ // Count free space, starting with the free area at the top and adding
+ // the old variable value.
+ //
+
+ for ( String = &NvConfiguration->Environment[ValueIndex] ;
+ READ_REGISTER_UCHAR( String ) != 0 ;
+ String++ ) {
+ Count++;
+ }
+
+ //
+ // Determine if free area is large enough to handle new value, if not
+ // return error.
+ //
+
+ for ( String = Value ; *String != 0 ; String++ ) {
+ if (Count-- == 0) {
+ return ENOSPC;
+ }
+ }
+
+ //
+ // Move ValueIndex to the end of the value and compress strings.
+ //
+
+ while(READ_REGISTER_UCHAR( &NvConfiguration->Environment[ValueIndex++]) != 0) {
+ }
+
+ while (ValueIndex < TopOfEnvironment ) {
+ Char = READ_REGISTER_UCHAR( &NvConfiguration->Environment[ValueIndex++] );
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Environment[VariableIndex++], Char);
+ }
+
+ //
+ // Adjust new top of environment.
+ //
+
+ TopOfEnvironment = VariableIndex;
+
+ //
+ // Zero to the end.
+ //
+
+ while (VariableIndex < LENGTH_OF_ENVIRONMENT) {
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Environment[VariableIndex++],
+ 0);
+ }
+
+ //
+ // Variable is new.
+ //
+
+ } else {
+
+ //
+ // Determine if free area is large enough to handle new value, if not
+ // return error.
+ //
+
+ for ( String = Value ; *String != 0 ; String++ ) {
+ if (Count-- == 0) {
+ return ENOSPC;
+ }
+ }
+
+ }
+
+ //
+ // If Value is not zero, write new variable and value.
+ //
+
+ if (*Value != 0) {
+
+ //
+ // Write new variable, converting to upper case.
+ //
+
+ while (*Variable != 0) {
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Environment[TopOfEnvironment++],
+ ((*Variable >= 'a') &&
+ (*Variable <= 'z') ?
+ (*Variable - 'a' + 'A') : *Variable));
+ Variable++;
+ }
+
+ //
+ // Write equal sign.
+ //
+
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Environment[TopOfEnvironment++], '=');
+
+ //
+ // Write new value.
+ //
+
+ while (*Value != 0) {
+ WRITE_REGISTER_UCHAR( &NvConfiguration->Environment[TopOfEnvironment++],
+ *Value++);
+ }
+ }
+
+ //
+ // Set checksum.
+ //
+
+ FwEnvironmentSetChecksum();
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+FwFindEnvironmentVariable (
+ IN PCHAR Variable,
+ OUT PULONG VariableIndex,
+ OUT PULONG ValueIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches (not case sensitive) the non-volatile ram for
+ Variable.
+
+
+Arguments:
+
+ Variable - Supplies a zero terminated string containing an environment
+ variable.
+
+Return Value:
+
+ If successful, returns ESUCCESS, otherwise returns ENOENT.
+
+--*/
+
+{
+ PNV_CONFIGURATION NvConfiguration;
+ PUCHAR String;
+ PUCHAR Environment;
+ ULONG Index;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // If Variable is null, return immediately.
+ //
+
+ if (*Variable == 0) {
+ return ENOENT;
+ }
+
+ Environment = NvConfiguration->Environment;
+ Index = 0;
+
+ while (TRUE) {
+
+ //
+ // Set string to beginning of Variable.
+ //
+
+ String = Variable;
+ *VariableIndex = Index;
+
+ //
+ // Search until the end of NVRAM.
+ //
+
+ while ( Index < LENGTH_OF_ENVIRONMENT ) {
+
+ //
+ // Convert to uppercase and break if mismatch.
+ //
+
+ if ( READ_REGISTER_UCHAR( &Environment[Index] ) !=
+ ((*String >= 'a') &&
+ (*String <= 'z') ?
+ (*String - 'a' + 'A') : *String) ) {
+ break;
+ }
+
+ String++;
+ Index++;
+ }
+
+ //
+ // Check to see if we're at the end of the string and the variable,
+ // which means a match.
+ //
+
+ if ((*String == 0) && (READ_REGISTER_UCHAR( &Environment[Index] ) == '=')) {
+ *ValueIndex = ++Index;
+ return ESUCCESS;
+ }
+
+ //
+ // Move index to the start of the next variable.
+ //
+
+ while (READ_REGISTER_UCHAR( &Environment[Index++] ) != 0) {
+ if (Index >= LENGTH_OF_ENVIRONMENT) {
+ return ENOENT;
+ }
+ }
+ }
+}
+#endif
+
diff --git a/private/ntos/fw/mips/jxfboot.c b/private/ntos/fw/mips/jxfboot.c
new file mode 100644
index 000000000..ac34c40df
--- /dev/null
+++ b/private/ntos/fw/mips/jxfboot.c
@@ -0,0 +1,2057 @@
+#if defined(JAZZ) && !defined(DUO)
+
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ jxfboot.c
+
+Abstract:
+
+ This module implements the floppy disk boot driver for the Jazz system.
+
+Author:
+
+ Darryl E. Havens (darrylh) 28-Aug-1989
+
+Environment:
+
+ Kernel mode only, raised IRQL, generally self-contained.
+
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#include "jazzprom.h"
+#include "jazzint.h"
+#include "ntdddisk.h"
+#include "flo_data.h"
+#include "fwstring.h"
+
+
+//
+// Define local static data.
+//
+
+UCHAR DebugByte[8];
+ULONG MotorStatus;
+PDRIVE_MEDIA_CONSTANTS CurrentDriveMediaConstants;
+
+//
+// Define timeout constants.
+//
+
+#define MICROSECONDS_10 10
+#define MICROSECONDS_250 250
+#define MILLISECONDS_15 (15 * 1000)
+#define MILLISECONDS_500 (500 * 1000)
+#define SECONDS_2 (2 * 1000 * 1000)
+#define FW_FLOPPY_TIMEOUT 2
+
+//
+// Define the number of times an operation is retried before it is considered
+// to be a hard error.
+//
+
+#define RETRY_COUNT 8
+
+//
+// Define the MINIMUM macro.
+//
+
+#define MINIMUM( x, y ) ( x <= y ? x : y )
+
+//
+// Define floppy device register structure.
+//
+
+typedef struct _FLOPPY_REGISTERS {
+ UCHAR StatusRegisterA;
+ UCHAR StatusRegisterB;
+ UCHAR DigitalOutput;
+ UCHAR Reserved1;
+ union {
+ UCHAR MainStatus;
+ UCHAR DataRateSelect;
+ } MsrDsr;
+ UCHAR Fifo;
+ UCHAR Reserved2;
+ union {
+ UCHAR DigitalInput;
+ UCHAR ConfigurationControl;
+ } DirCcr;
+} FLOPPY_REGISTERS, *PFLOPPY_REGISTERS;
+
+//
+// Define pointer to the floppy registers.
+//
+
+#define FLOPPY_CONTROL ((volatile PFLOPPY_REGISTERS)FLOPPY_VIRTUAL_BASE)
+
+PUCHAR Floppy0Path = "multi(0)disk(0)fdisk(0)";
+PUCHAR Floppy1Path = "multi(0)disk(0)fdisk(1)";
+
+
+ARC_STATUS
+FloppyClose (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+FloppyMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ );
+
+ARC_STATUS
+FloppyOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ OUT PULONG FileId
+ );
+
+ARC_STATUS
+FloppyRead (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+FloppyGetReadStatus (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+FloppySeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+FloppyWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+FloppyGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Finfo
+ );
+
+ARC_STATUS
+FloppyBootIO(
+ IN PMDL MdlAddress,
+ IN ULONG StartingBlock,
+ IN ULONG FileId,
+ IN BOOLEAN ReadWrite
+ );
+
+VOID
+ClearFloppyFifo (
+ IN VOID
+ );
+
+ULONG
+ReadFloppyFifo (
+ IN PUCHAR Buffer
+ );
+
+VOID
+WriteFloppyFifo(
+ IN PUCHAR Buffer,
+ IN ULONG Size
+ );
+
+//
+// Declare and Initialize the floppy disk device entry table.
+//
+
+BL_DEVICE_ENTRY_TABLE FloppyEntryTable = {
+ FloppyClose,
+ FloppyMount,
+ FloppyOpen,
+ FloppyRead,
+ FloppyGetReadStatus,
+ FloppySeek,
+ FloppyWrite,
+ FloppyGetFileInformation,
+ (PARC_SET_FILE_INFO_ROUTINE)NULL
+ };
+
+//
+// Define prototypes for all routines used by this module.
+//
+
+
+ARC_STATUS
+FloppyBootClose(
+ );
+
+BOOLEAN
+Recalibrate (
+ UCHAR DriveNumber
+ );
+
+ VOID
+FloppyBootSetup(
+ VOID
+ );
+
+UCHAR
+ReceiveByte (
+ );
+
+BOOLEAN
+SendByte(
+ IN UCHAR SourceByte
+ );
+
+ARC_STATUS
+FloppyDetermineMediaType(
+ IN OUT PFLOPPY_CONTEXT FloppyContext
+ );
+
+ARC_STATUS
+FloppyDatarateSpecifyConfigure(
+ IN DRIVE_MEDIA_TYPE DriveMediaType,
+ IN UCHAR DriveNumber
+ );
+
+
+ARC_STATUS
+FloppyClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes the file table entry specified by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+Return Value:
+
+ ESUCCESS is returned
+
+--*/
+
+{
+ FloppyBootClose();
+ BlFileTable[FileId].Flags.Open = 0;
+ return ESUCCESS;
+}
+
+ARC_STATUS
+FloppyMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+ARC_STATUS
+FloppyOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ IN OUT PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PCONFIGURATION_COMPONENT FloppyComponent, FloppyController;
+ UCHAR Data[sizeof(CM_PARTIAL_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 8 +
+ sizeof(CM_FLOPPY_DEVICE_DATA)];
+ PCM_PARTIAL_RESOURCE_LIST List = (PCM_PARTIAL_RESOURCE_LIST)Data;
+ PCM_FLOPPY_DEVICE_DATA FloppyData;
+ ULONG DriveNumber;
+ ULONG Index;
+ ARC_STATUS ArcStatus;
+ CHAR TempBuffer[SECTOR_SIZE + 32];
+ PCHAR TempPointer;
+ ULONG Count;
+ UCHAR mediaDescriptor;
+ MEDIA_TYPE mediaType;
+ DRIVE_MEDIA_TYPE driveMediaType;
+ ULONG DriveType;
+ ULONG ConfigDriveType;
+
+ //
+ // Get the drive number from the pathname.
+ //
+
+ if (FwGetPathMnemonicKey(OpenPath, "fdisk", &DriveNumber)) {
+ return ENODEV;
+ }
+
+ //
+ // Default to 1.44MB floppy
+ //
+
+ BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1440;
+
+ //
+ // Look in the configuration database for the floppy device data to
+ // determine the size of the floppy drive.
+ //
+
+ FloppyComponent = FwGetComponent(OpenPath);
+ if ((FloppyComponent != NULL) &&
+ (FloppyComponent->Type == FloppyDiskPeripheral)) {
+ if (FwGetConfigurationData(List, FloppyComponent) == ESUCCESS) {
+ FloppyData = (PCM_FLOPPY_DEVICE_DATA)&List->PartialDescriptors[List->Count];
+ if (strcmp(FloppyData->Size,"5.25")==0) {
+ BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1200;
+ } else {
+ if (strcmp(FloppyData->Size,"3.5")==0) {
+ if (FloppyData->MaxDensity == 2880) {
+ BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_2880;
+ } else {
+ BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1440;
+ }
+ }
+ }
+ }
+ }
+
+ ConfigDriveType = BlFileTable[*FileId].u.FloppyContext.DriveType;
+ BlFileTable[*FileId].u.FloppyContext.DiskId = DriveNumber;
+ BlFileTable[*FileId].Position.LowPart=0;
+ BlFileTable[*FileId].Position.HighPart=0;
+
+ //
+ // Enable the drive and start the motor via the DOR.
+ //
+
+ if (MotorStatus != DriveNumber) {
+ WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->DigitalOutput,
+ ((0xc + DriveNumber) + (1 << (DriveNumber + 4))));
+ MotorStatus = DriveNumber;
+
+ //
+ // Wait for at least 500ms to ensure that the motor really is running.
+ //
+
+ FwStallExecution(MILLISECONDS_500);
+ }
+
+ //
+ // Determine the disk density.
+ //
+
+ ClearFloppyFifo();
+ ArcStatus = FloppyDetermineMediaType(&BlFileTable[*FileId].u.FloppyContext);
+ if (ArcStatus == EIO) {
+ FloppyClose(*FileId);
+
+ //
+ // Reset the floppy, it seems to get in a bad state.
+ //
+
+ FloppyBootSetup();
+ return(ArcStatus);
+ } else if (ArcStatus != ESUCCESS) {
+
+ //
+ // The floppy was not readable, so try the other floppy type.
+ //
+
+ DriveType = BlFileTable[*FileId].u.FloppyContext.DriveType;
+ if ((DriveType == DRIVE_TYPE_1440) || (DriveType == DRIVE_TYPE_2880)) {
+ BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1200;
+ } else {
+ BlFileTable[*FileId].u.FloppyContext.DriveType = DRIVE_TYPE_1440;
+ }
+
+ ArcStatus = FloppyDetermineMediaType(&BlFileTable[*FileId].u.FloppyContext);
+ if (ArcStatus == EIO) {
+ FloppyClose(*FileId);
+ return(ArcStatus);
+ } else if (ArcStatus != ESUCCESS) {
+ BlFileTable[*FileId].u.FloppyContext.DriveType = DriveType;
+// FwPrint("Unrecognized floppy format\r\n");
+ FloppyClose(*FileId);
+ return(ArcStatus);
+ }
+ }
+
+ //
+ // Read the first sector to get the media descriptor byte.
+ //
+
+ TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1)
+ & ~(KeGetDcacheFillSize() - 1));
+ ArcStatus = FloppyRead(*FileId, TempPointer, SECTOR_SIZE, &Count);
+
+ if (ArcStatus != ESUCCESS) {
+// FwPrint("Error opening floppy\r\n");
+ FloppyClose(*FileId);
+ return(ArcStatus);
+ }
+
+ //
+ // Check the media descriptor byte to verify that we have the right
+ // drive and media type.
+ //
+
+ DriveType = BlFileTable[*FileId].u.FloppyContext.DriveType;
+ mediaDescriptor = *( TempPointer + MEDIA_DESCRIPTOR_OFFSET );
+ mediaType = 0;
+
+ switch ( mediaDescriptor ) {
+
+ case MEDIA_DESCRIPTOR_160K:
+ mediaType = F5_160_512;
+ DriveType = DRIVE_TYPE_1200;
+ break;
+
+ case MEDIA_DESCRIPTOR_180K:
+ mediaType = F5_180_512;
+ DriveType = DRIVE_TYPE_1200;
+ break;
+
+ case MEDIA_DESCRIPTOR_320K:
+ mediaType = F5_320_512;
+ DriveType = DRIVE_TYPE_1200;
+ break;
+
+ case MEDIA_DESCRIPTOR_360K:
+ mediaType = F5_360_512;
+ DriveType = DRIVE_TYPE_1200;
+ break;
+
+ case MEDIA_DESCRIPTOR_720K_OR_1220K:
+
+ //
+ // The following code tries to take care of the case when the floppy
+ // is really a 5 1/4" drive but the firmware thinks its 3 1/2". A
+ // 1.2 MByte floppy can be read with the 1.44 MByte parameters, but
+ // the descriptor byte will be MEDIA_DESCRIPTOR_720K_OR_1220K. Check
+ // if the parameters are really for 720 K, otherwise default to
+ // 1.2 MByte.
+ //
+
+ if ((DriveType == DRIVE_TYPE_1440) &&
+ (BlFileTable[*FileId].u.FloppyContext.SectorsPerTrack == 9)) {
+ mediaType = F3_720_512;
+ } else {
+ mediaType = F5_1Pt2_512;
+ DriveType = DRIVE_TYPE_1200;
+ }
+ break;
+
+ case MEDIA_DESCRIPTOR_1440K_OR_2880K:
+ mediaType = F3_1Pt44_512;
+ DriveType = DRIVE_TYPE_1440;
+ break;
+
+ default:
+ break;
+
+ }
+
+ if ( mediaType != 0 ) {
+
+ //
+ // Find the constants for this media type.
+ //
+
+ driveMediaType = DriveMediaLimits[DriveType].HighestDriveMediaType;
+ while ( ( DriveMediaConstants[driveMediaType].MediaType != mediaType ) &&
+ ( driveMediaType > DriveMediaLimits[DriveType].LowestDriveMediaType ) ) {
+
+ driveMediaType--;
+ }
+
+ //
+ // Set the sectors per track and the drive type in the floppy
+ // context record.
+ //
+
+ BlFileTable[*FileId].u.FloppyContext.SectorsPerTrack =
+ DriveMediaConstants[driveMediaType].SectorsPerTrack;
+ BlFileTable[*FileId].u.FloppyContext.DriveType = DriveType;
+ }
+
+ //
+ // If the floppy drive type has changed, update the configuration database
+ // with the correct drive type. NOTE Doesn't do 2.88 MByte floppies.
+ //
+
+ if (DriveType != ConfigDriveType) {
+
+ if (DriveType == DRIVE_TYPE_1200) {
+ strcpy(FloppyData->Size,"5.25");
+ FloppyData->MaxDensity = 1200;
+ } else {
+ strcpy(FloppyData->Size,"3.5");
+ FloppyData->MaxDensity = 1440;
+ }
+
+ //
+ // Get a pointer to the floppy controller component.
+ //
+
+ if ((FloppyController = FwGetParent(FloppyComponent)) != NULL) {
+
+ //
+ // Delete the old entry, note that this does not actually delete the
+ // data in the database, it only changes the pointers, so that the
+ // AddChild call can still use the old component data structure.
+ //
+
+ if (FwDeleteComponent(FloppyComponent) == ESUCCESS) {
+
+ //
+ // Add back the modified floppy structure.
+ //
+
+ FwAddChild(FloppyController, FloppyComponent, List);
+ }
+ }
+ }
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+FloppyRead (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ This function reads data from the floppy starting at the position
+ specified in the file table.
+
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a poiner to the buffer that receives the data
+ read.
+
+ Length - Supplies the number of bytes to be read.
+
+ Count - Supplies a pointer to a variable that receives the number of
+ bytes actually read.
+
+Return Value:
+
+
+ The read completion status is returned.
+
+--*/
+
+{
+
+ ARC_STATUS ArcStatus;
+ ULONG FrameNumber;
+ ULONG Index;
+ ULONG Limit;
+ PMDL MdlAddress;
+ UCHAR MdlBuffer[sizeof(MDL) + ((64 / 4) + 1) * sizeof(ULONG)];
+ ULONG NumberOfPages;
+ ULONG Offset;
+ PULONG PageFrame;
+ ULONG Position;
+ CHAR TempBuffer[SECTOR_SIZE + 32];
+ PCHAR TempPointer;
+
+ //
+ // If the requested size of the transfer is zero return ESUCCESS
+ //
+ if (Length==0) {
+ return ESUCCESS;
+ }
+ //
+ // If the current position is not at a sector boundary , then
+ // read the first and/or last sector separately and copy the data.
+ //
+
+ Offset = BlFileTable[FileId].Position.LowPart & (SECTOR_SIZE - 1);
+ if (Offset != 0) {
+ //
+ // Adjust position to the sector boundary, align the transfer address
+ // and read that first sector.
+ //
+ BlFileTable[FileId].Position.LowPart -= Offset;
+ TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1)
+ & ~(KeGetDcacheFillSize() - 1));
+
+ ArcStatus = FloppyRead(FileId, TempPointer, SECTOR_SIZE, Count);
+
+ //
+ // If the transfer was not successful, then reset the position
+ // and return the completion status.
+ //
+ if (ArcStatus != ESUCCESS) {
+ BlFileTable[FileId].Position.LowPart += Offset;
+ return ArcStatus;
+ }
+
+ //
+ // If the length of read is less than the number of bytes from
+ // the offset to the end of the sector, then copy only the number
+ // of bytes required to fulfil the request. Otherwise copy to the end
+ // of the sector and, read the remaining data.
+ //
+
+ if ((SECTOR_SIZE - Offset) > Length) {
+ Limit = Offset + Length;
+ } else {
+ Limit = SECTOR_SIZE;
+ }
+
+ //
+ // Copy the data to the specified buffer.
+ //
+ for (Index = Offset; Index < Limit; Index += 1) {
+ *((PCHAR)Buffer)++ = *(TempPointer + Index);
+ }
+
+ //
+ // Adjust the current position and
+ // Read the remaining part of the specified transfer.
+ //
+
+ BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE-Limit;
+ Position = BlFileTable[FileId].Position.LowPart;
+ ArcStatus = FloppyRead(FileId,
+ Buffer,
+ Length - (Limit - Offset),
+ Count);
+
+ //
+ // If the transfer was not successful, then reset the device
+ // position and return the completion status.
+ //
+
+ if (ArcStatus != ESUCCESS) {
+ BlFileTable[FileId].Position.LowPart = Position;
+ return ArcStatus;
+ } else {
+ *Count = Length;
+ return ESUCCESS;
+ }
+ } else {
+ //
+ // if the size of requested data is not a multiple of the sector
+ // size then read the last sector separately.
+ //
+ if (Length & (SECTOR_SIZE - 1)) {
+ Position = BlFileTable[FileId].Position.LowPart;
+ ArcStatus = FloppyRead(FileId,
+ Buffer,
+ Length & (~(SECTOR_SIZE - 1)),
+ Count);
+
+ //
+ // If the transfer was not successful, then reset the device
+ // position and return the completion status.
+ //
+ if (ArcStatus != ESUCCESS) {
+ BlFileTable[FileId].Position.LowPart = Position;
+ return ArcStatus;
+ }
+
+ //
+ // Read the last sector and copy the requested data.
+ //
+ TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1)
+ & ~(KeGetDcacheFillSize() - 1));
+
+ ArcStatus = FloppyRead(FileId, TempPointer, SECTOR_SIZE, Count);
+
+ //
+ // If the transfer was not successful return the completion status.
+ //
+ if (ArcStatus != ESUCCESS) {
+ return ArcStatus;
+ }
+
+ //
+ // Copy the data to the specified buffer.
+ //
+ (PCHAR)Buffer += Length & (~(SECTOR_SIZE - 1));
+ Limit = Length & (SECTOR_SIZE - 1);
+ for (Index = 0; Index < Limit; Index += 1) {
+ *((PCHAR)Buffer)++ = *(TempPointer + Index);
+ }
+ BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE - Limit;
+ *Count = Length;
+ return ESUCCESS;
+
+
+
+ } else {
+
+ //
+ // Build the memory descriptor list.
+ //
+
+ MdlAddress = (PMDL)&MdlBuffer[0];
+ MdlAddress->Next = NULL;
+ MdlAddress->Size = sizeof(MDL) +
+ ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Length) * sizeof(ULONG);
+ MdlAddress->StartVa = (PVOID)PAGE_ALIGN(Buffer);
+ MdlAddress->ByteCount = Length;
+ MdlAddress->ByteOffset = BYTE_OFFSET(Buffer);
+ PageFrame = (PULONG)(MdlAddress + 1);
+ FrameNumber = (((ULONG)MdlAddress->StartVa) & 0x1fffffff) >> PAGE_SHIFT;
+ NumberOfPages = (MdlAddress->ByteCount +
+ MdlAddress->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ for (Index = 0; Index < NumberOfPages; Index += 1) {
+ *PageFrame++ = FrameNumber++;
+ }
+
+ //
+ // Flush I/O buffers and read from the boot device.
+ //
+
+ HalFlushIoBuffers(MdlAddress, TRUE, TRUE);
+ ArcStatus = FloppyBootIO(MdlAddress,
+ BlFileTable[FileId].Position.LowPart >> SECTOR_SHIFT,
+ FileId,
+ FALSE);
+
+ if (ArcStatus == ESUCCESS) {
+ BlFileTable[FileId].Position.LowPart += Length;
+ *Count = Length;
+ return ESUCCESS;
+ } else {
+ *Count = 0;
+ return EIO;
+ }
+ }
+ }
+}
+
+ARC_STATUS
+FloppyWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ This function writes data to the floppy starting at the position
+ specified in the file table.
+
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Buffer - Supplies a poiner to the buffer that contains the data
+ to be written.
+
+ Length - Supplies the number of bytes to be writtes.
+
+ Count - Supplies a pointer to a variable that receives the number of
+ bytes actually written.
+
+Return Value:
+
+
+ The write completion status is returned.
+
+--*/
+
+{
+
+ ARC_STATUS ArcStatus;
+ ULONG FrameNumber;
+ ULONG Index;
+ ULONG Limit;
+ PMDL MdlAddress;
+ UCHAR MdlBuffer[sizeof(MDL) + ((64 / 4) + 1) * sizeof(ULONG)];
+ ULONG NumberOfPages;
+ ULONG Offset;
+ PULONG PageFrame;
+ ULONG Position;
+ CHAR TempBuffer[SECTOR_SIZE + 32];
+ PCHAR TempPointer;
+
+ //
+ // If the requested size of the transfer is zero return ESUCCESS
+ //
+ if (Length==0) {
+ return ESUCCESS;
+ }
+ //
+ // If the current position is not at a sector boundary , then
+ // read the first and/or last sector separately and copy the data.
+ //
+
+ Offset = BlFileTable[FileId].Position.LowPart & (SECTOR_SIZE - 1);
+ if (Offset != 0) {
+ //
+ // Adjust position to the sector boundary, align the transfer address
+ // and read that first sector.
+ //
+ BlFileTable[FileId].Position.LowPart -= Offset;
+ TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1)
+ & ~(KeGetDcacheFillSize() - 1));
+
+ ArcStatus = FloppyRead(FileId, TempPointer, SECTOR_SIZE, Count);
+
+ //
+ // If the transfer was not successful, then reset the position
+ // and return the completion status.
+ //
+ if (ArcStatus != ESUCCESS) {
+ BlFileTable[FileId].Position.LowPart += Offset;
+ return ArcStatus;
+ } else {
+ //
+ // Reset the position as it was before the read.
+ //
+ BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE;
+ }
+
+ //
+ // If the length of write is less than the number of bytes from
+ // the offset to the end of the sector, then copy only the number
+ // of bytes required to fulfil the request. Otherwise copy to the end
+ // of the sector and, read the remaining data.
+ //
+
+ if ((SECTOR_SIZE - Offset) > Length) {
+ Limit = Offset + Length;
+ } else {
+ Limit = SECTOR_SIZE;
+ }
+
+ //
+ // Merge the data from the specified buffer.
+ //
+ for (Index = Offset; Index < Limit; Index += 1) {
+ *(TempPointer + Index) = *((PCHAR)Buffer)++;
+ }
+
+ //
+ // Write the modified sector.
+ //
+ ArcStatus = FloppyWrite(FileId, TempPointer, SECTOR_SIZE, Count);
+
+ if (ArcStatus != ESUCCESS) {
+ return ArcStatus;
+ }
+
+ //
+ // Adjust the current position and
+ // Write the remaining part of the specified transfer.
+ //
+
+ BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE-Limit;
+ Position = BlFileTable[FileId].Position.LowPart;
+ ArcStatus = FloppyWrite(FileId,
+ Buffer,
+ Length - (Limit - Offset),
+ Count);
+
+ //
+ // If the transfer was not successful, then reset the device
+ // position and return the completion status.
+ //
+
+ if (ArcStatus != ESUCCESS) {
+ BlFileTable[FileId].Position.LowPart = Position;
+ return ArcStatus;
+ } else {
+ *Count = Length;
+ return ESUCCESS;
+ }
+ } else {
+ //
+ // if the size of requested data is not a multiple of the sector
+ // size then write the last sector separately.
+ //
+ if (Length & (SECTOR_SIZE - 1)) {
+
+ //
+ // Do the transfer of the complete sectors in the middle
+ //
+ Position = BlFileTable[FileId].Position.LowPart;
+ ArcStatus = FloppyWrite(FileId,
+ Buffer,
+ Length & (~(SECTOR_SIZE - 1)),
+ Count);
+
+ //
+ // If the transfer was not successful, then reset the device
+ // position and return the completion status.
+ //
+ if (ArcStatus != ESUCCESS) {
+ BlFileTable[FileId].Position.LowPart = Position;
+ return ArcStatus;
+ }
+
+ //
+ // Read the last sector and copy the requested data.
+ //
+ TempPointer = (PVOID) ((ULONG) (TempBuffer + KeGetDcacheFillSize() - 1)
+ & ~(KeGetDcacheFillSize() - 1));
+
+ ArcStatus = FloppyRead(FileId, TempPointer, SECTOR_SIZE, Count);
+
+ //
+ // If the transfer was not successful return the completion status.
+ //
+ if (ArcStatus != ESUCCESS) {
+ return ArcStatus;
+ }
+
+ //
+ // Copy the data to the specified buffer.
+ //
+ (PCHAR)Buffer += Length & (~(SECTOR_SIZE - 1));
+ Limit = Length & (SECTOR_SIZE - 1);
+ for (Index = 0; Index < Limit; Index += 1) {
+ *(TempPointer + Index) = *((PCHAR)Buffer)++;
+ }
+ //
+ // Adjust the position and write the data.
+ //
+ BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE;
+ ArcStatus = FloppyWrite(FileId, TempPointer, SECTOR_SIZE, Count);
+
+ //
+ // Set the position for the requested transfer
+ //
+ BlFileTable[FileId].Position.LowPart -= SECTOR_SIZE - Limit;
+
+ *Count = Length;
+ return ArcStatus;
+
+ } else {
+
+ //
+ // Build the memory descriptor list.
+ //
+
+ MdlAddress = (PMDL)&MdlBuffer[0];
+ MdlAddress->Next = NULL;
+ MdlAddress->Size = sizeof(MDL) +
+ ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Length) * sizeof(ULONG);
+ MdlAddress->StartVa = (PVOID)PAGE_ALIGN(Buffer);
+ MdlAddress->ByteCount = Length;
+ MdlAddress->ByteOffset = BYTE_OFFSET(Buffer);
+ PageFrame = (PULONG)(MdlAddress + 1);
+ FrameNumber = (((ULONG)MdlAddress->StartVa) & 0x1fffffff) >> PAGE_SHIFT;
+ NumberOfPages = (MdlAddress->ByteCount +
+ MdlAddress->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ for (Index = 0; Index < NumberOfPages; Index += 1) {
+ *PageFrame++ = FrameNumber++;
+ }
+
+ //
+ // Flush I/O buffers and write to the boot device.
+ //
+
+ HalFlushIoBuffers(MdlAddress, FALSE, TRUE);
+ ArcStatus = FloppyBootIO(MdlAddress,
+ BlFileTable[FileId].Position.LowPart >> SECTOR_SHIFT,
+ FileId,
+ TRUE);
+
+ if (ArcStatus == ESUCCESS) {
+ BlFileTable[FileId].Position.LowPart += Length;
+ *Count = Length;
+ return ESUCCESS;
+ } else {
+ *Count = 0;
+ return EIO;
+ }
+ }
+ }
+}
+
+ARC_STATUS
+FloppyGetReadStatus (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+ARC_STATUS
+FloppySeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+ This function sets the device position to the specified offset for
+ the specified file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Offset - Supplies to new device position.
+
+ SeekMode - Supplies the mode for the position.
+
+Return Value:
+
+ ESUCCESS is returned.
+
+--*/
+
+{
+
+ //
+ // Set the current device position as specifed by the seek mode.
+ //
+
+ if (SeekMode == SeekAbsolute) {
+ BlFileTable[FileId].Position.LowPart = Offset->LowPart;
+
+ } else if (SeekMode == SeekRelative) {
+ BlFileTable[FileId].Position.LowPart += Offset->LowPart;
+ }
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+FloppyGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Finfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the floppy size.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+ Finfo - Supplies a pointer to where the File Information is stored.
+
+Return Value:
+
+ ESUCCESS is returned.
+
+--*/
+
+{
+
+ RtlZeroMemory(Finfo, sizeof(FILE_INFORMATION));
+
+ switch (BlFileTable[FileId].u.FloppyContext.DriveType) {
+
+ case DRIVE_TYPE_1200: Finfo->EndingAddress.LowPart = 1200 * 1024;
+ break;
+ case DRIVE_TYPE_1440: Finfo->EndingAddress.LowPart = 1440 * 1024;
+ break;
+ case DRIVE_TYPE_2880: Finfo->EndingAddress.LowPart = 2880 * 1024;
+ break;
+
+ default : return EINVAL;
+ }
+
+ Finfo->CurrentPosition = BlFileTable[FileId].Position;
+ Finfo->Type = FloppyDiskPeripheral;
+ return ESUCCESS;
+}
+
+
+VOID
+FloppyBootSetup(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is invoked to initialize the floppy boot device before any
+ other floppy operations are attempted. This routine performs the following
+ operations to initialize the device:
+
+ o Clear the reset and DMA gate flags in the DOR
+ o Reset the floppy by writing the s/w reset in the DSR
+ o Set the program data rate in the CCR
+ o Issue a sense interrupt command and read the four statuses back
+ o Issue a configure command
+ o Issue a specify command
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG i,j;
+ //
+ // Begin by clearing the reset and DMA gate flags in the DOR.
+ //
+
+ WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->DigitalOutput, 0x0c);
+
+ //
+ // Reset the floppy controller by setting the s/w reset bit in the DSR.
+ //
+
+ WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.DataRateSelect, 0x80);
+
+ //
+ // Set the data rate in the CCR.
+ //
+
+// WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->DirCcr.ConfigurationControl, 0);
+
+ if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1),
+ FW_FLOPPY_TIMEOUT)) {
+// FwPrint("Floppy setup timeout\r\n");
+ return;
+ }
+
+
+ //
+ // Issue the sense interrupt command and read back the status and
+ // relative cylinder number from the controller. This is done for
+ // each of the four possible devices. Note that the output is always
+ // ignored.
+ //
+
+ for (i = j = 0; i <= 3; i++) {
+ SendByte(COMMND_SENSE_INTERRUPT);
+ DebugByte[j++] = ReceiveByte();
+ DebugByte[j++] = ReceiveByte();
+ }
+
+ //
+ // Issue the configuration command.
+ //
+
+ SendByte( COMMND_CONFIGURE ); // command
+ SendByte( 0x00 ); // required 0
+ SendByte( 0x58 ); // implied seeks, disable polling & threshold = 8
+ SendByte( 0x00 ); // precompensation track = 0
+
+ //
+ // Issue the specify command.
+ //
+
+ SendByte( COMMND_SPECIFY ); // command
+ SendByte( 0xdf ); // step rate time=d, head unload=f
+ SendByte( 0x03 ); // head load=1, DMA disabled
+
+ return;
+}
+
+VOID
+FloppyInitialize(
+ IN OUT PDRIVER_LOOKUP_ENTRY LookupTable,
+ IN ULONG Entries
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the FloppyDriver.
+
+Arguments:
+
+ LookupTable - Pointer to the driver lookup table where the pathnames
+ recognized by this driver will be stored.
+
+ Entries - Number of entries in the table.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCONFIGURATION_COMPONENT FloppyComponent;
+ CHAR FloppyPath[32];
+ ULONG Drive;
+ //
+ // Set motor status to all motors stopped.
+ //
+
+ MotorStatus = MAXLONG;
+
+ FloppyBootSetup();
+
+ //
+ // Default to floppy 0 in case no configuration is present in the NVRAM
+ //
+ LookupTable->DevicePath = Floppy0Path;
+ LookupTable->DispatchTable = &FloppyEntryTable;
+
+ //
+ // Get the floppy configuration information.
+ //
+ FloppyComponent = FwGetComponent(Floppy0Path);
+ if ((FloppyComponent != NULL) &&
+ (FloppyComponent->Type == FloppyDiskPeripheral)) {
+
+ //
+ // Initialize the lookup table.
+ //
+
+ LookupTable->DevicePath = Floppy0Path;
+ LookupTable->DispatchTable = &FloppyEntryTable;
+ LookupTable++;
+
+ //
+ // Return if no more room in the lookup table.
+ //
+
+ if (Entries == 1) {
+ return;
+ }
+ }
+ FloppyComponent = FwGetComponent(Floppy1Path);
+ if ((FloppyComponent != NULL) &&
+ (FloppyComponent->Type == FloppyDiskPeripheral)) {
+
+ //
+ // Initialize the lookup table.
+ //
+ LookupTable->DevicePath = Floppy1Path;
+ LookupTable->DispatchTable = &FloppyEntryTable;
+ }
+}
+
+ARC_STATUS
+FloppyBootClose(
+ )
+
+/*++
+
+Routine Description:
+
+ This routine shuts down the floppy after the boot has taken place.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Normal, successful completion status.
+
+--*/
+
+{
+
+ //
+ // Turn the floppy drive's motor off and indicate that the
+ // motor has been shut off.
+ //
+
+ WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->DigitalOutput, 0xc);
+ MotorStatus = MAXLONG;
+
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+FloppyBootIO (
+ IN PMDL Mdl,
+ IN ULONG StartingBlock,
+ IN ULONG FileId,
+ IN BOOLEAN ReadWrite
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads or writes blocks from the floppy into the buffer described by
+ the MDL. The size of the read is the number of bytes mapped by the MDL
+ and the blocks read start at StartingBlock.
+
+Arguments:
+
+ Mdl - Memory Descriptor List for buffer.
+
+ StartingBlock - Block to begin the read operation.
+
+ FileId - The file identifier of the floppy drive to access.
+
+ ReadWrite - Specifies the kind of transfer to be done
+ TRUE = WRITE
+ FALSE = READ
+
+Return Value:
+
+ The function value is the status of the operation.
+
+
+--*/
+
+{
+
+ UCHAR Cylinder;
+ UCHAR Head = 0;
+ UCHAR Sector;
+ UCHAR EndSector;
+ ULONG BlockCount;
+ ULONG TransferSize;
+ ULONG TransferedBytes;
+ ULONG i,j,k;
+ PUCHAR Buffer;
+ BOOLEAN Success;
+ ARC_STATUS Status = ESUCCESS;
+ UCHAR DriveNumber;
+ ULONG SectorsPerTrack;
+
+ DriveNumber = BlFileTable[FileId].u.FloppyContext.DiskId;
+ SectorsPerTrack = BlFileTable[FileId].u.FloppyContext.SectorsPerTrack;
+
+ //
+ // Enable the drive and start the motor via the DOR.
+ //
+
+ if (MotorStatus != DriveNumber) {
+ WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->DigitalOutput,
+ ((0xc + DriveNumber) + (1 << (DriveNumber + 4))));
+ MotorStatus = DriveNumber;
+
+ //
+ // Wait for at least 500ms to ensure that the motor really is running.
+ //
+
+ FwStallExecution(MILLISECONDS_500);
+ }
+
+ //
+ // Get the number of blocks that need to be read in order to fulfill
+ // this request. Also set the base address of the caller's buffer.
+ //
+
+ Buffer = ((PUCHAR) Mdl->StartVa) + Mdl->ByteOffset;
+
+ //
+ // Get the parameters for the read command.
+ //
+
+ Cylinder = StartingBlock / (SectorsPerTrack * 2);
+ Sector = (StartingBlock % SectorsPerTrack) + 1;
+ Head = (StartingBlock / SectorsPerTrack) % 2;
+
+ ClearFloppyFifo();
+
+ //
+ // Loop reading blocks from the device until the request has been
+ // satisfied.
+ //
+
+ for (BlockCount = Mdl->ByteCount >> 9; BlockCount > 0; ) {
+
+ //
+ // Determine the size of this read based on the number of blocks
+ // required and where the current sector is on the current track.
+ //
+
+ EndSector = MINIMUM( SectorsPerTrack, (Sector + (BlockCount - 1)) );
+ TransferSize = (EndSector - Sector) + 1;
+ BlockCount -= TransferSize;
+ TransferSize <<= 9;
+
+ //
+ // Attempt to read the block(s) up to RETRY_COUNT times.
+ //
+
+ for (k = 0; k < RETRY_COUNT; k++) {
+
+ //
+ // Assume that the operation will be successful.
+ //
+
+ Success = TRUE;
+
+ //
+ // Do an explicit seek if this is a 360 K disk in a 1.2 MB drive.
+ //
+
+ if (CurrentDriveMediaConstants->CylinderShift != 0) {
+ if (!SendByte( COMMND_SEEK ) ||
+ !SendByte( (Head << 2) + DriveNumber ) || // head select & drive
+ !SendByte( Cylinder << CurrentDriveMediaConstants->CylinderShift )) {
+ return(EIO);
+ }
+
+ if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1),
+ FW_FLOPPY_TIMEOUT)) {
+ return(EIO);
+ }
+
+ //
+ // Send the sense interrupt command.
+ //
+
+ if (!SendByte( COMMND_SENSE_INTERRUPT )) { // command
+ return(EIO);
+ }
+
+ //
+ // Read back the information from the drive and check the status of the
+ // recalibrate command.
+ //
+
+ DebugByte[0] = ReceiveByte();
+ DebugByte[1] = ReceiveByte();
+
+ if (DebugByte[1] != (Cylinder << CurrentDriveMediaConstants->CylinderShift)) {
+ return(EIO);
+ }
+
+ //
+ // Now try to read the ID from wherever we're at.
+ //
+
+ if (!SendByte( COMMND_READ_ID + COMMND_MFM ) || // command
+ !SendByte( DriveNumber | ((CurrentDriveMediaConstants->NumberOfHeads - 1) << 2) )) {
+ return(EIO);
+ }
+
+ if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1),
+ FW_FLOPPY_TIMEOUT)) {
+ return(EIO);
+ }
+
+ for (i = 0; i < 7; i++) {
+ DebugByte[i] = ReceiveByte();
+ }
+
+ if ( ( DebugByte[0] !=
+ (UCHAR)(DriveNumber |
+ ((CurrentDriveMediaConstants->NumberOfHeads - 1) << 2))) ||
+ ( DebugByte[1] != 0 ) ||
+ ( DebugByte[2] != 0 ) ) {
+
+ return(EIO);
+ }
+
+ }
+
+ //
+ // Send the command and parameters for the operation.
+ //
+
+ if (ReadWrite == TRUE) {
+ if (!SendByte( COMMND_WRITE_DATA + COMMND_MFM )) {
+ return(EIO);
+ }
+ } else {
+ if (!SendByte( COMMND_READ_DATA + COMMND_MFM )) {
+ return(EIO);
+ }
+ }
+ if (!SendByte( (Head << 2) + DriveNumber ) || // head select & drive
+ !SendByte( Cylinder ) || // cylinder
+ !SendByte( Head ) || // head
+ !SendByte( Sector ) || // sector
+ !SendByte( 2 ) || // sector size; 2 => 512B/sec
+ !SendByte( EndSector ) || // end of track sector
+ !SendByte( CurrentDriveMediaConstants->ReadWriteGapLength ) ||
+ !SendByte( 0xff )) { // special sector size
+ return(EIO);
+ }
+
+ //
+ // Ensure that the floppy drive does not time-out.
+ //
+
+ for (j = 0; j < SECONDS_2; j += MICROSECONDS_10) {
+ if (READ_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) > 127) {
+ break;
+ }
+
+ FwStallExecution(MICROSECONDS_10);
+ }
+
+ //
+ // Check for time-out; if one occurred, then return unsuccessful
+ // status.
+ //
+
+ if (j == SECONDS_2) {
+// FwPrint("Floppy timeout\r\n");
+ return EIO;
+ }
+
+ //
+ // Read the data from the appropriate block(s) and check the number
+ // of bytes actually read.
+ //
+
+ if (ReadWrite == TRUE) {
+ WriteFloppyFifo(Buffer,TransferSize);
+ } else {
+ TransferedBytes = ReadFloppyFifo(Buffer);
+ if (TransferedBytes != TransferSize) {
+ Success = FALSE;
+ }
+ }
+
+ //
+ // Read the status information from the device.
+ //
+
+ while (READ_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) <= 127) {
+ }
+
+ for (i = 0; i < 7; i++) {
+ DebugByte[i] = ReceiveByte();
+ }
+
+ if (((DebugByte[0] >> 4) == 2) &&
+ (DebugByte[1] == 0) &&
+ (DebugByte[2] == 0) &&
+ Success) {
+ ;
+
+ } else {
+
+ if ((DebugByte[0] >> 4) != 4) {
+ Success = FALSE;
+ }
+
+ if (DebugByte[1] != 0x80) {
+ Success = FALSE;
+ }
+
+ if (DebugByte[2] != 0) {
+ Success = FALSE;
+ }
+ }
+
+ //
+ // If the operation was successful, exit the loop.
+ //
+
+ if (Success) {
+ Buffer += TransferSize;
+ break;
+ }
+
+ //
+ // The operation did not work. Attempt to recalibrate the
+ // device and wait for everything to settle out, and then
+ // try the operation again.
+ //
+
+ if (!Recalibrate(DriveNumber)) {
+// FwPrint("Floppy recalibration error\r\n");
+ return(EIO);
+ }
+ FwStallExecution(MILLISECONDS_15);
+ }
+
+ //
+ // If the operation was not successful after RETRY_COUNT tries, get
+ // out now.
+ //
+
+ if (!Success) {
+ Status = EIO;
+ break;
+ }
+
+ //
+ // If more data is needed, get the next place to read from. Note
+ // that if there is more data to be read, then the last sector
+ // just read was the last sector on this head.
+ //
+
+ if (BlockCount > 0) {
+ if (Head == 1) {
+ Cylinder += 1;
+ Head = 0;
+ } else {
+ Head = 1;
+ }
+ Sector = 1;
+ }
+
+ if (Success) {
+ Status = ESUCCESS;
+ }
+ }
+ return Status;
+}
+
+BOOLEAN
+Recalibrate(
+ UCHAR DriveNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine issues a recalibrate command to the device, waits for it to
+ interrupt, sends it a sense interrupt command, and checks the result to
+ ensure that the recalibrate command worked properly.
+
+Arguments:
+
+ DriveNumber - Supplies the Floppy drive to recalibrate.
+
+Return Value:
+
+ Returns TRUE if the recalibrate was successful, FALSE if not.
+
+--*/
+
+{
+
+ //
+ // Send the recalibrate command to the device.
+ //
+
+ if (!SendByte( COMMND_RECALIBRATE ) || // command
+ !SendByte( DriveNumber )) { // drive select
+ return(FALSE);
+ }
+
+ if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1),
+ FW_FLOPPY_TIMEOUT)) {
+// FwPrint("Floppy recalibrate timeout\r\n");
+ return(FALSE);
+ }
+
+ //
+ // Send the sense interrupt command.
+ //
+
+ if (!SendByte( COMMND_SENSE_INTERRUPT )) { // command
+ return(FALSE);
+ }
+
+ //
+ // Read back the information from the drive and check the status of the
+ // recalibrate command.
+ //
+
+ DebugByte[0] = ReceiveByte();
+ if ((DebugByte[0] >> 4) != 2) {
+ return FALSE;
+ }
+
+ DebugByte[1] = ReceiveByte();
+
+ if ((READ_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) &
+ STATUS_IO_READY_MASK) == STATUS_READ_READY) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+UCHAR
+ReceiveByte(
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the next byte from the floppy FIFO register.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The function value is the value of the byte read from the floppy FIFO.
+
+--*/
+
+{
+
+ ULONG i;
+
+ //
+ // Check status register for readiness to receive data.
+ //
+
+ for (i = 0; i < MICROSECONDS_250; i += MICROSECONDS_10) {
+ if ((READ_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) &
+ STATUS_IO_READY_MASK) == STATUS_READ_READY) {
+ return READ_REGISTER_UCHAR(&FLOPPY_CONTROL->Fifo);
+ }
+
+ FwStallExecution(MICROSECONDS_10);
+ }
+
+ //
+ // A timeout occurred while attempting to read data from the floppy fifo.
+ // Output an error message and return.
+ //
+
+// FwPrint("Error reading from floppy fifo\r\n");
+ return(0xFF);
+}
+
+BOOLEAN
+SendByte(
+ IN UCHAR SourceByte
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a specified byte to the floppy FIFO register.
+
+Arguments:
+
+ SourceByte - Byte to be sent to the controller.
+
+Return Value:
+
+ If the byte was successfully written to the floppy FIFO, TRUE is returned,
+ otherwise FALSE is returned.
+
+--*/
+
+{
+
+ ULONG i;
+
+ //
+ // Check status register for readiness to receive data.
+ //
+
+ for (i = 0; i < MICROSECONDS_250; i += MICROSECONDS_10) {
+ if ((READ_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) &
+ STATUS_IO_READY_MASK) == STATUS_WRITE_READY) {
+ WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->Fifo, SourceByte);
+ return(TRUE);
+ }
+
+ FwStallExecution(MICROSECONDS_10);
+ }
+
+ //
+ // A timeout occurred while attempting to write data to the floppy fifo.
+ // Output an error message and return.
+ //
+
+// FwPrint("Error writing to floppy fifo\r\n");
+ return(FALSE);
+}
+
+VOID
+ClearFloppyFifo(
+ IN VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine empties the fifo.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG i;
+
+ //
+ // Check status register for readiness to receive data.
+ //
+ while ((READ_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.MainStatus) &
+ STATUS_IO_READY_MASK) == STATUS_READ_READY) {
+ READ_REGISTER_UCHAR(&FLOPPY_CONTROL->Fifo);
+ FwStallExecution(MICROSECONDS_10);
+ }
+}
+
+
+ARC_STATUS
+FloppyDatarateSpecifyConfigure(
+ IN DRIVE_MEDIA_TYPE DriveMediaType,
+ IN UCHAR DriveNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called to set up the controller every time a new type
+ of diskette is to be accessed. It issues the CONFIGURE command,
+ does a SPECIFY, sets the data rate, and RECALIBRATEs the drive.
+
+Arguments:
+
+ DriveMediaType - supplies the drive type/media density combination.
+
+ DriveNumber - supplies the drive number.
+
+Return Value:
+
+ ESUCCESS if the controller is properly prepared; appropriate
+ error propogated otherwise.
+
+--*/
+
+{
+ UCHAR Configure;
+
+ //
+ // Don't enable implied seeks when there is a 360K disk in a 1.2M drive.
+ //
+
+ if (DriveMediaConstants[DriveMediaType].CylinderShift) {
+ Configure = 0x18;
+ } else {
+ Configure = 0x58;
+ }
+
+ //
+ // Issue the configuration command.
+ //
+
+ if (!SendByte( COMMND_CONFIGURE ) || // command
+ !SendByte( 0x00 ) || // required 0
+ !SendByte( Configure ) || // implied seeks, disable polling & threshold = 8
+ !SendByte( 0x00 ) || // precompensation track = 0
+
+ //
+ // Issue SPECIFY command to program the head load and unload
+ // rates, the drive step rate, and the DMA data transfer mode.
+ //
+
+ !SendByte( COMMND_SPECIFY ) || // command
+ !SendByte( DriveMediaConstants[DriveMediaType].StepRateHeadUnloadTime) ||
+ !SendByte( DriveMediaConstants[DriveMediaType].HeadLoadTime + 1)) {
+ return(EIO);
+ }
+
+ //
+ // Program the data rate
+ //
+
+ WRITE_REGISTER_UCHAR(&FLOPPY_CONTROL->MsrDsr.DataRateSelect,
+ DriveMediaConstants[DriveMediaType].DataTransferRate );
+
+ //
+ // Recalibrate the drive, now that we've changed all its
+ // parameters.
+ //
+
+ if (Recalibrate(DriveNumber)) {
+ return(ESUCCESS);
+ } else {
+// FwPrint("Floppy recalibration error\r\n");
+ return(EIO);
+ }
+}
+
+ARC_STATUS
+FloppyDetermineMediaType(
+ IN OUT PFLOPPY_CONTEXT FloppyContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is called by FloppyBootIO() when the media type is
+ unknown. It assumes the largest media supported by the drive is
+ available, and keeps trying lower values until it finds one that
+ works.
+
+Arguments:
+
+ FloppyContext - supplies a pointer to the floppy context structure.
+
+Return Value:
+
+ ESUCCESS if the type of the media is determined; appropriate
+ error propogated otherwise.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ BOOLEAN mediaTypesExhausted = FALSE;
+ DRIVE_MEDIA_TYPE DriveMediaType;
+ UCHAR DriveNumber;
+ ULONG i;
+
+ //
+ // Assume that the largest supported media is in the drive. If that
+ // turns out to be untrue, we'll try successively smaller media types
+ // until we find what's really in there (or we run out and decide
+ // that the media isn't formatted).
+ //
+
+ DriveMediaType =
+ DriveMediaLimits[FloppyContext->DriveType].HighestDriveMediaType;
+
+ DriveNumber = FloppyContext->DiskId;
+
+ do {
+
+ Status = FloppyDatarateSpecifyConfigure( DriveMediaType, DriveNumber );
+
+ if ( Status != ESUCCESS ) {
+
+ //
+ // The SPECIFY or CONFIGURE commands resulted in an error.
+ // Force ourselves out of this loop and return error.
+ //
+
+ mediaTypesExhausted = TRUE;
+
+ } else {
+
+ CurrentDriveMediaConstants = &DriveMediaConstants[DriveMediaType];
+
+ //
+ // Now try to read the ID from wherever we're at.
+ //
+
+ if (!SendByte( COMMND_READ_ID + COMMND_MFM ) || // command
+ !SendByte( DriveNumber | ((CurrentDriveMediaConstants->NumberOfHeads - 1) << 2) )) {
+ return(EIO);
+ }
+
+ if (FwWaitForDeviceInterrupt(1 << (FLOPPY_VECTOR - DEVICE_VECTORS - 1),
+ FW_FLOPPY_TIMEOUT)) {
+// FwPrint("Floppy determine media timeout\r\n");
+ return(EIO);
+ }
+
+ for (i = 0; i < 7; i++) {
+ DebugByte[i] = ReceiveByte();
+ }
+
+ if ( ( DebugByte[0] !=
+ (UCHAR)(DriveNumber |
+ ((CurrentDriveMediaConstants->NumberOfHeads - 1) << 2))) ||
+ ( DebugByte[1] != 0 ) ||
+ ( DebugByte[2] != 0 ) ) {
+
+ DriveMediaType--;
+
+ Status = ENXIO;
+
+ //
+ // Next comparison must be signed, for when
+ // LowestDriveMediaType = 0.
+ //
+
+ if ( (CHAR)( DriveMediaType ) <
+ (CHAR)( DriveMediaLimits[FloppyContext->DriveType].LowestDriveMediaType )) {
+
+ mediaTypesExhausted = TRUE;
+
+ }
+ }
+ }
+
+ } while ( ( ( Status != ESUCCESS ) ) && !( mediaTypesExhausted ) );
+
+ if ( Status == ESUCCESS ) {
+
+ FloppyContext->SectorsPerTrack =
+ CurrentDriveMediaConstants->SectorsPerTrack;
+ }
+ return Status;
+}
+#endif
diff --git a/private/ntos/fw/mips/jxfont.s b/private/ntos/fw/mips/jxfont.s
new file mode 100644
index 000000000..bf9d952f3
--- /dev/null
+++ b/private/ntos/fw/mips/jxfont.s
@@ -0,0 +1,3126 @@
+#if defined (JAZZ)
+
+// TITLE("Hardware Architecture Layer Font Table")
+//++
+//
+// Copyright (c) 1991 Microsoft Corporation
+//
+// Module Name:
+//
+// jxfonts.s
+//
+// Abstract:
+//
+// This module defines the font used for a MIPS R3000 or R4000 Jazz
+// system.
+//
+// Author:
+//
+// David N. Cutler (davec) 27-Apr-1991
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+
+//
+// Define font table.
+//
+// Characters are 16 pixels wide and 32 pixels high.
+//
+
+ .rdata
+ .globl FwUsFont
+
+ .align 2
+FwUsFont:
+
+Char0:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char !
+Char1:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X03E0 // 0000001111100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X01C0 // 0000000111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char "
+Char2:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0330 // 0000001100110000
+ .half 0X0330 // 0000001100110000
+ .half 0X0330 // 0000001100110000
+ .half 0X0330 // 0000001100110000
+ .half 0X0330 // 0000001100110000
+ .half 0X0330 // 0000001100110000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char #
+Char3:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X1100 // 0001000100000000
+ .half 0X1180 // 0001000110000000
+ .half 0X1980 // 0001100110000000
+ .half 0X1880 // 0001100010000000
+ .half 0X08C0 // 0000100011000000
+ .half 0X0CC0 // 0000110011000000
+ .half 0X0CC0 // 0000110011000000
+ .half 0X7FFE // 0111111111111110
+ .half 0X0660 // 0000011001100000
+ .half 0X0620 // 0000011000100000
+ .half 0X0230 // 0000001000110000
+ .half 0X0230 // 0000001000110000
+ .half 0X3FFF // 0011111111111111
+ .half 0X0118 // 0000000100011000
+ .half 0X0198 // 0000000110011000
+ .half 0X0188 // 0000000110001000
+ .half 0X008C // 0000000010001100
+ .half 0X00CC // 0000000011001100
+ .half 0X00C4 // 0000000011000100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char4:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0BE0 // 0000101111100000
+ .half 0X0FF0 // 0000111111110000
+ .half 0X0C38 // 0000110000111000
+ .half 0X0818 // 0000100000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X0030 // 0000000000110000
+ .half 0X03F0 // 0000001111110000
+ .half 0X0FC0 // 0000111111000000
+ .half 0X1E00 // 0001111000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X1818 // 0001100000011000
+ .half 0X1C38 // 0001110000111000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X07E8 // 0000011111101000
+ .half 0X0080 // 0000000010000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char %
+Char5:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X00E0 // 0000000011100000
+ .half 0X01F0 // 0000000111110000
+ .half 0X0318 // 0000001100011000
+ .half 0X0318 // 0000001100011000
+ .half 0X0318 // 0000001100011000
+ .half 0X19F0 // 0001100111110000
+ .half 0X1EE0 // 0001111011100000
+ .half 0X0380 // 0000001110000000
+ .half 0X00E0 // 0000000011100000
+ .half 0X0738 // 0000011100111000
+ .half 0X0F80 // 0000111110000000
+ .half 0X18C0 // 0001100011000000
+ .half 0X18C0 // 0001100011000000
+ .half 0X18C0 // 0001100011000000
+ .half 0X0F80 // 0000111110000000
+ .half 0X0700 // 0000011100000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char &
+Char6:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X01E0 // 0000000111100000
+ .half 0X03F0 // 0000001111110000
+ .half 0X0338 // 0000001100111000
+ .half 0X0018 // 0000000000011000
+ .half 0X0038 // 0000000000111000
+ .half 0X0030 // 0000000000110000
+ .half 0X0070 // 0000000001110000
+ .half 0X18F8 // 0001100011111000
+ .half 0X1DD8 // 0001110111011000
+ .half 0X0D8C // 0000110110001100
+ .half 0X0F0C // 0000111100001100
+ .half 0X070C // 0000011100001100
+ .half 0X0F1C // 0000111100011100
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1CF0 // 0001110011110000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char '
+Char7:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char (
+Char8:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0200 // 0000001000000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0200 // 0000001000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char )
+Char9:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0020 // 0000000000100000
+ .half 0X0060 // 0000000001100000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0380 // 0000001110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X0060 // 0000000001100000
+ .half 0X0020 // 0000000000100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char *
+Char10:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X1998 // 0001100110011000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X07E0 // 0000011111100000
+ .half 0X03C0 // 0000001111000000
+ .half 0X03C0 // 0000001111000000
+ .half 0X0660 // 0000011001100000
+ .half 0X0420 // 0000010000100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char +
+Char11:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X7FFE // 0111111111111110
+ .half 0X7FFE // 0111111111111110
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char ,
+Char12:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0780 // 0000011110000000
+ .half 0X03C0 // 0000001111000000
+ .half 0X03C0 // 0000001111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X00E0 // 0000000011100000
+ .half 0X00E0 // 0000000011100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char -
+Char13:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3FFC // 0011111111111100
+ .half 0X3FFC // 0011111111111100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char .
+Char14:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X03E0 // 0000001111100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X01C0 // 0000000111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char /
+Char15:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0018 // 0000000000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char16:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X03C0 // 0000001111000000
+ .half 0X07E0 // 0000011111100000
+ .half 0X0E70 // 0000111001110000
+ .half 0X0C30 // 0000110000110000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X0C30 // 0000110000110000
+ .half 0X0E70 // 0000111001110000
+ .half 0X07E0 // 0000011111100000
+ .half 0X03C0 // 0000001111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char17:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X01F8 // 0000000111111000
+ .half 0X01B8 // 0000000110111000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char18:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X01E0 // 0000000111100000
+ .half 0X07F8 // 0000011111111000
+ .half 0X0E18 // 0000111000011000
+ .half 0X0C08 // 0000110000001000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0180 // 0000000110000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X00E0 // 0000000011100000
+ .half 0X0070 // 0000000001110000
+ .half 0X0818 // 0000100000011000
+ .half 0X0FFC // 0000111111111100
+ .half 0X0FFC // 0000111111111100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char19:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X03E0 // 0000001111100000
+ .half 0X07F8 // 0000011111111000
+ .half 0X0E38 // 0000111000111000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X03C0 // 0000001111000000
+ .half 0X0F00 // 0000111100000000
+ .half 0X1C00 // 0001110000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X0C1C // 0000110000011100
+ .half 0X0FFC // 0000111111111100
+ .half 0X03F0 // 0000001111110000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char20:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0380 // 0000001110000000
+ .half 0X0380 // 0000001110000000
+ .half 0X03C0 // 0000001111000000
+ .half 0X0360 // 0000001101100000
+ .half 0X0360 // 0000001101100000
+ .half 0X0330 // 0000001100110000
+ .half 0X0310 // 0000001100010000
+ .half 0X0318 // 0000001100011000
+ .half 0X0308 // 0000001100001000
+ .half 0X030C // 0000001100001100
+ .half 0X1FFC // 0001111111111100
+ .half 0X1FFC // 0001111111111100
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X1FC0 // 0001111111000000
+ .half 0X1FC0 // 0001111111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char21:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X0018 // 0000000000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X03F8 // 0000001111111000
+ .half 0X07F8 // 0000011111111000
+ .half 0X0E18 // 0000111000011000
+ .half 0X1C00 // 0001110000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X1C00 // 0001110000000000
+ .half 0X0E0C // 0000111000001100
+ .half 0X07FC // 0000011111111100
+ .half 0X03F0 // 0000001111110000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char22:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X1F00 // 0001111100000000
+ .half 0X0FC0 // 0000111111000000
+ .half 0X00E0 // 0000000011100000
+ .half 0X0070 // 0000000001110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X03D8 // 0000001111011000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X0C38 // 0000110000111000
+ .half 0X1838 // 0001100000111000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1830 // 0001100000110000
+ .half 0X0C70 // 0000110001110000
+ .half 0X0FE0 // 0000111111100000
+ .half 0X03C0 // 0000001111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char23:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1818 // 0001100000011000
+ .half 0X0800 // 0000100000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char24:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X03C0 // 0000001111000000
+ .half 0X0FF0 // 0000111111110000
+ .half 0X0C30 // 0000110000110000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X0C30 // 0000110000110000
+ .half 0X07E0 // 0000011111100000
+ .half 0X07E0 // 0000011111100000
+ .half 0X0C30 // 0000110000110000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1C38 // 0001110000111000
+ .half 0X0FF0 // 0000111111110000
+ .half 0X03C0 // 0000001111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char25:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X03C0 // 0000001111000000
+ .half 0X07F0 // 0000011111110000
+ .half 0X0E30 // 0000111000110000
+ .half 0X0C18 // 0000110000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1C18 // 0001110000011000
+ .half 0X1C30 // 0001110000110000
+ .half 0X1FF0 // 0001111111110000
+ .half 0x1BC0 // 0001101111000000
+ .half 0X1C00 // 0001110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0E00 // 0000111000000000
+ .half 0X0700 // 0000011100000000
+ .half 0X03F0 // 0000001111110000
+ .half 0X00F8 // 0000000011111000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char :
+Char26:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X03E0 // 0000001111100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X01C0 // 0000000111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X03E0 // 0000001111100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X01C0 // 0000000111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char ;
+Char27:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0380 // 0000001110000000
+ .half 0X07C0 // 0000011111000000
+ .half 0X07C0 // 0000011111000000
+ .half 0X07C0 // 0000011111000000
+ .half 0X0380 // 0000001110000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0780 // 0000011110000000
+ .half 0X0380 // 0000001110000000
+ .half 0X03C0 // 0000001111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00E0 // 0000000011100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char <
+Char28:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3000 // 0011000000000000
+ .half 0X3C00 // 0011110000000000
+ .half 0X0F80 // 0000111110000000
+ .half 0X01E0 // 0000000111100000
+ .half 0X0078 // 0000000001111000
+ .half 0X001E // 0000000000011110
+ .half 0X001E // 0000000000011110
+ .half 0X0078 // 0000000001111000
+ .half 0X01E0 // 0000000111100000
+ .half 0X0F80 // 0000111110000000
+ .half 0X3E00 // 0011111000000000
+ .half 0X3000 // 0011000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char =
+Char29:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3FFE // 0011111111111110
+ .half 0X3FFE // 0011111111111110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3FFE // 0011111111111110
+ .half 0X3FFE // 0011111111111110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char >
+Char30:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0006 // 0000000000000110
+ .half 0X001E // 0000000000011110
+ .half 0X00F8 // 0000000011111000
+ .half 0X03C0 // 0000001111000000
+ .half 0X0F00 // 0000111100000000
+ .half 0X3C00 // 0011110000000000
+ .half 0X3C00 // 0011110000000000
+ .half 0X0F00 // 0000111100000000
+ .half 0X03C0 // 0000001111000000
+ .half 0X00F8 // 0000000011111000
+ .half 0X003E // 0000000000111110
+ .half 0X0006 // 0000000000000110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char ?
+Char31:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X03F0 // 0000001111110000
+ .half 0X07F8 // 0000011111111000
+ .half 0X0E18 // 0000111000011000
+ .half 0X0C08 // 0000110000001000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X07C0 // 0000011111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X0040 // 0000000001000000
+ .half 0X0000 // 0000000000000000
+ .half 0X00E0 // 0000000011100000
+ .half 0X01F0 // 0000000111110000
+ .half 0X01F0 // 0000000111110000
+ .half 0X01F0 // 0000000111110000
+ .half 0X00E0 // 0000000011100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char @
+Char32:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X03C0 // 0000001111000000
+ .half 0X07E0 // 0000011111100000
+ .half 0X0E70 // 0000111001110000
+ .half 0X0C30 // 0000110000110000
+ .half 0X0C30 // 0000110000110000
+ .half 0X0C18 // 0000110000011000
+ .half 0X0F98 // 0000111110011000
+ .half 0X0CD8 // 0000110011011000
+ .half 0X0C78 // 0000110001111000
+ .half 0X0C78 // 0000110001111000
+ .half 0X0C78 // 0000110001111000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X0FD8 // 0000111111011000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0070 // 0000000001110000
+ .half 0X0FE0 // 0000111111100000
+ .half 0X07C0 // 0000011111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char33:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X01F8 // 0000000111111000
+ .half 0X01F8 // 0000000111111000
+ .half 0X0160 // 0000000101100000
+ .half 0X0360 // 0000001101100000
+ .half 0X0320 // 0000001100100000
+ .half 0X0630 // 0000011000110000
+ .half 0X0630 // 0000011000110000
+ .half 0X0C10 // 0000110000010000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X180C // 0001100000001100
+ .half 0X300C // 0011000000001100
+ .half 0X300C // 0011000000001100
+ .half 0XFE3F // 1111111000111111
+ .half 0XFE3F // 1111111000111111
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char34:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X07FE // 0000011111111110
+ .half 0X0FFE // 0000111111111110
+ .half 0X1C18 // 0001110000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1C18 // 0001110000011000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X3818 // 0011100000011000
+ .half 0X3018 // 0011000000011000
+ .half 0X3018 // 0011000000011000
+ .half 0X3018 // 0011000000011000
+ .half 0X3818 // 0011100000011000
+ .half 0X1FFE // 0001111111111110
+ .half 0X0FFE // 0000111111111110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char35:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0x37C0 // 0011011111000000
+ .half 0X3FF0 // 0011111111110000
+ .half 0X3C38 // 0011110000111000
+ .half 0X380C // 0011100000001100
+ .half 0X300C // 0011000000001100
+ .half 0X0006 // 0000000000000110
+ .half 0X0006 // 0000000000000110
+ .half 0X0006 // 0000000000000110
+ .half 0X0006 // 0000000000000110
+ .half 0X0006 // 0000000000000110
+ .half 0X000C // 0000000000001100
+ .half 0X200C // 0010000000001100
+ .half 0X3838 // 0011100000111000
+ .half 0X1FF0 // 0001111111110000
+ .half 0X07C0 // 0000011111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char36:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X07FC // 0000011111111100
+ .half 0X0FFC // 0000111111111100
+ .half 0X1C18 // 0001110000011000
+ .half 0X3018 // 0011000000011000
+ .half 0X7018 // 0111000000011000
+ .half 0X6018 // 0110000000011000
+ .half 0X6018 // 0110000000011000
+ .half 0X6018 // 0110000000011000
+ .half 0X6018 // 0110000000011000
+ .half 0X6018 // 0110000000011000
+ .half 0X3018 // 0011000000011000
+ .half 0X3018 // 0011000000011000
+ .half 0X1C18 // 0001110000011000
+ .half 0X0FFC // 0000111111111100
+ .half 0X07FC // 0000011111111100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char37:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3FFE // 0011111111111110
+ .half 0X3FFE // 0011111111111110
+ .half 0X3018 // 0011000000011000
+ .half 0X3018 // 0011000000011000
+ .half 0x3618 // 0011011000011000
+ .half 0X0618 // 0000011000011000
+ .half 0X07F8 // 0000011111111000
+ .half 0X07F8 // 0000011111111000
+ .half 0X0618 // 0000011000011000
+ .half 0X0618 // 0000011000011000
+ .half 0X3018 // 0011000000011000
+ .half 0X3018 // 0011000000011000
+ .half 0X3018 // 0011000000011000
+ .half 0X3FFE // 0011111111111110
+ .half 0X3FFE // 0011111111111110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char38:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3FFE // 0011111111111110
+ .half 0X3FFE // 0011111111111110
+ .half 0X3018 // 0011000000011000
+ .half 0X3018 // 0011000000011000
+ .half 0x3618 // 0011011000011000
+ .half 0X0618 // 0000011000011000
+ .half 0X07F8 // 0000011111111000
+ .half 0X07F8 // 0000011111111000
+ .half 0X0618 // 0000011000011000
+ .half 0X0618 // 0000011000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X01FE // 0000000111111110
+ .half 0X01FE // 0000000111111110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char39:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0x37C0 // 0011011111000000
+ .half 0X3FF0 // 0011111111110000
+ .half 0X3C38 // 0011110000111000
+ .half 0X380C // 0011100000001100
+ .half 0X300C // 0011000000001100
+ .half 0X0006 // 0000000000000110
+ .half 0X0006 // 0000000000000110
+ .half 0X0006 // 0000000000000110
+ .half 0X7F06 // 0111111100000110
+ .half 0X7F06 // 0111111100000110
+ .half 0X300C // 0011000000001100
+ .half 0X301C // 0011000000011100
+ .half 0X3038 // 0011000000111000
+ .half 0X3FF0 // 0011111111110000
+ .half 0X0FC0 // 0000111111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char40:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3E7C // 0011111001111100
+ .half 0X3E7C // 0011111001111100
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X3E7C // 0011111001111100
+ .half 0X3E7C // 0011111001111100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char41:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X1FFC // 0001111111111100
+ .half 0X1FFC // 0001111111111100
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X1FFC // 0001111111111100
+ .half 0X1FFC // 0001111111111100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char42:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3FE0 // 0011111111100000
+ .half 0X3FE0 // 0011111111100000
+ .half 0X0600 // 0000011000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X0606 // 0000011000000110
+ .half 0X0606 // 0000011000000110
+ .half 0X0606 // 0000011000000110
+ .half 0X0606 // 0000011000000110
+ .half 0X070E // 0000011100001110
+ .half 0X03FE // 0000001111111110
+ .half 0X01F8 // 0000000111111000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char43:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3E7E // 0011111001111110
+ .half 0X3E7E // 0011111001111110
+ .half 0X0C18 // 0000110000011000
+ .half 0X0618 // 0000011000011000
+ .half 0X0318 // 0000001100011000
+ .half 0X0198 // 0000000110011000
+ .half 0X00D8 // 0000000011011000
+ .half 0X03F8 // 0000001111111000
+ .half 0X0738 // 0000011100111000
+ .half 0X0618 // 0000011000011000
+ .half 0X0C18 // 0000110000011000
+ .half 0X0C18 // 0000110000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X787E // 0111100001111110
+ .half 0X707E // 0111000001111110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char44:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X03FE // 0000001111111110
+ .half 0X03FE // 0000001111111110
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X6030 // 0110000000110000
+ .half 0X6030 // 0110000000110000
+ .half 0X6030 // 0110000000110000
+ .half 0X6030 // 0110000000110000
+ .half 0X6030 // 0110000000110000
+ .half 0X7FFE // 0111111111111110
+ .half 0X7FFE // 0111111111111110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char45:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X781E // 0111100000011110
+ .half 0X781E // 0111100000011110
+ .half 0X3C3C // 0011110000111100
+ .half 0X3C3C // 0011110000111100
+ .half 0x346C // 0011010001101100
+ .half 0x366C // 0011011001101100
+ .half 0x324C // 0011001001001100
+ .half 0X33CC // 0011001111001100
+ .half 0X318C // 0011000110001100
+ .half 0X318C // 0011000110001100
+ .half 0X300C // 0011000000001100
+ .half 0X300C // 0011000000001100
+ .half 0X300C // 0011000000001100
+ .half 0X7C3F // 0111110000111111
+ .half 0X7C3F // 0111110000111111
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char46:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X7E1E // 0111111000011110
+ .half 0X7E3E // 0111111000111110
+ .half 0X3078 // 0011000001111000
+ .half 0X3078 // 0011000001111000
+ .half 0X30D8 // 0011000011011000
+ .half 0X30D8 // 0011000011011000
+ .half 0X3198 // 0011000110011000
+ .half 0X3318 // 0011001100011000
+ .half 0X3318 // 0011001100011000
+ .half 0X3618 // 0011011000011000
+ .half 0X3618 // 0011011000011000
+ .half 0X3C18 // 0011110000011000
+ .half 0X3C18 // 0011110000011000
+ .half 0X38FC // 0011100011111100
+ .half 0X30FC // 0011000011111100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char47:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X07E0 // 0000011111100000
+ .half 0X0FF0 // 0000111111110000
+ .half 0X1C38 // 0001110000111000
+ .half 0X300C // 0011000000001100
+ .half 0X700E // 0111000000001110
+ .half 0X6006 // 0110000000000110
+ .half 0X6006 // 0110000000000110
+ .half 0X6006 // 0110000000000110
+ .half 0X6006 // 0110000000000110
+ .half 0X6006 // 0110000000000110
+ .half 0X700C // 0111000000001100
+ .half 0X300C // 0011000000001100
+ .half 0X1C38 // 0001110000111000
+ .half 0X0FF0 // 0000111111110000
+ .half 0X07E0 // 0000011111100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char48:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0FFC // 0000111111111100
+ .half 0X3FFC // 0011111111111100
+ .half 0X3830 // 0011100000110000
+ .half 0X6030 // 0110000000110000
+ .half 0X6030 // 0110000000110000
+ .half 0X6030 // 0110000000110000
+ .half 0X6030 // 0110000000110000
+ .half 0X3830 // 0011100000110000
+ .half 0X3FF0 // 0011111111110000
+ .half 0X0FF0 // 0000111111110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X03FC // 0000001111111100
+ .half 0X03FC // 0000001111111100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char49:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X07E0 // 0000011111100000
+ .half 0X0FF0 // 0000111111110000
+ .half 0X1C38 // 0001110000111000
+ .half 0X300C // 0011000000001100
+ .half 0X300C // 0011000000001100
+ .half 0X6006 // 0110000000000110
+ .half 0X6006 // 0110000000000110
+ .half 0X6006 // 0110000000000110
+ .half 0X6006 // 0110000000000110
+ .half 0X6006 // 0110000000000110
+ .half 0X700E // 0111000000001110
+ .half 0X300C // 0011000000001100
+ .half 0X1C3C // 0001110000111100
+ .half 0X0FF8 // 0000111111111000
+ .half 0X07E0 // 0000011111100000
+ .half 0X0020 // 0000000000100000
+ .half 0X3FF0 // 0011111111110000
+ .half 0X3C30 // 0011110000110000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char50:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X07FE // 0000011111111110
+ .half 0X0FFE // 0000111111111110
+ .half 0X1C18 // 0001110000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1C18 // 0001110000011000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X03F8 // 0000001111111000
+ .half 0X0718 // 0000011100011000
+ .half 0X0618 // 0000011000011000
+ .half 0X0C18 // 0000110000011000
+ .half 0X1C18 // 0001110000011000
+ .half 0X787E // 0111100001111110
+ .half 0X707E // 0111000001111110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char51:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0BE0 // 0000101111100000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X0E1C // 0000111000011100
+ .half 0X0C0C // 0000110000001100
+ .half 0X080C // 0000100000001100
+ .half 0X000C // 0000000000001100
+ .half 0X0078 // 0000000001111000
+ .half 0X07F0 // 0000011111110000
+ .half 0X0F80 // 0000111110000000
+ .half 0X1800 // 0001100000000000
+ .half 0X180C // 0001100000001100
+ .half 0X180C // 0001100000001100
+ .half 0X1C1C // 0001110000011100
+ .half 0X0FFC // 0000111111111100
+ .half 0X03EC // 0000001111101100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char52:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3FFE // 0011111111111110
+ .half 0X3FFE // 0011111111111110
+ .half 0X3186 // 0011000110000110
+ .half 0X3186 // 0011000110000110
+ .half 0X3186 // 0011000110000110
+ .half 0X3186 // 0011000110000110
+ .half 0X2182 // 0010000110000010
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char53:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3E3E // 0011111000111110
+ .half 0X3E3E // 0011111000111110
+ .half 0X180C // 0001100000001100
+ .half 0X180C // 0001100000001100
+ .half 0X180C // 0001100000001100
+ .half 0X180C // 0001100000001100
+ .half 0X180C // 0001100000001100
+ .half 0X180C // 0001100000001100
+ .half 0X180C // 0001100000001100
+ .half 0X180C // 0001100000001100
+ .half 0X180C // 0001100000001100
+ .half 0X1C1C // 0001110000011100
+ .half 0X0C38 // 0000110000111000
+ .half 0X0FF0 // 0000111111110000
+ .half 0X03E0 // 0000001111100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char54:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X7E3F // 0111111000111111
+ .half 0X7E3F // 0111111000111111
+ .half 0X300C // 0011000000001100
+ .half 0X180C // 0001100000001100
+ .half 0X180C // 0001100000001100
+ .half 0X0818 // 0000100000011000
+ .half 0X0C18 // 0000110000011000
+ .half 0X0C30 // 0000110000110000
+ .half 0X0630 // 0000011000110000
+ .half 0X0630 // 0000011000110000
+ .half 0X0660 // 0000011001100000
+ .half 0X0360 // 0000001101100000
+ .half 0X03C0 // 0000001111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char55:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X7E3F // 0111111000111111
+ .half 0X7E3F // 0111111000111111
+ .half 0X3006 // 0011000000000110
+ .half 0X3006 // 0011000000000110
+ .half 0X1086 // 0001000010000110
+ .half 0X1084 // 0001000010000100
+ .half 0X19CC // 0001100111001100
+ .half 0X19CC // 0001100111001100
+ .half 0x1B6C // 0001101101101100
+ .half 0x1B2C // 0001101100101100
+ .half 0x1A2C // 0001101000101100
+ .half 0X0E38 // 0000111000111000
+ .half 0X0E38 // 0000111000111000
+ .half 0X0C18 // 0000110000011000
+ .half 0X0C18 // 0000110000011000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char56:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3E3E // 0011111000111110
+ .half 0X3E3E // 0011111000111110
+ .half 0X0C18 // 0000110000011000
+ .half 0X0E38 // 0000111000111000
+ .half 0X0630 // 0000011000110000
+ .half 0X0360 // 0000001101100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X01C0 // 0000000111000000
+ .half 0X0360 // 0000001101100000
+ .half 0X0770 // 0000011101110000
+ .half 0X0630 // 0000011000110000
+ .half 0X0C18 // 0000110000011000
+ .half 0X1C1C // 0001110000011100
+ .half 0X3E3E // 0011111000111110
+ .half 0X3E3E // 0011111000111110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char57:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X7C7E // 0111110001111110
+ .half 0X7C7E // 0111110001111110
+ .half 0X1818 // 0001100000011000
+ .half 0X1830 // 0001100000110000
+ .half 0X0C30 // 0000110000110000
+ .half 0X0660 // 0000011001100000
+ .half 0X06E0 // 0000011011100000
+ .half 0X03C0 // 0000001111000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0FF0 // 0000111111110000
+ .half 0X0FF0 // 0000111111110000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char58:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1C18 // 0001110000011000
+ .half 0X0E18 // 0000111000011000
+ .half 0X0618 // 0000011000011000
+ .half 0X0318 // 0000001100011000
+ .half 0X0380 // 0000001110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X18E0 // 0001100011100000
+ .half 0X1870 // 0001100001110000
+ .half 0X1830 // 0001100000110000
+ .half 0X1818 // 0001100000011000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char [
+Char59:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X03E0 // 0000001111100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char <bh>
+Char60:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0018 // 0000000000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0600 // 0000011000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char ]
+Char61:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X03E0 // 0000001111100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X0300 // 0000001100000000
+ .half 0X03E0 // 0000001111100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char ^
+Char62:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0080 // 0000000010000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X0360 // 0000001101100000
+ .half 0X0630 // 0000011000110000
+ .half 0X0C18 // 0000110000011000
+ .half 0X0808 // 0000100000001000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char63:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0XFFFF // 1111111111111111
+ .half 0XFFFF // 1111111111111111
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char `
+Char64:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0018 // 0000000000011000
+ .half 0X0078 // 0000000001111000
+ .half 0X00E0 // 0000000011100000
+ .half 0X0300 // 0000001100000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char65:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X07E0 // 0000011111100000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X1C30 // 0001110000110000
+ .half 0X1800 // 0001100000000000
+ .half 0X1FE0 // 0001111111100000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X181C // 0001100000011100
+ .half 0X180C // 0001100000001100
+ .half 0X180C // 0001100000001100
+ .half 0X1E1C // 0001111000011100
+ .half 0x7BF8 // 0111101111111000
+ .half 0x79F0 // 0111100111110000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char66:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X001E // 0000000000011110
+ .half 0X001E // 0000000000011110
+ .half 0X0018 // 0000000000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X0F98 // 0000111110011000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X3878 // 0011100001111000
+ .half 0X3038 // 0011000000111000
+ .half 0X6018 // 0110000000011000
+ .half 0X6018 // 0110000000011000
+ .half 0X6018 // 0110000000011000
+ .half 0X6018 // 0110000000011000
+ .half 0X3038 // 0011000000111000
+ .half 0X3878 // 0011100001111000
+ .half 0X1FDE // 0001111111011110
+ .half 0X0F9E // 0000111110011110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char67:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0x1BE0 // 0001101111100000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1E1C // 0001111000011100
+ .half 0X1C0C // 0001110000001100
+ .half 0X1806 // 0001100000000110
+ .half 0X0006 // 0000000000000110
+ .half 0X0006 // 0000000000000110
+ .half 0X0006 // 0000000000000110
+ .half 0X180C // 0001100000001100
+ .half 0X1C1C // 0001110000011100
+ .half 0X0FF8 // 0000111111111000
+ .half 0X03E0 // 0000001111100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char68:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X1E00 // 0001111000000000
+ .half 0X1E00 // 0001111000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X19F0 // 0001100111110000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1E1C // 0001111000011100
+ .half 0X1C0C // 0001110000001100
+ .half 0X1806 // 0001100000000110
+ .half 0X1806 // 0001100000000110
+ .half 0X1806 // 0001100000000110
+ .half 0X1806 // 0001100000000110
+ .half 0X1C0E // 0001110000001110
+ .half 0X1E1C // 0001111000011100
+ .half 0x7BF8 // 0111101111111000
+ .half 0x79F0 // 0111100111110000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char69:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X03E0 // 0000001111100000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X1C1C // 0001110000011100
+ .half 0X380C // 0011100000001100
+ .half 0X3006 // 0011000000000110
+ .half 0X3FFE // 0011111111111110
+ .half 0X3FFE // 0011111111111110
+ .half 0X0006 // 0000000000000110
+ .half 0X000E // 0000000000001110
+ .half 0X3C1C // 0011110000011100
+ .half 0X1FF8 // 0001111111111000
+ .half 0X07E0 // 0000011111100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char70:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3F00 // 0011111100000000
+ .half 0X3F80 // 0011111110000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char71:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0x79E0 // 0111100111100000
+ .half 0X7FF0 // 0111111111110000
+ .half 0X1E38 // 0001111000111000
+ .half 0X181C // 0001100000011100
+ .half 0X180C // 0001100000001100
+ .half 0X180C // 0001100000001100
+ .half 0X180C // 0001100000001100
+ .half 0X181C // 0001100000011100
+ .half 0X1C38 // 0001110000111000
+ .half 0X1FF0 // 0001111111110000
+ .half 0X19E0 // 0001100111100000
+ .half 0X1800 // 0001100000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0FE0 // 0000111111100000
+ .half 0X03E0 // 0000001111100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char72:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X001E // 0000000000011110
+ .half 0X001E // 0000000000011110
+ .half 0X0018 // 0000000000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X0798 // 0000011110011000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X1C78 // 0001110001111000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X7E7E // 0111111001111110
+ .half 0X7E7E // 0111111001111110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char73:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X01F8 // 0000000111111000
+ .half 0X01F8 // 0000000111111000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X3FFC // 0011111111111100
+ .half 0X3FFC // 0011111111111100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char74:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0700 // 0000011100000000
+ .half 0X0700 // 0000011100000000
+ .half 0X0700 // 0000011100000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0C00 // 0000110000000000
+ .half 0X0600 // 0000011000000000
+ .half 0X07F8 // 0000011111111000
+ .half 0X01F0 // 0000000111110000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char75:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X003C // 0000000000111100
+ .half 0X003C // 0000000000111100
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X3E30 // 0011111000110000
+ .half 0X3E30 // 0011111000110000
+ .half 0X0630 // 0000011000110000
+ .half 0X0330 // 0000001100110000
+ .half 0X01B0 // 0000000110110000
+ .half 0X01F0 // 0000000111110000
+ .half 0X03F0 // 0000001111110000
+ .half 0X0730 // 0000011100110000
+ .half 0X0E30 // 0000111000110000
+ .half 0X1C30 // 0001110000110000
+ .half 0X7C3C // 0111110000111100
+ .half 0X7C3C // 0111110000111100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char76:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X01F8 // 0000000111111000
+ .half 0X01F8 // 0000000111111000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X3FFC // 0011111111111100
+ .half 0X3FFC // 0011111111111100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char77:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3CEF // 0011110011100111
+ .half 0X3FFF // 0011111111111111
+ .half 0x638C // 0110001110001100
+ .half 0X618C // 0110000110001100
+ .half 0X618C // 0110000110001100
+ .half 0X618C // 0110000110001100
+ .half 0X618C // 0110000110001100
+ .half 0X618C // 0110000110001100
+ .half 0X618C // 0110000110001100
+ .half 0X618C // 0110000110001100
+ .half 0XE79F // 1110011110011111
+ .half 0XE79F // 1110011110011111
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char78:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X079E // 0000011110011110
+ .half 0X0FFE // 0000111111111110
+ .half 0X1C78 // 0001110001111000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X7E7E // 0111111001111110
+ .half 0X7E7E // 0111111001111110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char79:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X03E0 // 0000001111100000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X1C1C // 0001110000011100
+ .half 0X180C // 0001100000001100
+ .half 0X3006 // 0011000000000110
+ .half 0X3006 // 0011000000000110
+ .half 0X3006 // 0011000000000110
+ .half 0X3006 // 0011000000000110
+ .half 0X180C // 0001100000001100
+ .half 0X1C1C // 0001110000011100
+ .half 0X0FF8 // 0000111111111000
+ .half 0X03E0 // 0000001111100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char80:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0F9E // 0000111110011110
+ .half 0X1FFE // 0001111111111110
+ .half 0X3878 // 0011100001111000
+ .half 0X3038 // 0011000000111000
+ .half 0X6018 // 0110000000011000
+ .half 0X6018 // 0110000000011000
+ .half 0X6018 // 0110000000011000
+ .half 0X6018 // 0110000000011000
+ .half 0X7038 // 0111000000111000
+ .half 0X3878 // 0011100001111000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X0F98 // 0000111110011000
+ .half 0X0018 // 0000000000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X0018 // 0000000000011000
+ .half 0X01FE // 0000000111111110
+ .half 0X01FE // 0000000111111110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char81:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X79F0 // 0111100111110000
+ .half 0x7BF8 // 0111101111111000
+ .half 0X1E1C // 0001111000011100
+ .half 0X1C0C // 0001110000001100
+ .half 0X1806 // 0001100000000110
+ .half 0X1806 // 0001100000000110
+ .half 0X1806 // 0001100000000110
+ .half 0X1806 // 0001100000000110
+ .half 0X1C0E // 0001110000001110
+ .half 0X1E1C // 0001111000011100
+ .half 0x1BF8 // 0001101111111000
+ .half 0X19F0 // 0001100111110000
+ .half 0X1800 // 0001100000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X1800 // 0001100000000000
+ .half 0X7F80 // 0111111110000000
+ .half 0X7F80 // 0111111110000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char82:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X3C7C // 0011110001111100
+ .half 0X7F7C // 0111111101111100
+ .half 0x23E0 // 0010001111100000
+ .half 0X00E0 // 0000000011100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0060 // 0000000001100000
+ .half 0X0FFC // 0000111111111100
+ .half 0X0FFC // 0000111111111100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char83:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0BF0 // 0000101111110000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X0E1C // 0000111000011100
+ .half 0X0C0C // 0000110000001100
+ .half 0X001C // 0000000000011100
+ .half 0X07F8 // 0000011111111000
+ .half 0X0FE0 // 0000111111100000
+ .half 0X1800 // 0001100000000000
+ .half 0X180C // 0001100000001100
+ .half 0X1C1C // 0001110000011100
+ .half 0X0FFC // 0000111111111100
+ .half 0X07EC // 0000011111101100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char84:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0FFE // 0000111111111110
+ .half 0X0FFE // 0000111111111110
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X0030 // 0000000000110000
+ .half 0X3870 // 0011100001110000
+ .half 0X1FE0 // 0001111111100000
+ .half 0X07C0 // 0000011111000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char85:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X1F1E // 0001111100011110
+ .half 0X1F1E // 0001111100011110
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1818 // 0001100000011000
+ .half 0X1E38 // 0001111000111000
+ .half 0X7FF0 // 0111111111110000
+ .half 0X79E0 // 0111100111100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char86:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0XFC7E // 1111110001111110
+ .half 0XFC7E // 1111110001111110
+ .half 0X3018 // 0011000000011000
+ .half 0X3038 // 0011000000111000
+ .half 0X1830 // 0001100000110000
+ .half 0X1830 // 0001100000110000
+ .half 0X0C60 // 0000110001100000
+ .half 0X0C60 // 0000110001100000
+ .half 0X06C0 // 0000011011000000
+ .half 0X06C0 // 0000011011000000
+ .half 0X0380 // 0000001110000000
+ .half 0X0380 // 0000001110000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char87:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0XF81F // 1111100000011111
+ .half 0XF81F // 1111100000011111
+ .half 0X6006 // 0110000000000110
+ .half 0X2184 // 0010000110000100
+ .half 0X338C // 0011001110001100
+ .half 0X33CC // 0011001111001100
+ .half 0x13C8 // 0001001111001000
+ .half 0x1A48 // 0001101001001000
+ .half 0X1E78 // 0001111001111000
+ .half 0X1E70 // 0001111001110000
+ .half 0X0C30 // 0000110000110000
+ .half 0X0C30 // 0000110000110000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char88:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X7E7E // 0111111001111110
+ .half 0X7E7E // 0111111001111110
+ .half 0X0C38 // 0000110000111000
+ .half 0X0670 // 0000011001110000
+ .half 0X07E0 // 0000011111100000
+ .half 0X0380 // 0000001110000000
+ .half 0X03C0 // 0000001111000000
+ .half 0X0660 // 0000011001100000
+ .half 0X0C30 // 0000110000110000
+ .half 0X1818 // 0001100000011000
+ .half 0X7C7E // 0111110001111110
+ .half 0X7C7E // 0111110001111110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char89:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X7C7E // 0111110001111110
+ .half 0X7C3E // 0111110000111110
+ .half 0X181C // 0001100000011100
+ .half 0X1818 // 0001100000011000
+ .half 0X0C30 // 0000110000110000
+ .half 0X0C30 // 0000110000110000
+ .half 0X0660 // 0000011001100000
+ .half 0X0660 // 0000011001100000
+ .half 0X03C0 // 0000001111000000
+ .half 0X03C0 // 0000001111000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X00C0 // 0000000011000000
+ .half 0X0060 // 0000000001100000
+ .half 0X01FE // 0000000111111110
+ .half 0X01FE // 0000000111111110
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// cha
+Char90:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X0C18 // 0000110000011000
+ .half 0X0E18 // 0000111000011000
+ .half 0X0700 // 0000011100000000
+ .half 0X0380 // 0000001110000000
+ .half 0X01C0 // 0000000111000000
+ .half 0X00E0 // 0000000011100000
+ .half 0X1870 // 0001100001110000
+ .half 0X1838 // 0001100000111000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X1FF8 // 0001111111111000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char {
+Char91:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0E00 // 0000111000000000
+ .half 0X0F00 // 0000111100000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X00E0 // 0000000011100000
+ .half 0X0070 // 0000000001110000
+ .half 0X00E0 // 0000000011100000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0F00 // 0000111100000000
+ .half 0X0E00 // 0000111000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char |
+Char92:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char }
+Char93:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0070 // 0000000001110000
+ .half 0X00F0 // 0000000011110000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0700 // 0000011100000000
+ .half 0X0E00 // 0000111000000000
+ .half 0X0700 // 0000011100000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X0180 // 0000000110000000
+ .half 0X00F0 // 0000000011110000
+ .half 0X0070 // 0000000001110000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+// char ~
+Char94:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X20F0 // 0010000011110000
+ .half 0X3FFC // 0011111111111100
+ .half 0X0F04 // 0000111100000100
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+
+// cha
+Char95:
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X03e0 // 0000001111100000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X0FF8 // 0000111111111000
+ .half 0X03e0 // 0000001111100000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+
+//
+// TEMPTEMP Add four halfwords here to keep garbage from printing on the screen
+// when the bullet character comes out. Fix this by compressing all the font
+// characters and have the output routine put out zeros at the top and
+// bottom of the fonts.
+//
+
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+ .half 0X0000 // 0000000000000000
+#endif
diff --git a/private/ntos/fw/mips/jxfwhal.h b/private/ntos/fw/mips/jxfwhal.h
new file mode 100644
index 000000000..53993d94b
--- /dev/null
+++ b/private/ntos/fw/mips/jxfwhal.h
@@ -0,0 +1,94 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxfwhal.h
+
+Abstract:
+
+ This header file defines the private Hardware Architecture Layer (HAL)
+ Jazz specific interfaces, defines and structures.
+
+Author:
+
+ Jeff Havens (jhavens) 09-Aug-91
+
+
+Revision History:
+
+--*/
+
+#ifndef _JXFWHAL_
+#define _JXFWHAL_
+
+
+//
+// Define global data used to locate the EISA control space and the realtime
+// clock registers.
+//
+
+extern PVOID HalpEisaControlBase;
+extern PVOID HalpRealTimeClockBase;
+
+//
+// Define adapter object structure.
+//
+
+typedef struct _ADAPTER_OBJECT {
+ CSHORT Type;
+ CSHORT Size;
+ ULONG MapRegistersPerChannel;
+ PVOID AdapterBaseVa;
+ PVOID MapRegisterBase;
+ ULONG NumberOfMapRegisters;
+ BOOLEAN AdapterInUse;
+ UCHAR ChannelNumber;
+ UCHAR AdapterNumber;
+ UCHAR AdapterMode;
+ PUCHAR PagePort;
+} ADAPTER_OBJECT;
+
+//
+// Define function prototypes.
+//
+
+PADAPTER_OBJECT
+HalpAllocateEisaAdapter(
+ IN PDEVICE_DESCRIPTION DeviceDescription
+ );
+
+BOOLEAN
+HalpCreateEisaStructures(
+ VOID
+ );
+
+VOID
+HalpDisableEisaInterrupt(
+ IN CCHAR Vector
+ );
+
+BOOLEAN
+HalpEisaDispatch(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ );
+
+VOID
+HalpEisaMapTransfer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+VOID
+HalpEnableEisaInterrupt(
+ IN CCHAR Vector,
+ IN KINTERRUPT_MODE InterruptMode
+ );
+
+#define HalpAllocateEisaAdapter(DeviceDescritption) NULL
+
+#endif // _JXFWHAL_
diff --git a/private/ntos/fw/mips/jxhwsup.c b/private/ntos/fw/mips/jxhwsup.c
new file mode 100644
index 000000000..6fe09d5b4
--- /dev/null
+++ b/private/ntos/fw/mips/jxhwsup.c
@@ -0,0 +1,1512 @@
+#if defined(JAZZ) || defined(DUO)
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ jxhwsup.c
+
+Abstract:
+
+ This module contains the IopXxx routines for the NT OS/2 I/O system that
+ are hardware dependent. Were these routines not hardware dependent,
+ they would normally reside in the internal.c module.
+
+Author:
+
+ Jeff Havens (jhavens) 14-Feb-1990
+
+Environment:
+
+ Kernel mode, local to I/O system
+
+Revision History:
+
+
+--*/
+#include "fwp.h"
+#include "jxfwhal.h"
+#include "eisa.h"
+#include "fwstring.h"
+
+
+
+
+PADAPTER_OBJECT HalpInternalAdapters[8];
+PADAPTER_OBJECT HalpEisaAdapter[8];
+PTRANSLATION_ENTRY FreeTranslationEntry = NULL;
+
+VOID
+IopAllocateCommonBuffer(
+ IN PVOID NonCachedExtension,
+ IN ULONG NonCachedExtensionSize,
+ OUT PPHYSICAL_ADDRESS LogicalAddress
+ );
+
+PADAPTER_OBJECT
+IopAllocateAdapter(
+ IN ULONG MapRegistersPerChannel,
+ IN PVOID AdapterBaseVa,
+ IN PVOID MapRegisterBase
+ );
+
+PADAPTER_OBJECT
+IopAllocateEisaAdapter(
+ IN PDEVICE_DESCRIPTION DeviceDescriptor
+ );
+
+#ifndef DUO
+
+PADAPTER_OBJECT
+HalGetAdapter(
+ IN PDEVICE_DESCRIPTION DeviceDescription,
+ IN OUT PULONG NumberOfMapRegisters
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the appropriate adapter object for the device defined
+ in the device description structure. Three bus types are supported for the
+ Jazz system: Internal, Isa, and Eisa.
+
+Arguments:
+
+ DeviceDescription - Supplies a description of the deivce.
+
+ NumberOfMapRegisters - Returns the maximum number of map registers which
+ may be allocated by the device driver.
+
+Return Value:
+
+ A pointer to the requested adpater object or NULL if an adapter could not
+ be created.
+
+--*/
+
+{
+ PADAPTER_OBJECT adapterObject;
+
+ //
+ // Make sure this is the correct version.
+ //
+
+ if (DeviceDescription->Version != DEVICE_DESCRIPTION_VERSION) {
+
+ return(NULL);
+
+ }
+
+ //
+ // Set the maximum number of map registers if requested.
+ //
+
+ if (NumberOfMapRegisters != NULL) {
+
+ //
+ // Return half the total number of map registers per channel.
+ //
+
+ *NumberOfMapRegisters = DMA_TRANSLATION_LIMIT / sizeof(TRANSLATION_ENTRY) -10;
+ }
+
+ if (DeviceDescription->InterfaceType == Internal) {
+
+
+ //
+ // Return the adapter pointer for internal adapters.
+ //
+ // If this is a master controler such as the SONIC then return the
+ // last channel.
+ //
+
+ if (DeviceDescription->Master) {
+
+ //
+ // Create an adapter if necessary.
+ //
+
+ if (HalpInternalAdapters[7] == NULL) {
+
+ HalpInternalAdapters[7] = IopAllocateAdapter(
+ 0,
+ (PVOID) &(DMA_CONTROL)->Channel[7],
+ NULL
+ );
+
+ }
+
+ return(HalpInternalAdapters[7]);
+
+ }
+
+ //
+ // Make sure the DMA channel range is valid. Only use channels 0-6.
+ //
+
+ if (DeviceDescription->DmaChannel > 6) {
+
+ return(NULL);
+ }
+
+ //
+ // If necessary allocate an adapter; otherwise,
+ // just return the adapter for the requested channel.
+ //
+
+ if (HalpInternalAdapters[DeviceDescription->DmaChannel] == NULL) {
+
+ HalpInternalAdapters[DeviceDescription->DmaChannel] =
+ IopAllocateAdapter(
+ 0,
+ (PVOID) &(DMA_CONTROL)->Channel[DeviceDescription->DmaChannel],
+ NULL
+ );
+
+ }
+
+ return(HalpInternalAdapters[DeviceDescription->DmaChannel]);
+ }
+
+ //
+ // If the request is for a unsupported bus then return NULL.
+ //
+
+ if (DeviceDescription->InterfaceType != Isa &&
+ DeviceDescription->InterfaceType != Eisa) {
+
+ //
+ // This bus type is unsupported return NULL.
+ //
+
+ return(NULL);
+ }
+
+ //
+ // Create an adapter object.
+ //
+
+ adapterObject = IopAllocateEisaAdapter( DeviceDescription );
+
+ return(adapterObject);
+}
+#else
+
+PADAPTER_OBJECT
+HalGetAdapter(
+ IN PDEVICE_DESCRIPTION DeviceDescription,
+ IN OUT PULONG NumberOfMapRegisters
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the appropriate adapter object for the device defined
+ in the device description structure. Three bus types are supported for the
+ Jazz system: Internal, Isa, and Eisa.
+
+Arguments:
+
+ DeviceDescription - Supplies a description of the deivce.
+
+ NumberOfMapRegisters - Returns the maximum number of map registers which
+ may be allocated by the device driver.
+
+Return Value:
+
+ A pointer to the requested adpater object or NULL if an adapter could not
+ be created.
+
+--*/
+
+{
+ PADAPTER_OBJECT adapterObject;
+ UCHAR adapterMode;
+
+ //
+ // Make sure this is the correct version.
+ //
+
+ if (DeviceDescription->Version != DEVICE_DESCRIPTION_VERSION) {
+
+ return(NULL);
+
+ }
+
+ //
+ // Set the maximum number of map registers if requested.
+ //
+
+ if (NumberOfMapRegisters != NULL) {
+
+ //
+ // Return half the total number of map registers per channel.
+ //
+
+ *NumberOfMapRegisters = DMA_TRANSLATION_LIMIT / sizeof(TRANSLATION_ENTRY) -10;
+ }
+
+ if (DeviceDescription->InterfaceType == Internal) {
+
+ //
+ // Return the adapter pointer for internal adapters.
+ //
+ // If this is a master controler return NULL; No adapter object is
+ // needed.
+ //
+
+ if (DeviceDescription->Master) {
+
+ adapterObject = IopAllocateAdapter(0,NULL,NULL);
+ adapterObject->PagePort = ~0;
+ adapterMode = 0;
+ ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE;
+ adapterObject->AdapterMode = adapterMode;
+ return (adapterObject);
+
+ } else {
+
+ //
+ // Internal channels not supported
+ //
+
+ return(NULL);
+ }
+
+ }
+
+ //
+ // If the request is for a unsupported bus then return NULL.
+ //
+
+ if ((DeviceDescription->InterfaceType != Isa) &&
+ (DeviceDescription->InterfaceType != Eisa)) {
+
+ //
+ // This bus type is unsupported return NULL.
+ //
+
+ return(NULL);
+ }
+
+ //
+ // Create an adapter object.
+ //
+
+ adapterObject = IopAllocateEisaAdapter(DeviceDescription);
+
+ return(adapterObject);
+}
+
+#endif
+
+#if 0
+VOID
+FixIsp(
+ )
+/*++
+
+Routine Description:
+
+ This is a temporary routine to set the ISP back to a usable way
+ after the eisa config stuff screws it.
+ This routine is to be used with the ncrc700 ISA debug board.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+{
+
+ //
+ // Initialize the Isp For Channel 5 Isa master
+ //
+
+ WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD2, 1);
+ WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD4, 5);
+ WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD8, 0);
+ WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xC6, 0);
+ WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xC6, 0);
+ WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD6, 0xD9);
+ WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD4, 0x1);
+
+
+ //
+ // Initialize the Isp For Channel 6 Isa master
+ //
+
+ //WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD2, 2);
+ //WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD4, 6);
+ //WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD8, 0);
+ //WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xCA, 0);
+ //WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xCA, 0);
+ //WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD6, 0xDA);
+ //WRITE_REGISTER_UCHAR(EISA_IO_VIRTUAL_BASE + 0xD4, 0x2);
+}
+#endif
+
+
+BOOLEAN
+HalTranslateBusAddress(
+ IN INTERFACE_TYPE InterfaceType,
+ IN ULONG BusNumber,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the system physical address for a specified I/O bus
+ address. The return value is suitable for use in a subsequent call to
+ MmMapIoSpace.
+
+Arguments:
+
+ InterfaceType - Supplies the type of bus which the address is for.
+
+ BusNumber - Supplies the bus number for the device.
+
+ BusAddress - Supplies the bus relative address.
+
+ AddressSpace - Supplies the address space number for the device: 0 for
+ memory and 1 for I/O space. Returns the address space on this system.
+
+Return Value:
+
+ Returns the system physical address for the specificed bus address.
+
+--*/
+
+{
+ TranslatedAddress->HighPart = 0;
+ TranslatedAddress->LowPart = 0;
+
+ //
+ // If this is for the internal bus then just return the passed parameter.
+ //
+
+ if (InterfaceType == Internal) {
+
+ //
+ // Return the passed parameters.
+ //
+
+
+ TranslatedAddress->LowPart = BusAddress.LowPart;
+ return(TRUE);
+ }
+
+ if (InterfaceType != Isa && InterfaceType != Eisa) {
+
+ //
+ // Not on this system return nothing.
+ //
+
+ *AddressSpace = 0;
+ return (FALSE);
+ }
+
+ //
+ // Jazz only has one I/O bus which is an EISA, so the bus number is unused.
+ //
+ // Determine the address based on whether the bus address is in I/O space
+ // or bus memory space.
+ //
+
+ if (*AddressSpace) {
+
+ //
+ // The address is in I/O space.
+ //
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = BusAddress.LowPart + EISA_CONTROL_PHYSICAL_BASE;
+ return(TRUE);
+
+ } else {
+
+ //
+ // The address is in memory space.
+ //
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = BusAddress.LowPart + EISA_MEMORY_PHYSICAL_BASE;
+ return(TRUE);
+ }
+}
+
+PADAPTER_OBJECT
+IopAllocateAdapter(
+ IN ULONG MapRegistersPerChannel,
+ IN PVOID AdapterBaseVa,
+ IN PVOID MapRegisterBase
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates and initializes an adapter object to represent an
+ adapter or a DMA controller on the system.
+
+Arguments:
+
+ MapRegistersPerChannel - Unused.
+
+ AdapterBaseVa - Base virtual address of the adapter itself. If AdpaterBaseVa
+ is NULL then the MasterAdapterObject is allocated.
+
+ MapRegisterBase - Unused.
+
+Return Value:
+
+ The function value is a pointer to the allocate adapter object.
+
+--*/
+
+{
+
+ PADAPTER_OBJECT AdapterObject;
+ ULONG Size;
+ ULONG Mode;
+
+ //
+ // Determine the size of the adapter.
+ //
+
+ Size = sizeof( ADAPTER_OBJECT );
+
+ //
+ // Now create the adapter object.
+ //
+
+ AdapterObject = FwAllocatePool(Size);
+
+ //
+ // If the adapter object was successfully created, then attempt to insert
+ // it into the the object table.
+ //
+
+ if (AdapterObject) {
+
+ //
+ // Initialize the adapter object itself.
+ //
+
+ AdapterObject->Type = IO_TYPE_ADAPTER;
+ AdapterObject->Size = Size;
+ AdapterObject->MapRegistersPerChannel =
+ DMA_TRANSLATION_LIMIT / sizeof( TRANSLATION_ENTRY) -10;
+ AdapterObject->AdapterBaseVa = AdapterBaseVa;
+ AdapterObject->PagePort = NULL;
+ AdapterObject->AdapterInUse = FALSE;
+
+ //
+ // Read the map register base from the Dma registers
+ // The last 10 pages are used to map NonCachedExtension.
+ //
+ AdapterObject->MapRegisterBase = (PVOID)(READ_REGISTER_ULONG(&DMA_CONTROL->TranslationBase.Long) | KSEG1_BASE);
+
+#ifndef DUO
+ //
+ // Initialize the DMA mode registers for the Floppy, SCSI and Sound.
+ // The initialization values come fomr the Jazz System Specification.
+ //
+
+ Mode = 0;
+ ((PDMA_CHANNEL_MODE) &Mode)->AccessTime = ACCESS_80NS;
+ ((PDMA_CHANNEL_MODE) &Mode)->TransferWidth = WIDTH_16BITS;
+ ((PDMA_CHANNEL_MODE) &Mode)->InterruptEnable = 0;
+ WRITE_REGISTER_ULONG(
+ &DMA_CONTROL->Channel[SCSI_CHANNEL].Mode.Long,
+ (ULONG) Mode
+ );
+
+ ((PDMA_CHANNEL_MODE) &Mode)->AccessTime = ACCESS_120NS;
+ ((PDMA_CHANNEL_MODE) &Mode)->TransferWidth = WIDTH_8BITS;
+ ((PDMA_CHANNEL_MODE) &Mode)->InterruptEnable = 0;
+ WRITE_REGISTER_ULONG(
+ &DMA_CONTROL->Channel[FLOPPY_CHANNEL].Mode.Long,
+ (ULONG) Mode
+ );
+#endif
+
+ } else {
+
+ //
+ // An error was incurred for some reason. Set the return value
+ // to NULL.
+ //
+
+ return(NULL);
+ }
+
+ return AdapterObject;
+
+}
+
+VOID
+IopAllocateCommonBuffer(
+ IN PVOID NonCachedExtension,
+ IN ULONG NonCachedExtensionSize,
+ OUT PPHYSICAL_ADDRESS LogicalAddress
+ )
+/*++
+
+Routine Description:
+
+ This routine sets the mapping in the IO translation table to
+ map the non cached memory (KSEG1) already allocated supplied
+ by NonCachedExtension.
+ It saves the IO logical address in DeviceExtension->PhysicalCommonBuffer
+ so that SpGetPhysicalAddress can return this address.
+
+Arguments:
+
+ NonCachedExtension
+
+ NonCachedExtensionSize - Supplies the size of the non cached extension.
+
+ LogicalAddress - Where the IO logical address is returned.
+
+Return Value:
+
+ Returns STATUS_SUCCESS unless too many map registers are requested.
+
+Notes:
+
+ Note that this routine MUST be invoked at DISPATCH_LEVEL or above.
+
+--*/
+
+{
+ PTRANSLATION_ENTRY DmaMapRegister;
+ ULONG BasePage;
+ ULONG NumberOfPages;
+
+ //
+ // If this is the first call.
+ // Initialize FreeTranslationEntry to the last 10 pages of the Translation table
+ //
+ if (FreeTranslationEntry == NULL) {
+ FreeTranslationEntry = READ_REGISTER_ULONG(&DMA_CONTROL->TranslationBase.Long);
+ FreeTranslationEntry += DMA_TRANSLATION_LIMIT/sizeof(TRANSLATION_ENTRY) - 10;
+ }
+
+
+ //
+ // Return the IO logical address of the common buffer
+ //
+ LogicalAddress->HighPart = 0;
+ LogicalAddress->LowPart = (FreeTranslationEntry - (PTRANSLATION_ENTRY)(READ_REGISTER_ULONG(&DMA_CONTROL->TranslationBase.Long))) << PAGE_SHIFT;
+ LogicalAddress->LowPart += BYTE_OFFSET(NonCachedExtension);
+
+ DmaMapRegister =(PTRANSLATION_ENTRY)((ULONG)FreeTranslationEntry | KSEG1_BASE);
+
+ BasePage = (ULONG)NonCachedExtension - KSEG1_BASE;
+
+ NumberOfPages = ((BasePage & 0xFFF) + NonCachedExtensionSize + PAGE_SIZE - 1) >> PAGE_SHIFT;
+
+ BasePage &= 0xFFFFF000;
+
+ for (;NumberOfPages;NumberOfPages--) {
+ // ScsiDebugPrint(2,"SpGetCommonBuffer Mapping %lx into %lx\n", BasePage,DmaMapRegister);
+ DmaMapRegister->PageFrame = BasePage;
+ BasePage += PAGE_SIZE;
+ DmaMapRegister++;
+ FreeTranslationEntry++;
+ }
+}
+
+NTSTATUS
+IoAllocateAdapterChannel(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN ULONG NumberOfMapRegisters,
+ IN PDRIVER_CONTROL ExecutionRoutine,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates the adapter channel specified by the adapter object.
+ This is accomplished by placing the device object of the driver that wants
+ to allocate the adapter on the adapter's queue. If the queue is already
+ "busy", then the adapter has already been allocated, so the device object
+ is simply placed onto the queue and waits until the adapter becomes free.
+
+ Once the adapter becomes free (or if it already is), then the driver's
+ execution routine is invoked.
+
+ Also, a number of map registers may be allocated to the driver by specifying
+ a non-zero value for NumberOfMapRegisters. Then the map register must be
+ allocated from the master adapter. Once there are a sufficient number of
+ map registers available, then the execution routine is called and the
+ base address of the allocated map registers in the adapter is also passed
+ to the driver's execution routine.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter control object to allocate to the
+ driver.
+
+ DeviceObject - Pointer to the driver's device object that represents the
+ device allocating the adapter.
+
+ NumberOfMapRegisters - The number of map registers that are to be allocated
+ from the channel, if any.
+
+ ExecutionRoutine - The address of the driver's execution routine that is
+ invoked once the adapter channel (and possibly map registers) have been
+ allocated.
+
+ Context - An untyped longword context parameter passed to the driver's
+ execution routine.
+
+Return Value:
+
+ Returns STATUS_SUCCESS unless too many map registers are requested.
+
+Notes:
+
+ Note that this routine MUST be invoked at DISPATCH_LEVEL or above.
+
+--*/
+
+{
+ IO_ALLOCATION_ACTION action;
+
+ //
+ // Make sure the adapter if free.
+ //
+
+ if (AdapterObject->AdapterInUse) {
+ DbgPrint("IoAllocateAdapterChannel: Called while adapter in use.\n");
+ }
+
+ //
+ // Make sure there are enough map registers.
+ //
+
+ if (NumberOfMapRegisters > AdapterObject->MapRegistersPerChannel) {
+
+ DbgPrint("IoAllocateAdapterChannel: Out of map registers.\n");
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ action = ExecutionRoutine( DeviceObject,
+ DeviceObject->CurrentIrp,
+ AdapterObject->MapRegisterBase,
+ Context );
+
+ //
+ // If the driver wishes to keep the map registers then
+ // increment the current base and decrease the number of existing map
+ // registers.
+ //
+
+ if (action == DeallocateObjectKeepRegisters) {
+
+ AdapterObject->MapRegistersPerChannel -= NumberOfMapRegisters;
+ (PTRANSLATION_ENTRY) AdapterObject->MapRegisterBase +=
+ NumberOfMapRegisters;
+
+ } else if (action == KeepObject) {
+
+ AdapterObject->AdapterInUse = TRUE;
+
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+VOID
+IoFreeMapRegisters(
+ PADAPTER_OBJECT AdapterObject,
+ PVOID MapRegisterBase,
+ ULONG NumberOfMapRegisters
+ )
+/*++
+
+Routine Description:
+
+ This routine deallocates the map registers for the adapter. If there are
+ any queued adapter waiting for an attempt is made to allocate the next
+ entry.
+
+Arguments:
+
+ AdapterObject - The adapter object to where the map register should be
+ returned.
+
+ MapRegisterBase - The map register base of the registers to be deallocated.
+
+ NumberOfMapRegisters - The number of registers to be deallocated.
+
+Return Value:
+
+ None
+
+--+*/
+
+{
+ PTRANSLATION_ENTRY translationEntry;
+
+ //
+ // Determine if this was the last allocation from the adapter. If is was
+ // then free the map registers by restoring the map register base and the
+ // channel count; otherwise the registers are lost. This handles the
+ // normal case.
+ //
+
+ translationEntry = AdapterObject->MapRegisterBase;
+ translationEntry -= NumberOfMapRegisters;
+
+ if (translationEntry == MapRegisterBase) {
+
+ //
+ // The last allocated registers are being freed.
+ //
+
+ AdapterObject->MapRegisterBase = (PVOID) translationEntry;
+ AdapterObject->MapRegistersPerChannel += NumberOfMapRegisters;
+ }
+}
+
+VOID
+IoFreeAdapterChannel(
+ IN PADAPTER_OBJECT AdapterObject
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is invoked to deallocate the specified adapter object.
+ Any map registers that were allocated are also automatically deallocated.
+ No checks are made to ensure that the adapter is really allocated to
+ a device object. However, if it is not, then kernel will bugcheck.
+
+ If another device is waiting in the queue to allocate the adapter object
+ it will be pulled from the queue and its execution routine will be
+ invoked.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter object to be deallocated.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ AdapterObject->AdapterInUse = FALSE;
+}
+
+PHYSICAL_ADDRESS
+IoMapTransfer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PMDL Mdl,
+ IN PVOID MapRegisterBase,
+ IN PVOID CurrentVa,
+ IN OUT PULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is invoked to set up the map registers in the DMA controller
+ to allow a transfer to or from a device.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter object representing the DMA
+ controller channel that has been allocated.
+
+ Mdl - Pointer to the MDL that describes the pages of memory that are
+ being read or written.
+
+ MapRegisterBase - The address of the base map register that has been
+ allocated to the device driver for use in mapping the transfer.
+
+ CurrentVa - Current virtual address in the buffer described by the MDL
+ that the transfer is being done to or from.
+
+ Length - Supplies the length of the transfer. This determines the
+ number of map registers that need to be written to map the transfer.
+ Returns the length of the transfer which was actually mapped.
+
+ WriteToDevice - Boolean value that indicates whether this is a write
+ to the device from memory (TRUE), or vice versa.
+
+Return Value:
+
+ Returns the logical address to be used by bus masters.
+
+--*/
+
+{
+ PTRANSLATION_ENTRY DmaMapRegister = MapRegisterBase;
+ PULONG PageFrameNumber;
+ ULONG NumberOfPages;
+ PHYSICAL_ADDRESS Offset;
+ ULONG i;
+
+ //
+ // Begin by determining where in the buffer this portion of the operation
+ // is taking place.
+ //
+
+ Offset.LowPart = BYTE_OFFSET( (PCHAR) CurrentVa - (PCHAR) Mdl->StartVa );
+ Offset.HighPart = 0;
+
+ PageFrameNumber = (PULONG) (Mdl + 1);
+ NumberOfPages = (Offset.LowPart + *Length + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ PageFrameNumber += (((PCHAR) CurrentVa - (PCHAR) Mdl->StartVa) >> PAGE_SHIFT);
+ for (i = 0; i < NumberOfPages; i++) {
+ (DmaMapRegister++)->PageFrame = (ULONG) *PageFrameNumber++ << PAGE_SHIFT;
+ }
+
+ //
+ // Set the offset to point to the map register plus the offset.
+ //
+
+ Offset.LowPart += ((PTRANSLATION_ENTRY) MapRegisterBase - (PTRANSLATION_ENTRY)
+ (READ_REGISTER_ULONG(&DMA_CONTROL->TranslationBase.Long) | KSEG1_BASE) << PAGE_SHIFT);
+
+ //
+ // Invalidate the translation entry.
+ //
+
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->TranslationInvalidate.Long, 1);
+
+
+ if ( AdapterObject == NULL) {
+ return(Offset);
+ }
+
+ if (AdapterObject->PagePort == NULL) {
+
+ //
+ // Set the local DMA Registers.
+ //
+
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->TranslationInvalidate.Long, 1);
+ WRITE_REGISTER_ULONG(&((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Address.Long, Offset.LowPart);
+ WRITE_REGISTER_ULONG(&((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->ByteCount.Long, *Length);
+ i = 0;
+ ((PDMA_CHANNEL_ENABLE) &i)->ChannelEnable = 1;
+ ((PDMA_CHANNEL_ENABLE) &i)->TransferDirection =
+ WriteToDevice ? DMA_WRITE_OP : DMA_READ_OP;
+ WRITE_REGISTER_ULONG(&((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Enable.Long, i);
+
+ }
+
+ return(Offset);
+}
+
+BOOLEAN
+IoFlushAdapterBuffers(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PMDL Mdl,
+ IN PVOID MapRegisterBase,
+ IN PVOID CurrentVa,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine flushes the DMA adpater object buffers. For the Jazz system
+ its clears the enable flag which aborts the dma.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter object representing the DMA
+ controller channel.
+
+ Mdl - A pointer to a Memory Descriptor List (MDL) that maps the locked-down
+ buffer to/from which the I/O occured.
+
+ MapRegisterBase - A pointer to the base of the map registers in the adapter
+ or DMA controller.
+
+ CurrentVa - The current virtual address in the buffer described the the Mdl
+ where the I/O operation occurred.
+
+ Length - Supplies the length of the transfer.
+
+ WriteToDevice - Supplies a BOOLEAN value that indicates the direction of
+ the data transfer was to the device.
+
+Return Value:
+
+ TRUE - If the transfer was successful.
+
+ FALSE - If there was an error in the transfer.
+
+--*/
+{
+ ULONG i;
+ UCHAR DataByte;
+
+
+ if (AdapterObject == NULL) {
+ return TRUE;
+ }
+ if (AdapterObject->PagePort) {
+
+ //
+ // If this is a master channel, then just return since the DMA
+ // request does not need to be disabled.
+ //
+
+ DataByte = AdapterObject->AdapterMode;
+
+ if (((PDMA_EISA_MODE) &DataByte)->RequestMode == CASCADE_REQUEST_MODE) {
+
+ return(TRUE);
+
+ }
+
+ //
+ // Clear the EISA DMA adapter.
+ //
+
+ if (AdapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber)
+ );
+
+ }
+
+ } else {
+
+ //
+ // Clear on board DMA this must be done, because writes to the
+ // direction bit are disabled while the channel is enabled.
+ //
+
+ i = READ_REGISTER_ULONG(
+ &((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Enable.Long
+ );
+
+ ((PDMA_CHANNEL_ENABLE) &i)->ChannelEnable = 0;
+ WRITE_REGISTER_ULONG(
+ &((PDMA_CHANNEL) AdapterObject->AdapterBaseVa)->Enable.Long,
+ i
+ );
+ }
+
+ return(TRUE);
+}
+
+PHYSICAL_ADDRESS
+MmGetPhysicalAddress (
+ IN PVOID BaseAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the corresponding physical address for a
+ valid virtual address.
+
+Arguments:
+
+ BaseAddress - Supplies the virtual address for which to return the
+ physical address.
+
+Return Value:
+
+ Returns the corresponding physical address.
+
+Environment:
+
+ Kernel mode. Any IRQL level.
+
+--*/
+
+{
+ PHYSICAL_ADDRESS PhysicalAddress;
+
+ PhysicalAddress.HighPart = 0;
+ PhysicalAddress.LowPart = (ULONG)BaseAddress & 0x1fffffff;
+ return(PhysicalAddress);
+}
+
+PVOID
+MmAllocateNonCachedMemory (
+ IN ULONG NumberOfBytes
+ )
+
+/*++
+
+Routine Description:
+
+ This function allocates a range of noncached memory in
+ the non-paged portion of the system address space.
+
+ This routine is designed to be used by a driver's initialization
+ routine to allocate a noncached block of virtual memory for
+ various device specific buffers.
+
+Arguments:
+
+ NumberOfBytes - Supplies the number of bytes to allocate.
+
+Return Value:
+
+ NULL - the specified request could not be satisfied.
+
+ NON-NULL - Returns a pointer (virtual address in the nonpaged portion
+ of the system) to the allocated physically contiguous
+ memory.
+
+Environment:
+
+ Kernel mode, IRQL of APC_LEVEL or below.
+
+--*/
+
+{
+ PVOID BaseAddress;
+
+ //
+ // Allocated the memory.
+ //
+
+ BaseAddress = FwAllocatePool(NumberOfBytes);
+
+ //
+ // Make it non-cached.
+ //
+
+ BaseAddress = (PVOID)((ULONG) BaseAddress | KSEG1_BASE);
+ return BaseAddress;
+}
+
+PVOID
+MmMapIoSpace (
+ IN PHYSICAL_ADDRESS PhysicalAddress,
+ IN ULONG NumberOfBytes,
+ IN BOOLEAN CacheEnable
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the corresponding virtual address for a
+ known physical address.
+
+Arguments:
+
+ PhysicalAddress - Supplies the phiscal address.
+
+ NumberOfBytes - Unused.
+
+ CacheEnable - Unused.
+
+Return Value:
+
+ Returns the corresponding virtual address.
+
+Environment:
+
+ Kernel mode. Any IRQL level.
+
+--*/
+
+{
+
+ PCCHAR VirtualAddress;
+
+ switch ((ULONG) PAGE_ALIGN(PhysicalAddress.LowPart)) {
+#ifndef DUO
+ case SCSI_PHYSICAL_BASE:
+ VirtualAddress = (PVOID) SCSI_VIRTUAL_BASE;
+ break;
+#else
+ case SCSI1_PHYSICAL_BASE:
+ VirtualAddress = (PVOID) SCSI1_VIRTUAL_BASE;
+ break;
+ case SCSI2_PHYSICAL_BASE:
+ VirtualAddress = (PVOID) SCSI2_VIRTUAL_BASE;
+ break;
+#endif
+
+ case EISA_CONTROL_PHYSICAL_BASE:
+ VirtualAddress = (PVOID) EISA_IO_VIRTUAL_BASE;
+ break;
+ case DMA_PHYSICAL_BASE:
+ VirtualAddress = (PVOID) DMA_VIRTUAL_BASE;
+ break;
+ default:
+ if (PhysicalAddress.LowPart >= EISA_MEMORY_PHYSICAL_BASE) {
+ VirtualAddress = (PVOID) EISA_MEMORY_VIRTUAL_BASE;
+ VirtualAddress += PhysicalAddress.LowPart&0xFFFFFF;
+ return(VirtualAddress);
+ }
+ return(NULL);
+ }
+
+ VirtualAddress += BYTE_OFFSET(PhysicalAddress.LowPart);
+
+ return(VirtualAddress);
+}
+
+
+PADAPTER_OBJECT
+IopAllocateEisaAdapter(
+ IN PDEVICE_DESCRIPTION DeviceDescriptor
+ )
+/*++
+
+Routine Description:
+
+ This function allocates an EISA adapter object according to the
+ specification supplied in the device description. The necessary device
+ descriptor information is saved. If there is
+ no existing adapter object for this channel then a new one is allocated.
+ The saved information in the adapter object is used to set the various DMA
+ modes when the channel is allocated or a map transfer is done.
+
+Arguments:
+
+ DeviceDescription - Supplies the description of the device which want to
+ use the DMA adapter.
+
+Return Value:
+
+ Returns a pointer to the newly created adapter object or NULL if one
+ cannot be created.
+
+--*/
+
+{
+ PADAPTER_OBJECT adapterObject;
+ PVOID adapterBaseVa;
+ ULONG channelNumber;
+ ULONG controllerNumber;
+ DMA_EXTENDED_MODE extendedMode;
+ UCHAR adapterMode;
+
+ //
+ // Determine if the the channel number is important. Master cards on
+ // Eisa do not use a channel number.
+ //
+ //
+ // Handle Isa master
+ // Channel 4 cannot be used since it is used for chaining. Return null if
+ // it is requested.
+ //
+
+ if ((DeviceDescriptor->InterfaceType != Isa) ||
+ (DeviceDescriptor->DmaChannel == 4) ||
+ (DeviceDescriptor->DmaChannel > 7)) {
+ return(NULL);
+ }
+
+ //
+ // Set the channel number number.
+ //
+
+ channelNumber = DeviceDescriptor->DmaChannel & 0x03;
+
+ //
+ // Set the adapter base address to the Base address register and controller
+ // number.
+ //
+
+ if (!(DeviceDescriptor->DmaChannel & 0x04)) {
+
+ controllerNumber = 1;
+ adapterBaseVa = (PVOID) &((PEISA_CONTROL)EISA_IO_VIRTUAL_BASE)->Dma1BasePort;
+
+ } else {
+
+ controllerNumber = 2;
+ adapterBaseVa = &((PEISA_CONTROL)EISA_IO_VIRTUAL_BASE)->Dma2BasePort;
+
+ }
+
+ //
+ // Determine if a new adapter object is necessary. If so then allocate it.
+ //
+
+ if (HalpEisaAdapter[DeviceDescriptor->DmaChannel] != NULL) {
+
+ adapterObject = HalpEisaAdapter[DeviceDescriptor->DmaChannel];
+
+ } else {
+
+ //
+ // Allocate an adapter object.
+ //
+
+ adapterObject = (PADAPTER_OBJECT) IopAllocateAdapter(
+ 0,
+ adapterBaseVa,
+ NULL
+ );
+
+ if (adapterObject == NULL) {
+ return(NULL);
+
+ }
+ HalpEisaAdapter[DeviceDescriptor->DmaChannel] = adapterObject;
+ }
+
+ //
+ // Setup the pointers to all the random registers.
+ //
+
+ adapterObject->ChannelNumber = channelNumber;
+
+ if (controllerNumber == 1) {
+
+ switch ((UCHAR)channelNumber) {
+
+ case 0:
+ adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel0;
+ break;
+
+ case 1:
+ adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel1;
+ break;
+
+ case 2:
+ adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel2;
+ break;
+
+ case 3:
+ adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel3;
+ break;
+ }
+
+ //
+ // Set the adapter number.
+ //
+
+ adapterObject->AdapterNumber = 1;
+
+ //
+ // Save the extended mode register address.
+ //
+
+ adapterBaseVa =
+ &((PEISA_CONTROL) EISA_IO_VIRTUAL_BASE)->Dma1ExtendedModePort;
+
+ } else {
+
+ switch (channelNumber) {
+ case 1:
+ adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel5;
+ break;
+
+ case 2:
+ adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel6;
+ break;
+
+ case 3:
+ adapterObject->PagePort = &((PDMA_PAGE) 0)->Channel7;
+ break;
+ }
+
+ //
+ // Set the adapter number.
+ //
+
+ adapterObject->AdapterNumber = 2;
+
+ //
+ // Save the extended mode register address.
+ //
+ adapterBaseVa =
+ &((PEISA_CONTROL) EISA_IO_VIRTUAL_BASE)->Dma2ExtendedModePort;
+
+ }
+
+ //
+ // Initialzie the extended mode port.
+ //
+
+ *((PUCHAR) &extendedMode) = 0;
+ extendedMode.ChannelNumber = channelNumber;
+
+ switch (DeviceDescriptor->DmaSpeed) {
+ case Compatible:
+ extendedMode.TimingMode = COMPATIBLITY_TIMING;
+ break;
+
+ case TypeA:
+ extendedMode.TimingMode = TYPE_A_TIMING;
+ break;
+
+ case TypeB:
+ extendedMode.TimingMode = TYPE_B_TIMING;
+ break;
+
+ case TypeC:
+ extendedMode.TimingMode = BURST_TIMING;
+ break;
+
+ default:
+ return(NULL);
+
+ }
+
+ switch (DeviceDescriptor->DmaWidth) {
+ case Width8Bits:
+ extendedMode.TransferSize = BY_BYTE_8_BITS;
+ break;
+
+ case Width16Bits:
+ extendedMode.TransferSize = BY_BYTE_16_BITS;
+ break;
+
+ case Width32Bits:
+ extendedMode.TransferSize = BY_BYTE_32_BITS;
+ break;
+
+ default:
+ return(NULL);
+
+ }
+
+ ScsiDebugPrint(1,"Isp 1 initialize reg %lx with %lx\r\n",adapterBaseVa, *((PUCHAR)&extendedMode));
+ WRITE_REGISTER_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode));
+
+ //
+ // Initialize the adapter mode register value to the correct parameters,
+ // and save them in the adapter object.
+ //
+
+ adapterMode = 0;
+ ((PDMA_EISA_MODE) &adapterMode)->Channel = adapterObject->ChannelNumber;
+
+ if (DeviceDescriptor->Master) {
+
+ ((PDMA_EISA_MODE) &adapterMode)->RequestMode = CASCADE_REQUEST_MODE;
+
+ //
+ // Set the mode, and enable the request.
+ //
+
+ if (adapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = adapterObject->AdapterBaseVa;
+
+ ScsiDebugPrint(1,"Isp 2 initialize reg %lx with %lx\r\n",&dmaControl->Mode, adapterMode);
+ WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+ ScsiDebugPrint(1,"Isp 3 initialize reg %lx with %lx\r\n",&dmaControl->SingleMask,(UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber));
+
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
+ );
+ } else {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = adapterObject->AdapterBaseVa;
+
+ ScsiDebugPrint(1,"Isp 2 initialize reg %lx with %lx\r\n",&dmaControl->Mode, adapterMode);
+ WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ ScsiDebugPrint(1,"Isp 3 initialize reg %lx with %lx\r\n",&dmaControl->SingleMask,(UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber));
+ WRITE_REGISTER_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
+ );
+
+ }
+
+ } else if (DeviceDescriptor->DemandMode) {
+
+ ((PDMA_EISA_MODE) &adapterMode)->RequestMode = DEMAND_REQUEST_MODE;
+
+ } else {
+
+ ((PDMA_EISA_MODE) &adapterMode)->RequestMode = SINGLE_REQUEST_MODE;
+
+ }
+
+ if (DeviceDescriptor->AutoInitialize) {
+
+ ((PDMA_EISA_MODE) &adapterMode)->AutoInitialize = 1;
+
+ }
+
+ adapterObject->AdapterMode = adapterMode;
+ adapterObject->MapRegisterBase = (PVOID) ((PTRANSLATION_ENTRY)adapterObject->MapRegisterBase + (0x100000>>PAGE_SHIFT));
+ return(adapterObject);
+}
+
+#endif
diff --git a/private/ntos/fw/mips/jxkbd.c b/private/ntos/fw/mips/jxkbd.c
new file mode 100644
index 000000000..dd1602f68
--- /dev/null
+++ b/private/ntos/fw/mips/jxkbd.c
@@ -0,0 +1,491 @@
+#if defined(JAZZ)
+
+
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ jxkbd.c
+
+Abstract:
+
+ This module implements the keyboard boot driver for the Jazz system.
+
+Author:
+
+ David M. Robinson (davidro) 8-Aug-1991
+
+Environment:
+
+ Kernel mode.
+
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#ifdef DUO
+#include "duoint.h"
+#else
+#include "jazzint.h"
+#endif
+#include "iodevice.h"
+#include "string.h"
+
+
+ARC_STATUS
+KeyboardClose (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+KeyboardMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ );
+
+ARC_STATUS
+KeyboardOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ IN OUT PULONG FileId
+ );
+
+ARC_STATUS
+KeyboardRead (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+KeyboardGetReadStatus (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+KeyboardSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+KeyboardWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+KeyboardGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Finfo
+ );
+
+//
+// Define static data.
+//
+BL_DEVICE_ENTRY_TABLE KeyboardEntryTable = {
+ KeyboardClose,
+ KeyboardMount,
+ KeyboardOpen,
+ KeyboardRead,
+ KeyboardGetReadStatus,
+ KeyboardSeek,
+ KeyboardWrite,
+ KeyboardGetFileInformation,
+ (PARC_SET_FILE_INFO_ROUTINE)NULL
+ };
+
+PCHAR KeyboardDevicePath = "multi(0)key(0)keyboard(0)";
+
+KEYBOARD_BUFFER KbdBuffer;
+
+BOOLEAN FwLeftShift;
+BOOLEAN FwRightShift;
+BOOLEAN FwControl;
+BOOLEAN FwAlt;
+BOOLEAN FwCapsLock;
+
+
+//
+// Define prototypes for all routines used by this module.
+//
+
+UCHAR
+FwInputScanCode(
+ VOID
+ );
+
+
+ARC_STATUS
+KeyboardGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Finfo
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns EINVAL as no FileInformation can be
+ returned for the Keyboard driver.
+
+Arguments:
+
+ The arguments are not used.
+
+Return Value:
+
+ EINVAL is returned
+
+--*/
+
+{
+ return EINVAL;
+}
+
+
+ARC_STATUS
+KeyboardClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes the file table entry specified by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+Return Value:
+
+ ESUCCESS is returned
+
+--*/
+
+{
+
+ BlFileTable[FileId].Flags.Open = 0;
+ return ESUCCESS;
+}
+
+ARC_STATUS
+KeyboardMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ return EINVAL;
+}
+
+ARC_STATUS
+KeyboardOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ IN OUT PULONG FileId
+ )
+/*++
+
+Routine Description:
+
+ This is the open routine for the Keyboard device.
+
+Arguments:
+
+ OpenPath - Supplies the pathname of the device to open.
+
+ OpenMode - Supplies the mode (read only, write only, or read write).
+
+ FileId - Supplies a free file identifier to use. If the device is already
+ open this parameter can be used to return the file identifier
+ already in use.
+
+Return Value:
+
+ If the open was successful, ESUCCESS is returned, otherwise an error code
+ is returned.
+
+--*/
+{
+ PCONSOLE_CONTEXT Context;
+
+ Context = &BlFileTable[*FileId].u.ConsoleContext;
+ if ( strstr(OpenPath, ")console(1)" ) != NULL ) {
+ Context->ConsoleNumber = 1;
+ } else {
+ Context->ConsoleNumber = 0;
+ }
+ return ESUCCESS;
+}
+
+ARC_STATUS
+KeyboardRead (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+/*++
+
+Routine Description:
+
+ This routine reads keys from the keyboard and passes along either ascii
+ or Unicode characters to the caller.
+
+Arguments:
+
+ FileId - Supplies a file id.
+
+ Buffer - Supplies a pointer to a buffer to receive the characters.
+
+ Length - Supplies the length of Buffer in bytes.
+
+ Count - Returns the count of the bytes that were received.
+
+Return Value:
+
+ A value of ESUCCESS is returned.
+
+--*/
+{
+ PCHAR OutputBuffer;
+ PCONSOLE_CONTEXT Context;
+ BOOLEAN Unicode;
+
+ OutputBuffer = (PCHAR)Buffer;
+ Context = &BlFileTable[FileId].u.ConsoleContext;
+
+ if (Context->ConsoleNumber == 1) {
+ if (Length & 1) {
+
+ //
+ // Length is not an even number of bytes, return an error.
+ //
+
+ return(EINVAL);
+ }
+ Unicode = TRUE;
+ } else {
+ Unicode = FALSE;
+ }
+
+ *Count = 0;
+ while (*Count < Length) {
+ *OutputBuffer++ = FwInputScanCode();
+ (*Count)++;
+ if (Unicode) {
+ *OutputBuffer++ = 0;
+ (*Count)++;
+ }
+ }
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+KeyboardGetReadStatus (
+ IN ULONG FileId
+ )
+/*++
+
+Routine Description:
+
+ This routine checks to see if a character is available from the keyboard.
+
+Arguments:
+
+ FileId - Supplies a file identifier.
+
+Return Value:
+
+ Returns ESUCCESS is a byte is available, otherwise EAGAIN is returned.
+
+--*/
+{
+ if (KbdBuffer.ReadIndex == KbdBuffer.WriteIndex) {
+ return EAGAIN;
+ } else {
+ return ESUCCESS;
+ }
+}
+
+
+ARC_STATUS
+KeyboardWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ ESUCCESS is returned.
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+ARC_STATUS
+KeyboardSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ ESUCCESS is returned.
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+VOID
+KeyboardInitialize (
+ IN OUT PDRIVER_LOOKUP_ENTRY LookupTableEntry,
+ IN ULONG Entries
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the keyboard control registers, clears the
+ fifo, and initializes the keyboard entry in the driver lookup table.
+
+Arguments:
+
+ LookupTableEntry - Supplies a pointer to the first free location in the
+ driver lookup table.
+
+ Entries - Supplies the number of free entries in the driver lookup table.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR Byte;
+ //
+ // Initialize the driver lookup table.
+ //
+
+ LookupTableEntry->DevicePath = KeyboardDevicePath;
+ LookupTableEntry->DispatchTable = &KeyboardEntryTable;
+
+ //
+ // Initialize static data.
+ //
+
+ FwLeftShift = FALSE;
+ FwRightShift = FALSE;
+ FwControl = FALSE;
+ FwAlt = FALSE;
+ FwCapsLock = FALSE;
+
+ KbdBuffer.ReadIndex = KbdBuffer.WriteIndex = 0;
+
+ //
+ // Call the selftest keyboard initialization routine.
+ //
+ InitKeyboard();
+
+ //
+ // Enable kbd interrupts in the keyboard controller.
+ //
+ SendKbdCommand(KBD_CTR_READ_COMMAND);
+ GetKbdData(&Byte,100);
+
+ //
+ // Clear translation mode and enable Kbd interrupt.
+ //
+ Byte = (Byte & 0xBF) | KbdCommandEnableKbdInt;
+ SendKbdCommand(KBD_CTR_WRITE_COMMAND);
+ SendKbdData(Byte);
+
+ //
+ // Enable keyboard interrupts in the interrupt enable register.
+ //
+ WRITE_REGISTER_USHORT(&((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Enable,
+ (1 << (KEYBOARD_VECTOR - DEVICE_VECTORS - 1)));
+
+
+ return;
+}
+
+UCHAR
+FwInputScanCode (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads a byte from the keyboard. If no data is available,
+ it blocks until a key is typed.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the character read from the keyboard.
+
+--*/
+
+{
+ UCHAR ScanCode;
+
+ while (KbdBuffer.ReadIndex == KbdBuffer.WriteIndex) {
+ }
+ KbdBuffer.ReadIndex = (KbdBuffer.ReadIndex+1) % KBD_BUFFER_SIZE;
+ ScanCode = KbdBuffer.Buffer[KbdBuffer.ReadIndex];
+
+ return ScanCode;
+}
+#endif
diff --git a/private/ntos/fw/mips/jxmemory.c b/private/ntos/fw/mips/jxmemory.c
new file mode 100644
index 000000000..4bc60d295
--- /dev/null
+++ b/private/ntos/fw/mips/jxmemory.c
@@ -0,0 +1,397 @@
+#if defined(JAZZ)
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxmemory.c
+
+Abstract:
+
+ This module implements the ARC firmware memory configuration operations
+ for a MIPS R3000 or R4000 Jazz system.
+
+Author:
+
+ David N. Cutler (davec) 18-May-1991
+
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#include "selfmap.h"
+extern end[];
+
+//
+// Define memory listhead, allocation entries, and free index.
+//
+
+ULONG FwMemoryFree;
+LIST_ENTRY FwMemoryListHead;
+FW_MEMORY_DESCRIPTOR FwMemoryTable[FW_MEMORY_TABLE_SIZE];
+
+VOID
+FwInitializeMemory (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the memory allocation list for the memory
+ configuration routine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG MemoryPages;
+ //
+ // Initialize the memory allocation listhead.
+ //
+
+ InitializeListHead(&FwMemoryListHead);
+
+ //
+ // Initialize the entry for the exception vectors and the system
+ // parameter block.
+ //
+
+ FwMemoryTable[0].MemoryEntry.MemoryType = MemoryFirmwarePermanent;
+
+ FwMemoryTable[0].MemoryEntry.BasePage = 0;
+ FwMemoryTable[0].MemoryEntry.PageCount = 2;
+ InsertTailList(&FwMemoryListHead, &FwMemoryTable[0].ListEntry);
+
+ //
+ // Initialize the entry for the firmware stack and code.
+ //
+
+ FwMemoryTable[1].MemoryEntry.MemoryType = MemoryFirmwareTemporary;
+
+ FwMemoryTable[1].MemoryEntry.PageCount = FW_PAGES - 2;
+ FwMemoryTable[1].MemoryEntry.BasePage = 2;
+ InsertTailList(&FwMemoryListHead, &FwMemoryTable[1].ListEntry);
+
+ //
+ // Initialize the entry for free memory and zero the free memory area.
+ //
+
+ FwMemoryTable[2].MemoryEntry.MemoryType = MemoryFree;
+ FwMemoryTable[2].MemoryEntry.BasePage = FW_PAGES;
+ FwMemoryTable[2].MemoryEntry.PageCount = 0x7ed - FW_PAGES;
+ InsertTailList(&FwMemoryListHead, &FwMemoryTable[2].ListEntry);
+
+ //
+ // Initialize the entry for the firmware pool.
+ //
+
+ FwMemoryTable[3].MemoryEntry.MemoryType = MemoryFirmwareTemporary;
+ FwMemoryTable[3].MemoryEntry.BasePage = 0x7ed;
+ FwMemoryTable[3].MemoryEntry.PageCount = 0x7fd - 0x7ed;
+ InsertTailList(&FwMemoryListHead, &FwMemoryTable[3].ListEntry);
+
+ //
+ // Initialize the entry for the PCR page used by the kernel debugger.
+ //
+
+ FwMemoryTable[4].MemoryEntry.MemoryType = MemoryFirmwareTemporary;
+ FwMemoryTable[4].MemoryEntry.BasePage = 0x7fd;
+ FwMemoryTable[4].MemoryEntry.PageCount = 0x800 - 0x7fd;
+ InsertTailList(&FwMemoryListHead, &FwMemoryTable[4].ListEntry);
+
+ //
+ // If the size of memory is greater than 8mb, then generate another
+ // descriptor to describe the free memory above the PCR page.
+ //
+
+ if ((MemorySize > 8) && (((ULONG) end & ~KSEG1_BASE) < 0x0800000)) {
+ MemoryPages = (MemorySize << (20 - PAGE_SHIFT));
+ FwMemoryTable[5].MemoryEntry.MemoryType = MemoryFree;
+ FwMemoryTable[5].MemoryEntry.BasePage = 0x800;
+ FwMemoryTable[5].MemoryEntry.PageCount = MemoryPages - 0x800;
+ InsertTailList(&FwMemoryListHead, &FwMemoryTable[5].ListEntry);
+ //RtlZeroMemory((PVOID)(KSEG0_BASE + 0x800000),
+ // (MemoryPages - 0x800) << PAGE_SHIFT);
+ FwMemoryFree = 6;
+
+ } else if (((ULONG) end & ~KSEG1_BASE) > 0x0800000) {
+
+ //
+ // If this copy of the firmware is loaded above 8 MB, then
+ // only part of memory should be zeroed and appropriate memory
+ // descriptors should be created.
+ //
+ // Note: currently all the memory between 800000 and the end
+ // of this code is made firmware permanent.
+ //
+
+ FwMemoryTable[5].MemoryEntry.MemoryType = MemoryFirmwarePermanent;
+ FwMemoryTable[5].MemoryEntry.BasePage = 0x800;
+ FwMemoryTable[5].MemoryEntry.PageCount =
+ ROUND_TO_PAGES((ULONG) end & ~KSEG1_BASE) - 0x800;
+ InsertTailList(&FwMemoryListHead, &FwMemoryTable[5].ListEntry);
+
+ MemoryPages = (MemorySize << (20 - PAGE_SHIFT));
+ FwMemoryTable[6].MemoryEntry.MemoryType = MemoryFree;
+ FwMemoryTable[6].MemoryEntry.BasePage = ROUND_TO_PAGES((ULONG) end & ~KSEG1_BASE);
+ FwMemoryTable[6].MemoryEntry.PageCount = MemoryPages -
+ FwMemoryTable[6].MemoryEntry.BasePage;
+ InsertTailList(&FwMemoryListHead, &FwMemoryTable[6].ListEntry);
+ //RtlZeroMemory((PVOID)(KSEG0_BASE + (FwMemoryTable[6].MemoryEntry.BasePage << PAGE_SHIFT)),
+ // FwMemoryTable[6].MemoryEntry.PageCount << PAGE_SHIFT);
+ FwMemoryFree = 7;
+
+ } else {
+ FwMemoryFree = 5;
+ }
+
+ //
+ // Initialize the memory configuration routine address in the system
+ // parameter block.
+ //
+
+ (PARC_MEMORY_ROUTINE)SYSTEM_BLOCK->FirmwareVector[MemoryRoutine] =
+ FwGetMemoryDescriptor;
+
+ return;
+}
+
+PMEMORY_DESCRIPTOR
+FwGetMemoryDescriptor (
+ IN PMEMORY_DESCRIPTOR MemoryDescriptor OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns a pointer to the next memory descriptor. If
+ the specified memory descriptor is NULL, then a pointer to the
+ first memory descriptor is returned. If there are no more memory
+ descriptors, then NULL is returned.
+
+Arguments:
+
+ MemoryDescriptor - Supplies a optional pointer to a memory descriptor.
+
+Return Value:
+
+ If there are any more entries in the memory descriptor list, the
+ address of the next descriptor is returned. Otherwise, NULL is
+ returned.
+
+--*/
+
+{
+
+ PFW_MEMORY_DESCRIPTOR TableEntry;
+ PLIST_ENTRY NextEntry;
+
+ //
+ // If a memory descriptor address is specified, then return the
+ // address of the next descriptor or NULL as appropriate. Otherwise,
+ // return the address of the first memory descriptor.
+ //
+
+ if (ARGUMENT_PRESENT(MemoryDescriptor)) {
+ TableEntry = CONTAINING_RECORD(MemoryDescriptor,
+ FW_MEMORY_DESCRIPTOR,
+ MemoryEntry);
+
+ NextEntry = TableEntry->ListEntry.Flink;
+ if (NextEntry != &FwMemoryListHead) {
+ return &(CONTAINING_RECORD(NextEntry,
+ FW_MEMORY_DESCRIPTOR,
+ ListEntry)->MemoryEntry);
+
+ } else {
+ return NULL;
+ }
+
+ } else {
+ return &FwMemoryTable[0].MemoryEntry;
+ }
+}
+
+VOID
+FwGenerateDescriptor (
+ IN PFW_MEMORY_DESCRIPTOR MemoryDescriptor,
+ IN MEMORY_TYPE MemoryType,
+ IN ULONG BasePage,
+ IN ULONG PageCount
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates a new memory descriptor to describe the
+ specified region of memory which is assumed to lie totally within
+ the specified region which is free.
+
+Arguments:
+
+ MemoryDescriptor - Supplies a pointer to a free memory descriptor
+ from which the specified memory is to be allocated.
+
+ MemoryType - Supplies the type that is assigned to the allocated
+ memory.
+
+ BasePage - Supplies the base page number.
+
+ PageCount - Supplies the number of pages.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PLIST_ENTRY NextEntry;
+ ULONG Offset;
+
+ //
+ // If the specified region totally consumes the free region, then no
+ // additional descriptors need to be allocated. If the specified region
+ // is at the start or end of the free region, then only one descriptor
+ // needs to be allocated. Otherwise, two additional descriptors need to
+ // be allocated.
+ //
+
+ Offset = BasePage - MemoryDescriptor->MemoryEntry.BasePage;
+ if ((Offset == 0) && (PageCount == MemoryDescriptor->MemoryEntry.PageCount)) {
+
+ //
+ // The specified region totally consumes the free region.
+ //
+
+ MemoryDescriptor->MemoryEntry.MemoryType = MemoryType;
+
+ } else {
+
+ //
+ // A memory descriptor must be generated to describe the allocated
+ // memory.
+ //
+
+ FwMemoryTable[FwMemoryFree].MemoryEntry.MemoryType = MemoryType;
+ FwMemoryTable[FwMemoryFree].MemoryEntry.BasePage = BasePage;
+ FwMemoryTable[FwMemoryFree].MemoryEntry.PageCount = PageCount;
+ InsertTailList(&FwMemoryListHead,
+ &FwMemoryTable[FwMemoryFree].ListEntry);
+
+ FwMemoryFree += 1;
+
+ //
+ // Determine whether an additional memory descriptor must be generated.
+ //
+
+ if (BasePage == MemoryDescriptor->MemoryEntry.BasePage) {
+
+ //
+ // The specified region lies at the start of the free region.
+ //
+
+ MemoryDescriptor->MemoryEntry.BasePage += PageCount;
+ MemoryDescriptor->MemoryEntry.PageCount -= PageCount;
+
+ } else if ((Offset + PageCount) == MemoryDescriptor->MemoryEntry.PageCount) {
+
+ //
+ // The specified region lies at the end of the free region.
+ //
+
+ MemoryDescriptor->MemoryEntry.PageCount -= PageCount;
+
+ } else {
+
+ //
+ // The specified region lies in the middle of the free region.
+ // Another memory descriptor must be generated.
+ //
+
+ FwMemoryTable[FwMemoryFree].MemoryEntry.MemoryType = MemoryFree;
+ FwMemoryTable[FwMemoryFree].MemoryEntry.BasePage = BasePage + PageCount;
+ FwMemoryTable[FwMemoryFree].MemoryEntry.PageCount =
+ MemoryDescriptor->MemoryEntry.PageCount -
+ (PageCount + Offset);
+ InsertTailList(&FwMemoryListHead,
+ &FwMemoryTable[FwMemoryFree].ListEntry);
+
+ FwMemoryFree += 1;
+ MemoryDescriptor->MemoryEntry.PageCount = Offset;
+ }
+ }
+
+ return;
+}
+
+VOID
+FwResetMemory(
+ VOID
+)
+
+/*++
+
+Routine Description:
+
+ This routine calls FwInitializeMemory to reset the memory descriptors
+ and then loops through and clears all of the appropriate memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PMEMORY_DESCRIPTOR MemoryDescriptor;
+
+ FwInitializeMemory();
+
+ //
+ // Reset all memory not used by the firmware.
+ // TEMPTEMP Just reset under 8M Bytes for now.
+ //
+
+ MemoryDescriptor = FwGetMemoryDescriptor(NULL);
+ while (MemoryDescriptor != NULL) {
+
+ if ((MemoryDescriptor->MemoryType != MemoryFirmwarePermanent) &&
+ (MemoryDescriptor->MemoryType != MemoryFirmwareTemporary) &&
+ (MemoryDescriptor->BasePage < 0x800)) {
+ RtlZeroMemory((PVOID)(KSEG0_BASE + (MemoryDescriptor->BasePage << PAGE_SHIFT)),
+ MemoryDescriptor->PageCount << PAGE_SHIFT);
+ }
+
+ MemoryDescriptor = FwGetMemoryDescriptor(MemoryDescriptor);
+ }
+
+ //
+ // Sweep the data cache
+ //
+
+ HalSweepDcache();
+
+}
+#endif
diff --git a/private/ntos/fw/mips/jxport.c b/private/ntos/fw/mips/jxport.c
new file mode 100644
index 000000000..e23b401e7
--- /dev/null
+++ b/private/ntos/fw/mips/jxport.c
@@ -0,0 +1,401 @@
+#if defined(JAZZ)
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxport.c
+
+Abstract:
+
+ This module implements the code that provides communication between
+ the kernel debugger on a MIPS R3000 or R4000 Jazz system and the host
+ system.
+
+Author:
+
+ David N. Cutler (davec) 28-Apr-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#include "jazzserp.h"
+
+// TEMPTEMP
+#define KDPORT_ENTRY 4
+
+extern BOOLEAN MctadrRev2;
+
+
+//
+// Temporarily, we use counter to do the timeout
+//
+
+#define TIMEOUT_COUNT 1024*512
+
+PUCHAR KdComPortInUse=NULL;
+
+//
+// Define serial port read and write addresses.
+//
+
+#define SP_READ ((PSP_READ_REGISTERS)(SP_VIRTUAL_BASE))
+#define SP_WRITE ((PSP_WRITE_REGISTERS)(SP_VIRTUAL_BASE))
+
+BOOLEAN
+KdPortInitialize (
+ PDEBUG_PARAMETERS DebugParameters,
+ PLOADER_PARAMETER_BLOCK LoaderBlock,
+ BOOLEAN Initialize
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the serial port used by the kernel debugger
+ and must be called during system initialization.
+
+Arguments:
+
+ DebugParameter - Supplies a pointer to the debug port parameters.
+
+ LoaderBlock - Supplies a pointer to the loader parameter block.
+
+ Initialize - Specifies a boolean value that determines whether the
+ debug port is initialized or just the debug port parameters
+ are captured.
+
+Return Value:
+
+ A value of TRUE is returned is the port was successfully initialized.
+ Otherwise, a value of FALSE is returned.
+
+
+--*/
+
+{
+
+ UCHAR DataByte;
+ ENTRYLO Pte[2];
+
+ //
+ // Map the serial port into the system virtual address space by loading
+ // a fixed TB entry.
+ //
+
+ Pte[0].PFN = SP_PHYSICAL_BASE >> PAGE_SHIFT;
+ Pte[0].G = 1;
+ Pte[0].V = 1;
+ Pte[0].D = 1;
+
+#if defined(R3000)
+
+ Pte[0].N = 1;
+
+#endif
+
+#if defined(R4000)
+
+ Pte[0].C = UNCACHED_POLICY;
+
+ Pte[1].PFN = 0;
+ Pte[1].G = 1;
+ Pte[1].V = 0;
+ Pte[1].D = 0;
+ Pte[1].C = 0;
+
+#endif
+
+ KdComPortInUse=(PUCHAR)SERIAL0_PHYSICAL_BASE;
+ KeFillFixedEntryTb((PHARDWARE_PTE)&Pte[0],
+ (PVOID)SP_VIRTUAL_BASE,
+ KDPORT_ENTRY);
+
+ //
+ // Clear the divisor latch, clear all interrupt enables, and reset and
+ // disable the FIFO's.
+ //
+
+ WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, 0x0);
+ WRITE_REGISTER_UCHAR(&SP_WRITE->InterruptEnable, 0x0);
+ DataByte = 0;
+ ((PSP_FIFO_CONTROL)(&DataByte))->ReceiveFifoReset = 1;
+ ((PSP_FIFO_CONTROL)(&DataByte))->TransmitFifoReset = 1;
+ WRITE_REGISTER_UCHAR(&SP_WRITE->FifoControl, DataByte);
+
+ //
+ // Set the divisor latch and set the baud rate to 19200 baud.
+ //
+ ((PSP_LINE_CONTROL)(&DataByte))->DivisorLatch = 1;
+ WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, DataByte);
+
+ //
+ // ****** Temporary ******
+ //
+ // The following code temporarily decides how to load the baud rate
+ // register based on whether a second level cache is present. This
+ // information should be acquired from the configuration information.
+ //
+#ifdef DUO
+ // 14 doesn't work
+ DataByte = 26;
+#else
+ if (MctadrRev2) {
+ DataByte = 26;
+ } else {
+ DataByte = BAUD_RATE_19200;
+ }
+#endif
+
+ WRITE_REGISTER_UCHAR(&SP_WRITE->TransmitBuffer, DataByte);
+ WRITE_REGISTER_UCHAR(&SP_WRITE->InterruptEnable, 0x0);
+
+ //
+ // Clear the divisor latch and set the character size to eight bits
+ // with one stop bit and no parity checking.
+ //
+
+ DataByte = 0;
+ ((PSP_LINE_CONTROL)(&DataByte))->CharacterSize = EIGHT_BITS;
+ WRITE_REGISTER_UCHAR(&SP_WRITE->LineControl, DataByte);
+
+ //
+ // Set data terminal ready and request to send.
+ //
+
+ DataByte = 0;
+ ((PSP_MODEM_CONTROL)(&DataByte))->DataTerminalReady = 1;
+ ((PSP_MODEM_CONTROL)(&DataByte))->RequestToSend = 1;
+ WRITE_REGISTER_UCHAR(&SP_WRITE->ModemControl, DataByte);
+ return TRUE;
+}
+
+ULONG
+KdPortGetByte (
+ OUT PUCHAR Input
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets a byte from the serial port used by the kernel
+ debugger.
+
+ N.B. It is assumed that the IRQL has been raised to the highest
+ level, and necessary multiprocessor synchronization has been
+ performed before this routine is called.
+
+Arguments:
+
+ Input - Supplies a pointer to a variable that receives the input
+ data byte.
+
+Return Value:
+
+ CP_GET_SUCCESS is returned if a byte is successfully read from the
+ kernel debugger line.
+
+ CP_GET_ERROR is returned if error encountered during reading.
+
+ CP_GET_NODATA is returned if timeout.
+
+--*/
+
+{
+
+ UCHAR DataByte;
+ ULONG TimeoutCount;
+
+ //
+ // Wait until data is available in the receive buffer.
+ //
+
+ TimeoutCount = TIMEOUT_COUNT;
+ do {
+ KeStallExecutionProcessor(1);
+ DataByte = READ_REGISTER_UCHAR(&SP_READ->LineStatus);
+ if (TimeoutCount-- == 0) {
+ return CP_GET_NODATA;
+ }
+ } while (((PSP_LINE_STATUS)(&DataByte))->DataReady == 0);
+
+ //
+ // Read input byte and store in callers buffer.
+ //
+
+ *Input = READ_REGISTER_UCHAR(&SP_READ->ReceiveBuffer);
+
+ //
+ // Return function value as the not of the error indicators.
+ //
+
+ if (((PSP_LINE_STATUS)(&DataByte))->ParityError ||
+ ((PSP_LINE_STATUS)(&DataByte))->FramingError ||
+ ((PSP_LINE_STATUS)(&DataByte))->OverrunError ||
+ ((PSP_LINE_STATUS)(&DataByte))->BreakIndicator) {
+ return CP_GET_ERROR;
+ } else {
+ return CP_GET_SUCCESS;
+ }
+}
+
+ULONG
+KdPortPollByte (
+ OUT PUCHAR Input
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets a byte from the serial port used by the kernel
+ debugger iff a byte is available.
+
+ N.B. It is assumed that the IRQL has been raised to the highest
+ level, and necessary multiprocessor synchronization has been
+ performed before this routine is called.
+
+Arguments:
+
+ Input - Supplies a pointer to a variable that receives the input
+ data byte.
+
+Return Value:
+
+ CP_GET_SUCCESS is returned if a byte is successfully read from the
+ kernel debugger line.
+
+ CP_GET_ERROR is returned if an error encountered during reading.
+
+ CP_GET_NODATA is returned if timeout occurs.
+
+--*/
+
+{
+
+ return KdPortGetByte(Input);
+
+}
+
+VOID
+KdPortPutByte (
+ IN UCHAR Output
+ )
+
+/*++
+
+Routine Description:
+
+ This routine puts a byte to the serial port used by the kernel debugger.
+
+ N.B. It is assumed that the IRQL has been raised to the highest level,
+ and necessary multiprocessor synchronization has been performed
+ before this routine is called.
+
+Arguments:
+
+ Output - Supplies the output data byte.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ UCHAR DataByte;
+
+ //
+ // Wait for transmit ready.
+ //
+
+ do {
+ DataByte = READ_REGISTER_UCHAR(&SP_READ->LineStatus);
+ } while (((PSP_LINE_STATUS)(&DataByte))->TransmitHoldingEmpty == 0);
+
+ //
+ // Wait for data set ready.
+ //
+
+// do {
+// DataByte = READ_REGISTER_UCHAR(&SP_READ->ModemStatus);
+// } while (((PSP_MODEM_STATUS)(&DataByte))->DataSetReady == 0);
+
+ //
+ // Transmit data.
+ //
+
+ WRITE_REGISTER_UCHAR(&SP_WRITE->TransmitBuffer, Output);
+ return;
+}
+
+VOID
+KdPortRestore (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine restores the state of the serial port after the kernel
+ debugger has been active.
+
+ N.B. This routine performs no function on the Jazz system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ return;
+}
+
+VOID
+KdPortSave (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine saves the state of the serial port and initializes the port
+ for use by the kernel debugger.
+
+ N.B. This routine performs no function on the Jazz system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ return;
+}
+
+#endif
diff --git a/private/ntos/fw/mips/jxreboot.c b/private/ntos/fw/mips/jxreboot.c
new file mode 100644
index 000000000..79af99295
--- /dev/null
+++ b/private/ntos/fw/mips/jxreboot.c
@@ -0,0 +1,403 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxreboot.c
+
+Abstract:
+
+ This module contains the Firmware Termination Functions.
+
+Author:
+
+ Lluis Abello (lluis) 4-Sep-1991
+
+
+Revision History:
+
+ Lluis Abello (lluis) 29-Apr-1993
+ Added FwpRestart function
+
+--*/
+#include "fwp.h"
+#include "selftest.h"
+#include "fwstring.h"
+#include "oli2msft.h"
+#include "arceisa.h"
+
+VOID FwBootRestartProcessorEnd(
+ IN VOID
+ );
+
+VOID FwBootRestartProcessor(
+ IN PVOID RestartBlock
+ );
+
+BOOLEAN
+SendKbdCommand(
+ IN UCHAR Command
+ );
+
+BOOLEAN
+SendKbdData(
+ IN UCHAR Data
+ );
+
+VOID
+ResetSystem (
+ IN VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine resets the system by asserting the reset line
+ from the keyboard controller.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ SendKbdCommand(0xD1);
+ SendKbdData(0);
+}
+
+VOID
+FwHalt(
+ IN VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine is the Firmware Halt termination function.
+ It displays a message and halts.
+ This routine is also the firmware PowerDown function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ FwClearScreen();
+ FwPrint(FW_SYSTEM_HALT_MSG);
+ DisableInterrupts();
+ for (;;) {
+ }
+}
+
+
+VOID
+FwpRestart(
+ IN VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine implements the Firmware Restart termination function.
+ If a valid restart block is detected, It is loaded and execution
+ continues at the restart address.
+ If no valid restart block is found, a soft reset is generated and the
+ normal boot sequence takes place.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Does not return to the caller.
+
+--*/
+{
+
+ PRESTART_BLOCK RestartBlock;
+ PULONG BlockPointer;
+ ULONG Checksum;
+ ULONG WhoAmI;
+
+#ifdef DUO
+ WhoAmI = READ_REGISTER_ULONG(&DMA_CONTROL->WhoAmI.Long);
+#else
+ WhoAmI = 0;
+#endif
+
+ RestartBlock = SYSTEM_BLOCK->RestartBlock;
+
+ while ((RestartBlock != NULL) && (RestartBlock->ProcessorId != WhoAmI)) {
+ RestartBlock = RestartBlock->NextRestartBlock;
+ }
+
+ if (RestartBlock != NULL) {
+
+ //
+ // Check signature;
+ //
+ if (RestartBlock->Signature == 0x42545352) {
+
+ //
+ // Check checksum.
+ //
+ //Checksum = 0;
+ //BlockPointer = (PULONG) RestartBlock;
+ //
+ //BlockPointer += sizeof(RESTART_BLOCK)/sizeof(ULONG);
+
+ //do {
+ // BlockPointer--;
+ // Checksum+= *BlockPointer;
+ //} while (BlockPointer != (PULONG)RestartBlock);
+
+ //if (Checksum == 0) {
+
+ //
+ // A valid restart block has been detected
+ // Flush the data cache and restart the processor.
+ //
+ HalSweepDcache();
+ VenRestartBlock(RestartBlock);
+ return;
+ //}
+ }
+ }
+
+ //
+ // No valid restart block found. Reset.
+ //
+ return;
+ //ResetSystem();
+}
+#ifdef DUO
+
+VOID
+ProcessorBSystemBoot(
+ IN VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine is the second processor boot routine. It polls the boot
+ status field of the restart block and when the StartProcessor bit
+ is set it restarts from the Restart block.
+
+ The master processor sets the address of this routine in the Task vector
+ and issues an IP interrupt to processor B who starts executing this code.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Does not return to the caller.
+
+--*/
+{
+ BOOT_STATUS BootStatus;
+ for (;;) {
+ BootStatus = SYSTEM_BLOCK->RestartBlock->NextRestartBlock->BootStatus;
+ if (BootStatus.ProcessorStart == 1) {
+ FwpRestart();
+ FwPrint("Processor B failed to start from Restart Block\r\n");
+ } else {
+ FwStallExecution(10000); // wait 10ms
+
+ //
+ // Check if another Ip interrupt was issued to us
+ // if it was give up boot.
+ //
+ if (IsIpInterruptSet()) {
+ return;
+ }
+
+
+ }
+ }
+}
+
+#endif
+
+
+VOID
+FwReboot(
+ IN VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine implements the Firmware Reboot termination function.
+ It generates a soft reset to the system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Does not return to the caller.
+
+--*/
+{
+ ResetSystem();
+}
+
+VOID
+FwEnterInteractiveMode(
+ IN VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine implements the Firmware EnterInteractiveMode function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ FwMonitor(3);
+}
+
+
+#ifdef DUO
+
+VOID
+InitializeRestartBlock(
+ IN VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine intializes the restart blocks for all processors.
+ The boot status field has already been initialized and indicates
+ weather the processor passed selftest or not.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PULONG BlockPointer;
+ PRESTART_BLOCK RestartBlock;
+ ULONG Checksum;
+ ULONG ProcessorId;
+
+ RestartBlock = SYSTEM_BLOCK->RestartBlock;
+
+ for (ProcessorId = 0; RestartBlock != NULL; ProcessorId++) {
+
+ RestartBlock->Signature = 0x42545352;
+ RestartBlock->Length = sizeof(RESTART_BLOCK);
+ RestartBlock->Version = ARC_VERSION;
+ RestartBlock->Revision = ARC_REVISION;
+ RestartBlock->RestartAddress = NULL;
+ RestartBlock->SaveAreaLength = (ULONG)SYSTEM_BLOCK->RestartBlock + sizeof(RESTART_BLOCK)- (ULONG)&SYSTEM_BLOCK->RestartBlock->u.SaveArea[0];
+ RestartBlock->BootMasterId = 0;
+ RestartBlock->ProcessorId = ProcessorId;
+
+ //
+ // Zero Save area.
+ //
+ RtlZeroMemory(RestartBlock->u.SaveArea,RestartBlock->SaveAreaLength);
+
+ //
+ // Compute checksum.
+ //
+ Checksum = 0;
+ RestartBlock->CheckSum = 0;
+ BlockPointer = (PULONG) RestartBlock;
+ BlockPointer += sizeof(RESTART_BLOCK)/sizeof(ULONG);
+
+ do {
+ BlockPointer--;
+ Checksum+= *BlockPointer;
+ } while (BlockPointer != (PULONG)RestartBlock);
+
+ RestartBlock->CheckSum = -Checksum;
+
+ //
+ // Get next restart block
+ //
+ RestartBlock = RestartBlock->NextRestartBlock;
+ }
+}
+
+#endif // DUO
+
+
+VOID
+FwTerminationInitialize(
+ IN VOID
+ )
+
+/*++
+
+Routine Description:
+
+ //
+ // Initialize the termination function entry points in the transfer vector
+ //
+ This routine initializes the termination function entry points
+ in the transfer vector.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PULONG Destination;
+
+ (PARC_HALT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[HaltRoutine] = FwHalt;
+ (PARC_POWERDOWN_ROUTINE)SYSTEM_BLOCK->FirmwareVector[PowerDownRoutine] = FwHalt;
+ (PARC_RESTART_ROUTINE)SYSTEM_BLOCK->FirmwareVector[RestartRoutine] = FwReboot;
+ (PARC_REBOOT_ROUTINE)SYSTEM_BLOCK->FirmwareVector[RebootRoutine] = FwReboot;
+ (PARC_INTERACTIVE_MODE_ROUTINE)SYSTEM_BLOCK->FirmwareVector[InteractiveModeRoutine] = FwEnterInteractiveMode;
+// (PARC_RETURN_FROM_MAIN_ROUTINE)SYSTEM_BLOCK->FirmwareVector[ReturnFromMainRoutine] = FwReturnFromMain;
+
+#ifdef DUO
+
+ InitializeRestartBlock();
+ Destination = (PULONG)(((ULONG)&SYSTEM_BLOCK->Adapter0Vector[MaximumEisaRoutine] & ~KSEG1_BASE) | KSEG0_BASE);
+ (PVEN_BOOT_RESTART_ROUTINE)SYSTEM_BLOCK->VendorVector[BootRestartRoutine] = Destination;
+ Destination = (PULONG)((ULONG)Destination | KSEG1_BASE);
+ RtlMoveMemory(Destination,FwBootRestartProcessor,(PCHAR)FwBootRestartProcessorEnd - (PCHAR)FwBootRestartProcessor);
+
+#endif // DUO
+
+}
diff --git a/private/ntos/fw/mips/jxserial.c b/private/ntos/fw/mips/jxserial.c
new file mode 100644
index 000000000..29eb6d8c8
--- /dev/null
+++ b/private/ntos/fw/mips/jxserial.c
@@ -0,0 +1,566 @@
+#if defined(JAZZ)
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxserial.c
+
+Abstract:
+
+ This module implements the serila boot driver for the Jazz system.
+
+Author:
+
+ Lluis Abello (lluis) 9-Aug-1991
+
+Environment:
+
+ Kernel mode.
+
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#include "jazzserp.h"
+
+ARC_STATUS
+SerialClose (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+SerialMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ );
+
+ARC_STATUS
+SerialOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ IN OUT PULONG FileId
+ );
+
+ARC_STATUS
+SerialRead (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+SerialGetReadStatus (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+SerialSeek (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+SerialWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+SerialGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Finfo
+ );
+//
+// Declare and initialize the Serial entry table.
+//
+BL_DEVICE_ENTRY_TABLE SerialEntryTable = {
+ SerialClose,
+ SerialMount,
+ SerialOpen,
+ SerialRead,
+ SerialGetReadStatus,
+ SerialSeek,
+ SerialWrite,
+ SerialGetFileInformation,
+ (PARC_SET_FILE_INFO_ROUTINE)NULL
+ };
+
+PCHAR PathNameSerialPort0 = "multi(0)serial(0)";
+PCHAR PathNameSerialPort1 = "multi(0)serial(1)";
+
+#define SP_BASE(Fid) PSP_WRITE_REGISTERS SP; \
+ SP = (PSP_WRITE_REGISTERS)BlFileTable[Fid].u.SerialContext.PortBase
+//
+// Define function prototypes
+//
+
+VOID
+SerialBootSetup(
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+SerialGetFileInformation (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Finfo
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns EINVAL as no FileInformation can be
+ returned for the Serial line driver.
+
+Arguments:
+
+ The arguments are not used.
+
+Return Value:
+
+ EINVAL is returned
+
+--*/
+
+{
+ return EINVAL;
+}
+
+ARC_STATUS
+SerialClose (
+ IN ULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This function closes the file table entry specified by the file id.
+
+Arguments:
+
+ FileId - Supplies the file table index.
+
+Return Value:
+
+ ESUCCESS is returned.
+
+--*/
+
+{
+ BlFileTable[FileId].Flags.Open = 0;
+ return ESUCCESS;
+}
+
+ARC_STATUS
+SerialBootWrite(
+ CHAR Char,
+ ULONG SP
+ )
+/*++
+
+Routine Description:
+
+ This routine writes a character to the serial port.
+
+Arguments:
+
+ Char - Character to write.
+
+ SP - Base address of the serial port.
+
+Return Value:
+
+ If the operation is performed without errors, ESUCCESS is returned,
+ otherwise an error code is returned.
+
+--*/
+{
+ UCHAR DataByte;
+
+ //
+ // wait for transmitter holding register to be empty
+ //
+ do {
+ DataByte=READ_REGISTER_UCHAR(&((PSP_READ_REGISTERS)SP)->LineStatus);
+ } while (((PSP_LINE_STATUS)(&DataByte))->TransmitHoldingEmpty == 0);
+
+ //
+ // transmit character
+ //
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP)->TransmitBuffer,Char);
+ return ESUCCESS;
+}
+ARC_STATUS
+SerialWrite (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+/*++
+
+Routine Description:
+
+ This routine implements the write operation for the ARC firmware
+ serial port driver.
+
+Arguments:
+
+ FileId - Supplies a file id.
+
+ Buffer - Supplies a pointer to a buffer containing the characters to
+ write to the serial port.
+
+ Length - Supplies the length of Buffer.
+
+ Count - Returns the count of the characters that were written.
+
+Return Value:
+
+ If the operation is performed without errors, ESUCCESS is returned,
+ otherwise an error code is returned.
+
+--*/
+{
+ ARC_STATUS Status;
+
+ for (*Count=0; *Count < Length; (*Count)++) {
+ if (Status=SerialBootWrite(*(PCHAR)Buffer,
+ BlFileTable[FileId].u.SerialContext.PortBase)
+ ) {
+ return Status;
+ }
+ ((PCHAR)Buffer)++;
+ }
+ return ESUCCESS;
+}
+
+ARC_STATUS
+SerialRead (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ This routine implements the read operation for the ARC firmware
+ serial port driver.
+
+Arguments:
+
+ FileId - Supplies a file id.
+
+ Buffer - Supplies a pointer to a buffer where the characters read
+ from the serial port will be stored.
+
+ Length - Supplies the length of Buffer.
+
+ Count - Returns the count of the characters that were read.
+
+Return Value:
+
+ If the operation is performed without errors, ESUCCESS is returned,
+ otherwise an error code is returned.
+
+--*/
+{
+ UCHAR DataByte;
+ SP_BASE(FileId);
+ for (*Count=0; *Count < Length; (*Count)++) {
+ //
+ // if no characters are available, then set data terminal ready
+ // and continue polling.
+ //
+ DataByte = READ_REGISTER_UCHAR(&((PSP_READ_REGISTERS)SP)->LineStatus);
+ if ((((PSP_LINE_STATUS)(&DataByte))->DataReady == 0)) {
+ DataByte=0;
+ ((PSP_MODEM_CONTROL)(&DataByte))->DataTerminalReady=1;
+ ((PSP_MODEM_CONTROL)(&DataByte))->Interrupt=1;
+ WRITE_REGISTER_UCHAR(&SP->ModemControl,DataByte);
+ }
+ //
+ // Poll until a character is available from the serial port
+ //
+ do {
+ DataByte=READ_REGISTER_UCHAR(&((PSP_READ_REGISTERS)SP)->LineStatus);
+ } while ((((PSP_LINE_STATUS)(&DataByte))->DataReady == 0));
+
+ //
+ // turn off data terminal ready
+ //
+ DataByte=0;
+ ((PSP_MODEM_CONTROL)(&DataByte))->Interrupt=1;
+ WRITE_REGISTER_UCHAR(&SP->ModemControl,DataByte);
+
+ //
+ // Read character
+ //
+ *(PCHAR)Buffer = READ_REGISTER_UCHAR(&((PSP_READ_REGISTERS)SP)->ReceiveBuffer);
+ ((PCHAR)Buffer)++;
+ }
+ return ESUCCESS;
+}
+
+
+ ARC_STATUS
+SerialOpen (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ IN OUT PULONG FileId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine opens the specified serial port.
+
+Arguments:
+
+ OpenPath - Supplies the pathname of the device to open.
+
+ OpenMode - Supplies the mode (read only, write only, or read write).
+
+ FileId - Supplies a free file identifier to use. If the device is already
+ open this parameter can be used to return the file identifier
+ already in use.
+
+Return Value:
+
+ If the open was successful, ESUCCESS is returned, otherwise an error code
+ is returned.
+
+--*/
+
+{
+ ULONG Port;
+ //
+ // Check for the serial port to open 0,1
+ //
+ if (FwGetPathMnemonicKey(OpenPath,
+ "serial",
+ &Port
+ )) {
+ return ENODEV;
+ }
+
+ //
+ // Init file table
+ //
+ BlFileTable[*FileId].u.SerialContext.PortNumber = Port;
+ BlFileTable[*FileId].u.SerialContext.PortBase = COMPORT1_VIRTUAL_BASE+0x1000*Port;
+
+ //
+ // Initialize the serial port.
+ //
+ SerialBootSetup(BlFileTable[*FileId].u.SerialContext.PortBase);
+ return ESUCCESS;
+}
+
+VOID
+SerialBootSetup(
+ IN ULONG SP
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the serial port controller.
+
+Arguments:
+
+ SP - Supplies the virtual address of the serial port.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UCHAR Trash;
+ UCHAR DataByte;
+ //
+ // Clear the divisor latch, clear all interrupt enables, and reset and
+ // disable the FIFO's.
+ //
+
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP)->LineControl, 0x0);
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP)->InterruptEnable, 0x0);
+ DataByte = 0;
+ ((PSP_FIFO_CONTROL)(&DataByte))->ReceiveFifoReset = 1;
+ ((PSP_FIFO_CONTROL)(&DataByte))->TransmitFifoReset = 1;
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP)->FifoControl, DataByte);
+
+ //
+ // Set the divisor latch and set the baud rate to 9600 baud.
+ //
+
+ DataByte = 0;
+ ((PSP_LINE_CONTROL)(&DataByte))->DivisorLatch = 1;
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP)->LineControl, DataByte);
+ if (MctadrRev2) {
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP)->TransmitBuffer, 52);
+ } else {
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP)->TransmitBuffer, BAUD_RATE_9600);
+ }
+// WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP)->TransmitBuffer, BAUD_RATE_19200);
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP)->InterruptEnable, 0x0);
+
+ //
+ // Clear the divisor latch and set the character size to eight bits
+ // with one stop bit and no parity checking.
+ //
+
+ DataByte = 0;
+ ((PSP_LINE_CONTROL)(&DataByte))->CharacterSize = EIGHT_BITS;
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP)->LineControl, DataByte);
+
+ //
+ // Set data terminal ready and request to send.
+ // And open interrupt tristate line
+ //
+
+ DataByte = 0;
+ ((PSP_MODEM_CONTROL)(&DataByte))->DataTerminalReady = 1;
+ ((PSP_MODEM_CONTROL)(&DataByte))->RequestToSend = 1;
+ ((PSP_MODEM_CONTROL)(&DataByte))->Interrupt=1;
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP)->ModemControl, DataByte);
+
+ Trash = READ_REGISTER_UCHAR(&((PSP_READ_REGISTERS)SP)->LineStatus);
+ Trash = READ_REGISTER_UCHAR(&((PSP_READ_REGISTERS)SP)->ReceiveBuffer);
+}
+
+ARC_STATUS
+SerialGetReadStatus (
+ IN ULONG FileId
+ )
+/*++
+
+Routine Description:
+
+ This routine checks to see if a character is available from the serial line.
+
+Arguments:
+
+ FileId - Supplies a file identifier.
+
+Return Value:
+
+ Returns ESUCCESS is a byte is available, otherwise EAGAIN is returned.
+
+--*/
+{
+ UCHAR DataByte;
+ SP_BASE(FileId);
+ DataByte = READ_REGISTER_UCHAR(&((PSP_READ_REGISTERS)SP)->LineStatus);
+ if ((((PSP_LINE_STATUS)(&DataByte))->DataReady == 0)) {
+ return EAGAIN;
+ }
+ return ESUCCESS;
+}
+
+ARC_STATUS
+SerialMount (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ return EINVAL;
+}
+
+ARC_STATUS
+SerialSeek (
+ IN ULONG FileId,
+ IN IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ ESUCCESS is returned.
+
+--*/
+
+{
+ return ESUCCESS;
+}
+
+VOID
+SerialInitialize(
+ IN OUT PDRIVER_LOOKUP_ENTRY LookupTableEntry,
+ IN ULONG Entries
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the serial device dispatch table
+ and the entries in the driver lookup table.
+
+Arguments:
+
+ LookupTableEntry - Supplies a pointer to the first free location in the
+ driver lookup table.
+
+ Entries - Supplies the number of free entries in the driver lookup table.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+
+ //
+ // Initialize the driver lookup table, and increment the pointer.
+ //
+
+ LookupTableEntry->DevicePath = PathNameSerialPort0;
+ LookupTableEntry->DispatchTable = &SerialEntryTable;
+
+ if (Entries>1) {
+ LookupTableEntry++;
+ LookupTableEntry->DevicePath = PathNameSerialPort1;
+ LookupTableEntry->DispatchTable = &SerialEntryTable;
+ }
+}
+
+#endif
diff --git a/private/ntos/fw/mips/jxsysid.c b/private/ntos/fw/mips/jxsysid.c
new file mode 100644
index 000000000..0c04e41df
--- /dev/null
+++ b/private/ntos/fw/mips/jxsysid.c
@@ -0,0 +1,144 @@
+#if defined(JAZZ)
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxsysid.c
+
+Abstract:
+
+ This module implements the ARC firmware System ID Query functions as
+ described in the Advanced Risc Computing Specification (Revision 1.00),
+ section 3.3.3.5, for a MIPS R3000 or R4000 Jazz system.
+
+Author:
+
+ David M. Robinson (davidro) 11-July-1991
+
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+
+//
+// Define the system identifier.
+//
+
+SYSTEM_ID SystemId;
+
+VOID
+FwSystemIdInitialize (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the system identifer routine address.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Initialize the system identifier routine address in the system
+ // parameter block.
+ //
+
+ (PARC_GET_SYSTEM_ID_ROUTINE)SYSTEM_BLOCK->FirmwareVector[GetSystemIdRoutine] =
+ FwGetSystemId;
+
+ (PARC_FLUSH_ALL_CACHES_ROUTINE)SYSTEM_BLOCK->FirmwareVector[FlushAllCachesRoutine] =
+ FwFlushAllCaches;
+
+ return;
+}
+
+
+PSYSTEM_ID
+FwGetSystemId (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the system ID, which consists of an eight byte
+ VendorId and an eight byte ProductId (in this case the ethernet address).
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns a pointer to a buffer containing the system id structure. This
+ structure is initialized on each call to prevent programs from changing
+ the value.
+
+--*/
+
+{
+ PUCHAR NvramSystemId;
+ ULONG Index;
+
+#ifdef DUO
+ CHAR SystemIdString[] = "MIPS DUO";
+#else
+ CHAR SystemIdString[] = "MIPS MAG";
+#endif
+
+ NvramSystemId = (PUCHAR)NVRAM_SYSTEM_ID;
+
+ for ( Index = 0 ; Index < 8 ; Index++ ) {
+ SystemId.ProductId[Index] = *NvramSystemId++;
+ }
+
+ for ( Index = 0 ; Index < 8 ; Index++ ) {
+ SystemId.VendorId[Index] = SystemIdString[Index];
+ }
+
+ return &SystemId;
+}
+
+
+VOID
+FwFlushAllCaches (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ TEMPTEMP Fix this up soon!!
+Arguments:
+
+ None.
+
+Return Value:
+
+
+--*/
+
+{
+
+ HalSweepIcache();
+ HalSweepDcache();
+ return;
+}
+
+#endif
diff --git a/private/ntos/fw/mips/jxvendor.c b/private/ntos/fw/mips/jxvendor.c
new file mode 100644
index 000000000..274a1eefe
--- /dev/null
+++ b/private/ntos/fw/mips/jxvendor.c
@@ -0,0 +1,195 @@
+#if defined(JAZZ)
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jxvendor.c
+
+Abstract:
+
+ Implementation of the vendor private routines for the Jazz ARC firmware.
+
+Author:
+
+ David M. Robinson (davidro) 13-June-1991
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+
+//
+// Routine prototypes.
+//
+
+PVOID
+FwAllocatePool(
+ IN ULONG NumberOfBytes
+ );
+
+VOID
+FwStallExecution (
+ IN ULONG MicroSeconds
+ );
+
+//
+// Static Variables
+//
+
+PCHAR FwPoolBase;
+PCHAR FwFreePool;
+
+
+VOID
+FwVendorInitialize(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the vendor private routines.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Initialize pointers and zero memory for the allocate pool routine.
+ //
+
+ FwPoolBase = (PCHAR)FW_POOL_BASE;
+ FwFreePool = (PCHAR)FW_POOL_BASE;
+ RtlZeroMemory(FwPoolBase, FW_POOL_SIZE);
+
+ //
+ // Initialize the vendor routine vector.
+ //
+
+ (PVEN_ALLOCATE_POOL_ROUTINE)SYSTEM_BLOCK->VendorVector[AllocatePoolRoutine] =
+ FwAllocatePool;
+
+ (PVEN_STALL_EXECUTION_ROUTINE)SYSTEM_BLOCK->VendorVector[StallExecutionRoutine] =
+ FwStallExecution;
+
+ (PVEN_PRINT_ROUTINE)SYSTEM_BLOCK->VendorVector[PrintRoutine] =
+ FwPrint;
+
+ return;
+}
+
+
+PVOID
+FwAllocatePool(
+ IN ULONG NumberOfBytes
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates the requested number of bytes from the firmware
+ pool. If enough pool exists to satisfy the request, a pointer to the
+ next free cache-aligned block is returned, otherwise NULL is returned.
+ The pool is zeroed at initialization time, and no corresponding
+ "FwFreePool" routine exists.
+
+Arguments:
+
+ NumberOfBytes - Supplies the number of bytes to allocate.
+
+Return Value:
+
+ NULL - Not enough pool exists to satisfy the request.
+
+ NON-NULL - Returns a pointer to the allocated pool.
+
+--*/
+
+{
+ PVOID Pool;
+
+ //
+ // If there is not enough free pool for this request or the requested
+ // number of bytes is zero, return NULL, otherwise return a pointer to
+ // the free block and update the free pointer.
+ //
+
+ if (((FwFreePool + NumberOfBytes) > (FwPoolBase + FW_POOL_SIZE)) ||
+ (NumberOfBytes == 0)) {
+
+ Pool = NULL;
+
+ } else {
+
+ Pool = FwFreePool;
+
+ //
+ // Move pointer to the next cache aligned section of free pool.
+ //
+
+ FwFreePool += ((NumberOfBytes - 1) & ~(KeGetDcacheFillSize() - 1)) +
+ KeGetDcacheFillSize();
+ }
+ return Pool;
+}
+
+VOID
+FwStallExecution (
+ IN ULONG MicroSeconds
+ )
+
+/*++
+
+Routine Description:
+
+ This function stalls execution for the specified number of microseconds.
+
+Arguments:
+
+ MicroSeconds - Supplies the number of microseconds that execution is to be
+ stalled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG Index;
+ ULONG Limit;
+ PULONG Store;
+ ULONG Value;
+
+ //
+ // ****** begin temporary code ******
+ //
+ // This code must be replaced with a smarter version. For now it assumes
+ // an execution rate of 50,000,000 instructions per second and 4 instructions
+ // per iteration.
+ //
+
+ Store = &Value;
+ Limit = (MicroSeconds * 50 / 4);
+ for (Index = 0; Index < Limit; Index += 1) {
+ *Store = Index;
+ }
+ return;
+}
+#endif
+
+
diff --git a/private/ntos/fw/mips/jxvideo.c b/private/ntos/fw/mips/jxvideo.c
new file mode 100644
index 000000000..a4db0974a
--- /dev/null
+++ b/private/ntos/fw/mips/jxvideo.c
@@ -0,0 +1,337 @@
+#if defined(JAZZ)
+
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ jxvideo.c
+
+Abstract:
+
+ This module implements the interface with the video prom initialization
+ code.
+
+Author:
+
+ David M. Robinson (davidro) 24-Jul-1991
+
+Environment:
+
+ Kernel mode.
+
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#include "jxvideo.h"
+#include "ioaccess.h"
+#include "selfmap.h"
+
+//
+// Static data
+//
+
+UCHAR PromStride, PromSize, PromId;
+UCHAR PromWidth;
+UCHAR AdrShift;
+PUCHAR IdentifierString;
+UCHAR PromString[32];
+
+VOID
+ReadVideoPromData(
+ IN ULONG SrcOfst,
+ IN ULONG DstAdr,
+ IN ULONG Size
+ );
+
+BOOLEAN
+ValidVideoProm(
+ )
+/*++
+
+Routine Description:
+
+ This routine checks for valid header info in the video prom.
+ At the same time it initializes the variables needed to
+ read data from the video prom.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE If the video rom is valid.
+ FALSE otherwise.
+
+--*/
+
+{
+
+ PromId = READ_REGISTER_UCHAR(VIDEO_CONTROL_VIRTUAL_BASE);
+
+ PromStride = READ_REGISTER_UCHAR(VIDEO_CONTROL_VIRTUAL_BASE+0x08);
+
+ switch (PromStride) {
+ case 1: AdrShift = 0;
+ break;
+
+ case 2: AdrShift = 1;
+ break;
+
+ case 4: AdrShift = 2;
+ break;
+
+ case 8: AdrShift = 3;
+ break;
+ default:
+ return FALSE;
+ }
+
+ PromWidth = READ_REGISTER_UCHAR(VIDEO_CONTROL_VIRTUAL_BASE+0x10);
+ if ((PromWidth != 1) && (PromWidth != 2) && (PromWidth != 4) &&
+ (PromWidth != 8)) {
+ return FALSE;
+ }
+ PromSize = READ_REGISTER_UCHAR(VIDEO_CONTROL_VIRTUAL_BASE+0x18);
+ if ((READ_REGISTER_UCHAR(VIDEO_CONTROL_VIRTUAL_BASE+0x20) != 'J') ||
+ (READ_REGISTER_UCHAR(VIDEO_CONTROL_VIRTUAL_BASE+0x28) != 'a') ||
+ (READ_REGISTER_UCHAR(VIDEO_CONTROL_VIRTUAL_BASE+0x30) != 'z') ||
+ (READ_REGISTER_UCHAR(VIDEO_CONTROL_VIRTUAL_BASE+0x38) != 'z')) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+ARC_STATUS
+InitializeVideoFromProm(
+ IN PMONITOR_CONFIGURATION_DATA Monitor
+ )
+/*++
+
+Routine Description:
+
+ This routine loads the code from the video prom into the specified address.
+
+Arguments:
+
+ DstAdr - Address where the video rom code is to be copied.
+
+Return Value:
+
+ If the video rom is not valid, returns EINVAL otherwise
+ return ESUCCESS
+
+--*/
+
+{
+
+ VIDEO_VIRTUAL_SPACE VideoAdr;
+ ARC_STATUS Status;
+ ULONG GlobalConfig;
+ ULONG VideoSize;
+ ULONG ConfigSize;
+ VIDEO_PROM_CONFIGURATION PromConfig;
+
+ if (ValidVideoProm() == FALSE) {
+ return EINVAL;
+ }
+
+ //
+ // Read VIDEO_PROM_CONFIGURATION structure
+ //
+
+ ReadVideoPromData(8,(ULONG)&PromConfig,sizeof(PromConfig));
+
+ //sprintf(String,"VideoMemorySize = %lx\r\n",PromConfig.VideoMemorySize);
+ //VenPrint(String);
+ //sprintf(String,"VideoControlSize = %lx\r\n",PromConfig.VideoControlSize);
+ //VenPrint(String);
+ //sprintf(String,"CodeOffset = %lx\r\n",PromConfig.CodeOffset);
+ //VenPrint(String);
+ //sprintf(String,"CodeSize = %lx\r\n",PromConfig.CodeSize);
+ //VenPrint(String);
+
+ //
+ // Set the video size in the global config
+ //
+
+ VideoSize = (PromConfig.VideoMemorySize > PromConfig.VideoControlSize ? PromConfig.VideoMemorySize : PromConfig.VideoControlSize);
+
+ //
+ // Initialize size of Video space
+ //
+ // 0 -> 512K
+ // 1 -> 2MB
+ // 2 -> 8MB
+ // 3 -> 32MB
+ //
+
+ ConfigSize = 0;
+
+ if (VideoSize > 0x80000) {
+ ConfigSize = 1;
+ }
+ if (VideoSize > 0x200000) {
+ ConfigSize = 2;
+ }
+
+ if (VideoSize > 0x800000) {
+ ConfigSize = 3;
+ }
+
+ GlobalConfig = READ_REGISTER_ULONG(&DMA_CONTROL->Configuration.Long);
+
+ VideoAdr.MemoryVirtualBase = VIDEO_MEMORY_VIRTUAL_BASE;
+ VideoAdr.ControlVirtualBase = VIDEO_CONTROL_VIRTUAL_BASE;
+
+#ifdef DUO
+ GlobalConfig = (GlobalConfig & 0x3C) | ConfigSize;
+#else
+
+ //sprintf(String,"Global Config = %lx\r\n",GlobalConfig);
+ //VenPrint(String);
+ //
+ // Look for the MCT_ADR REV2 Map Prom bit in the configuration register,
+ // if there this is a REV2, otherwise REV1.
+ //
+ if (GlobalConfig & 0x400) {
+ GlobalConfig = (GlobalConfig & 0xFCFF) | (ConfigSize << 8);
+ } else {
+ GlobalConfig = (GlobalConfig & 0xFF3F) | (ConfigSize << 6);
+ }
+#endif
+
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->Configuration.Long,GlobalConfig);
+ //sprintf(String,"Setting Global Config = %lx\r\n",GlobalConfig);
+ //VenPrint(String);
+
+ //
+ // Read the identifier string
+ //
+
+ ReadVideoPromData(8+sizeof(PromConfig),(ULONG)PromString,32);
+ IdentifierString = &PromString[0];
+
+ // VenPrint(IdentifierString);
+
+ //
+ // Copy the code from the video prom to system memory.
+ // The prom is copied uncached, no need to flush Dcache.
+ // This memory has just been tested. There has no been any
+ // code before -> no need to flush Icache.
+ //
+
+ ReadVideoPromData(PromConfig.CodeOffset,VIDEO_PROM_CODE_UNCACHED_BASE,PromConfig.CodeSize);
+
+ //VenPrint("Code loaded\r\n");
+ //DbgBreakPoint();
+ //
+ // Flush caches!!!!
+ //
+
+ // FwFlushAllCaches();
+
+ //VenPrint("Code loaded and caches flushed\r\n");
+ //DbgBreakPoint();
+
+ //VenPrint("\r\nJumping to the moon\r\n");
+
+ Status = InitializeVideo(&VideoAdr,Monitor);
+
+ //sprintf(String,"Return status %lx \r\n",Status);
+ //VenPrint (String);
+
+ return Status;
+
+}
+
+VOID
+ReadVideoPromData(
+ IN ULONG SrcOfst,
+ IN ULONG DstAdr,
+ IN ULONG Size
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies Size bytes of data from the Video PROM starting
+ at SrcOfst into DstAdr.
+ This routine takes into account PromStride and PromWidth;
+
+Arguments:
+
+ SrcOfst - Offset from the beginning of the video prom in bytes
+ without taking into account PromStride.
+ DstAdr - Address where the video rom data is to be copied.
+ Size - Size in bytes to copy
+
+Return Value:
+
+ If the video rom is not valid, returns EINVAL otherwise
+ return ESUCCESS
+
+--*/
+
+{
+
+ULONG SrcAdr;
+ULONG LastAdr;
+
+ SrcAdr = SrcOfst;
+ LastAdr = DstAdr+Size;
+
+ switch (PromWidth) {
+
+ //
+ // Read 1 byte at a time.
+ //
+ case 1:
+ while ( DstAdr < LastAdr) {
+ *(PUCHAR)DstAdr = READ_REGISTER_UCHAR(VIDEO_CONTROL_VIRTUAL_BASE + (SrcAdr << AdrShift));
+ SrcAdr+=1;
+ DstAdr+=1;
+ }
+ break;
+
+
+ //
+ // Read 2 bytes at a time.
+ //
+
+ case 2:
+ while ( DstAdr < LastAdr) {
+ *(PUSHORT)DstAdr = READ_REGISTER_USHORT(VIDEO_CONTROL_VIRTUAL_BASE + (SrcAdr << AdrShift));
+ SrcAdr+=1;
+ DstAdr+=2;
+ }
+ break;
+
+
+ //
+ // Read 4 bytes at a time.
+ //
+
+ case 4:
+ case 8:
+
+ while ( DstAdr < LastAdr) {
+ *(PULONG)DstAdr = READ_REGISTER_ULONG(VIDEO_CONTROL_VIRTUAL_BASE + (SrcAdr << AdrShift));
+ SrcAdr+=1;
+ DstAdr+=4;
+ }
+ break;
+
+ }
+
+}
+
+#endif
diff --git a/private/ntos/fw/mips/jxvideo.h b/private/ntos/fw/mips/jxvideo.h
new file mode 100644
index 000000000..bf98df674
--- /dev/null
+++ b/private/ntos/fw/mips/jxvideo.h
@@ -0,0 +1,158 @@
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ jxvideo.h
+
+Abstract:
+
+ This module implements contains definitions for the interface with
+ the video prom initialization code.
+
+
+Author:
+
+ Lluis Abello (lluis) 16-Jul-1992
+
+Environment:
+
+ Kernel mode.
+
+
+Revision History:
+
+--*/
+
+#ifndef _JXVIDEO_
+
+#define _JXVIDEO_
+
+// The video PROM contains the following structure starting at offset zero
+// from the PROM base address. Each entry is 8 bytes wide with the low byte
+// containing data and the upper 7 bytes reserved.
+//
+// 63 8 7 0 Offset
+// +------------------+ +------------------+
+// | reserved | | Board_Identifier | 0x00
+// +------------------+ +------------------+
+// | reserved | | PROM_Stride | 0x08
+// +------------------+ +------------------+
+// | reserved | | PROM_Width | 0x10
+// +------------------+ +------------------+
+// | reserved | | PROM_Size | 0x18
+// +------------------+ +------------------+
+// | reserved | | Test_Byte_0 | 0x20
+// +------------------+ +------------------+
+// | reserved | | Test_Byte_1 | 0x28
+// +------------------+ +------------------+
+// | reserved | | Test_Byte_2 | 0x30
+// +------------------+ +------------------+
+// | reserved | | Test_Byte_3 | 0x38
+// +------------------+ +------------------+
+//
+//
+// Board_Identifier - supplies two bytes identifying the video board.
+//
+// PROM_Stride - supplies the stride of the PROM in bytes. Possible
+// values are:
+//
+// 1 - data every byte
+// 2 - data every 2 bytes
+// 4 - data every 4 bytes
+// 8 - data every 8 bytes
+//
+// PROM_Width - supplies the width of the PROM in bytes. Possible values
+// are:
+//
+// 1 - 1 byte wide
+// 2 - 2 bytes wide
+// 4 - 4 bytes wide
+// 8 - 8 bytes wide
+//
+// PROM_Size - supplies the size of the PROM in 4 KByte pages.
+//
+// Test_Bytes_[3:0] - supplies a test pattern ("Jazz").
+//
+// This strucure viewed from the video prom, i.e. the system
+//prom reads it taking into account PROM_Stride and PROM_Width
+//follows:
+//
+//typedef struct _VIDEO_PROM_CONFIGURATION {
+// ULONG VideoMemorySize;
+// ULONG VideoControlSize;
+// ULONG CodeOffset;
+// ULONG CodeSize;
+//} VIDEO_PROM_CONFIGURATION; *PVIDEO_PROM_CONFIGURATION;
+//
+//
+// VideoMemorySize - Supplies the size of video memory in bytes
+//
+// VideoControlSize - Supplies the size of video control in bytes
+//
+// CodeOffset - Supplies the offset in bytes from the beginning
+// of the video prom to the first byte of code which
+// is also the entry point of the initialization routine.
+//
+// CodeSize - Supplies the size of the code in bytes.
+//
+//
+//
+// Following this structure there is a IdentifierString -
+// Zero terminated string that identifies the video card "JazzG364", "
+// JazzVXL" ...
+
+
+
+typedef struct _VIDEO_PROM_CONFIGURATION {
+ ULONG VideoMemorySize;
+ ULONG VideoControlSize;
+ ULONG CodeOffset;
+ ULONG CodeSize;
+} VIDEO_PROM_CONFIGURATION, *PVIDEO_PROM_CONFIGURATION;
+
+
+typedef struct _VIDEO_VIRTUAL_SPACE {
+ ULONG MemoryVirtualBase;
+ ULONG ControlVirtualBase;
+} VIDEO_VIRTUAL_SPACE, *PVIDEO_VIRTUAL_SPACE;
+
+typedef
+ARC_STATUS
+(*PVIDEO_INITIALIZE_ROUTINE) (
+ IN PVIDEO_VIRTUAL_SPACE VideoAdr,
+ IN PMONITOR_CONFIGURATION_DATA VideoConfig
+ );
+
+#define InitializeVideo(VideoAdr, VideoConfig) \
+ ((PVIDEO_INITIALIZE_ROUTINE)(VIDEO_PROM_CODE_VIRTUAL_BASE)) \
+ ((VideoAdr), (VideoConfig))
+
+ARC_STATUS
+InitializeVideoFromProm(
+ IN PMONITOR_CONFIGURATION_DATA Monitor
+ );
+
+//
+// Define colors, HI = High Intensity
+//
+
+#define FW_COLOR_BLACK 0x00
+#define FW_COLOR_RED 0x01
+#define FW_COLOR_GREEN 0x02
+#define FW_COLOR_YELLOW 0x03
+#define FW_COLOR_BLUE 0x04
+#define FW_COLOR_MAGENTA 0x05
+#define FW_COLOR_CYAN 0x06
+#define FW_COLOR_WHITE 0x07
+#define FW_COLOR_HI_BLACK 0x08
+#define FW_COLOR_HI_RED 0x09
+#define FW_COLOR_HI_GREEN 0x0A
+#define FW_COLOR_HI_YELLOW 0x0B
+#define FW_COLOR_HI_BLUE 0x0C
+#define FW_COLOR_HI_MAGENTA 0x0D
+#define FW_COLOR_HI_CYAN 0x0E
+#define FW_COLOR_HI_WHITE 0x0F
+
+#endif
diff --git a/private/ntos/fw/mips/jzboot.c b/private/ntos/fw/mips/jzboot.c
new file mode 100644
index 000000000..cb90de71f
--- /dev/null
+++ b/private/ntos/fw/mips/jzboot.c
@@ -0,0 +1,1201 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jzboot.c
+
+Abstract:
+
+ This module contains the code to manage the boot selections.
+
+
+Author:
+
+ David M. Robinson (davidro) 25-Oct-1991
+
+Revision History:
+
+--*/
+
+#include "jzsetup.h"
+
+//
+// Routine prototypes.
+//
+
+ARC_STATUS
+JzPickSystemPartition (
+ OUT PCHAR SystemPartition,
+ IN OUT PULONG CurrentLine
+ );
+
+ARC_STATUS
+JzPickOsPartition (
+ OUT PCHAR OsPartition,
+ IN OUT PULONG CurrentLine
+ );
+
+
+ULONG
+JzGetYesNo (
+ IN PULONG CurrentLine,
+ IN PCHAR PromptString,
+ IN BOOLEAN YesIsDefault
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Line;
+ ULONG ReturnValue;
+
+ Line = *CurrentLine;
+ *CurrentLine += NUMBER_OF_YES_NO + 2;
+
+ JzSetPosition( Line, 0);
+ JzPrint(PromptString);
+
+ ReturnValue = JxDisplayMenu( YesNoChoices,
+ NUMBER_OF_YES_NO,
+ YesIsDefault ? 0 : 1,
+ Line + 1);
+
+ JzSetPosition( *CurrentLine, 0);
+ return ReturnValue;
+}
+
+ULONG
+JzGetCountdownValue (
+ IN PULONG CurrentLine
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Line;
+ ULONG ReturnValue;
+ CHAR TempString[5];
+ GETSTRING_ACTION Action;
+
+ Line = *CurrentLine;
+ *CurrentLine += 1;
+
+ JzSetPosition( Line, 0);
+
+ JzPrint(JZ_COUNTDOWN_MSG);
+ JzPrint("\x9bK");
+
+ do {
+ Action = FwGetString( TempString,
+ sizeof(TempString),
+ "5",
+ Line,
+ strlen(JZ_COUNTDOWN_MSG));
+
+ if (Action == GetStringEscape) {
+ return(-1);
+ }
+
+ } while ( Action != GetStringSuccess );
+
+ ReturnValue = atoi(TempString);
+ JzSetPosition( *CurrentLine, 0);
+
+ return ReturnValue;
+}
+
+
+VOID
+JzDeleteVariableSegment (
+ PCHAR VariableName,
+ ULONG Selection
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PCHAR Variable;
+ CHAR VariableValue[MAXIMUM_ENVIRONMENT_VALUE];
+ ULONG Index;
+ ULONG Count;
+ BOOLEAN FirstSegment;
+
+ if ((Variable = ArcGetEnvironmentVariable(VariableName)) == NULL) {
+ return;
+ }
+
+ FirstSegment = TRUE;
+ Index = 0;
+ *VariableValue = 0;
+ while (strchr(Variable,';') != NULL) {
+ Count = strchr(Variable,';') - Variable;
+ if (Index != Selection) {
+ if (!FirstSegment) {
+ strcat(VariableValue,";");
+ }
+ strncat(VariableValue, Variable, Count);
+ FirstSegment = FALSE;
+ }
+ Variable += Count + 1;
+ Index++;
+ }
+
+ if (Index != Selection) {
+ if (!FirstSegment) {
+ strcat(VariableValue,";");
+ }
+ strcat(VariableValue,Variable);
+ }
+
+ ArcSetEnvironmentVariable(VariableName, VariableValue);
+ return;
+}
+
+VOID
+JzAddBootSelection (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ARC_STATUS Status;
+ CHAR SystemPartition[128];
+ CHAR OsloaderFilename[80];
+ CHAR OsPartition[128];
+ CHAR OsFilename[80];
+ CHAR LoadIdentifier[80];
+ PCHAR Variable;
+ PCHAR TempPointer;
+ CHAR VariableValue[256];
+ ULONG Index;
+ UCHAR Character;
+ ULONG Count;
+ ULONG CurrentLine;
+ LONG YesNo;
+ BOOLEAN DebugOn;
+ GETSTRING_ACTION Action;
+ BOOLEAN SecondaryBoot;
+
+ JzClearScreen();
+ JzShowTime(TRUE);
+ CurrentLine = 2;
+ JzSetPosition( CurrentLine, 0);
+
+ //
+ // Count the boot selections
+ //
+
+ strcpy(OsPartition, BootString[OsLoadPartitionVariable]);
+ strcpy(OsFilename, BootString[OsLoadFilenameVariable]);
+
+ for ( Index = 0 ; Index < 4 ; Index++ ) {
+
+ SecondaryBoot = FwGetVariableSegment(Index, OsPartition);
+ SecondaryBoot = FwGetVariableSegment(Index, OsFilename) ||
+ SecondaryBoot;
+
+ if (!SecondaryBoot) {
+ break;
+ }
+ }
+
+ //
+ // Increment to new boot selection. Print warning and return if too many.
+ //
+
+ Index++;
+// if (Index == 5) {
+// JzPrint(" Too many boot selections, delete some before adding another,\r\n");
+// Index = 0;
+// goto MakeError;
+// }
+
+ //
+ // Pick a system partition.
+ //
+
+ if (JzPickSystemPartition(SystemPartition, &CurrentLine) != ESUCCESS) {
+ return;
+ }
+
+ JzPrint(JZ_OSLOADER_MSG);
+
+ do {
+ Action = FwGetString( OsloaderFilename,
+ sizeof(OsloaderFilename),
+ "\\os\\nt\\osloader.exe",
+ CurrentLine,
+ strlen(JZ_OSLOADER_MSG));
+ if (Action == GetStringEscape) {
+ return;
+ }
+ } while ( Action != GetStringSuccess );
+
+ CurrentLine += 1;
+ JzSetPosition( CurrentLine, 0);
+
+ YesNo = JzGetYesNo(&CurrentLine, JZ_OS_MSG, TRUE);
+ if (YesNo == -1) {
+ return;
+ }
+
+ if (YesNo == 0) {
+ strcpy(OsPartition, SystemPartition);
+ } else {
+
+ //
+ // Determine os partition.
+ //
+
+ if (JzPickOsPartition(OsPartition, &CurrentLine) != ESUCCESS) {
+ return;
+ }
+
+ }
+
+ JzPrint(JZ_OS_ROOT_MSG);
+
+ do {
+ Action = FwGetString( OsFilename,
+ sizeof(OsFilename),
+ "\\winnt",
+ CurrentLine,
+ strlen(JZ_OS_ROOT_MSG));
+ if (Action == GetStringEscape) {
+ return;
+ }
+ } while ( Action != GetStringSuccess );
+ CurrentLine += 1;
+ JzSetPosition( CurrentLine, 0);
+
+ JzPrint(JZ_BOOT_NAME_MSG);
+ do {
+ Action = FwGetString( LoadIdentifier,
+ sizeof(LoadIdentifier),
+ "Windows NT ",
+ CurrentLine,
+ strlen(JZ_BOOT_NAME_MSG));
+ if (Action == GetStringEscape) {
+ return;
+ }
+ } while ( Action != GetStringSuccess );
+ CurrentLine += 1;
+ JzSetPosition( CurrentLine, 0);
+
+ YesNo = JzGetYesNo(&CurrentLine,JZ_INIT_DEBUG_MSG , FALSE);
+ if (YesNo == -1) {
+ return;
+ }
+
+ if (YesNo == 0) {
+ DebugOn = TRUE;
+ } else {
+ DebugOn = FALSE;
+ }
+
+ Index = 0;
+ Status = FwSetVariableSegment(0, BootString[LoadIdentifierVariable], LoadIdentifier);
+ if (Status != ESUCCESS) {
+ goto MakeError;
+ }
+
+
+ Index = 1;
+
+ //
+ // If the SystemPartition variable is set but the Osloader variable is null,
+ // clear the SystemPartition variable before adding it back.
+ //
+
+ if ((ArcGetEnvironmentVariable(BootString[SystemPartitionVariable]) != NULL) &&
+ (ArcGetEnvironmentVariable(BootString[OsLoaderVariable]) == NULL)) {
+ ArcSetEnvironmentVariable(BootString[SystemPartitionVariable],"");
+ }
+ Status = FwSetVariableSegment(0, BootString[SystemPartitionVariable], SystemPartition);
+ if (Status != ESUCCESS) {
+ goto MakeError;
+ }
+
+ //
+ // Add a new selection to the OSLOADER environment variable.
+ //
+
+ Index = 2;
+ strcpy(VariableValue, SystemPartition);
+ strcat(VariableValue, OsloaderFilename);
+ Status = FwSetVariableSegment(0, BootString[OsLoaderVariable], VariableValue);
+
+ if (Status != ESUCCESS) {
+ goto MakeError;
+ }
+
+ //
+ // Add a new selection to the OSLOADPARTITION environment variable.
+ //
+
+ Index = 3;
+ Status = FwSetVariableSegment(0, BootString[OsLoadPartitionVariable], OsPartition);
+ if (Status != ESUCCESS) {
+ goto MakeError;
+ }
+
+ //
+ // Add a new selection to the OSLOADFILENAME environment variable.
+ //
+
+ Index = 4;
+ Status = FwSetVariableSegment(0, BootString[OsLoadFilenameVariable], OsFilename);
+ if (Status != ESUCCESS) {
+ goto MakeError;
+ }
+
+ //
+ // Add a new selection to the OSLOADOPTIONS environment variable.
+ //
+
+ if (DebugOn) {
+ strcpy(VariableValue, "debug");
+ } else {
+ strcpy(VariableValue, "nodebug");
+ }
+
+ Index = 5;
+ Status = FwSetVariableSegment(0, BootString[OsLoadOptionsVariable], VariableValue);
+ if (Status != ESUCCESS) {
+ goto MakeError;
+ }
+
+ return;
+
+MakeError:
+
+ JzPrint(JZ_CANT_SET_VARIABLE_MSG);
+
+ //
+ // Delete any segments that were added.
+ //
+
+ for ( Count = 0 ; Count < Index ; Count++ ) {
+ JzDeleteVariableSegment(BootString[Count], 0);
+ }
+
+ FwWaitForKeypress();
+}
+
+
+LONG
+JzPickBootSelection (
+ IN OUT PULONG CurrentLine,
+ IN PCHAR PromptString
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allows the user to indicate a boot selection choice.
+
+Arguments:
+
+ CurrentLine - Supplies a pointer to the current display line value.
+
+ PromptString - Supplies a pointer to a string which indicates the reason
+ the boot selection choice is needed.
+
+Return Value:
+
+ Returns the boot selection number, -1 if none.
+
+--*/
+{
+ PCHAR Variable;
+ CHAR VariableValue[MAXIMUM_ENVIRONMENT_VALUE];
+ CHAR BootChoices[5][128];
+ PCHAR BootMenu[5];
+ CHAR OsloadPartition[128];
+ CHAR OsloadFilename[128];
+ CHAR LoadIdentifier[80];
+ BOOLEAN SecondaryBoot;
+ ULONG Index;
+ ULONG Selection;
+
+ //
+ // Get each boot selection
+ //
+
+ strcpy(OsloadPartition, BootString[OsLoadPartitionVariable]);
+ strcpy(OsloadFilename, BootString[OsLoadFilenameVariable]);
+ strcpy(LoadIdentifier, BootString[LoadIdentifierVariable]);
+
+ for ( Index = 0 ; ; Index++ ) {
+
+ SecondaryBoot = FwGetVariableSegment(Index, OsloadPartition);
+ SecondaryBoot = FwGetVariableSegment(Index, OsloadFilename) ||
+ SecondaryBoot;
+ SecondaryBoot = FwGetVariableSegment(Index, LoadIdentifier) ||
+ SecondaryBoot;
+
+ if (LoadIdentifier[sizeof("LOADIDENTIFIER=") - 1] != 0) {
+ strcpy(BootChoices[Index],
+ &LoadIdentifier[sizeof("LOADIDENTIFIER=") - 1]);
+ } else {
+ strcpy(BootChoices[Index],
+ &OsloadPartition[sizeof("OsloadPartition=") - 1]);
+ strcat(BootChoices[Index],
+ &OsloadFilename[sizeof("OsloadFilename=") - 1]);
+ }
+
+ BootMenu[Index] = BootChoices[Index];
+
+ if (!SecondaryBoot || (Index == 4)) {
+ break;
+ }
+ }
+
+ JzPrint(PromptString);
+ *CurrentLine += 1;
+
+ Selection = JxDisplayMenu( BootMenu,
+ Index + 1,
+ 0,
+ *CurrentLine);
+
+ JzSetPosition(*CurrentLine, 0);
+
+ return(Selection);
+}
+
+VOID
+JzDeleteBootSelection (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine deletes a boot selection from the boot environment variables.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ARC_STATUS Status;
+ ULONG CurrentLine;
+ LONG Selection;
+ ULONG Index;
+
+ JzClearScreen();
+ JzShowTime(TRUE);
+ CurrentLine = 2;
+ JzSetPosition( CurrentLine, 0);
+
+ if (ArcGetEnvironmentVariable(BootString[OsLoadPartitionVariable]) == NULL) {
+ JzPrint(JZ_NO_SELECTIONS_TO_DELETE_MSG);
+ CurrentLine += 1;
+ FwWaitForKeypress();
+ return;
+ }
+
+ Selection = JzPickBootSelection( &CurrentLine, JZ_SELECTION_TO_DELETE_MSG);
+
+ if (Selection == -1) {
+ return;
+ }
+
+ for ( Index = 0 ; Index < MaximumBootVariable ; Index++ ) {
+ JzDeleteVariableSegment(BootString[Index],Selection);
+ }
+
+ JzPrint(JZ_CRLF_MSG);
+
+ return;
+}
+
+VOID
+JzEditSelection (
+ LONG Selection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allows the environment variables for a specified boot
+ selection to be edited.
+
+Arguments:
+
+ Selection - Specifies the boot selection to edit.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ARC_STATUS Status;
+ CHAR SystemPartition[128];
+ CHAR Osloader[128];
+ CHAR OsloadPartition[128];
+ CHAR OsloadFilename[128];
+ CHAR OsloadOptions[128];
+ CHAR LoadIdentifier[128];
+
+ do {
+ JzClearScreen();
+ JzShowTime(TRUE);
+ JzSetPosition( 7, 0);
+
+ //
+ // Display the current boot selection environment variables.
+ //
+
+ strcpy(SystemPartition, BootString[SystemPartitionVariable]);
+ strcpy(Osloader, BootString[OsLoaderVariable]);
+ strcpy(OsloadPartition, BootString[OsLoadPartitionVariable]);
+ strcpy(OsloadFilename, BootString[OsLoadFilenameVariable]);
+ strcpy(OsloadOptions, BootString[OsLoadOptionsVariable]);
+ strcpy(LoadIdentifier, BootString[LoadIdentifierVariable]);
+ FwGetVariableSegment(Selection, SystemPartition);
+ FwGetVariableSegment(Selection, Osloader);
+ FwGetVariableSegment(Selection, OsloadPartition);
+ FwGetVariableSegment(Selection, OsloadFilename);
+ FwGetVariableSegment(Selection, OsloadOptions);
+ FwGetVariableSegment(Selection, LoadIdentifier);
+
+ JzPrint( JZ_ENVIR_FOR_BOOT_MSG,
+ Selection + 1);
+
+ JzPrint(JZ_FORMAT1_MSG, LoadIdentifier);
+ JzPrint(JZ_FORMAT1_MSG, SystemPartition);
+ JzPrint(JZ_FORMAT1_MSG, Osloader);
+ JzPrint(JZ_FORMAT1_MSG, OsloadPartition);
+ JzPrint(JZ_FORMAT1_MSG, OsloadFilename);
+ JzPrint(JZ_FORMAT1_MSG, OsloadOptions);
+
+ JzSetPosition( 2, 0);
+ JzPrint(JZ_USE_ARROWS_MSG);
+
+ } while ( JzSetBootEnvironmentVariable(Selection) );
+ return;
+}
+
+VOID
+JzEditBootSelection (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allows the environment variables for a boot selection to
+ be edited.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ARC_STATUS Status;
+ ULONG CurrentLine;
+ LONG Selection;
+
+ JzClearScreen();
+ JzShowTime(TRUE);
+ CurrentLine = 2;
+ JzSetPosition( CurrentLine, 0);
+
+ if (ArcGetEnvironmentVariable(BootString[OsLoadPartitionVariable]) == NULL) {
+ JzPrint(JZ_NO_SELECTIONS_TO_EDIT_MSG);
+ CurrentLine += 1;
+ FwWaitForKeypress();
+ return;
+ }
+
+ Selection = JzPickBootSelection( &CurrentLine, JZ_SELECTION_TO_EDIT_MSG);
+
+ if (Selection == -1) {
+ return;
+ }
+
+ JzEditSelection(Selection);
+
+ return;
+}
+
+VOID
+JzRearrangeBootSelections (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allows the environment variables for a boot selection to
+ be rearranged.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ARC_STATUS Status;
+ ULONG CurrentLine;
+ LONG Selection;
+ ULONG Index;
+ CHAR Segment[128];
+
+ JzClearScreen();
+ JzShowTime(TRUE);
+ CurrentLine = 2;
+ JzSetPosition( CurrentLine, 0);
+
+ if (ArcGetEnvironmentVariable(BootString[OsLoadPartitionVariable]) == NULL) {
+ JzPrint(JZ_NO_SELECTIONS_TO_REARRANGE_MSG);
+ CurrentLine += 1;
+ FwWaitForKeypress();
+ return;
+ }
+
+ do {
+ JzClearScreen();
+ JzShowTime(TRUE);
+ CurrentLine = 2;
+ JzSetPosition( CurrentLine, 0);
+
+ Selection = JzPickBootSelection( &CurrentLine, JZ_PICK_SELECTION_MSG);
+
+ if (Selection == -1) {
+ continue;
+ }
+
+ for ( Index = 0 ; Index < MaximumBootVariable ; Index++ ) {
+ strcpy( Segment, BootString[Index]);
+ FwGetVariableSegment( Selection, Segment );
+ JzDeleteVariableSegment( BootString[Index], Selection );
+ FwSetVariableSegment( 0, BootString[Index], strchr(Segment, '=') + 1);
+ }
+ } while ( Selection != -1 );
+ return;
+}
+
+
+VOID
+JzSetupAutoboot (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allows the environment variables controlling autoboot
+ to be set.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ARC_STATUS Status;
+ ULONG Autoboot;
+ ULONG Countdown;
+ CHAR CountdownString[5];
+ ULONG CurrentLine;
+
+ JzClearScreen();
+ JzShowTime(TRUE);
+ CurrentLine = 2;
+
+ Autoboot = JzGetYesNo(&CurrentLine, JZ_SHOULD_AUTOBOOT_MSG, FALSE);
+ if (Autoboot == -1) {
+ return;
+ }
+
+ switch (Autoboot) {
+ case 0:
+ Status = ArcSetEnvironmentVariable("AUTOLOAD",
+ "YES");
+ break;
+ default:
+ Status = ArcSetEnvironmentVariable("AUTOLOAD",
+ "NO");
+ break;
+ }
+
+ if (Status != ESUCCESS) {
+ JzPrint(JZ_CANT_SET_VARIABLE_MSG);
+ return;
+ }
+
+ if (Autoboot != 0) {
+ return;
+ }
+
+ Countdown = JzGetCountdownValue(&CurrentLine);
+ if (Countdown == -1) {
+ return;
+ }
+
+ if (Countdown != 5) {
+ sprintf( CountdownString,
+ "%d",
+ Countdown);
+
+ Status = ArcSetEnvironmentVariable("COUNTDOWN",
+ CountdownString);
+
+ if (Status != ESUCCESS) {
+ JzPrint(JZ_CANT_SET_VARIABLE_MSG);
+ return;
+ }
+ } else {
+ ArcSetEnvironmentVariable("COUNTDOWN",
+ "");
+ }
+
+ return;
+}
+
+
+VOID
+JzEditVariable (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allows environment variables to be edited.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ARC_STATUS Status;
+ ULONG CurrentLine;
+ PCHAR Variable;
+ ULONG Index, Count;
+
+
+ do {
+
+ JzClearScreen();
+ JzShowTime(TRUE);
+ JzSetPosition( 7, 0);
+
+ //
+ // Get the entire environment.
+ //
+
+ Variable = FwEnvironmentLoad();
+
+ JzPrint(JZ_ENVIRONMENT_VARS_MSG);
+
+ if (Variable != NULL) {
+
+ //
+ // Print all of the other environment variables.
+ //
+
+ while (*Variable) {
+
+ if ((strstr(Variable, "SYSTEMPARTITION=") == NULL) &&
+ (strstr(Variable, "OSLOADER=") == NULL) &&
+ (strstr(Variable, "OSLOADPARTITION=") == NULL) &&
+ (strstr(Variable, "OSLOADFILENAME=") == NULL) &&
+ (strstr(Variable, "OSLOADOPTIONS=") == NULL) &&
+ (strstr(Variable, "LOADIDENTIFIER=") == NULL)) {
+
+ JzPrint(" ");
+ while (strchr(Variable,';') != NULL) {
+ Index = strchr(Variable,';') - Variable + 1;
+ ArcWrite(ARC_CONSOLE_OUTPUT, Variable, Index, &Count);
+ JzPrint("\r\n ");
+ Variable += Index;
+ }
+ JzPrint(Variable);
+ JzPrint(JZ_CRLF_MSG);
+ }
+ Variable = strchr(Variable,'\0') + 1;
+ }
+ }
+
+ JzSetPosition( 2, 0);
+ JzPrint(JZ_USE_ARROWS_MSG);
+
+ } while ( JzSetEnvironmentVariable() );
+ return;
+}
+
+BOOLEAN
+JzCheckBootSelection (
+ IN LONG Selection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks the integrity of a boot selection.
+
+Arguments:
+
+ Selection - The number of the selection to check.
+
+Return Value:
+
+ Returns TRUE if there are more selections after the current one, otherwise
+ returns FALSE.
+
+--*/
+{
+ ARC_STATUS Status;
+ ULONG CurrentLine;
+ ULONG Fid;
+ ULONG MenuSelection;
+ ULONG Index;
+ CHAR Segment[128];
+ CHAR Value[128];
+ BOOLEAN MoreSelections;
+ BOOLEAN Problem;
+
+ JzClearScreen();
+ JzSetPosition( 2, 0);
+ JzPrint(JZ_CHECKING_BOOT_SEL_MSG, Selection);
+
+ CurrentLine = 5 + NUMBER_OF_PROBLEMS;
+ JzSetPosition( CurrentLine, 0);
+
+ MoreSelections = FALSE;
+ Problem = FALSE;
+
+ JzSetScreenColor( ArcColorYellow, ArcColorBlue);
+
+ for ( Index = 0 ; Index < MaximumBootVariable ; Index++ ) {
+
+ strcpy(Segment, BootString[Index]);
+ MoreSelections = FwGetVariableSegment(Selection, Segment) || MoreSelections;
+ strcpy(Value, strchr(Segment, '=') + 1);
+
+ //
+ // Check to make sure the value is not NULL, except for OsloadOptions
+ // which can legally have a NULL value.
+ //
+
+ if (Index != OsLoadOptionsVariable) {
+ if (Value[0] == 0) {
+ Problem = TRUE;
+ JzPrint(JZ_VARIABLE_NULL_MSG, BootString[Index]);
+ continue;
+ }
+ }
+
+ //
+ // If this is the SystemPartition, Osloader, or OsloadPartition variable,
+ // check to make sure it can be opened.
+ //
+
+ if ((Index == SystemPartitionVariable) ||
+ (Index == OsLoaderVariable) ||
+ (Index == OsLoadPartitionVariable) ) {
+
+ if (ArcOpen(Value, ArcOpenReadOnly, &Fid) != ESUCCESS) {
+ Problem = TRUE;
+ JzPrint( JZ_CANT_BE_FOUND_MSG,
+ BootString[Index]);
+ JzPrint( JZ_FORMAT1_MSG,
+ Value);
+ } else {
+ ArcClose(Fid);
+ }
+
+ }
+ }
+
+ JzSetScreenColor( ArcColorWhite, ArcColorBlue);
+
+ if (Problem) {
+
+ JzShowTime(TRUE);
+ CurrentLine = 2;
+ JzSetPosition( CurrentLine, 0);
+
+ JzPrint( JZ_PROBLEMS_FOUND_MSG, Selection);
+
+ MenuSelection = JxDisplayMenu( ProblemChoices,
+ NUMBER_OF_PROBLEMS,
+ 0,
+ CurrentLine + 2);
+
+ //
+ // Switch based on the action.
+ //
+
+ switch (MenuSelection) {
+
+ //
+ // Ignore
+ //
+
+ case 0:
+ break;
+
+ //
+ // Delete this boot selection
+ //
+
+ case 1:
+
+ for ( Index = 0 ; Index < MaximumBootVariable ; Index++ ) {
+ JzDeleteVariableSegment(BootString[Index],Selection);
+ }
+ break;
+
+ //
+ // Edit this boot selection
+ //
+
+ case 2:
+ JzEditSelection(Selection);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return(MoreSelections);
+}
+
+
+VOID
+JzCheckBootSelections (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine cycles through all of the boot selections and checks them.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Index;
+
+ //
+ // Look to see if any boot selections exist. Skip the SystemPartition
+ // variable because that can be set without any selections.
+ //
+
+ for ( Index = 0 ; Index < MaximumBootVariable ; Index++ ) {
+ if ( (Index != SystemPartitionVariable) &&
+ (ArcGetEnvironmentVariable(BootString[Index]) != NULL)) {
+ break;
+ }
+ }
+
+ //
+ // If there are boot selections, check them.
+ //
+
+ if (Index != MaximumBootVariable) {
+ Index = 0;
+ while (JzCheckBootSelection(Index)) {
+ Index++;
+ }
+ }
+ return;
+}
+
+
+VOID
+JzBootMenu(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine displays the boot menu.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ LONG DefaultChoice = 0;
+
+ //
+ // Loop on choices until exit is selected.
+ //
+
+ while (TRUE) {
+
+ DefaultChoice = JzGetSelection(JzBootChoices,
+ NUMBER_OF_JZ_BOOT_CHOICES,
+ DefaultChoice);
+
+ //
+ // If the escape key was pressed, return.
+ //
+
+ if (DefaultChoice == -1) {
+ DefaultChoice = 0x7fffffff;
+ }
+
+ //
+ // Switch based on the action.
+ //
+
+ switch (DefaultChoice) {
+
+ //
+ // Add boot selection
+ //
+
+ case 0:
+ JzAddBootSelection();
+ break;
+
+ //
+ // Delete a boot selection
+ //
+
+ case 1:
+ JzDeleteBootSelection();
+ break;
+
+ //
+ // Edit a boot selection
+ //
+
+ case 2:
+ JzEditBootSelection();
+ break;
+
+ //
+ // Rearrange boot selections
+ //
+
+ case 3:
+ JzRearrangeBootSelections();
+ break;
+
+ //
+ // Check boot selections
+ //
+
+ case 4:
+ JzCheckBootSelections();
+ break;
+
+ //
+ // Setup autoboot parameters
+ //
+
+ case 5:
+ JzSetupAutoboot();
+ break;
+
+ //
+ // Exit.
+ //
+
+ default:
+ return;
+ }
+ }
+}
diff --git a/private/ntos/fw/mips/jzcommon.c b/private/ntos/fw/mips/jzcommon.c
new file mode 100644
index 000000000..2041a43eb
--- /dev/null
+++ b/private/ntos/fw/mips/jzcommon.c
@@ -0,0 +1,876 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jzcommon.c
+
+Abstract:
+
+ This program contains the common routines for the Jazz setup program.
+
+Author:
+
+ David M. Robinson (davidro) 25-Oct-1991
+
+Revision History:
+
+--*/
+
+#include "jzsetup.h"
+
+//
+// Static Data
+//
+
+CHAR VolatileEnvironment[LENGTH_OF_ENVIRONMENT];
+BOOLEAN SetupIsRunning;
+extern PCHAR Banner1, Banner2;
+
+int
+vsprintf (
+ char *string,
+ char *format,
+ va_list arglist);
+
+VOID
+JzPrint (
+ PCHAR Format,
+ ...
+ )
+
+{
+
+ va_list arglist;
+ UCHAR Buffer[256];
+ ULONG Count;
+ ULONG Length;
+
+ //
+ // Format the output into a buffer and then print it.
+ //
+
+ va_start(arglist, Format);
+ Length = vsprintf(Buffer, Format, arglist);
+
+ ArcWrite( ARC_CONSOLE_OUTPUT, Buffer, Length, &Count);
+
+ va_end(arglist);
+ return 0;
+}
+
+
+ULONG
+JxDisplayMenu (
+ IN PCHAR Choices[],
+ IN ULONG NumberOfChoices,
+ IN LONG DefaultChoice,
+ IN ULONG CurrentLine
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ Returns -1 if the escape key is pressed, otherwise returns the menu item
+ selected, where 0 is the first item.
+
+--*/
+
+{
+ ULONG Index;
+ UCHAR Character;
+ ULONG Count;
+
+ for (Index = 0; Index < NumberOfChoices ; Index++ ) {
+ JzSetPosition( Index + CurrentLine, 10);
+ if (Index == DefaultChoice) {
+ JzSetScreenAttributes( TRUE, FALSE, TRUE);
+ JzPrint(Choices[Index]);
+ JzSetScreenAttributes( TRUE, FALSE, FALSE);
+ } else {
+ JzPrint(Choices[Index]);
+ }
+ }
+
+ Character = 0;
+ do {
+ if (SetupIsRunning) {
+ JzShowTime(FALSE);
+ }
+ if (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ switch (Character) {
+
+ case ASCII_ESC:
+
+ //
+ // If there is another character available, look to see if
+ // this a control sequence. This is an attempt to make
+ // Escape sequences from a terminal work.
+ //
+
+ JzStallExecution(10000);
+
+ if (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ if (Character != '[') {
+ return(-1);
+ }
+ } else {
+ return(-1);
+ }
+
+ case ASCII_CSI:
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ JzSetPosition( DefaultChoice + CurrentLine, 10);
+ JzPrint(Choices[DefaultChoice]);
+ switch (Character) {
+ case 'A':
+ case 'D':
+ DefaultChoice--;
+ if (DefaultChoice < 0) {
+ DefaultChoice = NumberOfChoices-1;
+ }
+ break;
+ case 'B':
+ case 'C':
+ DefaultChoice++;
+ if (DefaultChoice == NumberOfChoices) {
+ DefaultChoice = 0;
+ }
+ break;
+ case 'H':
+ DefaultChoice = 0;
+ break;
+ default:
+ break;
+ }
+ JzSetPosition( DefaultChoice + CurrentLine, 10);
+ JzSetScreenAttributes( TRUE, FALSE, TRUE);
+ JzPrint(Choices[DefaultChoice]);
+ JzSetScreenAttributes( TRUE, FALSE, FALSE);
+ continue;
+
+ default:
+ break;
+ }
+ }
+
+ } while ((Character != '\n') && (Character != ASCII_CR));
+
+ return DefaultChoice;
+}
+
+
+GETSTRING_ACTION
+FwGetString(
+ OUT PCHAR String,
+ IN ULONG StringLength,
+ IN PCHAR InitialString OPTIONAL,
+ IN ULONG CurrentRow,
+ IN ULONG CurrentColumn
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads a string from standardin until a carriage return is
+ found, StringLength is reached, or ESC is pushed.
+
+Arguments:
+
+ String - Supplies a pointer to a location where the string is to be stored.
+
+ StringLength - Supplies the Max Length to read.
+
+ InitialString - Supplies an optional initial string.
+
+ CurrentRow - Supplies the current screen row.
+
+ CurrentColumn - Supplies the current screen column.
+
+Return Value:
+
+ If the string was successfully obtained GetStringSuccess is return,
+ otherwise one of the following codes is returned.
+
+ GetStringEscape - the escape key was pressed or StringLength was reached.
+ GetStringUpArrow - the up arrow key was pressed.
+ GetStringDownArrow - the down arrow key was pressed.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ UCHAR c;
+ ULONG Count;
+ PCHAR Buffer;
+ PCHAR Cursor;
+ PCHAR CopyPointer;
+ GETSTRING_ACTION Action;
+ BOOLEAN CarriageReturn;
+
+ //
+ // If an initial string was supplied, update the output string.
+ //
+
+ if (ARGUMENT_PRESENT(InitialString)) {
+ strcpy(String, InitialString);
+ Buffer = strchr(String, 0);
+ } else {
+ *String = 0;
+ Buffer = String;
+ }
+
+ Cursor = Buffer;
+
+ while (TRUE) {
+
+ //
+ // Flag to print a carriage return/line feed when all is done.
+ //
+
+ CarriageReturn = FALSE;
+
+ //
+ // Print the string.
+ //
+
+ JzSetPosition(CurrentRow, CurrentColumn);
+ JzPrint(String);
+ JzPrint("\x9bK");
+
+ //
+ // Print the cursor.
+ //
+
+ JzSetScreenAttributes(TRUE,FALSE,TRUE);
+ JzSetPosition(CurrentRow, (Cursor - String) + CurrentColumn);
+ if (Cursor >= Buffer) {
+ JzPrint(" ");
+ } else {
+ ArcWrite(ARC_CONSOLE_OUTPUT,Cursor,1,&Count);
+ }
+ JzSetScreenAttributes(TRUE,FALSE,FALSE);
+
+ while (ArcGetReadStatus(ARC_CONSOLE_INPUT) != ESUCCESS) {
+ if (SetupIsRunning) {
+ JzShowTime(FALSE);
+ }
+ }
+ Status = ArcRead(ARC_CONSOLE_INPUT,&c,1,&Count);
+
+ if (Status != ESUCCESS) {
+ Action = GetStringEscape;
+ goto EndGetString;
+ }
+
+ if (Buffer-String == StringLength) {
+ Action = GetStringEscape;
+ goto EndGetString;
+ }
+
+ switch (c) {
+ case ASCII_ESC:
+
+ //
+ // If there is another character available, look to see if
+ // this a control sequence, and fall through to ASCII_CSI.
+ // This is an attempt to make escape sequences from a terminal work.
+ //
+
+ JzStallExecution(10000);
+
+ if (ArcGetReadStatus(ARC_CONSOLE_INPUT) == ESUCCESS) {
+ ArcRead(ARC_CONSOLE_INPUT, &c, 1, &Count);
+ if (c != '[') {
+ Action = GetStringEscape;
+ goto EndGetString;
+ }
+ } else {
+ Action = GetStringEscape;
+ goto EndGetString;
+ }
+
+ case ASCII_CSI:
+
+ ArcRead(ARC_CONSOLE_INPUT, &c, 1, &Count);
+ switch (c) {
+
+ case 'A':
+ Action = GetStringUpArrow;
+ goto EndGetString;
+
+ case 'D':
+ if (Cursor != String) {
+ Cursor--;
+ }
+ continue;
+
+ case 'B':
+ Action = GetStringDownArrow;
+ goto EndGetString;
+
+ case 'C':
+ if (Cursor != Buffer) {
+ Cursor++;
+ }
+ continue;
+
+ case 'H':
+ Cursor = String;
+ continue;
+
+ case 'K':
+ Cursor = Buffer;
+ continue;
+
+ case 'P':
+ CopyPointer = Cursor;
+ while (*CopyPointer) {
+ *CopyPointer = *(CopyPointer + 1);
+ CopyPointer++;
+ }
+ if (Buffer != String) {
+ Buffer--;
+ }
+ continue;
+
+ default:
+ break;
+ }
+ break;
+
+ case '\r':
+ case '\n':
+
+ CarriageReturn = TRUE;
+ Action = GetStringSuccess;
+ goto EndGetString;
+
+ case '\b':
+
+ if (Cursor != String) {
+ Cursor--;
+ }
+ CopyPointer = Cursor;
+ while (*CopyPointer) {
+ *CopyPointer = *(CopyPointer + 1);
+ CopyPointer++;
+ }
+ if (Buffer != String) {
+ Buffer--;
+ }
+ break;
+
+ default:
+
+ //
+ // Store the character.
+ //
+
+ CopyPointer = ++Buffer;
+ if (CopyPointer > Cursor) {
+ while (CopyPointer != Cursor) {
+ *CopyPointer = *(CopyPointer - 1);
+ CopyPointer--;
+ }
+ }
+ *Cursor++ = c;
+ break;
+ }
+ }
+ Action = GetStringEscape;
+
+EndGetString:
+
+ //
+ // Clear the cursor.
+ //
+
+ JzSetPosition(CurrentRow, (Cursor - String) + CurrentColumn);
+ if (Cursor >= Buffer) {
+ JzPrint(" ");
+ } else {
+ ArcWrite(ARC_CONSOLE_OUTPUT,Cursor,1,&Count);
+ }
+
+ if (CarriageReturn) {
+ ArcWrite(ARC_CONSOLE_OUTPUT,JZ_CRLF_MSG,2,&Count);
+ }
+
+ //
+ // Make sure we return a null string if not successful.
+ //
+
+ if (Action != GetStringSuccess) {
+ *String = 0;
+ }
+
+ return(Action);
+}
+
+
+ARC_STATUS
+FwEnvironmentCheckChecksum (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks the environment area checksum.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the checksum is good, ESUCCESS is returned, otherwise EIO is returned.
+
+--*/
+
+{
+ PUCHAR NvChars;
+ PNV_CONFIGURATION NvConfiguration;
+ ULONG Index;
+ ULONG Checksum1, Checksum2;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // Form checksum from NVRAM data.
+ //
+
+ Checksum1 = 0;
+ NvChars = (PUCHAR)&NvConfiguration->Environment[0];
+
+ for ( Index = 0 ;
+ Index < LENGTH_OF_ENVIRONMENT;
+ Index++ ) {
+ Checksum1 += READ_REGISTER_UCHAR( NvChars++ );
+ }
+
+ //
+ // Reconstitute checksum and return error if no compare.
+ //
+
+ Checksum2 = (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum2[0] ) |
+ (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum2[1] ) << 8 |
+ (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum2[2] ) << 16 |
+ (ULONG)READ_REGISTER_UCHAR( &NvConfiguration->Checksum2[3] ) << 24 ;
+
+ if (Checksum1 != Checksum2) {
+ return EIO;
+ } else {
+ return ESUCCESS;
+ }
+}
+
+PCHAR
+FwEnvironmentLoad (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine loads the entire environment into a volatile environment
+ area.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the checksum is good, a pointer to the environment in returned,
+ otherwise NULL is returned.
+
+--*/
+
+{
+ ULONG Index;
+ PUCHAR NvChars;
+ PUCHAR VChars;
+ PNV_CONFIGURATION NvConfiguration;
+
+ if (FwEnvironmentCheckChecksum() == ESUCCESS) {
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // Copy the data into the volatile area.
+ //
+
+ NvChars = (PUCHAR)&NvConfiguration->Environment[0];
+ VChars = (PUCHAR)&VolatileEnvironment;
+
+ for ( Index = 0 ;
+ Index < LENGTH_OF_ENVIRONMENT;
+ Index++ ) {
+ *VChars++ = READ_REGISTER_UCHAR( NvChars++ );
+ }
+
+ return (PCHAR)&VolatileEnvironment;
+ } else {
+ return NULL;
+ }
+}
+
+
+BOOLEAN
+FwGetPathMnemonicKey(
+ IN PCHAR OpenPath,
+ IN PCHAR Mnemonic,
+ IN PULONG Key
+ )
+
+/*++
+
+Routine Description:
+
+ This routine looks for the given Mnemonic in OpenPath.
+ If Mnemonic is a component of the path, then it converts the key
+ value to an integer wich is returned in Key.
+
+Arguments:
+
+ OpenPath - Pointer to a string that contains an ARC pathname.
+
+ Mnemonic - Pointer to a string that contains a ARC Mnemonic
+
+ Key - Pointer to a ULONG where the Key value is stored.
+
+
+Return Value:
+
+ FALSE if mnemonic is found in path and a valid key is converted.
+ TRUE otherwise.
+
+--*/
+
+{
+
+ PCHAR Tmp;
+ CHAR Digits[4];
+ ULONG i;
+ CHAR String[16];
+
+ //
+ // Construct a string of the form ")mnemonic("
+ //
+ String[0]=')';
+ for(i=1;*Mnemonic;i++) {
+ String[i] = * Mnemonic++;
+ }
+ String[i++]='(';
+ String[i]='\0';
+
+ if ((Tmp=strstr(OpenPath,&String[1])) == NULL) {
+ return TRUE;
+ }
+
+ if (Tmp != OpenPath) {
+ if ((Tmp=strstr(OpenPath,String)) == NULL) {
+ return TRUE;
+ }
+ } else {
+ i--;
+ }
+ //
+ // skip the mnemonic and convert the value in between parentesis to integer
+ //
+ Tmp+=i;
+ for (i=0;i<3;i++) {
+ if (*Tmp == ')') {
+ Digits[i] = '\0';
+ break;
+ }
+ Digits[i] = *Tmp++;
+ }
+ Digits[i]='\0';
+ *Key = atoi(Digits);
+ return FALSE;
+}
+
+
+VOID
+FwWaitForKeypress(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine waits for a keypress, then returns.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR Character;
+ ULONG Count;
+
+ JzPrint(JZ_PRESS_KEY_MSG);
+ while (ArcGetReadStatus(ARC_CONSOLE_INPUT) != ESUCCESS) {
+ if (SetupIsRunning) {
+ JzShowTime(FALSE);
+ }
+ }
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ JzPrint("%c2J", ASCII_CSI);
+}
+
+BOOLEAN
+FwGetVariableSegment (
+ IN ULONG SegmentNumber,
+ IN OUT PCHAR Segment
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the specified segment of an environment variable.
+ Segments are separated by semicolons.
+
+Arguments:
+
+ SegmentNumber - Supplies the number of the segment to return.
+
+ Segment - Supplies a pointer to the name of the environment variable.
+ The variable may be followed by an equal sign.
+ An '=' and the segment value are appended to this name and
+ returned.
+
+
+Return Value:
+
+ If one or more segments exist after the specified segment, TRUE is returned,
+ otherwise FALSE is returned.
+
+--*/
+
+{
+ ULONG Index;
+ ULONG Count;
+ PCHAR VariableValue;
+ PCHAR TempPointer;
+
+ //
+ // Remove an equal sign if present.
+ //
+
+ if ((TempPointer = strchr(Segment, '=')) != NULL) {
+ *TempPointer = 0;
+ }
+
+ //
+ // Get variable, add equal sign, and advance Segment to where the value
+ // is to be added.
+ //
+
+ VariableValue = ArcGetEnvironmentVariable(Segment);
+ strcat(Segment, "=");
+ Segment = strchr(Segment, '=') + 1;
+
+ //
+ // If there was no variable, return.
+ //
+
+ if (VariableValue == NULL) {
+ return(FALSE);
+ }
+
+ Index = 0;
+ Count = 0;
+
+ //
+ // Search for the requested segment and copy it to the return value.
+ //
+
+ while ((TempPointer = strchr(VariableValue,';')) != NULL) {
+ Count = TempPointer - VariableValue;
+
+ if (Index == SegmentNumber) {
+ strncpy(Segment, VariableValue, Count);
+ Segment[Count] = 0;
+ return TRUE;
+ }
+
+ VariableValue += Count + 1;
+ Index++;
+ }
+
+ //
+ // If there is data left, copy it to the return value.
+ //
+
+ strcpy(Segment,VariableValue);
+
+ return(FALSE);
+}
+
+ARC_STATUS
+FwSetVariableSegment (
+ IN ULONG SegmentNumber,
+ IN PCHAR VariableName,
+ IN PCHAR NewSegment
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the specified segment of an environment variable.
+ Segments are separated by semicolons.
+
+Arguments:
+
+ SegmentNumber - Supplies the number of the segment to add.
+
+ VariableName - Supplies a pointer to the name of the environment variable.
+ The variable may be followed by an equal sign.
+
+ NewSegment - Supplies a pointer to the new segment.
+
+Return Value:
+
+ Returns ESUCCESS is the segment is set, otherwise an error code is
+ returned.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ PCHAR Variable;
+ PCHAR NextVariable;
+ PCHAR EndOfVariable;
+ CHAR VariableValue[256];
+ ULONG Index;
+ ULONG Count;
+
+ Variable = ArcGetEnvironmentVariable(VariableName);
+ VariableValue[0] = 0;
+
+ if (Variable != NULL) {
+ EndOfVariable = strchr(Variable, 0);
+ for (Index = 0; Index < SegmentNumber ; Index++ ) {
+ NextVariable = strchr(Variable, ';');
+ if (NextVariable != NULL) {
+ Count = NextVariable - Variable + 1;
+ strncat(VariableValue, Variable, Count);
+ Variable = NextVariable + 1;
+ } else {
+ strcat(VariableValue, Variable);
+ Variable = EndOfVariable;
+ strcat(VariableValue, ";");
+ }
+ }
+ } else {
+ for (Index = 0; Index < SegmentNumber ; Index++ ) {
+ strcat(VariableValue, ";");
+ }
+ }
+
+ strcat(VariableValue, NewSegment);
+
+ if ((Variable != NULL) && (Variable != EndOfVariable)) {
+ strcat(VariableValue, ";");
+ strcat(VariableValue, Variable);
+ }
+
+ Status = ArcSetEnvironmentVariable(VariableName, VariableValue);
+ return(Status);
+}
+
+
+ULONG
+JzGetSelection (
+ IN PCHAR Menu[],
+ IN ULONG NumberOfChoices,
+ IN ULONG DefaultChoice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets a menu selection from the user.
+
+Arguments:
+
+ Menu - Supplies an array of pointers to menu character strings.
+
+ Selections - Supplies the number of menu selections.
+
+ DefaultChoice - Supplies the current default choice.
+
+Return Value:
+
+ Returns the value selected, -1 if the escape key was pressed.
+
+--*/
+{
+ ULONG CurrentLine;
+ ULONG Index;
+
+ //
+ // Clear screen and print banner.
+ //
+
+ JzSetScreenAttributes( TRUE, FALSE, FALSE);
+ JzPrint("%c2J", ASCII_CSI);
+
+ CurrentLine = 0;
+ JzSetPosition( CurrentLine++, 0);
+
+ JzPrint(Banner1);
+ JzSetPosition( CurrentLine++, 0);
+ JzPrint(Banner2);
+ JzShowTime(TRUE);
+
+ CurrentLine += NumberOfChoices + 3;
+ JzSetPosition(CurrentLine, 0);
+
+ //
+ // Display the menu and the wait for an action to be selected.
+ //
+
+ DefaultChoice = JxDisplayMenu(Menu,
+ NumberOfChoices,
+ DefaultChoice,
+ 3);
+
+ //
+ // Clear the choices.
+ //
+
+ for (Index = 0; Index < NumberOfChoices ; Index++ ) {
+ JzSetPosition( Index + 3, 5);
+ JzPrint("%cK", ASCII_CSI);
+ }
+
+ return(DefaultChoice);
+}
diff --git a/private/ntos/fw/mips/jzconfig.c b/private/ntos/fw/mips/jzconfig.c
new file mode 100644
index 000000000..d6d364a63
--- /dev/null
+++ b/private/ntos/fw/mips/jzconfig.c
@@ -0,0 +1,1613 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jzconfig.c
+
+Abstract:
+
+ This module contains the code to make the configuration
+ data structures in the Jazz NVRAM.
+
+
+Author:
+
+ David M. Robinson (davidro) 25-Oct-1991
+
+Revision History:
+
+--*/
+
+#include "jzsetup.h"
+#include "jxvideo.h"
+#include "oli2msft.h"
+#include "inc.h"
+
+#define MAXIMUM_DEVICE_SPECIFIC_DATA 32
+
+
+VOID
+JzMakeComponent (
+ PCONFIGURATION_COMPONENT Component,
+ CONFIGURATION_CLASS Class,
+ CONFIGURATION_TYPE Type,
+ BOOLEAN ReadOnly,
+ BOOLEAN Removable,
+ BOOLEAN ConsoleIn,
+ BOOLEAN ConsoleOut,
+ BOOLEAN Input,
+ BOOLEAN Output,
+ ULONG Key,
+ ULONG ConfigurationDataLength,
+ PCHAR Identifier
+ )
+
+/*++
+
+Routine Description:
+
+ This routine fills in a configuration component structure.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Set values that are constant for all entries.
+ //
+
+ Component->Version = ARC_VERSION;
+ Component->Revision = ARC_REVISION;
+ Component->AffinityMask = 0xffffffff;
+ Component->Flags.Failed = 0;
+
+ //
+ // Fill out the structure.
+ //
+
+ Component->Class = Class;
+ Component->Type = Type;
+ Component->Flags.ReadOnly = ReadOnly ? 1 : 0;
+ Component->Flags.Removable = Removable ? 1 : 0;
+ Component->Flags.ConsoleIn = ConsoleIn ? 1 : 0;
+ Component->Flags.ConsoleOut = ConsoleOut ? 1 : 0;
+ Component->Flags.Input = Input ? 1 : 0;
+ Component->Flags.Output = Output ? 1 : 0;
+ Component->Key = Key;
+ Component->ConfigurationDataLength = ConfigurationDataLength;
+ if (Identifier != NULL) {
+ Component->IdentifierLength = strlen(Identifier) + 1;
+ } else {
+ Component->IdentifierLength = 0;
+ }
+ Component->Identifier = Identifier;
+
+ return;
+}
+
+
+ULONG
+JzMakeDescriptor (
+ PCM_PARTIAL_RESOURCE_LIST Descriptor,
+ BOOLEAN Port,
+ ULONG PortStart,
+ ULONG PortSize,
+ BOOLEAN Interrupt,
+ USHORT InterruptFlags,
+ ULONG Level,
+ ULONG Vector,
+ BOOLEAN Memory,
+ ULONG MemoryStart,
+ ULONG MemorySize,
+ BOOLEAN Dma,
+ ULONG Channel,
+ BOOLEAN SecondChannel, // Hack for sound
+ BOOLEAN DeviceSpecificData,
+ ULONG Size,
+ PVOID Data
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a resource descriptor structure.
+
+Arguments:
+
+
+Return Value:
+
+ Returns the size of the structure.
+
+--*/
+{
+ ULONG Index;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Partial;
+
+ Index = 0;
+
+ if (Port) {
+ Partial = &Descriptor->PartialDescriptors[Index];
+ Partial->Type = CmResourceTypePort;
+ Partial->ShareDisposition = CmResourceShareDeviceExclusive;
+ Partial->Flags = 0;
+ Partial->u.Port.Start.LowPart = PortStart;
+ Partial->u.Port.Start.HighPart = 0;
+ Partial->u.Port.Length = PortSize;
+ Index++;
+ }
+
+ if (Interrupt) {
+ Partial = &Descriptor->PartialDescriptors[Index];
+ Partial->Type = CmResourceTypeInterrupt;
+ Partial->ShareDisposition = CmResourceShareDeviceExclusive;
+ Partial->Flags = InterruptFlags;
+ Partial->u.Interrupt.Level = Level;
+ Partial->u.Interrupt.Vector = Vector;
+ Partial->u.Interrupt.Affinity = 0;
+ Index++;
+ }
+
+ if (Memory) {
+ Partial = &Descriptor->PartialDescriptors[Index];
+ Partial->Type = CmResourceTypeMemory;
+ Partial->ShareDisposition = CmResourceShareDeviceExclusive;
+ Partial->Flags = 0;
+ Partial->u.Memory.Start.LowPart = MemoryStart;
+ Partial->u.Memory.Start.HighPart = 0;
+ Partial->u.Memory.Length = MemorySize;
+ Index++;
+ }
+
+ if (Dma) {
+ Partial = &Descriptor->PartialDescriptors[Index];
+ Partial->Type = CmResourceTypeDma;
+ Partial->ShareDisposition = CmResourceShareDeviceExclusive;
+ Partial->Flags = 0;
+ Partial->u.Dma.Channel = Channel;
+ Partial->u.Dma.Port = 0;
+ Partial->u.Dma.Reserved1 = 0;
+ Index++;
+ if (SecondChannel) {
+ Partial = &Descriptor->PartialDescriptors[Index];
+ Partial->Type = CmResourceTypeDma;
+ Partial->ShareDisposition = CmResourceShareDeviceExclusive;
+ Partial->Flags = 0;
+ Partial->u.Dma.Channel = Channel + 1;
+ Partial->u.Dma.Port = 0;
+ Partial->u.Dma.Reserved1 = 0;
+ Index++;
+ }
+ }
+
+ if (DeviceSpecificData) {
+ // Should add a check for maximum size of data.
+ Partial = &Descriptor->PartialDescriptors[Index];
+ Partial->Type = CmResourceTypeDeviceSpecific;
+ Partial->ShareDisposition = CmResourceShareDeviceExclusive;
+ Partial->Flags = 0;
+ Partial->u.DeviceSpecificData.DataSize = Size;
+ Partial->u.DeviceSpecificData.Reserved1 = 0;
+ Partial->u.DeviceSpecificData.Reserved2 = 0;
+ Index++;
+ RtlMoveMemory((PVOID)&Descriptor->PartialDescriptors[Index], Data, Size);
+ }
+
+ Descriptor->Count = Index;
+ Descriptor->Version = ARC_VERSION;
+ Descriptor->Revision = ARC_REVISION;
+ return(sizeof(CM_PARTIAL_RESOURCE_LIST) +
+ (Index ? ((Index - 1) * sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR)) : 0) +
+ Size);
+
+}
+
+
+ARC_STATUS
+JzAddProcessor (
+ IN ULONG ProcessorNumber
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds processor and associated cache entries to the
+ configuration structure.
+
+Arguments:
+
+ ProcessorNumber - Supplies the processor number.
+
+Return Value:
+
+ Returns ESSUCESS if the entries were successfully added, otherwise returns
+ an error message.
+
+--*/
+{
+ CONFIGURATION_COMPONENT Component;
+ PCHAR ProcessorName;
+ CHAR Identifier[40];
+ PCONFIGURATION_COMPONENT Root, Level1;
+ ULONG DcacheLineSize, DcacheSize, IcacheLineSize, IcacheSize;
+ ULONG ScacheLineSize, ScacheSize;
+ ULONG Temp;
+ ULONG FloatingId;
+ ULONG ProcessorId;
+
+ //
+ // Determine cache parameters.
+ //
+
+ IcacheLineSize = 0;
+ Temp = PCR->FirstLevelIcacheFillSize >> 1;
+ while (Temp) {
+ IcacheLineSize++;
+ Temp = Temp >> 1;
+ }
+ IcacheSize = 0;
+ Temp = (PCR->FirstLevelIcacheSize >> PAGE_SHIFT) >> 1;
+ while (Temp) {
+ IcacheSize++;
+ Temp = Temp >> 1;
+ }
+ DcacheLineSize = 0;
+ Temp = PCR->FirstLevelDcacheFillSize >> 1;
+ while (Temp) {
+ DcacheLineSize++;
+ Temp = Temp >> 1;
+ }
+ DcacheSize = 0;
+ Temp = (PCR->FirstLevelDcacheSize >> PAGE_SHIFT) >> 1;
+ while (Temp) {
+ DcacheSize++;
+ Temp = Temp >> 1;
+ }
+
+ ScacheLineSize = 0;
+ Temp = PCR->SecondLevelDcacheFillSize >> 1;
+ while (Temp) {
+ ScacheLineSize++;
+ Temp = Temp >> 1;
+ }
+ ScacheSize = 0;
+ Temp = (PCR->SecondLevelDcacheSize >> PAGE_SHIFT) >> 1;
+ while (Temp) {
+ ScacheSize++;
+ Temp = Temp >> 1;
+ }
+
+ //
+ // Get root component.
+ //
+
+ Root = ArcGetChild(NULL);
+
+ if (Root == NULL) {
+ return(EINVAL);
+ }
+
+ //
+ // Determine Identifier; cache size is units of log2(4 KByte pages).
+ //
+
+ switch (IcacheSize) {
+
+ case 1:
+ ProcessorName = "R4000";
+ break;
+
+ case 2:
+ ProcessorName = "R4400";
+ break;
+
+ default:
+ ProcessorName = "Unknown";
+ break;
+ }
+
+ //
+ // Add processor and floating point revision, but only for systems with
+ // restart parameter blocks (i.e. DUO).
+ //
+
+#ifdef DUO
+ BlQueryImplementationAndRevision(&ProcessorId, &FloatingId);
+ sprintf(&Identifier[0],
+ "MIPS-%s - Pr %d/%d.%d, Fp %d/%d",
+ ProcessorName,
+ (ProcessorId >> 8) & 0xff,
+ (ProcessorId >> 4) & 0xf,
+ ProcessorId & 0xf,
+ (FloatingId >> 8) & 0xff,
+ FloatingId & 0xff);
+#else
+ sprintf(&Identifier[0],
+ "MIPS-%s",
+ ProcessorName);
+#endif
+
+
+ JzMakeComponent(&Component,
+ ProcessorClass, // Class
+ CentralProcessor, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ FALSE, // Input
+ FALSE, // Output
+ ProcessorNumber, // Key
+ 0, // ConfigurationDataLength
+ Identifier // Identifier
+ );
+
+ if ((Level1 = ArcAddChild( Root, &Component, NULL )) == NULL) {
+ return(EINVAL);
+ }
+
+ //
+ // Add caches as child of processor.
+ //
+
+ JzMakeComponent(&Component,
+ CacheClass, // Class
+ PrimaryIcache, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ FALSE, // Input
+ FALSE, // Output
+ 1 << 24 |
+ IcacheLineSize << 16 |
+ IcacheSize, // Key
+ 0, // ConfigurationDataLength
+ NULL // Identifier
+ );
+
+ if ((ArcAddChild( Level1, &Component, NULL )) == NULL) {
+ return(EINVAL);
+ }
+
+ JzMakeComponent(&Component,
+ CacheClass, // Class
+ PrimaryDcache, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ FALSE, // Input
+ FALSE, // Output
+ 1 << 24 |
+ DcacheLineSize << 16 |
+ DcacheSize, // Key
+ 0, // ConfigurationDataLength
+ NULL // Identifier
+ );
+
+ if ((ArcAddChild( Level1, &Component, NULL )) == NULL) {
+ return(EINVAL);
+ }
+
+ //
+ // Add a secondary cache if present
+ //
+
+ if (ScacheSize != 0) {
+ JzMakeComponent(&Component,
+ CacheClass, // Class
+ SecondaryDcache, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ FALSE, // Input
+ FALSE, // Output
+ 1 << 24 |
+ ScacheLineSize << 16 |
+ ScacheSize, // Key
+ 0, // ConfigurationDataLength
+ NULL // Identifier
+ );
+
+ if ((ArcAddChild( Level1, &Component, NULL )) == NULL) {
+ return(EINVAL);
+ }
+ }
+}
+
+
+VOID
+JzMakeConfiguration (
+ ULONG Monitor,
+ ULONG Floppy,
+ ULONG Floppy2
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the configuration entries by calling the firmware
+ add child routine.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CONFIGURATION_COMPONENT Component;
+ PCHAR Identifier;
+ PCONFIGURATION_COMPONENT Root, Level1, Level2, Level3;
+ UCHAR Buffer[sizeof(CM_PARTIAL_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 5) +
+ MAXIMUM_DEVICE_SPECIFIC_DATA];
+ PCM_PARTIAL_RESOURCE_LIST Descriptor = (PCM_PARTIAL_RESOURCE_LIST)&Buffer;
+ ULONG DescriptorSize;
+ JAZZ_VIDEO_TYPE VideoType;
+ CM_VIDEO_DEVICE_DATA VideoDeviceData;
+ MONITOR_CONFIGURATION_DATA MonitorData; // TEMPTEMP
+ JAZZ_G300_CONFIGURATION_DATA VideoData; // TEMPTEMP
+ CM_MONITOR_DEVICE_DATA MonitorDeviceData;
+ CM_SCSI_DEVICE_DATA ScsiDeviceData;
+ CM_FLOPPY_DEVICE_DATA FloppyDeviceData;
+ CM_SERIAL_DEVICE_DATA SerialDeviceData;
+ ULONG Temp;
+ UCHAR VideoIdentifier[32];
+ EISA_ADAPTER_DETAILS EisaAdapterDetails;
+ BOOLEAN OldProm;
+
+ //
+ // Add root.
+ //
+
+ JzMakeComponent(&Component,
+ SystemClass, // Class
+ ArcSystem, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ FALSE, // Input
+ FALSE, // Output
+ 0, // Key
+ 0, // ConfigurationDataLength
+#ifdef DUO
+ "Microsoft-Duo" // Identifier
+#else
+ "Microsoft-Jazz" // Identifier
+#endif
+ );
+
+ if ((Root = ArcAddChild( NULL, &Component, NULL )) == NULL) {
+ return;
+ }
+
+ //
+ // Add the jazz local bus as a child of root.
+ //
+
+ JzMakeComponent(&Component,
+ AdapterClass, // Class
+ MultiFunctionAdapter, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ FALSE, // Input
+ FALSE, // Output
+ 0, // Key
+ 0, // ConfigurationDataLength
+ "Jazz-Internal Bus" // Identifier
+ );
+
+ if ((Level1 = ArcAddChild( Root, &Component, NULL )) == NULL) {
+ return;
+ }
+
+#if 0
+ //
+ // Add graphics board as a child of the local bus.
+ //
+
+ //
+ // Determine which video board is installed.
+ //
+
+ VideoType = READ_REGISTER_UCHAR((PUCHAR)0xe0200000);
+
+ if (VideoType == JazzVideoG300) {
+ VideoDeviceData.VideoClock = 8125000;
+ Identifier = "Jazz G300";
+ } else {
+ if (ValidVideoProm()) {
+
+ //
+ // Read the identifier string from the video prom
+ //
+ ReadVideoPromData(8+sizeof(VIDEO_PROM_CONFIGURATION),(ULONG)VideoIdentifier,32);
+ Identifier = VideoIdentifier;
+
+ //
+ // Init the clock stuff
+ //
+
+ switch (VideoType) {
+ case JazzVideoG364:
+ VideoDeviceData.VideoClock = 8125000;
+ break;
+ case MipsVideoG364:
+ VideoDeviceData.VideoClock = 5000000;
+ break;
+ }
+ } else {
+
+ //
+ // TEMPTEMP For know still check for g364 without code in the
+ // video prom.
+ //
+
+ switch (VideoType) {
+ case JazzVideoG364:
+ Identifier = "Jazz G364";
+ VideoDeviceData.VideoClock = 8125000;
+ break;
+ case MipsVideoG364:
+ Identifier = "Mips G364";
+ VideoDeviceData.VideoClock = 5000000;
+ break;
+ default:
+ Identifier = "Unknown";
+ break;
+ }
+ }
+ }
+
+ VideoDeviceData.Version = 0;
+ VideoDeviceData.Revision = 0;
+
+ DescriptorSize =
+ JzMakeDescriptor (Descriptor, // Descriptor
+ TRUE, // Port
+ VIDEO_CONTROL_PHYSICAL_BASE, // PortStart
+ (PAGE_SIZE << 9), // PortSize
+ TRUE, // Interrupt
+ 0, // InterruptFlags
+ DEVICE_LEVEL, // Level
+ VIDEO_VECTOR, // Vector
+ TRUE, // Memory
+ VIDEO_MEMORY_PHYSICAL_BASE, // MemoryStart
+ (PAGE_SIZE << 9), // MemorySize
+ FALSE, // Dma
+ 0, // Channel
+ FALSE, // SecondChannel
+ TRUE, // DeviceSpecificData
+ sizeof(CM_VIDEO_DEVICE_DATA), // Size
+ (PVOID)&VideoDeviceData // Data
+ );
+
+ //
+ // Add graphics board as a child of the local bus.
+ //
+
+ JzMakeComponent(&Component,
+ ControllerClass, // Class
+ DisplayController, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ TRUE, // ConsoleOut
+ FALSE, // Input
+ TRUE, // Output
+ 0, // Key
+ DescriptorSize, // ConfigurationDataLength
+ Identifier // Identifier
+ );
+
+
+ if ((Level2 = ArcAddChild( Level1, &Component, Descriptor )) == NULL) {
+ return;
+ }
+#endif
+
+ //
+ // Add graphics board as a child of the local bus.
+ //
+
+ VideoData.Irql = DEVICE_LEVEL;
+ VideoData.Vector = VIDEO_VECTOR;
+ VideoData.Version = 1;
+ VideoData.Revision = 0;
+ VideoData.ControlBase = VIDEO_CONTROL_PHYSICAL_BASE;
+ VideoData.ControlSize = PAGE_SIZE << 9;
+ VideoData.CursorBase = CURSOR_CONTROL_PHYSICAL_BASE;
+ VideoData.CursorSize = PAGE_SIZE;
+ VideoData.FrameBase = VIDEO_MEMORY_PHYSICAL_BASE;
+ VideoData.FrameSize = PAGE_SIZE << 9;
+
+ //
+ // Determine which video board is installed.
+ //
+
+ VideoType = READ_REGISTER_UCHAR((PUCHAR)0xe0200000);
+
+ if (VideoType == JazzVideoG300) {
+ Identifier = "Jazz G300";
+ } else {
+ if (ValidVideoProm()) {
+
+ //
+ // Read the identifier string from the video prom
+ //
+ ReadVideoPromData(8+sizeof(VIDEO_PROM_CONFIGURATION),(ULONG)VideoIdentifier,32);
+ Identifier = VideoIdentifier;
+
+ } else {
+
+ //
+ // For now still check for g364 without code in the
+ // video prom.
+ //
+
+ switch (VideoType) {
+ case JazzVideoG364:
+ Identifier = "Jazz G364";
+ break;
+ case MipsVideoG364:
+ Identifier = "Mips G364";
+ break;
+ default:
+ Identifier = "Unknown";
+ break;
+ }
+ }
+ }
+
+ JzMakeComponent(&Component,
+ ControllerClass, // Class
+ DisplayController, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ TRUE, // ConsoleOut
+ FALSE, // Input
+ TRUE, // Output
+ 0, // Key
+ sizeof(JAZZ_G300_CONFIGURATION_DATA), // ConfigurationDataLength
+ Identifier // Identifier
+ );
+
+ if ((Level2 = ArcAddChild( Level1, &Component, &VideoData )) == NULL) {
+ return;
+ }
+
+ //
+ // Add the monitor as a child of the graphics board.
+ //
+
+ JzMakeComponent(&Component,
+ PeripheralClass, // Class
+ MonitorPeripheral, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ TRUE, // ConsoleOut
+ FALSE, // Input
+ TRUE, // Output
+ 0, // Key
+ sizeof(MONITOR_CONFIGURATION_DATA), // ConfigurationDataLength
+ NULL // Identifier
+ );
+
+ MonitorData.Version = 1;
+ MonitorData.Revision = 0;
+
+ //
+ // Check to see if this is version 1.1 or greater.
+ //
+
+ if ((SYSTEM_BLOCK->Version * 100 + SYSTEM_BLOCK->Revision) >= 101) {
+ OldProm = FALSE;
+ } else {
+ OldProm = TRUE;
+ }
+
+ switch (Monitor) {
+
+ case 0:
+ Component.IdentifierLength = sizeof("1280x1024");
+ Component.Identifier = "1280x1024";
+
+ MonitorData.HorizontalResolution = 1280;
+ MonitorData.HorizontalDisplayTime = 11832; // Mips uses 11636
+// MonitorData.HorizontalBackPorch = 1746;
+// MonitorData.HorizontalFrontPorch = 437;
+ MonitorData.HorizontalBackPorch = 1596; // Mips uses 2070
+ MonitorData.HorizontalFrontPorch = 587; // Mips uses 407
+ MonitorData.HorizontalSync = 1745; // Mips uses 1701
+ MonitorData.VerticalResolution = 1024;
+ MonitorData.VerticalBackPorch = 28; // Mips uses 32
+ MonitorData.VerticalFrontPorch = 1;
+ MonitorData.VerticalSync = 3;
+ MonitorData.HorizontalScreenSize = 343;
+ MonitorData.VerticalScreenSize = 274;
+
+ if (OldProm) {
+ MonitorData.HorizontalBackPorch = 1849;
+ MonitorData.HorizontalFrontPorch = 407;
+ MonitorData.VerticalFrontPorch = 3;
+ }
+
+ break;
+
+ case 1:
+ Component.IdentifierLength = sizeof("1024x768");
+ Component.Identifier = "1024x768";
+
+ MonitorData.HorizontalResolution = 1024;
+ MonitorData.HorizontalDisplayTime = 16000; // Mips uses 15754
+ MonitorData.HorizontalBackPorch = 2000; // Mips uses 2462
+ MonitorData.HorizontalFrontPorch = 1000; // Mips uses 369
+ MonitorData.HorizontalSync = 1500; // Mips uses 2092
+ MonitorData.VerticalResolution = 768;
+ MonitorData.VerticalBackPorch = 39; // Mips uses 35
+ MonitorData.VerticalFrontPorch = 1;
+ MonitorData.VerticalSync = 1; // Mips uses 3
+ MonitorData.HorizontalScreenSize = 343;
+ MonitorData.VerticalScreenSize = 274;
+
+ if (OldProm) {
+ MonitorData.VerticalFrontPorch = 3;
+ }
+
+ break;
+
+ case 2:
+ Component.IdentifierLength = sizeof("800x600");
+ Component.Identifier = "800x600";
+
+ MonitorData.HorizontalResolution = 800;
+ MonitorData.HorizontalDisplayTime = 14130;
+ MonitorData.HorizontalBackPorch = 2670;
+ MonitorData.HorizontalFrontPorch = 440;
+ MonitorData.HorizontalSync = 3110;
+ MonitorData.VerticalResolution = 600;
+// MonitorData.VerticalBackPorch = 7;
+ MonitorData.VerticalBackPorch = 18;
+ MonitorData.VerticalFrontPorch = 1;
+// MonitorData.VerticalSync = 14;
+ MonitorData.VerticalSync = 3;
+ MonitorData.HorizontalScreenSize = 343;
+ MonitorData.VerticalScreenSize = 274;
+
+ if (OldProm) {
+ MonitorData.VerticalFrontPorch = 7;
+ }
+
+ break;
+
+ case 3:
+ Component.IdentifierLength = sizeof("640x480");
+ Component.Identifier = "640x480";
+
+ MonitorData.HorizontalResolution = 640;
+ MonitorData.HorizontalDisplayTime = 25422;
+ MonitorData.HorizontalBackPorch = 1907;
+ MonitorData.HorizontalFrontPorch = 636;
+ MonitorData.HorizontalSync = 3814;
+ MonitorData.VerticalResolution = 480;
+ MonitorData.VerticalBackPorch = 33;
+ MonitorData.VerticalFrontPorch = 10;
+ MonitorData.VerticalSync = 2;
+ MonitorData.HorizontalScreenSize = 350;
+ MonitorData.VerticalScreenSize = 270;
+
+ if (OldProm) {
+ MonitorData.VerticalBackPorch = 33;
+ MonitorData.VerticalFrontPorch = 10;
+ }
+
+ break;
+
+ default:
+ break;
+
+ }
+
+ if ((Level3 = ArcAddChild( Level2, &Component, &MonitorData )) == NULL) {
+ return;
+ }
+
+ //
+ // Add the network adapter as a child of the local bus.
+ //
+
+ JzAddNetwork( Level1 );
+
+#ifndef DUO
+ //
+ // Add the floppy disk controller as a child of the local bus.
+ //
+
+ DescriptorSize =
+ JzMakeDescriptor (Descriptor, // Descriptor
+ TRUE, // Port
+ FLOPPY_PHYSICAL_BASE, // PortStart
+ PAGE_SIZE, // PortSize
+ TRUE, // Interrupt
+ 0, // InterruptFlags
+ DEVICE_LEVEL, // Level
+ FLOPPY_VECTOR, // Vector
+ FALSE, // Memory
+ 0, // MemoryStart
+ 0, // MemorySize
+ TRUE, // Dma
+ FLOPPY_CHANNEL, // Channel
+ FALSE, // SecondChannel
+ FALSE, // DeviceSpecificData
+ 0, // Size
+ NULL // Data
+ );
+
+ JzMakeComponent(&Component,
+ ControllerClass, // Class
+ DiskController, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ TRUE, // Input
+ TRUE, // Output
+ 0, // Key
+ DescriptorSize, // ConfigurationDataLength
+ "I82077" // Identifier
+ );
+
+ if ((Level2 = ArcAddChild( Level1, &Component, Descriptor )) == NULL) {
+ return;
+ }
+
+ //
+ // Add the floppy disk itself as a child of the floppy disk controller.
+ //
+
+ FloppyDeviceData.Version = ARC_VERSION;
+ FloppyDeviceData.Revision = ARC_REVISION;
+
+ switch (Floppy) {
+
+ case 0:
+ FloppyDeviceData.Size[0] = '5';
+ FloppyDeviceData.Size[1] = '.';
+ FloppyDeviceData.Size[2] = '2';
+ FloppyDeviceData.Size[3] = '5';
+ FloppyDeviceData.Size[4] = 0;
+ FloppyDeviceData.Size[5] = 0;
+ FloppyDeviceData.Size[6] = 0;
+ FloppyDeviceData.Size[7] = 0;
+ FloppyDeviceData.MaxDensity = 1200;
+ FloppyDeviceData.MountDensity = 0;
+ break;
+
+ case 1:
+ case 2:
+ FloppyDeviceData.Size[0] = '3';
+ FloppyDeviceData.Size[1] = '.';
+ FloppyDeviceData.Size[2] = '5';
+ FloppyDeviceData.Size[3] = 0;
+ FloppyDeviceData.Size[4] = 0;
+ FloppyDeviceData.Size[5] = 0;
+ FloppyDeviceData.Size[6] = 0;
+ FloppyDeviceData.Size[7] = 0;
+ if (Floppy == 1) {
+ FloppyDeviceData.MaxDensity = 1440;
+ } else {
+ FloppyDeviceData.MaxDensity = 2880;
+ }
+ FloppyDeviceData.MountDensity = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ DescriptorSize =
+ JzMakeDescriptor (Descriptor, // Descriptor
+ FALSE, // Port
+ 0, // PortStart
+ 0, // PortSize
+ FALSE, // Interrupt
+ 0, // InterruptFlags
+ 0, // Level
+ 0, // Vector
+ FALSE, // Memory
+ 0, // MemoryStart
+ 0, // MemorySize
+ FALSE, // Dma
+ 0, // Channel
+ FALSE, // SecondChannel
+ TRUE, // DeviceSpecificData
+ sizeof(CM_FLOPPY_DEVICE_DATA), // Size
+ (PVOID)&FloppyDeviceData // Data
+ );
+
+ JzMakeComponent(&Component,
+ PeripheralClass, // Class
+ FloppyDiskPeripheral, // Type
+ FALSE, // Readonly
+ TRUE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ TRUE, // Input
+ TRUE, // Output
+ 0, // Key
+ DescriptorSize, // ConfigurationDataLength
+ NULL // Identifier
+ );
+
+ if ((ArcAddChild( Level2, &Component, Descriptor )) == NULL) {
+ return;
+ }
+
+ //
+ // Add a second floppy disk as a child of the floppy disk controller.
+ //
+
+ if (Floppy2 != -1) {
+
+ FloppyDeviceData.Version = ARC_VERSION;
+ FloppyDeviceData.Revision = ARC_REVISION;
+
+ switch (Floppy2) {
+
+ case 0:
+ FloppyDeviceData.Size[0] = '5';
+ FloppyDeviceData.Size[1] = '.';
+ FloppyDeviceData.Size[2] = '2';
+ FloppyDeviceData.Size[3] = '5';
+ FloppyDeviceData.Size[4] = 0;
+ FloppyDeviceData.Size[5] = 0;
+ FloppyDeviceData.Size[6] = 0;
+ FloppyDeviceData.Size[7] = 0;
+ FloppyDeviceData.MaxDensity = 1200;
+ FloppyDeviceData.MountDensity = 0;
+ break;
+
+ case 1:
+ case 2:
+ FloppyDeviceData.Size[0] = '3';
+ FloppyDeviceData.Size[1] = '.';
+ FloppyDeviceData.Size[2] = '5';
+ FloppyDeviceData.Size[3] = 0;
+ FloppyDeviceData.Size[4] = 0;
+ FloppyDeviceData.Size[5] = 0;
+ FloppyDeviceData.Size[6] = 0;
+ FloppyDeviceData.Size[7] = 0;
+ if (Floppy == 1) {
+ FloppyDeviceData.MaxDensity = 1440;
+ } else {
+ FloppyDeviceData.MaxDensity = 2880;
+ }
+ FloppyDeviceData.MountDensity = 0;
+ break;
+
+ default:
+ break;
+ }
+
+ DescriptorSize =
+ JzMakeDescriptor (Descriptor, // Descriptor
+ FALSE, // Port
+ 0, // PortStart
+ 0, // PortSize
+ FALSE, // Interrupt
+ 0, // InterruptFlags
+ 0, // Level
+ 0, // Vector
+ FALSE, // Memory
+ 0, // MemoryStart
+ 0, // MemorySize
+ FALSE, // Dma
+ 0, // Channel
+ FALSE, // SecondChannel
+ TRUE, // DeviceSpecificData
+ sizeof(CM_FLOPPY_DEVICE_DATA), // Size
+ (PVOID)&FloppyDeviceData // Data
+ );
+
+ JzMakeComponent(&Component,
+ PeripheralClass, // Class
+ FloppyDiskPeripheral, // Type
+ FALSE, // Readonly
+ TRUE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ TRUE, // Input
+ TRUE, // Output
+ 1, // Key
+ DescriptorSize, // ConfigurationDataLength
+ NULL // Identifier
+ );
+
+ if ((ArcAddChild( Level2, &Component, Descriptor )) == NULL) {
+ return;
+ }
+
+ }
+
+#endif
+
+ //
+ // Add the keyboard controller as a child of the local bus.
+ //
+
+ DescriptorSize =
+ JzMakeDescriptor (Descriptor, // Descriptor
+ TRUE, // Port
+ KEYBOARD_PHYSICAL_BASE, // PortStart
+ PAGE_SIZE, // PortSize
+ TRUE, // Interrupt
+ 0, // InterruptFlags
+ DEVICE_LEVEL, // Level
+ KEYBOARD_VECTOR, // Vector
+ FALSE, // Memory
+ 0, // MemoryStart
+ 0, // MemorySize
+ FALSE, // Dma
+ 0, // Channel
+ FALSE, // SecondChannel
+ FALSE, // DeviceSpecificData
+ 0, // Size
+ NULL // Data
+ );
+
+ JzMakeComponent(&Component,
+ ControllerClass, // Class
+ KeyboardController, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ TRUE, // ConsoleIn
+ FALSE, // ConsoleOut
+ TRUE, // Input
+ FALSE, // Output
+ 0, // Key
+ DescriptorSize, // ConfigurationDataLength
+ "I8742" // Identifier
+ );
+
+ if ((Level2 = ArcAddChild( Level1, &Component, Descriptor )) == NULL) {
+ return;
+ }
+
+ //
+ // Add the keyboard itself as a child of the keyboard controller.
+ //
+
+ JzMakeComponent(&Component,
+ PeripheralClass, // Class
+ KeyboardPeripheral, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ TRUE, // ConsoleIn
+ FALSE, // ConsoleOut
+ TRUE, // Input
+ FALSE, // Output
+ 0, // Key
+ 0, // ConfigurationDataLength
+ "PCAT_ENHANCED" // Identifier
+ );
+
+ if ((ArcAddChild( Level2, &Component, NULL )) == NULL) {
+ return;
+ }
+
+ //
+ // Add the mouse controller as a child of the local bus.
+ //
+
+ DescriptorSize =
+ JzMakeDescriptor (Descriptor, // Descriptor
+ TRUE, // Port
+ MOUSE_PHYSICAL_BASE, // PortStart
+ PAGE_SIZE, // PortSize
+ TRUE, // Interrupt
+ 0, // InterruptFlags
+ DEVICE_LEVEL, // Level
+ MOUSE_VECTOR, // Vector
+ FALSE, // Memory
+ 0, // MemoryStart
+ 0, // MemorySize
+ FALSE, // Dma
+ 0, // Channel
+ FALSE, // SecondChannel
+ FALSE, // DeviceSpecificData
+ 0, // Size
+ NULL // Data
+ );
+
+ JzMakeComponent(&Component,
+ ControllerClass, // Class
+ PointerController, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ TRUE, // Input
+ FALSE, // Output
+ 0, // Key
+ DescriptorSize, // ConfigurationDataLength
+ "I8742" // Identifier
+ );
+
+ if ((Level2 = ArcAddChild( Level1, &Component, Descriptor )) == NULL) {
+ return;
+ }
+
+ //
+ // Add the mouse itself as a child of the mouse controller.
+ //
+
+ JzMakeComponent(&Component,
+ PeripheralClass, // Class
+ PointerPeripheral, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ TRUE, // Input
+ FALSE, // Output
+ 0, // Key
+ 0, // ConfigurationDataLength
+ "PS2 MOUSE" // Identifier
+ );
+
+ if ((ArcAddChild( Level2, &Component, NULL )) == NULL) {
+ return;
+ }
+
+ //
+ // Add the serial, parallel, and audio controllers as children of the
+ // local bus.
+ //
+
+#ifdef DUO
+ SerialDeviceData.BaudClock = 8000000;
+#else
+
+ //
+ // If this is Jazz, set the baud clock to 4 MHz, otherwise to 8 MHz.
+ // If the revision register is 2 or above, this is a Fusion or Fission
+ // machine.
+ //
+
+ Temp = READ_REGISTER_ULONG(&DMA_CONTROL->RevisionLevel.Long);
+
+ if (Temp > 1) {
+ SerialDeviceData.BaudClock = 8000000;
+ } else {
+ SerialDeviceData.BaudClock = 4233600;
+ }
+#endif
+
+ SerialDeviceData.Version = ARC_VERSION;
+ SerialDeviceData.Revision = ARC_REVISION;
+
+ DescriptorSize =
+ JzMakeDescriptor (Descriptor, // Descriptor
+ TRUE, // Port
+ SERIAL0_PHYSICAL_BASE, // PortStart
+ PAGE_SIZE, // PortSize
+ TRUE, // Interrupt
+ 0, // InterruptFlags
+ DEVICE_LEVEL, // Level
+ SERIAL0_VECTOR, // Vector
+ FALSE, // Memory
+ 0, // MemoryStart
+ 0, // MemorySize
+ FALSE, // Dma
+ 0, // Channel
+ FALSE, // SecondChannel
+ TRUE, // DeviceSpecificData
+ sizeof(CM_SERIAL_DEVICE_DATA), // Size
+ (PVOID)&SerialDeviceData // Data
+ );
+
+ JzMakeComponent(&Component,
+ ControllerClass, // Class
+ SerialController, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ TRUE, // Input
+ TRUE, // Output
+ 0, // Key
+ DescriptorSize, // ConfigurationDataLength
+ "COM1" // Identifier
+ );
+
+ if ((ArcAddChild( Level1, &Component, Descriptor )) == NULL) {
+ return;
+ }
+
+ DescriptorSize =
+ JzMakeDescriptor (Descriptor, // Descriptor
+ TRUE, // Port
+ SERIAL1_PHYSICAL_BASE, // PortStart
+ PAGE_SIZE, // PortSize
+ TRUE, // Interrupt
+ 0, // InterruptFlags
+ DEVICE_LEVEL, // Level
+ SERIAL1_VECTOR, // Vector
+ FALSE, // Memory
+ 0, // MemoryStart
+ 0, // MemorySize
+ FALSE, // Dma
+ 0, // Channel
+ FALSE, // SecondChannel
+ TRUE, // DeviceSpecificData
+ sizeof(CM_SERIAL_DEVICE_DATA), // Size
+ (PVOID)&SerialDeviceData // Data
+ );
+
+ JzMakeComponent(&Component,
+ ControllerClass, // Class
+ SerialController, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ TRUE, // Input
+ TRUE, // Output
+ 0, // Key
+ DescriptorSize, // ConfigurationDataLength
+ "COM2" // Identifier
+ );
+
+ if ((ArcAddChild( Level1, &Component, Descriptor )) == NULL) {
+ return;
+ }
+
+ DescriptorSize =
+ JzMakeDescriptor (Descriptor, // Descriptor
+ TRUE, // Port
+ PARALLEL_PHYSICAL_BASE, // PortStart
+ PAGE_SIZE, // PortSize
+ TRUE, // Interrupt
+ 0, // InterruptFlags
+ DEVICE_LEVEL, // Level
+ PARALLEL_VECTOR, // Vector
+ FALSE, // Memory
+ 0, // MemoryStart
+ 0, // MemorySize
+ FALSE, // Dma
+ 0, // Channel
+ FALSE, // SecondChannel
+ FALSE, // DeviceSpecificData
+ 0, // Size
+ NULL // Data
+ );
+
+ JzMakeComponent(&Component,
+ ControllerClass, // Class
+ ParallelController, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ TRUE, // Input
+ TRUE, // Output
+ 0, // Key
+ DescriptorSize, // ConfigurationDataLength
+ "LPT1" // Identifier
+ );
+
+ if ((ArcAddChild( Level1, &Component, Descriptor )) == NULL) {
+ return;
+ }
+
+#ifndef DUO
+ DescriptorSize =
+ JzMakeDescriptor (Descriptor, // Descriptor
+ TRUE, // Port
+ SOUND_PHYSICAL_BASE, // PortStart
+ PAGE_SIZE, // PortSize
+ TRUE, // Interrupt
+ 0, // InterruptFlags
+ DEVICE_LEVEL, // Level
+ SOUND_VECTOR, // Vector
+ FALSE, // Memory
+ 0, // MemoryStart
+ 0, // MemorySize
+ TRUE, // Dma
+ SOUND_CHANNEL_A, // Channel
+ TRUE, // SecondChannel
+ FALSE, // DeviceSpecificData
+ 0, // Size
+ NULL // Data
+ );
+
+ JzMakeComponent(&Component,
+ ControllerClass, // Class
+ AudioController, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ TRUE, // Input
+ TRUE, // Output
+ 0, // Key
+ DescriptorSize, // ConfigurationDataLength
+ "MAGNUM" // Identifier
+ );
+
+ if ((ArcAddChild( Level1, &Component, Descriptor )) == NULL) {
+ return;
+ }
+
+#endif
+
+ //
+ // Add the eisa adapter as a child of root.
+ //
+
+ EisaAdapterDetails.NumberOfSlots = VIR_0_SLOTS ? VIR_0_SLOTS + 16 : PHYS_0_SLOTS;
+ EisaAdapterDetails.IoStart = (PVOID)EISA_EXTERNAL_IO_VIRTUAL_BASE;
+ EisaAdapterDetails.IoSize = PHYS_0_SLOTS * 0x1000;
+
+ EisaAdapterDetails.ConfigDataHeader.Version = ARC_VERSION;
+ EisaAdapterDetails.ConfigDataHeader.Revision = ARC_REVISION;
+ EisaAdapterDetails.ConfigDataHeader.Type = NULL;
+ EisaAdapterDetails.ConfigDataHeader.Vendor = NULL;
+ EisaAdapterDetails.ConfigDataHeader.ProductName = NULL;
+ EisaAdapterDetails.ConfigDataHeader.SerialNumber = NULL;
+
+ JzMakeComponent(&Component,
+ AdapterClass, // Class
+ EisaAdapter, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ FALSE, // Input
+ FALSE, // Output
+ 0, // Key
+ sizeof(EISA_ADAPTER_DETAILS), // ConfigurationDataLength
+ "EISA" // Identifier
+ );
+
+ if ((Level1 = ArcAddChild( Root, &Component, &EisaAdapterDetails )) == NULL) {
+ return;
+ }
+
+#ifndef DUO
+ //
+ // Add the scsi adapter as a child of the root.
+ //
+
+ ScsiDeviceData.Version = ARC_VERSION;
+ ScsiDeviceData.Revision = ARC_REVISION;
+ ScsiDeviceData.HostIdentifier = ScsiHostId;
+
+ DescriptorSize =
+ JzMakeDescriptor (Descriptor, // Descriptor
+ FALSE, // Port
+ 0, // PortStart
+ 0, // PortSize
+ TRUE, // Interrupt
+ 0, // InterruptFlags
+ DEVICE_LEVEL, // Level
+ SCSI_VECTOR, // Vector
+ TRUE, // Memory
+ SCSI_PHYSICAL_BASE, // MemoryStart
+ PAGE_SIZE, // MemorySize
+ TRUE, // Dma
+ SCSI_CHANNEL, // Channel
+ FALSE, // SecondChannel
+ TRUE, // DeviceSpecificData
+ sizeof(CM_SCSI_DEVICE_DATA), // Size
+ (PVOID)&ScsiDeviceData // Data
+ );
+
+ JzMakeComponent(&Component,
+ AdapterClass, // Class
+ ScsiAdapter, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ FALSE, // Input
+ FALSE, // Output
+ 0, // Key
+ DescriptorSize, // ConfigurationDataLength
+ "ESP216" // Identifier
+ );
+
+ if ((Level1 = ArcAddChild( Root, &Component, Descriptor )) == NULL) {
+ return;
+ }
+
+#else
+ //
+ // Add the two scsi adapters as children of the root. NOTE: Add the
+ // second one first so they will be the right way around for setupldr.
+ //
+
+ ScsiDeviceData.Version = ARC_VERSION;
+ ScsiDeviceData.Revision = ARC_REVISION;
+ ScsiDeviceData.HostIdentifier = ScsiHostId;
+
+ DescriptorSize =
+ JzMakeDescriptor (Descriptor, // Descriptor
+ FALSE, // Port
+ 0, // PortStart
+ 0, // PortSize
+ TRUE, // Interrupt
+ 0, // InterruptFlags
+ DEVICE_LEVEL, // Level
+ SCSI1_VECTOR, // Vector
+ TRUE, // Memory
+ SCSI1_PHYSICAL_BASE, // MemoryStart
+ PAGE_SIZE, // MemorySize
+ FALSE, // Dma
+ 0, // Channel
+ FALSE, // SecondChannel
+ TRUE, // DeviceSpecificData
+ sizeof(CM_SCSI_DEVICE_DATA), // Size
+ (PVOID)&ScsiDeviceData // Data
+ );
+
+ JzMakeComponent(&Component,
+ AdapterClass, // Class
+ ScsiAdapter, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ FALSE, // Input
+ FALSE, // Output
+ 0, // Key
+ DescriptorSize, // ConfigurationDataLength
+ "NCRC700" // Identifier
+ );
+
+ if ((Level1 = ArcAddChild( Root, &Component, Descriptor )) == NULL) {
+ return;
+ }
+
+ DescriptorSize =
+ JzMakeDescriptor (Descriptor, // Descriptor
+ FALSE, // Port
+ 0, // PortStart
+ 0, // PortSize
+ TRUE, // Interrupt
+ 0, // InterruptFlags
+ DEVICE_LEVEL, // Level
+ SCSI2_VECTOR, // Vector
+ TRUE, // Memory
+ SCSI2_PHYSICAL_BASE, // MemoryStart
+ PAGE_SIZE, // MemorySize
+ FALSE, // Dma
+ 0, // Channel
+ FALSE, // SecondChannel
+ TRUE, // DeviceSpecificData
+ sizeof(CM_SCSI_DEVICE_DATA), // Size
+ (PVOID)&ScsiDeviceData // Data
+ );
+
+ JzMakeComponent(&Component,
+ AdapterClass, // Class
+ ScsiAdapter, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ FALSE, // Input
+ FALSE, // Output
+ 1, // Key
+ DescriptorSize, // ConfigurationDataLength
+ "NCRC700" // Identifier
+ );
+
+ if ((Level1 = ArcAddChild( Root, &Component, Descriptor )) == NULL) {
+ return;
+ }
+
+#endif
+
+ return;
+}
+
+VOID
+JzAddNetwork (
+ PCONFIGURATION_COMPONENT Parent
+ )
+
+/*++
+
+Routine Description:
+
+ This routine adds the network component to the tree.
+
+Arguments:
+
+ Parent - The parent for the network component.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CM_SONIC_DEVICE_DATA SonicDeviceData;
+ ULONG Index;
+ PUCHAR NvramAddress = (PUCHAR)NVRAM_SYSTEM_ID;
+ CONFIGURATION_COMPONENT Component;
+ UCHAR Buffer[sizeof(CM_PARTIAL_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 5) +
+ MAXIMUM_DEVICE_SPECIFIC_DATA];
+ PCM_PARTIAL_RESOURCE_LIST Descriptor = (PCM_PARTIAL_RESOURCE_LIST)&Buffer;
+ ULONG DescriptorSize;
+
+ SonicDeviceData.Version = ARC_VERSION;
+ SonicDeviceData.Revision = ARC_REVISION;
+ SonicDeviceData.DataConfigurationRegister = 0x2423;
+ for (Index = 0; Index < 8 ; Index++ ) {
+ SonicDeviceData.EthernetAddress[Index] =
+ READ_REGISTER_UCHAR(&NvramAddress[Index]);
+ }
+
+ DescriptorSize =
+ JzMakeDescriptor (Descriptor, // Descriptor
+ TRUE, // Port
+ NET_PHYSICAL_BASE, // PortStart
+ PAGE_SIZE, // PortSize
+ TRUE, // Interrupt
+ 0, // InterruptFlags
+ DEVICE_LEVEL, // Level
+ NET_VECTOR, // Vector
+ FALSE, // Memory
+ 0, // MemoryStart
+ 0, // MemorySize
+ FALSE, // Dma
+ 0, // Channel
+ FALSE, // SecondChannel
+ TRUE, // DeviceSpecificData
+ sizeof(CM_SONIC_DEVICE_DATA), // Size
+ (PVOID)&SonicDeviceData // Data
+ );
+
+ JzMakeComponent(&Component,
+ ControllerClass, // Class
+ NetworkController, // Type
+ FALSE, // Readonly
+ FALSE, // Removeable
+ FALSE, // ConsoleIn
+ FALSE, // ConsoleOut
+ TRUE, // Input
+ TRUE, // Output
+ 0, // Key
+ DescriptorSize, // ConfigurationDataLength
+ "SONIC" // Identifier
+ );
+
+ ArcAddChild( Parent, &Component, Descriptor );
+
+ return;
+}
diff --git a/private/ntos/fw/mips/jzenvir.c b/private/ntos/fw/mips/jzenvir.c
new file mode 100644
index 000000000..988afedf5
--- /dev/null
+++ b/private/ntos/fw/mips/jzenvir.c
@@ -0,0 +1,381 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jzenvir.c
+
+Abstract:
+
+ This module contains the code to change an environment variable.
+
+Author:
+
+ David M. Robinson (davidro) 25-Oct-1991
+
+Revision History:
+
+--*/
+
+
+
+#include "jzsetup.h"
+
+//
+// Environment variables.
+//
+
+PCHAR BootString[] = { "LOADIDENTIFIER",
+ "SYSTEMPARTITION",
+ "OSLOADER",
+ "OSLOADPARTITION",
+ "OSLOADFILENAME",
+ "OSLOADOPTIONS" };
+
+BOOLEAN
+JzSetBootEnvironmentVariable (
+ IN ULONG CurrentBootSelection
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allows the user to edit boot environment variables.
+
+Arguments:
+
+ CurrentBootSelection - Supplies the current segment number to edit.
+
+Return Value:
+
+ Returns true if a variable was set, FALSE if ESC was pressed.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ LONG Index;
+ PCHAR Variable;
+ PCHAR LastVariable;
+ CHAR VariableName[32];
+ CHAR VariableValue[128];
+ CHAR Segment[128];
+ GETSTRING_ACTION Action;
+ PCHAR NextVariable;
+
+ Index = 0;
+ do {
+
+ JzSetPosition( 3, 5);
+ JzPrint("\x9bK");
+ JzPrint(JZ_NAME_MSG);
+ Action = FwGetString( VariableName,
+ sizeof(VariableName),
+ BootString[Index],
+ 3,
+ 5 + strlen(JZ_NAME_MSG)
+ );
+ switch (Action) {
+
+ case GetStringEscape:
+ return(FALSE);
+
+ case GetStringUpArrow:
+ if (Index == 0) {
+ Index = 5;
+ } else {
+ Index--;
+ }
+ break;
+
+ case GetStringDownArrow:
+ if (Index == 5) {
+ Index = 0;
+ } else {
+ Index++;
+ }
+ break;
+
+ default:
+ continue;
+
+ }
+
+ } while (Action != GetStringSuccess);
+
+ if (VariableName[0] == 0) {
+ return(FALSE);
+ }
+
+ Variable = NULL;
+ Action = GetStringUpArrow;
+ do {
+
+ switch (Action) {
+
+ case GetStringEscape:
+ return(FALSE);
+
+ case GetStringUpArrow:
+ case GetStringDownArrow:
+ if (Variable == NULL) {
+ strcpy(Segment, VariableName);
+ FwGetVariableSegment( CurrentBootSelection, Segment );
+ strcpy(VariableValue, strchr(Segment, '=') + 1);
+ Variable = VariableValue;
+ } else {
+ Variable = NULL;
+ }
+ break;
+
+ default:
+ continue;
+ }
+
+ JzSetPosition( 4, 5);
+ JzPrint("\x9bK");
+ JzPrint(JZ_VALUE_MSG);
+
+ Action = FwGetString( VariableValue,
+ sizeof(VariableValue),
+ Variable,
+ 4,
+ 5 + strlen(JZ_VALUE_MSG)
+ );
+
+ } while (Action != GetStringSuccess );
+
+ //
+ // Save the old value.
+ //
+
+ strcpy(Segment, VariableName);
+ FwGetVariableSegment( CurrentBootSelection, Segment );
+
+ //
+ // Delete the old value.
+ //
+
+ JzDeleteVariableSegment( VariableName, CurrentBootSelection );
+
+ //
+ // Add in the new value.
+ //
+
+ Status = FwSetVariableSegment( CurrentBootSelection,
+ VariableName,
+ VariableValue );
+
+ if (Status != ESUCCESS) {
+
+ //
+ // Try to add back in the old value.
+ //
+
+ FwSetVariableSegment( CurrentBootSelection,
+ VariableName,
+ strchr(Segment, '=') + 1);
+
+ JzSetPosition(5, 5);
+ if (Status == ENOSPC) {
+ JzPrint(JZ_NO_NVRAM_SPACE_MSG);
+ } else {
+ JzPrint(JZ_NVRAM_CHKSUM_MSG);
+ }
+ JzPrint(JZ_PRESS_KEY2_MSG);
+ FwWaitForKeypress();
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
+
+BOOLEAN
+JzSetEnvironmentVariable (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allow the user to edit environment variables other than
+ the ones for boot.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns true if a variable was set, FALSE if ESC was pressed.
+
+--*/
+
+{
+ ARC_STATUS Status;
+ LONG Index;
+ ULONG Position;
+ PCHAR EqualSign;
+ ULONG EnvironmentIndex;
+ PCHAR Variable;
+ PCHAR LastVariable;
+ CHAR VariableName[32];
+ CHAR InitialVariableName[32];
+ CHAR VariableValue[256];
+ CHAR Segment[256];
+ GETSTRING_ACTION Action;
+ PCHAR Environment;
+
+ //
+ // Index of '0' is a blank entry, so the user can fill out a new environment
+ // variable if required.
+ //
+
+ Variable = NULL;
+ Index = 0;
+ do {
+
+ JzSetPosition( 3, 5);
+ JzPrint("\x9bK");
+ JzPrint(JZ_NAME_MSG);
+ Action = FwGetString( VariableName,
+ sizeof(VariableName),
+ Variable,
+ 3,
+ 5 + strlen(JZ_NAME_MSG)
+ );
+ switch (Action) {
+
+ case GetStringEscape:
+ return(FALSE);
+
+ case GetStringUpArrow:
+ Index--;
+ break;
+
+ case GetStringDownArrow:
+ Index++;
+ break;
+
+ default:
+ continue;
+
+ }
+
+ Environment = FwEnvironmentLoad();
+ LastVariable = Environment;
+ EnvironmentIndex = 1;
+ while (TRUE) {
+
+ //
+ // Jump over any boot variables.
+ //
+
+ while((strstr(Environment, "SYSTEMPARTITION=") != NULL) ||
+ (strstr(Environment, "OSLOADER=") != NULL) ||
+ (strstr(Environment, "OSLOADPARTITION=") != NULL) ||
+ (strstr(Environment, "OSLOADFILENAME=") != NULL) ||
+ (strstr(Environment, "OSLOADOPTIONS=") != NULL) ||
+ (strstr(Environment, "LOADIDENTIFIER=") != NULL)) {
+ Environment = strchr(Environment, '\0') + 1;
+ if (*Environment == 0) {
+ break;
+ }
+ }
+
+ //
+ // The end of the environment was reached without matching
+ // the index. If the index is less than zero, set it to
+ // the last variable found, otherwise set it to 0.
+ //
+
+ if (*Environment == 0) {
+ EnvironmentIndex--;
+ if (Index < 0) {
+ Environment = LastVariable;
+ Index = EnvironmentIndex;
+ } else {
+ Index = 0;
+ Variable = NULL;
+ break;
+ }
+ }
+
+ //
+ // We're on the right variable.
+ //
+
+ if (Index == EnvironmentIndex) {
+
+ InitialVariableName[0] = 0;
+ EqualSign = strchr(Environment, '=');
+ if (EqualSign != NULL) {
+ Position = EqualSign - Environment;
+ strncpy(InitialVariableName, Environment, Position);
+ InitialVariableName[Position] = 0;
+ }
+ Variable = InitialVariableName;
+ break;
+ }
+
+ LastVariable = Environment;
+ Environment = strchr(Environment, '\0') + 1;
+ EnvironmentIndex++;
+ }
+
+ } while (Action != GetStringSuccess);
+
+ if (VariableName[0] == 0) {
+ return(FALSE);
+ }
+
+ Variable = NULL;
+ Action = GetStringUpArrow;
+ do {
+ switch (Action) {
+
+ case GetStringEscape:
+ return(FALSE);
+
+ case GetStringUpArrow:
+ case GetStringDownArrow:
+ if (Variable == NULL) {
+ Variable = ArcGetEnvironmentVariable(VariableName);
+ } else {
+ Variable = NULL;
+ }
+ break;
+
+ default:
+ continue;
+ }
+
+ JzSetPosition( 4, 5);
+ JzPrint("\x9bK");
+ JzPrint(JZ_VALUE_MSG);
+
+ Action = FwGetString( VariableValue,
+ sizeof(VariableValue),
+ Variable,
+ 4,
+ 5 + strlen(JZ_VALUE_MSG)
+ );
+ } while (Action != GetStringSuccess );
+
+ if ((Status = ArcSetEnvironmentVariable( VariableName, VariableValue)) != ESUCCESS) {
+ JzSetPosition(5, 5);
+ if (Status == ENOSPC) {
+ JzPrint(JZ_NO_NVRAM_SPACE_MSG);
+ } else {
+ JzPrint(JZ_NVRAM_CHKSUM_MSG);
+ }
+ JzPrint(JZ_PRESS_KEY2_MSG);
+ FwWaitForKeypress();
+ return(FALSE);
+ }
+
+ return(TRUE);
+}
diff --git a/private/ntos/fw/mips/jzether.c b/private/ntos/fw/mips/jzether.c
new file mode 100644
index 000000000..013c5156d
--- /dev/null
+++ b/private/ntos/fw/mips/jzether.c
@@ -0,0 +1,158 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jzether.c
+
+Abstract:
+
+ This module contains the Jazz ethernet address setup code.
+
+Author:
+
+ David M. Robinson (davidro) 9-Aug-1991
+
+Revision History:
+
+--*/
+
+
+
+#include "jzsetup.h"
+
+VOID
+JzSetEthernet (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ ARC_STATUS Status;
+ UCHAR Address[8];
+ ULONG Index;
+ UCHAR Character;
+ ULONG Count;
+ ULONG Protected;
+ PUCHAR NvramAddress = (PUCHAR)NVRAM_SYSTEM_ID;
+ ULONG Nibble, ByteSum, CheckSum;
+ CHAR PromptAddress[16];
+ PCONFIGURATION_COMPONENT ParentComponent, NetworkComponent;
+ UCHAR Data[sizeof(CM_PARTIAL_RESOURCE_LIST) +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 8 +
+ sizeof(CM_FLOPPY_DEVICE_DATA)];
+ PCM_PARTIAL_RESOURCE_LIST List = (PCM_PARTIAL_RESOURCE_LIST)Data;
+ PCM_SONIC_DEVICE_DATA SonicDeviceData;
+
+ //
+ // Get and display current ethernet address.
+ //
+
+ for (Index = 0; Index < 8 ; Index++ ) {
+ Address[Index] = READ_REGISTER_UCHAR(&NvramAddress[Index]);
+ }
+ JzSetPosition( 3, 5);
+
+ JzPrint(JZ_CURRENT_ENET_MSG);
+ for (Index = 0; Index < 6 ; Index++) {
+ JzPrint("%02lx", Address[Index]);
+ }
+
+ JzSetPosition( 4, 5);
+
+// Protected = READ_REGISTER_ULONG (&DMA_CONTROL->SystemSecurity.Long);
+// if ((Protected & (~READ_ONLY_DISABLE_WRITE))==0) {
+// JzPrint("The NVRAM is ReadOnly, cannot write new address\r\n");
+// } else {
+
+ JzPrint(JZ_NEW_ENET_MSG);
+ while (FwGetString( PromptAddress,
+ sizeof(PromptAddress),
+ NULL,
+ 4,
+ 5 + strlen(JZ_NEW_ENET_MSG)) > GetStringEscape ) {
+ }
+
+ if (*PromptAddress == 0) {
+ return;
+ }
+
+ JzSetPosition( 5, 5);
+ if (strlen(PromptAddress) == 12) {
+ CheckSum=0;
+ for (Index = 0; Index < 12; Index += 2) {
+
+ //
+ // Convert each nibble pair to a byte.
+ //
+
+ Nibble = ((PromptAddress[Index] >= '0') && (PromptAddress[Index] <= '9')) ?
+ PromptAddress[Index] - '0' :
+ tolower(PromptAddress[Index]) - 'a' + 10;
+ ByteSum = (Nibble << 4);
+ Nibble = ((PromptAddress[Index+1] >= '0') && (PromptAddress[Index+1] <= '9')) ?
+ PromptAddress[Index+1] - '0' :
+ tolower(PromptAddress[Index+1]) - 'a' + 10;
+
+ ByteSum |= Nibble;
+ WRITE_REGISTER_UCHAR( &NvramAddress[Index/2], ByteSum);
+
+ CheckSum += ByteSum;
+ if (CheckSum >= 256) { // carry
+ CheckSum++; // Add the carry
+ CheckSum &= 0xFF; // remove it from bit 9
+ }
+ }
+
+ WRITE_REGISTER_UCHAR( &NvramAddress[6], 0);
+ WRITE_REGISTER_UCHAR( &NvramAddress[7], 0xFF - CheckSum);
+
+ for (Index = 0; Index < 8 ; Index++ ) {
+ Address[Index] = READ_REGISTER_UCHAR(&NvramAddress[Index]);
+ }
+
+ JzPrint(JZ_WRITTEN_ENET_MSG);
+
+ for (Index = 0; Index < 8 ; Index++) {
+ JzPrint("%02lx", Address[Index]);
+ }
+
+ JzSetPosition( 6, 5);
+ NetworkComponent = ArcGetComponent("multi()net()");
+ if ((NetworkComponent != NULL) &&
+ (NetworkComponent->Type == NetworkController)) {
+ JzPrint(JZ_FOUND_NET_MSG);
+ ParentComponent = ArcGetParent(NetworkComponent);
+ if (ArcDeleteComponent(NetworkComponent) == ESUCCESS) {
+ JzAddNetwork( ParentComponent );
+ JzPrint(JZ_FIXED_MSG);
+ } else {
+ JzPrint(JZ_NOT_FIXED_MSG);
+ }
+ }
+
+ } else {
+ JzPrint(JZ_INVALID_ENET_MSG);
+ }
+// }
+
+ //
+ // Save configuration in Nvram.
+ //
+
+ JzSetPosition( 7, 4);
+ JzPrint(JZ_SAVE_CONFIG_MSG);
+ ArcSaveConfiguration();
+
+ JzSetPosition( 8, 4);
+ FwWaitForKeypress();
+}
diff --git a/private/ntos/fw/mips/jzgetpar.c b/private/ntos/fw/mips/jzgetpar.c
new file mode 100644
index 000000000..7da1afaa2
--- /dev/null
+++ b/private/ntos/fw/mips/jzgetpar.c
@@ -0,0 +1,690 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ jzgetpar.c
+
+Abstract:
+
+ This module contains the code to manage the boot selections.
+
+
+Author:
+
+ David M. Robinson (davidro) 25-Oct-1991
+
+Revision History:
+
+--*/
+
+#include "jzsetup.h"
+
+
+
+#ifdef DUO
+ULONG
+JzGetScsiBus (
+ IN PULONG CurrentLine,
+ IN ULONG InitialValue
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Line;
+ ULONG ReturnValue;
+ CHAR TempString[5];
+ GETSTRING_ACTION Action;
+
+ Line = *CurrentLine;
+ *CurrentLine += 1;
+
+ while (TRUE) {
+ JzSetPosition( Line, 0);
+
+ JzPrint(JZ_ENTER_SCSI_BUS_MSG);
+ JzPrint("\x9bK");
+
+ sprintf(TempString, "%1d", InitialValue);
+
+ do {
+ Action = FwGetString( TempString,
+ sizeof(TempString),
+ TempString,
+ Line,
+ strlen(JZ_ENTER_SCSI_BUS_MSG));
+
+ if (Action == GetStringEscape) {
+ return(-1);
+ }
+
+ } while ( Action != GetStringSuccess );
+
+ ReturnValue = atoi(TempString);
+
+ if ((ReturnValue >= 0) && (ReturnValue <= 1)) {
+ break;
+ }
+ }
+
+ JzSetPosition( *CurrentLine, 0);
+ return ReturnValue;
+}
+#endif // DUO
+
+
+ULONG
+JzGetDevice (
+ IN PULONG CurrentLine
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Line;
+ ULONG ReturnValue;
+
+ Line = *CurrentLine;
+ *CurrentLine += NUMBER_OF_MEDIA + 2;
+
+ JzPrint(JZ_SELECT_MEDIA_MSG);
+
+ ReturnValue = JxDisplayMenu( MediaChoices,
+ NUMBER_OF_MEDIA,
+ 0,
+ Line + 1);
+
+ JzSetPosition( *CurrentLine, 0);
+ return ReturnValue;
+}
+
+
+ULONG
+JzGetScsiId (
+ IN PULONG CurrentLine,
+ IN PCHAR Prompt,
+ IN ULONG InitialValue
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Line;
+ ULONG ReturnValue;
+ CHAR TempString[5];
+ GETSTRING_ACTION Action;
+
+ Line = *CurrentLine;
+ *CurrentLine += 1;
+
+ while (TRUE) {
+ JzSetPosition( Line, 0);
+
+ JzPrint(Prompt);
+ JzPrint("\x9bK");
+
+ sprintf(TempString, "%1d", InitialValue);
+
+ do {
+ Action = FwGetString( TempString,
+ sizeof(TempString),
+ TempString,
+ Line,
+ strlen(Prompt) + 1);
+
+ if (Action == GetStringEscape) {
+ return(-1);
+ }
+
+ } while ( Action != GetStringSuccess );
+
+ ReturnValue = atoi(TempString);
+
+ if ((ReturnValue >= 0) && (ReturnValue <= 7)) {
+ break;
+ }
+ }
+
+ JzSetPosition( *CurrentLine, 0);
+ return ReturnValue;
+}
+
+
+ULONG
+JzGetPartition (
+ IN PULONG CurrentLine,
+ IN BOOLEAN MustBeFat
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Line;
+ ULONG ReturnValue;
+ CHAR TempString[5];
+ GETSTRING_ACTION Action;
+
+ Line = *CurrentLine;
+ *CurrentLine += 1;
+
+ while (TRUE) {
+ JzSetPosition( Line, 0);
+
+ if (MustBeFat) {
+ JzPrint(JZ_ENTER_FAT_PART_MSG);
+ JzPrint("\x9bK");
+
+ do {
+ Action = FwGetString( TempString,
+ sizeof(TempString),
+ "1",
+ Line,
+ strlen(JZ_ENTER_FAT_PART_MSG));
+
+ if (Action == GetStringEscape) {
+ return(-1);
+ }
+
+ } while ( Action != GetStringSuccess );
+
+ } else {
+ JzPrint(JZ_ENTER_PART_MSG);
+ JzPrint("\x9bK");
+
+ do {
+ Action = FwGetString( TempString,
+ sizeof(TempString),
+ "1",
+ Line,
+ strlen(JZ_ENTER_PART_MSG));
+
+ if (Action == GetStringEscape) {
+ return(-1);
+ }
+
+ } while ( Action != GetStringSuccess );
+
+ }
+
+ ReturnValue = atoi(TempString);
+
+ if ((ReturnValue >= 0) && (ReturnValue <= 9)) {
+ break;
+ }
+ }
+
+ JzSetPosition( *CurrentLine, 0);
+ return ReturnValue;
+}
+
+
+ARC_STATUS
+JzPickSystemPartition (
+ OUT PCHAR SystemPartition,
+ IN OUT PULONG CurrentLine
+ )
+
+/*++
+
+Routine Description:
+
+ This routine picks a system partition from the FWSEARCHPATH or
+ SYSTEMPARTITION environment variables, or builds a new one.
+
+Arguments:
+
+ SystemPartition - Supplies a pointer to a character array to receive the
+ system partition.
+
+ CurrentLine - The current display line.
+
+Return Value:
+
+ If a system partition is picked, ESUCCESS is returned, otherwise an error
+ code is returned.
+
+--*/
+{
+ CHAR Variable[128];
+ PCHAR Segment;
+ ULONG NumberOfChoices;
+ ULONG Index, i;
+ BOOLEAN More;
+ BOOLEAN FoundOne;
+ ULONG SecondPass;
+ ULONG BusNumber[10];
+ ULONG Device[10]; // 0 = scsi disk, 1 = scsi floppy, 2 = cdrom
+ ULONG DeviceId[10];
+ ULONG DevicePartition[10];
+ ULONG Key;
+ CHAR MenuItem[11][40];
+ PCHAR Menu[10];
+
+ //
+ // Loop through the FWSEARCHPATH and SYSTEMPARTITION variables
+ // for potential system partitions.
+ //
+
+ NumberOfChoices = 0;
+ SecondPass = 0;
+
+ do {
+
+ Index = 0;
+ if (!SecondPass) {
+ strcpy(Variable, "FWSEARCHPATH");
+ } else {
+ strcpy(Variable, BootString[SystemPartitionVariable]);
+ }
+
+ do {
+ FoundOne = FALSE;
+ More = FwGetVariableSegment(Index++, Variable);
+
+ //
+ // Advance to the segment.
+ //
+ Segment = strchr(Variable, '=') + 1;
+ if (Segment == NULL) {
+ continue;
+ }
+
+ //
+ // Convert Segment to lower case.
+ //
+
+ for (i = 0 ; Segment[i] ; i++ ) {
+ Segment[i] = tolower(Segment[i]);
+ }
+
+ //
+ // Look for segments of the type "scsi(w)disk(x)rdisk()partition(z)"
+ // or "scsi(w)disk(x)fdisk()" or "scsi(w)cdrom(x)fdisk()"
+ //
+
+ if (!FwGetPathMnemonicKey( Segment, "scsi", &Key )) {
+ BusNumber[NumberOfChoices] = Key;
+ if (!FwGetPathMnemonicKey( Segment, "disk", &Key )) {
+ DeviceId[NumberOfChoices] = Key;
+ if (!FwGetPathMnemonicKey( Segment, "rdisk", &Key )) {
+ if (!FwGetPathMnemonicKey( Segment, "partition", &Key )) {
+ Device[NumberOfChoices] = 0;
+ DevicePartition[NumberOfChoices] = Key;
+ FoundOne = TRUE;
+ }
+ } else if (!FwGetPathMnemonicKey( Segment, "fdisk", &Key )) {
+ Device[NumberOfChoices] = 1;
+ DevicePartition[NumberOfChoices] = 0;
+ FoundOne = TRUE;
+ }
+ } else if (!FwGetPathMnemonicKey( Segment, "cdrom", &Key )) {
+ if (!FwGetPathMnemonicKey( Segment, "fdisk", &Key )) {
+ Device[NumberOfChoices] = 2;
+ DeviceId[NumberOfChoices] = Key;
+ DevicePartition[NumberOfChoices] = 0;
+ FoundOne = TRUE;
+ }
+ }
+ }
+
+ //
+ // Increment number of choices if this is not a duplicate entry.
+ //
+
+ if (FoundOne) {
+ for ( i = 0 ; i < NumberOfChoices ; i++ ) {
+ if ((Device[NumberOfChoices] == Device[i]) &&
+#ifdef DUO
+ (BusNumber[NumberOfChoices] == BusNumber[i]) &&
+#endif DUO
+ (DeviceId[NumberOfChoices] == DeviceId[i]) &&
+ (DevicePartition[NumberOfChoices] == DevicePartition[i])) {
+ break;
+ }
+ }
+ if (i == NumberOfChoices) {
+ NumberOfChoices++;
+ if (NumberOfChoices == 10) {
+ break;
+ }
+ }
+ }
+ } while ( More );
+ } while ( !(SecondPass++) && (NumberOfChoices < 10));
+
+ if (NumberOfChoices != 0) {
+
+ //
+ // Display the choices.
+ //
+
+ JzPrint(JZ_SELECT_SYS_PART_MSG);
+ *CurrentLine += 1;
+ JzSetPosition( *CurrentLine, 0);
+
+ for ( Index = 0 ; Index < NumberOfChoices ; Index++ ) {
+ switch (Device[Index]) {
+#ifdef DUO
+ case 0:
+ sprintf( MenuItem[Index],
+ JZ_SCSI_HD_MSG,
+ BusNumber[Index],
+ DeviceId[Index],
+ DevicePartition[Index]);
+ break;
+ case 1:
+ sprintf( MenuItem[Index],
+ JZ_SCSI_FL_MSG,
+ BusNumber[Index],
+ DeviceId[Index]);
+ break;
+ default:
+ sprintf( MenuItem[Index],
+ JZ_SCSI_CD_MSG,
+ BusNumber[Index],
+ DeviceId[Index]);
+ break;
+#else
+ case 0:
+ sprintf( MenuItem[Index],
+ JZ_SCSI_HD_MSG,
+ DeviceId[Index],
+ DevicePartition[Index]);
+ break;
+ case 1:
+ sprintf( MenuItem[Index],
+ JZ_SCSI_FL_MSG,
+ DeviceId[Index]);
+ break;
+ default:
+ sprintf( MenuItem[Index],
+ JZ_SCSI_CD_MSG,
+ DeviceId[Index]);
+ break;
+#endif // DUO
+ }
+ Menu[Index] = MenuItem[Index];
+ }
+
+ strcpy(MenuItem[Index], JZ_NEW_SYS_PART_MSG);
+ Menu[Index] = MenuItem[Index];
+
+ Index = JxDisplayMenu(Menu,
+ NumberOfChoices + 1,
+ 0,
+ *CurrentLine);
+
+ *CurrentLine += NumberOfChoices + 2;
+
+ if (Index == -1) {
+ return(EINVAL);
+ }
+
+ //
+ // If the user selects new system partition, indicate this by setting
+ // NumberOfChoices to zero.
+ //
+
+ if (Index == NumberOfChoices) {
+ NumberOfChoices = 0;
+ }
+ }
+
+ //
+ // If NumberOfChoices is zero, select a new partition.
+ //
+
+ if (NumberOfChoices == 0) {
+
+ Index = 0;
+
+ //
+ // Determine system partition.
+ //
+
+ JzSetPosition( *CurrentLine, 0);
+ JzPrint(JZ_LOCATE_SYS_PART_MSG);
+ *CurrentLine += 1;
+ JzSetPosition( *CurrentLine, 0);
+
+#ifdef DUO
+ BusNumber[0] = JzGetScsiBus(CurrentLine, 0);
+ if (BusNumber[0] == -1) {
+ return(EINVAL);
+ }
+#endif // DUO
+
+ Device[0] = JzGetDevice(CurrentLine);
+ if (Device[0] == -1) {
+ return(EINVAL);
+ }
+
+ DeviceId[0] = JzGetScsiId(CurrentLine, JZ_ENTER_SCSI_ID_MSG, 0);
+ if (DeviceId[0] == -1) {
+ return(EINVAL);
+ }
+
+ //
+ // If the media is scsi disk, get the partition.
+ //
+
+ if (Device[0] == 0) {
+ DevicePartition[0] = JzGetPartition(CurrentLine, TRUE);
+ if (DevicePartition[0] == -1) {
+ return(EINVAL);
+ }
+ }
+ }
+
+ //
+ // Create a name string from the Device, DeviceId,
+ // DevicePartition.
+ //
+
+ switch (Device[Index]) {
+#ifdef DUO
+ case 0:
+ sprintf( SystemPartition,
+ "scsi(%1d)disk(%1d)rdisk()partition(%1d)",
+ BusNumber[Index],
+ DeviceId[Index],
+ DevicePartition[Index]);
+ break;
+ case 1:
+ sprintf( SystemPartition,
+ "scsi(%1d)disk(%1d)fdisk()",
+ BusNumber[Index],
+ DeviceId[Index]);
+ break;
+ default:
+ sprintf( SystemPartition,
+ "scsi(%1d)cdrom(%1d)fdisk()",
+ BusNumber[Index],
+ DeviceId[Index]);
+ break;
+#else
+ case 0:
+ sprintf( SystemPartition,
+ "scsi()disk(%1d)rdisk()partition(%1d)",
+ DeviceId[Index],
+ DevicePartition[Index]);
+ break;
+ case 1:
+ sprintf( SystemPartition,
+ "scsi()disk(%1d)fdisk()",
+ DeviceId[Index]);
+ break;
+ default:
+ sprintf( SystemPartition,
+ "scsi()cdrom(%1d)fdisk()",
+ DeviceId[Index]);
+ break;
+#endif // DUO
+ }
+
+ JzSetPosition(*CurrentLine, 0);
+ return(ESUCCESS);
+}
+
+
+ARC_STATUS
+JzPickOsPartition (
+ OUT PCHAR OsPartition,
+ IN OUT PULONG CurrentLine
+ )
+
+/*++
+
+Routine Description:
+
+ This routine picks an OsPartition.
+
+Arguments:
+
+ OsSystemPartition - Supplies a pointer to a character array to receive the
+ operationg system partition.
+
+ CurrentLine - The current display line.
+
+Return Value:
+
+ If a system partition is picked, ESUCCESS is returned, otherwise an error
+ code is returned.
+
+--*/
+{
+ LONG BusNumber;
+ LONG Device;
+ LONG DeviceId;
+ LONG DevicePartition;
+
+ //
+ // Determine os partition.
+ //
+
+ JzPrint(JZ_LOCATE_OS_PART_MSG);
+ *CurrentLine += 1;
+ JzSetPosition( *CurrentLine, 0);
+
+#ifdef DUO
+ BusNumber = JzGetScsiBus(CurrentLine, 0);
+ if (BusNumber == -1) {
+ return(EINVAL);
+ }
+#endif // DUO
+
+ Device = JzGetDevice(CurrentLine);
+ if (Device == -1) {
+ return(EINVAL);
+ }
+
+ DeviceId = JzGetScsiId(CurrentLine, JZ_ENTER_SCSI_ID_MSG, 0);
+ if (DeviceId == -1) {
+ return(EINVAL);
+ }
+
+ //
+ // If the media is scsi disk, get the partition.
+ //
+
+ if (Device == 0) {
+ DevicePartition = JzGetPartition(CurrentLine, FALSE);
+ if (DevicePartition == -1) {
+ return(EINVAL);
+ }
+ }
+
+ //
+ // Create a name string from the Device, DeviceId,
+ // DevicePartition.
+ //
+
+ switch (Device) {
+#ifdef DUO
+ case 0:
+ sprintf( OsPartition,
+ "scsi(%1d)disk(%1d)rdisk()partition(%1d)",
+ BusNumber,
+ DeviceId,
+ DevicePartition);
+ break;
+ case 1:
+ sprintf( OsPartition,
+ "scsi(%1d)disk(%1d)fdisk()",
+ BusNumber,
+ DeviceId);
+ break;
+ default:
+ sprintf( OsPartition,
+ "scsi(%1d)cdrom(%1d)fdisk()",
+ BusNumber,
+ DeviceId);
+ break;
+#else
+ case 0:
+ sprintf( OsPartition,
+ "scsi()disk(%1d)rdisk()partition(%1d)",
+ DeviceId,
+ DevicePartition);
+ break;
+ case 1:
+ sprintf( OsPartition,
+ "scsi()disk(%1d)fdisk()",
+ DeviceId);
+ break;
+ default:
+ sprintf( OsPartition,
+ "scsi()cdrom(%1d)fdisk()",
+ DeviceId);
+ break;
+#endif // DUO
+ }
+ return(ESUCCESS);
+}
+
diff --git a/private/ntos/fw/mips/jzmake.c b/private/ntos/fw/mips/jzmake.c
new file mode 100644
index 000000000..806b4959b
--- /dev/null
+++ b/private/ntos/fw/mips/jzmake.c
@@ -0,0 +1,496 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jzmake.c
+
+Abstract:
+
+ This module contains the code to make the configuration and environment
+ variable data structures in the Jazz NVRAM.
+
+
+Author:
+
+ David M. Robinson (davidro) 25-Oct-1991
+
+Revision History:
+
+--*/
+
+#include "jzsetup.h"
+
+//
+// Routine prototypes.
+//
+
+VOID
+JzMakeConfiguration (
+ ULONG Monitor,
+ ULONG Floppy,
+ ULONG Floppy2
+ );
+
+BOOLEAN
+JzMatchComponent(
+ IN PCHAR Value1,
+ IN PCHAR Value2
+ );
+
+ULONG
+JzGetYesNo (
+ IN PULONG CurrentLine,
+ IN PCHAR PromptString,
+ IN BOOLEAN YesIsDefault
+ );
+
+#ifdef DUO
+ULONG
+JzGetScsiBus (
+ IN PULONG CurrentLine,
+ IN ULONG InitialValue
+ );
+#endif // DUO
+
+ULONG
+JzGetScsiId (
+ IN PULONG CurrentLine,
+ IN PCHAR Prompt,
+ IN ULONG InitialValue
+ );
+
+ULONG
+JzGetDevice (
+ IN PULONG CurrentLine
+ );
+
+ULONG
+JzGetPartition (
+ IN PULONG CurrentLine,
+ IN BOOLEAN MustBeFat
+ );
+
+
+VOID
+JzMakeEnvironment (
+ ULONG BusNumber,
+ ULONG Device,
+ ULONG DeviceId,
+ ULONG DevicePartition
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the environment variables.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ARC_STATUS Status;
+ CHAR TempString[80];
+
+ switch (Device) {
+#ifdef DUO
+ case 0:
+ sprintf( TempString,
+ "scsi(%1d)disk(%1d)rdisk()partition(%1d)",
+ BusNumber,
+ DeviceId,
+ DevicePartition);
+ break;
+ case 1:
+ sprintf( TempString,
+ "scsi(%1d)disk(%1d)fdisk()",
+ BusNumber,
+ DeviceId);
+ break;
+ default:
+ sprintf( TempString,
+ "scsi(%1d)cdrom(%1d)fdisk()",
+ BusNumber,
+ DeviceId);
+ break;
+#else
+ case 0:
+ sprintf( TempString,
+ "scsi()disk(%1d)rdisk()partition(%1d)",
+ DeviceId,
+ DevicePartition);
+ break;
+ case 1:
+ sprintf( TempString,
+ "scsi()disk(%1d)fdisk()",
+ DeviceId);
+ break;
+ default:
+ sprintf( TempString,
+ "scsi()cdrom(%1d)fdisk()",
+ DeviceId);
+ break;
+#endif // DUO
+ }
+
+ Status = ArcSetEnvironmentVariable("CONSOLEIN",
+ "multi()key()keyboard()console()");
+
+ if (Status != ESUCCESS) {
+ goto TestError;
+ }
+
+ Status = ArcSetEnvironmentVariable("CONSOLEOUT",
+ "multi()video()monitor()console()");
+
+ if (Status != ESUCCESS) {
+ goto TestError;
+ }
+
+ Status = ArcSetEnvironmentVariable("FWSEARCHPATH",
+ TempString);
+
+ if (Status != ESUCCESS) {
+ goto TestError;
+ }
+
+ // TEMPTEMP
+ Status = ArcSetEnvironmentVariable("SYSTEMPARTITION",
+ TempString);
+
+ if (Status != ESUCCESS) {
+ goto TestError;
+ }
+ // TEMPTEMP
+
+// Status = ArcSetEnvironmentVariable("TIMEZONE",
+// "PST8PDT");
+
+// if (Status != ESUCCESS) {
+// goto TestError;
+// }
+
+#ifndef DUO
+ Status = ArcSetEnvironmentVariable("A:",
+ "multi()disk()fdisk()");
+#endif // DUO
+
+ if (Status != ESUCCESS) {
+ goto TestError;
+ }
+
+ return;
+
+TestError:
+
+ JzPrint(JZ_CANT_SET_VARIABLE_MSG);
+ return;
+}
+
+
+ULONG
+JzGetMonitor (
+ IN PULONG CurrentLine
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Line;
+ ULONG ReturnValue;
+
+ Line = *CurrentLine;
+ *CurrentLine += NUMBER_OF_RESOLUTIONS + 2;
+
+ JzSetPosition( Line, 0);
+ JzPrint(JZ_MONITOR_RES_MSG);
+
+ ReturnValue = JxDisplayMenu( ResolutionChoices,
+ NUMBER_OF_RESOLUTIONS,
+ 0,
+ Line + 1);
+
+ JzSetPosition( *CurrentLine, 0);
+ return ReturnValue;
+}
+
+
+ULONG
+JzGetFloppy (
+ IN PULONG CurrentLine
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Line;
+ ULONG ReturnValue;
+
+ Line = *CurrentLine;
+ *CurrentLine += NUMBER_OF_FLOPPIES + 2;
+
+ JzSetPosition( Line, 0);
+ JzPrint(JZ_FLOPPY_SIZE_MSG);
+
+ ReturnValue = JxDisplayMenu( FloppyChoices,
+ NUMBER_OF_FLOPPIES,
+ 1,
+ Line + 1);
+
+ JzSetPosition( *CurrentLine, 0);
+ return ReturnValue;
+}
+
+
+BOOLEAN
+JzMakeDefaultConfiguration (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns TRUE if the configuration was modified, otherwise returns FALSE.
+
+--*/
+{
+ ARC_STATUS Status;
+ ULONG Index;
+ UCHAR Character;
+ ULONG Count;
+ PUCHAR Nvram;
+ ULONG CurrentLine;
+ LONG Monitor;
+ LONG Floppy;
+ LONG Floppy2;
+ ULONG OldScsiHostId;
+
+ JzClearScreen();
+ JzShowTime(TRUE);
+ CurrentLine = 2;
+
+ Monitor = JzGetMonitor(&CurrentLine);
+ if (Monitor == -1) {
+ return(FALSE);
+ }
+
+ Floppy = JzGetFloppy(&CurrentLine);
+ if (Floppy == -1) {
+ return(FALSE);
+ }
+
+ Floppy2 = JzGetYesNo(&CurrentLine, JZ_2ND_FLOPPY_MSG, FALSE);
+ if (Floppy2 == -1) {
+ return(FALSE);
+ }
+
+ if (Floppy2 == 0) {
+ Floppy2 = JzGetFloppy(&CurrentLine);
+ if (Floppy == -1) {
+ return(FALSE);
+ }
+ } else {
+ Floppy2 = -1;
+ }
+
+ //
+ // Save the current scsi host id, and then change ScsiHostId to an invalid
+ // value so that the user can select the current id (see JzGetScsiId).
+ //
+
+ OldScsiHostId = ScsiHostId;
+ ScsiHostId = 8;
+ ScsiHostId = JzGetScsiId(&CurrentLine, JZ_SCSI_HOST_MSG, OldScsiHostId);
+ if (ScsiHostId == -1) {
+ ScsiHostId = OldScsiHostId;
+ return(FALSE);
+ }
+
+ //
+ // Clear the configuration information.
+ //
+
+ JzPrint(JZ_CLEAR_CONFIG_MSG);
+
+ //
+ // Zero all of the configuration read/write NVRAM, note that the checksum is
+ // also zero in this case.
+ //
+
+ for ( Nvram = (PUCHAR)(NVRAM_CONFIGURATION);
+ Nvram < (PUCHAR)(NVRAM_CONFIGURATION +
+ sizeof(COMPRESSED_CONFIGURATION_PACKET) * NUMBER_OF_ENTRIES +
+ LENGTH_OF_IDENTIFIER +
+ LENGTH_OF_DATA +
+ 4) ;
+ Nvram++ ) {
+ WRITE_REGISTER_UCHAR( Nvram, 0 );
+ }
+
+ //
+ // Clear the EISA space.
+ //
+
+ Nvram = (PUCHAR)((PNV_CONFIGURATION)NVRAM_CONFIGURATION)->EisaData;
+ for ( Index = 0;
+ Index < LENGTH_OF_EISA_DATA + 4;
+ Index++ ) {
+ WRITE_REGISTER_UCHAR( &Nvram[Index], 0 );
+ }
+
+ //
+ // Add components.
+ //
+
+ JzPrint(JZ_ADD_CONFIG_MSG);
+ JzMakeConfiguration(Monitor, Floppy, Floppy2);
+
+ //
+ // Save configuration in Nvram.
+ //
+
+ JzPrint(JZ_SAVE_CONFIG_MSG);
+ ArcSaveConfiguration();
+
+ JzPrint(JZ_DONE_CONFIG_MSG);
+ FwWaitForKeypress();
+
+ return(TRUE);
+}
+
+
+VOID
+JzMakeDefaultEnvironment (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ARC_STATUS Status;
+ ULONG Index;
+ UCHAR Character;
+ ULONG Count;
+ PUCHAR Nvram;
+ ULONG CurrentLine;
+ LONG BusNumber;
+ LONG Device;
+ LONG DeviceId;
+ LONG DevicePartition;
+
+
+ JzClearScreen();
+ JzShowTime(TRUE);
+ CurrentLine = 2;
+ JzSetPosition( CurrentLine, 0);
+
+ JzPrint(JZ_DEFAULT_SYS_PART_MSG);
+ CurrentLine += 1;
+ JzSetPosition( CurrentLine, 0);
+
+#ifdef DUO
+ BusNumber = JzGetScsiBus(&CurrentLine, 0);
+ if (BusNumber == -1) {
+ return;
+ }
+#endif // DUO
+
+ Device = JzGetDevice(&CurrentLine);
+ if (Device == -1) {
+ return;
+ }
+
+ DeviceId = JzGetScsiId(&CurrentLine, " Enter SCSI ID: ", 0);
+ if (DeviceId == -1) {
+ return;
+ }
+
+ //
+ // If the media is scsi disk, get the partition.
+ //
+
+ if (Device == 0) {
+ DevicePartition = JzGetPartition(&CurrentLine, TRUE);
+ if (DevicePartition == -1) {
+ return;
+ }
+
+ }
+
+ //
+ // Clear the environment information.
+ //
+
+ JzPrint(JZ_CLEAR_CONFIG_MSG);
+
+ //
+ // Zero all of the environment read/write NVRAM, note that the checksum is
+ // also zero in this case.
+ //
+
+ Nvram = (PUCHAR)((PNV_CONFIGURATION)NVRAM_CONFIGURATION)->Environment;
+ for ( Index = 0;
+ Index < LENGTH_OF_ENVIRONMENT + 4;
+ Index++ ) {
+ WRITE_REGISTER_UCHAR( &Nvram[Index], 0 );
+ }
+
+ //
+ // Add environment variables.
+ //
+
+ JzPrint(JZ_ADD_ENVIR_MSG);
+ JzMakeEnvironment(BusNumber, Device, DeviceId, DevicePartition);
+ FwWaitForKeypress();
+
+ return;
+}
+
diff --git a/private/ntos/fw/mips/jzsetup.c b/private/ntos/fw/mips/jzsetup.c
new file mode 100644
index 000000000..15583e794
--- /dev/null
+++ b/private/ntos/fw/mips/jzsetup.c
@@ -0,0 +1,307 @@
+/*++
+
+Copyright (c) 1991, 1992 Microsoft Corporation
+
+Module Name:
+
+ jzsetup.c
+
+Abstract:
+
+ This program loads up the Jazz non-volatile ram.
+
+Author:
+
+ David M. Robinson (davidro) 9-Aug-1991
+
+Revision History:
+
+--*/
+
+#include "jzsetup.h"
+
+//
+// Routine prototypes.
+//
+
+BOOLEAN
+JzInitializationMenu(
+ VOID
+ );
+
+VOID
+JzBootMenu(
+ VOID
+ );
+
+VOID
+JzEnvironmentMenu(
+ VOID
+ );
+
+//
+// Static data.
+//
+
+ULONG ScsiHostId;
+PCHAR Banner1 = " JAZZ Setup Program Version 0.17";
+PCHAR Banner2 = " Copyright (c) 1993 Microsoft Corporation";
+
+
+ULONG
+JzInitializeScsiHostId (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gets the ScsiHostId from the configuration database if if
+ exists.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The ScsiHostId is read from the ScsiController configuration component
+ if it exists. If not, a value of 7 is returned.
+
+--*/
+{
+ PCONFIGURATION_COMPONENT Component;
+ PCM_SCSI_DEVICE_DATA ScsiDeviceData;
+ UCHAR Buffer[sizeof(CM_PARTIAL_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 5) +
+ sizeof(CM_SCSI_DEVICE_DATA)];
+ PCM_PARTIAL_RESOURCE_LIST Descriptor = (PCM_PARTIAL_RESOURCE_LIST)&Buffer;
+ ULONG Count;
+
+ if (((Component = ArcGetComponent("scsi(0)")) != NULL) &&
+ (Component->Class == AdapterClass) && (Component->Type == ScsiAdapter) &&
+ (ArcGetConfigurationData((PVOID)Descriptor, Component) == ESUCCESS) &&
+ ((Count = Descriptor->Count) < 6)) {
+
+ ScsiDeviceData = (PCM_SCSI_DEVICE_DATA)&Descriptor->PartialDescriptors[Count];
+
+ if (ScsiDeviceData->HostIdentifier > 7) {
+ return(7);
+ } else {
+ return(ScsiDeviceData->HostIdentifier);
+ }
+ }
+
+ return(7);
+
+}
+
+VOID
+JzSetup (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is the top level of the setup program.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ BOOLEAN Reboot;
+ LONG DefaultChoice = 0;
+
+ //
+ // Setup is running.
+ //
+
+ SetupIsRunning = TRUE;
+
+ //
+ // Initialize the ScsiHostId Value.
+ //
+
+ ScsiHostId = JzInitializeScsiHostId();
+
+ //
+ // Set up the screen.
+ //
+
+ JzSetScreenAttributes( TRUE, FALSE, FALSE);
+ JzSetScreenColor(ArcColorWhite, ArcColorBlue);
+
+ //
+ // Loop on choices until exit is selected.
+ //
+
+ Reboot = FALSE;
+
+ while (TRUE) {
+
+ DefaultChoice = JzGetSelection(JzSetupChoices,
+ NUMBER_OF_JZ_SETUP_CHOICES,
+ DefaultChoice);
+
+ //
+ // If the escape key was pressed, exit.
+ //
+
+ if (DefaultChoice == -1) {
+ DefaultChoice = 0x7fffffff;
+ }
+
+ //
+ // Switch based on the action.
+ //
+
+ switch (DefaultChoice) {
+
+ //
+ // Change or initialize the configuration.
+ //
+
+ case 0:
+ Reboot = Reboot || JzInitializationMenu();
+ break;
+
+ //
+ // Manage the boot process.
+ //
+
+ case 1:
+ JzBootMenu();
+ break;
+
+ //
+ // Exit.
+ //
+
+ default:
+ if (Reboot) {
+ ArcReboot();
+ }
+ return;
+ }
+ }
+}
+
+BOOLEAN
+JzInitializationMenu(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine displays the configuration menu.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If a system reboot is required, TRUE is returned, otherwise FALSE is
+ returned.
+
+--*/
+{
+
+ BOOLEAN Reboot;
+ LONG DefaultChoice = 0;
+
+ //
+ // Loop on choices until exit is selected.
+ //
+
+ Reboot = FALSE;
+
+ while (TRUE) {
+
+ DefaultChoice = JzGetSelection(ConfigurationChoices,
+ NUMBER_OF_CONFIGURATION_CHOICES,
+ DefaultChoice);
+
+ //
+ // If the escape key was pressed, return.
+ //
+
+ if (DefaultChoice == -1) {
+ DefaultChoice = 0x7fffffff;
+ }
+
+ //
+ // Switch based on the action.
+ //
+
+ switch (DefaultChoice) {
+
+ //
+ // Load default configuration.
+ //
+
+ case 0:
+ Reboot = Reboot || JzMakeDefaultConfiguration();
+ break;
+
+ //
+ // Load default environment.
+ //
+
+ case 1:
+ JzMakeDefaultEnvironment();
+ break;
+
+
+ //
+ // Edit an environment variable
+ //
+ case 2:
+ JzEditVariable();
+ break;
+
+ //
+ // Set the RTC.
+ //
+
+ case 3:
+ JzSetTime();
+ break;
+
+ //
+ // Change the ethernet address.
+ //
+
+ case 4:
+ JzSetEthernet();
+ break;
+
+ //
+ // Run the debug monitor.
+ //
+
+ case 5:
+ SetupIsRunning = FALSE;
+ ArcEnterInteractiveMode();
+ SetupIsRunning = TRUE;
+ break;
+
+ //
+ // Return to main menu.
+ //
+
+ default:
+ return(Reboot);
+ }
+ }
+}
diff --git a/private/ntos/fw/mips/jzsetup.h b/private/ntos/fw/mips/jzsetup.h
new file mode 100644
index 000000000..a46711ce8
--- /dev/null
+++ b/private/ntos/fw/mips/jzsetup.h
@@ -0,0 +1,154 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jzsetup.h
+
+Abstract:
+
+ This module contains the definitions for the Jazz setup program.
+
+Author:
+
+ David M. Robinson (davidro) 25-Oct-1991
+
+Revision History:
+
+--*/
+
+#ifndef _JZSETUP_
+#define _JZSETUP_
+
+
+#include "fwp.h"
+#include "jazzvdeo.h"
+#include "jazzrtc.h"
+#include "string.h"
+#include "iodevice.h"
+#include "jzstring.h"
+
+#define KeFlushWriteBuffer()
+
+#define MAX_NUMBER_OF_ENVIRONMENT_VARIABLES 20
+
+#define EISA_NMI 0x70
+
+extern PCHAR BootString[];
+extern ULONG ScsiHostId;
+
+typedef enum _BOOT_VARIABLES {
+ LoadIdentifierVariable,
+ SystemPartitionVariable,
+ OsLoaderVariable,
+ OsLoadPartitionVariable,
+ OsLoadFilenameVariable,
+ OsLoadOptionsVariable,
+ MaximumBootVariable
+ } BOOT_VARIABLE;
+
+
+//
+// Print macros.
+//
+
+#define JzClearScreen() \
+ JzPrint("%c2J", ASCII_CSI)
+
+#define JzSetScreenColor(FgColor, BgColor) \
+ JzPrint("%c3%dm", ASCII_CSI, (UCHAR)FgColor); \
+ JzPrint("%c4%dm", ASCII_CSI, (UCHAR)BgColor)
+
+#define JzSetScreenAttributes( HighIntensity, Underscored, ReverseVideo ) \
+ JzPrint("%c0m", ASCII_CSI); \
+ if (HighIntensity) { \
+ JzPrint("%c1m", ASCII_CSI); \
+ } \
+ if (Underscored) { \
+ JzPrint("%c4m", ASCII_CSI); \
+ } \
+ if (ReverseVideo) { \
+ JzPrint("%c7m", ASCII_CSI); \
+ }
+
+#define JzSetPosition( Row, Column ) \
+ JzPrint("%c%d;%dH", ASCII_CSI, (Row + 1), (Column + 1))
+
+#define JzStallExecution( Wait ) \
+ { \
+ ULONG HackStall; \
+ for (HackStall = 0;HackStall < (Wait << 4);HackStall++) { \
+ } \
+ }
+
+
+
+//
+// Routine prototypes.
+//
+
+VOID
+JzSetEthernet (
+ VOID
+ );
+
+VOID
+JzSetTime (
+ VOID
+ );
+
+VOID
+JzShowTime (
+ BOOLEAN First
+ );
+
+BOOLEAN
+JzMakeDefaultConfiguration (
+ VOID
+ );
+
+VOID
+JzMakeDefaultEnvironment (
+ VOID
+ );
+
+VOID
+JzAddBootSelection (
+ VOID
+ );
+
+VOID
+JzDeleteBootSelection (
+ VOID
+ );
+
+BOOLEAN
+JzSetBootEnvironmentVariable (
+ IN ULONG CurrentBootSelection
+ );
+
+BOOLEAN
+JzSetEnvironmentVariable (
+ VOID
+ );
+
+VOID
+JzAddNetwork(
+ PCONFIGURATION_COMPONENT Parent
+ );
+
+VOID
+JzDeleteVariableSegment (
+ PCHAR VariableName,
+ ULONG Selection
+ );
+
+ULONG
+JzGetSelection(
+ IN PCHAR Menu[],
+ IN ULONG NumberOfChoices,
+ IN ULONG DefaultChoice
+ );
+
+#endif // _JZSETUP_
diff --git a/private/ntos/fw/mips/jzstring.h b/private/ntos/fw/mips/jzstring.h
new file mode 100644
index 000000000..243e2ebf0
--- /dev/null
+++ b/private/ntos/fw/mips/jzstring.h
@@ -0,0 +1,102 @@
+//
+// Common strings.
+//
+
+extern PCHAR JZ_CRLF_MSG;
+
+//
+// Prompt strings.
+//
+
+extern PCHAR JZ_COUNTDOWN_MSG;
+extern PCHAR JZ_OSLOADER_MSG;
+extern PCHAR JZ_OS_MSG;
+extern PCHAR JZ_OS_ROOT_MSG;
+extern PCHAR JZ_BOOT_NAME_MSG;
+extern PCHAR JZ_INIT_DEBUG_MSG;
+extern PCHAR JZ_CANT_SET_VARIABLE_MSG;
+extern PCHAR JZ_NO_SELECTIONS_TO_DELETE_MSG;
+extern PCHAR JZ_SELECTION_TO_DELETE_MSG;
+extern PCHAR JZ_ENVIR_FOR_BOOT_MSG;
+extern PCHAR JZ_FORMAT1_MSG;
+extern PCHAR JZ_USE_ARROWS_MSG;
+extern PCHAR JZ_NO_SELECTIONS_TO_EDIT_MSG;
+extern PCHAR JZ_SELECTION_TO_EDIT_MSG;
+extern PCHAR JZ_NO_SELECTIONS_TO_REARRANGE_MSG;
+extern PCHAR JZ_PICK_SELECTION_MSG;
+extern PCHAR JZ_SHOULD_AUTOBOOT_MSG;
+extern PCHAR JZ_ENVIRONMENT_VARS_MSG;
+extern PCHAR JZ_CHECKING_BOOT_SEL_MSG;
+extern PCHAR JZ_VARIABLE_NULL_MSG;
+extern PCHAR JZ_CANT_BE_FOUND_MSG;
+extern PCHAR JZ_PROBLEMS_FOUND_MSG;
+extern PCHAR JZ_PRESS_KEY_MSG;
+extern PCHAR JZ_PRESS_KEY2_MSG;
+extern PCHAR JZ_NAME_MSG;
+extern PCHAR JZ_VALUE_MSG;
+extern PCHAR JZ_NO_NVRAM_SPACE_MSG;
+extern PCHAR JZ_NVRAM_CHKSUM_MSG;
+extern PCHAR JZ_CURRENT_ENET_MSG;
+extern PCHAR JZ_NEW_ENET_MSG;
+extern PCHAR JZ_WRITTEN_ENET_MSG;
+extern PCHAR JZ_FOUND_NET_MSG;
+extern PCHAR JZ_FIXED_MSG;
+extern PCHAR JZ_NOT_FIXED_MSG;
+extern PCHAR JZ_INVALID_ENET_MSG;
+extern PCHAR JZ_SELECT_MEDIA_MSG;
+extern PCHAR JZ_ENTER_FAT_PART_MSG;
+extern PCHAR JZ_ENTER_PART_MSG;
+extern PCHAR JZ_SELECT_SYS_PART_MSG;
+extern PCHAR JZ_SCSI_HD_MSG;
+extern PCHAR JZ_SCSI_FL_MSG;
+extern PCHAR JZ_SCSI_CD_MSG;
+extern PCHAR JZ_NEW_SYS_PART_MSG;
+extern PCHAR JZ_LOCATE_SYS_PART_MSG;
+extern PCHAR JZ_ENTER_SCSI_BUS_MSG;
+extern PCHAR JZ_ENTER_SCSI_ID_MSG;
+extern PCHAR JZ_LOCATE_OS_PART_MSG;
+extern PCHAR JZ_MONITOR_RES_MSG;
+extern PCHAR JZ_FLOPPY_SIZE_MSG;
+extern PCHAR JZ_2ND_FLOPPY_MSG;
+extern PCHAR JZ_SCSI_HOST_MSG;
+extern PCHAR JZ_CLEAR_CONFIG_MSG;
+extern PCHAR JZ_ADD_CONFIG_MSG;
+extern PCHAR JZ_ADD_ENVIR_MSG;
+extern PCHAR JZ_SAVE_CONFIG_MSG;
+extern PCHAR JZ_DONE_CONFIG_MSG;
+extern PCHAR JZ_DEFAULT_SYS_PART_MSG;
+extern PCHAR JZ_ENTER_DATE_MSG;
+extern PCHAR JZ_ENTER_TIME_MSG;
+extern PCHAR JZ_ILLEGAL_TIME_MSG;
+extern PCHAR JZ_PM;
+extern PCHAR JZ_AM;
+
+//
+// Menus.
+//
+
+extern PCHAR ProblemChoices[];
+#define NUMBER_OF_PROBLEMS 3
+
+extern PCHAR YesNoChoices[];
+#define NUMBER_OF_YES_NO 2
+
+extern PCHAR MediaChoices[];
+#define NUMBER_OF_MEDIA 3
+
+extern PCHAR JzBootChoices[];
+#define NUMBER_OF_JZ_BOOT_CHOICES 7
+
+extern PCHAR ResolutionChoices[];
+#define NUMBER_OF_RESOLUTIONS 4
+
+extern PCHAR FloppyChoices[];
+#define NUMBER_OF_FLOPPIES 2
+
+extern PCHAR Weekday[];
+
+extern PCHAR JzSetupChoices[];
+#define NUMBER_OF_JZ_SETUP_CHOICES 3
+
+PCHAR ConfigurationChoices[];
+#define NUMBER_OF_CONFIGURATION_CHOICES 7
diff --git a/private/ntos/fw/mips/jzstubs.c b/private/ntos/fw/mips/jzstubs.c
new file mode 100644
index 000000000..98096bfc2
--- /dev/null
+++ b/private/ntos/fw/mips/jzstubs.c
@@ -0,0 +1,36 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ jzstubs.c
+
+Abstract:
+
+ This module contains jzsetup stubs.
+
+Author:
+
+ David M. Robinson (davidro) 11-Sept-1992
+
+Revision History:
+
+--*/
+
+
+#include "ntos.h"
+
+
+NTSTATUS
+ZwQuerySystemInformation (
+ IN SYSTEM_INFORMATION_CLASS SystemInformationClass,
+ OUT PVOID SystemInformation,
+ IN ULONG SystemInformationLength,
+ OUT PULONG ReturnLength OPTIONAL
+ )
+
+{
+ return;
+}
+
diff --git a/private/ntos/fw/mips/jztime.c b/private/ntos/fw/mips/jztime.c
new file mode 100644
index 000000000..d57296de6
--- /dev/null
+++ b/private/ntos/fw/mips/jztime.c
@@ -0,0 +1,415 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ jztime.c
+
+Abstract:
+
+ This module contains the code to set the Jazz time.
+
+Author:
+
+ David M. Robinson (davidro) 25-Oct-1991
+
+Revision History:
+
+--*/
+
+
+
+#include "jzsetup.h"
+
+//
+// Static Data
+//
+
+PVOID JzEisaControlBase;
+PVOID JzRealTimeClockBase;
+ULONG LastTime = 0;
+
+
+UCHAR
+JzReadClockRegister (
+ UCHAR Register
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the specified realtime clock register.
+
+Arguments:
+
+ Register - Supplies the number of the register whose value is read.
+
+Return Value:
+
+ The value of the register is returned as the function value.
+
+--*/
+
+{
+
+ UCHAR DataByte;
+
+ //
+ // Read the EISA NMI enable register, insert the realtime clock register
+ // number, and write the value back to the EISA NMI enable register. This
+ // selects the realtime clock register that is read.
+ //
+
+ DataByte = READ_REGISTER_UCHAR((PUCHAR)JzEisaControlBase + EISA_NMI);
+ DataByte = (DataByte & 0x80) | Register;
+ WRITE_REGISTER_UCHAR((PUCHAR)JzEisaControlBase + EISA_NMI, DataByte);
+
+ //
+ // Read the realtime clock register value.
+ //
+
+ DataByte = READ_REGISTER_UCHAR((PUCHAR)JzRealTimeClockBase);
+ return DataByte;
+}
+
+VOID
+JzWriteClockRegister (
+ UCHAR Register,
+ UCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the specified value to the specified realtime
+ clock register.
+
+Arguments:
+
+ Register - Supplies the number of the register whose value is written.
+
+ Value - Supplies the value that is written to the specified register.
+
+Return Value:
+
+ The value of the register is returned as the function value.
+
+--*/
+
+{
+ UCHAR DataByte;
+
+ //
+ // Read the EISA NMI enable register, insert the realtime clock register
+ // number, and write the value back to the EISA NMI enable register. This
+ // selects the realtime clock register that is written.
+ //
+
+ DataByte = READ_REGISTER_UCHAR((PUCHAR)JzEisaControlBase + EISA_NMI);
+ DataByte = (DataByte & 0x80) | Register;
+ WRITE_REGISTER_UCHAR((PUCHAR)JzEisaControlBase + EISA_NMI, DataByte);
+
+ //
+ // Write the realtime clock register value.
+ //
+
+ WRITE_REGISTER_UCHAR((PUCHAR)JzRealTimeClockBase, Value);
+ return;
+}
+
+VOID
+JzWriteTime (
+ IN PTIME_FIELDS TimeFields
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the realtime clock.
+
+ N.B. This routine assumes that the caller has provided any required
+ synchronization to set the realtime clock information.
+
+Arguments:
+
+ TimeFields - Supplies a pointer to a time structure that specifies the
+ realtime clock information.
+
+Return Value:
+
+ If the power to the realtime clock has not failed, then the time
+ values are written to the realtime clock and a value of TRUE is
+ returned. Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+
+ UCHAR DataByte;
+
+ //
+ // If the realtime clock battery is still functioning, then write
+ // the realtime clock values, and return a function value of TRUE.
+ // Otherwise, return a function value of FALSE.
+ //
+
+ DataByte = JzReadClockRegister(RTC_CONTROL_REGISTERD);
+ if (((PRTC_CONTROL_REGISTER_D)(&DataByte))->ValidTime == 1) {
+
+ //
+ // Set the realtime clock control to set the time.
+ //
+
+ DataByte = 0;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->HoursFormat = 1;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->DataMode = 1;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SetTime = 1;
+ JzWriteClockRegister(RTC_CONTROL_REGISTERB, DataByte);
+
+ //
+ // Write the realtime clock values.
+ //
+
+ JzWriteClockRegister(RTC_YEAR, (UCHAR)(TimeFields->Year - 1980));
+ JzWriteClockRegister(RTC_MONTH, (UCHAR)TimeFields->Month);
+ JzWriteClockRegister(RTC_DAY_OF_MONTH, (UCHAR)TimeFields->Day);
+ JzWriteClockRegister(RTC_DAY_OF_WEEK, (UCHAR)(TimeFields->Weekday + 1));
+ JzWriteClockRegister(RTC_HOUR, (UCHAR)TimeFields->Hour);
+ JzWriteClockRegister(RTC_MINUTE, (UCHAR)TimeFields->Minute);
+ JzWriteClockRegister(RTC_SECOND, (UCHAR)TimeFields->Second);
+
+ //
+ // Set the realtime clock control to update the time.
+ //
+
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SetTime = 0;
+ JzWriteClockRegister(RTC_CONTROL_REGISTERB, DataByte);
+ return;
+
+ } else {
+ return;
+ }
+}
+
+
+VOID
+JzSetTime (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+
+ UCHAR Character;
+ ULONG Count;
+ PTIME_FIELDS TimeFields;
+ TIME Time;
+ CHAR TimeString[80];
+ CHAR DateString[80];
+ PCHAR StartToken;
+ PCHAR EndToken;
+ GETSTRING_ACTION Action;
+
+ //
+ // Set addresses for RTC access.
+ //
+
+ JzEisaControlBase = (PVOID)EISA_IO_VIRTUAL_BASE;
+ JzRealTimeClockBase = (PVOID)RTC_VIRTUAL_BASE;
+
+ JzSetPosition( 3, 5);
+ JzPrint(JZ_ENTER_DATE_MSG);
+ do {
+ Action = FwGetString( DateString,
+ sizeof(DateString),
+ NULL,
+ 3,
+ 5 + strlen(JZ_ENTER_DATE_MSG));
+ if (Action == GetStringEscape) {
+ return;
+ }
+ } while ( Action != GetStringSuccess );
+
+ JzSetPosition( 4, 5);
+ JzPrint(JZ_ENTER_TIME_MSG);
+ do {
+ Action = FwGetString( TimeString,
+ sizeof(TimeString),
+ NULL,
+ 4,
+ 5 + strlen(JZ_ENTER_TIME_MSG));
+ if (Action == GetStringEscape) {
+ return;
+ }
+ } while ( Action != GetStringSuccess );
+
+ //
+ // Get time
+ //
+
+ TimeFields = ArcGetTime();
+
+ StartToken = DateString;
+ if (*StartToken != 0) {
+ EndToken = strchr(StartToken, '-');
+ if (EndToken != NULL) {
+ *EndToken = 0;
+ TimeFields->Month = atoi(StartToken);
+ StartToken = EndToken + 1;
+ }
+
+ EndToken = strchr(StartToken, '-');
+ if (EndToken != NULL) {
+ *EndToken = 0;
+ TimeFields->Day = atoi(StartToken);
+ StartToken = EndToken + 1;
+ TimeFields->Year = atoi(StartToken);
+ if (TimeFields->Year < 100) {
+ if (TimeFields->Year < 80) {
+ TimeFields->Year += 2000;
+ } else {
+ TimeFields->Year += 1900;
+ }
+ }
+ }
+ }
+
+ StartToken = TimeString;
+ if (*StartToken != 0) {
+ EndToken = strchr(StartToken, ':');
+
+ if (EndToken != NULL) {
+ *EndToken = 0;
+ TimeFields->Hour = atoi(StartToken);
+ StartToken = EndToken + 1;
+ }
+
+ EndToken = strchr(StartToken, ':');
+ if (EndToken != NULL) {
+ *EndToken = 0;
+ TimeFields->Minute = atoi(StartToken);
+ StartToken = EndToken + 1;
+ TimeFields->Second = atoi(StartToken);
+ } else {
+ TimeFields->Minute = atoi(StartToken);
+ TimeFields->Second = 0;
+ }
+
+ }
+
+ if (!RtlTimeFieldsToTime(TimeFields, &Time)) {
+ JzSetPosition( 5, 5);
+ JzPrint(JZ_ILLEGAL_TIME_MSG);
+ JzPrint(JZ_PRESS_KEY2_MSG);
+ ArcRead(ARC_CONSOLE_INPUT, &Character, 1, &Count);
+ } else {
+ RtlTimeToTimeFields( &Time, TimeFields);
+ JzWriteTime(TimeFields);
+ }
+
+}
+
+VOID
+JzShowTime (
+ BOOLEAN First
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ First - If TRUE then don't check LastTime.
+
+Return Value:
+
+--*/
+
+{
+
+ PTIME_FIELDS TimeFields;
+ TIME Time;
+ BOOLEAN Pm;
+ ULONG ThisTime;
+
+ //
+ // Set addresses for RTC access.
+ //
+
+ JzEisaControlBase = (PVOID)EISA_IO_VIRTUAL_BASE;
+ JzRealTimeClockBase = (PVOID)RTC_VIRTUAL_BASE;
+
+ //
+ // See if the time has changed since last time we were called. This is
+ // for when the display is over the serial port, so we don't blast
+ // characters out all the time.
+ //
+
+ ThisTime = ArcGetRelativeTime();
+ if (!First && (ThisTime == LastTime)) {
+
+ //
+ // Stall to get rid of the "whistle" on Jazz.
+ //
+
+ JzStallExecution(1000);
+ return;
+ }
+ LastTime = ThisTime;
+
+ //
+ // Get and display time.
+ //
+
+ TimeFields = ArcGetTime();
+
+ JzSetPosition( 0, 44);
+ JzPrint("%s, ", Weekday[TimeFields->Weekday]);
+ JzPrint("%d-", TimeFields->Month);
+ JzPrint("%d-", TimeFields->Day);
+ JzPrint("%d ", TimeFields->Year);
+
+ if (TimeFields->Hour >= 12) {
+ Pm = TRUE;
+ } else {
+ Pm = FALSE;
+ }
+
+ if (TimeFields->Hour > 12) {
+ TimeFields->Hour -= 12;
+ } else if (TimeFields->Hour == 0) {
+ TimeFields->Hour = 12;
+ }
+
+ JzPrint("%d:", TimeFields->Hour);
+ JzPrint("%02d:", TimeFields->Minute);
+ JzPrint("%02d ", TimeFields->Second);
+ if (Pm) {
+ JzPrint(JZ_PM);
+ } else {
+ JzPrint(JZ_AM);
+ }
+
+ //
+ // Clear anything to the end of the line.
+ //
+
+ JzPrint("%cK", ASCII_CSI);
+
+ return;
+
+}
diff --git a/private/ntos/fw/mips/jzusa.c b/private/ntos/fw/mips/jzusa.c
new file mode 100644
index 000000000..5853a8260
--- /dev/null
+++ b/private/ntos/fw/mips/jzusa.c
@@ -0,0 +1,173 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ jzusa.c
+
+Abstract:
+
+ This module contains the jz english strings.
+
+Author:
+
+ David M. Robinson (davidro) 21-May-1993
+
+
+Revision History:
+
+
+--*/
+
+#include "ntos.h"
+
+//
+// Common strings.
+//
+
+PCHAR JZ_CRLF_MSG = "\r\n";
+
+//
+// Prompt strings.
+//
+
+PCHAR JZ_COUNTDOWN_MSG = " Enter Countdown value (in seconds): ";
+PCHAR JZ_OSLOADER_MSG = " Enter the osloader directory and name: ";
+PCHAR JZ_OS_MSG = " Is the operating system in the same partition as the osloader: ";
+PCHAR JZ_OS_ROOT_MSG = " Enter the operating system root directory: ";
+PCHAR JZ_BOOT_NAME_MSG = " Enter a name for this boot selection: ";
+PCHAR JZ_INIT_DEBUG_MSG = " Do you want to initialize the debugger at boot time: ";
+PCHAR JZ_CANT_SET_VARIABLE_MSG = " Can't set an environment variable, ";
+PCHAR JZ_NO_SELECTIONS_TO_DELETE_MSG = " No selections to delete, ";
+PCHAR JZ_SELECTION_TO_DELETE_MSG = " Selection to delete: ";
+PCHAR JZ_ENVIR_FOR_BOOT_MSG = "\r\n Environment variables for boot selection %d:\r\n";
+PCHAR JZ_FORMAT1_MSG = " %s\r\n";
+PCHAR JZ_USE_ARROWS_MSG = " Use Arrow keys to select a variable, ESC to exit: ";
+PCHAR JZ_NO_SELECTIONS_TO_EDIT_MSG = " No selections to edit, ";
+PCHAR JZ_SELECTION_TO_EDIT_MSG = " Selection to edit: ";
+PCHAR JZ_NO_SELECTIONS_TO_REARRANGE_MSG = " No selections to rearrange, ";
+PCHAR JZ_PICK_SELECTION_MSG = " Pick selection to move to the top, ESC to exit: ";
+PCHAR JZ_SHOULD_AUTOBOOT_MSG = " Should the system autoboot: ";
+PCHAR JZ_ENVIRONMENT_VARS_MSG = "\r\n Environment variables:\r\n";
+PCHAR JZ_CHECKING_BOOT_SEL_MSG = " Checking boot selection %d...";
+PCHAR JZ_VARIABLE_NULL_MSG = " %s variable is NULL\r\n";
+PCHAR JZ_CANT_BE_FOUND_MSG = " %s cannot be found, value is:\r\n";
+PCHAR JZ_PROBLEMS_FOUND_MSG = " Problems were found with boot selection %d. Choose an action:";
+PCHAR JZ_PRESS_KEY_MSG = " Press any key to continue...\r\n";
+PCHAR JZ_PRESS_KEY2_MSG = ", press any key to continue";
+PCHAR JZ_NAME_MSG = "Name: ";
+PCHAR JZ_VALUE_MSG = "Value: ";
+PCHAR JZ_NO_NVRAM_SPACE_MSG = "Error: No space in the NVRAM for this variable";
+PCHAR JZ_NVRAM_CHKSUM_MSG = "Error: The NVRAM checksum is invalid";
+PCHAR JZ_CURRENT_ENET_MSG = "The current Ethernet station address is: ";
+PCHAR JZ_NEW_ENET_MSG = "Enter the new station address: ";
+PCHAR JZ_WRITTEN_ENET_MSG = "The value written to NVRAM is: ";
+PCHAR JZ_FOUND_NET_MSG = "Found Network Component...";
+PCHAR JZ_FIXED_MSG = "Fixed\r\n";
+PCHAR JZ_NOT_FIXED_MSG = "Not Fixed\r\n";
+PCHAR JZ_INVALID_ENET_MSG = "Invalid station address entered.";
+PCHAR JZ_SELECT_MEDIA_MSG = " Select media: ";
+PCHAR JZ_ENTER_FAT_PART_MSG = " Enter partition (must be FAT) : ";
+PCHAR JZ_ENTER_PART_MSG = " Enter partition : ";
+PCHAR JZ_SELECT_SYS_PART_MSG = " Select a system partition for this boot selection:";
+#ifdef DUO
+PCHAR JZ_SCSI_HD_MSG = "Scsi Bus %1d Hard Disk %1d Partition %1d";
+PCHAR JZ_SCSI_FL_MSG = "Scsi Bus %1d Floppy Disk %1d";
+PCHAR JZ_SCSI_CD_MSG = "Scsi Bus %1d CD-ROM %1d";
+#else
+PCHAR JZ_SCSI_HD_MSG = "Scsi Hard Disk %1d Partition %1d";
+PCHAR JZ_SCSI_FL_MSG = "Scsi Floppy Disk %1d";
+PCHAR JZ_SCSI_CD_MSG = "Scsi CD-ROM %1d";
+#endif // DUO
+PCHAR JZ_NEW_SYS_PART_MSG = "New system partition";
+PCHAR JZ_LOCATE_SYS_PART_MSG = " Enter location of system partition for this boot selection: ";
+PCHAR JZ_ENTER_SCSI_BUS_MSG = " Enter SCSI Bus: ";
+PCHAR JZ_ENTER_SCSI_ID_MSG = " Enter SCSI ID: ";
+PCHAR JZ_LOCATE_OS_PART_MSG = " Enter location of os partition: ";
+PCHAR JZ_MONITOR_RES_MSG = " Select monitor resolution: ";
+PCHAR JZ_FLOPPY_SIZE_MSG = " Select floppy size: ";
+PCHAR JZ_2ND_FLOPPY_MSG = " Is there a second floppy: ";
+PCHAR JZ_SCSI_HOST_MSG = " Enter SCSI Host ID (6 - 7): ";
+PCHAR JZ_CLEAR_CONFIG_MSG = " \r\n Clearing configuration information.\r\n";
+PCHAR JZ_ADD_CONFIG_MSG = " Adding configuration components.\r\n";
+PCHAR JZ_ADD_ENVIR_MSG = " Adding environment variables.\r\n";
+PCHAR JZ_SAVE_CONFIG_MSG = " Saving the configuration.\r\n";
+PCHAR JZ_DONE_CONFIG_MSG = " Done, the system will reset upon program exit.\r\n";
+PCHAR JZ_DEFAULT_SYS_PART_MSG = " Enter location of default system partition: ";
+PCHAR JZ_ENTER_DATE_MSG = "Enter the new date (mm-dd-yy) : ";
+PCHAR JZ_ENTER_TIME_MSG = "Enter time (hh:mm:ss) : ";
+PCHAR JZ_ILLEGAL_TIME_MSG = "Illegal time value";
+PCHAR JZ_PM = "PM";
+PCHAR JZ_AM = "AM";
+
+//
+// Menus.
+//
+
+PCHAR ProblemChoices[] = {
+ "Ignore problems with this boot selection",
+ "Delete this boot selection",
+ "Change this boot selection"
+};
+
+PCHAR YesNoChoices[] = {
+ "Yes",
+ "No"
+};
+
+PCHAR MediaChoices[] = {
+ "Scsi Hard Disk",
+ "Scsi Floppy Disk",
+ "CD-ROM"
+};
+
+PCHAR JzBootChoices[] = {
+ "Add a boot selection",
+ "Delete a boot selection",
+ "Change a boot selection",
+ "Rearrange boot selections",
+ "Check boot selections",
+ "Setup autoboot",
+ "Return to main menu"
+};
+
+PCHAR ResolutionChoices[] = {
+ "1280x1024",
+ "1024x768",
+ "800x600",
+ "640x480"
+};
+
+PCHAR FloppyChoices[] = {
+ "5.25",
+ "3.5 1.44 M"
+// "3.5 2.88 M"
+};
+
+PCHAR Weekday[] = {
+ "Sunday",
+ "Monday",
+ "Tuesday",
+ "Wednesday",
+ "Thursday",
+ "Friday",
+ "Saturday"
+ };
+
+PCHAR JzSetupChoices[] = {
+ "Initialize system",
+ "Manage startup",
+ "Exit"
+};
+
+PCHAR ConfigurationChoices[] = {
+ "Set default configuration",
+ "Set default environment",
+ "Set environment variables",
+ "Set time",
+ "Set ethernet address",
+ "Run debug monitor",
+ "Return to main menu"
+};
+
diff --git a/private/ntos/fw/mips/jzvxl484.c b/private/ntos/fw/mips/jzvxl484.c
new file mode 100644
index 000000000..a39f520b6
--- /dev/null
+++ b/private/ntos/fw/mips/jzvxl484.c
@@ -0,0 +1,724 @@
+#if defined(JAZZ)
+
+/*++
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ jzvxl484.c
+
+cAbstract:
+
+ This module implements the video prom code for the Jazz VXL BT484
+
+Author:
+
+ Lluis Abello (lluis) 28-May-1992
+
+Environment:
+
+ Kernel mode.
+
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#include "jzvxl484.h"
+#include "jxvideo.h"
+#include "jaginit.h"
+
+#define KeFlushWriteBuffer()
+
+ARC_STATUS
+InitializeBt484(
+ IN PVIDEO_VIRTUAL_SPACE VirtualAdr
+ );
+
+VOID
+FillVideoMemory(
+ IN ULONG StartAddress,
+ IN ULONG Size,
+ IN ULONG Pattern
+ );
+
+ULONG
+CheckVideoMemoryAddressTest(
+ IN ULONG StartAddress,
+ IN ULONG Size
+ );
+
+VOID
+WriteVideoMemoryAddressTest(
+ IN ULONG StartAddress,
+ IN ULONG Size
+ );
+
+
+//
+// Define colors, HI = High Intensity
+//
+
+#define BT484_PALETTE_BLACK_R 0x00
+#define BT484_PALETTE_BLACK_G 0x00
+#define BT484_PALETTE_BLACK_B 0x00
+
+#define BT484_PALETTE_RED_R 0xB0
+#define BT484_PALETTE_RED_G 0x00
+#define BT484_PALETTE_RED_B 0x00
+
+#define BT484_PALETTE_GREEN_R 0x00
+#define BT484_PALETTE_GREEN_B 0xB0
+#define BT484_PALETTE_GREEN_G 0x00
+
+#define BT484_PALETTE_YELLOW_R 0xB0
+#define BT484_PALETTE_YELLOW_G 0xB0
+#define BT484_PALETTE_YELLOW_B 0x00
+
+#define BT484_PALETTE_BLUE_R 0x00
+#define BT484_PALETTE_BLUE_G 0x00
+#define BT484_PALETTE_BLUE_B 0xB0
+
+#define BT484_PALETTE_MAGENTA_R 0xB0
+#define BT484_PALETTE_MAGENTA_G 0x00
+#define BT484_PALETTE_MAGENTA_B 0xB0
+
+#define BT484_PALETTE_CYAN_R 0x00
+#define BT484_PALETTE_CYAN_G 0xB0
+#define BT484_PALETTE_CYAN_B 0xB0
+
+#define BT484_PALETTE_WHITE_R 0xB0
+#define BT484_PALETTE_WHITE_G 0xB0
+#define BT484_PALETTE_WHITE_B 0xB0
+
+#define BT484_PALETTE_HI_BLACK_R 0x00
+#define BT484_PALETTE_HI_BLACK_G 0x00
+#define BT484_PALETTE_HI_BLACK_B 0x00
+
+#define BT484_PALETTE_HI_RED_R 0xFF
+#define BT484_PALETTE_HI_RED_G 0x00
+#define BT484_PALETTE_HI_RED_B 0x00
+
+#define BT484_PALETTE_HI_GREEN_R 0x00
+#define BT484_PALETTE_HI_GREEN_G 0xFF
+#define BT484_PALETTE_HI_GREEN_B 0x00
+
+#define BT484_PALETTE_HI_YELLOW_R 0xFF
+#define BT484_PALETTE_HI_YELLOW_G 0xFF
+#define BT484_PALETTE_HI_YELLOW_B 0x00
+
+#define BT484_PALETTE_HI_BLUE_R 0x00
+#define BT484_PALETTE_HI_BLUE_G 0x00
+#define BT484_PALETTE_HI_BLUE_B 0xFF
+
+#define BT484_PALETTE_HI_MAGENTA_R 0xFF
+#define BT484_PALETTE_HI_MAGENTA_G 0x00
+#define BT484_PALETTE_HI_MAGENTA_B 0xFF
+
+#define BT484_PALETTE_HI_CYAN_R 0x00
+#define BT484_PALETTE_HI_CYAN_G 0xFF
+#define BT484_PALETTE_HI_CYAN_B 0xFF
+
+#define BT484_PALETTE_HI_WHITE_R 0xFF
+#define BT484_PALETTE_HI_WHITE_G 0xFF
+#define BT484_PALETTE_HI_WHITE_B 0xFF
+
+
+UCHAR ColorTable[16*3]={
+ BT484_PALETTE_BLACK_R,
+ BT484_PALETTE_BLACK_G,
+ BT484_PALETTE_BLACK_B,
+ BT484_PALETTE_RED_R,
+ BT484_PALETTE_RED_G,
+ BT484_PALETTE_RED_B,
+ BT484_PALETTE_GREEN_R,
+ BT484_PALETTE_GREEN_B,
+ BT484_PALETTE_GREEN_G,
+ BT484_PALETTE_YELLOW_R,
+ BT484_PALETTE_YELLOW_G,
+ BT484_PALETTE_YELLOW_B,
+ BT484_PALETTE_BLUE_R,
+ BT484_PALETTE_BLUE_G,
+ BT484_PALETTE_BLUE_B,
+ BT484_PALETTE_MAGENTA_R,
+ BT484_PALETTE_MAGENTA_G,
+ BT484_PALETTE_MAGENTA_B,
+ BT484_PALETTE_CYAN_R,
+ BT484_PALETTE_CYAN_G,
+ BT484_PALETTE_CYAN_B,
+ BT484_PALETTE_WHITE_R,
+ BT484_PALETTE_WHITE_G,
+ BT484_PALETTE_WHITE_B,
+ BT484_PALETTE_HI_BLACK_R,
+ BT484_PALETTE_HI_BLACK_G,
+ BT484_PALETTE_HI_BLACK_B,
+ BT484_PALETTE_HI_RED_R,
+ BT484_PALETTE_HI_RED_G,
+ BT484_PALETTE_HI_RED_B,
+ BT484_PALETTE_HI_GREEN_R,
+ BT484_PALETTE_HI_GREEN_G,
+ BT484_PALETTE_HI_GREEN_B,
+ BT484_PALETTE_HI_YELLOW_R,
+ BT484_PALETTE_HI_YELLOW_G,
+ BT484_PALETTE_HI_YELLOW_B,
+ BT484_PALETTE_HI_BLUE_R,
+ BT484_PALETTE_HI_BLUE_G,
+ BT484_PALETTE_HI_BLUE_B,
+ BT484_PALETTE_HI_MAGENTA_R,
+ BT484_PALETTE_HI_MAGENTA_G,
+ BT484_PALETTE_HI_MAGENTA_B,
+ BT484_PALETTE_HI_CYAN_R,
+ BT484_PALETTE_HI_CYAN_G,
+ BT484_PALETTE_HI_CYAN_B,
+ BT484_PALETTE_HI_WHITE_R,
+ BT484_PALETTE_HI_WHITE_G,
+ BT484_PALETTE_HI_WHITE_B
+ };
+
+//
+// Define colors, HI = High Intensity
+//
+
+#define FW_COLOR_BLACK 0x00
+#define FW_COLOR_RED 0x01
+#define FW_COLOR_GREEN 0x02
+#define FW_COLOR_YELLOW 0x03
+#define FW_COLOR_BLUE 0x04
+#define FW_COLOR_MAGENTA 0x05
+#define FW_COLOR_CYAN 0x06
+#define FW_COLOR_WHITE 0x07
+#define FW_COLOR_HI_BLACK 0x08
+#define FW_COLOR_HI_RED 0x09
+#define FW_COLOR_HI_GREEN 0x0A
+#define FW_COLOR_HI_YELLOW 0x0B
+#define FW_COLOR_HI_BLUE 0x0C
+#define FW_COLOR_HI_MAGENTA 0x0D
+#define FW_COLOR_HI_CYAN 0x0E
+#define FW_COLOR_HI_WHITE 0x0F
+
+
+ARC_STATUS
+InitializeVXL (
+ IN PVIDEO_VIRTUAL_SPACE VirtualAdr,
+ IN PMONITOR_CONFIGURATION_DATA Monitor
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the JazzVxl Graphics accelerator.
+
+Arguments:
+
+ Monitor - Monitor configuration data.
+ VirtualAdr - Pointer to a pair of virtual addresses for video&Control spaces.
+
+Return Value:
+
+ If the video was initialized, ESUCCESS is returned, otherwise an error
+ code is returned.
+
+--*/
+
+{
+ ULONG Index;
+ PJAGUAR_REGISTERS Jaguar = (PJAGUAR_REGISTERS)(VirtualAdr->ControlVirtualBase + VXL_JAGUAR_BASE_OFFSET);
+ PBT484_REGISTERS Bt484 = (PBT484_REGISTERS)(VirtualAdr->ControlVirtualBase + VXL_BT484_BASE_OFFSET);
+ PUCHAR Clock = (PUCHAR)(VirtualAdr->ControlVirtualBase + VXL_CLOCK_BASE_OFFSET);
+ UCHAR DataChar;
+ UCHAR CmdReg0;
+ ULONG VideoMemory = VirtualAdr->MemoryVirtualBase;
+ JAGUAR_REG_INIT JagInitData;
+ ULONG Status;
+
+
+
+ //
+ // Define clock value for the ICS part (pS)
+ //
+
+ ULONG ClockResList[32] = { 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4,42918,40984,38760,36724,33523,31017,
+ 29197,27548,24882,23491,22482,21468,20509,19920,
+ 18692,18054,16722,15015,14773,14053,13040, 4};
+
+ //
+ // Define a default jaguar init and monitor config for
+ // use when a BOGUS init value is sent.
+ //
+
+ JAGUAR_REG_INIT JagDefaultData = {
+ 0xc, // Clock Selector
+ 0, // Bt485 clock 2x multiply
+ 1, // BitBlt Control
+ 0, // TopOfScreen
+ 41, // Horizontal Blank
+ 4, // Horizontal Begin Sync
+ 29, // Horizontal End Sync
+ 201, // Horizontal Total
+ 45, // Vertical Blank
+ 11, // Vertical Begin Sync
+ 13, // Vertical End Sync
+ 525, // Vertical Total
+ 0x200, // XFER LENGTH
+ 4, // Vertival Interrupt Line
+ 640 // Screen X
+ };
+
+
+ MONITOR_CONFIGURATION_DATA DefaultMonitor = {
+ 0, // version :do not change
+ 0, // revision :do not change
+ 640, // HorizontalResolution
+ 25422, // HorizontalDisplayTime
+ 636, // HorizontalBackPorch
+ 1907, // HorizontalFrontPorch
+ 3813, // HorizontalSync
+ 480, // VerticalResolution
+ 33, // VerticalBackPorch
+ 10, // VerticalFrontPorch
+ 2, // VerticalSync
+ 0, // HorizontalScreenSize : do not change
+ 0 // VerticalScreenSize : do not change
+ };
+
+
+ LONG HorDisplayTime;
+ LONG HorResolutionDiv;
+ LONG ReqClockPeriod;
+ LONG CurrentClockError;
+ LONG MinErrorValue;
+ USHORT MinErrorIndex;
+ LONG ShiftClockPeriod;
+
+ USHORT BoardTypeBt485;
+
+
+ //
+ // Test the first bank of video memory
+ //
+
+ WriteVideoMemoryAddressTest(VideoMemory,
+ 0x200000
+ );
+
+ Status = CheckVideoMemoryAddressTest(VideoMemory,
+ 0x200000
+ );
+
+ if (Status != 0) {
+ return EINVAL;
+ }
+
+ //
+ // Determine if this is a Bt484 or Bt485 board. To do this write a 1 to command
+ // register bit 07 then write 01 to the address register 0. This will enable
+ // read/writes to command register 3 on a Bt485 but not on a Bt484. Clear
+ // Command register 3 then read it back. On a Bt485 the return value will be 0x00,
+ // on a Bt484 it will be 0x40.
+ //
+
+
+ //
+ // Get the value in command register 0, then set bit 07
+ //
+
+ DataChar = READ_REGISTER_UCHAR(&Bt484->Command0.Byte);
+ DataChar |= 0x80;
+ WRITE_REGISTER_UCHAR(&Bt484->Command0.Byte,DataChar);
+
+ //
+ // Write 0x01 to the address register
+ //
+
+ WRITE_REGISTER_UCHAR(&Bt484->PaletteCursorWrAddress.Byte,0x01);
+
+ //
+ // Clear command register 3
+ //
+
+ WRITE_REGISTER_UCHAR(&Bt484->Status.Byte,0x00);
+
+ //
+ // Read Command Register 3 back and compare
+ //
+
+ DataChar = READ_REGISTER_UCHAR(&Bt484->Status.Byte);
+
+ if (DataChar != 0x00) {
+
+ //
+ // This is a Bt484
+ //
+
+ BoardTypeBt485 = 0;
+ JagInitData.Bt485Multiply = 0;
+
+ } else {
+
+ //
+ // This is a Bt485
+ //
+
+ BoardTypeBt485 = 1;
+ JagInitData.Bt485Multiply = 0;
+ }
+
+ //
+ // Calculate the requested clock frequency then find the closest match in the
+ // ICS clock frequency table. The requested clock frequency in picoseconds =
+ //
+ // Horizontal display time * 1000
+ // ------------------------------
+ // horizontal resolution
+ //
+ //
+
+ HorDisplayTime = Monitor->HorizontalDisplayTime * 1000;
+ HorResolutionDiv = Monitor->HorizontalResolution;
+
+ ReqClockPeriod = HorDisplayTime / HorResolutionDiv;
+
+ //
+ // Check for a configuration needing a Bt485 and a board that is a 484. In
+ // This case we will have to resort to a default 640 x 480 config
+ //
+
+ if ((BoardTypeBt485 == 0) & (ReqClockPeriod < ClockResList[30])) {
+
+ //
+ // We were told to display a mode that we don't support, set
+ // the output to the default mode and also return the monitor
+ // info to a default mode which will later be stored into
+ // NVRAM so that the HAL will init ok and also the next ROM init
+ // will be correct.
+ //
+
+ JagInitData = JagDefaultData;
+
+ Monitor->HorizontalResolution = DefaultMonitor.HorizontalResolution;
+ Monitor->HorizontalDisplayTime = DefaultMonitor.HorizontalDisplayTime;
+ Monitor->HorizontalBackPorch = DefaultMonitor.HorizontalBackPorch;
+ Monitor->HorizontalFrontPorch = DefaultMonitor.HorizontalFrontPorch;
+ Monitor->HorizontalSync = DefaultMonitor.HorizontalSync;
+ Monitor->VerticalResolution = DefaultMonitor.VerticalResolution;
+ Monitor->VerticalBackPorch = DefaultMonitor.VerticalBackPorch;
+ Monitor->VerticalFrontPorch = DefaultMonitor.VerticalFrontPorch;
+ Monitor->VerticalSync = DefaultMonitor.VerticalSync;
+
+ } else {
+
+ //
+ // Check for a Bt485 frequency
+ //
+
+ if ((BoardTypeBt485 == 1) & (ReqClockPeriod < ClockResList[30])) {
+ ReqClockPeriod = ReqClockPeriod * 2;
+ JagInitData.Bt485Multiply = 1;
+ }
+
+
+
+ MinErrorIndex = 0;
+
+ //
+ // Gaurentee a maximum starting error
+ //
+
+ MinErrorValue = ReqClockPeriod + 1;
+
+ for (Index=0;Index<32;Index++) {
+
+ //
+ // Calculate the absolute value of clock error and find the
+ // closest match in the array of clock values
+ //
+
+ CurrentClockError = ReqClockPeriod - ClockResList[Index];
+ if (CurrentClockError < 0) {
+ CurrentClockError *= -1;
+ }
+
+ if (CurrentClockError < MinErrorValue) {
+ MinErrorValue = CurrentClockError;
+ MinErrorIndex = Index;
+ }
+ }
+
+ //
+ // We now have a closest match in the clock array, now calculate the
+ // values for the Bt484/Bt485 register values
+ //
+
+ JagInitData.ClockFreq = MinErrorIndex;
+ JagInitData.BitBltControl = 1;
+ JagInitData.TopOfScreen = 0;
+ JagInitData.XferLength = 0x200;
+ JagInitData.VerticalInterruptLine = 4;
+ JagInitData.HorizontalDisplay = Monitor->HorizontalResolution;
+
+
+ //
+ // All jaguar timing values are based on the brooktree shift clock value which
+ // is the clock frequency divided by 4. (period * 4) If this is a Bt485 using
+ // its internal 2x clock multiplier than is is period * 2; (freq * 2 / 4)
+ //
+
+
+ if (JagInitData.Bt485Multiply == 1) {
+ ShiftClockPeriod = ClockResList[MinErrorIndex] * 2;
+ } else {
+ ShiftClockPeriod = ClockResList[MinErrorIndex] * 4;
+ }
+
+
+ JagInitData.HorizontalBlank = ((Monitor->HorizontalBackPorch +
+ Monitor->HorizontalSync +
+ Monitor->HorizontalFrontPorch) * 1000)
+ / ShiftClockPeriod;
+
+ JagInitData.HorizontalBeginSync = (Monitor->HorizontalFrontPorch * 1000)
+ / ShiftClockPeriod;
+
+ JagInitData.HorizontalEndSync = ((Monitor->HorizontalSync +
+ Monitor->HorizontalFrontPorch) * 1000)
+ / ShiftClockPeriod;
+
+ JagInitData.HorizontalLine = JagInitData.HorizontalBlank +
+ (Monitor->HorizontalResolution / 4);
+
+
+ JagInitData.VerticalBlank = Monitor->VerticalBackPorch +
+ Monitor->VerticalSync +
+ Monitor->VerticalFrontPorch;
+
+
+ JagInitData.VerticalBeginSync = Monitor->VerticalFrontPorch;
+
+ JagInitData.VerticalEndSync = Monitor->VerticalFrontPorch +
+ Monitor->VerticalSync;
+
+ JagInitData.VerticalLine = Monitor->VerticalBackPorch +
+ Monitor->VerticalSync +
+ Monitor->VerticalFrontPorch +
+ Monitor->VerticalResolution;
+
+ }
+
+ //
+ // Start ICS Clock pll and stabilize.
+ //
+
+ WRITE_REGISTER_UCHAR(Clock,JagInitData.ClockFreq);
+
+ //
+ // Wait 10 uS for PLL clock to stabilize on the video board
+ //
+ for (Index=0;Index<10;Index++) {
+ READ_REGISTER_UCHAR(Clock);
+ }
+
+ //
+ // Initialize Bt484 Command Register 0 to:
+ //
+ // 8 Bit DAC Resolution
+ //
+
+ CmdReg0 = 0;
+ ((PBT484_COMMAND0)(&CmdReg0))->DacResolution = 1;
+ ((PBT484_COMMAND0)(&CmdReg0))->GreenSyncEnable = 1;
+ ((PBT484_COMMAND0)(&CmdReg0))->SetupEnable = 1;
+ WRITE_REGISTER_UCHAR(&Bt484->Command0.Byte,CmdReg0);
+
+ //
+ // Initialize Command Register 1 to:
+ //
+
+ DataChar = 0;
+
+ ((PBT484_COMMAND1)(&DataChar))->BitsPerPixel = VXL_EIGHT_BITS_PER_PIXEL;
+
+
+ WRITE_REGISTER_UCHAR(&Bt484->Command1.Byte,DataChar);
+
+ //
+ // Initialize Command Register 2 to:
+ //
+ // SCLK Enabled
+ // TestMode disabled
+ // PortselMask Non Masked
+ // PCLK 1
+ // NonInterlaced
+ //
+
+ DataChar = 0;
+ ((PBT484_COMMAND2)(&DataChar))->SclkDisable = 0;
+ ((PBT484_COMMAND2)(&DataChar))->TestEnable = 0;
+ ((PBT484_COMMAND2)(&DataChar))->PortselMask = 1;
+ ((PBT484_COMMAND2)(&DataChar))->PclkSelect = 1;
+ ((PBT484_COMMAND2)(&DataChar))->InterlacedDisplay = 0;
+ ((PBT484_COMMAND2)(&DataChar))->PaletteIndexing = CONTIGUOUS_PALETTE;
+ ((PBT484_COMMAND2)(&DataChar))->CursorMode = BT_CURSOR_WINDOWS;
+
+
+ WRITE_REGISTER_UCHAR(&Bt484->Command2.Byte,DataChar);
+
+ //
+ // if JagInitData.ClockFreq bit 8 is set then this is a Bt485 mode that requires
+ // the internal 2x clock multiplier to be enabled.
+ //
+
+ if (JagInitData.Bt485Multiply == 1) {
+
+ //
+ // To access cmd register 3, first set bit CR17 in command register 0
+ //
+
+ CmdReg0 |= 0x80;
+ WRITE_REGISTER_UCHAR(&Bt484->Command0.Byte,CmdReg0);
+
+ //
+ // Write a 0x01 to Address register
+ //
+
+ WRITE_REGISTER_UCHAR(&Bt484->PaletteCursorWrAddress.Byte,0x01);
+
+ //
+ // Write to cmd register 3 in the status register location. Cmd3 is initialized
+ // to turn on the 2x clock multiplier.
+ //
+
+ DataChar = 0;
+ ((PBT484_COMMAND3)(&DataChar))->ClockMultiplier = 1;
+
+ WRITE_REGISTER_UCHAR(&Bt484->Status.Byte,DataChar);
+
+ //
+ // Allow 10 uS for the 2x multiplier to stabilize
+ //
+
+ for (Index=0;Index<10;Index++) {
+ READ_REGISTER_UCHAR(Clock);
+ }
+ }
+
+
+
+
+ //
+ // Initialize Color Palette.
+ //
+ // Set address pointer to base of color palette.
+ // Initialize first 16 entries from color table.
+ // Zero remaining entries.
+ //
+
+ WRITE_REGISTER_UCHAR(&Bt484->PaletteCursorWrAddress.Byte,0);
+
+ for (Index=0;Index<16*3;Index++) {
+ WRITE_REGISTER_UCHAR(&Bt484->PaletteColor.Byte,ColorTable[Index]);
+ }
+
+ for (;Index<256*3;Index++) {
+ WRITE_REGISTER_UCHAR(&Bt484->PaletteColor.Byte,0);
+ }
+
+ //
+ // Initialize Cursor and Overscan color.
+ //
+ // Set address pointer base.
+ // Zero 4 entries.
+ //
+
+ WRITE_REGISTER_UCHAR(&Bt484->CursorColorWrAddress.Byte,0);
+
+ for (Index=0;Index<4*3;Index++) {
+ WRITE_REGISTER_UCHAR(&Bt484->CursorColor.Byte,0);
+ }
+
+ //
+ // Initialize cursor RAM
+ //
+ // Set address pointer to base of ram.
+ // Clear both planes
+ //
+
+ WRITE_REGISTER_UCHAR(&Bt484->PaletteCursorWrAddress.Byte,0);
+
+ for (Index=0;Index<256;Index++) {
+ WRITE_REGISTER_UCHAR(&Bt484->CursorRam.Byte,0);
+ }
+
+
+ //
+ // Initialize cursor position registers--cursor off.
+ //
+
+ WRITE_REGISTER_UCHAR(&Bt484->CursorXLow.Byte,0);
+ WRITE_REGISTER_UCHAR(&Bt484->CursorXHigh.Byte,0);
+ WRITE_REGISTER_UCHAR(&Bt484->CursorYLow.Byte,0);
+ WRITE_REGISTER_UCHAR(&Bt484->CursorYHigh.Byte,0);
+
+ //
+ // Initialize pixel mask.
+ //
+
+ WRITE_REGISTER_UCHAR(&Bt484->PixelMask.Byte,0xFF);
+
+ //
+ // Init Jaguar Registers
+ //
+
+ WRITE_REGISTER_USHORT(&Jaguar->TopOfScreen.Short,
+ JagInitData.TopOfScreen);
+
+ WRITE_REGISTER_USHORT(&Jaguar->HorizontalBlank.Short,
+ JagInitData.HorizontalBlank);
+
+ WRITE_REGISTER_USHORT(&Jaguar->HorizontalBeginSync.Short,
+ JagInitData.HorizontalBeginSync);
+
+ WRITE_REGISTER_USHORT(&Jaguar->HorizontalEndSync.Short,
+ JagInitData.HorizontalEndSync);
+
+ WRITE_REGISTER_USHORT(&Jaguar->HorizontalLine.Short,
+ JagInitData.HorizontalLine);
+
+ WRITE_REGISTER_USHORT(&Jaguar->VerticalBlank.Short,
+ JagInitData.VerticalBlank);
+
+ WRITE_REGISTER_USHORT(&Jaguar->VerticalBeginSync.Short,
+ JagInitData.VerticalBeginSync);
+
+ WRITE_REGISTER_USHORT(&Jaguar->VerticalEndSync.Short,
+ JagInitData.VerticalEndSync);
+
+ WRITE_REGISTER_USHORT(&Jaguar->VerticalLine.Short,
+ JagInitData.VerticalLine);
+
+ WRITE_REGISTER_USHORT(&Jaguar->XferLength.Short,
+ JagInitData.XferLength);
+
+ WRITE_REGISTER_USHORT(&Jaguar->VerticalInterruptLine.Short,
+ JagInitData.VerticalInterruptLine);
+
+ WRITE_REGISTER_USHORT(&Jaguar->HorizontalDisplay.Short,
+ JagInitData.HorizontalDisplay);
+
+ WRITE_REGISTER_UCHAR(&Jaguar->BitBltControl.Byte,
+ JagInitData.BitBltControl);
+
+ //
+ // Enable timing.
+ //
+
+ WRITE_REGISTER_UCHAR(&Jaguar->MonitorControl,MONITOR_TIMING_ENABLE);
+
+ return ESUCCESS;
+
+}
+
+#endif
diff --git a/private/ntos/fw/mips/jzvxlh.s b/private/ntos/fw/mips/jzvxlh.s
new file mode 100644
index 000000000..0fc29687e
--- /dev/null
+++ b/private/ntos/fw/mips/jzvxlh.s
@@ -0,0 +1,61 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ jzvxlh.s
+
+Abstract:
+
+ This module contains the video prom header for VXL.
+ It must be placed starting at the first rom location.
+
+Author:
+
+ Lluis Abello (lluis) 15-Jul-92
+
+Environment:
+
+
+
+Notes:
+
+ This module doesn't contain any code.
+
+
+Revision History:
+
+
+
+--*/
+//
+// include header file
+//
+#include <ksmips.h>
+
+#define VXL_ID 2
+.text
+
+.byte VXL_ID // Video Board ID
+.byte 8 // PROM_Stride
+.byte 1 // PROM_Width
+.byte 0x10 // PROM_Size = 16 4KB pages
+.ascii "Jazz"
+
+//
+// The following data corresponds to this structure.
+//
+//typedef struct _VIDEO_PROM_CONFIGURATION {
+// ULONG VideoMemorySize;
+// ULONG VideoControlSize;
+// ULONG CodeOffset;
+// ULONG CodeSize;
+// UCHAR IdentifierString[];
+//} VIDEO_PROM_CONFIGURATION; *PVIDEO_PROM_CONFIGURATION;
+
+.word 0x400000 // VideoMemorySize = 4MB
+.word 0x400000 // VideoControlSize = 4MB
+.word 0x200 // CodeOffset. Code starts at offset 200 from video prom
+.word 0x4000 // CodeSize 16K of code...
+.asciiz "VXL"
diff --git a/private/ntos/fw/mips/kbdmouse.h b/private/ntos/fw/mips/kbdmouse.h
new file mode 100644
index 000000000..b22543d77
--- /dev/null
+++ b/private/ntos/fw/mips/kbdmouse.h
@@ -0,0 +1,149 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ Kbdmouse.h
+
+Abstract:
+
+ This module contains definitions for the keyboard controller
+ in the jazz system.
+
+ It supports Mouse and Keyboard.
+
+Author:
+
+ Lluis Abello (lluis) 11-Jul-1990
+
+Environment:
+
+
+Revision History:
+
+--*/
+
+#ifndef _KBDMOUSE_
+#define _KBDMOUSE_
+//
+// Keyboard Controller Commands
+//
+#define KBD_CTR_WRITE_COMMAND 0x60
+#define KBD_CTR_READ_COMMAND 0x20
+#define KBD_CTR_TEST_PASSWORD 0xA4
+#define KBD_CTR_LOAD_PASSWORD 0xA5
+#define KBD_CTR_ENABLE_PASSWORD 0xA6
+#define KBD_CTR_DISABLE_AUX 0xA7
+#define KBD_CTR_ENABLE_AUX 0xA8
+#define KBD_CTR_AUXLINES_TEST 0xA9
+#define KBD_CTR_SELFTEST 0xAA
+#define KBD_CTR_KBDLINES_TEST 0xAB
+#define KBD_CTR_ENABLE_KBD 0xAE
+#define KBD_CTR_WRITE_AUX 0xD4
+
+//
+// Keyboard Controller Data
+//
+#define Kbd_Ctr_Selftest_Passed 0x55
+#define Kbd_Ctr_Password_Installed 0xFA
+#define Kbd_Ctr_Password_Not_Installed 0xF1
+
+//
+// Controller Command Byte bit definitions.
+//
+#define KbdCommandByteDisableAux (1 << 5)
+#define KbdCommandByteDisableKbd (1 << 4)
+#define KbdCommandEnableAuxInt (1 << 1)
+#define KbdCommandEnableKbdInt (1 << 0)
+
+//
+// Keyboard Controller Status byte masks
+//
+#define KBD_OBF_MASK 0x1 // Output buffer full
+#define KBD_IBF_MASK 0x2 // Input buffer full
+#define KBD_FROM_AUX_MASK 0x20 // Byte from Aux Port.
+
+//
+// Interface Test Results
+//
+#define INTERFACE_NO_ERROR 0x00
+#define CLOCK_STUCK_LOW 0x01
+#define CLOCK_STUCK_HIGH 0x02
+#define DATA_STUCK_LOW 0x03
+#define DATA_STUCK_HIGH 0x04
+
+//
+// Timeout
+//
+#define KBD_TIMEOUT 0xFFFFF
+#define KBD_INT_TIMEOUT 0xFFFF
+
+//
+// Keyboard Commands
+//
+#define KbdEcho 0xee // request keyboard to return echo response "EE"
+#define KbdSelScanCode 0xf0 // Scan codes 1,2,3 or 0 = rquest current.
+#define KbdReadID 0xf2 // Request for two byte response
+#define KbdSetRate 0xf3 // Set tellematic Rate
+#define KbdEnable 0xF4 // Clears Buffer and Starts Scanning.
+#define KbdDisable 0xF5 // reset to power up
+
+#define KbdSetDefault 0xf6 //
+#define KbdSetAllTlmtic 0xf7 // Set all keys telematic
+#define KbdSetAllMkBr 0xf8 // Set all keys Make /Break
+#define KbdSetAllMake 0xf9 // Set all keys Make only
+#define KbdSetKeyTlmtic 0xfb // Set individual key telemativ
+#define KbdSetKeyMkBr 0xfc // set individual key make/break
+#define KbdSetKeyMk 0xfd // set individual key make only
+#define KbdResend 0xfe // request to resend last transfer
+#define KbdReset 0xff // request to start a program reset
+#define KbdAck 0xfa // keyboard ack after reset
+#define KbdBat 0xAA // Keyboard Bat completion Response
+
+//
+// Define scan codes.
+//
+
+#define KEY_LEFT_SHIFT 0x2A
+#define KEY_RIGHT_SHIFT 0X36
+#define KEY_CAPS_LOCK 0X3A
+#define KEY_CONTROL 0X1D
+#define KEY_ALT 0X38
+#define KEY_UP_ARROW 0X48
+#define KEY_DOWN_ARROW 0X50
+#define KEY_LEFT_ARROW 0X4B
+#define KEY_RIGHT_ARROW 0X4D
+#define KEY_HOME 0X47
+#define KEY_END 0X4F
+#define KEY_INSERT 0X52
+#define KEY_DELETE 0X53
+#define KEY_SYS_REQUEST 0X54
+#define KEY_PRINT_SCREEN 0x37
+#define KEY_ESC 0x01
+#define KEY_PAGE_UP 0x49
+#define KEY_PAGE_DOWN 0x51
+#define KEY_F1 0x3B
+#define KEY_F2 0x3C
+#define KEY_F3 0x3D
+#define KEY_F4 0x3E
+#define KEY_F5 0x3F
+#define KEY_F6 0x40
+#define KEY_F7 0x41
+#define KEY_F8 0x42
+#define KEY_F9 0x43
+#define KEY_F10 0x44
+#define KEY_F11 0x57
+#define KEY_F12 0x58
+
+
+//
+// Define Keyboard controller register offsets.
+// Status (read) and Command (write) are the same register.
+//
+
+#define KbdDataReg 0x0
+#define KbdStatusReg 0x1
+#define KbdCommandReg 0x1
+
+#endif //_KBDMOUSE_
diff --git a/private/ntos/fw/mips/kbdtest.c b/private/ntos/fw/mips/kbdtest.c
new file mode 100644
index 000000000..b3672dd1e
--- /dev/null
+++ b/private/ntos/fw/mips/kbdtest.c
@@ -0,0 +1,317 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ Kbdtest.c
+
+Abstract:
+
+ This module implements the Keyboard and mouse test for the self-test.
+
+Author:
+
+ Lluis Abello (lluis) 10-Feb-1991
+
+Environment:
+
+ Rom self-test.
+
+Revision History:
+
+--*/
+#include <ntos.h>
+#include "iodevice.h"
+#include "kbdmouse.h"
+#include "ioaccess.h"
+
+volatile ULONG TimerTicks;
+
+
+VOID
+ClearKbdFifo(
+ )
+/*++
+
+Routine Description:
+
+ This routine empties the Keyboard controller Fifo.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UCHAR Trash, Stat;
+ volatile Timeout;
+
+ //
+ // wait until the previous command is processed.
+ //
+
+ while ((READ_REGISTER_UCHAR(&KEYBOARD_READ->Status) & KBD_IBF_MASK) != 0) {
+ }
+ while ((READ_REGISTER_UCHAR(&KEYBOARD_READ->Status) & KBD_OBF_MASK) != 0) {
+ Trash= READ_REGISTER_UCHAR(&KEYBOARD_READ->Data);
+ for (Timeout=0;Timeout<10000;Timeout++) {
+ }
+ }
+}
+
+BOOLEAN
+GetKbdData(
+ PUCHAR C,
+ ULONG msec
+ )
+/*++
+
+Routine Description:
+
+ This routine polls the Status Register until Data is available or timeout,
+ then it reads and returns the Data.
+
+Arguments:
+
+ C - pointer to a byte where to write the read value
+ msec - time-out time in milliseconds
+
+Return Value:
+
+ TRUE if timeout, FALSE if OK;
+
+--*/
+{
+ TimerTicks=msec;
+ while (TimerTicks) {
+ if (READ_REGISTER_UCHAR(&KEYBOARD_READ->Status) & KBD_OBF_MASK) {
+ *C = READ_REGISTER_UCHAR(&KEYBOARD_READ->Data);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+BOOLEAN
+SendKbdData(
+ IN UCHAR Data
+ )
+/*++
+
+Routine Description:
+
+ This routine polls the Status Register until the controller is ready to
+ accept a data or timeout, then it send the Data.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if timeout, FALSE if OK;
+
+--*/
+{
+ ULONG i;
+
+ for (i=0; i <KBD_TIMEOUT; i++) {
+ if ((READ_REGISTER_UCHAR(&KEYBOARD_READ->Status) & KBD_IBF_MASK) == 0) {
+ WRITE_REGISTER_UCHAR(&KEYBOARD_WRITE->Data,Data);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+BOOLEAN
+SendKbdCommand(
+ IN UCHAR Command
+ )
+/*++
+
+Routine Description:
+
+ This routine polls the Status Register until the controller is ready to
+ accept a command or timeout, then it send the Command.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE if timeout, FALSE if OK;
+
+--*/
+{
+ ULONG i;
+
+ for (i=0; i <KBD_TIMEOUT; i++) {
+ if ((READ_REGISTER_UCHAR(&KEYBOARD_READ->Status) & KBD_IBF_MASK) == 0) {
+ WRITE_REGISTER_UCHAR(&KEYBOARD_WRITE->Command,Command);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+ULONG
+InitKeyboard(
+ )
+/*++
+
+Routine Description:
+
+ This routine enables amd initializes the keyboard.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE if passed,
+ TRUE if bad ACK or BAT received,
+ TIME_OUT if no response is received from the keyboard.
+
+--*/
+{
+ UCHAR Result;
+ ULONG i;
+
+ //
+ // Send Reset to Keyboard.
+ //
+
+ ClearKbdFifo();
+ for (;;) {
+ if (SendKbdData(KbdReset)) {
+ return TIME_OUT;
+ }
+ if (GetKbdData(&Result,1000)) {
+ return TIME_OUT;
+ }
+ if (Result == KbdResend) {
+ if (GetKbdData(&Result,1000)) {
+ return TIME_OUT;
+ }
+ continue;
+ }
+ if (Result != KbdAck) {
+ return TRUE;
+ }
+ if (GetKbdData(&Result,7000)) {
+ return TIME_OUT;
+ }
+ if (Result != KbdBat) {
+ return TRUE;
+ }
+ break;
+ }
+
+ //
+ // Enable Kbd and Select keyboard Scan code.
+ //
+
+ if (SendKbdCommand(KBD_CTR_ENABLE_KBD)) {
+ return TIME_OUT;
+ }
+ if (SendKbdData(KbdSelScanCode)) {
+ return TIME_OUT;
+ }
+ if (GetKbdData(&Result,1000)) {
+ return TIME_OUT;
+ }
+ if (SendKbdData(1)) { // select Scan code 1
+ return TIME_OUT;
+ }
+ if (GetKbdData(&Result,1000)) {
+ return TIME_OUT;
+ }
+ return FALSE;
+}
+
+ULONG
+InitKeyboardController(
+ )
+/*++
+
+Routine Description:
+
+ This routine Initializes the Keyboard controller.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ FALSE if passed,
+ TRUE if bad response received from keyboard controller,
+ TIME_OUT if no response is received from the keyboard controller.
+
+--*/
+{
+ UCHAR Result;
+
+ //
+ // Clear both fifos.
+ //
+
+ ClearKbdFifo();
+
+ //
+ // Send Selftest Command. This has to be done before anything else.
+ //
+
+ if (SendKbdCommand(KBD_CTR_SELFTEST)) {
+ return TIME_OUT;
+ }
+ if (GetKbdData(&Result,1000)) {
+ return TIME_OUT;
+ }
+ if (Result != Kbd_Ctr_Selftest_Passed) {
+ return TRUE;
+ }
+
+ //
+ // Now the Keyboard and Mouse are disabled.
+ //
+
+ //
+ // Test Keyboard lines.
+ //
+
+ if (SendKbdCommand(KBD_CTR_KBDLINES_TEST)) {
+ return TIME_OUT;
+ }
+ if (GetKbdData(&Result,1000)) {
+ return TIME_OUT;
+ }
+ if (Result != INTERFACE_NO_ERROR) {
+ return TRUE;
+ }
+
+ //
+ // Test Aux lines.
+ //
+
+ if (SendKbdCommand(KBD_CTR_AUXLINES_TEST)) {
+ return TIME_OUT;
+ }
+ if (GetKbdData(&Result,1000)) {
+ return TIME_OUT;
+ }
+ if (Result != INTERFACE_NO_ERROR) {
+ return TRUE;
+ }
+ return FALSE;
+}
diff --git a/private/ntos/fw/mips/led.h b/private/ntos/fw/mips/led.h
new file mode 100644
index 000000000..788ea9e78
--- /dev/null
+++ b/private/ntos/fw/mips/led.h
@@ -0,0 +1,127 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ led.h
+
+Abstract:
+
+ This module defines test and subtest values to display in the
+ LED.
+
+Author:
+
+ Lluis Abello (lluis) 10-Jan-1991
+
+Revision History:
+
+--*/
+//
+// Diagnostic bits definitions.
+//
+#define DIAGNOSTIC_MASK ((1<<6) | (1<<7))
+#define CONFIGURATION_MASK (1<<7)
+#define LOOP_ON_ERROR_MASK (1<<6)
+#define LOOP_ON_ERROR 6
+#define CONFIGURATION 7
+#ifdef DUO
+#define IGNORE_ERRORS_MASK (1<<5)
+#endif
+//
+// LED symbols
+//
+#define LED_BLANK 0xD
+#define LED_MINUS_SIGN 0xB
+#define LED_DECIMAL_POINT 0x10
+
+//
+// LED Display routine control values
+//
+
+#define LED_NORMAL 0x0
+#define LED_BLINK 0x1
+#define LED_LOOP_ERROR 0x2
+#define LED_DELAY_LOOP 0xFFFF // time a digit shown in LED is:
+ // LED_DELAY_LOOP * time 2 ROM fetches
+//
+// LED display values
+//
+#define TEST_SHIFT 4
+
+#define LED_PROCESSOR_TEST 0xE0
+#define LED_TLB_TEST 0xE1
+#define LED_CACHE_INIT 0x60
+#define LED_ICACHE 0XE2
+#define LED_DCACHE 0XE3
+#define LED_SELFCOPY 0xE0
+
+#define LED_INTERRUPT 0x03
+#define LED_NOT_INTERRUPT 0x04 // for any not expected interrupt
+
+#define LED_MCTADR_RESET 0x00
+#define LED_MCTADR_REG 0x01
+#define LED_IO_CACHE 0x02
+
+#define LED_ROM_CHECKSUM 0xC0
+
+#define LED_MEMORY_TEST_1 0xAA
+#define LED_WRITE_MEMORY_2 0xA0
+#define LED_READ_MEMORY_2 0xA0
+#define LED_MAIN_MEMORY 0xA0 //becomes A1,A2,A3
+#define LED_READ_MERGE_WRITE 0xA4
+#define LED_WRONG_MEMORY 0xAE //bad SIMMs installed
+
+
+#define LED_VIDEOMEM 0x90
+#define LED_VIDEOMEM_CHECK_1 0x90
+#define LED_VIDEO_CONTROLLER 0x91
+#define LED_VIDEOMEM_CHECK_2 0x92
+
+
+#define LED_SERIAL_RESET 0x60
+#define LED_SERIAL1_REG 0x61
+#define LED_SERIAL2_REG 0x62
+#define LED_SERIAL1_LBACK 0x63
+#define LED_SERIAL2_LBACK 0x64
+#define LED_SERIAL_INIT 0x65
+#define LED_PARALLEL_REG 0x66
+
+#define LED_KEYBOARD_CTRL 0x50
+#define LED_KEYBOARD_INIT 0x51
+
+#define LED_BEEP 0x40
+#define LED_RTC 0x41
+#define LED_ISP 0x42
+
+#define LED_FLOPPY_RESET 0x30
+#define LED_FLOPPY_REG 0x31
+
+#define LED_SCSI_RESET 0x20
+#define LED_SCSI_REG 0X21
+
+#define LED_SONIC_RESET 0x10
+#define LED_SONIC_REG 0x11
+#define LED_SONIC_LOOPBACK 0x12
+
+#define LED_SOUND 0xC1
+
+#define LED_NVRAM 0x70
+
+#define LED_INIT_COMMAND 0xA5
+
+#define LED_ZEROMEM 0x00
+//
+// Exceptions
+//
+#define LED_PARITY 0xB0
+#define LED_NMI 0xB1
+
+//
+// Processor B selftest.
+//
+#define LED_B_MEMORY_TEST_1 0x20
+#define LED_B_MEMORY_TEST_2 0x21
+
+#define LED_SELFTEST 0x80
diff --git a/private/ntos/fw/mips/linkj4fw.rsp b/private/ntos/fw/mips/linkj4fw.rsp
new file mode 100644
index 000000000..8706a7469
--- /dev/null
+++ b/private/ntos/fw/mips/linkj4fw.rsp
@@ -0,0 +1,79 @@
+-machine:mips
+-rom
+-fixed
+-align:0x200
+-map:j4fw.map
+-base:0x8000c000
+-debug:none
+-entry:FwEntry
+obj\mips\fwentry.obj
+obj\mips\selftest.obj
+obj\mips\memtest.obj
+obj\mips\sonictst.obj
+obj\mips\kbdtest.obj
+obj\mips\j4inter.obj
+obj\mips\x4trap.obj
+obj\mips\j4start.obj
+obj\mips\j4cache.obj
+obj\mips\fwtrap.obj
+obj\mips\monitor.obj
+obj\mips\jxserial.obj
+obj\mips\fwio.obj
+obj\mips\fwprint.obj
+obj\mips\jxboot.obj
+obj\mips\jxreboot.obj
+obj\mips\jxconfig.obj
+obj\mips\jxdisp.obj
+obj\mips\fwtime.obj
+obj\mips\fwload.obj
+obj\mips\fwsignal.obj
+obj\mips\jxenvir.obj
+obj\mips\rlefont.obj
+obj\mips\jxhwsup.obj
+obj\mips\jxkbd.obj
+obj\mips\jxmemory.obj
+obj\mips\jxsysid.obj
+obj\mips\jxvendor.obj
+obj\mips\jxfboot.obj
+obj\mips\xxirql.obj
+obj\mips\jxport.obj
+obj\mips\jxvideo.obj
+..\bldr\obj\mips\fatboot.obj
+..\bldr\obj\mips\exceptn.obj
+..\bldr\obj\mips\scsiboot.obj
+..\bldr\obj\mips\scsidisk.obj
+..\bldr\obj\mips\xxchkstk.obj
+..\miniport\ncr53c94\obj\mips\ncr53c9x.obj
+..\obj\mips\kd.lib
+obj\mips\debug.obj
+..\rtl\obj\mips\rtl.lib
+\nt\public\sdk\lib\mips\libcnt.lib
+..\bldr\obj\mips\cdfsboot.obj
+obj\mips\xxfonts.obj
+obj\mips\pldfont.obj
+obj\mips\eisafunc.obj
+obj\mips\eisapod.obj
+obj\mips\eisaini.obj
+obj\mips\eisaintr.obj
+obj\mips\eisamisc.obj
+obj\mips\subrout.obj
+obj\mips\omf.obj
+obj\mips\jzsetup.obj
+obj\mips\jzboot.obj
+obj\mips\jzcommon.obj
+obj\mips\jzconfig.obj
+obj\mips\jzenvir.obj
+obj\mips\jzether.obj
+obj\mips\jzgetpar.obj
+obj\mips\jzmake.obj
+obj\mips\jzstubs.obj
+obj\mips\jztime.obj
+obj\mips\jxbmp.obj
+obj\mips\bmp.obj
+obj\mips\stubs.obj
+..\nthals\halfxs\obj\mips\jxtime.obj
+obj\mips\fwusa.obj
+obj\mips\jzusa.obj
+obj\mips\eisausa.obj
+obj\mips\vgaoem.obj
+obj\mips\8514oem.obj
diff --git a/private/ntos/fw/mips/linkj4rs.rsp b/private/ntos/fw/mips/linkj4rs.rsp
new file mode 100644
index 000000000..117ac5e83
--- /dev/null
+++ b/private/ntos/fw/mips/linkj4rs.rsp
@@ -0,0 +1,9 @@
+-machine:mips
+-rom
+-fixed
+-align:0x200
+-debug:none
+-map:j4reset.map
+-base:0xE1000000,0xE1001600
+-entry:_start
+obj\mips\j4reset.obj
diff --git a/private/ntos/fw/mips/linkj4sy.rsp b/private/ntos/fw/mips/linkj4sy.rsp
new file mode 100644
index 000000000..8fe1ee681
--- /dev/null
+++ b/private/ntos/fw/mips/linkj4sy.rsp
@@ -0,0 +1,75 @@
+-machine:mips
+-align:0x200
+-map:j4fw.map
+-base:0x8000c000,0x8003ce00
+-debug:full
+-debugtype:coff
+-entry:FwEntry
+obj\mips\fwentry.obj
+obj\mips\selftest.obj
+obj\mips\memtest.obj
+obj\mips\sonictst.obj
+obj\mips\kbdtest.obj
+obj\mips\j4inter.obj
+obj\mips\x4trap.obj
+obj\mips\j4start.obj
+obj\mips\j4cache.obj
+obj\mips\fwtrap.obj
+obj\mips\monitor.obj
+obj\mips\jxserial.obj
+obj\mips\fwio.obj
+obj\mips\fwprint.obj
+obj\mips\jxboot.obj
+obj\mips\jxreboot.obj
+obj\mips\jxconfig.obj
+obj\mips\jxdisp.obj
+obj\mips\fwtime.obj
+obj\mips\fwload.obj
+obj\mips\fwsignal.obj
+obj\mips\jxenvir.obj
+obj\mips\jxhwsup.obj
+obj\mips\jxkbd.obj
+obj\mips\jxmemory.obj
+obj\mips\jxsysid.obj
+obj\mips\jxvendor.obj
+obj\mips\jxfboot.obj
+obj\mips\xxirql.obj
+obj\mips\jxport.obj
+obj\mips\jxvideo.obj
+..\bldr\obj\mips\fatboot.obj
+..\bldr\obj\mips\exceptn.obj
+..\bldr\obj\mips\scsiboot.obj
+..\bldr\obj\mips\scsidisk.obj
+..\bldr\obj\mips\xxchkstk.obj
+..\miniport\ncr53c94\obj\mips\ncr53c9x.obj
+..\obj\mips\kd.lib
+obj\mips\debug.obj
+..\rtl\obj\mips\rtl.lib
+\nt\public\sdk\lib\mips\libcnt.lib
+..\bldr\obj\mips\cdfsboot.obj
+obj\mips\eisafunc.obj
+obj\mips\eisapod.obj
+obj\mips\eisaini.obj
+obj\mips\eisaintr.obj
+obj\mips\eisamisc.obj
+obj\mips\subrout.obj
+obj\mips\omf.obj
+obj\mips\jzsetup.obj
+obj\mips\jzboot.obj
+obj\mips\jzcommon.obj
+obj\mips\jzconfig.obj
+obj\mips\jzenvir.obj
+obj\mips\jzether.obj
+obj\mips\jzgetpar.obj
+obj\mips\jzmake.obj
+obj\mips\jzstubs.obj
+obj\mips\jztime.obj
+obj\mips\jxbmp.obj
+obj\mips\bmp.obj
+obj\mips\stubs.obj
+..\nthals\halfxs\obj\mips\jxtime.obj
+obj\mips\fwusa.obj
+obj\mips\jzusa.obj
+obj\mips\eisausa.obj
+obj\mips\vgaoem.obj
+obj\mips\8514oem.obj
diff --git a/private/ntos/fw/mips/linkset.rsp b/private/ntos/fw/mips/linkset.rsp
new file mode 100644
index 000000000..b85d945fc
--- /dev/null
+++ b/private/ntos/fw/mips/linkset.rsp
@@ -0,0 +1,21 @@
+-machine:mips
+-align:0x200
+-rom
+-debugtype:coff
+-debug:notmapped
+-base:0xa0600000,0xa0610000
+-entry:JzSetup
+obj\mips\jzsetup.obj
+obj\mips\jzboot.obj
+obj\mips\jzcommon.obj
+obj\mips\jzconfig.obj
+obj\mips\jzenvir.obj
+obj\mips\jzether.obj
+obj\mips\jzgetpar.obj
+obj\mips\jzmake.obj
+obj\mips\jzstubs.obj
+obj\mips\jztime.obj
+obj\mips\jxvideo.obj
+\nt\public\sdk\lib\mips\libcnt.lib
+..\rtl\obj\mips\rtl.lib
+obj\mips\jzusa.obj
diff --git a/private/ntos/fw/mips/lk364h.rsp b/private/ntos/fw/mips/lk364h.rsp
new file mode 100644
index 000000000..d25f1d65a
--- /dev/null
+++ b/private/ntos/fw/mips/lk364h.rsp
@@ -0,0 +1,7 @@
+-machine:mips
+-rom
+-fixed
+-align:0x200
+-base:0
+-debug:none
+obj\mips\mg364h.obj
diff --git a/private/ntos/fw/mips/lk364rom.rsp b/private/ntos/fw/mips/lk364rom.rsp
new file mode 100644
index 000000000..ea1f6f506
--- /dev/null
+++ b/private/ntos/fw/mips/lk364rom.rsp
@@ -0,0 +1,9 @@
+-machine:mips
+-rom
+-fixed
+-align:0x200
+-base:0x10000000,0x10001000
+-debug:none
+-entry:InitializeG364
+obj\mips\jazzg364.obj
+\nt\public\sdk\lib\mips\libcnt.lib
diff --git a/private/ntos/fw/mips/lkvxlh.rsp b/private/ntos/fw/mips/lkvxlh.rsp
new file mode 100644
index 000000000..923e39d1e
--- /dev/null
+++ b/private/ntos/fw/mips/lkvxlh.rsp
@@ -0,0 +1,7 @@
+-machine:mips
+-rom
+-fixed
+-align:0x200
+-base:0
+-debug:none
+obj\mips\jzvxlh.obj
diff --git a/private/ntos/fw/mips/lkvxlrom.rsp b/private/ntos/fw/mips/lkvxlrom.rsp
new file mode 100644
index 000000000..7644f5630
--- /dev/null
+++ b/private/ntos/fw/mips/lkvxlrom.rsp
@@ -0,0 +1,10 @@
+-machine:mips
+-rom
+-fixed
+-align:0x200
+-base:0x10000000,0x10001000
+-debug:none
+-entry:InitializeVXL
+obj\mips\jzvxl484.obj
+obj\mips\memtest.obj
+\nt\public\sdk\lib\mips\libcnt.lib
diff --git a/private/ntos/fw/mips/memtest.s b/private/ntos/fw/mips/memtest.s
new file mode 100644
index 000000000..f6f94081c
--- /dev/null
+++ b/private/ntos/fw/mips/memtest.s
@@ -0,0 +1,926 @@
+#if defined(JAZZ)
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ memtest.s
+
+Abstract:
+
+ This module contains the assembly routine to test memory.
+
+Author:
+
+ Lluis Abello (lluis) 10-Aug-91
+
+Environment:
+
+ Executes in kernal mode.
+
+--*/
+
+#include "ksmips.h"
+#include "selfmap.h"
+#include "j4reset.h"
+
+
+.text
+.set noreorder
+.set noat
+ /*++
+VOID
+WriteMemoryAddressTest(
+ StartAddress
+ Size
+ Xor pattern
+ )
+Routine Description:
+
+ This routine will store the address of each location xored with
+ the Pattern into each location.
+ It packs together two words and does double word stores to
+ speed it up.
+
+Arguments:
+
+ a0 - supplies start of memory area to test (must be in KSEG0)
+ a1 - supplies length of memory area in bytes
+ a2 - supplies the pattern to Xor with.
+
+ Note: the values of the arguments are preserved.
+
+Return Value:
+
+ This routine returns no value.
+--*/
+ LEAF_ENTRY(WriteMemoryAddressTest)
+// add t1,a0,a1 // t1 = last address.
+// xor t0,a0,a2 // t0 value to write
+// move t2,a0 // t2=current address
+//writeaddress:
+// mtc1 t0,f0 // move lower word to cop1
+// addiu t2,t2,4 // compute next address
+// xor t0,t2,a2 // next pattern
+// mtc1 t0,f1 // move upper word to cop1
+// addiu t2,t2,4 // compute next address
+// sdc1 f0,-8(t2) // store even doubleword.
+// xor t0,t2,a2 // next pattern
+// mtc1 t0,f0 // move lower word to cop1
+// addiu t2,t2,4 // compute next address
+// xor t0,t2,a2 // next pattern
+// mtc1 t0,f1 // move upper word to cop1
+// addiu t2,t2,4 // compute next address
+// sdc1 f0,-8(t2) // store odd doubleword.
+// bne t2,t1, writeaddress // check for end condition
+// xor t0,t2,a2 // value to write
+// j ra
+// nop
+
+//
+// Enable parity exceptions. To make sure this works.
+//
+ li t1,(1 << PSR_CU1) | (1 << PSR_BEV)
+ mtc0 t1,psr
+ nop
+ nop
+
+//
+// Create dirty exclusive cache blocks and zero the data.
+//
+ mfc0 t5,config // get configuration data
+ li t4,16 //
+ srl t0,t5,CONFIG_DB // compute data cache line size
+ and t0,t0,1 //
+ sll t4,t4,t0 // 1st fill size
+ li t1,(1 << CONFIG_SC)
+ and t0,t5,t1
+ beq t0,zero,SecondaryCache // if zero secondary cache
+
+PrimaryOnly:
+ move t0,a0 // put start address in t0
+ addu t9,t0,a1 // compute ending address
+ and t8,t4,0x10 // test if 16-byte cache block
+
+//
+// Store data using primary data cache only.
+//
+
+30: cache CREATE_DIRTY_EXCLUSIVE_D,0(t0) // create cache block
+ move t1,t0 // save beginning block address
+ xor t5,t0,a2 // create pattern to write
+ mtc1 t5,f0 // move to lower word of double word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ mtc1 t5,f1 // move to upper word of double word
+ addiu t0,t0,4 // increment address
+ sdc1 f0,-8(t0) // store double word
+ xor t5,t0,a2 // create pattern to write
+ mtc1 t5,f0 // move to lower word of double word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ mtc1 t5,f1 // move to upper word of double word
+ addiu t0,t0,4 // increment address
+ bne zero,t8,40f // if ne, 16-byte cache line
+ sdc1 f0,-8(t0) // store double word
+ xor t5,t0,a2 // create pattern to write
+ mtc1 t5,f0 // move to lower word of double word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ mtc1 t5,f1 // move to upper word of double word
+ addiu t0,t0,4 // increment address
+ sdc1 f0,-8(t0) // store double word
+ xor t5,t0,a2 // create pattern to write
+ mtc1 t5,f0 // move to lower word of double word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ mtc1 t5,f1 // move to upper word of double word
+ addiu t0,t0,4 // increment address
+ sdc1 f0,-8(t0) // store double word
+40: nop
+ nop
+ cache INDEX_WRITEBACK_INVALIDATE_D,(t1) // Flush out the data
+ nop
+ bne t0,t9,30b // if ne, more blocks to zero
+ nop
+
+ j ra
+ nop
+
+//
+// Store data using primary and secondary data caches.
+//
+
+SecondaryCache:
+ // t4 = primary data cache line size
+ srl t0,t5,CONFIG_DC // compute primary data cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li t6,1 //
+ sll t6,t6,t0 // t6 = primary data cache size
+ srl t0,t5,CONFIG_SB // compute secondary cache line size
+ and t0,t0,3 //
+ li t8,16 //
+ sll t8,t8,t0 // t8 = secondary cache line size
+ li t5,SECONDARY_CACHE_SIZE // t5 = secondary cache size
+//
+// Write Back all the dirty data from the primary to the secondary cache.
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t2,t1,t6 // add cache size
+ subu t2,t2,t4 // adjust for cache line size.
+WriteBackPrimary:
+ cache INDEX_WRITEBACK_INVALIDATE_D,0(t1) // Invalidate Data cache
+ bne t1,t2,WriteBackPrimary // loop
+ addu t1,t1,t4 // increment index by cache line
+
+
+//
+// Write Back all the dirty data from the secondary to memory
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t2,t1,t5 // add cache size
+ subu t2,t2,t8 // adjust for cache line size.
+WriteBackSecondary:
+ cache INDEX_WRITEBACK_INVALIDATE_SD,0(t1) // Invalidate Data cache
+ bne t1,t2,WriteBackSecondary// loop
+ addu t1,t1,t8 // increment index by cache line
+
+//
+// Now all the dirty data has been saved. And both primary and secondary
+// Data caches are invalid an clean.
+//
+
+ move t0,a0 // put start address in t0
+ addu t9,t0,a1 // compute ending address
+ li t1,16 // If the secondary line is 16
+ beq t1,t8,Secondary16 // bytes go do the write
+ li t1,32 // If the secondary line is 32
+ beq t1,t8,Secondary32 // bytes go do the write
+ nop
+.globl Secondary64
+ .align 4
+ mtc0 zero,taghi
+
+Secondary64:
+ srl t5,t0,5
+ andi t5,t5,0x380
+ ori t5,(5 << TAGLO_SSTATE)
+ li t2,~KSEG1_BASE
+ and t2,t2,t0
+ srl t2,t2,17
+ sll t2,t2,13
+ or t2,t5,t2
+ mtc0 t2,taglo
+ nop
+ nop
+ cache INDEX_STORE_TAG_SD,0(t0)// create cache block
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ nop
+ cache HIT_WRITEBACK_INVALIDATE_SD,-64(t0) // Flush cache block
+ bne t0,t9,Secondary64 // if ne, more data to zero
+ nop
+
+ j ra
+ nop
+
+Secondary16:
+ cache CREATE_DIRTY_EXCLUSIVE_SD,0(t0) // create cache block
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ nop
+ cache HIT_WRITEBACK_INVALIDATE_SD,-16(t0) // Flush cache block
+ bne t0,t9,Secondary16 // if ne, more data to zero
+ nop
+
+ j ra
+ nop
+
+Secondary32:
+ cache CREATE_DIRTY_EXCLUSIVE_SD,0(t0) // create cache block
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ xor t5,t0,a2 // create pattern to write
+ sw t5,0(t0) // store word
+ addiu t0,t0,4 // increment address
+ nop
+ cache HIT_WRITEBACK_INVALIDATE_SD,-32(t0) // Flush cache block
+ bne t0,t9,Secondary32 // if ne, more data to zero
+ nop
+
+ j ra
+ nop
+
+ .end WriteMemoryAddressTest
+
+ /*++
+VOID
+CheckMemoryAddressTest(
+ StartAddress
+ Size
+ Xor pattern
+ LedDisplayValue
+ )
+Routine Description:
+
+ This routine will check that each location contains it's address
+ xored with the Pattern as written by WriteMemoryAddressTest.
+
+ Note: the values of the arguments are preserved.
+
+Arguments:
+
+ This routine will check that each location contains it's address
+ xored with the Pattern as written by WriteMemoryAddressTest. The memory
+ is read cached or non cached according to the address specified by a0.
+ Write address test writes allways KSEG1_ADR=KSEG1_ADR ^ KSEG1_XOR
+ if a0 is in KSEG0 to read the data cached, then the XOR_PATTERN
+ Must be such that:
+ KSEG0_ADR ^ KSEG0_XOR = KSEG1_ADR ^ KSEG1_XOR
+ Examples:
+
+ If XorPattern with which WriteMemoryAddressTest was called is KSEG1_PAT
+ and the XorPattern this routine needs is KSEG0_PAT:
+ KSEG1_XOR Written KSEG0_XOR So that
+ 0x00000000 0xA0 0x20000000 0x80 ^ 0x20 = 0xA0
+ 0xFFFFFFFF 0x5F 0xDFFFFFFF 0x80 ^ 0xDF = 0x5F
+ 0x01010101 0xA1 0x21010101 0x80 ^ 0x21 = 0xA1
+
+ Note: the values of the arguments are preserved.
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+ a2 - supplies the pattern to Xor with.
+ a3 - suplies the value to display in the led in case of failure
+
+Return Value:
+
+ If successful returns a 0, otherwise returns a 1.
+
+--*/
+ LEAF_ENTRY(CheckMemoryAddressTest)
+ move t3,a0 // t3 first address.
+ add t2,t3,a1 // last address.
+checkaddress:
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail
+ addiu t3,t3,4 // compute next address
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail
+ addiu t3,t3,4 // compute next address
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail
+ addiu t3,t3,4 // compute next address
+ lw t1,0(t3) // load from first location
+ xor t0,t3,a2 // first expected value
+ bne t1,t0,PatternFail // check last one.
+ addiu t3,t3,4 // compute next address
+ bne t3,t2, checkaddress // check for end condition
+ nop
+ j ra // return a zero to the caller
+ move v0,zero // set return value to zero.
+PatternFail:
+ j ra //
+// addiu v0,zero,1 // return a 1 to the caller
+ addu v0,zero,t3 // return failing address to caller
+ .end CheckMemoryAddressTest
+
+/*++
+VOID
+WriteVideoMemoryAddressTest(
+ StartAddress
+ Size
+ )
+Routine Description:
+
+ This routine will store the address of each location
+ into each location. It packs two double words together
+ to do sdc1 and speed it up.
+
+Arguments:
+
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+
+ Note: the values of the arguments are preserved.
+
+Return Value:
+
+ This routine returns no value.
+--*/
+ LEAF_ENTRY(WriteVideoMemoryAddressTest)
+ addu t1,a0,a1 // t1 = last address.
+ move t2,a0 // t2=current address
+10:
+ mtc1 t2,f0 // move lower word to cop1
+ addiu t2,t2,4 // compute next address
+ mtc1 t2,f1 // move upper word to cop1
+ addiu t2,t2,4 // compute next address
+ sdc1 f0,-8(t2) // store even doubleword
+ mtc1 t2,f2 // move lower word to cop1
+ addiu t2,t2,4 // compute next address
+ mtc1 t2,f3 // move upper word to cop1
+ addiu t2,t2,4 // compute next address
+ bne t2,t1, 10b // check for end condition
+ sdc1 f2,-8(t2) // store odd doubleword.
+ j ra
+ nop
+ .end WriteVideoMemoryAddressTest
+ /*++
+VOID
+CheckVideoMemoryAddressTest(
+ StartAddress
+ Size
+ )
+Routine Description:
+
+ This routine will check that each location contains it's address
+ xored with the Pattern as written by WriteMemoryAddressTest.
+
+Arguments:
+
+ Note: the values of the arguments are preserved.
+ a0 - supplies start of memory area to test
+ a1 - supplies length of memory area in bytes
+
+Return Value:
+
+ This routine returns FALSE if no errors are found.
+ Otherwise returns true.
+
+--*/
+ LEAF_ENTRY(CheckVideoMemoryAddressTest)
+ addu t2,a0,a1 // compute last address.
+10:
+ ldc1 f0,0(a0) // read data
+ ldc1 f2,8(a0) // read data
+ mfc1 t0,f0 // move from cop
+ mfc1 t1,f1 // move from cop
+ bne t0,a0,VideoMemoryFail // compare
+ addiu a0,a0,4 // inc address for next expected value
+ bne t1,a0,VideoMemoryFail // compare.
+ mfc1 t0,f2 // move from cop
+ mfc1 t1,f3 // move from cop
+ addiu a0,a0,4 // inc address for next expected value
+ bne t0,a0,VideoMemoryFail // compare
+ addiu a0,a0,4 // inc address for next expected value
+ bne t1,a0,VideoMemoryFail // compare.
+ addiu a0,a0,4
+ bne a0,t2,10b
+ nop
+ j ra // return a zero to the caller
+ move v0,zero //
+VideoMemoryFail:
+ j ra //
+ addiu v0,zero,1 // return a 1 to the caller
+ .end CheckVideoMemoryAddressTest
+
+.set at
+
+ LEAF_ENTRY(RomReadMergeWrite)
+ mfc0 t5,config // read config
+ lui t0,0xa004 // uncached address
+ lui t1,0x8004 //8004 // same cached address R4KFIX
+ li t6,16 // end of loop counter
+ move t2,zero // byte counter
+ srl t3,t5,CONFIG_DC // compute data cache size
+ and t3,t3,0x7 //
+ addu t3,t3,12 //
+ li t9,1 //
+ sll t9,t9,t3 // t9 = data cache size
+WriteNextByte:
+ sw zero,0(t1) // clear memory line
+ sw zero,4(t1) // clear memory line
+ sw zero,8(t1) // clear memory line
+ sw zero,12(t1) // clear memory line
+ addu t8,t9,t1 // add cache size to address
+ lw zero,0(t8) // Force a replacement of the cache line -> updates memory
+ add t4,t0,t2 // compute ith byte address
+ nor t5,t2,zero // invert value
+ sb t5,0(t4) // write byte <= read/merge/write
+ move t3,zero // init read index
+CheckNextByte:
+ add t4,t3,t1 // compute cached address
+ lb t4,0(t4) // read byte
+ beq t3,t2, Inverted // if equal is the inverted value
+ nor t5,t2,zero
+ move t5,zero // else expect a zero
+Inverted:
+ bne t4,t5, Error // compare with what we wrote.
+ addiu t3,t3,1 // next byte index
+ bne t3,t6,CheckNextByte
+ nop
+ addiu t2,t2,1 // inc write index
+ bne t2,t6,WriteNextByte
+ nop
+// do the same storing half words
+ move t2,zero // byte counter
+WriteNextHalf:
+ sw zero,0(t1) // clear memory line
+ sw zero,4(t1) // clear memory line
+ sw zero,8(t1) // clear memory line
+ sw zero,12(t1) // clear memory line
+ addu t8,t9,t1 // add cache size to address
+ lw zero,0(t8) // Force a replacement of the cache line -> updates memory
+ add t4,t0,t2 // compute ith byte address
+ nor t5,t2,zero // invert value
+ sh t5,0(t4) // write half <= read/merge/write
+ move t3,zero // init read index
+CheckNextHalf:
+ add t4,t3,t1 // compute cached address
+ lh t4,0(t4) // read half
+ beq t3,t2,InvertedHalf // if equal is the inverted value
+ nor t5,t2,zero // invert value
+ move t5,zero // else expect a zero
+InvertedHalf:
+ bne t4,t5, Error // compare with what we wrote.
+ addiu t3,t3,2 // next half index
+ bne t3,t6,CheckNextHalf
+ nop
+ addiu t2,t2,2 // inc write index
+ bne t2,t6,WriteNextHalf
+ nop
+ j ra
+ move v0,zero // return no errors
+Error:
+ sw t4,20(t0)
+ j ra
+ addiu v0,zero,1 // return errors
+ .end RomReadMergeWrite
+ .set noat
+ /*++
+VOID
+FillVideoMemory(
+ StartAddress
+ Size
+ Pattern
+ )
+Routine Description:
+
+ This routine will fill the given range of video memory with
+ the supplied pattern. The fill is done by doing double word
+ writes and the range must be 16byte aligned.
+
+Arguments:
+
+ a0 - supplies start of memory area
+ a1 - supplies length of memory area
+ a2 - supplies the pattern to fill video memory with. (1byte)
+
+Return Value:
+
+ None.
+
+--*/
+ LEAF_ENTRY(FillVideoMemory)
+ andi a2,a2,0xFF // Mask out byte
+ sll t0,a2,8 // Shift Byte
+ or t0,t0,a2 // or them to make half
+ sll a2,t0,16 // shift half
+ or a2,t0,a2 // or them to make a word
+ addu t0,a0,a1 // compute last address.
+ mtc1 a2,f0 // move pattern to cop1
+ mtc1 a2,f1 // move pattern to cop1
+10:
+ addiu a0,a0,16 // compute next address
+ sdc1 f0,-16(a0) // do a store
+ bne a0,t0,10b // check for end condition
+ sdc1 f0,-8(a0) // do a store
+ j ra
+ nop
+ .end FillVideoMemory
+ /*++
+VOID FwVideoScroll(
+ PUCHAR StartAddress,
+ PUCHAR EndAddress,
+ PUCHAR Destination
+ );
+
+Routine Description:
+
+ This routine writes the pattern to the specified range of addresses
+ doing video pipeline writes on double writes.
+
+Arguments:
+
+ StartAddress - Suplies the range of addresses to be scrolled
+ EndAddress - this addresses must be aligned to 256byte boundaries.
+ Destination - Suplies the Destination address for the scroll
+ (i.e the contents of StartAddress will be moved
+ to destination address and so on).
+
+Return Value:
+
+ None.
+
+--*/
+ .set noreorder
+ .set noat
+ LEAF_ENTRY(FwVideoScroll)
+ScrollRead:
+ ldc1 f0,0x0(a0) // read video
+ ldc1 f2,0x8(a0)
+ ldc1 f4,0x10(a0)
+ ldc1 f6,0x18(a0)
+ ldc1 f8,0x20(a0)
+ ldc1 f10,0x28(a0)
+ ldc1 f12,0x30(a0)
+ ldc1 f14,0x38(a0)
+ ldc1 f16,0x40(a0)
+ ldc1 f18,0x48(a0)
+ ldc1 f20,0x50(a0)
+ ldc1 f22,0x58(a0)
+ ldc1 f24,0x60(a0)
+ ldc1 f26,0x68(a0)
+ ldc1 f28,0x70(a0)
+ ldc1 f30,0x78(a0)
+ addiu a0,a0,0x80 // increment source address
+ sdc1 f0,0x0(a2) // store them pipelining
+ sdc1 f2,0x8(a2)
+ sdc1 f4,0x10(a2)
+ sdc1 f6,0x18(a2)
+ sdc1 f8,0x20(a2)
+ sdc1 f10,0x28(a2)
+ sdc1 f12,0x30(a2)
+ sdc1 f14,0x38(a2)
+ sdc1 f16,0x40(a2)
+ sdc1 f18,0x48(a2)
+ sdc1 f20,0x50(a2)
+ sdc1 f22,0x58(a2)
+ sdc1 f24,0x60(a2)
+ sdc1 f26,0x68(a2)
+ sdc1 f28,0x70(a2)
+ sdc1 f30,0x78(a2)
+ bne a0,a1,ScrollRead // check for last
+ addiu a2,a2,0x80 // increment destination
+ j ra // return to caller
+ nop
+ .end FwVideoScroll
+ /*++
+VOID
+StoreDoubleWord(
+ IN ULONG Address,
+ IN PVOID Value
+ );
+
+Routine Description:
+
+ This routine writes the value pointed by a1 to the address supplied
+ in a0.
+
+Arguments:
+
+ a0 - Address to write double to.
+ a1 - pointer to value to write.
+
+Return Value:
+
+ None.
+
+--*/
+ LEAF_ENTRY(StoreDoubleWord)
+ ldc1 f0,0(a1)
+ nop
+ sdc1 f0,0(a0)
+ j ra
+ nop
+ .end StoreDoubleWord
+ /*++
+VOID
+LoadDoubleWord(
+ IN ULONG Address,
+ OUT PVOID Result
+ );
+
+Routine Description:
+
+ This routine reads a double from the address suplied in a0 and
+ stores the red value in the address supplied by result.
+
+Arguments:
+
+ a0 - Address to read double from.
+ a1 - pointer to double to store result.
+
+Return Value:
+
+ None.
+
+--*/
+ LEAF_ENTRY(LoadDoubleWord)
+ ldc1 f0,0(a0)
+ nop
+ sdc1 f0,0(a1)
+ j ra
+ nop
+ .end
+ /*++
+VOID
+WildZeroMemory(
+ IN ULONG StartAddress,
+ IN ULONG Size
+ )
+Routine Description:
+
+ This routine zeroes the specified range of memory by doing
+ cache line writes.
+
+
+Arguments:
+
+ a0 - supplies the physical address of the range of memory to
+ zero. This address must be a multiple of the Data Cache Size.
+
+ a1 - supplies length of memory to zero.
+ This value must be a multiple of the Data Cache Size.
+
+Return Value:
+
+ None.
+
+--*/
+ LEAF_ENTRY(WildZeroMemory)
+
+// TEMPTEMP
+// li t0,KSEG1_BASE // get non-cached base
+// or t0,t0,a0 // physical address in KSEG1
+// addu t1,t0,a1 // end
+// mtc1 zero,f0 // set write pattern
+// mtc1 zero,f1 //
+//
+//10:
+// sdc1 f0,0(t0)
+// addu t0,t0,16
+// bne t0,t1,10b
+// sdc1 f0,-8(t0)
+//
+// li t0,KSEG0_BASE // get cached base
+// or t0,t0,a0 // physical address in KSEG0
+// addu t1,t0,a1 // end
+//10:
+// lw zero,0(t0)
+// addu t0,t0,16
+// bne t0,t1,10b
+// nop
+//
+// j ra
+// nop
+// TEMPTEMP
+
+//
+// Create dirty exclusive cache blocks and zero the data.
+//
+
+ mfc0 t5,config // get configuration data
+ li t4,16 //
+ srl t0,t5,CONFIG_DB // compute data cache line size
+ and t0,t0,1 //
+ sll t4,t4,t0 // t4 = 1st fill size
+ li t1,(1 << CONFIG_SC)
+ and t0,t5,t1
+ mtc1 zero,f0 // set write pattern
+ mtc1 zero,f1 //
+ beq t0,zero,SecondaryWild // if zero secondary cache
+
+PrimaryWild:
+ li t0,KSEG0_BASE // get cached base
+ or t0,t0,a0 // physical address in KSEG0
+ addu t9,t0,a1 // compute ending address
+ and t8,t4,0x10 // test if 16-byte cache block
+
+//
+// Zero data using primary data cache only.
+//
+
+30: cache CREATE_DIRTY_EXCLUSIVE_D,0(t0) // create cache block
+ move t1,t0 // save beginning block address
+ addu t0,t0,t4 // compute next block address
+ bne zero,t8,40f // if ne, 16-byte cache line
+ sdc1 f0,-16(t0) //
+ sdc1 f0,-24(t0) // zero 16 bytes
+ sdc1 f0,-32(t0) //
+40: sdc1 f0,-8(t0) // zero 16 bytes
+ nop
+ nop
+ cache INDEX_WRITEBACK_INVALIDATE_D,0(t1) // Flush out the data
+ bne t0,t9,30b // if ne, more blocks to zero
+ nop
+
+ j ra
+ nop
+
+//
+// Zero data using primary and secondary data caches.
+//
+SecondaryWild:
+ // t4 = primary data cache line size
+ srl t0,t5,CONFIG_DC // compute primary data cache size
+ and t0,t0,0x7 //
+ addu t0,t0,12 //
+ li t6,1 //
+ sll t6,t6,t0 // t6 = primary data cache size
+ srl t0,t5,CONFIG_SB // compute secondary cache line size
+ and t0,t0,3 //
+ li t8,16 //
+ sll t8,t8,t0 // t8 = secondary cache line size
+ li t5,SECONDARY_CACHE_SIZE // t5 = secondary cache size
+//
+// Write Back all the dirty data from the primary to the secondary cache.
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t2,t1,t6 // add cache size
+ subu t2,t2,t4 // adjust for cache line size.
+WriteBackPrimaryW:
+ cache INDEX_WRITEBACK_INVALIDATE_D,0(t1) // Invalidate Data cache
+ bne t1,t2,WriteBackPrimaryW // loop
+ addu t1,t1,t4 // increment index by cache line
+
+
+//
+// Write Back all the dirty data from the secondary to memory
+//
+ li t1,KSEG0_BASE+(1<<20) // get virtual address to index cache
+ addu t2,t1,t5 // add cache size
+ subu t2,t2,t8 // adjust for cache line size.
+WriteBackSecondaryW:
+ cache INDEX_WRITEBACK_INVALIDATE_SD,0(t1) // Invalidate Data cache
+ bne t1,t2,WriteBackSecondaryW // loop
+ addu t1,t1,t8 // increment index by cache line
+
+//
+// Now all the dirty data has been saved. And both primary and secondary
+// Data caches are invalid an clean.
+//
+
+ li t0,KSEG0_BASE // get cached base
+ or t0,t0,a0 // physical address in KSEG0
+ addu t9,t0,a1 // compute ending address
+ subu t9,t9,t8 // adjust last address
+ li t1,16 // If the secondary line is 16
+ beq t1,t8,SecondaryW16 // bytes go do the write
+ li t1,32 // If the secondary line is 32
+ beq t1,t8,SecondaryW32 // bytes go do the write
+ nop
+
+SecondaryW64:
+ cache CREATE_DIRTY_EXCLUSIVE_SD,0(t0) // create cache block
+ sdc1 f0,0(t0) // store double word
+ sdc1 f0,8(t0) // store double word
+ sdc1 f0,16(t0) // store double word
+ sdc1 f0,24(t0) // store double word
+ sdc1 f0,32(t0) // store double word
+ sdc1 f0,40(t0) // store double word
+ sdc1 f0,48(t0) // store double word
+ sdc1 f0,56(t0) // store double word
+ cache HIT_WRITEBACK_INVALIDATE_SD,0(t0) // Flush cache block
+ bne t0,t9,SecondaryW64 // if ne, more data to zero
+ addiu t0,t0,64
+ j ra
+ nop
+
+SecondaryW32:
+ cache CREATE_DIRTY_EXCLUSIVE_SD,0(t0) // create cache block
+ sdc1 f0,0(t0) // store double word
+ sdc1 f0,8(t0) // store double word
+ sdc1 f0,16(t0) // store double word
+ sdc1 f0,24(t0) // store double word
+ cache HIT_WRITEBACK_INVALIDATE_SD,0(t0) // Flush cache block
+ bne t0,t9,SecondaryW32 // if ne, more data to zero
+ addiu t0,t0,32
+ j ra
+ nop
+
+SecondaryW16:
+ cache CREATE_DIRTY_EXCLUSIVE_SD,0(t0) // create cache block
+ sdc1 f0,0(t0) // store double word
+ sdc1 f0,8(t0) // store double word
+ cache HIT_WRITEBACK_INVALIDATE_SD,0(t0) // Flush cache block
+ bne t0,t9,SecondaryW16 // if ne, more data to zero
+ addiu t0,t0,16
+ j ra
+ nop
+
+ .end WildZeroMemory
+
+#endif
+
diff --git a/private/ntos/fw/mips/mg364h.s b/private/ntos/fw/mips/mg364h.s
new file mode 100644
index 000000000..dadae8c27
--- /dev/null
+++ b/private/ntos/fw/mips/mg364h.s
@@ -0,0 +1,60 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ mg364h.s
+
+Abstract:
+
+ This module contains the video prom header for Mips G364.
+ It must be placed starting at the first video rom location.
+
+Author:
+
+ Lluis Abello (lluis) 21-Jul-92
+
+Environment:
+
+
+
+Notes:
+
+ This module doesn't contain any code.
+ Data is in the text section, so that the linker puts it at the
+ begining.
+
+
+Revision History:
+
+
+
+--*/
+
+#include <ksmips.h>
+
+.text
+
+.byte 0x10 // Video Board ID
+.byte 8 // PROM_Stride
+.byte 1 // PROM_Width
+.byte 0x20 // PROM_Size = 32 4KB pages
+.ascii "Jazz"
+
+//
+// The following data corresponds to this structure.
+//
+//typedef struct _VIDEO_PROM_CONFIGURATION {
+// ULONG VideoMemorySize;
+// ULONG VideoControlSize;
+// ULONG CodeOffset;
+// ULONG CodeSize;
+// UCHAR IdentifierString[];
+//} VIDEO_PROM_CONFIGURATION; *PVIDEO_PROM_CONFIGURATION;
+
+.word 0x200000 // VideoMemorySize = 4MB
+.word 0x200000 // VideoControlSize = 4MB
+.word 0x200 // CodeOffset. Code starts at offset 200 from video prom
+.word 0x4000 // CodeSize 16K of code...
+.asciiz "Mips G364"
diff --git a/private/ntos/fw/mips/monitor.c b/private/ntos/fw/mips/monitor.c
new file mode 100644
index 000000000..e82a8c2ba
--- /dev/null
+++ b/private/ntos/fw/mips/monitor.c
@@ -0,0 +1,1499 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ monitor.c
+
+Abstract:
+
+ This file contains the monitor for the firmware.
+
+Author:
+
+ Lluis Abello (lluis) 09-Sep-91
+
+--*/
+
+#include "fwp.h"
+#include "monitor.h"
+#include "selfmap.h"
+#include "sys\types.h"
+#include "stdlib.h"
+#include "string.h"
+#include "jzsetup.h"
+#include "selftest.h"
+#include "fwstring.h"
+
+
+#define BYTE 1
+#define HALF 2
+#define WORD 4
+
+#define R4000_XCODE_MASK (0x1f << 2)
+#define XCODE_INSTRUCTION_BUS_ERROR 0x18
+#define XCODE_DATA_BUS_ERROR 0x1c
+
+
+ VOID
+RomPutLine(
+ IN PCHAR String
+ );
+
+VOID
+FillVideoMemory(
+ IN ULONG,
+ IN ULONG,
+ IN ULONG
+ );
+
+#define MoveCursorToColumn(Spaces) \
+ FwPrint("\r\x9B"#Spaces"C")
+
+//
+// declare static variables.
+//
+extern BOOLEAN ProcessorBEnabled;
+ULONG Argc;
+ULONG CurrentArg;
+
+COMMAND_NAME_ID CurrentCommand;
+
+ULONG DataSize;
+ULONG DataSizeMask;
+ULONG DataSizeShift;
+
+ULONG DefaultAddress;
+
+// ****** temp ******
+// strtoul sets errno in case of overflow and is not declared anywhere else.
+//
+// int errno;
+
+PCHAR RegisterNameTable[(REGISTER_NAME_ID)invalidregister] = {
+ "zero", // general register 0
+ "at", // general register 1
+ "v0", // general register 2
+ "v1", // general register 3
+ "a0", // general register 4
+ "a1", // general register 5
+ "a2", // general register 6
+ "a3", // general register 7
+ "t0", // general register 8
+ "t1", // general register 9
+ "t2", // general register 10
+ "t3", // general register 11
+ "t4", // general register 12
+ "t5", // general register 13
+ "t6", // general register 14
+ "t7", // general register 15
+ "s0", // general register 16
+ "s1", // general register 17
+ "s2", // general register 18
+ "s3", // general register 19
+ "s4", // general register 20
+ "s5", // general register 21
+ "s6", // general register 22
+ "s7", // general register 23
+ "t8", // general register 24
+ "t9", // general register 25
+ "k0", // general register 26
+ "k1", // general register 27
+ "gp", // general register 28
+ "sp", // general register 29
+ "s8", // general register 30
+ "ra", // general register 31
+ "f0", // fp register 0
+ "f1", // fp register 1
+ "f2", // fp register 2
+ "f3", // fp register 3
+ "f4", // fp register 4
+ "f5", // fp register 5
+ "f6", // fp register 6
+ "f7", // fp register 7
+ "f8", // fp register 8
+ "f9", // fp register 9
+ "f10", // fp register 10
+ "f11", // fp register 11
+ "f12", // fp register 12
+ "f13", // fp register 13
+ "f14", // fp register 14
+ "f15", // fp register 15
+ "f16", // fp register 16
+ "f17", // fp register 17
+ "f18", // fp register 18
+ "f19", // fp register 19
+ "f20", // fp register 20
+ "f21", // fp register 21
+ "f22", // fp register 22
+ "f23", // fp register 23
+ "f24", // fp register 24
+ "f25", // fp register 25
+ "f26", // fp register 26
+ "f27", // fp register 27
+ "f28", // fp register 28
+ "f29", // fp register 29
+ "f30", // fp register 30
+ "f31", // fp register 31
+ "fsr", // fp status register
+ "index", // cop0 register 0
+ "random", // cop0 register 1
+ "entrylo0", // cop0 register 2
+ "entrylo1", // cop0 register 3
+ "context", // cop0 register 4
+ "pagemask", // cop0 register 5
+ "wired", // cop0 register 6
+ "badvaddr", // cop0 register 8
+ "count", // cop0 register 9
+ "entryhi", // cop0 register 10
+ "compare", // cop0 register 11
+ "psr", // cop0 register 12
+ "cause", // cop0 register 13
+ "epc", // cop0 register 14
+ "prid", // cop0 register 15
+ "config", // cop0 register 16
+ "lladdr", // cop0 register 17
+ "watchlo", // cop0 register 18
+ "watchhi", // cop0 register 19
+ "ecc", // cop0 register 26
+ "cacheerror", // cop0 register 27
+ "taglo", // cop0 register 28
+ "taghi", // cop0 register 29
+ "errorepc" // cop0 register 30
+ };
+
+CHAR UnknownException[] = "Unknown";
+PCHAR ExceptionNameTable[32] = {
+ "Int", // exception code 0
+ "Mod", // exception code 1
+ "TlbL", // exception code 2
+ "TlbS", // exception code 3
+ "AdEL", // exception code 4
+ "AdES", // exception code 5
+ "IBE", // exception code 6
+ "DBE", // exception code 7
+ "Sys", // exception code 8
+ "Bp", // exception code 9
+ "RI", // exception code 10
+ "CpU", // exception code 11
+ "Ov", // exception code 12
+ "Tr", // exception code 13
+ "VCEI", // exception code 14
+ "FPE", // exception code 15
+ UnknownException, // exception code 16
+ UnknownException, // exception code 17
+ UnknownException, // exception code 18
+ UnknownException, // exception code 19
+ UnknownException, // exception code 20
+ UnknownException, // exception code 21
+ UnknownException, // exception code 22
+ "WATCH", // exception code 23
+ UnknownException, // exception code 24
+ UnknownException, // exception code 25
+ UnknownException, // exception code 26
+ UnknownException, // exception code 27
+ UnknownException, // exception code 28
+ UnknownException, // exception code 29
+ UnknownException, // exception code 30
+ "VCED" // exception code 31
+ };
+
+PCHAR CommandNameTable[(COMMAND_NAME_ID)invalidcommand] = {
+ "d",
+ "db",
+ "dw",
+ "dd",
+ "e",
+ "eb",
+ "ew",
+ "ed",
+ "o",
+ "ob",
+ "ow",
+ "od",
+ "i",
+ "ib",
+ "iw",
+ "id",
+ "r",
+ "z",
+ "f",
+ "a",
+ "h",
+ "?",
+#ifdef DUO
+ "s",
+#endif
+ "q"
+ };
+
+extern ULONG RegisterTable[(REGISTER_NAME_ID)invalidregister];
+extern LONG FwRow;
+extern LONG FwColumn;
+
+
+REGISTER_NAME_ID
+GetRegister(
+ IN PCHAR RegName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the index in the register table for the
+ given register. Or invalid if the given register name doesn't
+ match any register.
+
+Arguments:
+
+ RegName - Null terminated string that contains the name of the register.
+
+Return Value:
+
+ Index on the Register Table for the requested register.
+
+--*/
+
+{
+ REGISTER_NAME_ID RegId;
+
+ for (RegId = 0; RegId < MON_INVALID_REGISTER_MSG; RegId++) {
+ if (strcmp(RegisterNameTable[RegId],RegName) == 0) {
+ break;
+ }
+ }
+ return RegId;
+}
+
+
+ULONG
+StrToUlong(
+ IN PCHAR String,
+ OUT CHAR ** Terminator
+ )
+/*++
+
+Routine Description:
+
+ This routine converts an ascii string to an unsigned long
+
+Arguments:
+
+ String - Null terminated string that contains the value to convert.
+ Terminator - Address of a pointer to a character. This routine
+ sets it to point to the cahracter in String that terminated
+ the conversion. This is '\0' in a normal case or whatever
+ garbage the string contained.
+
+
+Return Value:
+
+ Returns the converted string
+
+--*/
+{
+ ULONG Ulong = 0;
+ ULONG Index;
+ for (Index=0;String[Index]; Index++) {
+
+ if ((String[Index] >= '0') && (String[Index] <= '9')) {
+ Ulong <<= 4;
+ Ulong |= String[Index] - '0';
+ continue;
+ }
+
+ //
+ // Strings are always lower case so this is not needed.
+ //
+ //if ((String[Index] >= 'A') && (String[Index] <= 'F')) {
+ // Ulong <<= 4;
+ // Ulong |= String[Index] - 'A' + 10;
+ // continue;
+ //}
+
+ if ((String[Index] >= 'a') && (String[Index] <= 'f')) {
+ Ulong <<= 4;
+ Ulong |= String[Index] - 'a' + 10;
+ continue;
+ }
+ *Terminator = &String[Index];
+ return 0xFFFFFFF;
+ }
+
+ //
+ // Check for overflow
+ //
+ if (Index > 8) {
+ *Terminator = &String[0];
+ } else {
+ *Terminator = &String[Index];
+ }
+ return Ulong;
+}
+
+
+BOOLEAN
+GetAddress(
+ IN PUCHAR String,
+ OUT PULONG Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts an ascii string to an address. The string
+ is the form:
+ [@reg | value]
+
+Arguments:
+
+ String - Null terminated string that contains the address to convert.
+ Address - Supplies a pointer to where the converted address is stored
+
+Return Value:
+
+ Returns TRUE if the string can be converted.
+ FALSE otherwise.
+
+--*/
+
+{
+ PUCHAR Terminator;
+ UCHAR Delimiter;
+ REGISTER_NAME_ID RegId;
+ if (*String == '@') {
+ String++; // skip @
+ if ((RegId = GetRegister(String)) == MON_INVALID_REGISTER_MSG) {
+ FwPrint(String);
+ FwPrint(MON_INVALID_REGISTER_MSG);
+ return FALSE;
+ } else {
+ *Address = RegisterTable[RegId];
+ }
+ } else {
+ *Address=StrToUlong(String,&Terminator);
+ if (*Terminator != '\0') {
+ //
+ // Not the whole string was converted.
+ //
+ FwPrint(Terminator);
+ FwPrint(MON_NOT_VALID_ADDRESS_MSG);
+ return FALSE;
+ }
+ }
+ return TRUE;
+}
+
+BOOLEAN
+GetAddressRange(
+ IN PCHAR Argv[],
+ OUT PULONG StartAddress,
+ OUT PULONG EndAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine converts an ascii string to a range, returning the starting
+ and end address.
+
+ The syntax for an address range is one of the following
+
+ startaddress endaddres
+ startaddress l numberofelements
+
+Arguments:
+
+ Argv - array of zero terminated argument strings.
+ StartAddress - Supplies a pointer to where the Start address is stored
+ EndAddress - Supplies a pointer to where the End address is stored
+
+Return Value:
+
+ Returns TRUE if Argv specifies a valid address range.
+ FALSE otherwise.
+
+--*/
+
+{
+ PCHAR Tmp;
+ CHAR Delimiter;
+
+ if (CurrentArg == Argc) {
+ return;
+ }
+ if (GetAddress(Argv[CurrentArg],StartAddress) == FALSE) {
+ return FALSE;
+ }
+ CurrentArg++;
+ if (CurrentArg == Argc) {
+ *EndAddress = *StartAddress+128;
+ return TRUE;
+ }
+ if (strcmp(Argv[CurrentArg],"l") == 0 ) {
+ //
+ // this is a range of the form "startaddress l count"
+ //
+ CurrentArg++;
+ if (CurrentArg == Argc) {
+ FwPrint(MON_INVALID_ARGUMENT_COUNT_MSG);
+ return FALSE;
+ }
+ if (GetAddress(Argv[CurrentArg],EndAddress) == FALSE) {
+ return FALSE;
+ }
+ CurrentArg++;
+ *EndAddress = (*EndAddress<<DataSizeShift) + *StartAddress;
+ } else {
+ if (GetAddress(Argv[CurrentArg],EndAddress) == FALSE) {
+ //
+ // the argument didn't convert the range is Start+128
+ //
+ *EndAddress = *StartAddress+128;
+ } else {
+ CurrentArg++;
+ }
+ }
+ //
+ // Check that the range is correct End > Start
+ //
+ if (*EndAddress <= *StartAddress) {
+ FwPrint(MON_INVALID_ADDRESS_RANGE_MSG);
+ return FALSE;
+ }
+ return TRUE;
+}
+COMMAND_NAME_ID
+GetCommand(
+ IN PCHAR CommandName
+ )
+
+/*++
+
+Routine Description:
+
+ This routine tries to match the supplied string
+ with one of the recognized commands.
+
+Arguments:
+
+ CommandName - Supplies a string to be matched with one of the monitor commands.
+
+Return Value:
+
+ Returns a value that identifies the command.
+
+--*/
+{
+ COMMAND_NAME_ID Index;
+ for (Index=0;Index<invalidcommand;Index++) {
+ if (strcmp(CommandNameTable[Index],CommandName) == 0) {
+ break;
+ }
+ }
+ return Index;
+}
+
+BOOLEAN
+RegisterCommand(
+ IN PCHAR Argv[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine will implement the REGISTER command given the
+ arguments in the argc,Argv form.
+
+Arguments:
+
+ Argv - array of zero terminated argument strings.
+
+Return Value:
+
+ Returns TRUE if the command is valid, FALSE otherwise.
+
+--*/
+{
+ REGISTER_NAME_ID RegId;
+ CHAR Message[64];
+ switch(Argc) {
+ case 1:
+ //
+ // Dump the value of all the registers
+ //
+ for (RegId=1;RegId<32;RegId++) {
+ sprintf(Message,MON_FORMAT1_MSG,RegisterNameTable[RegId],RegisterTable[RegId]);
+ FwPrint(Message);
+ if ((RegId%6) == 0) {
+ FwPrint(FW_CRLF_MSG);
+ }
+ }
+ sprintf(Message,MON_FORMAT1_MSG,RegisterNameTable[psr],RegisterTable[psr]);
+ FwPrint(Message);
+ sprintf(Message,MON_FORMAT1_MSG,RegisterNameTable[epc],RegisterTable[epc]);
+ FwPrint(Message);
+ sprintf(Message,MON_FORMAT1_MSG,RegisterNameTable[cause],RegisterTable[cause]);
+ FwPrint(Message);
+ sprintf(Message,MON_FORMAT1_MSG,RegisterNameTable[errorepc],RegisterTable[errorepc]);
+ FwPrint(Message);
+ FwPrint(FW_CRLF_MSG);
+ sprintf(Message,MON_FORMAT1_MSG,RegisterNameTable[badvaddr],RegisterTable[badvaddr]);
+ FwPrint(Message);
+ FwPrint(FW_CRLF_MSG);
+ return TRUE;
+ case 2:
+ //
+ // Dump the value of the specified register.
+ //
+ if ((RegId = GetRegister(Argv[1])) == MON_INVALID_REGISTER_MSG) {
+ FwPrint(Argv[1]);
+ FwPrint(MON_INVALID_REGISTER_MSG);
+ return FALSE;
+ } else {
+ sprintf(Message,"%s = %08lx\r\n",RegisterNameTable[RegId],RegisterTable[RegId]);
+ FwPrint(Message);
+ return TRUE;
+ }
+ default:
+ FwPrint(MON_INVALID_ARGUMENT_COUNT_MSG);
+ return FALSE;
+ }
+}
+
+VOID
+InputValue(
+ IN ULONG Address,
+ OUT PVOID Value
+ )
+/*++
+
+Routine Description:
+
+ This routine reads a value from the supplied address and displays
+ it. DataSize is set to the size of the value to read.
+
+Arguments:
+
+ Address - Supplies the address where the value is to be read from.
+ Value - Pointer to where the value read is stored.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CHAR Message[32];
+
+ switch(DataSize) {
+ case BYTE:
+ *(PUCHAR)Value = *(PUCHAR)Address; // read byte
+ sprintf(Message,"%02x ",*(PUCHAR)Value);
+ break;
+ //
+ // Display same data in ascii
+ //
+ case HALF:
+ sprintf(Message,"%04x ",*(PUSHORT)Address);
+ break;
+ case WORD:
+ sprintf(Message,"%08lx ",*(PULONG)Address);
+ break;
+ }
+ FwPrint(Message);
+}
+
+
+BOOLEAN
+DumpCommand(
+ IN PCHAR Argv[]
+ )
+/*++
+
+Routine Description:
+
+ This routine will implement the DUMP command given the
+ arguments in the argc,Argv form.
+
+Arguments:
+
+ Argv - array of zero terminated argument strings.
+
+Return Value:
+
+ Returns TRUE if the command is valid, FALSE otherwise.
+
+--*/
+
+{
+ ULONG Start,End;
+ ULONG i,LineLength;
+ ULONG DataLine[16];
+ UCHAR Message[32];
+ //
+ // Set the right range of addresses. If none specified use last
+ // set of addresses+128.
+ //
+ if (Argc == 1) {
+ Start = DefaultAddress;
+ End = Start + 128;
+ } else {
+ if (GetAddressRange(Argv,&Start,&End) == FALSE) {
+ return FALSE;
+ }
+ //
+ // if after getting the range not all the argument were processsed.
+ //
+ if (CurrentArg != Argc) {
+ FwPrint(MON_INVALID_ARGUMENT_COUNT_MSG);
+ return FALSE;
+ }
+ }
+
+ //
+ // Check for proper alignment.
+ //
+ if ((DataSizeMask&Start) || (DataSizeMask&End)) {
+ FwPrint(MON_UNALIGNED_ADDRESS_MSG);
+ return FALSE;
+ } else {
+ //
+ // Set new addresses
+ //
+ DefaultAddress = End;
+ }
+ while (Start < End) {
+ //
+ // Print address of line.
+ //
+ sprintf(Message,"0x%08lx: ",Start);
+ FwPrint(Message);
+ LineLength = End-Start;
+ if (LineLength > 16) {
+ LineLength = 16;
+ }
+ for (i=0;i<LineLength;i+=DataSize) {
+ InputValue(Start,&DataLine[i]);
+ Start+=DataSize;
+ }
+ if (DataSize == 1) {
+ //
+ // If bytes display same data in ASCII
+ //
+ MoveCursorToColumn(60);
+ for (i=0;i<LineLength;i++) {
+ if (isprint((UCHAR)DataLine[i])) {
+ sprintf(Message,"%c",DataLine[i]);
+ FwPrint(Message);
+ } else {
+ FwPrint(".");
+ }
+ }
+ }
+ FwPrint(FW_CRLF_MSG);
+ }
+ return TRUE;
+}
+
+BOOLEAN
+ZeroCommand(
+ IN PCHAR Argv[]
+ )
+/*++
+
+Routine Description:
+
+ This routine will implement the Zero command given the
+ arguments in the argc,Argv form.
+
+Arguments:
+
+ Argv - array of zero terminated argument strings.
+
+Return Value:
+
+ Returns TRUE if the command is valid, FALSE otherwise.
+
+--*/
+
+{
+ ULONG Start,End;
+ //
+ // Set the right range of addresses. If none specified use last
+ // set of addresses+128.
+ //
+ if (Argc == 1) {
+ Start = DefaultAddress;
+ End = Start + 128;
+ } else {
+ if (GetAddressRange(Argv,&Start,&End) == FALSE) {
+ return FALSE;
+ }
+ //
+ // if after getting the range not all the argument were processsed.
+ //
+ if (CurrentArg != Argc) {
+ FwPrint(MON_INVALID_ARGUMENT_COUNT_MSG);
+ return FALSE;
+ }
+ }
+
+ //
+ // Check for proper alignment.
+ //
+ if ((0xF&Start) || (0xF&End)) {
+ FwPrint(MON_UNALIGNED_ADDRESS_MSG);
+ return FALSE;
+ } else {
+ //
+ // Set new addresses
+ //
+ DefaultAddress = End;
+ }
+ FillVideoMemory(Start,End-Start,0);
+ return TRUE;
+}
+
+BOOLEAN
+OutputValue(
+ IN PCHAR AsciiValue,
+ IN ULONG Address
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the converted value to the specified
+ address. DataSize is set to the size of the data to be written.
+
+Arguments:
+
+ AsciiValue - Supplies a pointer to a string that contains an hexadecimal
+ value.
+ Address - Supplies the address where the value is to be written to.
+
+Return Value:
+
+ TRUE if the value is successfully converted.
+ FALSE otherwise.
+
+--*/
+{
+ ULONG Value;
+ PCHAR Terminator;
+
+ //
+ // Conver value to integer
+ //
+ Value = StrToUlong(AsciiValue,&Terminator);
+ if (*Terminator != '\0') {
+ //
+ // Not the whole string was converted.
+ //
+ FwPrint(Terminator);
+ FwPrint(MON_INVALID_VALUE_MSG);
+ return FALSE;
+ } else {
+ //
+ // Store the value.
+ //
+ switch (DataSize) {
+ case BYTE:*(PUCHAR)Address = (UCHAR)Value;
+ break;
+ case HALF:*(PUSHORT)Address = (USHORT)Value;
+ break;
+ case WORD: *(PULONG)Address = (ULONG)Value;
+ break;
+ }
+ }
+ return TRUE;
+}
+
+BOOLEAN
+OutputCommand(
+ IN PCHAR Argv[]
+ )
+/*++
+
+Routine Description:
+
+ This routine will implement the OUTPUT command given the
+ arguments in the argc,Argv form.
+
+Arguments:
+
+ Argv - array of zero terminated argument strings.
+
+Return Value:
+
+ Returns TRUE if the command is valid, FALSE otherwise.
+
+--*/
+
+{
+ ULONG Start;
+
+ if (Argc!=3) {
+ FwPrint(MON_INVALID_ARGUMENT_COUNT_MSG);
+ return FALSE;
+ }
+ if (GetAddress(Argv[1],&Start) == FALSE) {
+ return FALSE;
+ }
+
+ //
+ // Check for proper alignment.
+ //
+ if (DataSizeMask & Start) {
+ FwPrint(MON_UNALIGNED_ADDRESS_MSG);
+ return FALSE;
+ }
+ if (OutputValue(Argv[2],Start) == TRUE) {
+ //
+ // Set new default addresses
+ //
+ DefaultAddress = Start+DataSize;
+ }
+ return TRUE;
+}
+
+BOOLEAN
+InputCommand(
+ IN PCHAR Argv[]
+ )
+/*++
+
+Routine Description:
+
+ This routine will implement the INPUT command given the
+ arguments in the argc,Argv form.
+
+Arguments:
+
+ Argv - array of zero terminated argument strings.
+
+Return Value:
+
+ Returns TRUE if the command is valid, FALSE otherwise.
+
+--*/
+
+{
+ ULONG Start;
+ UCHAR Message[16];
+ ULONG Trash;
+ if (Argc!=2) {
+ FwPrint(MON_INVALID_ARGUMENT_COUNT_MSG);
+ return FALSE;
+ }
+
+ if (GetAddress(Argv[1],&Start) == FALSE) {
+ return FALSE;
+ }
+
+ //
+ // Check for proper alignment.
+ //
+ if (DataSizeMask & Start) {
+ FwPrint(MON_UNALIGNED_ADDRESS_MSG);
+ return FALSE;
+ }
+ sprintf(Message,"0x%08lx: ",Start);
+ FwPrint(Message);
+ InputValue(Start,&Trash);
+ FwPrint(FW_CRLF_MSG);
+ //
+ // Set new default addresses
+ //
+ DefaultAddress = Start+DataSize;
+ return TRUE;
+}
+
+BOOLEAN
+EnterCommand(
+ IN PCHAR Argv[]
+ )
+/*++
+
+Routine Description:
+
+ This routine will implement the ENTER command given the
+ arguments in the argc,Argv form.
+
+Arguments:
+
+ Argv - array of zero terminated argument strings.
+
+Return Value:
+
+ Returns TRUE if the command is valid, FALSE otherwise.
+
+--*/
+
+{
+ ULONG Start;
+ CHAR String[32];
+ GETSTRING_ACTION Action;
+
+ //
+ // Set the right range of addresses. If none specified use last
+ // set of addresses+128.
+ //
+ switch(Argc) {
+ case 1:
+ Start = DefaultAddress;
+ break;
+ case 2:
+ if (GetAddress(Argv[1],&Start) == FALSE) {
+ return FALSE;
+ }
+ break;
+ case 3:
+ //
+ // This is equivalent to the output command
+ //
+ return OutputCommand(Argv);
+ default:
+ FwPrint(MON_INVALID_ARGUMENT_COUNT_MSG);
+ return FALSE;
+ }
+
+ //
+ // Check for proper alignment.
+ //
+ if (DataSizeMask & Start) {
+ FwPrint(MON_UNALIGNED_ADDRESS_MSG);
+ return FALSE;
+ }
+ for (;;) {
+ //
+ // Print address of line.
+ //
+ sprintf(String,"0x%08lx: ",Start);
+ FwPrint(String);
+ switch (DataSize) {
+ case BYTE:
+ sprintf(String,"%02x . ",*(PUCHAR)Start);
+ break;
+ case HALF:
+ sprintf(String,"%04x . ",*(PUSHORT)Start);
+ break;
+ case WORD:
+ sprintf(String,"%08lx . ",*(PULONG)Start);
+ break;
+ }
+ FwPrint(String);
+ do {
+ Action = FwGetString(String,10,NULL,FwRow,FwColumn);
+ } while ((Action != GetStringSuccess) && (Action != GetStringEscape));
+ FwPrint(FW_CRLF_MSG);
+
+ if (String[0] == '\0') { // carriage return exit enter command
+ //
+ // set new default address.
+ //
+ DefaultAddress = Start;
+ return TRUE;
+ }
+ if (String[0] == ' ') { // blank = next data element.
+ Start+=DataSize;
+ continue;
+ }
+ if (String[0] == '-') { // hypen = previous data element.
+ Start-=DataSize;
+ continue;
+ }
+ if (OutputValue(String,Start) == TRUE) { // deposit the value.
+ Start+=DataSize;
+ }
+ }
+ return TRUE;
+}
+
+BOOLEAN
+FillCommand(
+ IN PCHAR Argv[]
+ )
+/*++
+
+Routine Description:
+
+ This routine will implement the FILL command given the
+ arguments in the argc,Argv form.
+
+Arguments:
+
+ Argv - array of zero terminated argument strings.
+
+Return Value:
+
+ Returns TRUE if the command is valid, FALSE otherwise.
+
+--*/
+
+{
+ ULONG Start,End,Values[16];
+ ULONG Index,Count;
+ PCHAR Terminator;
+
+ if (GetAddressRange(Argv,&Start,&End) == FALSE) {
+ return FALSE;
+ }
+ //
+ // if there are no more arguments we don't know what to fill with.
+ //
+ if (CurrentArg == Argc) {
+ FwPrint(MON_INVALID_ARGUMENT_COUNT_MSG);
+ return FALSE;
+ }
+
+ //
+ // Convert the values
+ //
+ for (Count=0;CurrentArg < Argc; CurrentArg++) {
+ Values[Count++] = StrToUlong(Argv[CurrentArg],&Terminator);
+ if (*Terminator != '\0') {
+ //
+ // Not the whole string was converted.
+ //
+ FwPrint(Terminator);
+ FwPrint(MON_INVALID_VALUE_MSG);
+ return FALSE;
+ }
+ }
+ Index = 0;
+ for (;Start < End;Start++) {
+ *((PCHAR)Start) = Values[Index++];
+ if (Index == Count) {
+ Index=0;
+ }
+ }
+ return TRUE;
+}
+
+
+BOOLEAN
+FwDumpLookupTable(
+ IN PCHAR Argv[]
+ )
+
+/*++
+
+Routine Description:
+
+ This routine displays the device names stored in the lookup table.
+
+Arguments:
+
+ Argv - array of zero terminated argument strings.
+
+Return Value:
+
+ Returns TRUE if the command is valid, FALSE otherwise.
+
+--*/
+
+{
+ UCHAR C;
+ ULONG Count;
+ PDRIVER_LOOKUP_ENTRY PLookupTable;
+
+ PLookupTable=&DeviceLookupTable[0];
+ while (PLookupTable->DevicePath != NULL) {
+ FwPrint(PLookupTable->DevicePath);
+ FwPrint(FW_CRLF_MSG);
+ PLookupTable++;
+ }
+ return(TRUE);
+}
+
+VOID
+Monitor(
+ IN ULONG CallerSource
+ )
+/*++
+
+Routine Description:
+
+ This is the main dispatch routine to the various commands
+ that can be typed at the monitor prompt.
+
+Arguments:
+
+ CallerSource - 0 if a UTLB or General exception occurred.
+ - 1 if an NMI_EXCEPTION occurred.
+ - 2 if a CACHE_EXCEPTION occurred.
+ - 3 if the caller is not an exception handler.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ CHAR Buffer[2][128];
+ ULONG ParityDiag[3];
+ PULONG ParDiag;
+ ULONG BufferIndex;
+ PCHAR Argv[10];
+ PCHAR Tmp;
+ CHAR String[128];
+ BOOLEAN CommandValid;
+ GETSTRING_ACTION Action;
+ ULONG Index;
+
+ JzSetScreenAttributes( TRUE, FALSE, FALSE);
+
+#ifdef DUO
+ //
+ // Set text White for processor A. Yellow for processor B
+ //
+ if (READ_REGISTER_ULONG(&DMA_CONTROL->WhoAmI.Long) == 0) {
+ JzSetScreenColor(ArcColorWhite, ArcColorBlue);
+ } else {
+ JzSetScreenColor(ArcColorYellow, ArcColorBlue);
+ }
+#else
+ JzSetScreenColor(ArcColorWhite, ArcColorBlue);
+#endif
+
+ FwPrint(MON_JAZZ_MONITOR_MSG);
+ sprintf(String,"%ld\r\n",*(PULONG)(PROM_ENTRY(2)));
+ FwPrint(String);
+ FwPrint(MON_PRESS_H_MSG);
+
+ //
+ // Initialize command line to null.
+ //
+ Argv[0] = (PCHAR)NULL;
+
+ if (CallerSource !=3) {
+
+ //
+ // Display Cause of exception.
+ //
+
+ switch(CallerSource) {
+ case 0:
+ FwPrint(ExceptionNameTable[((RegisterTable[cause])&0xFF) >> 2]);
+ break;
+ case NMI_EXCEPTION:
+ FwPrint(MON_NMI_MSG);
+ break;
+ case CACHE_EXCEPTION:
+ FwPrint(MON_CACHE_ERROR_MSG);
+ break;
+ }
+ FwPrint(MON_EXCEPTION_MSG);
+
+ //
+ // simulate a dump all registers command;
+ //
+
+ Argc = 1;
+ RegisterCommand(Argv);
+ Argc = 0;
+ }
+ //
+ // Initialize Static variables.
+ //
+ DefaultAddress = KSEG1_BASE;
+ DataSize = WORD;
+ BufferIndex = 0;
+
+#ifdef DUO
+//
+// Report system parity exceptions.
+//
+//
+ if ((((RegisterTable[cause]&R4000_XCODE_MASK) == XCODE_DATA_BUS_ERROR) ||
+ ((RegisterTable[cause]&R4000_XCODE_MASK) == XCODE_INSTRUCTION_BUS_ERROR)) &&
+ (READ_REGISTER_ULONG(&DMA_CONTROL->NmiSource.Long) == 1)) {
+
+ //
+ // This is a bus error exception. And the cause is ecc error.
+ //
+
+ sprintf(String,
+ MON_ECC_ERROR_MSG,
+ RegisterTable[epc]
+ );
+ FwPrint(String);
+
+ //
+ // align ParDiag to a double word address
+ //
+ ParDiag = (PULONG) ((ULONG)(&ParityDiag[1]) & 0xFFFFFFF8);
+ LoadDoubleWord(&DMA_CONTROL->EccDiagnostic,ParDiag);
+ sprintf(String,
+ MON_MEM_ECC_FAILED_MSG,
+ READ_REGISTER_ULONG(&DMA_CONTROL->MemoryFailedAddress.Long),
+ *ParDiag,
+ *(ParDiag+1)
+ );
+
+
+ }
+
+#endif
+
+
+ if (CallerSource == CACHE_EXCEPTION) {
+
+ //
+ // try to print as much info as possible.
+ //
+ sprintf(String,
+ MON_CACHE_ERROR_EPC_MSG,
+ RegisterTable[cacheerror],
+ RegisterTable[errorepc]
+ );
+ FwPrint(String);
+
+#ifndef DUO
+//
+// Do not print Parity Diag for a DUO CacheError exception since it's only
+// an internal one.
+//
+ //
+ // align ParDiag to a double word address
+ //
+ ParDiag = (PULONG) ((ULONG)(&ParityDiag[1]) & 0xFFFFFFF8);
+ LoadDoubleWord(&DMA_CONTROL->ParityDiagnosticLow.Long,ParDiag);
+ sprintf(String,
+ MON_PARITY_DIAG_MSG,
+ *ParDiag,
+ *(ParDiag+1)
+ );
+ FwPrint(String);
+
+#endif
+
+ //
+ // Now we will probably die, as the keyboard is interrupt
+ // driven and the interrupt handler is cached... Life is Tough!
+ //
+ }
+
+ //
+ // loop forever getting commands and dispatching them
+ //
+ while(TRUE) {
+
+ //
+ // print prompt
+ //
+
+ FwPrint(">");
+
+ //
+ // read a command.
+ //
+
+ do {
+ Action = FwGetString(Buffer[BufferIndex],128,NULL,FwRow,FwColumn);
+ } while ((Action != GetStringSuccess) && (Action != GetStringEscape));
+ FwPrint(FW_CRLF_MSG);
+
+ //
+ // convert string to lower case.
+ //
+
+ for(Tmp=Buffer[BufferIndex];*Tmp;*Tmp++) {
+ *Tmp=tolower(*Tmp);
+ }
+
+ //
+ // if escape was pressed, simulate a quit command.
+ //
+
+ if (Action == GetStringEscape) {
+ Argc = 1;
+ Argv[0] = "q";
+
+ //
+ // separate command line into tokens delimited by spaces
+ // load up Argv with pointers to arguments and put count in Argc
+ //
+
+ } else if (*Buffer[BufferIndex] != '\0') {
+ Tmp = Buffer[BufferIndex];
+ Argc = 0;
+ //
+ // Skip leading blanks
+ //
+ while ( *Tmp == ' ') {
+ Tmp++;
+ }
+ while ( *Tmp ) {
+ Argv[Argc++] = Tmp;
+ while ( *Tmp ) {
+ if (*Tmp == ' ') {
+ *Tmp++ = '\0';
+ while ( *Tmp == ' ') {
+ Tmp++;
+ }
+ break;
+ }
+ Tmp++;
+ }
+ }
+
+ //if ((Argv[Argc] = strtok(Buffer[BufferIndex]," ")) != NULL) {
+ // Argc++;
+ // while((Argv[Argc]=strtok((PCHAR)NULL," ")) != NULL) {
+ // Argc++;
+ // }
+ //}
+
+ //
+ // Increment index so that next command is read into the other
+ // buffer. And we preserve the previous one.
+ //
+
+ BufferIndex = (BufferIndex+1) & 0x1;
+ } else {
+
+ //
+ // repeat the last command already in Argv Argc
+ //
+
+ }
+
+ //
+ // if first argument is not null, then dispatch to routines.
+ //
+
+ if (Argv[0] != (PCHAR) NULL) {
+ CurrentArg = 1;
+ CurrentCommand = GetCommand(Argv[0]);
+ switch(CurrentCommand) {
+ case DumpByte:
+ case DumpWord:
+ case DumpDouble:
+ DataSizeShift = (CurrentCommand - Dump -1);
+ DataSize = 1 << DataSizeShift;
+ DataSizeMask = DataSize-1;
+ case Dump:
+ CommandValid = DumpCommand(Argv);
+ break;
+
+ case EnterByte:
+ case EnterWord:
+ case EnterDouble:
+ DataSizeShift = (CurrentCommand - Enter -1);
+ DataSize = 1 << DataSizeShift;
+ DataSizeMask = DataSize-1;
+ case Enter:
+ CommandValid = EnterCommand(Argv);
+ break;
+
+ case OutputByte:
+ case OutputWord:
+ case OutputDouble:
+ DataSizeShift = (CurrentCommand - Output -1);
+ DataSize = 1 << DataSizeShift;
+ DataSizeMask = DataSize-1;
+ case Output:
+ CommandValid = OutputCommand(Argv);
+ break;
+ case InputByte:
+ case InputWord:
+ case InputDouble:
+ DataSizeShift = (CurrentCommand - Input -1);
+ DataSize = 1 << DataSizeShift;
+ DataSizeMask = DataSize-1;
+ case Input:
+ CommandValid = InputCommand(Argv);
+ break;
+ case Register:
+ CommandValid = RegisterCommand(Argv);
+ break;
+ case Zero:
+ CommandValid = ZeroCommand(Argv);
+ break;
+ case Fill:
+ CommandValid = FillCommand(Argv);
+ break;
+ case AvailableDevices:
+ CommandValid = FwDumpLookupTable(Argv);
+ break;
+ case Help:
+ case Help2:
+ for (Index = 0 ; Index < MON_HELP_SIZE ; Index++) {
+ FwPrint(MON_HELP_TABLE[Index]);
+ FwPrint(FW_CRLF_MSG);
+ }
+ break;
+#ifdef DUO
+ case SwitchProcessor:
+ if (ProcessorBEnabled == FALSE) {
+ FwPrint(MON_PROCESSOR_B_MSG);
+ break;
+ }
+ if (READ_REGISTER_ULONG(&DMA_CONTROL->WhoAmI.Long) == 0) {
+ PPROCESSOR_B_TASK_VECTOR TaskVector;
+
+ //
+ // Set the monitor entry point in the TaskVector
+ //
+ TaskVector = (PPROCESSOR_B_TASK_VECTOR)&ProcessorBTask;
+ TaskVector->Routine = FwMonitor;
+ TaskVector->Data = 0;
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
+ WaitForIpInterrupt(0);
+ JzSetScreenColor(ArcColorWhite, ArcColorBlue);
+ break;
+ }
+
+ //
+ // if processor B then do the same as in a quit command.
+ //
+#endif
+ case Quit:
+ if (CallerSource == 3) {
+ return;
+ } else {
+ //
+ // We came because of an exception.
+ // The only way to exit is reseting the system.
+ //
+ FwPrint(MON_NO_RETURN_MSG);
+ FwPrint(MON_RESET_MACHINE_MSG);
+
+ do {
+ Action = FwGetString(Buffer[BufferIndex],128,NULL,FwRow,FwColumn);
+ } while ((Action != GetStringSuccess) && (Action != GetStringEscape));
+ FwPrint(FW_CRLF_MSG);
+
+ Buffer[BufferIndex][0]=tolower(Buffer[BufferIndex][0]);
+ if (strcmp(Buffer[BufferIndex],"y") == 0) {
+ ResetSystem();
+ // ArcReboot();
+ }
+ break;
+ }
+ case invalidcommand:
+ FwPrint(MON_UNRECOGNIZED_COMMAND_MSG);
+ //
+ // Clear the argument so that re-do last command
+ // doesn't repeat the erroneous command.
+ //
+ CommandValid = FALSE;
+ break;
+ }
+
+ if (!CommandValid) {
+ Argv[0] = (PCHAR) NULL;
+ }
+ }
+ }
+}
diff --git a/private/ntos/fw/mips/monitor.h b/private/ntos/fw/mips/monitor.h
new file mode 100644
index 000000000..8ed220345
--- /dev/null
+++ b/private/ntos/fw/mips/monitor.h
@@ -0,0 +1,159 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ monitor.h
+
+Abstract:
+
+ This module contains definitions for monitor.c
+
+Author:
+
+ Lluis Abello (lluis) 09-Sep-1991
+
+Revision History:
+
+--*/
+
+#ifndef _MONITOR_
+#define _MONITOR_
+
+//
+// Define register names.
+//
+typedef enum _REGISTER_NAME_ID {
+ zero, // general register 0
+ at, // general register 1
+ v0, // general register 2
+ v1, // general register 3
+ a0, // general register 4
+ a1, // general register 5
+ a2, // general register 6
+ a3, // general register 7
+ t0, // general register 8
+ t1, // general register 9
+ t2, // general register 10
+ t3, // general register 11
+ t4, // general register 12
+ t5, // general register 13
+ t6, // general register 14
+ t7, // general register 15
+ s0, // general register 16
+ s1, // general register 17
+ s2, // general register 18
+ s3, // general register 19
+ s4, // general register 20
+ s5, // general register 21
+ s6, // general register 22
+ s7, // general register 23
+ t8, // general register 24
+ t9, // general register 25
+ k0, // general register 26
+ k1, // general register 27
+ gp, // general register 28
+ sp, // general register 29
+ s8, // general register 30
+ ra, // general register 31
+ f0, // fp register 0
+ f1, // fp register 1
+ f2, // fp register 2
+ f3, // fp register 3
+ f4, // fp register 4
+ f5, // fp register 5
+ f6, // fp register 6
+ f7, // fp register 7
+ f8, // fp register 8
+ f9, // fp register 9
+ f10, // fp register 10
+ f11, // fp register 11
+ f12, // fp register 12
+ f13, // fp register 13
+ f14, // fp register 14
+ f15, // fp register 15
+ f16, // fp register 16
+ f17, // fp register 17
+ f18, // fp register 18
+ f19, // fp register 19
+ f20, // fp register 20
+ f21, // fp register 21
+ f22, // fp register 22
+ f23, // fp register 23
+ f24, // fp register 24
+ f25, // fp register 25
+ f26, // fp register 26
+ f27, // fp register 27
+ f28, // fp register 28
+ f29, // fp register 29
+ f30, // fp register 30
+ f31, // fp register 31
+ fsr, // fp status register
+ index, // cop0 register 0
+ random, // cop0 register 1
+ entrylo0, // cop0 register 2
+ entrylo1, // cop0 register 3
+ context, // cop0 register 4
+ pagemask, // cop0 register 5
+ wired, // cop0 register 6
+ badvaddr, // cop0 register 8
+ count, // cop0 register 9
+ entryhi, // cop0 register 10
+ compare, // cop0 register 11
+ psr, // cop0 register 12
+ cause, // cop0 register 13
+ epc, // cop0 register 14
+ prid, // cop0 register 15
+ config, // cop0 register 16
+ lladdr, // cop0 register 17
+ watchlo, // cop0 register 18
+ watchhi, // cop0 register 19
+ ecc, // cop0 register 26
+ cacheerror, // cop0 register 27
+ taglo, // cop0 register 28
+ taghi, // cop0 register 29
+ errorepc, // cop0 register 30
+ invalidregister
+} REGISTER_NAME_ID;
+
+extern PCHAR RegisterNameTable[(REGISTER_NAME_ID)invalidregister];
+
+extern ULONG RegisterTable[(REGISTER_NAME_ID)invalidregister];
+
+//
+// Define Command names.
+//
+typedef enum _COMMAND_NAME_ID {
+ Dump,
+ DumpByte,
+ DumpWord,
+ DumpDouble,
+ Enter,
+ EnterByte,
+ EnterWord,
+ EnterDouble,
+ Output,
+ OutputByte,
+ OutputWord,
+ OutputDouble,
+ Input,
+ InputByte,
+ InputWord,
+ InputDouble,
+ Register,
+ Zero,
+ Fill,
+ AvailableDevices,
+ Help,
+ Help2,
+#ifdef DUO
+ SwitchProcessor,
+#endif
+ Quit,
+ invalidcommand
+} COMMAND_NAME_ID;
+
+extern PCHAR CommandNameTable[(COMMAND_NAME_ID)invalidcommand];
+
+#endif // _MONITOR_
diff --git a/private/ntos/fw/mips/oli2msft.h b/private/ntos/fw/mips/oli2msft.h
new file mode 100644
index 000000000..2733d4503
--- /dev/null
+++ b/private/ntos/fw/mips/oli2msft.h
@@ -0,0 +1,39 @@
+
+// ----------------------------------------------------------------------------
+// File: oli2msft.h
+//
+// Description: General type definitions used in C files by Olivetti and
+// not Microsoft
+//
+// ----------------------------------------------------------------------------
+
+typedef ULONG BOOLEAN_ULONG;
+typedef BOOLEAN_ULONG *PBOOLEAN_ULONG;
+
+//
+// Configuration related defines
+//
+
+#define MAX_MNEMONIC_LEN 20 // max name length (with '\0')
+#define MAX_DEVICE_PATH_LEN 63 // ending '\0' excluded
+#define MAX_FILE_PATH_LEN 127 // ending '\0' excluded
+#define MAX_PATH_LEN (MAX_DEVICE_PATH_LEN + MAX_FILE_PATH_LEN)
+#define KEY_MAX_DIGITS 4 // max digits within a "key
+ // string" (\'0' not included).
+//
+// Configuration Data Header
+//
+
+typedef struct _CONFIGDATAHEADER
+ {
+ USHORT Version;
+ USHORT Revision;
+ PCHAR Type;
+ PCHAR Vendor;
+ PCHAR ProductName;
+ PCHAR SerialNumber;
+ } CONFIGDATAHEADER, *PCONFIGDATAHEADER;
+
+#define CONFIGDATAHEADER_SIZE sizeof(CONFIGDATAHEADER)
+
+#define MAXIMUM_SECTOR_SIZE 2048 // # bytes per sector
diff --git a/private/ntos/fw/mips/omf.c b/private/ntos/fw/mips/omf.c
new file mode 100644
index 000000000..67cbc466e
--- /dev/null
+++ b/private/ntos/fw/mips/omf.c
@@ -0,0 +1,3791 @@
+// ----------------------------------------------------------------------------
+//
+// Copyright (c) 1992 Olivetti
+//
+// File: omf.c
+//
+// Description: this code implements the omf protocol as defined
+// in the ARC-EISA addendum.
+//
+// ----------------------------------------------------------------------------
+
+#include "fwp.h"
+#include "oli2msft.h"
+#include "arceisa.h"
+#include "inc.h"
+#include "string.h"
+#include "debug.h"
+
+extern BL_FILE_TABLE BlFileTable [BL_FILE_TABLE_SIZE];
+
+#define DEVICE_DEVICE 0xDEAD
+
+
+// ----------------------------------------------------------------------------
+// Declare Function Prototypes
+// ----------------------------------------------------------------------------
+
+ARC_STATUS
+OmfOpen
+ (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ IN OUT PULONG FileId
+ );
+
+ARC_STATUS
+OmfClose
+ (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+OmfMount
+ (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ );
+
+ARC_STATUS
+OmfRead
+ (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+OmfWrite
+ (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+OmfGetReadStatus
+ (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+OmfSeek
+ (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+OmfGetFileInformation
+ (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ );
+
+ARC_STATUS
+OmfSetFileInformation
+ (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ );
+
+ARC_STATUS
+OmfGetDirectoryEntry
+ (
+ IN ULONG FileId,
+ IN DIRECTORY_ENTRY *DirEntry,
+ IN ULONG NumberDir,
+ OUT PULONG CountDir
+ );
+
+ARC_STATUS
+OmfFileOpen
+ (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ IN OUT PULONG FileId
+ );
+
+ARC_STATUS
+OmfFileClose
+ (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+OmfFileMount
+ (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ );
+
+ARC_STATUS
+OmfFileRead
+ (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+OmfFileWrite
+ (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ );
+
+ARC_STATUS
+OmfFileGetReadStatus
+ (
+ IN ULONG FileId
+ );
+
+ARC_STATUS
+OmfFileSeek
+ (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ );
+
+ARC_STATUS
+OmfFileGetFileInformation
+ (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ );
+
+ARC_STATUS
+OmfFileSetFileInformation
+ (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ );
+
+ARC_STATUS
+OmfFileGetDirectoryEntry
+ (
+ IN ULONG FileId,
+ IN DIRECTORY_ENTRY *DirEntry,
+ IN ULONG NumberDir,
+ OUT PULONG CountDir
+ );
+
+BOOLEAN
+MaxOmfFatFiles
+ (
+ IN OUT PCHAR MasterName,
+ IN PCHAR CheckedName
+ );
+
+BOOLEAN
+OmfFileNameValidate
+ (
+ IN PCHAR OpenPath,
+ OUT PCHAR OmfFileName,
+ OUT PCHAR OmfType
+ );
+
+BOOLEAN
+CmpOmfFiles
+ (
+ IN PCHAR OmfFileName,
+ IN CHAR OmfType,
+ IN POMF_DIR_ENT POmfDirEnt
+ );
+
+BOOLEAN
+OmfHeaderValidate
+ (
+ IN ULONG FileId
+ );
+
+BOOLEAN
+OmfFileValidate
+ (
+ IN ULONG FileId
+ );
+
+VOID
+ConvertOmfDirToArcDir
+ (
+ IN POMF_DIR_ENT POmfDirEnt,
+ OUT DIRECTORY_ENTRY *PArcDirEnt
+ );
+
+BOOLEAN
+FwGetEisaId
+ (
+ IN PCHAR PathName,
+ OUT PCHAR EisaId,
+ OUT PUCHAR IdInfo
+ );
+
+VOID
+FwUncompressEisaId
+ (
+ IN PUCHAR CompEisaId,
+ OUT PUCHAR UncompEisaId
+ );
+
+BOOLEAN
+FwGetEisaBusIoCpuAddress
+ (
+ IN PCHAR EisaPath,
+ OUT PVOID *IoBusAddress
+ );
+
+PCHAR
+FwGetEnvironmentVariable
+ (
+ IN PCHAR Variable
+ );
+
+PCONFIGURATION_COMPONENT
+FwGetComponent
+ (
+ IN PCHAR Pathname
+ );
+
+LARGE_INTEGER
+RtlConvertUlongToLargeInteger
+ (
+ IN ULONG UnsignedInteger
+ );
+
+LARGE_INTEGER
+RtlLargeIntegerAdd
+ (
+ IN LARGE_INTEGER Addend1,
+ IN LARGE_INTEGER Addend2
+ );
+
+ARC_STATUS
+FwFileIdChecksum
+ (
+ IN ULONG FileId,
+ IN LARGE_INTEGER StartingOffset,
+ IN ULONG Length,
+ IN OUT PUCHAR Checksum
+ );
+
+BOOLEAN
+FwGetMnemonicKey
+ (
+ IN PCHAR Path,
+ IN PCHAR Mnemonic,
+ IN PULONG Key
+ );
+
+BOOLEAN
+FwGetNextMnemonic
+ (
+ IN PCHAR Path,
+ IN PCHAR Mnemonic,
+ OUT PCHAR NextMnemonic
+ );
+
+BOOLEAN
+FwGetMnemonicPath
+ (
+ IN PCHAR Path,
+ IN PCHAR Mnemonic,
+ OUT PCHAR MnemonicPath
+ );
+
+BOOLEAN
+GetNextPath
+ (
+ IN OUT PCHAR *PPathList,
+ OUT PCHAR PathTarget
+ );
+
+
+// ----------------------------------------------------------------------------
+// Global Data
+// ----------------------------------------------------------------------------
+
+//
+// Omf entry table.
+// This is a structure that provides entry to the OMF system procedures.
+// It is exported when a OMF is opened as a device.
+//
+
+BL_DEVICE_ENTRY_TABLE OmfEntryTable =
+ {
+ OmfClose,
+ OmfMount,
+ OmfOpen,
+ OmfRead,
+ OmfGetReadStatus,
+ OmfSeek,
+ OmfWrite,
+ OmfGetFileInformation,
+ OmfSetFileInformation,
+ OmfGetDirectoryEntry
+ };
+
+
+//
+// Omf file entry table.
+// This is a structure that provides entry to the OMF file system procedures.
+// It is exported when a OMF file is opened.
+//
+
+BL_DEVICE_ENTRY_TABLE OmfFileEntryTable =
+ {
+ OmfFileClose,
+ OmfFileMount,
+ OmfFileOpen,
+ OmfFileRead,
+ OmfFileGetReadStatus,
+ OmfFileSeek,
+ OmfFileWrite,
+ OmfFileGetFileInformation,
+ OmfFileSetFileInformation,
+ OmfFileGetDirectoryEntry
+ };
+
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfOpen:
+//
+// DESCRIPTION: The routine opens the newest version/revision of OMF for
+// the specified Product ID.
+//
+// a) It reads the EISAROM bit of the <device> component of
+// the Path argument on the EISA bus spcified by the key of
+// the <adapter> component of Path argument.
+// b) If this bit is one, then a byte checksum is performed on
+// the ROM-based OMF header and OMF directory.
+// The Product ID, Firmware Version and Revision fields
+// values are retained for the next operations.
+// c) Next, the partitions, specified by the FWSearchPath
+// environment variable are searched for files of the
+// following form in the \eisa\omf subdirectory:
+//
+// <device>"V".LF"R"
+//
+// <device> = EISA Product ID (7 chars)
+// "V" = version ([0-9],[A-Z])
+// "R" = revision ([0-9],[A-Z])
+//
+// d) The OMF FAT file (or ROM) with a greater value of version-
+// revision and with a correct checksum is used.
+// f) Initialize some data structures
+//
+// When Open is used to access an OMF as a raw device, all input
+// functions are permitted. These functions include Read, Seek
+// and Close. Read and Seek are bounded by the current OMF size.
+// For example, to read the OMF of a serial options board that was
+// in slot 3 of EISA bus 0 as raw device, create and Open a path
+// as follows: eisa(0)serial(3)omf() .
+//
+// ARGUMENTS: OpenPath Supplies a pointer to a zero terminated device
+// path name.
+// OpenMode Supplies the mode of the open.
+// FileId Supplies a pointer to a variable that specifies
+// the file table entry that is to be filled in
+// if the open is successful.
+//
+// RETURN: ESUCCESS is returned if the open operation is successful.
+// ENODEV the device portion of the pathname is invalid
+//
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfOpen
+ (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ IN OUT PULONG FileId
+ )
+{
+ //
+ // initialize local variables
+ //
+
+ LARGE_INTEGER Offset; // large interger for seek operations
+ ULONG SlotNumber; // eisa slot number
+ CHAR EisaCtrlMnemonic[ MAX_MNEMONIC_LEN +1 ]; // eisa ctrl mnemonic name
+ UCHAR IdInfo; // info id byte
+ PVOID IoBusAddress; // eisa I/O base address (virtual)
+ PUCHAR SlotAddress; // I/O address
+ BOOLEAN OmfRomOk=FALSE; // OMF ROM initialization flag
+ BOOLEAN OmfFatFileOk=FALSE; // OMF FAT file initialization flag
+ ULONG Count; // # of bytes transferred
+ PCHAR PFwSearchPath; // system partitions list pointer
+ CHAR OmfPathName[MAX_PATH_LEN +1]; // directory+subdirectory+file name
+ CHAR OmfPathBuffer[MAX_PATH_LEN +1] = {'\0'}; // OMF path name buffer
+ CHAR OmfFatFileName[]=" .LF "; // omf name (FAT format)
+
+ ULONG OmfSubdirId; // file Id of \eisa\omf subdirectory
+ POMF_HEADER_CONTEXT POmfHeaderContext; // OMF header context pointer
+ POMF_HDR POmfHeader; // pointer to OMF ROM/FAT file header
+ DIRECTORY_ENTRY DirEntBuffer; // ARC directory entry
+
+ PRINTDBG("OmfOpen\n\r"); // debug support
+
+ //
+ // this is a read only device
+ //
+
+ if ( OpenMode != ArcOpenReadOnly )
+ {
+ return EROFS;
+ }
+
+ //
+ // The path must have the following form : eisa(x)"mnemonic"(y)omf()
+ // Get EISA ID, slot number and its I/O address space.
+ //
+
+ if ( !FwGetNextMnemonic( OpenPath, "eisa", EisaCtrlMnemonic )
+ ||
+ !FwGetMnemonicKey( OpenPath, EisaCtrlMnemonic, &SlotNumber )
+ ||
+ !FwGetMnemonicPath( OpenPath, EisaCtrlMnemonic, OmfPathName )
+ ||
+ !FwGetEisaId( OmfPathName, OmfFatFileName, &IdInfo )
+ ||
+ !FwGetMnemonicPath( OpenPath,"eisa",OmfPathName )
+ ||
+ !FwGetEisaBusIoCpuAddress( OmfPathName, &IoBusAddress ) )
+ {
+ return ENODEV;
+ }
+
+ //
+ // Initialize some variables
+ //
+
+ POmfHeaderContext = &BlFileTable[ *FileId ].u.OmfHeaderContext;
+ POmfHeader = &POmfHeaderContext->OmfHeader;
+ SlotAddress = (PUCHAR)IoBusAddress + SlotNumber * 0x1000;
+ Offset.LowPart = 0; // seek operation
+ Offset.HighPart = 0; // seek operation
+
+ //
+ // Check EISAROM bit of the Expansion Board Control Bits field.
+ // If the EISA ID is readable, the controller supports the EISA extensions
+ //
+
+ // DEBUG-DEBUG : for now skip the OMF ROM check because
+ // at the moment there isn't any board available
+ // with an OMF ROM to test the routine.
+
+ if (0)
+ //if ( !(IdInfo & CFG_UNREADABLE_ID) &&
+ // READ_REGISTER_UCHAR( SlotAddress + EXPANSION_BOARD_CTRL_BITS ) &
+ // EISAROMBIT )
+ {
+ //
+ // initialize some fields to direct the OmfRead to the ROM
+ //
+
+ POmfHeaderContext->RomIndex = (PULONG)(SlotAddress+ROMINDEX);
+ POmfHeaderContext->RomRead = (PULONG)(SlotAddress+ROMREAD);
+ POmfHeaderContext->FileId = DEVICE_DEVICE;
+ POmfHeader->FwSize = 0; // max length simulation
+
+ //
+ // check OMF ROM header, copy it in the OmfHeaderContext structure
+ //
+
+ if ( !OmfSeek( *FileId, &Offset, SeekAbsolute)
+ &&
+ !OmfRead( *FileId,
+ (PVOID)POmfHeader,
+ (ULONG)sizeof(OMF_HDR),
+ &Count )
+ &&
+ OmfHeaderValidate( *FileId ) )
+ {
+ //
+ // copy version and revision
+ //
+
+ ((POMF_FAT_FILE_NAME)OmfFatFileName)->Version =
+ POmfHeader->FwVersion;
+ ((POMF_FAT_FILE_NAME)OmfFatFileName)->Revision =
+ POmfHeader->FwRevision;
+ //
+ // OMF ROM initialization has been done
+ //
+
+ OmfRomOk=TRUE;
+ }
+ }
+
+ //
+ // Set the current FileId to "open" so that calls to FwOpen won't use
+ // this FileId. This will get reset later.
+ //
+
+ BlFileTable[ *FileId ].Flags.Open = 1;
+
+ //
+ // check now if there is any file that upgrate the OFM ROM firmware.
+ // the partitions, specified by the FWSearchPath environment variable,
+ // are searched for files of the following form in the \eisa\omf
+ // subdirectory:
+ // <device>"V".LF"R"
+ //
+ // <device> = EISA Product ID (7 chars)
+ // "V" = version ([0-9],[A-Z])
+ // "R" = revision ([0-9],[A-Z])
+ //
+
+ if ( (PFwSearchPath = FwGetEnvironmentVariable("FWSearchPath")) != NULL )
+ {
+ //
+ // check all the directories specified by FWSearchPath
+ //
+
+ while ( GetNextPath( &PFwSearchPath, OmfPathName ))
+ {
+ //
+ // open the directory
+ //
+
+ strcat(OmfPathName, "\\eisa\\omf" );
+
+ if ( FwOpen( OmfPathName, ArcOpenDirectory, &OmfSubdirId ))
+ {
+ //
+ // Go check next path
+ //
+
+ continue;
+ }
+
+ //
+ // Check all files within the directory
+ //
+
+ while (!FwGetDirectoryEntry ( OmfSubdirId, &DirEntBuffer,
+ (ULONG) 1, &Count) )
+ {
+ //
+ // check directory flag, length of file name and file name
+ //
+
+ if ( !( DirEntBuffer.FileAttribute & ArcDirectoryFile )
+ &&
+ DirEntBuffer.FileNameLength
+ &&
+ MaxOmfFatFiles( OmfFatFileName, DirEntBuffer.FileName ))
+ {
+ //
+ // correct name, save file path
+ //
+
+ strcat( strcpy(OmfPathBuffer, OmfPathName), "\\" );
+ strcat(OmfPathBuffer, OmfFatFileName);
+ }
+ }
+
+ //
+ // close directory before opening the next
+ //
+
+ FwClose( OmfSubdirId );
+ }
+ }
+
+ //
+ // check for a valid OMF FAT file name
+ //
+
+ if ( OmfPathBuffer[0] )
+ {
+ //
+ // open file
+ //
+
+ if (FwOpen(OmfPathBuffer, ArcOpenReadOnly, &POmfHeaderContext->FileId))
+ {
+ //
+ // return with error
+ //
+
+ BlFileTable[ *FileId ].Flags.Open = 0;
+ return ENODEV;
+ }
+
+ POmfHeader->FwSize=0; // max length simulation
+
+ //
+ // validate header and copy data in the OmfHeaderContext structure
+ //
+
+ if ( OmfSeek( *FileId, &Offset, SeekAbsolute )
+ ||
+ OmfRead( *FileId,
+ (PVOID)POmfHeader,
+ (ULONG)sizeof(OMF_HDR),
+ &Count)
+ ||
+ !OmfHeaderValidate( *FileId ) )
+ {
+
+ PRINTDBG("No OK\n\r");
+
+ //
+ // close file and return with error
+ //
+
+ FwClose(POmfHeaderContext->FileId);
+ BlFileTable[ *FileId ].Flags.Open = 0;
+ return ENODEV;
+ }
+
+ //
+ // OMF FAT file initialization is done.
+ //
+
+ PRINTDBG("It's OK\n\r");
+
+ OmfFatFileOk=TRUE;
+ }
+
+ //
+ // Reset the open flag.
+ //
+
+ BlFileTable[ *FileId ].Flags.Open = 0;
+
+ //
+ // if OMF initialization not done, return error
+ //
+
+// if ( !OmfRomOk && !OmfFatFileOk )
+ if ( !OmfFatFileOk )
+ {
+ return ENOENT;
+ }
+ else
+ {
+ BlFileTable[ *FileId ].Position.LowPart=0;
+ BlFileTable[ *FileId ].Position.HighPart=0;
+ return ESUCCESS;
+ }
+}
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfClose:
+//
+// DESCRIPTION: The routine closes the file table entry specified by file id.
+// If a OMF FAT file has been used, the routine calls the FwClose
+// function using its file table entry (file id).
+// the routine uses the following logic :
+//
+// if (OMF FAT file)
+// {
+// close file;
+// if (error closing file)
+// return error;
+// }
+// reset open flag;
+// return ok;
+//
+// ARGUMENTS: FileId Supplies a pointer to a variable that specifies
+// the file table entry.
+//
+// RETURN: ESUCCESS is returned if the open operation is successful.
+// EBADF invalid file descriptor
+//
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfClose
+ (
+ IN ULONG FileId
+ )
+{
+ //
+ // initialize local variables
+ //
+
+ ARC_STATUS Status; // store return status from FwClose
+
+ //
+ // if OMF FAT file is used, call FwClose using its file table index
+ //
+
+ PRINTDBG("OmfClose\n\r");
+
+ if ( BlFileTable[ FileId ].DeviceId != DEVICE_DEVICE)
+ {
+ return EBADF;
+ }
+
+ if ( BlFileTable[ FileId ].u.OmfHeaderContext.FileId != DEVICE_DEVICE
+ &&
+ (Status = FwClose( BlFileTable[ FileId ].u.OmfHeaderContext.FileId)))
+ {
+ return Status;
+ }
+
+ //
+ // all done, return ok
+ //
+
+ BlFileTable[ FileId ].Flags.Open = 0;
+ return ESUCCESS;
+}
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfMount:
+//
+// DESCRIPTION: The routine does nothing and return EBADF.
+//
+// ARGUMENTS: MountPath device path specifier.
+// Operation mount operation (load/unload).
+//
+// RETURN: EBADF invalid operation
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfMount
+ (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ )
+{
+ //
+ // return error : invalid operation.
+ //
+
+ return EBADF;
+}
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfRead:
+//
+// DESCRIPTION: This routine implements the read operation for the ARC-EISA
+// firmware "OMF" driver.
+//
+// ARGUMENTS: FileId Supplies a pointer to a variable that specifies
+// the file table entry.
+// Buffer Supplies a pointer to a buffer where the
+// characters read will be stored.
+// Length Supplies the length of Buffer.
+// Count Return the count of the characters that
+// were read.
+//
+// RETURN: ESUCCESS is returned if the open operation is successful.
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfRead
+ (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+{
+
+ //
+ // initialize local variables
+ //
+
+ ARC_STATUS Status; // ARC status
+ POMF_HEADER_CONTEXT POmfHeaderContext; // OMF header context pointer
+ ULONG OmfSize; // OMF firmware size (bytes)
+ PLARGE_INTEGER PPosition; // file/device position field pointer
+ USHORT ByteIndex; // byte index within the word
+ ULONG WordBuffer; // 1 word buffer
+
+
+ PRINTDBG("OmfRead\n\r");
+
+ //
+ // Initialize some variables
+ //
+
+ POmfHeaderContext = &BlFileTable[ FileId ].u.OmfHeaderContext;
+
+ //
+ // compute OMF length in bytes
+ //
+
+ OmfSize = (ULONG)POmfHeaderContext->OmfHeader.FwSize * OMF_BLOCK_SIZE;
+
+ if ( !OmfSize )
+ {
+ OmfSize = OMF_MAX_SIZE;
+ }
+
+ //
+ // initialize byte count read to zero and position variable
+ //
+
+ *Count = 0;
+ PPosition = &BlFileTable[ FileId ].Position;
+
+ //
+ // if length is zero or end of "file", return ESUCCESS.
+ //
+
+ if ( !Length || PPosition->LowPart >= OmfSize )
+ {
+ return ESUCCESS;
+ }
+
+ //
+ // adjust length if it is too big.
+ //
+
+ Length = MIN( Length, OmfSize ); // to prevent the add to overflow
+
+ if ( PPosition->LowPart + Length > OmfSize )
+ {
+ Length = OmfSize - PPosition->LowPart;
+ }
+
+ //
+ // if OMF FAT file, read from file.
+ //
+
+ if ( POmfHeaderContext->FileId != DEVICE_DEVICE )
+ {
+ if ( !(Status = FwSeek( POmfHeaderContext->FileId,
+ PPosition,
+ SeekAbsolute ))
+ &&
+ !(Status = FwRead( POmfHeaderContext->FileId,
+ Buffer,
+ Length,
+ Count )) )
+ {
+ PPosition->LowPart += *Count;
+ }
+ return Status;
+ }
+
+ //
+ // write word index and compute starting byte index (within a word)
+ //
+
+ WRITE_REGISTER_ULONG( POmfHeaderContext->RomIndex,
+ PPosition->LowPart >> WORD_2P2 );
+
+ //
+ // read OMF ROM
+ // one loop per word
+ //
+
+ while ( Length )
+ {
+ ByteIndex = (USHORT) (PPosition->LowPart & (1<<WORD_2P2)-1);
+
+ //
+ // read the whole word if the buffer and OMF pointers are
+ // word aligned.
+ // // |
+ if ( !ByteIndex // DEBUG V
+ &&
+ !((USHORT)((PUCHAR)Buffer + *Count) & (1 << WORD_2P2) -1 ) )
+ {
+ while ( Length >= (1 << WORD_2P2) )
+ {
+ *((PULONG)( (PUCHAR)Buffer + *Count ))=
+ READ_REGISTER_ULONG( POmfHeaderContext->RomRead );
+ *Count += 1<<WORD_2P2;
+ Length -= 1<<WORD_2P2;
+ }
+ }
+
+ //
+ // read the word in bytes units if the buffer or the OMF pointers
+ // are not word aligned or if just part of the word is needed.
+ //
+
+ if ( Length )
+ {
+ WordBuffer = READ_REGISTER_ULONG( POmfHeaderContext->RomRead );
+
+ //
+ // read just the selected bytes
+ //
+
+ while ( ByteIndex < (1 << WORD_2P2) && Length-- )
+ {
+ *( (PUCHAR)Buffer + *Count++ )=
+ (UCHAR)( WordBuffer >> BITSXBYTE * ByteIndex++ );
+ }
+ }
+
+ //
+ // update OMF pointer
+ //
+
+ PPosition->LowPart += *Count;
+ }
+
+ //
+ // return all done
+ //
+
+ return ESUCCESS;
+}
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfWrite:
+//
+// DESCRIPTION: This routine implements the write operation for the ARC-EISA
+// firmware "OMF" driver.
+//
+// ARGUMENTS: FileId Supplies a pointer to a variable that specifies
+// the file table entry.
+// Buffer Supplies a pointer to a buffer where the
+// characters are read.
+// Length Supplies the length of Buffer.
+// Count Return the count of the characters that
+// were written.
+//
+// RETURN: EBADF invalid operation
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfWrite
+ (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+{
+ //
+ // return error : invalid operation
+ //
+
+ return EBADF;
+}
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfGetReadStatus:
+//
+// DESCRIPTION: This routine implements the GetReadStatus operation for the
+// ARC-EISA firmware "OMF" driver.
+//
+// ARGUMENTS: FileId Supplies a pointer to a variable that specifies
+// the file table entry.
+//
+// RETURN: ESUCCESS return always success.
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfGetReadStatus
+ (
+ IN ULONG FileId
+ )
+{
+ //
+ // return ok
+ //
+
+ return ESUCCESS;
+}
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfSeek:
+//
+// DESCRIPTION: This routine implements the Seek operation for the
+// ARC-EISA firmware "OMF" driver.
+//
+// ARGUMENTS: FileId Supplies a pointer to a variable that specifies
+// the file table entry.
+// Offset Supplies the offset in the file to position to.
+// SeekMode Supplies the mode of the seek operation
+//
+// RETURN: ESUCCESS returned if the operation is successful.
+// EINVAL returned otherwise.
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfSeek
+ (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+{
+ //
+ // local variables
+ //
+
+ LARGE_INTEGER Point; // New position
+ ULONG OmfSize; // OMF size in bytes
+
+ PRINTDBG("OmfSeek\n\r");
+
+ //
+ // initialize some variables
+ //
+
+ OmfSize = (ULONG)BlFileTable[ FileId ].u.OmfHeaderContext.OmfHeader.FwSize *
+ OMF_BLOCK_SIZE;
+
+ if ( !OmfSize )
+ {
+ OmfSize=OMF_MAX_SIZE;
+ }
+
+ //
+ // compute new offset value
+ //
+
+ switch( SeekMode )
+ {
+ case SeekAbsolute:
+ Point = *Offset;
+ break;
+ case SeekRelative:
+ Point = RtlLargeIntegerAdd( BlFileTable[FileId].Position, *Offset );
+ break;
+ default:
+ return EINVAL;
+ }
+
+ //
+ // if the high 32 bits are not zero, return an error.
+ // if new offset is valid, update position field.
+ // if the position value 0-based is equal to the OMF size (1-based),
+ // the EOF has been reached. no error is returned in this case and
+ // the count field is set to zero with ESUCCESS error code for any
+ // successive read operation. note that this combination (ESUCCESS and
+ // count=0) is used to rappresent EOF (end of file).
+ //
+
+ if ( Point.HighPart || Point.LowPart > OmfSize )
+ {
+ return EINVAL;
+ }
+ else
+ {
+ BlFileTable[FileId].Position = Point;
+ return ESUCCESS;
+ }
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfGetFileInformation:
+//
+// DESCRIPTION: This routine implements the GetFileInformation for the
+// ARC-EISA firmware "OMF" driver.
+//
+// ARGUMENTS: FileId Supplies the file table index.
+// Buffer Supplies the buffer to receive the file
+// information. Note that it must be large
+// enough to hold the full file name.
+//
+// RETURN: EBADF invalid operation
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfGetFileInformation
+ (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ )
+{
+ //
+ // return error : invalid operation
+ //
+
+ return EBADF;
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfSetFileInformation:
+//
+// DESCRIPTION: This routine implements the SetFileInformation for the
+// ARC-EISA firmware "OMF" driver.
+//
+// ARGUMENTS: FileId Supplies the file table index.
+// AttributeFlags Supplies the value (on or off) for each
+// attribute being modified.
+// AttributeMask Supplies a mask of the attributes being altered.
+// All other file attributes are left alone.
+//
+// RETURN: EBADF invalid operation
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfSetFileInformation
+ (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ )
+{
+ //
+ // return error : invalid operation
+ //
+
+ return EBADF;
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfGetDirectoryEntry:
+//
+// DESCRIPTION: This routine implements the GetDirectoryEntry for the
+// ARC-EISA firmware "OMF" driver.
+//
+// ARGUMENTS: FileId Supplies the file table index.
+// DirEntry Pointer to a directory entry structure
+// NumberDir # of entries to read
+// Count # of entries read
+//
+// RETURN: EBADF directory operations are not supported
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfGetDirectoryEntry
+ (
+ IN ULONG FileId,
+ IN DIRECTORY_ENTRY *DirEntry,
+ IN ULONG NumberDir,
+ OUT PULONG CountDir
+ )
+{
+ //
+ // return error : directory operations are not supported
+ //
+
+ return EBADF;
+}
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfFileOpen:
+//
+// DESCRIPTION: The routine opens the OMF file.
+// The <extension> of the <filename> is optional. The caller can
+// make the following assumptions if the <extension> is not
+// included in the <filename> :
+// . the firmware searches for folders whose type is MIPS first.
+// This is equivalent to using '.A' as the <extension>. If
+// the requested folder of this type is found in the most recent
+// OMF, then this folder is used.
+// . If the modst recent OMF does not contain the requested folder
+// whose type is MIPS, then the SMF searches for the requested
+// folder whose type is BINARY. This is equivalent to using '.B'
+// as the <extension>. If the requested folder of this type is
+// found in the most recent OMF then this folder is used.
+// . If there are no folders with either type in the most recent
+// OMF, the operation fails.
+//
+// When omf() is used as <protocol spec> and the filename is the
+// string "\", the path specification represents the OMF directory.
+// The only valid operation to perform on the OMF directory is to
+// Open it, then use FwGetDirectoryEntry to enumerate the folders
+// within the OMF, and then Close it. For example, to
+// enumerate all folders that are containded in the OMF of a
+// serail options board that was in slot 3 of EISA bus0, create
+// and Open a path as follows : eisa(0)serial(3)omf()\ .
+// To open the diagnostic folder for the above EISA option board
+// the system utilty would create and Open the path specification :
+// eisa(0)serial(3)omf()\T-SERIAL.
+//
+//
+// ARGUMENTS: OpenPath Supplies a pointer to a zero terminated OMF
+// file name.
+// OpenMode Supplies the mode of the open.
+// FileId Supplies the file table entry index
+//
+// RETURN: ESUCCESS is returned if the open operation is successful.
+// ENOENT the named device or file does not exist.
+//
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfFileOpen
+ (
+ IN PCHAR OpenPath,
+ IN OPEN_MODE OpenMode,
+ IN OUT PULONG FileId
+ )
+{
+ //
+ // initialize local variables
+ //
+
+ ARC_STATUS Status; // ARC status
+ ULONG DeviceId; // device table entry index
+ POMF_DIR_ENT POmfDirEnt; // OMF directory entry pointer
+ POMF_HDR POmfHeader; // OMF header pointer
+ LARGE_INTEGER AbsolutePosition; // position
+ ULONG TypeIndex,DirIndex; // general indexes
+ ULONG Count; // # of bytes transferred
+ CHAR OmfFileName[OMF_FILE_NAME_LEN]; // folder name
+ BOOLEAN SearchSucceeded = FALSE; // match flag
+ BOOLEAN IsDirectory = FALSE; // directory flag
+ CHAR OmfType[] = {'A','B','\0'}; // default sequance of search:
+ // relocatable MIPS I object
+ // format binary data format
+ // end of chain
+
+ PRINTDBG("OmfFileOpen\n\r"); // debug support
+
+ //
+ // Initialize some variables
+ //
+
+ DeviceId = BlFileTable[ *FileId ].DeviceId;
+ POmfDirEnt = &BlFileTable[ *FileId ].u.OmfFileContext.OmfDirEnt;
+ POmfHeader = &BlFileTable[ DeviceId ].u.OmfHeaderContext.OmfHeader;
+ AbsolutePosition.HighPart=0; // for seek operations
+
+ //
+ // initialize the file/directory pointer to zero
+ //
+
+ BlFileTable[ *FileId ].Position.LowPart=0;
+ BlFileTable[ *FileId ].Position.HighPart=0;
+
+ //
+ // the first char must be the directory char, otherwise it's an error
+ //
+
+ if ( *OpenPath++ != '\\' );
+
+ //
+ // else check if the open is for the root directory
+ //
+
+ else if ( *OpenPath == '\0' )
+ {
+ POmfDirEnt->FolderName[0]='\0';
+ SearchSucceeded = TRUE;
+ IsDirectory = TRUE;
+ }
+
+ //
+ // else validate OMF file name
+ //
+
+ else if ( !OmfFileNameValidate( OpenPath, OmfFileName, OmfType ));
+
+ //
+ // then search the specified file name
+ //
+
+ else
+ {
+ //
+ // save the omf file name
+ //
+
+ strcpy( BlFileTable[ *FileId ].FileName, OpenPath );
+ BlFileTable[ *FileId ].FileNameLength = strlen( OpenPath );
+
+ //
+ // one loop per file
+ //
+
+ for (TypeIndex = 0; !SearchSucceeded && OmfType[TypeIndex]; TypeIndex++)
+ {
+ //
+ // search the directory for the specified OMF file name
+ //
+
+ for ( DirIndex = 0, AbsolutePosition.LowPart =
+ POmfHeader->FolderDirectoryLink << WORD_2P2;
+
+ DirIndex < POmfHeader->FolderCount && !SearchSucceeded;
+
+ DirIndex++, AbsolutePosition.LowPart += sizeof(OMF_DIR_ENT) )
+ {
+ //
+ // exit if error during seek or read.
+ //
+
+ if ((Status = FwSeek(DeviceId, &AbsolutePosition, SeekAbsolute))
+ ||
+ (Status = FwRead(DeviceId,
+ (PVOID)POmfDirEnt,
+ (ULONG)sizeof(OMF_DIR_ENT),
+ &Count )))
+ {
+ return Status;
+ }
+
+ //
+ // check OMF file name
+ //
+
+ SearchSucceeded = CmpOmfFiles( OmfFileName,
+ OmfType[TypeIndex],
+ (PVOID)POmfDirEnt );
+ }
+ }
+
+ //
+ // if the search has been successful, validate file's header
+ //
+
+ if (SearchSucceeded && !OmfFileValidate( *FileId ))
+ {
+ SearchSucceeded = FALSE;
+ }
+ }
+
+ //
+ // At this point we've cracked the name up to (an maybe including the last
+ // component). We located the last component if the SearchSucceeded flag
+ // is true, otherwise the last component does not exist. If we located
+ // the last component then this is like an open or a supersede, but not a
+ // create.
+ //
+
+ if (SearchSucceeded)
+ {
+ //
+ // Check if the last component is a directory
+ //
+
+ if (IsDirectory)
+ {
+ //
+ // For an existing directory the only valid open mode is
+ // OpenDirectory all other modes return an error
+ //
+
+ switch (OpenMode)
+ {
+
+ case ArcOpenReadOnly:
+ case ArcOpenWriteOnly:
+ case ArcOpenReadWrite:
+ case ArcCreateWriteOnly:
+ case ArcCreateReadWrite:
+ case ArcSupersedeWriteOnly:
+ case ArcSupersedeReadWrite:
+
+ //
+ // if we reach here then the caller got a directory but
+ // didn't want to open a directory
+ //
+
+ return EISDIR;
+
+ case ArcOpenDirectory:
+
+ //
+ // if we reach here then the caller got a directory and
+ // wanted to open a directory.
+ //
+
+ BlFileTable[ *FileId ].Flags.Open = 1;
+ BlFileTable[ *FileId ].Flags.Read = 1;
+
+ return ESUCCESS;
+
+ case ArcCreateDirectory:
+
+ //
+ // if we reach here then the caller got a directory and
+ // wanted to create a new directory
+ //
+
+ return EACCES;
+
+ default:
+
+ //
+ // invalid open mode
+ //
+
+ return EINVAL;
+ }
+ }
+
+ //
+ // If we get there then we have an existing file that is being opened.
+ // We can open existing files only read only.
+ //
+
+ switch (OpenMode)
+ {
+ case ArcOpenReadOnly:
+
+ //
+ // if we reach here then the user got a file and wanted to
+ // open the file read only
+ //
+
+ BlFileTable[ *FileId ].Flags.Open = 1;
+ BlFileTable[ *FileId ].Flags.Read = 1;
+
+ return ESUCCESS;
+
+ case ArcOpenWriteOnly:
+ case ArcOpenReadWrite:
+ case ArcCreateWriteOnly:
+ case ArcCreateReadWrite:
+ case ArcSupersedeWriteOnly:
+ case ArcSupersedeReadWrite:
+
+ //
+ // if we reach here then we are trying to open a read only
+ // device for write.
+ //
+
+ return EROFS;
+
+ case ArcOpenDirectory:
+ case ArcCreateDirectory:
+
+ //
+ // if we reach here then the user got a file and wanted a
+ // directory
+ //
+
+ return ENOTDIR;
+
+ default:
+
+ //
+ // invalid open mode
+ //
+
+ return EINVAL;
+ }
+ }
+
+ //
+ // If we get here the last component does not exist so we are trying to
+ // create either a new file or a directory.
+ //
+
+ switch (OpenMode)
+ {
+ case ArcOpenReadOnly:
+ case ArcOpenWriteOnly:
+ case ArcOpenReadWrite:
+ case ArcOpenDirectory:
+
+ //
+ // if we reach here then the user did not get a file but wanted
+ // a file
+ //
+
+ return ENOENT;
+
+ case ArcCreateWriteOnly:
+ case ArcSupersedeWriteOnly:
+ case ArcCreateReadWrite:
+ case ArcSupersedeReadWrite:
+ case ArcCreateDirectory:
+
+ //
+ // if we get hre the user wants to create something.
+ //
+
+ return EROFS;
+
+ default:
+
+ //
+ // invalid open mode
+ //
+
+ return EINVAL;
+ }
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfFileClose:
+//
+// DESCRIPTION: The routine closes the file table entry specified by file id.
+//
+// ARGUMENTS: FileId Supplies the file table index.
+//
+// RETURN: ESUCCESS is returned if the open operation is successful.
+//
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfFileClose
+ (
+ IN ULONG FileId
+ )
+{
+ PRINTDBG("OmfFileClose\n\r");
+
+ //
+ // clear flag and exit
+ //
+
+ BlFileTable[FileId].Flags.Open = 0;
+ return ESUCCESS;
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfFileMount:
+//
+// DESCRIPTION: The routine does nothing and return EBADF.
+//
+// ARGUMENTS: MountPath device path specifier.
+// Operation mount operation (load/unload).
+//
+// RETURN: EBADF invalid operation
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfFileMount
+ (
+ IN PCHAR MountPath,
+ IN MOUNT_OPERATION Operation
+ )
+{
+ //
+ // return error : invalid operation.
+ //
+
+ return EBADF;
+}
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfFileGetReadStatus
+//
+// DESCRIPTION: This routine implements the GetReadStatus operation for the
+// ARC-EISA firmware OMF file.
+//
+// ARGUMENTS: FileId Supplies a pointer to a variable that specifies
+// the file table entry.
+//
+// RETURN: ESUCCESS return always success.
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfFileGetReadStatus
+ (
+ IN ULONG FileId
+ )
+{
+ //
+ // return ok
+ //
+
+ return ESUCCESS;
+}
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfFileRead:
+//
+// DESCRIPTION: This routine implements the read operation for the ARC-EISA
+// firmware "OMF" driver.
+//
+// ARGUMENTS: FileId Supplies the file table index.
+// Buffer Supplies a pointer to a buffer where the
+// characters read will be stored.
+// Length Supplies the length of Buffer.
+// Count Return the count of the characters that
+// were read.
+//
+// RETURN: ESUCCESS is returned if the open operation is successful.
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfFileRead
+ (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+{
+
+ //
+ // initialize local variables
+ //
+ ARC_STATUS Status; // ARC status
+ POMF_DIR_ENT POmfDirEnt; // OMF directory entry pointer
+ LARGE_INTEGER AbsolutePosition; // OMF file, logical pointer
+ ULONG OmfFileSize; // OMF file size in bytes
+
+ PRINTDBG("OmfFileRead\n\r");
+
+ //
+ // initialize some variables
+ //
+
+ POmfDirEnt = &BlFileTable[ FileId ].u.OmfFileContext.OmfDirEnt;
+
+ //
+ // if directory entry, exit with error
+ //
+
+ if ( !POmfDirEnt->FolderName[0] )
+ {
+ return EBADF; // check this error code "EGI_Q"
+ }
+
+ //
+ // initialize byte count read to zero
+ //
+
+ *Count=0;
+ OmfFileSize = POmfDirEnt->FolderSize << WORD_2P2;
+
+ //
+ // if length is zero or EOF (end of file), return ESUCCESS.
+ //
+
+ if (!Length || BlFileTable[FileId].Position.LowPart >= OmfFileSize)
+ {
+ return ESUCCESS;
+ }
+
+ //
+ // adjust length if it is too big.
+ //
+
+ Length = MIN( Length, OmfFileSize ); // to prevent the add to overflow
+
+ if ( BlFileTable[ FileId ].Position.LowPart + Length > OmfFileSize )
+ {
+ Length = OmfFileSize - BlFileTable[ FileId ].Position.LowPart;
+ }
+
+ //
+ // find OMF absolute offset from OMF file absolute offset
+ //
+
+ AbsolutePosition.HighPart = 0;
+ AbsolutePosition.LowPart = BlFileTable[ FileId ].Position.LowPart +
+ ( POmfDirEnt->FolderLink << WORD_2P2 );
+
+ //
+ // seek + read command
+ //
+
+ if ( (Status = FwSeek( BlFileTable[ FileId ].DeviceId,
+ &AbsolutePosition,
+ SeekAbsolute ))
+ ||
+ (Status = FwRead( BlFileTable[FileId].DeviceId,
+ Buffer,
+ Length,
+ Count )) )
+ {
+ return Status;
+ }
+
+ //
+ // update file pointer and exit
+ //
+
+ BlFileTable[FileId].Position.LowPart += *Count;
+ return ESUCCESS;
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfFileWrite:
+//
+// DESCRIPTION: This routine implements the write operation for the ARC-EISA
+// firmware "OMF" driver.
+//
+// ARGUMENTS: FileId Supplies the file table index.
+// Buffer Supplies a pointer to a buffer where the
+// characters are read.
+// Length Supplies the length of Buffer.
+// Count Return the count of the characters that
+// were written.
+//
+// RETURN: EBADF invalid operation
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfFileWrite
+ (
+ IN ULONG FileId,
+ IN PVOID Buffer,
+ IN ULONG Length,
+ OUT PULONG Count
+ )
+{
+ //
+ // return error : invalid operation
+ //
+
+ return EBADF;
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfFileSeek:
+//
+// DESCRIPTION: This routine implements the Seek operation for the
+// ARC-EISA firmware "OMF" driver.
+//
+// ARGUMENTS: FileId Supplies the file table index.
+// Offset Supplies the offset in the file to position to.
+// SeekMode Supplies the mode of the seek operation
+//
+// RETURN: ESUCCESS returned if the operation is successful.
+// EINVAL returned otherwise.
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfFileSeek
+ (
+ IN ULONG FileId,
+ IN PLARGE_INTEGER Offset,
+ IN SEEK_MODE SeekMode
+ )
+{
+ //
+ // local variables
+ //
+
+ LARGE_INTEGER Point; // New position
+ POMF_DIR_ENT POmfDirEnt; // OMF directory entry pointer
+
+ PRINTDBG("OmfFileSeek\n\r");
+
+ //
+ // initialize some variables
+ //
+
+ POmfDirEnt = &BlFileTable[ FileId ].u.OmfFileContext.OmfDirEnt;
+
+ //
+ // The offset parameter must be zero, if directory entry.
+ //
+
+ if ( !POmfDirEnt->FolderName[0] && ( Offset->LowPart || Offset->HighPart ))
+ {
+ return EINVAL;
+ }
+
+ //
+ // compute new offset value
+ //
+
+ switch(SeekMode)
+ {
+ case SeekAbsolute:
+ Point = *Offset;
+ break;
+ case SeekRelative:
+ Point = RtlLargeIntegerAdd( BlFileTable[FileId].Position, *Offset );
+ break;
+ default:
+ return EINVAL;
+ }
+
+ //
+ // if new offset is valid, update position field.
+ // if the position value 0-based is equal to the OMF size (1-based),
+ // the EOF has been reached. no error is returned in this case and
+ // the count field is set to zero with ESUCCESS error code for any
+ // successive read operation. note that this combination (ESUCCESS and
+ // count=0) is used to rappresent EOF (end of file).
+ //
+
+ if ( POmfDirEnt->FolderName[0] &&
+ (Point.HighPart || Point.LowPart > POmfDirEnt->FolderSize << WORD_2P2))
+ {
+ return EINVAL;
+ }
+ else
+ {
+ BlFileTable[ FileId ].Position = Point;
+ return ESUCCESS;
+ }
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfFileGetFileInformation:
+//
+// DESCRIPTION: This routine implements the GetFileInformation for the
+// ARC-EISA firmware "OMF" driver.
+//
+// ARGUMENTS: FileId Supplies the file table index.
+// Buffer Supplies the buffer to receive the file
+// information. Note that it must be large
+// enough to hold the full file name.
+//
+// RETURN: EBADF invalid operation
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfFileGetFileInformation
+ (
+ IN ULONG FileId,
+ OUT PFILE_INFORMATION Buffer
+ )
+{
+ //
+ // define local variable
+ //
+
+ PBL_FILE_TABLE FileTableEntry = &BlFileTable[ FileId ];
+
+ PRINTDBG("OmfFileGetFileInformation\n\r");
+
+ //
+ // if root, exit with error
+ //
+
+ if ( !FileTableEntry->u.OmfFileContext.OmfDirEnt.FolderName[0] )
+ {
+ return EBADF;
+ }
+
+ //
+ // set output fields
+ //
+
+ RtlZeroMemory(Buffer, sizeof(FILE_INFORMATION));
+
+ //
+ // ending address (high part is already zero) and current address
+ //
+
+ Buffer->EndingAddress.LowPart =
+ FileTableEntry->u.OmfFileContext.OmfDirEnt.FolderSize << WORD_2P2;
+ Buffer->CurrentPosition.LowPart = FileTableEntry->Position.LowPart;
+ Buffer->CurrentPosition.HighPart = FileTableEntry->Position.HighPart;
+
+ //
+ // device type
+ //
+
+ Buffer->Type = OtherPeripheral;
+
+ //
+ // file name length, attributes and file name string
+ //
+
+ Buffer->FileNameLength = FileTableEntry->FileNameLength;
+ Buffer->Attributes = ArcReadOnlyFile;
+ strcpy( Buffer->FileName, FileTableEntry->FileName );
+
+ //
+ // all done
+ //
+
+ return ESUCCESS;
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfFileSetFileInformation:
+//
+// DESCRIPTION: This routine implements the SetFileInformation for the
+// ARC-EISA firmware "OMF" driver.
+//
+// ARGUMENTS: FileId Supplies the file table index.
+// AttributeFlags Supplies the value (on or off) for each
+// attribute being modified.
+// AttributeMask Supplies a mask of the attributes being altered.
+// All other file attributes are left alone.
+//
+// RETURN: EBADF invalid operation
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfFileSetFileInformation
+ (
+ IN ULONG FileId,
+ IN ULONG AttributeFlags,
+ IN ULONG AttributeMask
+ )
+{
+ //
+ // return error : invalid operation
+ //
+
+ return EROFS;
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfFileGetDirectoryEntry:
+//
+// DESCRIPTION: This routine implements the GetDirectoryEntry for the
+// ARC-EISA firmware "OMF" driver.
+//
+// ARGUMENTS: FileId Supplies the file table index.
+// DirEntry Pointer to a directory entry structure
+// NumberDir # of entries to read
+// Count # of entries read
+//
+// RETURN: ESUCCESS returned if the operation is successful.
+// EINVAL returned otherwise.
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+OmfFileGetDirectoryEntry
+ (
+ IN ULONG FileId,
+ IN DIRECTORY_ENTRY *DirEntry,
+ IN ULONG NumberDir,
+ OUT PULONG CountDir
+ )
+{
+ //
+ // initialize local variables
+ //
+
+ ARC_STATUS Status; // ARC status
+ ULONG DeviceId; // file table entry for the device
+ POMF_HDR POmfHeader; // pointer to OMF ROM/FAT file header
+ ULONG CurrentDir; // current directory entry
+ LARGE_INTEGER AbsolutePosition; // OMF file, pointer of logical pointer
+ OMF_DIR_ENT OmfFileBuffer; // buffer for directory entries
+ ULONG Count; // # of bytes read
+
+ PRINTDBG("OmfFileGetDirectoryEntry\n\r");
+
+ //
+ // if not directory entry, exit with error
+ //
+
+ if ( BlFileTable[ FileId ].u.OmfFileContext.OmfDirEnt.FolderName[0] )
+ {
+ return EBADF;
+ }
+
+ //
+ // Initialize the output count to zero
+ //
+
+ *CountDir=0;
+
+ //
+ // if NumberDir is zero, return ESUCCESS.
+ //
+
+ if ( !NumberDir )
+ {
+ return ESUCCESS;
+ }
+
+ //
+ // initialize variables
+ //
+
+ Count=0;
+ DeviceId = BlFileTable[ FileId ].DeviceId;
+ POmfHeader = &BlFileTable[ DeviceId ].u.OmfHeaderContext.OmfHeader;
+ CurrentDir = BlFileTable[ FileId ].Position.LowPart/sizeof(OMF_DIR_ENT);
+
+ //
+ // if no more entries, return ENOTDIR
+ //
+
+ if ( CurrentDir >= POmfHeader->FolderCount )
+ {
+ return ENOTDIR;
+ }
+
+ //
+ // adjust count if it is too big.
+ //
+
+ NumberDir = MIN( NumberDir, POmfHeader->FolderCount ); //avoid add overflow
+
+ if ( CurrentDir + NumberDir > POmfHeader->FolderCount )
+ {
+ NumberDir = POmfHeader->FolderCount - CurrentDir;
+ }
+
+ //
+ // find OMF absolute offset from OMF file absolute offset
+ //
+
+ AbsolutePosition.HighPart = 0;
+ AbsolutePosition.LowPart = BlFileTable[FileId].Position.LowPart +
+ (POmfHeader->FolderDirectoryLink<<WORD_2P2);
+
+ //
+ // seek command
+ //
+
+ if ( Status = FwSeek( DeviceId, &AbsolutePosition, SeekAbsolute ))
+ {
+ return Status;
+ }
+
+ //
+ // read command
+ //
+
+ while( NumberDir-- )
+ {
+ //
+ // read one directory entry
+ //
+
+ if ( Status = FwRead( DeviceId,
+ &OmfFileBuffer,
+ (ULONG)sizeof(OMF_DIR_ENT),
+ &Count ))
+ {
+ return Status;
+ }
+
+ //
+ // if bytes read are not sizeof(OMF_DIR_ENT), return error
+ //
+
+ if ( Count != sizeof(OMF_DIR_ENT) )
+ {
+ return EBADF;
+ }
+
+ //
+ // convert OMF directory entry in ARC directory entry
+ //
+
+ ConvertOmfDirToArcDir( &OmfFileBuffer, DirEntry++ );
+ ++*CountDir;
+ }
+
+ //
+ // update file pointer and exit
+ //
+
+ BlFileTable[FileId].Position.LowPart += *CountDir * sizeof(OMF_DIR_ENT);
+ return ESUCCESS;
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: MaxOmfFatFiles:
+//
+// DESCRIPTION: The routine returns the most updated file name for the
+// specified product Id.
+// A FALSE is returned if the OMF FAT file name has not been
+// modified.
+//
+// ARGUMENTS: MasterName name used as base
+// CheckedName name checked
+//
+// RETURN: TRUE is returned if the OMF FAT file name has been
+// modified.
+// FALSE is returned in all the other cases.
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+MaxOmfFatFiles
+ (
+ IN OUT PCHAR MasterName,
+ IN PCHAR CheckedName
+ )
+{
+ //
+ // Define variables
+ //
+
+ CHAR MasterVersion, MasterRevision; // master name
+ CHAR CheckedVersion, CheckedRevision; // checked name
+ POMF_FAT_FILE_NAME PointerMaster; // master name pointer
+ POMF_FAT_FILE_NAME PointerChecked; // checked name pointer
+
+ PRINTDBG("MaxOmfFatFiles\n\r");
+
+ //
+ // save version and revision master values
+ //
+
+ PointerMaster = (POMF_FAT_FILE_NAME)MasterName;
+ MasterVersion = PointerMaster->Version;
+ MasterRevision = PointerMaster->Revision;
+
+ //
+ // save version and revision checked values
+ //
+
+ PointerChecked = (POMF_FAT_FILE_NAME)CheckedName;
+ CheckedVersion = PointerChecked->Version;
+ CheckedRevision = PointerChecked->Revision;
+ PointerChecked->Version = MasterVersion;
+ PointerChecked->Revision = MasterRevision;
+
+ //
+ // update name if new version for the same product Id
+ //
+
+ if (strcmp(MasterName, CheckedName)
+ ||
+ CheckedVersion<MasterVersion
+ ||
+ (CheckedVersion == MasterVersion && CheckedRevision <= MasterRevision))
+ {
+ return FALSE;
+ }
+ else
+ {
+ PointerMaster->Version = CheckedVersion;
+ PointerMaster->Revision = CheckedRevision;
+ return TRUE;
+ }
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfFileNameValidate:
+//
+// DESCRIPTION: The routine validates the requested OMF file name.
+// The name is decomposed in Folder Name and Folder Type.
+//
+// ARGUMENTS: OpenPath Supplies a pointer to a zero terminated OMF
+// file name.
+// OmfFileName Supplies a pointer to an array used to store
+// the Folder Name.
+// OmfType Supplies a pointer to an array used to store
+// the Folder Types.
+//
+// RETURN: TRUE is returned if the operation succeed.
+// FALSE is returned if the OpenPath is incorrect.
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+OmfFileNameValidate
+ (
+ IN PCHAR OpenPath,
+ OUT PCHAR OmfFileName,
+ OUT PCHAR OmfType
+ )
+
+{
+ //
+ // Define variables
+ //
+
+ ULONG NameIndex; // general index
+
+ PRINTDBG("OmfFileNameValidate\n\r");
+
+ //
+ // name validation
+ //
+
+ for ( NameIndex = 0;
+ NameIndex < OMF_FILE_NAME_LEN && *OpenPath && *OpenPath != '.';
+ NameIndex++ )
+ {
+ if (
+ isupper( *OpenPath ) // upper case letter
+ ||
+ isdigit( *OpenPath ) // digit
+ ||
+ *OpenPath=='-' // '-' minus
+ ||
+ (*OpenPath=='$' && NameIndex==0) // $ char in 1st position
+ )
+ {
+ *OmfFileName++=*OpenPath++;
+ }
+ else
+ {
+ return FALSE;
+ }
+ }
+
+ //
+ // return error if name length > of OMF_FILE_NAME_LEN
+ //
+
+ if ( NameIndex == OMF_FILE_NAME_LEN && *OpenPath && *OpenPath != '.')
+ {
+ return FALSE;
+ }
+
+ //
+ // fill right with null chars ('\0') if Folder Name is less than 12 chars
+ //
+
+ while( NameIndex++ < OMF_FILE_NAME_LEN )
+ {
+ *OmfFileName++='\0';
+ }
+
+ //
+ // extension validation
+ //
+
+ if ( *OpenPath++ && *OpenPath ) // skip "null", ".null"
+ {
+ switch( *OpenPath ) // check type field
+ {
+ case 'A':
+ case 'B':
+ *OmfType++ = *OpenPath++;
+ *OmfType = '\0'; // means : end of types
+ break;
+ default:
+ return FALSE;
+ }
+ if( *OpenPath ) // error if more chars
+ {
+ return FALSE;
+ }
+ }
+
+ //
+ // all done, return ok
+ //
+
+ return TRUE;
+}
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: CmpOmfFiles:
+//
+// DESCRIPTION: The routine checks if the selected directory entry has the
+// requested OMF file name.
+//
+// ARGUMENTS: OmfFileName Requested OMF file name pointer.
+// OmfType Requested OMF file type pointer.
+// POmfDirEnt Directory entry to check.
+//
+// RETURN: TRUE is returned if the operation succeed.
+// FALSE is returned if the name or type doesn't match.
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+CmpOmfFiles
+ (
+ IN PCHAR OmfFileName,
+ IN CHAR OmfType,
+ IN POMF_DIR_ENT POmfDirEnt
+ )
+{
+ //
+ // Define variables
+ //
+
+ ULONG NameIndex; // general index
+
+ PRINTDBG("CmpOmfFiles\n\r");
+
+ //
+ // check name
+ //
+
+ for ( NameIndex=0; NameIndex < OMF_FILE_NAME_LEN; NameIndex++ )
+ {
+ if ( OmfFileName[ NameIndex ] != POmfDirEnt->FolderName[ NameIndex ] )
+ {
+ return FALSE;
+ }
+ }
+
+ //
+ // check extension
+ //
+
+ if ( OmfType != POmfDirEnt->FolderType )
+ {
+ return FALSE;
+ }
+
+ //
+ // all done, return ok
+ //
+
+ return TRUE;
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfHeaderValidate:
+//
+// DESCRIPTION: The routine checks if the specified OMF header data is valid.
+//
+// ARGUMENTS: FileId file table entry index
+//
+// RETURN: TRUE is returned if file is ok.
+// FALSE is returned if file is not correct.
+//
+// ASSUMPTIONS: The header data has already been copied in the
+// context data of the file table entry.
+// The size of all the OMF structures is a multiple of a word.
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+OmfHeaderValidate
+ (
+ IN ULONG FileId
+ )
+{
+ //
+ // local variables
+ //
+
+ POMF_HDR POmfHeader; // pointer to the header data
+ ULONG OmfDirLink; // directory link in words
+ ULONG OmfDirLength; // directory size in words
+ ULONG OmfSize; // OMF size in bytes
+ UCHAR Checksum=0; // used to compute the checksum
+
+ PRINTDBG("OmfHeaderValidate\n\r");
+
+ //
+ // initialize variables
+ //
+
+ POmfHeader = &BlFileTable[FileId].u.OmfHeaderContext.OmfHeader;
+ OmfDirLink = POmfHeader->FolderDirectoryLink;
+
+ OmfDirLength =(POmfHeader->FolderCount * sizeof(OMF_DIR_ENT))/(1<<WORD_2P2);
+ OmfSize = (ULONG)POmfHeader->FwSize * OMF_BLOCK_SIZE;
+ if (!OmfSize)
+ {
+ OmfSize = OMF_MAX_SIZE;
+ }
+
+ //
+ // check header values
+ //
+
+ if ( POmfHeader->ID[0] != OMF_ID_1ST
+ ||
+ POmfHeader->ID[1] != OMF_ID_2ND
+ ||
+ POmfHeader->ID[2] != OMF_ID_3RD
+ ||
+ POmfHeader->ID[3] != OMF_ID_4TH
+ ||
+ !isalnum(POmfHeader->FwVersion)
+ ||
+ !isalnum(POmfHeader->FwRevision)
+ ||
+ sizeof(OMF_HDR) > OmfSize
+ ||
+ OmfDirLink + OmfDirLength > OmfSize/(1<<WORD_2P2)
+ ||
+ FwFileIdChecksum( FileId,
+ RtlConvertUlongToLargeInteger(0l),
+ (ULONG)(sizeof(OMF_HDR)),
+ &Checksum )
+ ||
+ FwFileIdChecksum( FileId,
+ RtlConvertUlongToLargeInteger(OmfDirLink<<WORD_2P2),
+ OmfDirLength << WORD_2P2,
+ &Checksum )
+// >>> FIXME <<<
+// ||
+// Checksum
+ )
+ {
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: OmfFileValidate:
+//
+// DESCRIPTION: The routine checks if the selected file is valid.
+//
+// ARGUMENTS: FileId file table entry index
+//
+// RETURN: TRUE is returned if file is ok.
+// FALSE is returned if file is not correct.
+//
+// ASSUMPTIONS: the folder name and its extension (type) have already
+// been validated.
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+OmfFileValidate
+ (
+ IN ULONG FileId
+ )
+{
+ //
+ // local variables
+ //
+
+ POMF_DIR_ENT POmfDirEnt; // OMF directory entry pointer
+ ULONG OmfFileLength; // file length, word count
+ ULONG OmfFileLink; // file link, word count
+ ULONG DeviceId; // device id file table entry
+ ULONG OmfLength; // OMF rom length, word count
+ UCHAR Checksum=0; // used to compute the checksum
+
+ PRINTDBG("OmfFileValidate\n\r");
+
+ //
+ // initialize variables
+ //
+
+ POmfDirEnt = &BlFileTable[FileId].u.OmfFileContext.OmfDirEnt;
+ OmfFileLink = POmfDirEnt->FolderLink;
+ OmfFileLength = POmfDirEnt->FolderSize;
+ DeviceId = BlFileTable[FileId].DeviceId;
+ OmfLength=(ULONG)BlFileTable[DeviceId].u.OmfHeaderContext.OmfHeader.FwSize *
+ OMF_BLOCK_SIZE/(1<<WORD_2P2);
+ if (!OmfLength)
+ {
+ OmfLength = OMF_MAX_SIZE/(1<<WORD_2P2);
+ }
+
+ //
+ // validate file
+ //
+
+ if ( OmfFileLink > OMF_MAX_FILE_LINK
+ ||
+ OmfFileLength > OMF_MAX_FILE_LEN
+ ||
+ OmfFileLink + OmfFileLength > OmfLength
+ ||
+ FwFileIdChecksum( DeviceId,
+ RtlConvertUlongToLargeInteger(OmfFileLink<<WORD_2P2),
+ OmfFileLength << WORD_2P2,
+ &Checksum )
+// >>> FIXME <<<
+// ||
+// (Checksum += POmfDirEnt->FolderChecksumByte)
+ )
+ {
+ return FALSE;
+ }
+ else
+ {
+ return TRUE;
+ }
+}
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: ConvertOmfDirToArcDir:
+//
+// DESCRIPTION: The routine converts the OMF directory entry in the ARC
+// directory entry format.
+//
+// ARGUMENTS: OmfFileBuffer pointer to OMF directory entry
+// DirEntry pointer to ARC directory entry to be filled
+//
+// RETURN: NONE
+//
+// ASSUMPTIONS: FileNameLengthMax is at least 3 chars.
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+VOID
+ConvertOmfDirToArcDir
+ (
+ IN POMF_DIR_ENT POmfDirEnt,
+ OUT DIRECTORY_ENTRY *PArcDirEnt
+ )
+{
+ //
+ // local variables
+ //
+
+ ULONG CharIndex; // name+extension length
+ ULONG MaxFileName; // max name length
+
+ PRINTDBG("ConvertOmfDirToArcDir\n\r");
+
+ //
+ // set attribute bit (read only file)
+ //
+
+ PArcDirEnt->FileAttribute = ArcReadOnlyFile;
+
+ //
+ // set file name (note that 3 means: '.' + extension + '\0' )
+ //
+
+ MaxFileName = MIN( 32 - 3, OMF_FILE_NAME_LEN );
+
+ for ( CharIndex = 0;
+ CharIndex < MaxFileName && POmfDirEnt->FolderName[ CharIndex ];
+ CharIndex++ )
+ {
+ PArcDirEnt->FileName[ CharIndex ] = POmfDirEnt->FolderName[ CharIndex];
+ }
+
+ //
+ // dot '.'
+ //
+
+ PArcDirEnt->FileName[ CharIndex++ ] = '.';
+
+ //
+ // extension
+ //
+
+ PArcDirEnt->FileName[ CharIndex++ ] = POmfDirEnt->FolderType;
+
+ //
+ // null char
+ //
+
+ PArcDirEnt->FileName[ CharIndex ]='\0';
+
+ //
+ // set length (note: CharIndex is 0-based)
+ //
+
+ PArcDirEnt->FileNameLength = CharIndex;
+
+ //
+ // all done, exit.
+ //
+
+ return;
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: FwGetEisaId:
+//
+// DESCRIPTION: The routine returns the requested board and info id.
+//
+// ARGUMENTS: PathName Option board path name pointer
+// EisaId Pointer to 7 bytes space for the id
+// IdInfo Pointer to 1 byte space for the info id
+//
+// RETURN: TRUE all done.
+// FALSE for any error.
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+FwGetEisaId
+ (
+ IN PCHAR PathName,
+ OUT PCHAR EisaId,
+ OUT PUCHAR IdInfo
+ )
+{
+ //
+ // define local variables
+ //
+
+ PCONFIGURATION_COMPONENT pComp; // Pointer to a component struc
+ EISA_SLOT_INFO SlotInfo; // pointer to first eisa info
+ BOOLEAN GetIdStatus = FALSE; // be pessimistic
+
+ PRINTDBG("FwGetEisaId\n\r"); // DEBUG SUPPORT
+
+ //
+ // Check to see if the motherboard component is being accessed. Since
+ // Jazz doesn't have a motherboard id, substitute values.
+ //
+
+ if (strstr(PathName, "eisa(0)other(0)") != NULL) {
+ EisaId[0] = 'J';
+ EisaId[1] = 'A';
+ EisaId[2] = 'Z';
+ EisaId[3] = '0';
+ EisaId[4] = '0';
+ EisaId[5] = '0';
+ EisaId[6] = '0';
+ *IdInfo = 0;
+ GetIdStatus = TRUE;
+
+ //
+ // get the requested component
+ //
+
+ } else if ( (pComp = FwGetComponent(PathName)) == NULL );
+
+ //
+ // check the configuration data length
+ //
+
+ else if ( pComp->ConfigurationDataLength < EISA_SLOT_MIN_INFO );
+
+ //
+ // get the slot info
+ //
+
+ else if ( FwGetConfigurationDataIndex( (PVOID)&SlotInfo,
+ pComp,
+ CONFIGDATAHEADER_SIZE,
+ EISA_SLOT_INFO_SIZE ));
+
+ //
+ // get the requested info
+ //
+
+ else
+ {
+ FwUncompressEisaId( &SlotInfo.Id1stChar, EisaId );
+ *IdInfo = SlotInfo.IdInfo;
+ GetIdStatus = TRUE;
+ }
+
+ //
+ // return status
+ //
+
+ return GetIdStatus;
+}
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: FwUncompressEisaId:
+//
+// DESCRIPTION: The routine converts the specified compressed ID in 7 ASCII
+// chars.
+//
+// ARGUMENTS: CompEisaId Pointer to the compressed ID (4 bytes)
+// UncompEisaId Pointer to the uncompressed ID (7 bytes)
+//
+// RETURN: none
+//
+// ASSUMPTIONS: Compressed ID : 1st byte bit 7 - Reserved
+// bits 6-2 - 1st char name comp
+// bits 1-0 - 2nd char name comp
+// 2nd byte bits 7-5 - 2nd char name
+// bits 4-0 - 3rd char name comp
+// 3rd byte bits 7-4 - 1st decimal number comp
+// bits 3-0 - 2nd decimal number comp
+// 4th byte bits 7-4 - 3rd decimal number comp
+// bits 3-0 - 4th decimal number comp
+//
+// Uncompressed ID: 1st byte 1st char name
+// 2nd byte 2nd char name
+// 3rd byte 3rd char name
+// 4th byte 1st decimal number
+// 5th byte 2nd decimal number
+// 6th byte 3rd decimal number
+// 7th byte 4th decimal number
+//
+// Compressed -> Uncompressed :
+//
+// char comp + 'A' - 1 = char uncompressed
+// decimal comp + '0' = decimal uncompressed
+//
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+VOID
+FwUncompressEisaId
+ (
+ IN PUCHAR CompEisaId,
+ OUT PUCHAR UncompEisaId
+ )
+{
+ //
+ // local variables
+ //
+
+ ULONG Id; // used to hold the 4 bytes ID
+ SHORT i; // general index
+ UCHAR d; // hexadecimal digit
+
+ PRINTDBG("FwUncompressEisaId\n\r");
+
+ //
+ // transform the 4 chars ID in a ULONG
+ //
+
+ Id = Fw4UcharToUlongMSB( CompEisaId );
+
+ //
+ // uncompress 4 digits, starting from the last one
+ //
+
+ for (i=3; i>=0; i--)
+ {
+ d = Id & ID_DIGIT_MASK;
+ UncompEisaId[3+i] = (d <= 9) ? (d + '0') : (d - 0xA + 'A');
+ Id >>= ID_DIGIT_SIZE;
+ }
+
+ //
+ // uncompress 3 chars
+ //
+
+ for (i=2; i>=0; i--)
+ {
+ UncompEisaId[i] = (Id & ID_CHAR_MASK) + 'A' - 1;
+ Id >>= ID_CHAR_SIZE;
+ }
+
+ //
+ // exit
+ //
+
+ return;
+}
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: FwGetEisaBusIoCpuAddress:
+//
+// DESCRIPTION: The routine returns the virtual (CPU) address for the specified
+// EISA bus.
+//
+// ARGUMENTS: EisaPath pointer to the path string
+// IoBusAddress pointer to a PVOID variable. It used to store
+// the computed address.
+//
+// RETURN: TRUE returned if all correct.
+// FALSE returned for any error.
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+FwGetEisaBusIoCpuAddress
+ (
+ IN PCHAR EisaPath,
+ OUT PVOID *IoBusAddress
+ )
+{
+ //
+ // define local variables
+ //
+
+ PCONFIGURATION_COMPONENT PComponent;
+ EISA_ADAPTER_DETAILS EisaInfo;
+
+ PRINTDBG("FwGetEisaBusIoCpuAddress\n\r");
+
+ //
+ // get the requested component and configuration data
+ //
+
+ if ( (PComponent = FwGetComponent( EisaPath )) == NULL ||
+ FwGetConfigurationData( (PVOID)&EisaInfo, PComponent ))
+ {
+ return FALSE;
+ }
+
+ //
+ // Return the requested virtual (CPU) address
+ //
+
+ *IoBusAddress = EisaInfo.IoStart;
+ return TRUE;
+}
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: FwFileChecksum:
+//
+// DESCRIPTION: The routine performs a byte checksum on the specified file.
+//
+// ARGUMENTS: Path File path
+// Checksum File checksum
+//
+// RETURN: ESUCCESS Operation completed successfully.
+// ...other Error code.
+//
+// ASSUMPTIONS: none
+//
+// CALLS: FwFileIdChecksum
+//
+// GLOBALS: none
+//
+// NOTES: The file length must be contained in a ULONG (4G -1).
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+FwFileChecksum
+ (
+ IN PCHAR Path,
+ OUT PUCHAR Checksum
+ )
+{
+ ARC_STATUS Status;
+ ULONG FileId;
+ FILE_INFORMATION FileInfo;
+
+ //
+ // initialize checksum to zero
+ //
+
+ *Checksum = 0;
+
+ //
+ // open file
+ //
+
+ if (Status = FwOpen( Path, ArcOpenReadOnly, &FileId ))
+ {
+ return Status;
+ }
+
+ //
+ // get file information
+ //
+
+ if (Status = FwGetFileInformation( FileId, &FileInfo ));
+
+ //
+ // return an error if file is greater than 4G - 1
+ //
+
+ else if (FileInfo.EndingAddress.HighPart != 0)
+ {
+ Status = EINVAL;
+ }
+
+ //
+ // perform the checksum and return the status
+ //
+
+ else
+ {
+ Status = FwFileIdChecksum( FileId,
+ FileInfo.StartingAddress,
+ FileInfo.EndingAddress.LowPart,
+ Checksum );
+ }
+
+ //
+ // clase file and return status
+ //
+
+ FwClose( FileId );
+ return Status;
+}
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: FwChecksumByte:
+//
+// DESCRIPTION: The routine performs a byte checksum on the specified buffer.
+//
+// ARGUMENTS: Buffer Pointer to area to checksum.
+// Length Length of area to checksum (bytes).
+// ChecksumByte The pointed byte is used in input as a
+// starting checksum value and in output as
+// the final checksum value.
+//
+// RETURN: ESUCCESS operation completed successfully
+//
+// ASSUMPTIONS: none
+//
+// CALLS: none
+//
+// GLOBALS: none
+//
+// NOTES: none
+//
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+FwChecksumByte (
+ IN PUCHAR Buffer,
+ IN ULONG Length,
+ IN OUT PUCHAR ChecksumByte
+ )
+{
+ //
+ // checksum the buffer and exit
+ //
+
+ while (Length--)
+ {
+ *ChecksumByte += *Buffer++;
+ }
+
+ return ESUCCESS;
+}
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: FwFileIdChecksum:
+//
+// DESCRIPTION: The routine performs a byte checksum within the spcified
+// range of the FileId.
+//
+// ARGUMENTS: FileId File table entry index.
+// StartingOffset Beginning of checksum range (byte offset).
+// Length Number of bytes to checksum.
+// Checksum Input : start checksum value
+// Output: image checksum
+//
+// RETURN: ESUCCESS Operation completed successfully.
+// ...other Error code.
+//
+// ASSUMPTIONS: none
+//
+// CALLS: FwChecksumByte
+//
+// GLOBALS: none
+//
+// NOTES: This routine can also be called during the "open" phase
+// (the open bit is not set), because the read and seek functions
+// are called directly using the table within the file id
+// descriptor.
+// ----------------------------------------------------------------------------
+//
+
+ARC_STATUS
+FwFileIdChecksum
+ (
+ IN ULONG FileId,
+ IN LARGE_INTEGER StartingOffset,
+ IN ULONG Length,
+ IN OUT PUCHAR Checksum
+ )
+{
+ ARC_STATUS Status;
+ ULONG BytesToRead;
+ ULONG Count;
+ UCHAR TempBuffer[MAXIMUM_SECTOR_SIZE + MAX_DCACHE_LINE_SIZE];
+ PUCHAR TempPointer = ALIGN_BUFFER( TempBuffer );
+
+ //
+ // If buffer length is zero, return ESUCCESS
+ //
+
+ if (Length==0)
+ {
+ return ESUCCESS;
+ }
+
+ //
+ // position the file pointer
+ //
+
+ if (Status = (BlFileTable[FileId].DeviceEntryTable->Seek)
+ (FileId, &StartingOffset, SeekAbsolute))
+ {
+ return Status;
+ }
+
+ //
+ // perform the checksum
+ //
+
+ do
+ {
+ BytesToRead = MIN( Length, MAXIMUM_SECTOR_SIZE );
+
+ //
+ // fill the buffer
+ //
+
+ if (Status = (BlFileTable[FileId].DeviceEntryTable->Read)
+ (FileId, TempPointer, BytesToRead, &Count))
+ {
+ return Status;
+ }
+
+ //
+ // make sure that we got the requested number of bytes
+ //
+
+ if (Count != BytesToRead)
+ {
+ return EINVAL;
+ }
+
+ //
+ // checksum the area
+ //
+
+ FwChecksumByte( TempPointer, BytesToRead, Checksum);
+
+ } while ( Length -= BytesToRead );
+
+ //
+ // all done
+ //
+
+ return Status;
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: FwGetMnemonicKey;
+//
+// DESCRIPTION: The routine returns the specified key. The specified key
+// within the path string must be in digits, an error is returned
+// otherwise.
+//
+// ARGUMENTS: Path pointer to the pathname string
+// Mnemonic mnemonic string
+// Key pointer to buffer used to hold the ouput
+//
+// RETURN: TRUE returned if all correct
+// FALSE returned invalid input parameter
+//
+// ASSUMPTIONS:
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+FwGetMnemonicKey
+ (
+ IN PCHAR Path,
+ IN PCHAR Mnemonic,
+ IN PULONG Key
+ )
+{
+ PCHAR Tmp;
+ PCHAR Tmp2;
+ CHAR Digits[ KEY_MAX_DIGITS + 1 ];
+ ULONG i;
+ CHAR String[ MAX_MNEMONIC_LEN + 3 ]; // mnemonic + ')' + '(' + '\0'
+
+ PRINTDBG("FwGetMnemonicKey\n\r");
+
+ //
+ // Construct a string of the form ")mnemonic("
+ //
+
+ String[0]=')';
+ for(i=1; *Mnemonic; i++)
+ {
+ String[i] = * Mnemonic++;
+ }
+ String[i++]='(';
+ String[i]='\0';
+
+ //
+ // first look for the "mnemonic(" string.
+ //
+
+ if ( (Tmp = strstr( Path, &String[1] )) == NULL)
+ {
+ return FALSE;
+ }
+
+ //
+ // if not the begin of the path name, look for the ")mnemonic(" string.
+ //
+
+ if (Tmp != Path)
+ {
+ if ( (Tmp = strstr( Path, String )) == NULL)
+ {
+ return FALSE;
+ }
+ }
+ else
+ {
+ i--;
+ }
+
+ //
+ // skip the mnemonic
+ //
+
+ Tmp+=i;
+
+ //
+ // make sure that the number of digits is within the allowed range
+ //
+
+ if ((Tmp2 = strchr(Tmp, ')')) == NULL || Tmp2 - Tmp > KEY_MAX_DIGITS )
+ {
+ return FALSE;
+ }
+
+ //
+ // convert the value in between parentesis to integer
+ //
+
+ for ( i=0; *Tmp != ')'; i++ )
+ {
+ if ( !isdigit( Digits[i] = *Tmp++ ))
+ {
+ return FALSE;
+ }
+ }
+ Digits[i]='\0';
+
+ //
+ // return the converted number
+ //
+
+ *Key = i ? atoi(Digits) : 0;
+ return TRUE;
+}
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: FwGetNextMnemonic:
+//
+// DESCRIPTION: The routine returns the next mnemonic in the list.
+// If Mnemonic is a null string, the first mnemonic of the list
+// is returned. The FALSE value is returned if the specified
+// mnemonic is not present or end of list.
+//
+//
+// ARGUMENTS: Path pointer to the pathname string.
+// Mnemonic mnemonic string pointer
+// NextMnemonic next mnemonic string pointer
+//
+// RETURN: TRUE returned if all correct
+// FALSE returned if invalid input parameter or end of
+// list
+//
+// ASSUMPTIONS: The path is composed by ARC mnemonic names as follows:
+// adapter(.)..adapter(.)controller(.)peripheral(.)'\0'.
+// The NextMnemonic string is big enough to hold the mnemonic
+// name.
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+FwGetNextMnemonic
+ (
+ IN PCHAR Path,
+ IN PCHAR Mnemonic,
+ OUT PCHAR NextMnemonic
+ )
+{
+ //
+ // local variables
+ //
+
+ PCHAR Tmp = Path;
+ PCHAR Tmp2;
+ ULONG i;
+ CHAR String[ MAX_MNEMONIC_LEN + 3 ]; // mnemonic + ')' + '(' + '\0'
+
+ PRINTDBG("FwGetNextMnemonic\n\r");
+
+ if ( *Mnemonic )
+ {
+ //
+ // Construct a string of the form ")mnemonic("
+ //
+
+ String[0]=')';
+ for(i=1; *Mnemonic; i++)
+ {
+ String[i] = *Mnemonic++;
+ }
+ String[i++]='(';
+ String[i]='\0';
+
+ //
+ // first look for the "mnemonic(" string.
+ //
+
+ if ( (Tmp = strstr( Path, &String[1] )) == NULL)
+ {
+ return FALSE;
+ }
+
+ //
+ // if not the begin of the path name, look for the ")mnemonic(" string.
+ //
+
+ if (Tmp != Path)
+ {
+ if ( (Tmp = strstr( Path, String )) == NULL)
+ {
+ return FALSE;
+ }
+ Tmp++;
+ }
+
+ //
+ // return an error if there is another mnemonic with same name
+ //
+
+ if (strstr( Tmp, String ) != NULL)
+ {
+ return FALSE;
+ }
+
+ //
+ // find the start of the next mnemonic
+ //
+
+ if ( (Tmp = strchr(Tmp,')')) == NULL )
+ {
+ return FALSE;
+ }
+ Tmp++;
+ }
+
+ //
+ // find the end of the next mnemonic and copy it.
+ //
+
+ if ( (Tmp2 = strchr(Tmp,'(')) == NULL || Tmp2 == Tmp ||
+ strchr( Tmp2, ')') == NULL )
+ {
+ return FALSE;
+ }
+
+ //
+ // copy the mnemonic
+ //
+
+ while( Tmp < Tmp2 )
+ {
+ *NextMnemonic++ = *Tmp++;
+ }
+ *NextMnemonic = '\0';
+
+ //
+ // return all done
+ //
+
+ return TRUE;
+}
+
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: FwGetMnemonicPath:
+//
+// DESCRIPTION: The routine returns a pointer to the mnemonic path.
+// The routine uses the first mnemoic match to built
+// the mnemonic path.
+//
+// ARGUMENTS: Path pointer to the path string.
+// Mnemonic pointer to the mnemomic.
+// MnemonicPath pointer to the mnemonic path string.
+//
+// RETURN: TRUE returned if all correct.
+// FALSE returned for any error.
+//
+// ASSUMPTIONS: the string pointed by MnemonicPath must be enough large to
+// contain the mnemoinc path.
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+FwGetMnemonicPath
+ (
+ IN PCHAR Path,
+ IN PCHAR Mnemonic,
+ OUT PCHAR MnemonicPath
+ )
+{
+ //
+ // local variables
+ //
+
+ PCHAR Tmp;
+ ULONG i;
+ CHAR String[ MAX_MNEMONIC_LEN + 3 ]; // mnemonic + ')' + '(' + '\0'
+
+ PRINTDBG("FwGetMnemonicPath\n\r");
+
+ //
+ // Construct a string of the form ")mnemonic("
+ //
+
+ String[0]=')';
+ for(i=1; *Mnemonic; i++)
+ {
+ String[i] = *Mnemonic++;
+ }
+ String[i++]='(';
+ String[i]='\0';
+
+ //
+ // first look for the "mnemonic(" string.
+ //
+
+ if ( (Tmp = strstr( Path, &String[1] )) == NULL)
+ {
+ return FALSE;
+ }
+
+ //
+ // if not the begin of the path name, look for the ")mnemonic(" string.
+ //
+
+ if (Tmp != Path)
+ {
+ if ( (Tmp = strstr( Path, String )) == NULL)
+ {
+ return FALSE;
+ }
+ Tmp++;
+ }
+
+ //
+ // find the end of this mnemonic
+ //
+
+ if ( (Tmp = strchr(Tmp,')')) == NULL )
+ {
+ return FALSE;
+ }
+
+ //
+ // copy the mnemonic path in the output string
+ //
+
+ strncpy( MnemonicPath, Path, Tmp-Path+1 );
+ MnemonicPath[ Tmp-Path+1 ] = '\0';
+
+ //
+ // all done, return
+ //
+
+ return TRUE;
+}
+
+
+
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: GetNextPath:
+//
+// DESCRIPTION: The routine isolates the first path string entry form the
+// specified path string list.
+//
+// ARGUMENTS: PathList pointer to the path string list pointer.
+// it is updated upon return to point the
+// next path string entry.
+// PathTarget pointer to the isolated path string.
+//
+//
+// RETURN: TRUE returned if operation is successful.
+// FALSE returned if end of list has been reached.
+//
+// ASSUMPTIONS: The path string list is ended with a null char ('\0') and
+// the path string entries are separated from each other with
+// the ';' char.
+// The target string has enough space to hold the isolated
+// path string.
+//
+// CALLS:
+//
+// GLOBALS:
+//
+// NOTES:
+// ----------------------------------------------------------------------------
+//
+
+BOOLEAN
+GetNextPath
+ (
+ IN OUT PCHAR *PPathList,
+ OUT PCHAR PathTarget
+ )
+{
+ PRINTDBG("GetNextPath\n\r");
+
+ //
+ // if end of list, retrun with error
+ //
+
+ if (!**PPathList)
+ {
+ return FALSE;
+ }
+
+ //
+ // copy the path string and update the pointer
+ //
+
+ for (; *PathTarget=**PPathList; *PathTarget++, *(*PPathList)++)
+ {
+ if (**PPathList==';')
+ {
+ *PathTarget='\0';
+ (*PPathList)++;
+ break;
+ }
+ }
+ return TRUE;
+}
+
+
+
+
diff --git a/private/ntos/fw/mips/pldfont.c b/private/ntos/fw/mips/pldfont.c
new file mode 100644
index 000000000..4dd32295c
--- /dev/null
+++ b/private/ntos/fw/mips/pldfont.c
@@ -0,0 +1,178 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ pldfont.c
+
+Abstract:
+
+ This module contains the font tables to display characters in a frame
+ buffer.
+
+Author:
+
+ David M. Robinson (davidro) 17-Aug-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+
+
+
+#define NORMAL 0x4
+#define BOLD 0x8
+#define DOUBLE 0xC
+
+#define HOLE1 0x1
+#define HOLE2 0x2
+#define HOLE3 0x3
+
+#define FILL3 0x9
+#define FILL1 0xa
+#define SHORTNORMAL 0xb
+
+#define PackFont( Left, Right, Top, Bottom ) \
+ (Left << 4) | Right, (Top << 4) | Bottom
+
+// Right Left Top Bottom
+
+
+unsigned char FwLdFont[258] = {
+
+ PackFont (NORMAL , NORMAL , 0 , 0 ), // 00
+ PackFont (BOLD , BOLD , 0 , 0 ), // 01
+ PackFont (0 , 0 , NORMAL , NORMAL ), // 02
+ PackFont (0 , 0 , BOLD , BOLD ), // 03
+ PackFont (NORMAL + HOLE2, 0 , 0 , 0 ), // 04
+ PackFont (0 , NORMAL + HOLE2, 0 , 0 ), // 05
+ PackFont (0 , 0 , NORMAL + HOLE2, 0 ), // 06
+ PackFont (0 , 0 , 0 , NORMAL + HOLE2 ), // 07
+ PackFont (NORMAL + HOLE3, 0 , 0 , 0 ), // 08
+ PackFont (0 , NORMAL + HOLE3, 0 , 0 ), // 09
+ PackFont (0 , 0 , NORMAL + HOLE3, 0 ), // 0A
+ PackFont (0 , 0 , 0 , NORMAL + HOLE3 ), // 0B
+ PackFont (NORMAL , 0 , 0 , NORMAL ), // 0C
+ PackFont (BOLD , 0 , 0 , NORMAL ), // 0D
+ PackFont (NORMAL , 0 , 0 , BOLD ), // 0E
+ PackFont (BOLD , FILL3 , 0 , BOLD ), // 0F
+ PackFont (0 , NORMAL , 0 , NORMAL ), // 10
+ PackFont (0 , BOLD , 0 , NORMAL ), // 11
+ PackFont (0 , NORMAL , 0 , BOLD ), // 13
+ PackFont (FILL3 , BOLD , 0 , BOLD ), // 12
+ PackFont (NORMAL , 0 , NORMAL , 0 ), // 14
+ PackFont (BOLD , 0 , NORMAL , 0 ), // 15
+ PackFont (NORMAL , 0 , BOLD , 0 ), // 16
+ PackFont (BOLD , FILL3 , BOLD , 0 ), // 17
+ PackFont (0 , NORMAL , NORMAL , 0 ), // 18
+ PackFont (0 , BOLD , NORMAL , 0 ), // 19
+ PackFont (0 , NORMAL , BOLD , 0 ), // 1A
+ PackFont (FILL3 , BOLD , BOLD , 0 ), // 1B
+ PackFont (NORMAL , 0 , NORMAL , NORMAL ), // 1C
+ PackFont (BOLD , 0 , NORMAL , NORMAL ), // 1D
+ PackFont (NORMAL , 0 , BOLD , NORMAL ), // 1E
+ PackFont (NORMAL , 0 , NORMAL , BOLD ), // 1F
+ PackFont (NORMAL , 0 , BOLD , BOLD ), // 20
+ PackFont (BOLD , 0 , BOLD , NORMAL ), // 21
+ PackFont (BOLD , 0 , NORMAL , BOLD ), // 22
+ PackFont (BOLD , 0 , BOLD , BOLD ), // 23
+ PackFont (0 , NORMAL , NORMAL , NORMAL ), // 24
+ PackFont (0 , BOLD , NORMAL , NORMAL ), // 25
+ PackFont (0 , NORMAL , BOLD , NORMAL ), // 26
+ PackFont (0 , NORMAL , NORMAL , BOLD ), // 27
+ PackFont (0 , NORMAL , BOLD , BOLD ), // 28
+ PackFont (0 , BOLD , BOLD , NORMAL ), // 29
+ PackFont (0 , BOLD , NORMAL , BOLD ), // 2A
+ PackFont (0 , BOLD , BOLD , BOLD ), // 2B
+ PackFont (NORMAL , NORMAL , 0 , NORMAL ), // 2C
+ PackFont (NORMAL , BOLD , 0 , NORMAL ), // 2D
+ PackFont (BOLD , NORMAL , 0 , NORMAL ), // 2E
+ PackFont (BOLD , BOLD , 0 , NORMAL ), // 2F
+ PackFont (NORMAL , NORMAL , 0 , BOLD ), // 30
+ PackFont (NORMAL , BOLD , 0 , BOLD ), // 31
+ PackFont (BOLD , NORMAL , 0 , BOLD ), // 32
+ PackFont (BOLD , BOLD , 0 , BOLD ), // 33
+ PackFont (NORMAL , NORMAL , NORMAL , 0 ), // 34
+ PackFont (NORMAL , BOLD , NORMAL , 0 ), // 35
+ PackFont (BOLD , NORMAL , NORMAL , 0 ), // 36
+ PackFont (BOLD , BOLD , NORMAL , 0 ), // 37
+ PackFont (NORMAL , NORMAL , BOLD , 0 ), // 38
+ PackFont (NORMAL , BOLD , BOLD , 0 ), // 39
+ PackFont (BOLD , NORMAL , BOLD , 0 ), // 3A
+ PackFont (BOLD , BOLD , BOLD , 0 ), // 3B
+ PackFont (NORMAL , NORMAL , NORMAL , NORMAL ), // 3C
+ PackFont (NORMAL , BOLD , NORMAL , NORMAL ), // 3D
+ PackFont (BOLD , NORMAL , NORMAL , NORMAL ), // 3E
+ PackFont (BOLD , BOLD , NORMAL , NORMAL ), // 3F
+ PackFont (NORMAL , NORMAL , BOLD , NORMAL ), // 40
+ PackFont (NORMAL , NORMAL , NORMAL , BOLD ), // 41
+ PackFont (NORMAL , NORMAL , BOLD , BOLD ), // 42
+ PackFont (NORMAL , BOLD , BOLD , NORMAL ), // 43
+ PackFont (BOLD , NORMAL , BOLD , NORMAL ), // 44
+ PackFont (NORMAL , BOLD , NORMAL , BOLD ), // 45
+ PackFont (BOLD , NORMAL , NORMAL , BOLD ), // 46
+ PackFont (BOLD , BOLD , BOLD , NORMAL ), // 47
+ PackFont (BOLD , BOLD , NORMAL , BOLD ), // 48
+ PackFont (NORMAL , BOLD , BOLD , BOLD ), // 49
+ PackFont (BOLD , NORMAL , BOLD , BOLD ), // 4A
+ PackFont (BOLD , BOLD , BOLD , BOLD ), // 4B
+ PackFont (NORMAL + HOLE1, 0 , 0 , 0 ), // 4C
+ PackFont (0 , NORMAL + HOLE1, 0 , 0 ), // 4D
+ PackFont (0 , 0 , NORMAL + HOLE1, 0 ), // 4E
+ PackFont (0 , 0 , 0 , NORMAL + HOLE1 ), // 4F
+ PackFont (DOUBLE , DOUBLE , FILL3 , FILL3 ), // 50
+ PackFont (FILL3 , FILL3 , DOUBLE , DOUBLE ), // 51
+ PackFont (DOUBLE , 0 , FILL1 , NORMAL ), // 52
+ PackFont (NORMAL , FILL1 , 0 , DOUBLE ), // 53
+ PackFont (DOUBLE , FILL3 , FILL3 , DOUBLE ), // 54
+ PackFont (0 , DOUBLE , FILL1 , NORMAL ), // 55
+ PackFont (FILL1 , NORMAL , 0 , DOUBLE ), // 56
+ PackFont (FILL3 , DOUBLE , FILL3 , DOUBLE ), // 57
+ PackFont (DOUBLE , 0 , NORMAL , FILL1 ), // 58
+ PackFont (NORMAL , FILL1 , DOUBLE , 0 ), // 59
+ PackFont (DOUBLE , FILL3 , DOUBLE , FILL3 ), // 5A
+ PackFont (0 , DOUBLE , NORMAL , FILL1 ), // 5B
+ PackFont (FILL1 , NORMAL , DOUBLE , 0 ), // 5C
+ PackFont (FILL3 , DOUBLE , DOUBLE , FILL3 ), // 5D
+ PackFont (DOUBLE , 0 , NORMAL , NORMAL ), // 5E
+ PackFont (SHORTNORMAL , FILL3 , DOUBLE , DOUBLE ), // 5F
+ PackFont (DOUBLE , FILL3 , DOUBLE , DOUBLE ), // 60
+ PackFont (0 , DOUBLE , NORMAL , NORMAL ), // 61
+ PackFont (FILL3 , SHORTNORMAL , DOUBLE , DOUBLE ), // 62
+ PackFont (FILL3 , DOUBLE , DOUBLE , DOUBLE ), // 63
+ PackFont (DOUBLE , DOUBLE , FILL3 , SHORTNORMAL ), // 64
+ PackFont (NORMAL , NORMAL , 0 , DOUBLE ), // 65
+ PackFont (DOUBLE , DOUBLE , FILL3 , DOUBLE ), // 66
+ PackFont (DOUBLE , DOUBLE , SHORTNORMAL , FILL3 ), // 67
+ PackFont (NORMAL , NORMAL , DOUBLE , 0 ), // 68
+ PackFont (DOUBLE , DOUBLE , DOUBLE , FILL3 ), // 69
+ PackFont (DOUBLE , DOUBLE , NORMAL , NORMAL ), // 6A
+ PackFont (NORMAL , NORMAL , DOUBLE , DOUBLE ), // 6B
+ PackFont (DOUBLE , DOUBLE , DOUBLE , DOUBLE ), // 6C
+ PackFont (0 , 0 , 0 , 0 ), // 6D
+ PackFont (0 , 0 , 0 , 0 ), // 6E
+ PackFont (0 , 0 , 0 , 0 ), // 6F
+ PackFont (0 , 0 , 0 , 0 ), // 70
+ PackFont (0 , 0 , 0 , 0 ), // 71
+ PackFont (0 , 0 , 0 , 0 ), // 72
+ PackFont (0 , 0 , 0 , 0 ), // 73
+ PackFont (0 , NORMAL , 0 , 0 ), // 74
+ PackFont (0 , 0 , NORMAL , 0 ), // 75
+ PackFont (NORMAL , 0 , 0 , 0 ), // 76
+ PackFont (0 , 0 , 0 , NORMAL ), // 77
+ PackFont (0 , BOLD , 0 , 0 ), // 78
+ PackFont (0 , 0 , BOLD , 0 ), // 79
+ PackFont (BOLD , 0 , 0 , 0 ), // 7A
+ PackFont (0 , 0 , 0 , BOLD ), // 7B
+ PackFont (BOLD , NORMAL , 0 , 0 ), // 7C
+ PackFont (0 , 0 , NORMAL , BOLD ), // 7D
+ PackFont (NORMAL , BOLD , 0 , 0 ), // 7E
+ PackFont (0 , 0 , BOLD , NORMAL ), // 7F
+ PackFont (0 , 0 , 0xf , 0xf ) // Invalid
+};
diff --git a/private/ntos/fw/mips/rlefont.c b/private/ntos/fw/mips/rlefont.c
new file mode 100644
index 000000000..23e5910c9
--- /dev/null
+++ b/private/ntos/fw/mips/rlefont.c
@@ -0,0 +1,5342 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ rlefont.c
+
+Abstract:
+
+ This module contains a run length encoded font.
+
+Author:
+
+ David M. Robinson (davidro) 7-Jul-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+
+unsigned char FwRleFont[2180] = {
+
+// Character 1
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000111000000
+// 0000000111000000
+// 0000000111000000
+// 0000000111000000
+// 0000000111000000
+// 0000000111000000
+// 0000000111000000
+// 0000000111000000
+// 0000000111000000
+// 0000000000000000
+// 0000000111000000
+// 0000001111100000
+// 0000001111100000
+// 0000001111100000
+// 0000000111000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x67, // 103
+ 0x3d, // 03 13
+ 0x3d, // 03 13
+ 0x3d, // 03 13
+ 0x3d, // 03 13
+ 0x3d, // 03 13
+ 0x3d, // 03 13
+ 0x3d, // 03 13
+ 0x3d, // 03 13
+ 0x3f, // 03 15
+ 0x0e, // 00 14
+ 0x3c, // 03 12
+ 0x5b, // 05 11
+ 0x5b, // 05 11
+ 0x5c, // 05 12
+ 0x30, // 03 00
+ 0x00, // End
+// Character 2
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001100110000
+// 0000001100110000
+// 0000001100110000
+// 0000001100110000
+// 0000001100110000
+// 0000001100110000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x46, // 70
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x20, // 02 00
+ 0x00, // End
+// Character 3
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0001000100000000
+// 0001000110000000
+// 0001100110000000
+// 0001100010000000
+// 0000100011000000
+// 0000110011000000
+// 0000110011000000
+// 0111111111111110
+// 0000011001100000
+// 0000011000100000
+// 0000001000110000
+// 0000001000110000
+// 0011111111111111
+// 0000000100011000
+// 0000000110011000
+// 0000000110001000
+// 0000000010001100
+// 0000000011001100
+// 0000000011000100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x33, // 51
+ 0x13, // 01 03
+ 0x1b, // 01 11
+ 0x13, // 01 03
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x23, // 02 03
+ 0x1b, // 01 11
+ 0x13, // 01 03
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x27, // 02 07
+ 0xe6, // 14 06
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x23, // 02 03
+ 0x1b, // 01 11
+ 0x13, // 01 03
+ 0x2a, // 02 10
+ 0x13, // 01 03
+ 0x26, // 02 06
+ 0xe7, // 14 07
+ 0x13, // 01 03
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x23, // 02 03
+ 0x1b, // 01 11
+ 0x13, // 01 03
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x23, // 02 03
+ 0x10, // 01 00
+ 0x00, // End
+// Character 4
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000110000000
+// 0000000110000000
+// 0000101111100000
+// 0000111111110000
+// 0000110000111000
+// 0000100000011000
+// 0000000000011000
+// 0000000000110000
+// 0000001111110000
+// 0000111111000000
+// 0001111000000000
+// 0001100000000000
+// 0001100000011000
+// 0001110000111000
+// 0000111111111000
+// 0000011111101000
+// 0000000010000000
+// 0000000011000000
+// 0000000011000000
+// 0000000011000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x47, // 71
+ 0x2e, // 02 14
+ 0x2b, // 02 11
+ 0x11, // 01 01
+ 0x59, // 05 09
+ 0x88, // 08 08
+ 0x24, // 02 04
+ 0x37, // 03 07
+ 0x16, // 01 06
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x2a, // 02 10
+ 0x68, // 06 08
+ 0x69, // 06 09
+ 0x4c, // 04 12
+ 0x2e, // 02 14
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x34, // 03 04
+ 0x37, // 03 07
+ 0x98, // 09 08
+ 0x61, // 06 01
+ 0x1b, // 01 11
+ 0x1f, // 01 15
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x20, // 02 00
+ 0x00, // End
+// Character 5
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000011100000
+// 0000000111110000
+// 0000001100011000
+// 0000001100011000
+// 0000001100011000
+// 0001100111110000
+// 0001111011100000
+// 0000001110000000
+// 0000000011100000
+// 0000011100111000
+// 0000111110000000
+// 0001100011000000
+// 0001100011000000
+// 0001100011000000
+// 0000111110000000
+// 0000011100000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x58, // 88
+ 0x3c, // 03 12
+ 0x5a, // 05 10
+ 0x23, // 02 03
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x26, // 02 06
+ 0x22, // 02 02
+ 0x57, // 05 07
+ 0x41, // 04 01
+ 0x3b, // 03 11
+ 0x3f, // 03 15
+ 0x3a, // 03 10
+ 0x32, // 03 02
+ 0x37, // 03 07
+ 0x5a, // 05 10
+ 0x23, // 02 03
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x2a, // 02 10
+ 0x5c, // 05 12
+ 0x30, // 03 00
+ 0x00, // End
+// Character 6
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000111100000
+// 0000001111110000
+// 0000001100111000
+// 0000000000011000
+// 0000000000111000
+// 0000000000110000
+// 0000000001110000
+// 0001100011111000
+// 0001110111011000
+// 0000110110001100
+// 0000111100001100
+// 0000011100001100
+// 0000111100011100
+// 0001111111111000
+// 0001110011110000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x67, // 103
+ 0x4b, // 04 11
+ 0x6a, // 06 10
+ 0x22, // 02 02
+ 0x3e, // 03 14
+ 0x2d, // 02 13
+ 0x3d, // 03 13
+ 0x2d, // 02 13
+ 0x37, // 03 07
+ 0x23, // 02 03
+ 0x56, // 05 06
+ 0x31, // 03 01
+ 0x31, // 03 01
+ 0x27, // 02 07
+ 0x21, // 02 01
+ 0x23, // 02 03
+ 0x26, // 02 06
+ 0x44, // 04 04
+ 0x27, // 02 07
+ 0x34, // 03 04
+ 0x26, // 02 06
+ 0x43, // 04 03
+ 0x35, // 03 05
+ 0xa6, // 10 06
+ 0x32, // 03 02
+ 0x40, // 04 00
+ 0x00, // End
+// Character 7
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x47, // 71
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x20, // 02 00
+ 0x00, // End
+// Character 8
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001000000000
+// 0000001100000000
+// 0000000110000000
+// 0000000110000000
+// 0000000011000000
+// 0000000011000000
+// 0000000011000000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000011000000
+// 0000000011000000
+// 0000000011000000
+// 0000000110000000
+// 0000000110000000
+// 0000001100000000
+// 0000001000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x56, // 86
+ 0x1f, // 01 15
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x10, // 01 00
+ 0x00, // End
+// Character 9
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000100000
+// 0000000001100000
+// 0000000011000000
+// 0000000011000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000111000000
+// 0000000011000000
+// 0000000001100000
+// 0000000000100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x5a, // 90
+ 0x1e, // 01 14
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x3e, // 03 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x3e, // 03 14
+ 0x2f, // 02 15
+ 0x2f, // 02 15
+ 0x10, // 01 00
+ 0x00, // End
+// Character 10
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0001100110011000
+// 0001111111111000
+// 0000011111100000
+// 0000001111000000
+// 0000001111000000
+// 0000011001100000
+// 0000010000100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x67, // 103
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x22, // 02 02
+ 0x26, // 02 06
+ 0xa8, // 10 08
+ 0x6b, // 06 11
+ 0x4c, // 04 12
+ 0x4b, // 04 11
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x14, // 01 04
+ 0x10, // 01 00
+ 0x00, // End
+// Character 11
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0111111111111110
+// 0111111111111110
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x67, // 103
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x28, // 02 08
+ 0xe2, // 14 02
+ 0xe8, // 14 08
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x20, // 02 00
+ 0x00, // End
+// Character 12
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000011110000000
+// 0000001111000000
+// 0000001111000000
+// 0000000111000000
+// 0000000111000000
+// 0000000011100000
+// 0000000011100000
+// 0000000001100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0xff, // 255
+ 0x0f, // 00 15
+ 0x07, // 00 07
+ 0x4d, // 04 13
+ 0x4c, // 04 12
+ 0x4d, // 04 13
+ 0x3d, // 03 13
+ 0x3e, // 03 14
+ 0x3d, // 03 13
+ 0x3e, // 03 14
+ 0x20, // 02 00
+ 0x00, // End
+// Character 13
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011111111111100
+// 0011111111111100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0xe2, // 226
+ 0xc4, // 12 04
+ 0xc0, // 12 00
+ 0x00, // End
+// Character 14
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000111000000
+// 0000001111100000
+// 0000001111100000
+// 0000001111100000
+// 0000000111000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0xff, // 255
+ 0x0f, // 00 15
+ 0x09, // 00 09
+ 0x3c, // 03 12
+ 0x5b, // 05 11
+ 0x5b, // 05 11
+ 0x5c, // 05 12
+ 0x30, // 03 00
+ 0x00, // End
+// Character 15
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0001100000000000
+// 0001100000000000
+// 0000110000000000
+// 0000110000000000
+// 0000011000000000
+// 0000011000000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000000110000000
+// 0000000110000000
+// 0000000011000000
+// 0000000011000000
+// 0000000001100000
+// 0000000001100000
+// 0000000000110000
+// 0000000000110000
+// 0000000000011000
+// 0000000000011000
+// 0000000000011000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x33, // 51
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x20, // 02 00
+ 0x00, // End
+// Character 16
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001111000000
+// 0000011111100000
+// 0000111001110000
+// 0000110000110000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0000110000110000
+// 0000111001110000
+// 0000011111100000
+// 0000001111000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x56, // 86
+ 0x4b, // 04 11
+ 0x69, // 06 09
+ 0x32, // 03 02
+ 0x38, // 03 08
+ 0x24, // 02 04
+ 0x27, // 02 07
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x27, // 02 07
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x32, // 03 02
+ 0x39, // 03 09
+ 0x6b, // 06 11
+ 0x40, // 04 00
+ 0x00, // End
+// Character 17
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000111000000
+// 0000000111111000
+// 0000000110111000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0001111111111000
+// 0001111111111000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x57, // 87
+ 0x3d, // 03 13
+ 0x6a, // 06 10
+ 0x21, // 02 01
+ 0x3a, // 03 10
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2a, // 02 10
+ 0xa6, // 10 06
+ 0xa0, // 10 00
+ 0x00, // End
+// Character 18
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000111100000
+// 0000011111111000
+// 0000111000011000
+// 0000110000001000
+// 0000110000000000
+// 0000110000000000
+// 0000110000000000
+// 0000011000000000
+// 0000001100000000
+// 0000000110000000
+// 0000000111000000
+// 0000000011100000
+// 0000000001110000
+// 0000100000011000
+// 0000111111111100
+// 0000111111111100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x57, // 87
+ 0x4a, // 04 10
+ 0x87, // 08 07
+ 0x34, // 03 04
+ 0x27, // 02 07
+ 0x26, // 02 06
+ 0x17, // 01 07
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2f, // 02 15
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x3e, // 03 14
+ 0x3e, // 03 14
+ 0x38, // 03 08
+ 0x16, // 01 06
+ 0x27, // 02 07
+ 0xa6, // 10 06
+ 0xa0, // 10 00
+ 0x00, // End
+// Character 19
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001111100000
+// 0000011111111000
+// 0000111000111000
+// 0000110000000000
+// 0000110000000000
+// 0000110000000000
+// 0000011000000000
+// 0000001111000000
+// 0000111100000000
+// 0001110000000000
+// 0001100000000000
+// 0001100000000000
+// 0001100000000000
+// 0000110000011100
+// 0000111111111100
+// 0000001111110000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x56, // 86
+ 0x5a, // 05 10
+ 0x87, // 08 07
+ 0x33, // 03 03
+ 0x37, // 03 07
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2f, // 02 15
+ 0x4a, // 04 10
+ 0x4b, // 04 11
+ 0x3d, // 03 13
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x25, // 02 05
+ 0x36, // 03 06
+ 0xa8, // 10 08
+ 0x60, // 06 00
+ 0x00, // End
+// Character 20
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001110000000
+// 0000001110000000
+// 0000001111000000
+// 0000001101100000
+// 0000001101100000
+// 0000001100110000
+// 0000001100010000
+// 0000001100011000
+// 0000001100001000
+// 0000001100001100
+// 0001111111111100
+// 0001111111111100
+// 0000001100000000
+// 0000001100000000
+// 0001111111000000
+// 0001111111000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x56, // 86
+ 0x3d, // 03 13
+ 0x3d, // 03 13
+ 0x4c, // 04 12
+ 0x21, // 02 01
+ 0x2b, // 02 11
+ 0x21, // 02 01
+ 0x2b, // 02 11
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x23, // 02 03
+ 0x1a, // 01 10
+ 0x23, // 02 03
+ 0x29, // 02 09
+ 0x24, // 02 04
+ 0x19, // 01 09
+ 0x24, // 02 04
+ 0x25, // 02 05
+ 0xb5, // 11 05
+ 0xb8, // 11 08
+ 0x2e, // 02 14
+ 0x2b, // 02 11
+ 0x79, // 07 09
+ 0x70, // 07 00
+ 0x00, // End
+// Character 21
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000111111111000
+// 0000111111111000
+// 0000000000011000
+// 0000000000011000
+// 0000000000011000
+// 0000001111111000
+// 0000011111111000
+// 0000111000011000
+// 0001110000000000
+// 0001100000000000
+// 0001100000000000
+// 0001100000000000
+// 0001110000000000
+// 0000111000001100
+// 0000011111111100
+// 0000001111110000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x54, // 84
+ 0x97, // 09 07
+ 0x9e, // 09 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x29, // 02 09
+ 0x78, // 07 08
+ 0x87, // 08 07
+ 0x34, // 03 04
+ 0x26, // 02 06
+ 0x3d, // 03 13
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x3e, // 03 14
+ 0x35, // 03 05
+ 0x27, // 02 07
+ 0x98, // 09 08
+ 0x60, // 06 00
+ 0x00, // End
+// Character 22
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0001111100000000
+// 0000111111000000
+// 0000000011100000
+// 0000000001110000
+// 0000000000110000
+// 0000000000110000
+// 0000001111011000
+// 0000111111111000
+// 0000110000111000
+// 0001100000111000
+// 0001100000011000
+// 0001100000011000
+// 0001100000110000
+// 0000110001110000
+// 0000111111100000
+// 0000001111000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x53, // 83
+ 0x5c, // 05 12
+ 0x6e, // 06 14
+ 0x3e, // 03 14
+ 0x3e, // 03 14
+ 0x2e, // 02 14
+ 0x2a, // 02 10
+ 0x41, // 04 01
+ 0x27, // 02 07
+ 0x97, // 09 07
+ 0x24, // 02 04
+ 0x36, // 03 06
+ 0x25, // 02 05
+ 0x36, // 03 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x25, // 02 05
+ 0x28, // 02 08
+ 0x23, // 02 03
+ 0x38, // 03 08
+ 0x7b, // 07 11
+ 0x40, // 04 00
+ 0x00, // End
+// Character 23
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0001111111111000
+// 0001111111111000
+// 0001100000011000
+// 0000100000000000
+// 0000110000000000
+// 0000110000000000
+// 0000011000000000
+// 0000011000000000
+// 0000011000000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000000110000000
+// 0000000110000000
+// 0000000111000000
+// 0000000011000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x53, // 83
+ 0xa6, // 10 06
+ 0xa6, // 10 06
+ 0x26, // 02 06
+ 0x27, // 02 07
+ 0x1f, // 01 15
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x3e, // 03 14
+ 0x20, // 02 00
+ 0x00, // End
+// Character 24
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001111000000
+// 0000111111110000
+// 0000110000110000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0000110000110000
+// 0000011111100000
+// 0000011111100000
+// 0000110000110000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001110000111000
+// 0000111111110000
+// 0000001111000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x56, // 86
+ 0x4a, // 04 10
+ 0x88, // 08 08
+ 0x24, // 02 04
+ 0x27, // 02 07
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x27, // 02 07
+ 0x24, // 02 04
+ 0x29, // 02 09
+ 0x6a, // 06 10
+ 0x69, // 06 09
+ 0x24, // 02 04
+ 0x27, // 02 07
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x34, // 03 04
+ 0x37, // 03 07
+ 0x8a, // 08 10
+ 0x40, // 04 00
+ 0x00, // End
+// Character 25
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001111000000
+// 0000011111110000
+// 0000111000110000
+// 0000110000011000
+// 0001100000011000
+// 0001100000011000
+// 0001110000011000
+// 0001110000110000
+// 0001111111110000
+// 0001101111000000
+// 0001110000000000
+// 0000110000000000
+// 0000111000000000
+// 0000011100000000
+// 0000001111110000
+// 0000000011111000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x56, // 86
+ 0x4b, // 04 11
+ 0x78, // 07 08
+ 0x33, // 03 03
+ 0x28, // 02 08
+ 0x25, // 02 05
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x35, // 03 05
+ 0x26, // 02 06
+ 0x34, // 03 04
+ 0x27, // 02 07
+ 0x97, // 09 07
+ 0x21, // 02 01
+ 0x49, // 04 09
+ 0x3e, // 03 14
+ 0x2e, // 02 14
+ 0x3e, // 03 14
+ 0x3e, // 03 14
+ 0x6c, // 06 12
+ 0x50, // 05 00
+ 0x00, // End
+// Character 26
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000111000000
+// 0000001111100000
+// 0000001111100000
+// 0000001111100000
+// 0000000111000000
+// 0000000000000000
+// 0000000111000000
+// 0000001111100000
+// 0000001111100000
+// 0000001111100000
+// 0000000111000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0xa7, // 167
+ 0x3c, // 03 12
+ 0x5b, // 05 11
+ 0x5b, // 05 11
+ 0x5c, // 05 12
+ 0x3f, // 03 15
+ 0x0e, // 00 14
+ 0x3c, // 03 12
+ 0x5b, // 05 11
+ 0x5b, // 05 11
+ 0x5c, // 05 12
+ 0x30, // 03 00
+ 0x00, // End
+// Character 27
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001110000000
+// 0000011111000000
+// 0000011111000000
+// 0000011111000000
+// 0000001110000000
+// 0000000000000000
+// 0000000000000000
+// 0000011110000000
+// 0000001110000000
+// 0000001111000000
+// 0000000111000000
+// 0000000111000000
+// 0000000011000000
+// 0000000011100000
+// 0000000001100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0xa6, // 166
+ 0x3c, // 03 12
+ 0x5b, // 05 11
+ 0x5b, // 05 11
+ 0x5c, // 05 12
+ 0x3f, // 03 15
+ 0x0f, // 00 15
+ 0x0e, // 00 14
+ 0x4d, // 04 13
+ 0x3d, // 03 13
+ 0x4d, // 04 13
+ 0x3d, // 03 13
+ 0x3e, // 03 14
+ 0x2e, // 02 14
+ 0x3e, // 03 14
+ 0x20, // 02 00
+ 0x00, // End
+// Character 28
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011000000000000
+// 0011110000000000
+// 0000111110000000
+// 0000000111100000
+// 0000000001111000
+// 0000000000011110
+// 0000000000011110
+// 0000000001111000
+// 0000000111100000
+// 0000111110000000
+// 0011111000000000
+// 0011000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x72, // 114
+ 0x2e, // 02 14
+ 0x4e, // 04 14
+ 0x5e, // 05 14
+ 0x4e, // 04 14
+ 0x4e, // 04 14
+ 0x4c, // 04 12
+ 0x4a, // 04 10
+ 0x4a, // 04 10
+ 0x49, // 04 09
+ 0x59, // 05 09
+ 0x5b, // 05 11
+ 0x20, // 02 00
+ 0x00, // End
+// Character 29
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011111111111110
+// 0011111111111110
+// 0000000000000000
+// 0000000000000000
+// 0011111111111110
+// 0011111111111110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0xa2, // 162
+ 0xd3, // 13 03
+ 0xdf, // 13 15
+ 0x0f, // 00 15
+ 0x05, // 00 05
+ 0xd3, // 13 03
+ 0xd0, // 13 00
+ 0x00, // End
+// Character 30
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000110
+// 0000000000011110
+// 0000000011111000
+// 0000001111000000
+// 0000111100000000
+// 0011110000000000
+// 0011110000000000
+// 0000111100000000
+// 0000001111000000
+// 0000000011111000
+// 0000000000111110
+// 0000000000000110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x7d, // 125
+ 0x2c, // 02 12
+ 0x49, // 04 09
+ 0x59, // 05 09
+ 0x4a, // 04 10
+ 0x4a, // 04 10
+ 0x4c, // 04 12
+ 0x4e, // 04 14
+ 0x4e, // 04 14
+ 0x4e, // 04 14
+ 0x5d, // 05 13
+ 0x5e, // 05 14
+ 0x20, // 02 00
+ 0x00, // End
+// Character 31
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001111110000
+// 0000011111111000
+// 0000111000011000
+// 0000110000001000
+// 0000110000000000
+// 0000011000000000
+// 0000011111000000
+// 0000000111000000
+// 0000000001000000
+// 0000000000000000
+// 0000000011100000
+// 0000000111110000
+// 0000000111110000
+// 0000000111110000
+// 0000000011100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x66, // 102
+ 0x69, // 06 09
+ 0x87, // 08 07
+ 0x34, // 03 04
+ 0x27, // 02 07
+ 0x26, // 02 06
+ 0x17, // 01 07
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x5d, // 05 13
+ 0x3f, // 03 15
+ 0x1f, // 01 15
+ 0x0f, // 00 15
+ 0x3c, // 03 12
+ 0x5b, // 05 11
+ 0x5b, // 05 11
+ 0x5c, // 05 12
+ 0x30, // 03 00
+ 0x00, // End
+// Character 32
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001111000000
+// 0000011111100000
+// 0000111001110000
+// 0000110000110000
+// 0000110000110000
+// 0000110000011000
+// 0000111110011000
+// 0000110011011000
+// 0000110001111000
+// 0000110001111000
+// 0000110001111000
+// 0000111111111000
+// 0000111111011000
+// 0000000000110000
+// 0000000000110000
+// 0000000001110000
+// 0000111111100000
+// 0000011111000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x46, // 70
+ 0x4b, // 04 11
+ 0x69, // 06 09
+ 0x32, // 03 02
+ 0x38, // 03 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x52, // 05 02
+ 0x27, // 02 07
+ 0x22, // 02 02
+ 0x21, // 02 01
+ 0x27, // 02 07
+ 0x23, // 02 03
+ 0x47, // 04 07
+ 0x23, // 02 03
+ 0x47, // 04 07
+ 0x23, // 02 03
+ 0x47, // 04 07
+ 0x97, // 09 07
+ 0x61, // 06 01
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x38, // 03 08
+ 0x7a, // 07 10
+ 0x50, // 05 00
+ 0x00, // End
+// Character 33
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000111111000
+// 0000000111111000
+// 0000000101100000
+// 0000001101100000
+// 0000001100100000
+// 0000011000110000
+// 0000011000110000
+// 0000110000010000
+// 0000111111111000
+// 0001111111111000
+// 0001100000001100
+// 0011000000001100
+// 0011000000001100
+// 1111111000111111
+// 1111111000111111
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x67, // 103
+ 0x6a, // 06 10
+ 0x6a, // 06 10
+ 0x11, // 01 01
+ 0x2b, // 02 11
+ 0x21, // 02 01
+ 0x2b, // 02 11
+ 0x22, // 02 02
+ 0x1a, // 01 10
+ 0x23, // 02 03
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x28, // 02 08
+ 0x25, // 02 05
+ 0x18, // 01 08
+ 0x96, // 09 06
+ 0xa6, // 10 06
+ 0x27, // 02 07
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x22, // 02 02
+ 0x73, // 07 03
+ 0xd3, // 13 03
+ 0x60, // 06 00
+ 0x00, // End
+// Character 34
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000011111111110
+// 0000111111111110
+// 0001110000011000
+// 0001100000011000
+// 0001100000011000
+// 0001110000011000
+// 0000111111111000
+// 0001111111111000
+// 0011100000011000
+// 0011000000011000
+// 0011000000011000
+// 0011000000011000
+// 0011100000011000
+// 0001111111111110
+// 0000111111111110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x65, // 101
+ 0xa5, // 10 05
+ 0xb4, // 11 04
+ 0x35, // 03 05
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x35, // 03 05
+ 0x27, // 02 07
+ 0x96, // 09 06
+ 0xa5, // 10 05
+ 0x36, // 03 06
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x36, // 03 06
+ 0x26, // 02 06
+ 0xc5, // 12 05
+ 0xb0, // 11 00
+ 0x00, // End
+// Character 35
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011011111000000
+// 0011111111110000
+// 0011110000111000
+// 0011100000001100
+// 0011000000001100
+// 0000000000000110
+// 0000000000000110
+// 0000000000000110
+// 0000000000000110
+// 0000000000000110
+// 0000000000001100
+// 0010000000001100
+// 0011100000111000
+// 0001111111110000
+// 0000011111000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x62, // 98
+ 0x21, // 02 01
+ 0x58, // 05 08
+ 0xa6, // 10 06
+ 0x44, // 04 04
+ 0x35, // 03 05
+ 0x37, // 03 07
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x24, // 02 04
+ 0x19, // 01 09
+ 0x24, // 02 04
+ 0x35, // 03 05
+ 0x36, // 03 06
+ 0x99, // 09 09
+ 0x50, // 05 00
+ 0x00, // End
+// Character 36
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000011111111100
+// 0000111111111100
+// 0001110000011000
+// 0011000000011000
+// 0111000000011000
+// 0110000000011000
+// 0110000000011000
+// 0110000000011000
+// 0110000000011000
+// 0110000000011000
+// 0011000000011000
+// 0011000000011000
+// 0001110000011000
+// 0000111111111100
+// 0000011111111100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x65, // 101
+ 0x96, // 09 06
+ 0xa5, // 10 05
+ 0x35, // 03 05
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x24, // 02 04
+ 0x37, // 03 07
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x26, // 02 06
+ 0x35, // 03 05
+ 0x27, // 02 07
+ 0xa7, // 10 07
+ 0x90, // 09 00
+ 0x00, // End
+// Character 37
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011111111111110
+// 0011111111111110
+// 0011000000011000
+// 0011000000011000
+// 0011011000011000
+// 0000011000011000
+// 0000011111111000
+// 0000011111111000
+// 0000011000011000
+// 0000011000011000
+// 0011000000011000
+// 0011000000011000
+// 0011000000011000
+// 0011111111111110
+// 0011111111111110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x62, // 98
+ 0xd3, // 13 03
+ 0xd3, // 13 03
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x21, // 02 01
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x88, // 08 08
+ 0x88, // 08 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0xd3, // 13 03
+ 0xd0, // 13 00
+ 0x00, // End
+// Character 38
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011111111111110
+// 0011111111111110
+// 0011000000011000
+// 0011000000011000
+// 0011011000011000
+// 0000011000011000
+// 0000011111111000
+// 0000011111111000
+// 0000011000011000
+// 0000011000011000
+// 0000000000011000
+// 0000000000011000
+// 0000000000011000
+// 0000000111111110
+// 0000000111111110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x62, // 98
+ 0xd3, // 13 03
+ 0xd3, // 13 03
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x21, // 02 01
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x88, // 08 08
+ 0x88, // 08 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2a, // 02 10
+ 0x88, // 08 08
+ 0x80, // 08 00
+ 0x00, // End
+// Character 39
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011011111000000
+// 0011111111110000
+// 0011110000111000
+// 0011100000001100
+// 0011000000001100
+// 0000000000000110
+// 0000000000000110
+// 0000000000000110
+// 0111111100000110
+// 0111111100000110
+// 0011000000001100
+// 0011000000011100
+// 0011000000111000
+// 0011111111110000
+// 0000111111000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x62, // 98
+ 0x21, // 02 01
+ 0x58, // 05 08
+ 0xa6, // 10 06
+ 0x44, // 04 04
+ 0x35, // 03 05
+ 0x37, // 03 07
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x22, // 02 02
+ 0x75, // 07 05
+ 0x22, // 02 02
+ 0x75, // 07 05
+ 0x23, // 02 03
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x27, // 02 07
+ 0x34, // 03 04
+ 0x26, // 02 06
+ 0x35, // 03 05
+ 0xa8, // 10 08
+ 0x60, // 06 00
+ 0x00, // End
+// Character 40
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011111001111100
+// 0011111001111100
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001111111111000
+// 0001111111111000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0011111001111100
+// 0011111001111100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x62, // 98
+ 0x52, // 05 02
+ 0x54, // 05 04
+ 0x52, // 05 02
+ 0x55, // 05 05
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0xa6, // 10 06
+ 0xa6, // 10 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x25, // 02 05
+ 0x52, // 05 02
+ 0x54, // 05 04
+ 0x52, // 05 02
+ 0x50, // 05 00
+ 0x00, // End
+// Character 41
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0001111111111100
+// 0001111111111100
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0001111111111100
+// 0001111111111100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x63, // 99
+ 0xb5, // 11 05
+ 0xb9, // 11 09
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2a, // 02 10
+ 0xb5, // 11 05
+ 0xb0, // 11 00
+ 0x00, // End
+// Character 42
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011111111100000
+// 0011111111100000
+// 0000011000000000
+// 0000011000000000
+// 0000011000000000
+// 0000011000000000
+// 0000011000000000
+// 0000011000000000
+// 0000011000000110
+// 0000011000000110
+// 0000011000000110
+// 0000011000000110
+// 0000011100001110
+// 0000001111111110
+// 0000000111111000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x62, // 98
+ 0x97, // 09 07
+ 0x9a, // 09 10
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x34, // 03 04
+ 0x37, // 03 07
+ 0x98, // 09 08
+ 0x60, // 06 00
+ 0x00, // End
+// Character 43
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011111001111110
+// 0011111001111110
+// 0000110000011000
+// 0000011000011000
+// 0000001100011000
+// 0000000110011000
+// 0000000011011000
+// 0000001111111000
+// 0000011100111000
+// 0000011000011000
+// 0000110000011000
+// 0000110000011000
+// 0001100000011000
+// 0111100001111110
+// 0111000001111110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x62, // 98
+ 0x52, // 05 02
+ 0x63, // 06 03
+ 0x52, // 05 02
+ 0x65, // 06 05
+ 0x25, // 02 05
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2b, // 02 11
+ 0x21, // 02 01
+ 0x29, // 02 09
+ 0x78, // 07 08
+ 0x32, // 03 02
+ 0x38, // 03 08
+ 0x24, // 02 04
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x24, // 02 04
+ 0x44, // 04 04
+ 0x62, // 06 02
+ 0x35, // 03 05
+ 0x60, // 06 00
+ 0x00, // End
+// Character 44
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001111111110
+// 0000001111111110
+// 0000000000110000
+// 0000000000110000
+// 0000000000110000
+// 0000000000110000
+// 0000000000110000
+// 0000000000110000
+// 0110000000110000
+// 0110000000110000
+// 0110000000110000
+// 0110000000110000
+// 0110000000110000
+// 0111111111111110
+// 0111111111111110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x66, // 102
+ 0x97, // 09 07
+ 0x9b, // 09 11
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0xe2, // 14 02
+ 0xe0, // 14 00
+ 0x00, // End
+// Character 45
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0111100000011110
+// 0111100000011110
+// 0011110000111100
+// 0011110000111100
+// 0011010001101100
+// 0011011001101100
+// 0011001001001100
+// 0011001111001100
+// 0011000110001100
+// 0011000110001100
+// 0011000000001100
+// 0011000000001100
+// 0011000000001100
+// 0111110000111111
+// 0111110000111111
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x61, // 97
+ 0x46, // 04 06
+ 0x42, // 04 02
+ 0x46, // 04 06
+ 0x43, // 04 03
+ 0x44, // 04 04
+ 0x44, // 04 04
+ 0x44, // 04 04
+ 0x44, // 04 04
+ 0x21, // 02 01
+ 0x13, // 01 03
+ 0x21, // 02 01
+ 0x24, // 02 04
+ 0x21, // 02 01
+ 0x22, // 02 02
+ 0x21, // 02 01
+ 0x24, // 02 04
+ 0x22, // 02 02
+ 0x12, // 01 02
+ 0x12, // 01 02
+ 0x24, // 02 04
+ 0x22, // 02 02
+ 0x42, // 04 02
+ 0x24, // 02 04
+ 0x23, // 02 03
+ 0x23, // 02 03
+ 0x24, // 02 04
+ 0x23, // 02 03
+ 0x23, // 02 03
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x23, // 02 03
+ 0x54, // 05 04
+ 0x61, // 06 01
+ 0x54, // 05 04
+ 0x60, // 06 00
+ 0x00, // End
+// Character 46
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0111111000011110
+// 0111111000111110
+// 0011000001111000
+// 0011000001111000
+// 0011000011011000
+// 0011000011011000
+// 0011000110011000
+// 0011001100011000
+// 0011001100011000
+// 0011011000011000
+// 0011011000011000
+// 0011110000011000
+// 0011110000011000
+// 0011100011111100
+// 0011000011111100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x61, // 97
+ 0x64, // 06 04
+ 0x42, // 04 02
+ 0x63, // 06 03
+ 0x53, // 05 03
+ 0x25, // 02 05
+ 0x45, // 04 05
+ 0x25, // 02 05
+ 0x45, // 04 05
+ 0x24, // 02 04
+ 0x21, // 02 01
+ 0x25, // 02 05
+ 0x24, // 02 04
+ 0x21, // 02 01
+ 0x25, // 02 05
+ 0x23, // 02 03
+ 0x22, // 02 02
+ 0x25, // 02 05
+ 0x22, // 02 02
+ 0x23, // 02 03
+ 0x25, // 02 05
+ 0x22, // 02 02
+ 0x23, // 02 03
+ 0x25, // 02 05
+ 0x21, // 02 01
+ 0x24, // 02 04
+ 0x25, // 02 05
+ 0x21, // 02 01
+ 0x24, // 02 04
+ 0x25, // 02 05
+ 0x45, // 04 05
+ 0x25, // 02 05
+ 0x45, // 04 05
+ 0x25, // 02 05
+ 0x33, // 03 03
+ 0x64, // 06 04
+ 0x24, // 02 04
+ 0x60, // 06 00
+ 0x00, // End
+// Character 47
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000011111100000
+// 0000111111110000
+// 0001110000111000
+// 0011000000001100
+// 0111000000001110
+// 0110000000000110
+// 0110000000000110
+// 0110000000000110
+// 0110000000000110
+// 0110000000000110
+// 0111000000001100
+// 0011000000001100
+// 0001110000111000
+// 0000111111110000
+// 0000011111100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x65, // 101
+ 0x69, // 06 09
+ 0x87, // 08 07
+ 0x34, // 03 04
+ 0x35, // 03 05
+ 0x28, // 02 08
+ 0x23, // 02 03
+ 0x38, // 03 08
+ 0x32, // 03 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x38, // 03 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x25, // 02 05
+ 0x34, // 03 04
+ 0x37, // 03 07
+ 0x89, // 08 09
+ 0x60, // 06 00
+ 0x00, // End
+// Character 48
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000111111111100
+// 0011111111111100
+// 0011100000110000
+// 0110000000110000
+// 0110000000110000
+// 0110000000110000
+// 0110000000110000
+// 0011100000110000
+// 0011111111110000
+// 0000111111110000
+// 0000000000110000
+// 0000000000110000
+// 0000000000110000
+// 0000001111111100
+// 0000001111111100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x64, // 100
+ 0xa4, // 10 04
+ 0xc4, // 12 04
+ 0x35, // 03 05
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x26, // 02 06
+ 0x35, // 03 05
+ 0x26, // 02 06
+ 0xa8, // 10 08
+ 0x8e, // 08 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2a, // 02 10
+ 0x88, // 08 08
+ 0x80, // 08 00
+ 0x00, // End
+// Character 49
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000011111100000
+// 0000111111110000
+// 0001110000111000
+// 0011000000001100
+// 0011000000001100
+// 0110000000000110
+// 0110000000000110
+// 0110000000000110
+// 0110000000000110
+// 0110000000000110
+// 0111000000001110
+// 0011000000001100
+// 0001110000111100
+// 0000111111111000
+// 0000011111100000
+// 0000000000100000
+// 0011111111110000
+// 0011110000110000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x65, // 101
+ 0x69, // 06 09
+ 0x87, // 08 07
+ 0x34, // 03 04
+ 0x35, // 03 05
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x23, // 02 03
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x38, // 03 08
+ 0x33, // 03 03
+ 0x28, // 02 08
+ 0x25, // 02 05
+ 0x34, // 03 04
+ 0x46, // 04 06
+ 0x98, // 09 08
+ 0x6f, // 06 15
+ 0x17, // 01 07
+ 0xa6, // 10 06
+ 0x44, // 04 04
+ 0x20, // 02 00
+ 0x00, // End
+// Character 50
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000011111111110
+// 0000111111111110
+// 0001110000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001110000011000
+// 0000111111111000
+// 0000001111111000
+// 0000011100011000
+// 0000011000011000
+// 0000110000011000
+// 0001110000011000
+// 0111100001111110
+// 0111000001111110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x65, // 101
+ 0xa5, // 10 05
+ 0xb4, // 11 04
+ 0x35, // 03 05
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x35, // 03 05
+ 0x27, // 02 07
+ 0x99, // 09 09
+ 0x78, // 07 08
+ 0x33, // 03 03
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x26, // 02 06
+ 0x35, // 03 05
+ 0x24, // 02 04
+ 0x44, // 04 04
+ 0x62, // 06 02
+ 0x35, // 03 05
+ 0x60, // 06 00
+ 0x00, // End
+// Character 51
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000101111100000
+// 0000111111111000
+// 0000111000011100
+// 0000110000001100
+// 0000100000001100
+// 0000000000001100
+// 0000000001111000
+// 0000011111110000
+// 0000111110000000
+// 0001100000000000
+// 0001100000001100
+// 0001100000001100
+// 0001110000011100
+// 0000111111111100
+// 0000001111101100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x64, // 100
+ 0x11, // 01 01
+ 0x59, // 05 09
+ 0x97, // 09 07
+ 0x34, // 03 04
+ 0x36, // 03 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x17, // 01 07
+ 0x2e, // 02 14
+ 0x2b, // 02 11
+ 0x48, // 04 08
+ 0x78, // 07 08
+ 0x5a, // 05 10
+ 0x2e, // 02 14
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x35, // 03 05
+ 0x36, // 03 06
+ 0xa8, // 10 08
+ 0x51, // 05 01
+ 0x20, // 02 00
+ 0x00, // End
+// Character 52
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011111111111110
+// 0011111111111110
+// 0011000110000110
+// 0011000110000110
+// 0011000110000110
+// 0011000110000110
+// 0010000110000010
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000111111111000
+// 0000111111111000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x62, // 98
+ 0xd3, // 13 03
+ 0xd3, // 13 03
+ 0x23, // 02 03
+ 0x24, // 02 04
+ 0x23, // 02 03
+ 0x23, // 02 03
+ 0x24, // 02 04
+ 0x23, // 02 03
+ 0x23, // 02 03
+ 0x24, // 02 04
+ 0x23, // 02 03
+ 0x23, // 02 03
+ 0x24, // 02 04
+ 0x23, // 02 03
+ 0x14, // 01 04
+ 0x25, // 02 05
+ 0x18, // 01 08
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2b, // 02 11
+ 0x97, // 09 07
+ 0x90, // 09 00
+ 0x00, // End
+// Character 53
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011111000111110
+// 0011111000111110
+// 0001100000001100
+// 0001100000001100
+// 0001100000001100
+// 0001100000001100
+// 0001100000001100
+// 0001100000001100
+// 0001100000001100
+// 0001100000001100
+// 0001100000001100
+// 0001110000011100
+// 0000110000111000
+// 0000111111110000
+// 0000001111100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x62, // 98
+ 0x53, // 05 03
+ 0x53, // 05 03
+ 0x53, // 05 03
+ 0x54, // 05 04
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x35, // 03 05
+ 0x36, // 03 06
+ 0x24, // 02 04
+ 0x37, // 03 07
+ 0x8a, // 08 10
+ 0x50, // 05 00
+ 0x00, // End
+// Character 54
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0111111000111111
+// 0111111000111111
+// 0011000000001100
+// 0001100000001100
+// 0001100000001100
+// 0000100000011000
+// 0000110000011000
+// 0000110000110000
+// 0000011000110000
+// 0000011000110000
+// 0000011001100000
+// 0000001101100000
+// 0000001111000000
+// 0000000111000000
+// 0000000111000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x61, // 97
+ 0x63, // 06 03
+ 0x61, // 06 01
+ 0x63, // 06 03
+ 0x62, // 06 02
+ 0x28, // 02 08
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x26, // 02 06
+ 0x16, // 01 06
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x24, // 02 04
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x29, // 02 09
+ 0x22, // 02 02
+ 0x2b, // 02 11
+ 0x21, // 02 01
+ 0x2b, // 02 11
+ 0x4d, // 04 13
+ 0x3d, // 03 13
+ 0x30, // 03 00
+ 0x00, // End
+// Character 55
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0111111000111111
+// 0111111000111111
+// 0011000000000110
+// 0011000000000110
+// 0001000010000110
+// 0001000010000100
+// 0001100111001100
+// 0001100111001100
+// 0001101101101100
+// 0001101100101100
+// 0001101000101100
+// 0000111000111000
+// 0000111000111000
+// 0000110000011000
+// 0000110000011000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x61, // 97
+ 0x63, // 06 03
+ 0x61, // 06 01
+ 0x63, // 06 03
+ 0x62, // 06 02
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x29, // 02 09
+ 0x24, // 02 04
+ 0x14, // 01 04
+ 0x14, // 01 04
+ 0x24, // 02 04
+ 0x14, // 01 04
+ 0x14, // 01 04
+ 0x15, // 01 05
+ 0x22, // 02 02
+ 0x32, // 03 02
+ 0x25, // 02 05
+ 0x22, // 02 02
+ 0x32, // 03 02
+ 0x25, // 02 05
+ 0x21, // 02 01
+ 0x21, // 02 01
+ 0x21, // 02 01
+ 0x25, // 02 05
+ 0x21, // 02 01
+ 0x22, // 02 02
+ 0x11, // 01 01
+ 0x25, // 02 05
+ 0x21, // 02 01
+ 0x13, // 01 03
+ 0x11, // 01 01
+ 0x26, // 02 06
+ 0x33, // 03 03
+ 0x37, // 03 07
+ 0x33, // 03 03
+ 0x37, // 03 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x20, // 02 00
+ 0x00, // End
+// Character 56
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011111000111110
+// 0011111000111110
+// 0000110000011000
+// 0000111000111000
+// 0000011000110000
+// 0000001101100000
+// 0000001111100000
+// 0000000111000000
+// 0000001101100000
+// 0000011101110000
+// 0000011000110000
+// 0000110000011000
+// 0001110000011100
+// 0011111000111110
+// 0011111000111110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x62, // 98
+ 0x53, // 05 03
+ 0x53, // 05 03
+ 0x53, // 05 03
+ 0x55, // 05 05
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x33, // 03 03
+ 0x38, // 03 08
+ 0x23, // 02 03
+ 0x2a, // 02 10
+ 0x21, // 02 01
+ 0x2b, // 02 11
+ 0x5c, // 05 12
+ 0x3c, // 03 12
+ 0x21, // 02 01
+ 0x2a, // 02 10
+ 0x31, // 03 01
+ 0x39, // 03 09
+ 0x23, // 02 03
+ 0x28, // 02 08
+ 0x25, // 02 05
+ 0x26, // 02 06
+ 0x35, // 03 05
+ 0x34, // 03 04
+ 0x53, // 05 03
+ 0x53, // 05 03
+ 0x53, // 05 03
+ 0x50, // 05 00
+ 0x00, // End
+// Character 57
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0111110001111110
+// 0111110001111110
+// 0001100000011000
+// 0001100000110000
+// 0000110000110000
+// 0000011001100000
+// 0000011011100000
+// 0000001111000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000111111110000
+// 0000111111110000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x61, // 97
+ 0x53, // 05 03
+ 0x62, // 06 02
+ 0x53, // 05 03
+ 0x64, // 06 04
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x25, // 02 05
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x29, // 02 09
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x21, // 02 01
+ 0x3b, // 03 11
+ 0x4d, // 04 13
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2b, // 02 11
+ 0x88, // 08 08
+ 0x80, // 08 00
+ 0x00, // End
+// Character 58
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0001111111111000
+// 0001111111111000
+// 0001110000011000
+// 0000111000011000
+// 0000011000011000
+// 0000001100011000
+// 0000001110000000
+// 0000000110000000
+// 0000000011000000
+// 0001100011100000
+// 0001100001110000
+// 0001100000110000
+// 0001100000011000
+// 0001111111111000
+// 0001111111111000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x63, // 99
+ 0xa6, // 10 06
+ 0xa6, // 10 06
+ 0x35, // 03 05
+ 0x27, // 02 07
+ 0x34, // 03 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x29, // 02 09
+ 0x3e, // 03 14
+ 0x2f, // 02 15
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x38, // 03 08
+ 0x24, // 02 04
+ 0x37, // 03 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0xa6, // 10 06
+ 0xa0, // 10 00
+ 0x00, // End
+// Character 59
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001111100000
+// 0000001111100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000001111100000
+// 0000001111100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x66, // 102
+ 0x5b, // 05 11
+ 0x5e, // 05 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2b, // 02 11
+ 0x5b, // 05 11
+ 0x50, // 05 00
+ 0x00, // End
+// Character 60
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000011000
+// 0000000000011000
+// 0000000000110000
+// 0000000000110000
+// 0000000001100000
+// 0000000001100000
+// 0000000011000000
+// 0000000011000000
+// 0000000011000000
+// 0000000110000000
+// 0000000110000000
+// 0000001100000000
+// 0000001100000000
+// 0000011000000000
+// 0000011000000000
+// 0000110000000000
+// 0000110000000000
+// 0001100000000000
+// 0001100000000000
+// 0001100000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x3b, // 59
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x2d, // 02 13
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x20, // 02 00
+ 0x00, // End
+// Character 61
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001111100000
+// 0000001111100000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001100000000
+// 0000001111100000
+// 0000001111100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x66, // 102
+ 0x5b, // 05 11
+ 0x5b, // 05 11
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x5b, // 05 11
+ 0x50, // 05 00
+ 0x00, // End
+// Character 62
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000010000000
+// 0000000111000000
+// 0000001101100000
+// 0000011000110000
+// 0000110000011000
+// 0000100000001000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x38, // 56
+ 0x1e, // 01 14
+ 0x3c, // 03 12
+ 0x21, // 02 01
+ 0x2a, // 02 10
+ 0x23, // 02 03
+ 0x28, // 02 08
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x17, // 01 07
+ 0x10, // 01 00
+ 0x00, // End
+// Character 63
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 1111111111111111
+// 1111111111111111
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0xff, // 255
+ 0x0f, // 00 15
+ 0x0f, // 00 15
+ 0x0f, // 00 15
+ 0x0f, // 00 15
+ 0x0f, // 00 15
+ 0x0f, // 00 15
+ 0x0f, // 00 15
+ 0x0f, // 00 15
+ 0x0f, // 00 15
+ 0x0f, // 00 15
+ 0x0b, // 00 11
+ 0xf0, // 15 00
+ 0xf0, // 15 00
+ 0x20, // 02 00
+ 0x00, // End
+// Character 64
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000011000
+// 0000000001111000
+// 0000000011100000
+// 0000001100000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x4b, // 75
+ 0x2c, // 02 12
+ 0x4b, // 04 11
+ 0x3b, // 03 11
+ 0x20, // 02 00
+ 0x00, // End
+// Character 65
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000011111100000
+// 0000111111111000
+// 0001110000110000
+// 0001100000000000
+// 0001111111100000
+// 0001111111111000
+// 0001100000011100
+// 0001100000001100
+// 0001100000001100
+// 0001111000011100
+// 0111101111111000
+// 0111100111110000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x95, // 149
+ 0x69, // 06 09
+ 0x96, // 09 06
+ 0x34, // 03 04
+ 0x27, // 02 07
+ 0x2e, // 02 14
+ 0x88, // 08 08
+ 0xa6, // 10 06
+ 0x26, // 02 06
+ 0x35, // 03 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x44, // 04 04
+ 0x33, // 03 03
+ 0x41, // 04 01
+ 0x74, // 07 04
+ 0x42, // 04 02
+ 0x50, // 05 00
+ 0x00, // End
+// Character 66
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000011110
+// 0000000000011110
+// 0000000000011000
+// 0000000000011000
+// 0000000000011000
+// 0000111110011000
+// 0001111111111000
+// 0011100001111000
+// 0011000000111000
+// 0110000000011000
+// 0110000000011000
+// 0110000000011000
+// 0110000000011000
+// 0011000000111000
+// 0011100001111000
+// 0001111111011110
+// 0000111110011110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x4b, // 75
+ 0x4c, // 04 12
+ 0x4c, // 04 12
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x27, // 02 07
+ 0x52, // 05 02
+ 0x26, // 02 06
+ 0xa5, // 10 05
+ 0x34, // 03 04
+ 0x45, // 04 05
+ 0x26, // 02 06
+ 0x34, // 03 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x25, // 02 05
+ 0x26, // 02 06
+ 0x35, // 03 05
+ 0x34, // 03 04
+ 0x46, // 04 06
+ 0x71, // 07 01
+ 0x45, // 04 05
+ 0x52, // 05 02
+ 0x40, // 04 00
+ 0x00, // End
+// Character 67
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0001101111100000
+// 0001111111111000
+// 0001111000011100
+// 0001110000001100
+// 0001100000000110
+// 0000000000000110
+// 0000000000000110
+// 0000000000000110
+// 0001100000001100
+// 0001110000011100
+// 0000111111111000
+// 0000001111100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x93, // 147
+ 0x21, // 02 01
+ 0x58, // 05 08
+ 0xa6, // 10 06
+ 0x44, // 04 04
+ 0x35, // 03 05
+ 0x36, // 03 06
+ 0x25, // 02 05
+ 0x28, // 02 08
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x24, // 02 04
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x35, // 03 05
+ 0x36, // 03 06
+ 0x99, // 09 09
+ 0x50, // 05 00
+ 0x00, // End
+// Character 68
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0001111000000000
+// 0001111000000000
+// 0001100000000000
+// 0001100000000000
+// 0001100000000000
+// 0001100111110000
+// 0001111111111000
+// 0001111000011100
+// 0001110000001100
+// 0001100000000110
+// 0001100000000110
+// 0001100000000110
+// 0001100000000110
+// 0001110000001110
+// 0001111000011100
+// 0111101111111000
+// 0111100111110000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x43, // 67
+ 0x4c, // 04 12
+ 0x4c, // 04 12
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x22, // 02 02
+ 0x57, // 05 07
+ 0xa6, // 10 06
+ 0x44, // 04 04
+ 0x35, // 03 05
+ 0x36, // 03 06
+ 0x25, // 02 05
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x36, // 03 06
+ 0x34, // 03 04
+ 0x44, // 04 04
+ 0x33, // 03 03
+ 0x41, // 04 01
+ 0x74, // 07 04
+ 0x42, // 04 02
+ 0x50, // 05 00
+ 0x00, // End
+// Character 69
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001111100000
+// 0000111111111000
+// 0001110000011100
+// 0011100000001100
+// 0011000000000110
+// 0011111111111110
+// 0011111111111110
+// 0000000000000110
+// 0000000000001110
+// 0011110000011100
+// 0001111111111000
+// 0000011111100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x96, // 150
+ 0x59, // 05 09
+ 0x96, // 09 06
+ 0x35, // 03 05
+ 0x34, // 03 04
+ 0x37, // 03 07
+ 0x24, // 02 04
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0xd3, // 13 03
+ 0xde, // 13 14
+ 0x2d, // 02 13
+ 0x33, // 03 03
+ 0x45, // 04 05
+ 0x35, // 03 05
+ 0xa8, // 10 08
+ 0x60, // 06 00
+ 0x00, // End
+// Character 70
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011111100000000
+// 0011111110000000
+// 0000000111000000
+// 0000000011000000
+// 0000000011000000
+// 0001111111111000
+// 0001111111111000
+// 0000000011000000
+// 0000000011000000
+// 0000000011000000
+// 0000000011000000
+// 0000000011000000
+// 0000000011000000
+// 0000000011000000
+// 0000000011000000
+// 0001111111111000
+// 0001111111111000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x42, // 66
+ 0x6a, // 06 10
+ 0x7e, // 07 14
+ 0x3e, // 03 14
+ 0x2e, // 02 14
+ 0x29, // 02 09
+ 0xa6, // 10 06
+ 0xab, // 10 11
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x29, // 02 09
+ 0xa6, // 10 06
+ 0xa0, // 10 00
+ 0x00, // End
+// Character 71
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0111100111100000
+// 0111111111110000
+// 0001111000111000
+// 0001100000011100
+// 0001100000001100
+// 0001100000001100
+// 0001100000001100
+// 0001100000011100
+// 0001110000111000
+// 0001111111110000
+// 0001100111100000
+// 0001100000000000
+// 0001100000000000
+// 0001100000000000
+// 0000110000000000
+// 0000111111100000
+// 0000001111100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x91, // 145
+ 0x42, // 04 02
+ 0x46, // 04 06
+ 0xb7, // 11 07
+ 0x43, // 04 03
+ 0x36, // 03 06
+ 0x26, // 02 06
+ 0x35, // 03 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x26, // 02 06
+ 0x35, // 03 05
+ 0x34, // 03 04
+ 0x36, // 03 06
+ 0x97, // 09 07
+ 0x22, // 02 02
+ 0x48, // 04 08
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x7b, // 07 11
+ 0x50, // 05 00
+ 0x00, // End
+// Character 72
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000011110
+// 0000000000011110
+// 0000000000011000
+// 0000000000011000
+// 0000000000011000
+// 0000011110011000
+// 0000111111111000
+// 0001110001111000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0111111001111110
+// 0111111001111110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x4b, // 75
+ 0x4c, // 04 12
+ 0x4c, // 04 12
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x28, // 02 08
+ 0x42, // 04 02
+ 0x27, // 02 07
+ 0x96, // 09 06
+ 0x33, // 03 03
+ 0x46, // 04 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x24, // 02 04
+ 0x62, // 06 02
+ 0x62, // 06 02
+ 0x62, // 06 02
+ 0x60, // 06 00
+ 0x00, // End
+// Character 73
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000111000000
+// 0000000111000000
+// 0000000111000000
+// 0000000000000000
+// 0000000000000000
+// 0000000111111000
+// 0000000111111000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0011111111111100
+// 0011111111111100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x47, // 71
+ 0x3d, // 03 13
+ 0x3d, // 03 13
+ 0x3f, // 03 15
+ 0x0f, // 00 15
+ 0x0f, // 00 15
+ 0x6a, // 06 10
+ 0x6a, // 06 10
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x29, // 02 09
+ 0xc4, // 12 04
+ 0xc0, // 12 00
+ 0x00, // End
+// Character 74
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000011100000000
+// 0000011100000000
+// 0000011100000000
+// 0000000000000000
+// 0000000000000000
+// 0000111111111000
+// 0000111111111000
+// 0000110000000000
+// 0000110000000000
+// 0000110000000000
+// 0000110000000000
+// 0000110000000000
+// 0000110000000000
+// 0000110000000000
+// 0000110000000000
+// 0000110000000000
+// 0000110000000000
+// 0000110000000000
+// 0000110000000000
+// 0000011000000000
+// 0000011111111000
+// 0000000111110000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x45, // 69
+ 0x3d, // 03 13
+ 0x3d, // 03 13
+ 0x3f, // 03 15
+ 0x0f, // 00 15
+ 0x0e, // 00 14
+ 0x97, // 09 07
+ 0x97, // 09 07
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x8a, // 08 10
+ 0x50, // 05 00
+ 0x00, // End
+// Character 75
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000111100
+// 0000000000111100
+// 0000000000110000
+// 0000000000110000
+// 0000000000110000
+// 0011111000110000
+// 0011111000110000
+// 0000011000110000
+// 0000001100110000
+// 0000000110110000
+// 0000000111110000
+// 0000001111110000
+// 0000011100110000
+// 0000111000110000
+// 0001110000110000
+// 0111110000111100
+// 0111110000111100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x4a, // 74
+ 0x4c, // 04 12
+ 0x4c, // 04 12
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x26, // 02 06
+ 0x53, // 05 03
+ 0x26, // 02 06
+ 0x53, // 05 03
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2b, // 02 11
+ 0x21, // 02 01
+ 0x2b, // 02 11
+ 0x5a, // 05 10
+ 0x69, // 06 09
+ 0x32, // 03 02
+ 0x28, // 02 08
+ 0x33, // 03 03
+ 0x27, // 02 07
+ 0x34, // 03 04
+ 0x25, // 02 05
+ 0x54, // 05 04
+ 0x43, // 04 03
+ 0x54, // 05 04
+ 0x40, // 04 00
+ 0x00, // End
+// Character 76
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000111111000
+// 0000000111111000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0011111111111100
+// 0011111111111100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x47, // 71
+ 0x6a, // 06 10
+ 0x6a, // 06 10
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x29, // 02 09
+ 0xc4, // 12 04
+ 0xc0, // 12 00
+ 0x00, // End
+// Character 77
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011110011101111
+// 0011111111111111
+// 0110001110001100
+// 0110000110001100
+// 0110000110001100
+// 0110000110001100
+// 0110000110001100
+// 0110000110001100
+// 0110000110001100
+// 0110000110001100
+// 1110011110011111
+// 1110011110011111
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x92, // 146
+ 0x42, // 04 02
+ 0x31, // 03 01
+ 0x42, // 04 02
+ 0xe1, // 14 01
+ 0x23, // 02 03
+ 0x33, // 03 03
+ 0x23, // 02 03
+ 0x24, // 02 04
+ 0x23, // 02 03
+ 0x23, // 02 03
+ 0x24, // 02 04
+ 0x23, // 02 03
+ 0x23, // 02 03
+ 0x24, // 02 04
+ 0x23, // 02 03
+ 0x23, // 02 03
+ 0x24, // 02 04
+ 0x23, // 02 03
+ 0x23, // 02 03
+ 0x24, // 02 04
+ 0x23, // 02 03
+ 0x23, // 02 03
+ 0x24, // 02 04
+ 0x23, // 02 03
+ 0x23, // 02 03
+ 0x24, // 02 04
+ 0x23, // 02 03
+ 0x22, // 02 02
+ 0x32, // 03 02
+ 0x42, // 04 02
+ 0x82, // 08 02
+ 0x42, // 04 02
+ 0x50, // 05 00
+ 0x00, // End
+// Character 78
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000011110011110
+// 0000111111111110
+// 0001110001111000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0111111001111110
+// 0111111001111110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x95, // 149
+ 0x42, // 04 02
+ 0x45, // 04 05
+ 0xb4, // 11 04
+ 0x33, // 03 03
+ 0x46, // 04 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x24, // 02 04
+ 0x62, // 06 02
+ 0x62, // 06 02
+ 0x62, // 06 02
+ 0x60, // 06 00
+ 0x00, // End
+// Character 79
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001111100000
+// 0000111111111000
+// 0001110000011100
+// 0001100000001100
+// 0011000000000110
+// 0011000000000110
+// 0011000000000110
+// 0011000000000110
+// 0001100000001100
+// 0001110000011100
+// 0000111111111000
+// 0000001111100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x96, // 150
+ 0x59, // 05 09
+ 0x96, // 09 06
+ 0x35, // 03 05
+ 0x35, // 03 05
+ 0x27, // 02 07
+ 0x24, // 02 04
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x29, // 02 09
+ 0x24, // 02 04
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x35, // 03 05
+ 0x36, // 03 06
+ 0x99, // 09 09
+ 0x50, // 05 00
+ 0x00, // End
+// Character 80
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000111110011110
+// 0001111111111110
+// 0011100001111000
+// 0011000000111000
+// 0110000000011000
+// 0110000000011000
+// 0110000000011000
+// 0110000000011000
+// 0111000000111000
+// 0011100001111000
+// 0001111111111000
+// 0000111110011000
+// 0000000000011000
+// 0000000000011000
+// 0000000000011000
+// 0000000111111110
+// 0000000111111110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x94, // 148
+ 0x52, // 05 02
+ 0x44, // 04 04
+ 0xc3, // 12 03
+ 0x34, // 03 04
+ 0x45, // 04 05
+ 0x26, // 02 06
+ 0x34, // 03 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x36, // 03 06
+ 0x35, // 03 05
+ 0x34, // 03 04
+ 0x46, // 04 06
+ 0xa7, // 10 07
+ 0x52, // 05 02
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2a, // 02 10
+ 0x88, // 08 08
+ 0x80, // 08 00
+ 0x00, // End
+// Character 81
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0111100111110000
+// 0111101111111000
+// 0001111000011100
+// 0001110000001100
+// 0001100000000110
+// 0001100000000110
+// 0001100000000110
+// 0001100000000110
+// 0001110000001110
+// 0001111000011100
+// 0001101111111000
+// 0001100111110000
+// 0001100000000000
+// 0001100000000000
+// 0001100000000000
+// 0111111110000000
+// 0111111110000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x91, // 145
+ 0x42, // 04 02
+ 0x55, // 05 05
+ 0x41, // 04 01
+ 0x76, // 07 06
+ 0x44, // 04 04
+ 0x35, // 03 05
+ 0x36, // 03 06
+ 0x25, // 02 05
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x36, // 03 06
+ 0x34, // 03 04
+ 0x44, // 04 04
+ 0x35, // 03 05
+ 0x21, // 02 01
+ 0x76, // 07 06
+ 0x22, // 02 02
+ 0x57, // 05 07
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2c, // 02 12
+ 0x88, // 08 08
+ 0x80, // 08 00
+ 0x00, // End
+// Character 82
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0011110001111100
+// 0111111101111100
+// 0010001111100000
+// 0000000011100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000000001100000
+// 0000111111111100
+// 0000111111111100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x92, // 146
+ 0x43, // 04 03
+ 0x53, // 05 03
+ 0x71, // 07 01
+ 0x54, // 05 04
+ 0x13, // 01 03
+ 0x5d, // 05 13
+ 0x3e, // 03 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x29, // 02 09
+ 0xa6, // 10 06
+ 0xa0, // 10 00
+ 0x00, // End
+// Character 83
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000101111110000
+// 0000111111111000
+// 0000111000011100
+// 0000110000001100
+// 0000000000011100
+// 0000011111111000
+// 0000111111100000
+// 0001100000000000
+// 0001100000001100
+// 0001110000011100
+// 0000111111111100
+// 0000011111101100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x94, // 148
+ 0x11, // 01 01
+ 0x68, // 06 08
+ 0x97, // 09 07
+ 0x34, // 03 04
+ 0x36, // 03 06
+ 0x26, // 02 06
+ 0x2d, // 02 13
+ 0x37, // 03 07
+ 0x87, // 08 07
+ 0x78, // 07 08
+ 0x2e, // 02 14
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x35, // 03 05
+ 0x36, // 03 06
+ 0xa7, // 10 07
+ 0x61, // 06 01
+ 0x20, // 02 00
+ 0x00, // End
+// Character 84
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000110000
+// 0000000000110000
+// 0000000000110000
+// 0000111111111110
+// 0000111111111110
+// 0000000000110000
+// 0000000000110000
+// 0000000000110000
+// 0000000000110000
+// 0000000000110000
+// 0000000000110000
+// 0000000000110000
+// 0011100001110000
+// 0001111111100000
+// 0000011111000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x6a, // 106
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x28, // 02 08
+ 0xb5, // 11 05
+ 0xbb, // 11 11
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x26, // 02 06
+ 0x34, // 03 04
+ 0x37, // 03 07
+ 0x8a, // 08 10
+ 0x50, // 05 00
+ 0x00, // End
+// Character 85
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0001111100011110
+// 0001111100011110
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001100000011000
+// 0001111000111000
+// 0111111111110000
+// 0111100111100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x93, // 147
+ 0x53, // 05 03
+ 0x44, // 04 04
+ 0x53, // 05 03
+ 0x44, // 04 04
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x26, // 02 06
+ 0x43, // 04 03
+ 0x34, // 03 04
+ 0xb5, // 11 05
+ 0x42, // 04 02
+ 0x40, // 04 00
+ 0x00, // End
+// Character 86
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 1111110001111110
+// 1111110001111110
+// 0011000000011000
+// 0011000000111000
+// 0001100000110000
+// 0001100000110000
+// 0000110001100000
+// 0000110001100000
+// 0000011011000000
+// 0000011011000000
+// 0000001110000000
+// 0000001110000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x90, // 144
+ 0x63, // 06 03
+ 0x61, // 06 01
+ 0x63, // 06 03
+ 0x63, // 06 03
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x26, // 02 06
+ 0x36, // 03 06
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x25, // 02 05
+ 0x28, // 02 08
+ 0x23, // 02 03
+ 0x29, // 02 09
+ 0x23, // 02 03
+ 0x2a, // 02 10
+ 0x21, // 02 01
+ 0x2b, // 02 11
+ 0x21, // 02 01
+ 0x2c, // 02 12
+ 0x3d, // 03 13
+ 0x30, // 03 00
+ 0x00, // End
+// Character 87
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 1111100000011111
+// 1111100000011111
+// 0110000000000110
+// 0010000110000100
+// 0011001110001100
+// 0011001111001100
+// 0001001111001000
+// 0001101001001000
+// 0001111001111000
+// 0001111001110000
+// 0000110000110000
+// 0000110000110000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x90, // 144
+ 0x56, // 05 06
+ 0xa6, // 10 06
+ 0x51, // 05 01
+ 0x2a, // 02 10
+ 0x23, // 02 03
+ 0x14, // 01 04
+ 0x24, // 02 04
+ 0x14, // 01 04
+ 0x22, // 02 02
+ 0x33, // 03 03
+ 0x24, // 02 04
+ 0x22, // 02 02
+ 0x42, // 04 02
+ 0x25, // 02 05
+ 0x12, // 01 02
+ 0x42, // 04 02
+ 0x16, // 01 06
+ 0x21, // 02 01
+ 0x12, // 01 02
+ 0x12, // 01 02
+ 0x16, // 01 06
+ 0x42, // 04 02
+ 0x46, // 04 06
+ 0x42, // 04 02
+ 0x38, // 03 08
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x20, // 02 00
+ 0x00, // End
+// Character 88
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0111111001111110
+// 0111111001111110
+// 0000110000111000
+// 0000011001110000
+// 0000011111100000
+// 0000001110000000
+// 0000001111000000
+// 0000011001100000
+// 0000110000110000
+// 0001100000011000
+// 0111110001111110
+// 0111110001111110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x91, // 145
+ 0x62, // 06 02
+ 0x62, // 06 02
+ 0x62, // 06 02
+ 0x65, // 06 05
+ 0x24, // 02 04
+ 0x38, // 03 08
+ 0x22, // 02 02
+ 0x39, // 03 09
+ 0x6b, // 06 11
+ 0x3d, // 03 13
+ 0x4b, // 04 11
+ 0x22, // 02 02
+ 0x29, // 02 09
+ 0x24, // 02 04
+ 0x27, // 02 07
+ 0x26, // 02 06
+ 0x24, // 02 04
+ 0x53, // 05 03
+ 0x62, // 06 02
+ 0x53, // 05 03
+ 0x60, // 06 00
+ 0x00, // End
+// Character 89
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0111110001111110
+// 0111110000111110
+// 0001100000011100
+// 0001100000011000
+// 0000110000110000
+// 0000110000110000
+// 0000011001100000
+// 0000011001100000
+// 0000001111000000
+// 0000001111000000
+// 0000000110000000
+// 0000000110000000
+// 0000000011000000
+// 0000000011000000
+// 0000000001100000
+// 0000000111111110
+// 0000000111111110
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x91, // 145
+ 0x53, // 05 03
+ 0x62, // 06 02
+ 0x54, // 05 04
+ 0x54, // 05 04
+ 0x26, // 02 06
+ 0x35, // 03 05
+ 0x26, // 02 06
+ 0x27, // 02 07
+ 0x24, // 02 04
+ 0x28, // 02 08
+ 0x24, // 02 04
+ 0x29, // 02 09
+ 0x22, // 02 02
+ 0x2a, // 02 10
+ 0x22, // 02 02
+ 0x2b, // 02 11
+ 0x4c, // 04 12
+ 0x4d, // 04 13
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x2c, // 02 12
+ 0x88, // 08 08
+ 0x80, // 08 00
+ 0x00, // End
+// Character 90
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0001111111111000
+// 0001111111111000
+// 0000110000011000
+// 0000111000011000
+// 0000011100000000
+// 0000001110000000
+// 0000000111000000
+// 0000000011100000
+// 0001100001110000
+// 0001100000111000
+// 0001111111111000
+// 0001111111111000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x93, // 147
+ 0xa6, // 10 06
+ 0xa7, // 10 07
+ 0x25, // 02 05
+ 0x27, // 02 07
+ 0x34, // 03 04
+ 0x28, // 02 08
+ 0x3e, // 03 14
+ 0x3e, // 03 14
+ 0x3e, // 03 14
+ 0x38, // 03 08
+ 0x24, // 02 04
+ 0x37, // 03 07
+ 0x25, // 02 05
+ 0x36, // 03 06
+ 0xa6, // 10 06
+ 0xa0, // 10 00
+ 0x00, // End
+// Character 91
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000111000000000
+// 0000111100000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000011100000
+// 0000000001110000
+// 0000000011100000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000111100000000
+// 0000111000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x54, // 84
+ 0x3d, // 03 13
+ 0x4f, // 04 15
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x3e, // 03 14
+ 0x3c, // 03 12
+ 0x3c, // 03 12
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2b, // 02 11
+ 0x4c, // 04 12
+ 0x30, // 03 00
+ 0x00, // End
+// Character 92
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x07, // 7
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x20, // 02 00
+ 0x00, // End
+// Character 93
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000001110000
+// 0000000011110000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000011100000000
+// 0000111000000000
+// 0000011100000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000110000000
+// 0000000011110000
+// 0000000001110000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0x59, // 89
+ 0x3c, // 03 12
+ 0x4b, // 04 11
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2c, // 02 12
+ 0x3c, // 03 12
+ 0x3e, // 03 14
+ 0x3f, // 03 15
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2e, // 02 14
+ 0x2f, // 02 15
+ 0x4d, // 04 13
+ 0x30, // 03 00
+ 0x00, // End
+// Character 94
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0010000011110000
+// 0011111111111100
+// 0000111100000100
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0xb2, // 178
+ 0x15, // 01 05
+ 0x46, // 04 06
+ 0xc6, // 12 06
+ 0x45, // 04 05
+ 0x10, // 01 00
+ 0x00, // End
+// Character 95
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000001111100000
+// 0000111111111000
+// 0000111111111000
+// 0000111111111000
+// 0000111111111000
+// 0000001111100000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+// 0000000000000000
+ 0xa6, // 166
+ 0x59, // 05 09
+ 0x97, // 09 07
+ 0x97, // 09 07
+ 0x97, // 09 07
+ 0x99, // 09 09
+ 0x50, // 05 00
+ 0x00 // End
+};
+// Total bytes = 2180
diff --git a/private/ntos/fw/mips/scsiport.c b/private/ntos/fw/mips/scsiport.c
new file mode 100644
index 000000000..670b329af
--- /dev/null
+++ b/private/ntos/fw/mips/scsiport.c
@@ -0,0 +1,4927 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ scsiboot.c
+
+Abstract:
+
+ This is the NT SCSI port driver.
+
+Author:
+
+ Mike Glass
+ Jeff Havens
+
+Environment:
+
+ kernel mode only
+
+Notes:
+
+ This module is linked into the kernel.
+
+Revision History:
+
+--*/
+
+#if !defined(DECSTATION)
+
+#include "stdarg.h"
+#include "stdio.h"
+#ifdef MIPS
+#include "..\fw\mips\fwp.h"
+#elif defined(ALPHA)
+#include "..\fw\alpha\fwp.h"
+#else
+#include "boot.h"
+#endif
+#include "scsi.h"
+#include "scsiboot.h"
+
+ULONG ScsiPortCount;
+ULONG ScsiDebug = 0;
+PDEVICE_OBJECT ScsiPortDeviceObject[10];
+PINQUIRYDATA InquiryDataBuffer;
+FULL_SCSI_REQUEST_BLOCK PrimarySrb;
+FULL_SCSI_REQUEST_BLOCK RequestSenseSrb;
+FULL_SCSI_REQUEST_BLOCK AbortSrb;
+
+//
+// Function declarations
+//
+VOID
+IopAllocateCommonBuffer(
+ IN PVOID NonCachedExtension,
+ IN ULONG NonCachedExtensionSize,
+ OUT PPHYSICAL_ADDRESS LogicalAddress
+ );
+
+ARC_STATUS
+ScsiPortDispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+ScsiPortExecute(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+VOID
+ScsiPortStartIo (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ );
+
+BOOLEAN
+ScsiPortInterrupt(
+ IN PKINTERRUPT InterruptObject,
+ IN PDEVICE_OBJECT DeviceObject
+ );
+
+VOID
+ScsiPortCompletionDpc(
+ IN PKDPC Dpc,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ );
+
+VOID
+ScsiPortTickHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context
+ );
+
+IO_ALLOCATION_ACTION
+ScsiPortAllocationRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+ARC_STATUS
+IssueInquiry(
+ IN PDEVICE_EXTENSION deviceExtension,
+ IN PLUNINFO LunInfo
+ );
+
+VOID
+IssueRequestSense(
+ IN PDEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK FailingSrb
+ );
+
+VOID
+ScsiPortInternalCompletion(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context
+ );
+
+PSCSI_BUS_SCAN_DATA
+ScsiBusScan(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN UCHAR ScsiBus,
+ IN UCHAR InitiatorBusId
+ );
+
+PLOGICAL_UNIT_EXTENSION
+CreateLogicalUnitExtension(
+ IN PDEVICE_EXTENSION DeviceExtension
+ );
+
+BOOLEAN
+SpStartIoSynchronized (
+ PVOID ServiceContext
+ );
+
+VOID
+IssueAbortRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PIRP FailingIrp
+ );
+
+IO_ALLOCATION_ACTION
+SpBuildScatterGather(
+ IN struct _DEVICE_OBJECT *DeviceObject,
+ IN struct _IRP *Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+BOOLEAN
+SpGetInterruptState(
+ IN PVOID ServiceContext
+ );
+
+VOID
+SpTimerDpc(
+ IN PKDPC Dpc,
+ IN PVOID Context,
+ IN PVOID SystemContext1,
+ IN PVOID SystemContext2
+ );
+
+PLOGICAL_UNIT_EXTENSION
+GetLogicalUnitExtension(
+ PDEVICE_EXTENSION DeviceExtension,
+ UCHAR TargetId
+ );
+
+NTSTATUS
+SpInitializeConfiguration(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PHW_INITIALIZATION_DATA HwInitData,
+ OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN BOOLEAN InitialCall
+ );
+
+NTSTATUS
+SpGetCommonBuffer(
+ PDEVICE_EXTENSION DeviceExtension,
+ ULONG NonCachedExtensionSize
+ );
+
+#ifdef i386
+ULONG
+HalpGetCmosData(
+ IN ULONG SourceLocation,
+ IN ULONG SourceAddress,
+ IN PVOID ReturnBuffer,
+ IN ULONG ByteCount
+ );
+#endif
+
+//
+// Routines start
+//
+
+ULONG
+ScsiPortInitialize(
+ IN PVOID Argument1,
+ IN PVOID Argument2,
+ IN struct _HW_INITIALIZATION_DATA *HwInitializationData,
+ IN PVOID HwContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the port driver.
+
+Arguments:
+
+ Argument1 - Pointer to driver object created by system
+ HwInitializationData - Miniport initialization structure
+ HwContext - Value passed to miniport driver's config routine
+
+Return Value:
+
+ The function value is the final status from the initialization operation.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension;
+ PDEVICE_OBJECT DeviceObject;
+ PORT_CONFIGURATION_INFORMATION configInfo;
+ KEVENT allocateAdapterEvent;
+ ULONG ExtensionAllocationSize;
+ ULONG j;
+ UCHAR scsiBus;
+ PULONG scsiPortNumber;
+ ULONG numberOfPageBreaks;
+ PIO_SCSI_CAPABILITIES capabilities;
+ BOOLEAN callAgain;
+ DEVICE_DESCRIPTION deviceDescription;
+ ARC_CODES status;
+ BOOLEAN foundOne = FALSE;
+
+ UNREFERENCED_PARAMETER(Argument1);
+ UNREFERENCED_PARAMETER(Argument2);
+
+ if (HwInitializationData->HwInitializationDataSize != sizeof(HW_INITIALIZATION_DATA)) {
+
+ DebugPrint((0,"ScsiPortInitialize: Miniport driver wrong version\n"));
+
+ return EBADF;
+ }
+
+ //
+ // Check that each required entry is not NULL.
+ //
+
+ if ((!HwInitializationData->HwInitialize) ||
+ (!HwInitializationData->HwFindAdapter) ||
+ (!HwInitializationData->HwResetBus)) {
+
+ DebugPrint((0,
+ "ScsiPortInitialize: Miniport driver missing required entry\n"));
+
+ return EBADF;
+ }
+
+CallAgain:
+
+ //
+ // Get the configuration information
+ //
+
+ scsiPortNumber = &ScsiPortCount;
+
+ //
+ // Determine size of extensions.
+ //
+
+ ExtensionAllocationSize = DEVICE_EXTENSION_SIZE +
+ HwInitializationData->DeviceExtensionSize + sizeof(DEVICE_OBJECT);
+
+ DeviceObject = ExAllocatePool(NonPagedPool, ExtensionAllocationSize);
+
+ if (DeviceObject == NULL) {
+ return ENOMEM;
+ }
+
+ RtlZeroMemory(DeviceObject, ExtensionAllocationSize);
+
+ //
+ // Set up device extension pointers
+ //
+
+ deviceExtension = DeviceObject->DeviceExtension = (PVOID) (DeviceObject + 1);
+ deviceExtension->DeviceObject = DeviceObject;
+
+ //
+ // Save the dependent driver routines in the device extension.
+ //
+
+ deviceExtension->HwInitialize = HwInitializationData->HwInitialize;
+ deviceExtension->HwStartIo = HwInitializationData->HwStartIo;
+ deviceExtension->HwInterrupt = HwInitializationData->HwInterrupt;
+ deviceExtension->HwReset = HwInitializationData->HwResetBus;
+ deviceExtension->HwDmaStarted = HwInitializationData->HwDmaStarted;
+ deviceExtension->HwLogicalUnitExtensionSize =
+ HwInitializationData->SpecificLuExtensionSize;
+
+ deviceExtension->HwDeviceExtension =
+ (PVOID)(deviceExtension + 1);
+
+ //
+ // Set indicater as to whether adapter needs kernel mapped buffers.
+ //
+
+ deviceExtension->MapBuffers = HwInitializationData->MapBuffers;
+
+ //
+ // Mark this object as supporting direct I/O so that I/O system
+ // will supply mdls in irps.
+ //
+
+ DeviceObject->Flags |= DO_DIRECT_IO;
+
+ //
+ // Check if miniport driver requires any noncached memory.
+ // SRB extensions will come from zoned memory. A page is
+ // allocated as it is the smallest unit of noncached memory
+ // allocation.
+ //
+
+ deviceExtension->SrbExtensionSize = HwInitializationData->SrbExtensionSize;
+
+ //
+ // Get the miniport configuration information.
+ //
+
+ capabilities = &deviceExtension->Capabilities;
+
+ capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
+
+ callAgain = FALSE;
+
+
+ if (!NT_SUCCESS(SpInitializeConfiguration(
+ deviceExtension,
+ HwInitializationData,
+ &configInfo,
+ TRUE
+ ))) {
+
+ DebugPrint((2, "ScsiPortInitialize: no Configuration info found\n"));
+ return(ENODEV);
+ }
+
+ configInfo.NumberOfAccessRanges = HwInitializationData->NumberOfAccessRanges;
+
+ configInfo.AccessRanges = ExAllocatePool(
+ NonPagedPool,
+ sizeof(ACCESS_RANGE) * HwInitializationData->NumberOfAccessRanges
+ );
+
+ if (configInfo.AccessRanges == NULL) {
+ return ENOMEM;
+ }
+
+ if (HwInitializationData->HwFindAdapter(
+ deviceExtension->HwDeviceExtension, // DeviceExtension
+ HwContext, // HwContext
+ NULL, // BusInformation
+ NULL, // ArgumentString
+ &configInfo, // ConfigurationInformation
+ &callAgain // Again
+ ) != SP_RETURN_FOUND) {
+
+ return foundOne ? ESUCCESS : EIO;
+ }
+
+ ScsiDebugPrint(1,"ScsiPortInitialize: SCSI adapter IRQ is %d\n",
+ configInfo.BusInterruptLevel);
+
+ ScsiDebugPrint(1,"ScsiPortInitialize: SCSI adapter ID is %d\n",
+ configInfo.InitiatorBusId[0]);
+
+ deviceExtension->NumberOfBuses = configInfo.NumberOfBuses;
+
+ //
+ // Free the pointer to the bus data at map register base. This was
+ // allocated by ScsiPortGetBusData.
+ //
+
+ if (deviceExtension->MapRegisterBase != NULL) {
+ ExFreePool(deviceExtension->MapRegisterBase);
+ }
+
+ //
+ // Allocate memory for the non cached extension if it has not already been
+ // allocated.
+ //
+
+ if (deviceExtension->SrbExtensionSize != 0 &&
+ deviceExtension->SrbExtensionZonePool == NULL) {
+
+ status = SpGetCommonBuffer(deviceExtension, 0);
+
+ if (status != ESUCCESS) {
+
+ return(status);
+ }
+ }
+
+ //
+ // Get the adapter object for this card.
+ //
+
+ if ((configInfo.Master || configInfo.DmaChannel != 0xFFFFFFFF)) {
+
+ deviceDescription.Version = DEVICE_DESCRIPTION_VERSION;
+ deviceDescription.DmaChannel = configInfo.DmaChannel;
+ deviceDescription.InterfaceType = configInfo.AdapterInterfaceType;
+ deviceDescription.BusNumber = configInfo.SystemIoBusNumber;
+ deviceDescription.DmaWidth = configInfo.DmaWidth;
+ deviceDescription.DmaSpeed = configInfo.DmaSpeed;
+ deviceDescription.DmaPort = configInfo.DmaPort;
+ deviceDescription.MaximumLength = configInfo.MaximumTransferLength;
+ deviceDescription.ScatterGather = configInfo.ScatterGather;
+ deviceDescription.Master = configInfo.Master;
+ deviceDescription.AutoInitialize = FALSE;
+ deviceDescription.DemandMode = FALSE;
+
+ // BugBug: Make the 0x11000 a define when there is one.
+ if (configInfo.MaximumTransferLength > 0x11000) {
+
+ deviceDescription.MaximumLength = 0x11000;
+
+ } else {
+
+ deviceDescription.MaximumLength = configInfo.MaximumTransferLength;
+
+ }
+
+ deviceExtension->DmaAdapterObject = HalGetAdapter(
+ &deviceDescription,
+ &numberOfPageBreaks
+ );
+
+ //
+ // Set maximum number of page breaks.
+ //
+
+ if (numberOfPageBreaks > configInfo.NumberOfPhysicalBreaks) {
+ capabilities->MaximumPhysicalPages = configInfo.NumberOfPhysicalBreaks;
+ } else {
+ capabilities->MaximumPhysicalPages = numberOfPageBreaks;
+ }
+
+ }
+
+ capabilities->Length = sizeof(IO_SCSI_CAPABILITIES);
+ capabilities->MaximumTransferLength = configInfo.MaximumTransferLength;
+ ScsiDebugPrint(1, "Maximum physical page breaks = %d. Maximum transfer length = %x\n", capabilities->MaximumPhysicalPages, capabilities->MaximumTransferLength);
+
+ if (HwInitializationData->ReceiveEvent) {
+ capabilities->SupportedAsynchronousEvents |=
+ SRBEV_SCSI_ASYNC_NOTIFICATION;
+ }
+
+ capabilities->TaggedQueuing = HwInitializationData->TaggedQueuing;
+ capabilities->AdapterScansDown = configInfo.AdapterScansDown;
+
+ //
+ // Make sure maximum nuber of pages is set to a reasonable value.
+ // This occurs for mini-ports with no Dma adapter.
+ //
+
+ if (capabilities->MaximumPhysicalPages == 0) {
+
+ capabilities->MaximumPhysicalPages =
+ ROUND_TO_PAGES(capabilities->MaximumTransferLength) + 1;
+
+ //
+ // Honor any limit requested by the mini-port.
+ //
+
+ if (configInfo.NumberOfPhysicalBreaks < capabilities->MaximumPhysicalPages) {
+
+ capabilities->MaximumPhysicalPages =
+ configInfo.NumberOfPhysicalBreaks;
+ }
+ }
+
+
+ if (deviceExtension->DmaAdapterObject != NULL &&
+ !HwInitializationData->NeedPhysicalAddresses) {
+
+ //
+ // Allocate the adapter object. For the port driver the adapter object
+ // and map registers are permentently allocated and used shared between
+ // all logical units. The adapter is allocated by initializing an event,
+ // calling IoAllocateAdapterChannel and waiting on the event. When the
+ // adapter and map registers are available, ScsiPortAllocationRoutine is
+ // called which set the event. In reality, all this takes zero time since
+ // the stuff is available immediately.
+ //
+ // Allocate the AdapterObject. The number of registers is equal to the
+ // maximum transfer length supported by the adapter + 1. This insures
+ // that there will always be a sufficient number of registers.
+ //
+ /* TODO: Fix this for the case when there is no maximum transfer length. */
+
+ IoAllocateAdapterChannel(
+ deviceExtension->DmaAdapterObject,
+ DeviceObject,
+// configInfo.NumberOfPhysicalBreaks,
+ capabilities->MaximumPhysicalPages,
+ ScsiPortAllocationRoutine,
+ &allocateAdapterEvent
+ );
+
+ //
+ // Wait for adapter object.
+ //
+
+ ASSERT(deviceExtension->MapRegisterBase);
+
+ deviceExtension->MasterWithAdapter = FALSE;
+
+ } else if (deviceExtension->DmaAdapterObject != NULL) {
+
+ //
+ // This SCSI adapter is a master with an adapter so a scatter/gather
+ // list needs to be allocated for each transfer.
+ //
+
+ deviceExtension->MasterWithAdapter = TRUE;
+
+ } else {
+
+ deviceExtension->MasterWithAdapter = FALSE;
+
+ } // end if (deviceExtension->DmaAdapterObject != NULL)
+
+ //
+ // Call the hardware dependent driver to do its initialization.
+ //
+
+ if (!KeSynchronizeExecution(
+ deviceExtension->InterruptObject,
+ deviceExtension->HwInitialize,
+ deviceExtension->HwDeviceExtension
+ )) {
+
+ ScsiDebugPrint(1,"ScsiPortInitialize: initialization failed\n");
+
+ return ENODEV;
+ }
+
+ //
+ // Allocate properly aligned INQUIRY buffer.
+ //
+
+ InquiryDataBuffer = ExAllocatePool(NonPagedPool, INQUIRYDATABUFFERSIZE);
+
+ if (InquiryDataBuffer == NULL) {
+ return(ENOMEM);
+ }
+
+ //
+ // Reset the scsi bus.
+ //
+
+ if (!deviceExtension->HwReset(
+ deviceExtension->HwDeviceExtension,
+ 0)){
+
+ ScsiDebugPrint(1,"Reset SCSI bus failed\n");
+ }
+
+ //
+ // Call the interupt handler for a few microseconds to clear any reset
+ // interrupts.
+ //
+
+ for (j = 0; j < 1000 * 100; j++) {
+
+ FwStallExecution(10);
+ if (deviceExtension->HwInterrupt != NULL) {
+ deviceExtension->HwInterrupt(deviceExtension->HwDeviceExtension);
+ }
+
+
+ }
+
+ //
+ // Wait 2 seconds for the devices to recover after the reset.
+ //
+
+ //FwStallExecution(2 * 1000 * 1000);
+ FwStallExecution(2 * 1000 * 100);
+
+ //
+ // Find devices on each SCSI bus.
+ //
+
+ //
+ // Allocate buffer for SCSI bus scan information.
+ //
+
+ deviceExtension->ScsiInfo = ExAllocatePool(NonPagedPool,
+ deviceExtension->NumberOfBuses * sizeof(PSCSI_BUS_SCAN_DATA) +
+ 4);
+
+ if (deviceExtension->ScsiInfo) {
+
+ deviceExtension->ScsiInfo->NumberOfBuses = deviceExtension->NumberOfBuses;
+
+ //
+ // Find devices on each SCSI bus.
+ //
+
+ for (scsiBus = 0; scsiBus < deviceExtension->NumberOfBuses; scsiBus++) {
+ deviceExtension->ScsiInfo->BusScanData[scsiBus] =
+ ScsiBusScan(deviceExtension,
+ scsiBus,
+ configInfo.InitiatorBusId[scsiBus]);
+ }
+ }
+
+ //
+ // Save the device object for use by the driver.
+ //
+
+ ScsiPortDeviceObject[*scsiPortNumber] = DeviceObject;
+
+ //
+ // Bump SCSI host bus adapters count.
+ //
+
+ (*scsiPortNumber)++;
+
+ foundOne = TRUE;
+
+ //
+ // If the adapter wants to be called again with the same configuration data
+ // then start over from the begining again.
+ //
+
+ if (callAgain) {
+ goto CallAgain;
+
+ }
+
+ return ESUCCESS;
+
+} // end ScsiPortInitialize()
+
+IO_ALLOCATION_ACTION
+ScsiPortAllocationRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by IoAllocateAdapterChannel when sufficent resources
+ are available to the driver. This routine saves the MapRegisterBase in the
+ device object and set the event pointed to by the context parameter.
+
+Arguments:
+
+ DeviceObject - Pointer to the device object to which the adapter is being
+ allocated.
+
+ Irp - Unused.
+
+ MapRegisterBase - Supplied by the Io subsystem for use in IoMapTransfer.
+
+ Context - Supplies a pointer to an event which is set to indicate the
+ AdapterObject has been allocated.
+
+Return Value:
+
+ KeepObject - Indicates the adapter and mapregisters should remain allocated
+ after return.
+
+--*/
+
+{
+ ((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->MapRegisterBase =
+ MapRegisterBase;
+
+ UNREFERENCED_PARAMETER(Irp);
+ UNREFERENCED_PARAMETER(Context);
+
+ return(KeepObject);
+}
+
+IO_ALLOCATION_ACTION
+SpBuildScatterGather(
+ IN struct _DEVICE_OBJECT *DeviceObject,
+ IN struct _IRP *Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by the I/O system when an adapter object and map
+ registers have been allocated. This routine then builds a scatter/gather
+ list for use by the mini-port driver. Next it sets the timeout and
+ the current Irp for the logical unit. Finally it calls the mini-port
+ StartIo routine. Once that routines complete, this routine will return
+ requesting that the adapter be freed and but the registers remain allocated.
+ The registers will be freed the request completes.
+
+Arguments:
+
+ DeviceObject - Supplies a pointer to the port driver device object.
+
+ Irp - Supplies a pointer to the current Irp.
+
+ MapRegisterBase - Supplies a context pointer to be used with calls the
+ adapter object routines.
+
+ Context - Supplies a pointer to the logical unit structure.
+
+Return Value:
+
+ Returns DeallocateObjectKeepRegisters so that the adapter object can be
+ used by other logical units.
+
+--*/
+
+{
+ BOOLEAN writeToDevice;
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+ PSCSI_REQUEST_BLOCK srb;
+ PSRB_SCATTER_GATHER scatterList;
+ ULONG totalLength;
+
+ logicalUnit = Context;
+ srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+ scatterList = logicalUnit->ScatterGather;
+ totalLength = 0;
+
+ //
+ // Save the MapRegisterBase for later use to deallocate the map registers.
+ //
+
+ logicalUnit->MapRegisterBase = MapRegisterBase;
+
+ //
+ // Build the scatter/gather list by looping throught the transfer calling
+ // I/O map transfer.
+ //
+
+ writeToDevice = srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE;
+
+ while (totalLength < srb->DataTransferLength) {
+
+ //
+ // Request that the rest of the transfer be mapped.
+ //
+
+ scatterList->Length = srb->DataTransferLength - totalLength;
+
+ //
+ // Since we are a master call I/O map transfer with a NULL adapter.
+ //
+
+ scatterList->PhysicalAddress = IoMapTransfer(
+ NULL,
+ Irp->MdlAddress,
+ MapRegisterBase,
+ (PCCHAR) srb->DataBuffer + totalLength,
+ &scatterList->Length,
+ writeToDevice
+ ).LowPart;
+
+ totalLength += scatterList->Length;
+ scatterList++;
+ }
+
+ //
+ // Set request timeout value from Srb SCSI extension in Irp.
+ //
+
+ logicalUnit->RequestTimeoutCounter = srb->TimeOutValue;
+
+ //
+ // Set current request for this logical unit.
+ //
+
+ logicalUnit->CurrentRequest = Irp;
+
+ /* TODO: Check the return value. */
+ KeSynchronizeExecution(
+ ((PDEVICE_EXTENSION) DeviceObject->DeviceExtension)->InterruptObject,
+ SpStartIoSynchronized,
+ DeviceObject
+ );
+
+ return(DeallocateObjectKeepRegisters);
+
+}
+
+VOID
+ScsiPortExecute(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls the start I/O routine an waits for the request to
+ complete. During the wait for complete the interrupt routine is called,
+ also the timer routines are called at the appropriate times. After the
+ request completes a check is made to determine if an request sense needs
+ to be issued.
+
+Arguments:
+
+ DeviceObject - Supplies pointer to Adapter device object.
+
+ Irp - Supplies a pointer to an IRP.
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ ULONG milliSecondTime;
+ ULONG secondTime;
+ ULONG completionDelay;
+ PDEVICE_EXTENSION deviceExtension;
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PSCSI_REQUEST_BLOCK srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+ PVOID logicalUnit;
+
+ deviceExtension = DeviceObject->DeviceExtension;
+ logicalUnit = GetLogicalUnitExtension(deviceExtension, srb->TargetId);
+
+ if (logicalUnit == NULL) {
+ Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
+ return;
+ }
+
+ //
+ // Mark IRP as pending.
+ //
+
+ Irp->PendingReturned = TRUE;
+
+ //
+ // Start the request.
+ //
+
+ ScsiPortStartIo( DeviceObject, Irp);
+
+ //
+ // The completion delay controls how long interrupts are serviced after
+ // a request has been completed. This allows interrupts which occur after
+ // a completion to be serviced.
+ //
+
+ completionDelay = COMPLETION_DELAY;
+
+ //
+ // Wait for the IRP to complete.
+ //
+
+ while (Irp->PendingReturned && completionDelay) {
+
+ //
+ // Wait 1 second then call the scsi port timer routine.
+ //
+
+ for (secondTime = 0; secondTime < 1000/ 500; secondTime++) {
+
+ for (milliSecondTime = 0; milliSecondTime < (250 * 1000 / PD_INTERLOOP_STALL); milliSecondTime++) {
+
+ ScsiPortInterrupt(NULL, DeviceObject);
+
+ if (!Irp->PendingReturned) {
+ if (completionDelay-- == 0) {
+ goto done;
+ }
+ }
+
+ if (deviceExtension->Flags & PD_ENABLE_CALL_REQUEST) {
+
+ //
+ // Call the mini-port requested routine.
+ //
+
+ deviceExtension->Flags &= ~PD_ENABLE_CALL_REQUEST;
+ deviceExtension->HwRequestInterrupt(deviceExtension->HwDeviceExtension);
+
+ if (deviceExtension->Flags & PD_DISABLE_CALL_REQUEST) {
+
+ deviceExtension->Flags &= ~(PD_DISABLE_INTERRUPTS | PD_DISABLE_CALL_REQUEST);
+ deviceExtension->HwRequestInterrupt(deviceExtension->HwDeviceExtension);
+
+ }
+ }
+
+ FwStallExecution(PD_INTERLOOP_STALL);
+
+ //
+ // Check the miniport timer.
+ //
+
+ if (deviceExtension->TimerValue != 0) {
+
+ deviceExtension->TimerValue--;
+
+ if (deviceExtension->TimerValue == 0) {
+
+ //
+ // The timer timed out so called requested timer routine.
+ //
+
+ deviceExtension->HwTimerRequest(deviceExtension->HwDeviceExtension);
+ }
+ }
+ }
+
+ }
+
+ ScsiPortTickHandler(DeviceObject, NULL);
+ }
+
+done:
+
+ if (!NT_SUCCESS(Irp->IoStatus.Status)) {
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+
+ //
+ // Determine if a REQUEST SENSE command needs to be done.
+ // Check that a CHECK_CONDITION was received, an autosense has not
+ // been done already, and that autosense has been requested.
+ //
+
+ if (srb->ScsiStatus == SCSISTAT_CHECK_CONDITION &&
+ !(srb->SrbStatus & SRB_STATUS_AUTOSENSE_VALID) &&
+ srb->SenseInfoBuffer) {
+
+ //
+ // Call IssueRequestSense and it will complete the request after
+ // the REQUEST SENSE completes.
+ //
+
+ IssueRequestSense(deviceExtension, Srb);
+ }
+ }
+}
+
+VOID
+ScsiPortStartIo (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ DeviceObject - Supplies pointer to Adapter device object.
+ Irp - Supplies a pointer to an IRP.
+
+Return Value:
+
+ Nothing.
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PSCSI_REQUEST_BLOCK Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+ PFULL_SCSI_REQUEST_BLOCK FullSrb;
+ NTSTATUS status;
+
+ ScsiDebugPrint(3,"ScsiPortStartIo: Enter routine\n");
+
+ FullSrb = CONTAINING_RECORD(Srb, FULL_SCSI_REQUEST_BLOCK, Srb);
+
+ if (deviceExtension->SrbExtensionZonePool && (Srb->SrbExtension == NULL
+ || deviceExtension->SrbExtensionSize > FullSrb->SrbExtensionSize)) {
+
+ //
+ // Allocate SRB extension from zone.
+ //
+
+ Srb->SrbExtension = deviceExtension->SrbExtensionPointer;
+
+ (PCCHAR) deviceExtension->SrbExtensionPointer +=
+ deviceExtension->SrbExtensionSize;
+
+ FullSrb->SrbExtensionSize = deviceExtension->SrbExtensionSize;
+
+ if ((ULONG) deviceExtension->SrbExtensionPointer >
+ (ULONG) deviceExtension->NonCachedExtension) {
+ ScsiDebugPrint(0, "NtLdr: ScsiPortStartIo: Srb extension overflow. Too many srb extension allocated.\n");
+ }
+
+ ScsiDebugPrint(3,"ExInterlockedAllocateFromZone: %lx\n",
+ Srb->SrbExtension);
+
+ ScsiDebugPrint(3,"Srb %lx\n",Srb);
+
+
+ }
+
+ //
+ // Get logical unit extension.
+ //
+
+ logicalUnit = GetLogicalUnitExtension(deviceExtension, Srb->TargetId);
+
+ //
+ // Flush the data buffer if necessary.
+ //
+
+ if (Srb->SrbFlags & (SRB_FLAGS_DATA_IN | SRB_FLAGS_DATA_OUT)) {
+
+ if (Srb->DataTransferLength > deviceExtension->Capabilities.MaximumTransferLength) {
+
+ ScsiDebugPrint(1, "Scsiboot: ScsiPortStartIo Length Exceeds limit %x, %x\n Hit any key\n",
+ Srb->DataTransferLength,
+ deviceExtension->Capabilities.MaximumTransferLength
+ );
+
+ }
+
+ KeFlushIoBuffers(
+ Irp->MdlAddress,
+ Srb->SrbFlags & SRB_FLAGS_DATA_IN ? TRUE : FALSE,
+ TRUE
+ );
+
+ //
+ // Determine if this adapter needs map registers
+ //
+
+ if (deviceExtension->MasterWithAdapter) {
+
+ //
+ // Calculate the number of map registers needed for this transfer.
+ //
+
+ logicalUnit->NumberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES(
+ Srb->DataBuffer,
+ Srb->DataTransferLength
+ );
+
+ //
+ // Allocate the adapter channel with sufficient map registers
+ // for the transfer.
+ //
+
+ status = IoAllocateAdapterChannel(
+ deviceExtension->DmaAdapterObject, // AdapterObject
+ DeviceObject, // DeviceObject.
+ logicalUnit->NumberOfMapRegisters, // NumberOfMapRegisters
+ SpBuildScatterGather, // ExecutionRoutine
+ logicalUnit // Context
+ );
+
+ if (!NT_SUCCESS(status)) {
+
+ ;
+ }
+
+ //
+ // The execution routine called by IoAllocateChannel will do the
+ // rest of the work so just return.
+ //
+
+ return;
+ }
+ }
+
+ //
+ // Set request timeout value from Srb SCSI extension in Irp.
+ //
+
+ logicalUnit->RequestTimeoutCounter = Srb->TimeOutValue;
+
+ //
+ // Set current request for this logical unit.
+ //
+
+ logicalUnit->CurrentRequest = Irp;
+
+ /* TODO: Check the return value. */
+ KeSynchronizeExecution(
+ deviceExtension->InterruptObject,
+ SpStartIoSynchronized,
+ DeviceObject
+ );
+
+ return;
+
+} // end ScsiPortStartIO()
+
+
+BOOLEAN
+SpStartIoSynchronized (
+ PVOID ServiceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine calls the dependent driver start io routine.
+
+Arguments:
+
+ ServiceContext - Supplies the pointer to the device object.
+
+Return Value:
+
+ Returns the value returned by the dependent start I/O routine.
+
+
+--*/
+
+{
+ PDEVICE_OBJECT DeviceObject = ServiceContext;
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION irpstack;
+ PSCSI_REQUEST_BLOCK Srb;
+
+ ScsiDebugPrint(3, "ScsiPortStartIoSynchronized: Enter routine\n");
+
+ irpstack = IoGetCurrentIrpStackLocation(DeviceObject->CurrentIrp);
+ Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+
+ ScsiDebugPrint(3, "SpPortStartIoSynchronized: SRB %lx\n",
+ Srb);
+
+ ScsiDebugPrint(3, "SpPortStartIoSynchronized: IRP %lx\n",
+ DeviceObject->CurrentIrp);
+
+ //
+ // Disable all synchronous transfers.
+ //
+
+ Srb->SrbFlags |=
+ (SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DISABLE_DISCONNECT | SRB_FLAGS_DISABLE_AUTOSENSE);
+
+ return deviceExtension->HwStartIo(
+ deviceExtension->HwDeviceExtension,
+ Srb
+ );
+
+} // end SpStartIoSynchronized()
+
+
+BOOLEAN
+ScsiPortInterrupt(
+ IN PKINTERRUPT Interrupt,
+ IN PDEVICE_OBJECT DeviceObject
+ )
+
+/*++
+
+Routine Description:
+
+
+Arguments:
+
+ Interrupt
+
+ Device Object
+
+Return Value:
+
+ Returns TRUE if interrupt expected.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+
+ UNREFERENCED_PARAMETER(Interrupt);
+
+ if (deviceExtension->HwInterrupt != NULL) {
+
+ if (deviceExtension->HwInterrupt(deviceExtension->HwDeviceExtension)) {
+
+ return TRUE;
+
+ } else {
+
+ return FALSE;
+ }
+ }
+
+ return(FALSE);
+
+} // end ScsiPortInterrupt()
+
+
+VOID
+ScsiPortCompletionDpc(
+ IN PKDPC Dpc,
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ Dpc
+ DeviceObject
+ Irp - not used
+ Context - not used
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension = DeviceObject->DeviceExtension;
+ PIO_STACK_LOCATION irpstack;
+ PSCSI_REQUEST_BLOCK Srb;
+ PLOGICAL_UNIT_EXTENSION luExtension;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(Context);
+
+ ScsiDebugPrint(3, "ScsiPortCompletionDpc Entered\n");
+
+ //
+ // Acquire the spinlock to protect the flags structure and the saved
+ // interrupt context.
+ //
+
+ KeAcquireSpinLock(&deviceExtension->SpinLock, &currentIrql);
+
+ //
+ // Check for a flush DMA adapter object request.
+ //
+
+ if (deviceExtension->InterruptFlags & PD_FLUSH_ADAPTER_BUFFERS) {
+
+ //
+ // Call IoFlushAdapterBuffers using the parameters saved from the last
+ // IoMapTransfer call.
+ //
+
+ IoFlushAdapterBuffers(
+ deviceExtension->DmaAdapterObject,
+ ((PIRP)deviceExtension->FlushAdapterParameters.Srb->OriginalRequest)
+ ->MdlAddress,
+ deviceExtension->MapRegisterBase,
+ deviceExtension->FlushAdapterParameters.LogicalAddress,
+ deviceExtension->FlushAdapterParameters.Length,
+ (BOOLEAN)(deviceExtension->FlushAdapterParameters.Srb->SrbFlags
+ & SRB_FLAGS_DATA_OUT ? TRUE : FALSE)
+ );
+
+ }
+
+ //
+ // Check for an IoMapTransfer DMA request.
+ //
+
+ if (deviceExtension->InterruptFlags & PD_MAP_TRANSFER) {
+
+ //
+ // Call IoMapTransfer using the parameters saved from the
+ // interrupt level.
+ //
+
+ IoMapTransfer(
+ deviceExtension->DmaAdapterObject,
+ ((PIRP)deviceExtension->MapTransferParameters.Srb->OriginalRequest)
+ ->MdlAddress,
+ deviceExtension->MapRegisterBase,
+ deviceExtension->MapTransferParameters.LogicalAddress,
+ &deviceExtension->MapTransferParameters.Length,
+ (BOOLEAN)(deviceExtension->MapTransferParameters.Srb->SrbFlags
+ & SRB_FLAGS_DATA_OUT ? TRUE : FALSE)
+ );
+
+ //
+ // Save the paramters for IoFlushAdapterBuffers.
+ //
+
+ deviceExtension->FlushAdapterParameters =
+ deviceExtension->MapTransferParameters;
+
+ //
+ // If necessary notify the mini-port driver that the DMA has been
+ // started.
+ //
+
+ if (deviceExtension->HwDmaStarted) {
+ KeSynchronizeExecution(
+ &deviceExtension->InterruptObject,
+ (PKSYNCHRONIZE_ROUTINE) deviceExtension->HwDmaStarted,
+ deviceExtension->HwDeviceExtension
+ );
+ }
+
+ }
+
+ //
+ // Process any completed requests.
+ //
+
+ while (deviceExtension->CompletedRequests != NULL) {
+
+ Irp = deviceExtension->CompletedRequests;
+ irpstack = IoGetCurrentIrpStackLocation(Irp);
+ Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+ luExtension =
+ GetLogicalUnitExtension(deviceExtension, Srb->TargetId);
+
+ ScsiDebugPrint(3, "ScsiPortCompletionDpc: SRB %lx\n", Srb);
+ ScsiDebugPrint(3, "ScsiPortCompletionDpc: IRP %lx\n", Irp);
+
+ //
+ // Remove the request from the linked-list.
+ //
+
+ deviceExtension->CompletedRequests =
+ irpstack->Parameters.Others.Argument3;
+
+ //
+ // Reset request timeout counter.
+ //
+
+ luExtension->RequestTimeoutCounter = -1;
+
+ //
+ // Flush the adapter buffers if necessary.
+ //
+
+ if (luExtension->MapRegisterBase) {
+
+ //
+ // Since we are a master call I/O flush adapter buffers with a NULL
+ // adapter.
+ //
+
+ IoFlushAdapterBuffers(
+ NULL,
+ Irp->MdlAddress,
+ luExtension->MapRegisterBase,
+ Srb->DataBuffer,
+ Srb->DataTransferLength,
+ (BOOLEAN) (Srb->SrbFlags & SRB_FLAGS_DATA_OUT ? TRUE : FALSE)
+ );
+
+ //
+ // Free the map registers.
+ //
+
+ IoFreeMapRegisters(
+ deviceExtension->DmaAdapterObject,
+ luExtension->MapRegisterBase,
+ luExtension->NumberOfMapRegisters
+ );
+
+ //
+ // Clear the MapRegisterBase.
+ //
+
+ luExtension->MapRegisterBase = NULL;
+
+ }
+
+ //
+ // Set IRP status. Class drivers will reset IRP status based
+ // on request sense if error.
+ //
+
+ if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) {
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ } else {
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // Move bytes transfered to IRP.
+ //
+
+ Irp->IoStatus.Information = Srb->DataTransferLength;
+
+ //
+ // If success then start next packet.
+ // Not starting packet effectively
+ // freezes the queue.
+ //
+
+ if (SRB_STATUS(Srb->SrbStatus) == SRB_STATUS_SUCCESS) {
+
+ ScsiDebugPrint(
+ 2,
+ "ScsiPortCompletionDpc: Iocompletion IRP %lx\n",
+ Irp
+ );
+
+ IoCompleteRequest(Irp, 2);
+
+ } else {
+
+ if ( Srb->ScsiStatus == SCSISTAT_BUSY &&
+ (luExtension->RetryCount++ < 2)) {
+ //
+ // If busy status is returned, then indicate that the logical
+ // unit is busy. The timeout code will restart the request
+ // when it fires. Reset the status to pending.
+ //
+ Srb->SrbStatus = SRB_STATUS_PENDING;
+ luExtension->CurrentRequest = Irp;
+ luExtension->Flags |= PD_LOGICAL_UNIT_IS_BUSY;
+ } else {
+
+
+ ScsiDebugPrint(
+ 3,
+ "ScsiPortCompletionDpc: Iocompletion IRP %lx\n",
+ Irp
+ );
+
+ IoCompleteRequest(Irp, 2);
+ }
+ }
+ }
+
+ //
+ // Release the spinlock.
+ //
+
+ KeReleaseSpinLock(&deviceExtension->SpinLock, currentIrql);
+
+ return;
+
+} // end ScsiPortCompletionDpc()
+
+
+ARC_STATUS
+IssueInquiry(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PLUNINFO LunInfo
+ )
+
+/*++
+
+Routine Description:
+
+ Build IRP, SRB and CDB for SCSI INQUIRY command.
+
+Arguments:
+
+ DeviceExtension - address of adapter's device object extension.
+ LunInfo - address of buffer for INQUIRY information.
+
+Return Value:
+
+ ARC_STATUS
+
+--*/
+
+{
+ PIRP irp;
+ PIO_STACK_LOCATION irpstack;
+ PCDB cdb;
+ PSCSI_REQUEST_BLOCK srb;
+ ARC_STATUS status;
+ ULONG retryCount = 0;
+
+ ScsiDebugPrint(3,"IssueInquiry: Enter routine\n");
+
+ if (InquiryDataBuffer == NULL) {
+ return ENOMEM;
+ }
+
+inquiryRetry:
+
+ //
+ // Build IRP for this request.
+ //
+
+ irp = InitializeIrp(
+ &PrimarySrb,
+ IRP_MJ_SCSI,
+ DeviceExtension->DeviceObject,
+ (PVOID)InquiryDataBuffer,
+ INQUIRYDATABUFFERSIZE
+ );
+
+ irpstack = IoGetNextIrpStackLocation(irp);
+
+ //
+ // Set major and minor codes.
+ //
+
+ irpstack->MajorFunction = IRP_MJ_SCSI;
+
+ //
+ // Fill in SRB fields.
+ //
+
+ irpstack->Parameters.Others.Argument1 = &PrimarySrb;
+ srb = &PrimarySrb.Srb;
+
+ srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+ srb->PathId = LunInfo->PathId;
+ srb->TargetId = LunInfo->TargetId;
+ srb->Lun = LunInfo->Lun;
+
+ srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+
+ srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DISABLE_DISCONNECT;
+
+ srb->SrbStatus = srb->ScsiStatus = 0;
+
+ srb->OriginalRequest = irp;
+
+ srb->NextSrb = 0;
+
+ //
+ // Set timeout to 5 seconds.
+ //
+
+ srb->TimeOutValue = 5;
+
+ srb->CdbLength = 6;
+
+ srb->SenseInfoBufferLength = 0;
+ srb->SenseInfoBuffer = 0;
+
+ srb->DataBuffer = MmGetMdlVirtualAddress(irp->MdlAddress);
+ srb->DataTransferLength = INQUIRYDATABUFFERSIZE;
+
+ cdb = (PCDB)srb->Cdb;
+
+ //
+ // Set CDB operation code.
+ //
+
+ cdb->CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
+
+ //
+ // Set CDB LUN.
+ //
+
+ cdb->CDB6INQUIRY.LogicalUnitNumber = LunInfo->Lun;
+ cdb->CDB6INQUIRY.Reserved1 = 0;
+
+ //
+ // Set allocation length to inquiry data buffer size.
+ //
+
+ cdb->CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
+
+ //
+ // Zero reserve field and
+ // Set EVPD Page Code to zero.
+ // Set Control field to zero.
+ // (See SCSI-II Specification.)
+ //
+
+ cdb->CDB6INQUIRY.PageCode = 0;
+ cdb->CDB6INQUIRY.IReserved = 0;
+ cdb->CDB6INQUIRY.Control = 0;
+
+ //
+ // Call port driver to handle this request.
+ //
+
+ (VOID)IoCallDriver(DeviceExtension->DeviceObject, irp);
+
+
+ if (SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SUCCESS) {
+
+ ScsiDebugPrint(2,"IssueInquiry: Inquiry failed SRB status %x\n",
+ srb->SrbStatus);
+
+ //
+ // NOTE: if INQUIRY fails with a data underrun,
+ // indicate success and let the class drivers
+ // determine whether the inquiry information
+ // is useful.
+ //
+
+ if (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN) {
+
+ //
+ // Copy INQUIRY buffer to LUNINFO.
+ //
+
+ ScsiDebugPrint(1,"IssueInquiry: Data underrun at TID %d\n",
+ LunInfo->TargetId);
+
+ RtlMoveMemory(LunInfo->InquiryData,
+ InquiryDataBuffer,
+ INQUIRYDATABUFFERSIZE);
+
+ status = STATUS_SUCCESS;
+
+ } else if ((SRB_STATUS(srb->SrbStatus) != SRB_STATUS_SELECTION_TIMEOUT) && (retryCount++ < 2)) {
+
+ //
+ // If the selection did not time out then retry the request.
+ //
+
+ ScsiDebugPrint(2,"IssueInquiry: Retry %d\n", retryCount);
+ goto inquiryRetry;
+
+ } else {
+
+ status = EIO;
+
+ }
+
+
+ } else {
+
+ //
+ // Copy INQUIRY buffer to LUNINFO.
+ //
+
+ RtlMoveMemory(LunInfo->InquiryData,
+ InquiryDataBuffer,
+ INQUIRYDATABUFFERSIZE);
+
+ status = STATUS_SUCCESS;
+ }
+
+ return status;
+
+} // end IssueInquiry()
+
+
+PSCSI_BUS_SCAN_DATA
+ScsiBusScan(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN UCHAR ScsiBus,
+ IN UCHAR InitiatorBusId
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ DeviceExtension
+ ScsiBus
+
+Return Value:
+
+ SCSI configuration information
+
+
+--*/
+{
+ PSCSI_BUS_SCAN_DATA busScanData;
+ PLUNINFO lunInfo;
+ UCHAR target;
+ UCHAR device = 0;
+ PLOGICAL_UNIT_EXTENSION nextLogicalUnitExtension;
+
+ ScsiDebugPrint(3,"ScsiBusScan: Enter routine\n");
+
+ busScanData = ExAllocatePool(NonPagedPool,
+ sizeof(SCSI_BUS_SCAN_DATA));
+
+ if (busScanData == NULL) {
+
+ //
+ // Insufficient system resources to complete bus scan.
+ //
+
+ return NULL;
+ }
+
+ RtlZeroMemory(busScanData,sizeof(SCSI_BUS_SCAN_DATA));
+
+ busScanData->Length = sizeof(SCSI_CONFIGURATION_INFO);
+
+ //
+ // Create first LUNINFO.
+ //
+
+ lunInfo = ExAllocatePool(NonPagedPool, sizeof(LUNINFO));
+
+ if (lunInfo == NULL) {
+
+ //
+ // Insufficient system resources to complete bus scan.
+ //
+
+ return NULL;
+ }
+
+ RtlZeroMemory(lunInfo, sizeof(LUNINFO));
+
+ //
+ // Create first logical unit extension.
+ //
+
+ nextLogicalUnitExtension = CreateLogicalUnitExtension(DeviceExtension);
+
+ if (nextLogicalUnitExtension == NULL) {
+ return(NULL);
+ }
+
+ //
+ // Link logical unit extension on list.
+ //
+
+ nextLogicalUnitExtension->NextLogicalUnit = DeviceExtension->LogicalUnitList;
+
+ DeviceExtension->LogicalUnitList = nextLogicalUnitExtension;
+
+ //
+ // Issue inquiry command to each target id to find devices.
+ //
+ // NOTE: Does not handle multiple logical units per target id.
+ //
+
+ for (target = 8; target > 0; target--) {
+
+ //
+ // This takes a long time so print a dot so the system doesn't look
+ // hung.
+ //
+
+ FwPrint(".");
+
+ if (InitiatorBusId == target-1) {
+ continue;
+ }
+
+ nextLogicalUnitExtension->PathId = lunInfo->PathId = ScsiBus;
+
+ nextLogicalUnitExtension->TargetId = lunInfo->TargetId = target-1;
+
+ nextLogicalUnitExtension->Lun = lunInfo->Lun = 0;
+
+ //
+ // Rezero hardware logigal unit extension if it's being recycled.
+ //
+
+ if (DeviceExtension->HwLogicalUnitExtensionSize) {
+
+ if (nextLogicalUnitExtension->SpecificLuExtension) {
+
+ RtlZeroMemory(nextLogicalUnitExtension->SpecificLuExtension,
+ DeviceExtension->HwLogicalUnitExtensionSize);
+ }
+
+ }
+
+ //
+ // Issue inquiry command.
+ //
+
+ ScsiDebugPrint(3,"ScsiBusScan: LunInfo at %lx\n", lunInfo);
+
+ ScsiDebugPrint(3, "ScsiBusScan: Device extension %lx\n",
+ DeviceExtension);
+
+ ScsiDebugPrint(2,"ScsiBusScan: Try TargetId %d LUN 0\n", target-1);
+
+ if (IssueInquiry(DeviceExtension, lunInfo) == ESUCCESS) {
+
+ ScsiDebugPrint(1,"ScsiBusScan: Found Device %d", device);
+ ScsiDebugPrint(1," at Target Id %d", lunInfo->TargetId);
+ ScsiDebugPrint(1," LUN %d\n", lunInfo->Lun);
+ //
+ // Link LUN information on list.
+ //
+
+ lunInfo->NextLunInfo = busScanData->LunInfoList;
+ busScanData->LunInfoList = lunInfo;
+
+ //
+ // This buffer is used. Get another.
+ //
+
+ lunInfo = ExAllocatePool(NonPagedPool, sizeof(LUNINFO));
+
+ if (lunInfo == NULL) {
+
+ //
+ // Insufficient system resources to complete bus scan.
+ //
+
+ return busScanData;
+ }
+
+ RtlZeroMemory(lunInfo, sizeof(LUNINFO));
+
+ //
+ // Current logical unit extension claimed.
+ // Create next logical unit.
+ //
+
+ nextLogicalUnitExtension =
+ CreateLogicalUnitExtension(DeviceExtension);
+
+ if (nextLogicalUnitExtension == NULL) {
+ return busScanData;
+ }
+
+ //
+ // Link logical unit extension on list.
+ //
+
+ nextLogicalUnitExtension->NextLogicalUnit =
+ DeviceExtension->LogicalUnitList;
+
+ DeviceExtension->LogicalUnitList = nextLogicalUnitExtension;
+
+ device++;
+ }
+
+ } // end for (target ...
+
+ //
+ // Remove unused logicalunit extension from list.
+ //
+
+ DeviceExtension->LogicalUnitList =
+ DeviceExtension->LogicalUnitList->NextLogicalUnit;
+
+ ExFreePool(nextLogicalUnitExtension);
+ ExFreePool(lunInfo);
+
+ busScanData->NumberOfLogicalUnits = device;
+ ScsiDebugPrint(1,
+ "ScsiBusScan: Found %d devices on SCSI bus %d\n",
+ device,
+ ScsiBus);
+
+ return busScanData;
+
+} // end ScsiBusScan()
+
+
+PLOGICAL_UNIT_EXTENSION
+CreateLogicalUnitExtension(
+ IN PDEVICE_EXTENSION DeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ Create logical unit extension.
+
+Arguments:
+
+ DeviceExtension
+ PathId
+
+Return Value:
+
+ Logical unit extension
+
+
+--*/
+{
+ PLOGICAL_UNIT_EXTENSION logicalUnitExtension;
+
+ //
+ // Create logical unit extension and link in chain.
+ //
+
+ logicalUnitExtension =
+ ExAllocatePool(NonPagedPool, sizeof(LOGICAL_UNIT_EXTENSION));
+
+ if (logicalUnitExtension == NULL) {
+ return(NULL);
+ }
+
+ //
+ // Zero logical unit extension.
+ //
+
+ RtlZeroMemory(logicalUnitExtension, sizeof(LOGICAL_UNIT_EXTENSION));
+
+ //
+ // Allocate miniport driver logical unit extension if necessary.
+ //
+
+ if (DeviceExtension->HwLogicalUnitExtensionSize) {
+
+ logicalUnitExtension->SpecificLuExtension =
+ ExAllocatePool(NonPagedPool,
+ DeviceExtension->HwLogicalUnitExtensionSize);
+
+ if (logicalUnitExtension->SpecificLuExtension == NULL) {
+ return(NULL);
+ }
+
+ //
+ // Zero hardware logical unit extension.
+ //
+
+ RtlZeroMemory(logicalUnitExtension->SpecificLuExtension,
+ DeviceExtension->HwLogicalUnitExtensionSize);
+ }
+
+ //
+ // Set timer counters in LogicalUnits to -1 to indicate no
+ // outstanding requests.
+ //
+
+ logicalUnitExtension->RequestTimeoutCounter = -1;
+
+ //
+ // Clear the current request field.
+ //
+
+ logicalUnitExtension->CurrentRequest = NULL;
+
+ return logicalUnitExtension;
+
+} // end CreateLogicalUnitExtension()
+
+
+//
+// Routines providing service to hardware dependent driver.
+//
+
+SCSI_PHYSICAL_ADDRESS
+ScsiPortGetPhysicalAddress(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PVOID VirtualAddress,
+ OUT ULONG *Length
+)
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ PSRB_SCATTER_GATHER scatterList;
+ PIRP irp;
+ PMDL mdl;
+ ULONG byteOffset;
+ ULONG whichPage;
+ PULONG pages;
+ ULONG address;
+
+ if (Srb == NULL) {
+
+ if (deviceExtension->SrbExtensionZonePool) {
+
+ address = (PUCHAR) VirtualAddress - (PUCHAR) deviceExtension->SrbExtensionZonePool +
+ deviceExtension->PhysicalZoneBase;
+
+ } else {
+
+ address = MmGetPhysicalAddress(VirtualAddress).LowPart;
+ }
+
+ //
+ // Return the requested length.
+ //
+
+ } else if (deviceExtension->MasterWithAdapter) {
+
+ //
+ // A scatter/gather list has already been allocated use it to determine
+ // the physical address and length. Get the scatter/gather list.
+ //
+
+ scatterList = GetLogicalUnitExtension(deviceExtension, Srb->TargetId)
+ ->ScatterGather;
+
+ //
+ // Calculate byte offset into the data buffer.
+ //
+
+ byteOffset = (PCHAR) VirtualAddress - (PCHAR) Srb->DataBuffer;
+
+ //
+ // Find the appropirate entry in the scatter/gatter list.
+ //
+
+ while (byteOffset >= scatterList->Length) {
+
+ byteOffset -= scatterList->Length;
+ scatterList++;
+ }
+
+ //
+ // Calculate the physical address and length to be returned.
+ //
+
+ *Length = scatterList->Length - byteOffset;
+ return(ScsiPortConvertUlongToPhysicalAddress(scatterList->PhysicalAddress + byteOffset));
+
+ } else {
+
+ //
+ // Get IRP from SRB.
+ //
+
+ irp = Srb->OriginalRequest;
+
+ //
+ // Get MDL from IRP.
+ //
+
+ mdl = irp->MdlAddress;
+
+ //
+ // Calculate byte offset from
+ // beginning of first physical page.
+ //
+
+ byteOffset = (PCHAR)VirtualAddress - (PCHAR)mdl->StartVa;
+
+ //
+ // Calculate which physical page.
+ //
+
+ whichPage = byteOffset >> PAGE_SHIFT;
+
+ //
+ // Calculate beginning of physical page array.
+ //
+
+ pages = (PULONG)(mdl + 1);
+
+ //
+ // Calculate physical address.
+ //
+
+ address = (pages[whichPage] << PAGE_SHIFT) +
+ BYTE_OFFSET(VirtualAddress);
+
+ //
+ // Assume the buffer is contiguous. Just return the requested length.
+ //
+ }
+
+ return ScsiPortConvertUlongToPhysicalAddress(address);
+
+} // end ScsiPortGetPhysicalAddress()
+
+
+PVOID
+ScsiPortGetVirtualAddress(
+ IN PVOID HwDeviceExtension,
+ IN SCSI_PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is returns a virtual address associated with a
+ physical address, if the physical address was obtained by a
+ call to ScsiPortGetPhysicalAddress.
+
+Arguments:
+
+ PhysicalAddress
+
+Return Value:
+
+ Virtual address if physical page hashed.
+ NULL if physical page not found in hash.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ PVOID address;
+
+
+
+ address = ScsiPortConvertPhysicalAddressToUlong(PhysicalAddress)
+ - deviceExtension->PhysicalZoneBase +
+ (PUCHAR)deviceExtension->SrbExtensionZonePool;
+
+ return address;
+
+} // end ScsiPortGetVirtualAddress()
+
+
+PVOID
+ScsiPortGetLogicalUnit(
+ IN PVOID HwDeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun
+ )
+
+/*++
+
+Routine Description:
+
+ Walk port driver's logical unit extension list searching
+ for entry.
+
+Arguments:
+
+ HwDeviceExtension - The port driver's device extension follows
+ the miniport's device extension and contains a pointer to
+ the logical device extension list.
+
+ PathId, TargetId and Lun - identify which logical unit on the
+ SCSI buses.
+
+Return Value:
+
+ If entry found return miniport driver's logical unit extension.
+ Else, return NULL.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension;
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+
+ ScsiDebugPrint(3, "ScsiPortGetLogicalUnit: TargetId %d\n",
+ TargetId);
+
+ //
+ // Get pointer to port driver device extension.
+ //
+
+ deviceExtension = (PDEVICE_EXTENSION)HwDeviceExtension -1;
+
+ //
+ // Get pointer to logical unit list.
+ //
+
+ logicalUnit = deviceExtension->LogicalUnitList;
+
+ //
+ // Walk list looking at target id for requested logical unit extension.
+ //
+
+ while (logicalUnit != NULL) {
+
+ if ((logicalUnit->TargetId == TargetId) &&
+ (logicalUnit->PathId == PathId) &&
+ (logicalUnit->Lun == Lun)) {
+
+ //
+ // Logical unit extension found.
+ // Return specific logical unit extension.
+ //
+
+ return logicalUnit->SpecificLuExtension;
+ }
+
+ //
+ // Get next logical unit.
+ //
+
+ logicalUnit = logicalUnit->NextLogicalUnit;
+ }
+
+ //
+ // Requested logical unit extension not found.
+ //
+
+ return NULL;
+
+} // end ScsiPortGetLogicalUnit()
+
+VOID
+ScsiPortNotification(
+ IN SCSI_NOTIFICATION_TYPE NotificationType,
+ IN PVOID HwDeviceExtension,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ (PDEVICE_EXTENSION) HwDeviceExtension - 1;
+ PIO_STACK_LOCATION irpstack;
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+ PSCSI_REQUEST_BLOCK srb;
+ va_list(ap);
+
+ va_start(ap, HwDeviceExtension);
+
+ switch (NotificationType) {
+
+ case NextLuRequest:
+ case NextRequest:
+
+ //
+ // Start next packet on adapter's queue.
+ //
+
+ ScsiDebugPrint(3,
+ "ScsiPortNotification: Start next request\n");
+
+ deviceExtension->InterruptFlags |= PD_READY_FOR_NEXT_REQUEST;
+ break;
+
+ case RequestComplete:
+
+ ScsiDebugPrint(3,
+ "ScsiPortNotification: Request complete\n");
+
+ srb = va_arg(ap, PSCSI_REQUEST_BLOCK);
+
+ if (srb->SrbStatus == SRB_STATUS_ERROR) {
+ }
+
+ //
+ // Link the completed request into a forward-linked list of IRPs.
+ //
+
+ irpstack = IoGetCurrentIrpStackLocation(
+ ((PIRP) srb->OriginalRequest)
+ );
+
+ irpstack->Parameters.Others.Argument3 =
+ deviceExtension->CompletedRequests;
+
+ deviceExtension->CompletedRequests = srb->OriginalRequest;
+
+ //
+ // Set logical unit current request to NULL
+ // to prevent race condition.
+ //
+
+ logicalUnit = GetLogicalUnitExtension(deviceExtension, srb->TargetId);
+
+ logicalUnit->CurrentRequest = NULL;
+
+ break;
+
+ case ResetDetected:
+
+ break;
+
+ case CallDisableInterrupts:
+
+ ASSERT(deviceExtension->Flags & PD_DISABLE_INTERRUPTS);
+
+ //
+ // The mini-port wants us to call the specified routine
+ // with interrupts disabled. This is done after the current
+ // HwRequestInterrutp routine completes. Indicate the call is
+ // needed and save the routine to be called.
+ //
+
+ deviceExtension->Flags |= PD_DISABLE_CALL_REQUEST;
+
+ deviceExtension->HwRequestInterrupt = va_arg(ap, PHW_INTERRUPT);
+
+ break;
+
+ case CallEnableInterrupts:
+
+ ASSERT(!(deviceExtension->Flags & PD_DISABLE_INTERRUPTS));
+
+ //
+ // The mini-port wants us to call the specified routine
+ // with interrupts enabled this is done from the DPC.
+ // Disable calls to the interrupt routine, indicate the call is
+ // needed and save the routine to be called.
+ //
+
+ deviceExtension->Flags |= PD_DISABLE_INTERRUPTS | PD_ENABLE_CALL_REQUEST;
+
+ deviceExtension->HwRequestInterrupt = va_arg(ap, PHW_INTERRUPT);
+
+ break;
+
+ case RequestTimerCall:
+
+ deviceExtension->HwTimerRequest = va_arg(ap, PHW_INTERRUPT);
+ deviceExtension->TimerValue =
+ (va_arg(ap, ULONG) + PD_INTERLOOP_STALL) / PD_INTERLOOP_STALL;
+ break;
+ }
+
+ va_end(ap);
+
+ //
+ // Check to see if the last DPC has been processed yet. If so
+ // queue another DPC.
+ //
+
+ ScsiPortCompletionDpc(
+ NULL, // Dpc
+ deviceExtension->DeviceObject, // DeviceObject
+ NULL, // Irp
+ NULL // Context
+ );
+
+} // end ScsiPortNotification()
+
+
+VOID
+ScsiPortFlushDma(
+ IN PVOID HwDeviceExtension
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks to see if the perivious IoMapTransfer has been done
+ started. If it has not, then the PD_MAP_TRANSER flag is cleared, and the
+ routine returns; otherwise, this routine schedules a DPC which will call
+ IoFlushAdapter buffers.
+
+Arguments:
+
+ HwDeviceExtension - Supplies a the hardware device extension for the
+ host bus adapter which will be doing the data transfer.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PDEVICE_EXTENSION deviceExtension;
+
+ deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+
+ if (deviceExtension->InterruptFlags & PD_MAP_TRANSFER) {
+
+ //
+ // The transfer has not been started so just clear the map transfer
+ // flag and return.
+ //
+
+ deviceExtension->InterruptFlags &= ~PD_MAP_TRANSFER;
+ return;
+ }
+
+ deviceExtension->InterruptFlags |= PD_FLUSH_ADAPTER_BUFFERS;
+
+ //
+ // Check to see if the last DPC has been processed yet. If so
+ // queue another DPC.
+ //
+
+ ScsiPortCompletionDpc(
+ NULL, // Dpc
+ deviceExtension->DeviceObject, // DeviceObject
+ NULL, // Irp
+ NULL // Context
+ );
+
+ return;
+
+}
+
+VOID
+ScsiPortIoMapTransfer(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb,
+ IN PVOID LogicalAddress,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ Saves the parameters for the call to IoMapTransfer and schedules the DPC
+ if necessary.
+
+Arguments:
+
+ HwDeviceExtension - Supplies a the hardware device extension for the
+ host bus adapter which will be doing the data transfer.
+
+ Srb - Supplies the particular request that data transfer is for.
+
+ LogicalAddress - Supplies the logical address where the transfer should
+ begin.
+
+ Length - Supplies the maximum length in bytes of the transfer.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension;
+
+ deviceExtension = ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+
+ //
+ // Make sure this host bus adapter has an Dma adapter object.
+ //
+
+ if (deviceExtension->DmaAdapterObject == NULL) {
+ //
+ // No DMA adapter, no work.
+ //
+ return;
+ }
+
+ deviceExtension->MapTransferParameters.Srb = Srb;
+ deviceExtension->MapTransferParameters.LogicalAddress = LogicalAddress;
+ deviceExtension->MapTransferParameters.Length = Length;
+
+ deviceExtension->InterruptFlags |= PD_MAP_TRANSFER;
+
+ //
+ // Check to see if the last DPC has been processed yet. If so
+ // queue another DPC.
+ //
+
+ ScsiPortCompletionDpc(
+ NULL, // Dpc
+ deviceExtension->DeviceObject, // DeviceObject
+ NULL, // Irp
+ NULL // Context
+ );
+
+} // end ScsiPortIoMapTransfer()
+
+
+VOID
+IssueRequestSense(
+ IN PDEVICE_EXTENSION deviceExtension,
+ IN PSCSI_REQUEST_BLOCK FailingSrb
+ )
+
+/*++
+
+Routine Description:
+
+ This routine creates a REQUEST SENSE request and uses IoCallDriver to
+ renter the driver. The completion routine cleans up the data structures
+ and processes the logical unit queue according to the flags.
+
+ A pointer to failing SRB is stored at the end of the request sense
+ Srb, so that the completion routine can find it.
+
+Arguments:
+
+ DeviceExension - Supplies a pointer to the device extension for this
+ SCSI port.
+
+ FailingSrb - Supplies a pointer to the request that the request sense
+ is being done for.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PIO_STACK_LOCATION irpstack;
+ PIRP Irp;
+ PSCSI_REQUEST_BLOCK Srb;
+ PCDB cdb;
+ PVOID *Pointer;
+
+ ScsiDebugPrint(3,"IssueRequestSense: Enter routine\n");
+
+ //
+ // Allocate Srb from non-paged pool
+ // plus room for a pointer to the failing IRP.
+ // Since this routine is in an error-handling
+ // path and a shortterm allocation
+ // NonPagedMustSucceed is requested.
+ //
+
+ Srb = &RequestSenseSrb.Srb;
+
+ //
+ // Allocate an IRP to issue the REQUEST SENSE request.
+ //
+
+ Irp = InitializeIrp(
+ &RequestSenseSrb,
+ IRP_MJ_READ,
+ deviceExtension->DeviceObject,
+ FailingSrb->SenseInfoBuffer,
+ FailingSrb->SenseInfoBufferLength
+ );
+
+ irpstack = IoGetNextIrpStackLocation(Irp);
+
+ irpstack->MajorFunction = IRP_MJ_SCSI;
+
+ //
+ // Save the Failing SRB after the request sense Srb.
+ //
+
+ Pointer = (PVOID *) (Srb+1);
+ *Pointer = FailingSrb;
+
+ //
+ // Build the REQUEST SENSE CDB.
+ //
+
+ Srb->CdbLength = 6;
+ cdb = (PCDB)Srb->Cdb;
+
+ cdb->CDB6INQUIRY.OperationCode = SCSIOP_REQUEST_SENSE;
+ cdb->CDB6INQUIRY.LogicalUnitNumber = 0;
+ cdb->CDB6INQUIRY.Reserved1 = 0;
+ cdb->CDB6INQUIRY.PageCode = 0;
+ cdb->CDB6INQUIRY.IReserved = 0;
+ cdb->CDB6INQUIRY.AllocationLength =
+ (UCHAR)FailingSrb->SenseInfoBufferLength;
+ cdb->CDB6INQUIRY.Control = 0;
+
+ //
+ // Save SRB address in next stack for port driver.
+ //
+
+ irpstack->Parameters.Others.Argument1 = (PVOID)Srb;
+
+ //
+ // Set up IRP Address.
+ //
+
+ Srb->OriginalRequest = Irp;
+
+ Srb->NextSrb = 0;
+
+ //
+ // Set up SCSI bus address.
+ //
+
+ Srb->TargetId = FailingSrb->TargetId;
+ Srb->Lun = FailingSrb->Lun;
+ Srb->PathId = FailingSrb->PathId;
+ Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
+ Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
+
+ //
+ // Set timeout value to 2 seconds.
+ //
+
+ Srb->TimeOutValue = 2;
+
+ //
+ // Disable auto request sense.
+ //
+
+ Srb->SenseInfoBufferLength = 0;
+
+ //
+ // Sense buffer is in stack.
+ //
+
+ Srb->SenseInfoBuffer = NULL;
+
+ //
+ // Set read and bypass frozen queue bits in flags.
+ //
+
+ //
+ // Set a speical flags to indicate the logical unit queue should be by
+ // passed and that no queue processing should be done when the request
+ // completes.
+ //
+
+ Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_BYPASS_FROZEN_QUEUE |
+ SRB_FLAGS_DISABLE_SYNCH_TRANSFER | SRB_FLAGS_DISABLE_DISCONNECT;
+
+ Srb->DataBuffer = FailingSrb->SenseInfoBuffer;
+
+ //
+ // Set the transfer length.
+ //
+
+ Srb->DataTransferLength = FailingSrb->SenseInfoBufferLength;
+
+ //
+ // Zero out status.
+ //
+
+ Srb->ScsiStatus = Srb->SrbStatus = 0;
+
+ (VOID)IoCallDriver(deviceExtension->DeviceObject, Irp);
+
+ ScsiPortInternalCompletion(deviceExtension->DeviceObject, Irp, Srb);
+
+ return;
+
+} // end IssueRequestSense()
+
+
+VOID
+ScsiPortInternalCompletion(
+ PDEVICE_OBJECT DeviceObject,
+ PIRP Irp,
+ PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ Device object
+ IRP
+ Context - pointer to SRB
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PSCSI_REQUEST_BLOCK srb = Context;
+ PIO_STACK_LOCATION irpstack = IoGetCurrentIrpStackLocation(Irp);
+ PSCSI_REQUEST_BLOCK failingSrb;
+ PIRP failingIrp;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ ScsiDebugPrint(3,"ScsiPortInternalCompletion: Enter routine\n");
+
+ //
+ // Request sense completed. If successful or data over/underrun
+ // get the failing SRB and indicate that the sense information
+ // is valid. The class driver will check for underrun and determine
+ // if there is enough sense information to be useful.
+ //
+
+ if ((SRB_STATUS(srb->SrbStatus) == SRB_STATUS_SUCCESS) ||
+ (SRB_STATUS(srb->SrbStatus) == SRB_STATUS_DATA_OVERRUN)) {
+
+ //
+ // Get a pointer to failing Irp and Srb.
+ //
+
+ failingSrb = *((PVOID *) (srb+1));
+ failingIrp = failingSrb->OriginalRequest;
+
+ //
+ // Report sense buffer is valid.
+ //
+
+ failingSrb->SrbStatus |= SRB_STATUS_AUTOSENSE_VALID;
+
+ //
+ // Copy bytes transferred to failing SRB
+ // request sense length field to communicate
+ // to the class drivers the number of valid
+ // sense bytes.
+ //
+
+ failingSrb->SenseInfoBufferLength = (UCHAR) srb->DataTransferLength;
+
+ }
+
+} // ScsiPortInternalCompletion()
+
+
+VOID
+ScsiPortTickHandler(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ (PDEVICE_EXTENSION) DeviceObject->DeviceExtension;
+ PLOGICAL_UNIT_EXTENSION logicalUnit;
+
+ UNREFERENCED_PARAMETER(Context);
+
+ logicalUnit = deviceExtension->LogicalUnitList;
+
+ //
+ // NOTE: The use of Current request needs to be synchronized with the
+ // clearing of current request.
+ //
+
+ while (logicalUnit != NULL) {
+
+ //
+ // Check for busy requests.
+ //
+
+ if (logicalUnit->Flags & PD_LOGICAL_UNIT_IS_BUSY) {
+
+ ScsiDebugPrint(1,"ScsiPortTickHandler: Retrying busy status request\n");
+
+ //
+ // Clear the busy flag and retry the request.
+ //
+
+ logicalUnit->Flags &= ~PD_LOGICAL_UNIT_IS_BUSY;
+
+ ScsiPortStartIo(DeviceObject, logicalUnit->CurrentRequest);
+
+ } else if (logicalUnit->RequestTimeoutCounter == 0) {
+
+ //
+ // Request timed out.
+ //
+
+ ScsiDebugPrint(1, "ScsiPortTickHandler: Request timed out\n");
+
+ //
+ // Reset request timeout counter to unused state.
+ //
+
+ logicalUnit->RequestTimeoutCounter = -1;
+
+ //
+ // Build and send request to abort command.
+ //
+
+ IssueAbortRequest(deviceExtension, logicalUnit->CurrentRequest);
+ } else if (logicalUnit->RequestTimeoutCounter != -1) {
+
+ ScsiDebugPrint(1, "ScsiPortTickHandler: Timeout value %lx\n",logicalUnit->RequestTimeoutCounter);
+ logicalUnit->RequestTimeoutCounter--;
+ }
+
+ logicalUnit = logicalUnit->NextLogicalUnit;
+ }
+
+ return;
+
+} // end ScsiPortTickHandler()
+
+
+VOID
+IssueAbortRequest(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PIRP FailingIrp
+ )
+
+/*++
+
+Routine Description:
+
+ A request timed out and to clear the request at the HBA
+ an ABORT request is issued. But first, if the request
+ that timed out was an ABORT command, then reset the
+ adapter instead.
+
+Arguments:
+
+ DeviceExension - Supplies a pointer to the device extension for this
+ SCSI port.
+
+ FailingIrp - Supplies a pointer to the request that is to be aborted.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG j;
+ ScsiDebugPrint(3,"IssueAbortRequest: Enter routine\n");
+
+
+ //
+ // A request to abort failed.
+ // Need to reset the adapter.
+ //
+
+ ScsiDebugPrint(1,"IssueAbort: Request timed out resetting the bus.\n");
+
+
+ if (!DeviceExtension->HwReset(
+ DeviceExtension->HwDeviceExtension,
+ 0)){
+
+ ScsiDebugPrint(1,"Reset SCSI bus failed\n");
+ }
+
+ //
+ // Call the interupt handler for a few microseconds to clear any reset
+ // interrupts.
+ //
+
+ for (j = 0; j < 1000 * 100; j++) {
+
+ FwStallExecution(10);
+ if (DeviceExtension->HwInterrupt != NULL) {
+ DeviceExtension->HwInterrupt(DeviceExtension->HwDeviceExtension);
+ }
+
+ }
+
+ //
+ // Wait 2 seconds for the devices to recover after the reset.
+ //
+
+ //FwStallExecution(2 * 1000 * 1000);
+ FwStallExecution(2 * 1000 * 100);
+
+ return;
+
+
+} // end IssueAbortRequest()
+
+
+BOOLEAN
+SpGetInterruptState(
+ IN PVOID ServiceContext
+ )
+
+/*++
+
+Routine Description:
+
+ This routine saves the InterruptFlags, MapTransferParameters and
+ CompletedRequests fields and clears the InterruptFlags.
+
+Arguments:
+
+ ServiceContext - Supplies a pointer to the device extension for this
+ SCSI port.
+
+Return Value:
+
+ Always returns TRUE.
+
+Notes:
+
+ Called via KeSynchronizeExecution.
+
+--*/
+{
+ PDEVICE_EXTENSION deviceExtension = ServiceContext;
+
+ //
+ // Move the interrupt state to save area.
+ //
+
+ deviceExtension->InterruptFlags = deviceExtension->InterruptFlags;
+ deviceExtension->CompletedRequests = deviceExtension->CompletedRequests;
+ deviceExtension->MapTransferParameters = deviceExtension->MapTransferParameters;
+
+ //
+ // Clear the interrupt state.
+ //
+
+ deviceExtension->InterruptFlags = 0;
+ deviceExtension->CompletedRequests = NULL;
+
+ return(TRUE);
+}
+
+VOID
+ScsiPortLogError(
+ IN PVOID HwDeviceExtension,
+ IN PSCSI_REQUEST_BLOCK Srb OPTIONAL,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN ULONG ErrorCode,
+ IN ULONG UniqueId
+ )
+
+/*++
+
+Routine Description:
+
+ This routine allocates an error log entry, copies the supplied text
+ to it, and requests that it be written to the error log file.
+
+Arguments:
+
+ DeviceExtenson - Supplies the HBA mini-port driver's adapter data storage.
+
+ TargetId, Lun and PathId - specify device address on a SCSI bus.
+
+ ErrorCode - Supplies an error code indicating the type of error.
+
+ UniqueId - Supplies a unique identifier for the error.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PCHAR errorCodeString;
+
+ switch (ErrorCode) {
+ case SP_BUS_PARITY_ERROR:
+ errorCodeString = "SCSI bus partity error";
+ break;
+
+ case SP_UNEXPECTED_DISCONNECT:
+ errorCodeString = "Unexpected disconnect";
+ break;
+
+ case SP_INVALID_RESELECTION:
+ errorCodeString = "Invalid reselection";
+ break;
+
+ case SP_BUS_TIME_OUT:
+ errorCodeString = "SCSI bus time out";
+ break;
+
+ case SP_PROTOCOL_ERROR:
+ errorCodeString = "SCSI protocol error";
+ break;
+
+ case SP_INTERNAL_ADAPTER_ERROR:
+ errorCodeString = "Internal adapter error";
+ break;
+
+ default:
+ errorCodeString = "Unknown error code";
+ break;
+
+ }
+
+ DebugPrint((0,"\n\nLogErrorEntry: Logging SCSI error packet. ErrorCode = %s.\n",
+ errorCodeString
+ ));
+ DebugPrint((0,
+ "PathId = %2x, TargetId = %2x, Lun = %2x, UniqueId = %x.\n\n",
+ PathId,
+ TargetId,
+ Lun,
+ UniqueId
+ ));
+
+
+ return;
+
+} // end ScsiPortLogError()
+
+
+VOID
+ScsiPortCompleteRequest(
+ IN PVOID HwDeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN UCHAR SrbStatus
+ )
+
+/*++
+
+Routine Description:
+
+ Complete all active requests for the specified logical unit.
+
+Arguments:
+
+ DeviceExtenson - Supplies the HBA mini-port driver's adapter data storage.
+
+ TargetId, Lun and PathId - specify device address on a SCSI bus.
+
+ SrbStatus - Status to be returned in each completed SRB.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ PSCSI_REQUEST_BLOCK Srb;
+ PSCSI_REQUEST_BLOCK failingSrb;
+ PLOGICAL_UNIT_EXTENSION luExtension;
+ PIRP nextIrp;
+ PIO_STACK_LOCATION irpstack;
+
+ UNREFERENCED_PARAMETER(PathId);
+ UNREFERENCED_PARAMETER(Lun);
+
+ if (TargetId == (UCHAR)(-1)) {
+
+ //
+ // Complete requests for all units on this bus.
+ //
+
+ luExtension = deviceExtension->LogicalUnitList;
+
+ while (luExtension != NULL) {
+
+ ScsiDebugPrint(2,
+ "ScsiPortCompleteRequest: Complete requests for targetid %d\n",
+ luExtension->TargetId);
+
+ //
+ // Complete requests until queue is empty.
+ //
+
+ if ((nextIrp = luExtension->CurrentRequest) != NULL &&
+ !(luExtension->Flags & PD_LOGICAL_UNIT_IS_BUSY)) {
+
+ ScsiDebugPrint(3,"ScsiPortCompleteRequest: Current request %lx\n",
+ nextIrp);
+
+ //
+ // Get SRB address from current IRP stack.
+ //
+
+ irpstack = IoGetCurrentIrpStackLocation(nextIrp);
+
+ Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+
+ //
+ // Just in case this is an abort request,
+ // get pointer to failingSrb.
+ //
+
+ failingSrb = Srb->NextSrb;
+
+ //
+ // Update SRB status.
+ //
+
+ Srb->SrbStatus = SrbStatus;
+
+ //
+ // Indicate no bytes transferred.
+ //
+
+ Srb->DataTransferLength = 0;
+
+ //
+ // Set IRP status.
+ //
+
+ nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+
+ //
+ // Move bytes transferred to IRP.
+ //
+
+ nextIrp->IoStatus.Information = Srb->DataTransferLength;
+
+ //
+ // Call notification routine.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)HwDeviceExtension,
+ Srb);
+
+ if (failingSrb) {
+
+ //
+ // This was an abort request. The failing
+ // SRB must also be completed.
+ //
+
+ failingSrb->SrbStatus = SrbStatus;
+ failingSrb->DataTransferLength = 0;
+
+ //
+ // Get IRP from SRB.
+ //
+
+ nextIrp = failingSrb->OriginalRequest;
+
+ //
+ // Set IRP status.
+ //
+
+ nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+
+ //
+ // Move bytes transferred to IRP.
+ //
+
+ nextIrp->IoStatus.Information =
+ failingSrb->DataTransferLength;
+
+ //
+ // Call notification routine.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)HwDeviceExtension,
+ failingSrb);
+ }
+
+ } // end if
+
+ luExtension = luExtension->NextLogicalUnit;
+
+ } // end while
+
+ } else {
+
+ //
+ // Complete all requests for this logical unit.
+ //
+
+ ScsiDebugPrint(2,
+ "ScsiPortCompleteRequest: Complete requests for targetid %d\n",
+ TargetId);
+
+
+ luExtension =
+ GetLogicalUnitExtension(deviceExtension, TargetId);
+
+ //
+ // Complete requests until queue is empty.
+ //
+
+ if ((nextIrp = luExtension->CurrentRequest) != NULL) {
+
+ ScsiDebugPrint(3,"ScsiPortCompleteRequest: Current request %lx\n",
+ nextIrp);
+
+ //
+ // Get SRB address from current IRP stack.
+ //
+
+ irpstack = IoGetCurrentIrpStackLocation(nextIrp);
+
+ Srb = (PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1;
+
+ //
+ // Update SRB status.
+ //
+
+ Srb->SrbStatus = SrbStatus;
+
+ //
+ // Indicate no bytes transferred.
+ //
+
+ Srb->DataTransferLength = 0;
+
+ //
+ // Set IRP status.
+ //
+
+ nextIrp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+
+ //
+ // Move bytes transferred to IRP.
+ //
+
+ nextIrp->IoStatus.Information = Srb->DataTransferLength;
+
+ //
+ // Call notification routine.
+ //
+
+ ScsiPortNotification(RequestComplete,
+ (PVOID)HwDeviceExtension,
+ Srb);
+
+ } // end while
+
+ } // end if ... else
+
+ return;
+
+
+} // end ScsiPortCompleteRequest()
+
+
+VOID
+ScsiPortMoveMemory(
+ IN PVOID WriteBuffer,
+ IN PVOID ReadBuffer,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ Copy from one buffer into another.
+
+Arguments:
+
+ ReadBuffer - source
+ WriteBuffer - destination
+ Length - number of bytes to copy
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ RtlMoveMemory(WriteBuffer, ReadBuffer, Length);
+
+} // end ScsiPortMoveMemory()
+
+
+VOID
+ScsiPortStallExecution(
+ ULONG Delay
+ )
+/*++
+
+Routine Description:
+
+ Wait number of microseconds in tight processor loop.
+
+Arguments:
+
+ Delay - number of microseconds to wait.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FwStallExecution(Delay);
+
+} // end ScsiPortStallExecution()
+
+
+PLOGICAL_UNIT_EXTENSION
+GetLogicalUnitExtension(
+ PDEVICE_EXTENSION deviceExtension,
+ UCHAR TargetId
+ )
+
+/*++
+
+Routine Description:
+
+ Walk logical unit extension list looking for
+ extension with matching target id.
+
+Arguments:
+
+ deviceExtension
+ TargetId
+
+Return Value:
+
+ Requested logical unit extension if found,
+ else NULL.
+
+--*/
+
+{
+ PLOGICAL_UNIT_EXTENSION logicalUnit = deviceExtension->LogicalUnitList;
+
+ while (logicalUnit != NULL) {
+
+ if (logicalUnit->TargetId == TargetId) {
+
+ return logicalUnit;
+ }
+
+ logicalUnit = logicalUnit->NextLogicalUnit;
+ }
+
+ //
+ // Logical unit extension not found.
+ //
+
+ return (PLOGICAL_UNIT_EXTENSION)NULL;
+
+} // end GetLogicalUnitExtension()
+
+
+VOID
+ScsiDebugPrint(
+ ULONG DebugPrintLevel,
+ PCCHAR DebugMessage,
+ ...
+ )
+
+/*++
+
+Routine Description:
+
+ Debug print for all SCSI drivers
+
+Arguments:
+
+ Debug print level between 0 and 3, with 3 being the most verbose.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ va_list ap;
+
+ va_start( ap, DebugMessage );
+
+ if (DebugPrintLevel <= ScsiDebug) {
+
+ char buffer[128];
+
+ vsprintf(buffer, DebugMessage, ap);
+ DbgPrint(buffer);
+ DbgPrint("\r");
+ }
+
+ va_end(ap);
+}
+
+UCHAR
+ScsiPortReadPortUchar(
+ IN PUCHAR Port
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+Return Value:
+
+ Returns the value read from the specified port address.
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ return(READ_REGISTER_UCHAR(Port));
+
+#else
+
+ return(READ_PORT_UCHAR(Port));
+
+#endif
+}
+
+USHORT
+ScsiPortReadPortUshort(
+ IN PUSHORT Port
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+Return Value:
+
+ Returns the value read from the specified port address.
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ return(READ_REGISTER_USHORT(Port));
+
+#else
+
+ return(READ_PORT_USHORT(Port));
+
+#endif
+}
+
+ULONG
+ScsiPortReadPortUlong(
+ IN PULONG Port
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+Return Value:
+
+ Returns the value read from the specified port address.
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ return(READ_REGISTER_ULONG(Port));
+
+#else
+
+ return(READ_PORT_ULONG(Port));
+
+#endif
+}
+
+UCHAR
+ScsiPortReadRegisterUchar(
+ IN PUCHAR Register
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+Return Value:
+
+ Returns the value read from the specified register address.
+
+--*/
+
+{
+
+ return(READ_REGISTER_UCHAR(Register));
+
+}
+
+USHORT
+ScsiPortReadRegisterUshort(
+ IN PUSHORT Register
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+Return Value:
+
+ Returns the value read from the specified register address.
+
+--*/
+
+{
+
+ return(READ_REGISTER_USHORT(Register));
+
+}
+
+ULONG
+ScsiPortReadRegisterUlong(
+ IN PULONG Register
+ )
+
+/*++
+
+Routine Description:
+
+ Read from the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+Return Value:
+
+ Returns the value read from the specified register address.
+
+--*/
+
+{
+
+ return(READ_REGISTER_ULONG(Register));
+
+}
+
+VOID
+ScsiPortReadRegisterBufferUchar(
+ IN PUCHAR Register,
+ IN PUCHAR Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned bytes from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortReadRegisterBufferUshort(
+ IN PUSHORT Register,
+ IN PUSHORT Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned shorts from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortReadRegisterBufferUlong(
+ IN PULONG Register,
+ IN PULONG Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned longs from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWritePortUchar(
+ IN PUCHAR Port,
+ IN UCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ WRITE_REGISTER_UCHAR(Port, Value);
+
+#else
+
+ WRITE_PORT_UCHAR(Port, Value);
+
+#endif
+}
+
+VOID
+ScsiPortWritePortUshort(
+ IN PUSHORT Port,
+ IN USHORT Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ WRITE_REGISTER_USHORT(Port, Value);
+
+#else
+
+ WRITE_PORT_USHORT(Port, Value);
+
+#endif
+}
+
+VOID
+ScsiPortWritePortUlong(
+ IN PULONG Port,
+ IN ULONG Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+#ifdef MIPS
+
+ WRITE_REGISTER_ULONG(Port, Value);
+
+#else
+
+ WRITE_PORT_ULONG(Port, Value);
+
+#endif
+}
+
+VOID
+ScsiPortWriteRegisterUchar(
+ IN PUCHAR Register,
+ IN UCHAR Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_UCHAR(Register, Value);
+
+}
+
+VOID
+ScsiPortWriteRegisterUshort(
+ IN PUSHORT Register,
+ IN USHORT Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_USHORT(Register, Value);
+
+}
+
+VOID
+ScsiPortWriteRegisterUlong(
+ IN PULONG Register,
+ IN ULONG Value
+ )
+
+/*++
+
+Routine Description:
+
+ Write to the specificed register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the register address.
+
+ Value - Supplies the value to be written.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_ULONG(Register, Value);
+
+}
+
+VOID
+ScsiPortWriteRegisterBufferUchar(
+ IN PUCHAR Register,
+ IN PUCHAR Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned bytes from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_BUFFER_UCHAR(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWriteRegisterBufferUshort(
+ IN PUSHORT Register,
+ IN PUSHORT Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned shorts from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_BUFFER_USHORT(Register, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWriteRegisterBufferUlong(
+ IN PULONG Register,
+ IN PULONG Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned longs from the specified register address.
+
+Arguments:
+
+ Register - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_REGISTER_BUFFER_ULONG(Register, Buffer, Count);
+
+}
+
+SCSI_PHYSICAL_ADDRESS
+ScsiPortConvertUlongToPhysicalAddress(
+ ULONG UlongAddress
+ )
+
+{
+ SCSI_PHYSICAL_ADDRESS physicalAddress;
+
+ physicalAddress.HighPart = 0;
+ physicalAddress.LowPart = UlongAddress;
+ return(physicalAddress);
+}
+
+#undef ScsiPortConvertPhysicalAddressToUlong
+
+ULONG
+ScsiPortConvertPhysicalAddressToUlong(
+ SCSI_PHYSICAL_ADDRESS Address
+ )
+{
+
+ return(Address.LowPart);
+}
+
+
+
+PIRP
+InitializeIrp(
+ PFULL_SCSI_REQUEST_BLOCK FullSrb,
+ CCHAR MajorFunction,
+ PVOID DeviceObject,
+ PVOID Buffer,
+ ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This funcition builds an IRP for use by the SCSI port driver and builds a
+ MDL list.
+
+Arguments:
+
+ FullSrb - Supplies a pointer to the full srb structure which contains the
+ Irp and Mdl.
+
+ MajorFunction - Supplies the major function code to initialize the Irp
+ entry.
+
+ DeviceObject - Supplies the device Object pointer to initialize the Irp
+ with.
+
+ Buffer - Supplies the virual address of the buffer for which the
+ Mdl should be built.
+
+ Length - Supplies the size of buffer for which the Mdl should be built.
+
+Return Value:
+
+ Returns a pointer to the initialized IRP.
+
+--*/
+
+{
+ PIRP irp;
+ PMDL mdl;
+ PULONG pageFrame;
+ ULONG frameNumber;
+ ULONG index;
+ ULONG numberOfPages;
+
+ irp = &FullSrb->Irp;
+ mdl = &FullSrb->Mdl;
+
+ irp->Tail.Overlay.CurrentStackLocation = &FullSrb->IrpStack[IRP_STACK_SIZE];
+
+ if (Buffer != NULL && Length != 0) {
+
+ //
+ // Build the memory descriptor list.
+ //
+
+ irp->MdlAddress = mdl;
+ mdl->Next = NULL;
+ mdl->Size = sizeof(MDL) +
+ ADDRESS_AND_SIZE_TO_SPAN_PAGES(Buffer, Length) * sizeof(ULONG);
+ mdl->StartVa = (PVOID)PAGE_ALIGN(Buffer);
+ mdl->ByteCount = Length;
+ mdl->ByteOffset = BYTE_OFFSET(Buffer);
+ mdl->MappedSystemVa = Buffer;
+ mdl->MdlFlags = MDL_MAPPED_TO_SYSTEM_VA;
+ pageFrame = (PULONG)(mdl + 1);
+ frameNumber = RtlLargeIntegerShiftRight(
+ MmGetPhysicalAddress(mdl->StartVa), PAGE_SHIFT).LowPart;
+ numberOfPages = (mdl->ByteCount +
+ mdl->ByteOffset + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ for (index = 0; index < numberOfPages; index += 1) {
+ *pageFrame++ = frameNumber++;
+ }
+
+ } else {
+ irp->MdlAddress = NULL;
+ }
+
+ return(irp);
+}
+
+PVOID
+ScsiPortGetDeviceBase(
+ IN PVOID HwDeviceExtension,
+ IN INTERFACE_TYPE BusType,
+ IN ULONG SystemIoBusNumber,
+ SCSI_PHYSICAL_ADDRESS IoAddress,
+ ULONG NumberOfBytes,
+ BOOLEAN InMemorySpace
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps an IO address to system address space.
+ Use ScsiPortFreeDeviceBase to unmap address.
+
+Arguments:
+
+ HwDeviceExtension - used to find port device extension.
+ BusType - what type of bus - eisa, mca, isa
+ SystemIoBusNumber - which IO bus (for machines with multiple buses).
+ IoAddress - base device address to be mapped.
+ NumberOfBytes - number of bytes for which address is valid.
+
+Return Value:
+
+ Mapped address
+
+--*/
+
+{
+ PHYSICAL_ADDRESS cardAddress;
+ ULONG addressSpace = InMemorySpace;
+ PVOID mappedAddress;
+
+ HalTranslateBusAddress(
+ BusType, // AdapterInterfaceType
+ SystemIoBusNumber, // SystemIoBusNumber
+ IoAddress, // Bus Address
+ &addressSpace, // AddressSpace
+ &cardAddress // Translated address
+ );
+
+ //
+ // Map the device base address into the virtual address space
+ // if the address is in memory space.
+ //
+
+ if (!addressSpace) {
+
+ mappedAddress = MmMapIoSpace(cardAddress,
+ NumberOfBytes,
+ FALSE);
+
+
+ } else {
+
+ mappedAddress = (PVOID)cardAddress.LowPart;
+ }
+
+ return mappedAddress;
+
+} // end ScsiPortGetDeviceBase()
+
+VOID
+ScsiPortFreeDeviceBase(
+ IN PVOID HwDeviceExtension,
+ IN PVOID MappedAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine unmaps an IO address that has been previously mapped
+ to system address space using ScsiPortGetDeviceBase().
+
+Arguments:
+
+ HwDeviceExtension - used to find port device extension.
+ MappedAddress - address to unmap.
+ NumberOfBytes - number of bytes mapped.
+ InIoSpace - addresses in IO space don't get mapped.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(HwDeviceExtension);
+ UNREFERENCED_PARAMETER(MappedAddress);
+
+ return;
+
+} // end ScsiPortFreeDeviceBase()
+
+ARC_STATUS
+GetAdapterCapabilities(
+ IN PDEVICE_OBJECT PortDeviceObject,
+ OUT PIO_SCSI_CAPABILITIES *PortCapabilities
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+ Status is returned.
+
+--*/
+
+{
+ *PortCapabilities = &((PDEVICE_EXTENSION)PortDeviceObject->DeviceExtension)
+ ->Capabilities;
+
+ return(ESUCCESS);
+} // end GetAdapterCapabilities()
+
+
+ARC_STATUS
+GetInquiryData(
+ IN PDEVICE_OBJECT PortDeviceObject,
+ OUT PSCSI_CONFIGURATION_INFO *ConfigInfo
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sends a request to a port driver to return
+ configuration information.
+
+Arguments:
+
+ The address of the configuration information is returned in
+ the formal parameter ConfigInfo.
+
+Return Value:
+
+ Status is returned.
+
+--*/
+{
+ *ConfigInfo = ((PDEVICE_EXTENSION)PortDeviceObject->DeviceExtension)
+ ->ScsiInfo;
+ return(ESUCCESS);
+} // end GetInquiryData()
+
+NTSTATUS
+SpInitializeConfiguration(
+ IN PDEVICE_EXTENSION DeviceExtension,
+ IN PHW_INITIALIZATION_DATA HwInitData,
+ OUT PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN BOOLEAN InitialCall
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the port configuration information structure.
+ Any necessary information is extracted from the registery.
+
+Arguments:
+
+ DeviceExtension - Supplies the device extension.
+
+ HwInitializationData - Supplies the initial miniport data.
+
+ ConfigInfo - Supplies the configuration information to be
+ initialized.
+
+ InitialCall - Indicates that this is first call to this function.
+ If InitialCall is FALSE, then the perivous configuration information
+ is used to determine the new information.
+
+Return Value:
+
+ Returns a status indicating the success or fail of the initializaiton.
+
+--*/
+
+{
+#ifdef i386
+ extern ULONG MachineType;
+#endif
+
+ ULONG j;
+
+ //
+ // If this is the initial call then zero the information and set
+ // the structure to the uninitialized values.
+ //
+
+ if (InitialCall) {
+
+ RtlZeroMemory(ConfigInfo, sizeof(PORT_CONFIGURATION_INFORMATION));
+
+ ConfigInfo->Length = sizeof(PORT_CONFIGURATION_INFORMATION);
+ ConfigInfo->AdapterInterfaceType = HwInitData->AdapterInterfaceType;
+ ConfigInfo->InterruptMode = Latched;
+ ConfigInfo->MaximumTransferLength = 0xffffffff;
+ ConfigInfo->NumberOfPhysicalBreaks = 0xffffffff;
+ ConfigInfo->DmaChannel = 0xffffffff;
+ ConfigInfo->NumberOfAccessRanges = HwInitData->NumberOfAccessRanges;
+
+#ifdef MIPS
+ {
+ PCONFIGURATION_COMPONENT Component;
+ PCM_SCSI_DEVICE_DATA ScsiDeviceData;
+ UCHAR Buffer[sizeof(CM_PARTIAL_RESOURCE_LIST) +
+ (sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR) * 5) +
+ sizeof(CM_SCSI_DEVICE_DATA)];
+ PCM_PARTIAL_RESOURCE_LIST Descriptor = (PCM_PARTIAL_RESOURCE_LIST)&Buffer;
+ ULONG Count;
+ ULONG ScsiHostId;
+ UCHAR ScsiComponentName[8];
+
+ //
+ // Build the string scsi(n) to get the Arc component info
+ // for the current scsi
+ //
+ sprintf(ScsiComponentName,"scsi(%d)",ScsiPortCount);
+ if (((Component = ArcGetComponent(ScsiComponentName)) != NULL) &&
+ (Component->Class == AdapterClass) && (Component->Type == ScsiAdapter) &&
+ (ArcGetConfigurationData((PVOID)Descriptor, Component) == ESUCCESS) &&
+ ((Count = Descriptor->Count) < 6)) {
+
+ ScsiDeviceData = (PCM_SCSI_DEVICE_DATA)&Descriptor->PartialDescriptors[Count];
+
+ if (ScsiDeviceData->HostIdentifier > 7) {
+ ScsiHostId = 7;
+ } else {
+ ScsiHostId = ScsiDeviceData->HostIdentifier;
+ }
+ } else {
+ ScsiHostId = 7;
+ }
+
+ for (j = 0; j < 8; j++) {
+ ConfigInfo->InitiatorBusId[j] = ScsiHostId;
+ }
+ }
+
+#else
+
+ for (j = 0; j < 8; j++) {
+ ConfigInfo->InitiatorBusId[j] = ~0;
+ }
+
+#endif
+
+#if i386
+ switch (HwInitData->AdapterInterfaceType) {
+ case Isa:
+ if ((MachineType & 0xff) == MACHINE_TYPE_ISA) {
+ return(STATUS_SUCCESS);
+ }
+ case Eisa:
+ if ((MachineType & 0xff) == MACHINE_TYPE_EISA) {
+ return(STATUS_SUCCESS);
+ } else {
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+
+ case MicroChannel:
+ if ((MachineType & 0xff) == MACHINE_TYPE_MCA) {
+ return(STATUS_SUCCESS);
+ } else {
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+
+ default:
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+#elif MIPS
+
+ //
+ // ****** TMP to use the DEMO board only. Eisa can be removed.
+ //
+ if ((HwInitData->AdapterInterfaceType != Internal) &&
+ (HwInitData->AdapterInterfaceType != Isa)) {
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+#endif
+
+ return(STATUS_SUCCESS);
+
+ } else {
+
+ return(STATUS_DEVICE_DOES_NOT_EXIST);
+ }
+}
+
+
+NTSTATUS
+SpGetCommonBuffer(
+ PDEVICE_EXTENSION DeviceExtension,
+ ULONG NonCachedExtensionSize
+ )
+/*++
+
+Routine Description:
+
+ This routine determines the required size of the common buffer. Allocates
+ the common buffer and finally sets up the srb extension zone. This routine
+ expects that the adapter object has already been allocated.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the device extension.
+
+ NonCachedExtensionSize - Supplies the size of the noncached device
+ extension for the mini-port driver.
+
+Return Value:
+
+ Returns the status of the allocate operation.
+
+--*/
+
+{
+ PVOID buffer;
+ ULONG length;
+ ULONG blockSize;
+
+ //
+ // Calculate the block size for the zone elements based on the Srb
+ // Extension.
+ //
+
+ blockSize = DeviceExtension->SrbExtensionSize;
+
+ //
+ // Last three bits of blocksize must be zero.
+ // Round blocksize up.
+ //
+
+ blockSize = (blockSize + 7) & ~7;
+
+ length = NonCachedExtensionSize + blockSize * MINIMUM_SRB_EXTENSIONS;
+
+ //
+ // Round the length up to a page size, since HalGetCommonBuffer allocates
+ // in pages anyway.
+ //
+
+ length = ROUND_TO_PAGES(length);
+
+ //
+ // Allocate one page for noncached deviceextension
+ // and srbextension zoned pool.
+ //
+ buffer = MmAllocateNonCachedMemory(length);
+ if (buffer == NULL) {
+
+ ScsiDebugPrint(1,
+ "ScsiPortInitialize: Could not allocate page of noncached pool\n");
+
+ return ENOMEM;
+ }
+
+ //
+ // Determine length and starting address of zone.
+ // If noncached device extension required then
+ // subtract size from page leaving rest for zone.
+ //
+
+ DeviceExtension->NonCachedExtension = (PUCHAR)buffer + length - NonCachedExtensionSize;
+
+ if (DeviceExtension->SrbExtensionSize) {
+
+ //
+ // Get block size.
+ //
+
+ blockSize = DeviceExtension->SrbExtensionSize;
+
+ //
+ // Record starting virtual address of zone.
+ //
+
+ DeviceExtension->SrbExtensionZonePool = buffer;
+ DeviceExtension->SrbExtensionPointer = buffer;
+ DeviceExtension->SrbExtensionSize = blockSize;
+
+ //
+ // Set the IO translation for the common buffer
+ // and store the mapping in PhysicalZoneBase.
+ //
+ IopAllocateCommonBuffer(buffer,
+ length,
+ &DeviceExtension->PhysicalZoneBase
+ );
+
+ } else {
+ DeviceExtension->SrbExtensionZonePool = NULL;
+ }
+
+ return(ESUCCESS);
+}
+
+PVOID
+ScsiPortGetUncachedExtension(
+ IN PVOID HwDeviceExtension,
+ IN PPORT_CONFIGURATION_INFORMATION ConfigInfo,
+ IN ULONG NumberOfBytes
+ )
+/*++
+
+Routine Description:
+
+ This function allocates a common buffer to be used as the uncached device
+ extension for the mini-port driver. This function will also allocate any
+ required SRB extensions. The DmaAdapter is allocated if it has not been
+ allocated previously.
+
+Arguments:
+
+ DeviceExtension - Supplies a pointer to the mini-ports device extension.
+
+ ConfigInfo - Supplies a pointer to the partially initialized configuraiton
+ information. This is used to get an DMA adapter object.
+
+ NumberOfBytes - Supplies the size of the extension which needs to be
+ allocated
+
+Return Value:
+
+ A pointer to the uncached device extension or NULL if the extension could
+ not be allocated or was previously allocated.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ NTSTATUS status;
+
+ //
+ // Make sure that an common buffer has not already been allocated.
+ //
+
+ if (deviceExtension->SrbExtensionZonePool != NULL) {
+ return(NULL);
+ }
+
+ //
+ // Allocate the common buffer.
+ //
+
+ status = SpGetCommonBuffer( deviceExtension, NumberOfBytes);
+
+ if (status != ESUCCESS) {
+ return(NULL);
+ }
+
+ return(deviceExtension->NonCachedExtension);
+}
+
+ULONG
+ScsiPortGetBusData(
+ IN PVOID DeviceExtension,
+ IN ULONG BusDataType,
+ IN ULONG SystemIoBusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ The function returns the bus data for an adapter slot or CMOS address.
+
+Arguments:
+
+ BusDataType - Supplies the type of bus.
+
+ BusNumber - Indicates which bus.
+
+ Buffer - Supplies the space to store the data.
+
+ Length - Supplies a count in bytes of the maximum amount to return.
+
+Return Value:
+
+ Returns the amount of data stored into the buffer.
+
+--*/
+
+{
+ ULONG DataLength = 0;
+
+#ifdef i386
+ PDEVICE_EXTENSION deviceExtension =
+ (PDEVICE_EXTENSION) DeviceExtension - 1;
+
+ //
+ // If the length is non-zero, the the requested data.
+ //
+
+ if (Length != 0) {
+
+ return( HalGetBusData( BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ Buffer,
+ Length
+ ));
+ }
+
+ //
+ // Free any previously allocated data.
+ //
+
+ if (deviceExtension->MapRegisterBase != NULL) {
+ ExFreePool(deviceExtension->MapRegisterBase);
+ }
+
+ if (BusDataType == EisaConfiguration) {
+
+#if 0
+ //
+ // Deteremine the length to allocate based on the number of functions
+ // for the slot.
+ //
+
+ Length = HalGetBusData( BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ &slotInformation,
+ sizeof(CM_EISA_SLOT_INFORMATION));
+
+
+ if (Length < sizeof(CM_EISA_SLOT_INFORMATION)) {
+
+ //
+ // The data is messed up since this should never occur
+ //
+
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Slot information not returned. Length = %d\n", Length);
+#if 0
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Hit any key\n");
+ if (ScsiDebug >= 1) {
+ while(!GET_KEY());
+ }
+#endif
+ return(0);
+ }
+
+ //
+ // Calculate the required length based on the number of functions.
+ //
+
+ Length = sizeof(CM_EISA_SLOT_INFORMATION) +
+ (sizeof(CM_EISA_FUNCTION_INFORMATION) * slotInformation.NumberFunctions);
+
+#else
+
+ //
+ // Since the loader does not really support freeing data and the EISA
+ // configuration data can be very large. Hal get bus data has be changed
+ // to accept a length of zero for EIAS configuration data.
+ //
+
+ DataLength = HalGetBusData( BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ Buffer,
+ Length
+ );
+
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Returning data. Length = %d\n", DataLength);
+#if 0
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Hit any key\n");
+ if (ScsiDebug >= 1) {
+ while(!GET_KEY());
+ }
+#endif
+
+ return(DataLength);
+#endif
+
+ } else {
+
+ Length = PAGE_SIZE;
+ }
+
+ deviceExtension->MapRegisterBase = ExAllocatePool(NonPagedPool, Length);
+
+ if (deviceExtension->MapRegisterBase == NULL) {
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Memory allocation failed. Length = %d\n", Length);
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Hit any key\n");
+ if (ScsiDebug >= 1) {
+ while(!GET_KEY());
+ }
+
+ return(0);
+ }
+
+ //
+ // Return the pointer to the mini-port driver.
+ //
+
+ *((PVOID *)Buffer) = deviceExtension->MapRegisterBase;
+
+ DataLength = HalGetBusData( BusDataType,
+ SystemIoBusNumber,
+ SlotNumber,
+ deviceExtension->MapRegisterBase,
+ Length
+ );
+
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Returning data. Length = %d\n", DataLength);
+#if 0
+ ScsiDebugPrint(1, "ScsiPortGetBusData: Hit any key\n");
+ if (ScsiDebug >= 1) {
+ while(!GET_KEY());
+ }
+#endif
+
+#endif
+ return(DataLength);
+}
+
+PSCSI_REQUEST_BLOCK
+ScsiPortGetSrb(
+ IN PVOID HwDeviceExtension,
+ IN UCHAR PathId,
+ IN UCHAR TargetId,
+ IN UCHAR Lun,
+ IN LONG QueueTag
+ )
+
+/*++
+
+Routine Description:
+
+ This routine retrieves an active SRB for a particuliar logical unit.
+
+Arguments:
+
+ HwDeviceExtension
+ PathId, TargetId, Lun - identify logical unit on SCSI bus.
+ QueueTag - -1 indicates request is not tagged.
+
+Return Value:
+
+ SRB, if one exists. Otherwise, NULL.
+
+--*/
+
+{
+ PDEVICE_EXTENSION deviceExtension =
+ ((PDEVICE_EXTENSION) HwDeviceExtension) - 1;
+ PLOGICAL_UNIT_EXTENSION luExtension;
+ PIRP irp;
+ PIO_STACK_LOCATION irpstack;
+
+
+ luExtension = GetLogicalUnitExtension(deviceExtension, TargetId);
+
+
+ if (luExtension == NULL) {
+ return(NULL);
+ }
+
+ irp = luExtension->CurrentRequest;
+ irpstack = IoGetCurrentIrpStackLocation(irp);
+ return ((PSCSI_REQUEST_BLOCK)irpstack->Parameters.Others.Argument1);
+
+} // end ScsiPortGetSrb()
+
+
+VOID
+ScsiPortReadPortBufferUchar(
+ IN PUCHAR Port,
+ IN PUCHAR Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned bytes from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_PORT_BUFFER_UCHAR(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortReadPortBufferUshort(
+ IN PUSHORT Port,
+ IN PUSHORT Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned shorts from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_PORT_BUFFER_USHORT(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortReadPortBufferUlong(
+ IN PULONG Port,
+ IN PULONG Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Read a buffer of unsigned longs from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ READ_PORT_BUFFER_ULONG(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWritePortBufferUchar(
+ IN PUCHAR Port,
+ IN PUCHAR Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned bytes from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_PORT_BUFFER_UCHAR(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWritePortBufferUshort(
+ IN PUSHORT Port,
+ IN PUSHORT Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned shorts from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_PORT_BUFFER_USHORT(Port, Buffer, Count);
+
+}
+
+VOID
+ScsiPortWritePortBufferUlong(
+ IN PULONG Port,
+ IN PULONG Buffer,
+ IN ULONG Count
+ )
+
+/*++
+
+Routine Description:
+
+ Write a buffer of unsigned longs from the specified port address.
+
+Arguments:
+
+ Port - Supplies a pointer to the port address.
+ Buffer - Supplies a pointer to the data buffer area.
+ Count - The count of items to move.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+
+ WRITE_PORT_BUFFER_ULONG(Port, Buffer, Count);
+
+}
+
+#endif /* DECSTATION */
diff --git a/private/ntos/fw/mips/selfmap.h b/private/ntos/fw/mips/selfmap.h
new file mode 100644
index 000000000..8ea7d49a3
--- /dev/null
+++ b/private/ntos/fw/mips/selfmap.h
@@ -0,0 +1,335 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ selfmap.h
+
+Abstract:
+
+ This module defines various memory addresses for the ROM self-test.
+
+Author:
+
+ Lluis Abello (lluis) 10-Jan-1991
+
+Revision History:
+
+--*/
+
+#ifndef _SELFMAP_
+#define _SELFMAP_
+
+
+#define PROM256
+
+#ifdef PROM64
+#define ROM_SIZE 0x10000
+#endif
+#ifdef PROM128
+#define ROM_SIZE 0x20000
+#endif
+#ifdef PROM256
+#define ROM_SIZE 0x40000
+#endif
+
+//
+// TTable points to 2Mb
+//
+#define TT_BASE_ADDRESS 0x200000
+
+#define MEMTEST_SIZE 0x2000 // Size of memory tested first
+#define STACK_SIZE 0xA000 // 40Kb of stack
+#define RAM_TEST_STACK_ADDRESS 0x8000BFF0 // Stack for code copied to memory
+#define RAM_TEST_STACK_ADDRESS_B 0x80005FF0 // stack for processor B
+
+#ifdef R3000
+#define INSTRUCTION_CACHE_SIZE 0x10000 // 64Kb of I Cache
+#define DATA_CACHE_SIZE 0x10000 // 64Kb of D Cache
+#define SIZE_OF_CACHES 0x10000 // 64Kb bigest cache.
+#define ROM_TLB_ENTRIES (ROM_SIZE >> 12)
+#define DEVICE_TLB_ENTRIES 16
+#define FIRST_UNUSED_TLB_ENTRY ROM_TLB_ENTRIES+DEVICE_TLB_ENTRIES
+#endif // R3000
+
+//
+// Define firmware size.
+// Firmware size includes code and stack.
+//
+// FW_TOP_ADDRESS must be a 64K aligned address.
+// The upper 64Kb (0x50000 to 0x60000) are reserved for the video prom code.
+// Note that the firmware size is 0x40000, it is loaded starting
+// at address 0xC000, and the fonts are unpacked at 0x4C000.
+//
+// N.B. If any of these numbers change, adjust the are of memory zero'd by
+// j4start.s.
+//
+
+#define FW_BOTTOM_ADDRESS 0xC000
+#define FW_SIZE 0x40000
+#define FW_FONT_SIZE (0x50000 - FW_SIZE - FW_BOTTOM_ADDRESS)
+#define VIDEO_PROM_SIZE 0x10000
+#define FW_TOP_ADDRESS (FW_BOTTOM_ADDRESS + FW_SIZE + FW_FONT_SIZE + VIDEO_PROM_SIZE)
+
+#define FW_PAGES ((FW_TOP_ADDRESS) >> PAGE_SHIFT)
+
+#define VIDEO_PROM_CODE_VIRTUAL_BASE 0x10000000 // Link address of video prom code
+#define VIDEO_PROM_CODE_PHYSICAL_BASE (FW_TOP_ADDRESS - VIDEO_PROM_SIZE) // phys address of video prom code
+#define VIDEO_PROM_CODE_UNCACHED_BASE (KSEG1_BASE + VIDEO_PROM_CODE_PHYSICAL_BASE) // uncached address where video prom code is copied
+
+#define FW_FONT_ADDRESS (KSEG0_BASE + FW_BOTTOM_ADDRESS + FW_SIZE)
+
+//
+// Address definitions for the SelftTests written in C.
+// The code is copied to RAM_TEST_LINK_ADDRESS from RAM_TEST_ROM_ADDRESS
+// so that it runs at the address it was linked.
+//
+
+#define RAM_TEST_DESTINATION_ADDRESS 0xA000c000 // uncached link address
+#define RAM_TEST_LINK_ADDRESS 0x8000c000 // Link Address of code
+
+//
+// FW_TOP_ADDRESS ___________
+// | Video rom |
+// | code |
+// |___________|
+// FW_SIZE | Code |
+// | & |
+// | Data |
+// | |
+// |___________|
+// | Stack || |
+// |_______\/__|
+// MEMTEST_SIZE |PutLed | Memory tested from ROM
+// |ZeroMem |
+// |MemoryTest |
+// 0 |___________|
+//
+
+#ifdef DUO
+#define LINK_ADDRESS 0xE1040000
+#else
+#define LINK_ADDRESS 0xE1000000
+#endif
+#define RESET_VECTOR 0xBFC00000
+
+//
+// Virtual - Physiscal base address pairs
+//
+#define TLB_TEST_PHYS 0x0 // To test the tlb
+#define TLB_TEST_VIRT 0x20000000 //
+#define RESV_VIRT 0xE4000000
+
+//
+// Entry LO - HI pairs
+//
+#ifdef R4000
+#define PROM_HI ((PROM_VIRTUAL_BASE >> 13) << ENTRYHI_VPN2)
+#define PROM_LO0 ((PROM_PHYSICAL_BASE >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + (1 << ENTRYLO_V) + (2 << ENTRYLO_C)
+#ifdef PROM256
+#define PROM_LO1 (1 << ENTRYLO_G)
+#define PROM_MASK (PAGEMASK_256KB << PAGEMASK_PAGEMASK)
+#endif
+#ifdef PROM128 //
+#define PROM_LO1 (((PROM_PHYSICAL_BASE+0x10000) >> 12) << ENTRYLO_PFN) + (1 << ENTRYLO_G) + \
+ (1 << ENTRYLO_V) + (2 << ENTRYLO_C)
+#define PROM_MASK (PAGEMASK_64KB << PAGEMASK_PAGEMASK)
+#endif
+#ifdef PROM64
+#define PROM_LO1 (1 << ENTRYLO_G) // If odd page not used
+#define PROM_MASK (PAGEMASK_64KB << PAGEMASK_PAGEMASK)
+#endif
+#define TLB_TEST_LO ((1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \
+ (1 << ENTRYLO_D) + (2 << ENTRYLO_C) + TLB_TEST_PHYS)
+
+#define TLB_TEST_HI TLB_TEST_VIRT
+
+#define TLB_KSEG_PHYS 0x0
+#define TLB_KSEG_LO ((1 << ENTRYLO_G) + (1 << ENTRYLO_V) + \
+ (1 << ENTRYLO_D) + (3 << ENTRYLO_C) + TLB_KSEG_PHYS)
+#define TLB_KSEG_VIRT 0x10000000
+#define TLB_KSEG_HI TLB_KSEG_VIRT
+#define TLB_KSEG_MASK (PAGEMASK_64KB << PAGEMASK_PAGEMASK)
+#endif // R4000
+
+#ifdef R3000
+//
+// Entry LO - HI pairs
+//
+#define DIAGNOSTIC_PHYSICAL_BASE 0x8000F000
+
+#define LED_LO ((1 << ENTRYLO_G) | (1 << ENTRYLO_V) | \
+ (1 << ENTRYLO_N) | (1 << ENTRYLO_D) | \
+ DIAGNOSTIC_PHYSICAL_BASE)
+#define LED_HI DIAGNOSTIC_VIRTUAL_BASE
+
+#define TLB_TEST_LO ((1 << ENTRYLO_G) | (1 << ENTRYLO_V) | \
+ (1 << ENTRYLO_N) | (1 << ENTRYLO_D) | \
+ TLB_TEST_PHYS)
+#define TLB_TEST_HI TLB_TEST_VIRT
+
+#define ROM_LO ((1 << ENTRYLO_G) | (1 << ENTRYLO_V) | \
+ (1 << ENTRYLO_N) | \
+ PROM_PHYSICAL_BASE)
+#define ROM_HI PROM_VIRTUAL_BASE
+
+#define DEVICE_LO ((1 << ENTRYLO_G) | (1 << ENTRYLO_V) | \
+ (1 << ENTRYLO_N) | (1 << ENTRYLO_D) | \
+ DEVICE_PHYSICAL_BASE)
+#define DEVICE_HI DEVICE_VIRTUAL_BASE
+
+#define PROC_LO ((1 << ENTRYLO_G) | (1 << ENTRYLO_V) | \
+ (1 << ENTRYLO_N) | \
+ INTERRUPT_PHYSICAL_BASE)
+#define PROC_HI INTERRUPT_VIRTUAL_BASE
+
+#define VID_LO ((1 << ENTRYLO_G) | (1 << ENTRYLO_V) | \
+ (1 << ENTRYLO_N) | (1 << ENTRYLO_D) | \
+ VIDEO_CONTROL_PHYSICAL_BASE)
+#define VID_HI VIDEO_CONTROL_VIRTUAL_BASE
+
+#define VIDMEM_LO ((1 << ENTRYLO_G) | (1 << ENTRYLO_V) | \
+ (1 << ENTRYLO_N) | (1 << ENTRYLO_D) | \
+ VIDEO_MEMORY_PHYSICAL_BASE)
+#define VIDMEM_HI VIDEO_MEMORY_PHYSICAL_BASE
+
+
+#define CURSOR_LO ((1 << ENTRYLO_G) | (1 << ENTRYLO_V) | \
+ (1 << ENTRYLO_N) | (1 << ENTRYLO_D) | \
+ VIDEO_CURSOR_PHYSICAL_BASE)
+#define CURSOR_HI VIDEO_CURSOR_VIRTUAL_BASE
+
+#define RESV_LO ((1 << ENTRYLO_G) | (1 << ENTRYLO_N))
+#define RESV_HI RESV_VIRT
+
+#endif //R3000
+//
+// Trap handling definitions.
+//
+#define COMMON_EXCEPTION 0
+#define NMI_EXCEPTION 1
+#define CACHE_EXCEPTION 2
+
+
+//
+// Define offsets from Register Table.
+// Must match the definiton in monitor.h
+//
+#define zeroRegTable 0x0
+#define atRegTable 0x4
+#define v0RegTable 0x8
+#define v1RegTable 0xC
+#define a0RegTable 0x10
+#define a1RegTable 0x14
+#define a2RegTable 0x18
+#define a3RegTable 0x1C
+#define t0RegTable 0x20
+#define t1RegTable 0x24
+#define t2RegTable 0x28
+#define t3RegTable 0x2C
+#define t4RegTable 0x30
+#define t5RegTable 0x34
+#define t6RegTable 0x38
+#define t7RegTable 0x3C
+#define s0RegTable 0x40
+#define s1RegTable 0x44
+#define s2RegTable 0x48
+#define s3RegTable 0x4C
+#define s4RegTable 0x50
+#define s5RegTable 0x54
+#define s6RegTable 0x58
+#define s7RegTable 0x5C
+#define t8RegTable 0x60
+#define t9RegTable 0x64
+#define k0RegTable 0x68
+#define k1RegTable 0x6C
+#define gpRegTable 0x70
+#define spRegTable 0x74
+#define s8RegTable 0x78
+#define raRegTable 0x7C
+#define f0RegTable 0x80
+#define f1RegTable 0x84
+#define f2RegTable 0x88
+#define f3RegTable 0x8C
+#define f4RegTable 0x90
+#define f5RegTable 0x94
+#define f6RegTable 0x98
+#define f7RegTable 0x9C
+#define f8RegTable 0xA0
+#define f9RegTable 0xA4
+#define f10RegTable 0xA8
+#define f11RegTable 0xAC
+#define f12RegTable 0xB0
+#define f13RegTable 0xB4
+#define f14RegTable 0xB8
+#define f15RegTable 0xBC
+#define f16RegTable 0xC0
+#define f17RegTable 0xC4
+#define f18RegTable 0xC8
+#define f19RegTable 0xCC
+#define f20RegTable 0xD0
+#define f21RegTable 0xD4
+#define f22RegTable 0xD8
+#define f23RegTable 0xDC
+#define f24RegTable 0xE0
+#define f25RegTable 0xE4
+#define f26RegTable 0xE8
+#define f27RegTable 0xEC
+#define f28RegTable 0xF0
+#define f29RegTable 0xF4
+#define f30RegTable 0xF8
+#define f31RegTable 0xFC
+#define fsrRegTable 0x100
+#define indexRegTable 0x104
+#define randomRegTable 0x108
+#define entrylo0RegTable 0x10C
+#define entrylo1RegTable 0x110
+#define contextRegTable 0x114
+#define pagemaskRegTable 0x118
+#define wiredRegTable 0x11C
+#define badvaddrRegTable 0x120
+#define countRegTable 0x124
+#define entryhiRegTable 0x128
+#define compareRegTable 0x12C
+#define psrRegTable 0x130
+#define causeRegTable 0x134
+#define epcRegTable 0x138
+#define pridRegTable 0x13C
+#define configRegTable 0x140
+#define lladdrRegTable 0x144
+#define watchloRegTable 0x148
+#define watchhiRegTable 0x14C
+#define eccRegTable 0x150
+#define cacheerrorRegTable 0x154
+#define tagloRegTable 0x158
+#define taghiRegTable 0x15C
+#define errorepcRegTable 0x160
+#define RegisterTableSize 0x164
+
+//
+// Define Fw exception frame offsets.
+//
+
+#define FwFrameK1 0x4
+#define FwFrameRa 0x8
+#define FwFrameA0 0xC
+#define FwFrameA1 0x10
+#define FwFrameA2 0x14
+#define FwFrameA3 0x18
+#define FwFrameV0 0x1C
+#define FwFrameV1 0x20
+#define FwFrameT0 0x24
+#define FwFrameT1 0x28
+#define FwFrameT2 0x2C
+#define FwFrameT3 0x30
+#define FwFrameT4 0x34
+#define FwFrameT5 0x38
+#define FwFrameT6 0x3C
+#define FwFrameT7 0x40
+#define FwFrameT8 0x44
+#define FwFrameT9 0x48
+#define FwFrameAT 0x4C
+#define FwFrameSize 0x50
+
+#endif // _SELFMAP_
diff --git a/private/ntos/fw/mips/selftest.c b/private/ntos/fw/mips/selftest.c
new file mode 100644
index 000000000..900c0d26d
--- /dev/null
+++ b/private/ntos/fw/mips/selftest.c
@@ -0,0 +1,2519 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ selftest.c
+
+Abstract:
+
+ This module contains the routines that perform the selftest of
+ the IO devices.
+
+Author:
+
+ Lluis Abello (lluis) 03-Jan-1991
+
+Environment:
+
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#include "iodevice.h"
+#include "led.h"
+#include "selfmap.h"
+#include "selftest.h"
+#include "ioaccess.h"
+#include "fwstring.h"
+#include "stdio.h"
+
+
+typedef CACHEERR *PCACHEERR;
+
+#define SetCursorPosition(Row,Column) \
+ FwPrint("\x9B"#Row";"#Column"H")
+#define MoveCursorLeft(Spaces) \
+ FwPrint("\x9B"#Spaces"D")
+#define ClearScreen() FwPrint("\x9B""2J");
+
+PUCHAR TranslationTable = "0123456789ABCDEF";
+UCHAR StationAddress[6];
+BOOLEAN ProcessorBEnabled = FALSE;
+BOOLEAN ValidEthernetAddress; // True if station address is OK False Otherwise
+BOOLEAN ConfigurationBit; // read value from diagnostic register
+BOOLEAN LoopOnError; // read value from diagnostic register
+BOOLEAN IgnoreErrors; // read value from diagnostic register
+volatile LONG TimerTicks; // Counter for timeouts
+BOOLEAN KeyboardInitialized; // True if the keyboard is initialized
+BOOLEAN MctadrRev2; // True if this is a rev2 ASIC
+
+PRTL_ALLOCATE_STRING_ROUTINE RtlAllocateStringRoutine =
+ (PRTL_ALLOCATE_STRING_ROUTINE)FwAllocatePool;
+PRTL_FREE_STRING_ROUTINE RtlFreeStringRoutine = FwpFreeStub;
+
+
+#ifndef DUO
+//
+// Table of memory size for each valid configuration.
+//
+UCHAR ConfigurationSize[64]=
+ { 0, 0, 0, 0, 4, 16, 0, 0,
+ 0, 0, 0, 0, 8, 20, 20, 32,
+ 0, 0, 0, 0, 8, 32, 0, 0,
+ 0, 0, 0, 0, 12, 36, 24, 48,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 16, 40, 40, 64
+ };
+
+USHORT FConfigurationSize[256]=
+// 0 1 2 3 4 5 6 7 8 9 A B C D E F
+ { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0
+ 4, 16, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 1
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 2
+ 8, 20, 68, 0, 0, 32, 80, 0, 0, 0,128, 0, 0, 0, 0, 0, // 3
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 4
+ 8, 32,128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 5
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 6
+ 12, 36,132, 0, 0, 48,144, 0, 0, 0,192, 0, 0, 0, 0, 0, // 7
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 8
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 9
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // A
+ 0, 24, 72, 0, 0, 0, 96, 0, 0, 0, 0, 0, 0, 0, 0, 0, // B
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // C
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // D
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // E
+ 16, 40,136, 0, 0, 64,160, 0, 0, 0,256, 0, 0, 0, 0, 0 // F
+ };
+#else
+//
+// This table indexed with the low 4 bits of the MemoryGroup config register,
+// returns the size of memory installed in the group in Megabytes.
+//
+UCHAR GroupSize[16]=
+ { 0, 0, 0, 0, // No SIMM installes
+ 4, 16, 64, 0, // Single Sided
+ 0, 0, 0, 0, // Reserved
+ 8, 32,128, 0 // Double Sided.
+ };
+#endif
+//
+// This variable is initialized to the size of the memory in Megabytes
+//
+
+ULONG MemorySize;
+
+ULONG KSEG_BASE[3]={KSEG1_BASE,KSEG0_BASE,KSEG0_BASE};
+ULONG XOR_KSEG_WRITE[3]={0x00000000,0xFFFFFFFF,0x01010101};
+ULONG XOR_KSEG_READ[3]={0x00000000,0xFFFFFFFF,0x01010101};
+
+
+//
+// Declare function prototypes.
+//
+VOID
+ReportJazzCacheErrorException(
+ IN ULONG CacheErr
+ );
+
+VOID
+ReportDuoCacheErrorException(
+ IN ULONG CacheErr
+ );
+
+VOID
+LoadDoubleWord(
+ IN ULONG Address,
+ OUT PVOID Result
+ );
+
+VOID
+InitializePCR(
+ );
+
+VOID
+FwBootSystem(
+ IN VOID
+ );
+
+ VOID
+RomSelftest(
+ IN VOID
+ );
+
+ARC_STATUS
+SerialBootWrite(
+ CHAR Char,
+ ULONG SP
+ );
+
+BOOLEAN
+ValidNvram(
+ OUT PUCHAR StationAddress
+ );
+
+VOID
+WriteMemoryAddressTest(
+ ULONG StartAddress,
+ ULONG Size,
+ ULONG Xorpattern
+ );
+
+PULONG
+CheckMemoryAddressTest(
+ ULONG StartAddress,
+ ULONG Size,
+ ULONG Xorpattern,
+ ULONG LedDisplayValue
+ );
+VOID
+WriteVideoMemoryAddressTest(
+ ULONG StartAddress,
+ ULONG Size
+ );
+ULONG
+CheckVideoMemoryAddressTest(
+ ULONG StartAddress,
+ ULONG Size
+ );
+
+VOID
+SetSmallDCacheBlock(
+ IN VOID
+ );
+
+VOID
+WildZeroMemory(
+ ULONG StartAddress,
+ ULONG Size
+ );
+
+VOID
+SerialBootSetup(
+ IN ULONG FileId
+ );
+VOID
+FwSelftest(
+ IN ULONG Cause,
+ IN ULONG Arg1
+ );
+
+
+VOID
+FwSelftest(
+ IN ULONG Cause,
+ IN ULONG Arg1
+ )
+/*++
+
+Routine Description:
+
+ This routine is the c routine called from the ROM. It must be placed
+ at the beginning of the C code because the ROM copies the code from this
+ point to the end and then jumps to it.
+
+Arguments:
+
+ Cause - 0 on a normal reset/powerup
+ 1 on a softreset.
+ 2 if an NMI occurred.
+ 3 if a cache error/parity occurred.
+
+ Arg1 - Error EPC if an NMI occurred
+ CacheErr register if a cache error occurred
+
+Return Value:
+
+ Never returns.
+
+--*/
+{
+ ULONG IntSrc;
+#ifdef DUO
+ ULONG Config;
+ ULONG MemConfig;
+ LONG Group;
+ CHAR Diag;
+#endif
+ CHAR String[128];
+ ULONG ProcessorBootStatus;
+
+
+#ifndef DUO
+ //
+ // Initialize MemorySize to the size of memory in MegaBytes. Look for the
+ // MCT_ADR REV2 Map Prom bit in the configuration register, if there this
+ // is a REV2, otherwise REV1.
+ //
+
+ if (DMA_CONTROL->Configuration.Long & 0x400) {
+ MemorySize = FConfigurationSize[DMA_CONTROL->Configuration.Long & 0xFF];
+ MctadrRev2 = TRUE;
+ } else {
+ MemorySize = ConfigurationSize[DMA_CONTROL->Configuration.Long & 0x3F];
+ MctadrRev2 = FALSE;
+ }
+
+#else
+ if (READ_REGISTER_ULONG(&DMA_CONTROL->WhoAmI.Long)) {
+ if (Cause == 2) {
+ //
+ // NMI
+ //
+ sprintf(String,
+ ST_NMI_MSG,
+ Arg1
+ );
+ FwPrint(ST_PROCESSOR_B_MSG);
+ FwPrint(String);
+ FwPrint(FW_SYSTEM_HALT_MSG);
+ for (;;) {
+ }
+ } else if (Cause == 3) {
+ //
+ // Cache error
+ //
+ } else {
+ //
+ // soft or cold reset.
+ //
+ ProcessorBMain();
+ }
+ }
+
+ MemorySize = 0;
+
+ for(Group=0;Group < 4; Group++) {
+ MemConfig = DMA_CONTROL->MemoryConfig[Group].Long;
+ MemorySize += GroupSize[MemConfig&0xF]; // plus size of group.
+ }
+
+#endif
+
+ //
+ // Set variables according to the bits in configuration register
+ //
+
+ ConfigurationBit = FALSE;
+ IgnoreErrors = FALSE;
+ LoopOnError = FALSE;
+ DisplayOutput = FALSE;
+ SerialOutput = FALSE;
+ KeyboardInitialized = FALSE;
+
+ //
+ // Look for configuration register.
+ //
+#ifdef DUO
+ Diag=READ_REGISTER_UCHAR(DIAGNOSTIC_VIRTUAL_BASE);
+ if ((Diag & LOOP_ON_ERROR_MASK) == 0) {
+ LoopOnError = TRUE;
+ }
+ if ((Diag & CONFIGURATION_MASK) == 0) {
+ ConfigurationBit = TRUE;
+ }
+ if ((Diag & IGNORE_ERRORS_MASK) == 0) {
+ IgnoreErrors = TRUE;
+ }
+#endif
+
+
+// Diag=READ_REGISTER_UCHAR(DIAGNOSTIC_VIRTUAL_BASE) & DIAGNOSTIC_MASK;
+// switch (Diag) {
+// case 0: IgnoreErrors = TRUE;
+// break;
+// case (1<<7): LoopOnError = TRUE;
+// break;
+// case (1<<6): ConfigurationBit = TRUE;
+// break;
+// }
+
+ //
+ // Set interrupt lines to a known state.
+ //
+
+ WRITE_REGISTER_UCHAR(&SP1_WRITE->ModemControl,0x08);
+ WRITE_REGISTER_UCHAR(&SP2_WRITE->ModemControl,0x08);
+#ifndef DUO
+ WRITE_REGISTER_UCHAR(&FLOPPY_WRITE->DigitalOutput,0x08);
+#endif
+ READ_REGISTER_UCHAR(&PARALLEL_READ->Status);
+
+ //
+ // Initialize the system parameter block.
+ //
+
+ SYSTEM_BLOCK->Signature = 0x53435241;
+ SYSTEM_BLOCK->Length = sizeof(SYSTEM_PARAMETER_BLOCK);
+ SYSTEM_BLOCK->Version = ARC_VERSION;
+ SYSTEM_BLOCK->Revision = ARC_REVISION;
+
+ //
+ // Allocate the restart block.
+ //
+
+ SYSTEM_BLOCK->RestartBlock = (PRESTART_BLOCK)((ULONG)((PUCHAR)SYSTEM_BLOCK + sizeof(SYSTEM_PARAMETER_BLOCK)) | KSEG1_BASE);
+
+ SYSTEM_BLOCK->DebugBlock = NULL;
+#ifdef DUO
+ //
+ // Link the second restart block for processor B.
+ //
+ SYSTEM_BLOCK->RestartBlock->NextRestartBlock = (PRESTART_BLOCK)(((ULONG)SYSTEM_BLOCK + sizeof(SYSTEM_PARAMETER_BLOCK) + sizeof(RESTART_BLOCK)) | KSEG1_BASE);
+
+ SYSTEM_BLOCK->RestartBlock->NextRestartBlock->NextRestartBlock = NULL;
+ SYSTEM_BLOCK->FirmwareVector = (PVOID)((ULONG)((PUCHAR)SYSTEM_BLOCK + sizeof(SYSTEM_PARAMETER_BLOCK) + 2*sizeof(RESTART_BLOCK)) | KSEG1_BASE);
+#else
+ SYSTEM_BLOCK->RestartBlock->NextRestartBlock = NULL;
+ SYSTEM_BLOCK->FirmwareVector =
+ (PVOID)((PUCHAR)SYSTEM_BLOCK + sizeof(SYSTEM_PARAMETER_BLOCK) + sizeof(RESTART_BLOCK));
+#endif
+
+
+ SYSTEM_BLOCK->FirmwareVectorLength = (ULONG)MaximumRoutine * sizeof(ULONG);
+ SYSTEM_BLOCK->VendorVectorLength = (ULONG)MaximumVendorRoutine * sizeof(ULONG);
+ SYSTEM_BLOCK->VendorVector =
+ (PVOID)(SYSTEM_BLOCK->FirmwareVector +
+ SYSTEM_BLOCK->FirmwareVectorLength);
+
+ //
+ // If the configuration bit is set, go to the serial port.
+ //
+
+ PutLedDisplay(LED_NVRAM);
+ if (ConfigurationBit) {
+ //
+ // Test the serial port if not a soft reset.
+ //
+ if (Cause == 0) {
+ ExecuteTest((TestRoutine)RomSerialResetTest,LED_SERIAL_RESET);
+ ExecuteTest((TestRoutine)RomSerial1RegistersTest,LED_SERIAL1_REG);
+ ExecuteTest((TestRoutine)RomSerial2RegistersTest,LED_SERIAL2_REG);
+ ExecuteTest((TestRoutine)RomSerial1LoopBackTest,LED_SERIAL1_LBACK);
+ ExecuteTest((TestRoutine)RomSerial2LoopBackTest,LED_SERIAL2_LBACK);
+ PutLedDisplay(LED_SERIAL_INIT);
+ }
+ //
+ // Initialize the serial port as there is no configuration
+ // data to initialize the video.
+ //
+ SerialBootSetup(COMPORT2_VIRTUAL_BASE);
+ SerialOutput = TRUE;
+ ClearScreen()
+
+ } else {
+
+ //
+ // If there is a valid Ethernet station address, protect it.
+ //
+
+ if (ValidNvram(StationAddress) == TRUE) {
+// WRITE_REGISTER_ULONG (&DMA_CONTROL->SystemSecurity.Long,READ_ONLY_DISABLE_WRITE);
+ }
+
+ //
+ // Test the video memory.
+ // Doesn't work for VXL
+ //
+ if (Cause == 0) {
+// ExecuteTest((TestRoutine)RomVideoMemory,LED_VIDEOMEM);
+ PutLedDisplay(LED_VIDEO_CONTROLLER);
+ }
+
+//TEMPTEMP
+// if (DisplayBootInitialize() != ESUCCESS) {
+// //
+// // If video is broken and the NVRAM was ok and the config
+// // bit was not set do not attempt to write to the serial port.
+// // No output device is available, so hang.
+// //
+// PutLedDisplay((LED_BLINK << 16) | LED_VIDEO_CONTROLLER);
+// } else {
+// //
+// // Video is ready to display messages.
+// //
+// DisplayOutput=TRUE;
+// }
+//TEMPTEMP
+
+ DisplayBootInitialize();
+ DisplayOutput=TRUE;
+ }
+ if (Cause == 2) {
+ //
+ // This is an NMI. Display a message and hang.
+ //
+ sprintf(String,
+ ST_NMI_MSG,
+ Arg1
+ );
+ FwPrint(String);
+ //
+ // Read The Interrupt source register and check the cause of the NMI.
+ //
+#ifndef DUO
+ IntSrc = READ_REGISTER_ULONG(&DMA_CONTROL->InterruptSource.Long);
+ if (IntSrc & (1<<9)) {
+ sprintf(String,
+ ST_INVALID_ADDRESS_MSG,
+ READ_REGISTER_ULONG(&DMA_CONTROL->InvalidAddress.Long)
+ );
+ FwPrint(String);
+ }
+ if (IntSrc & (1<<10)) {
+ sprintf(String,
+ ST_IO_CACHE_ADDRESS_MSG,
+ READ_REGISTER_ULONG(&DMA_CONTROL->MemoryFailedAddress.Long)
+ );
+ FwPrint(String);
+ }
+ FwPrint(FW_SYSTEM_HALT_MSG);
+#else
+ IntSrc = READ_REGISTER_ULONG(&DMA_CONTROL->NmiSource.Long);
+ if (IntSrc & (1<<1)) {
+ sprintf(String,
+ ST_INVALID_ADDRESS_MSG,
+ READ_REGISTER_ULONG(&DMA_CONTROL->InvalidAddress.Long)
+ );
+ FwPrint(String);
+ }
+ if (IntSrc & (1<<2)) {
+ sprintf(String,
+ ST_IO_CACHE_ADDRESS_MSG,
+ READ_REGISTER_ULONG(&DMA_CONTROL->MemoryFailedAddress.Long)
+ );
+ FwPrint(String);
+ }
+
+ //
+ // Notify processor B
+ //
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IpInterruptRequest.Long,2);
+
+#endif
+
+ //
+ // Hang blinking LED.
+ //
+ PutLedDisplay((LED_BLINK << 16) | LED_NMI);
+ }
+ if (Cause == 3) {
+#ifndef DUO
+ ReportJazzCacheErrorException(Arg1);
+#else
+ ReportDuoCacheErrorException(Arg1);
+#endif
+ PutLedDisplay((LED_BLINK << 16) | LED_PARITY);
+ }
+ //
+ // Reset the EISA bus. This is required because the EBC reset line on Jazz
+ // is connected wrong.
+ //
+
+ WRITE_REGISTER_UCHAR(&EISA_CONTROL->ExtendedNmiResetControl,0x01);
+ FwStallExecution(10);
+ WRITE_REGISTER_UCHAR(&EISA_CONTROL->ExtendedNmiResetControl,0x00);
+ FwStallExecution(10);
+
+ if (Cause == 0) {
+ //
+ // Execute selftest if it's not a soft reset.
+ //
+
+ FwPrintVersion();
+ FwPrint(FW_CRLF_MSG);
+ RomSelftest();
+ } else {
+ //
+ // Need to initialize whatever the Selftest initializes.
+ //
+ PutLedDisplay(LED_KEYBOARD_CTRL);
+ if (InitKeyboardController()) {
+ FwPrint(ST_KEYBOARD_ERROR_MSG);
+ }
+ PutLedDisplay(LED_ISP);
+ RomInitISP();
+ }
+
+ //
+ // Initialize master processor boot status.
+ //
+ ProcessorBootStatus = 0;
+ ((PBOOT_STATUS)&ProcessorBootStatus)->ProcessorReady = 1;
+ ((PBOOT_STATUS)&ProcessorBootStatus)->ProcessorRunning = 1;
+ ((PBOOT_STATUS)&ProcessorBootStatus)->ProcessorStart = 1;
+ ((PBOOT_STATUS)&ProcessorBootStatus)->BootStarted = 1;
+ SYSTEM_BLOCK->RestartBlock->BootStatus = *((PBOOT_STATUS)&ProcessorBootStatus);
+
+ //
+ // Zero the entire Memory.
+ //
+ PutLedDisplay(LED_ZEROMEM);
+
+// WildZeroMemory(FW_TOP_ADDRESS,MEMORY_SIZE - FW_TOP_ADDRESS);
+ RtlZeroMemory((PVOID)(FW_TOP_ADDRESS | KSEG0_BASE),MEMORY_SIZE - FW_TOP_ADDRESS);
+
+#ifdef DUO
+
+ //
+ // Initialize processor B boot status to not ready.
+ //
+ ProcessorBootStatus = 0;
+
+ //
+ // Processor B Has been idle all this time. Check if it is present
+ // and enable it.
+ //
+
+
+ Diag=READ_REGISTER_UCHAR(DIAGNOSTIC_VIRTUAL_BASE);
+
+
+ if (!(Diag & 1)) {
+ InitializePCR();
+ FwPrint(ST_ENABLE_PROCESSOR_B_MSG);
+
+// HalSweepDcache();
+ //
+ // TEMPTEMP we want to see all icache misses for now
+ //
+// HalSweepIcache();
+
+ //
+ // end TEMPTEMP
+ //
+
+ Config = READ_REGISTER_ULONG(&DMA_CONTROL->Configuration.Long);
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->Configuration.Long,Config | ENABLE_PROCESSOR_B);
+
+ //
+ // Processor B has been enabled. It will execute the rom code to initialize
+ // its caches and then call ProcessorBMain from where it will issue
+ // an Ip interrupt to us.
+ //
+ if (WaitForIpInterrupt(5000) == FALSE) {
+ FwPrint(ST_TIMEOUT_PROCESSOR_B_MSG);
+ } else {
+ FwPrint(FW_OK_MSG);
+
+ //
+ // If Processor B passes selftest, set processor ready bit in boot status.
+ // Otherwise disable processor B
+ //
+ if (ProcessorBSelftest()) {
+ ((PBOOT_STATUS)&ProcessorBootStatus)->ProcessorReady = 1;
+ ProcessorBEnabled = TRUE;
+ }
+ }
+ //
+ // If processor B failed selftest or never received its IP interrupt
+ // Disable It.
+ //
+ if (!ProcessorBEnabled) {
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->Configuration.Long,Config);
+ FwPrint(ST_PROCESSOR_B_DISABLED_MSG);
+ }
+ } else {
+ FwPrint(ST_PROCESSOR_B_NOT_PRESENT_MSG);
+ }
+
+ SYSTEM_BLOCK->RestartBlock->NextRestartBlock->BootStatus = *((PBOOT_STATUS)&ProcessorBootStatus);
+
+
+ //
+ // Disable all interrupts except IP and Local Device (for keyboard)
+ //
+
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->InterruptEnable.Long,
+ (ENABLE_IP_INTERRUPTS | ENABLE_DEVICE_INTERRUPTS));
+
+#endif
+
+ InitializePCR();
+ PutLedDisplay(LED_BLANK<<4);
+ FwBootSystem();
+
+ //
+ // Hang if we come back.
+ //
+
+ PutLedDisplay((LED_BLINK << 16) | 0xBB);
+}
+
+
+VOID
+RomSelftest (
+ IN VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine implements the self-test video phase.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ULONG Status;
+ULONG i,j,Test,CurrentK;
+LONG BlockSize;
+CHAR String[128];
+ULONG SIZE_OF_UNTESTED_MEMORY = MEMORY_SIZE-(FW_TOP_ADDRESS);
+
+//TEMPTEMP
+PULONG Cached;
+
+ PutLedDisplay(LED_MAIN_MEMORY);
+
+ //
+ // Display in the screen that the memory is being tested.
+ //
+
+ SetCursorPosition(4,1);
+// sprintf(String,"Total memory is %d MBytes (%x)\r\n",MemorySize,DMA_CONTROL->Configuration.Long);
+// FwPrint(String);
+ FwPrint(ST_MEMORY_TEST_MSG);
+
+ //
+ // Zero the memory so that memtest can run cached.
+ //
+ //WildZeroMemory(FW_TOP_ADDRESS,SIZE_OF_UNTESTED_MEMORY);
+
+ for (Test=0;Test<1;Test++) { // 3!!
+ //
+ // display on the screen and LED that we start writing.
+ //
+// SetCursorPosition(1,14);
+// sprintf(String,"%x",Test+1);
+// FwPrint(String);
+ PutLedDisplay(LED_MAIN_MEMORY+Test+1);
+ //
+ // Write address test to the remaining untested memory
+ //
+ WriteMemoryAddressTest(KSEG0_BASE+FW_TOP_ADDRESS,
+ SIZE_OF_UNTESTED_MEMORY,
+ XOR_KSEG_WRITE[Test]);
+
+ //
+ // Adjust first block size to align the tested memory to a block boundary
+ //
+
+ BlockSize = KB_PER_TEST - TESTED_KB;
+ while (BlockSize <= 0) {
+ BlockSize += KB_PER_TEST;
+ }
+ CurrentK = TESTED_KB;
+ do {
+
+ //
+ // Display what has been tested so far.
+ //
+
+ SetCursorPosition(4,15);
+ sprintf(String,"%6d",CurrentK);
+ FwPrint(String);
+ Cached = CheckMemoryAddressTest(
+ KSEG0_BASE + (CurrentK << 10), // cached address
+ BlockSize << 10, // test up to next block boundary
+ XOR_KSEG_READ[Test], // Xor Pattern
+ (LED_BLINK << 16) + LED_MAIN_MEMORY);
+ if (Cached != 0) {
+
+ //
+ // Memory Error found.
+ //
+
+ FwPrint(ST_MEMORY_ERROR_MSG);
+
+ if (LoopOnError) {
+ // display in the LED that we start looping.
+ PutLedDisplay((LED_LOOP_ERROR << 16)+LED_MAIN_MEMORY);
+ for (;;) {
+ CheckMemoryAddressTest(
+ KSEG0_BASE + (CurrentK << 10), // cached address
+ BlockSize << 10, // test up to next block boundary
+ XOR_KSEG_READ[Test], // Xor Pattern
+ (LED_BLINK << 16) + LED_MAIN_MEMORY);
+ }
+ } else {
+ FwPrint(ST_HANG_MSG);
+ // hang blinking the LED
+ PutLedDisplay((LED_BLINK << 16) + LED_MAIN_MEMORY + Test + 1);
+ }
+
+ }
+ CurrentK += BlockSize;
+ BlockSize = KB_PER_TEST;
+ } while (CurrentK < KB_OF_MEMORY);
+
+ //
+ // display the final amount of tested memory.
+ //
+
+ SetCursorPosition(4,15);
+ sprintf(String,"%6d",CurrentK);
+ FwPrint(String);
+ }
+
+// TEMPTEMP This test won't work on a secondary cache machine, fix.
+// ExecuteTest((TestRoutine)RomReadMergeWrite,LED_READ_MERGE_WRITE);
+
+ //
+ // Test the rest of devices in the board.
+ //
+
+ FwPrint(ST_TEST_MSG);
+ FwPrint(ST_MEMORY_CONTROLLER_MSG);
+ if (ExecuteTest((TestRoutine)RomIOCacheTest,LED_IO_CACHE)) {
+ return;
+ }
+
+ //
+ // Enable interrupts and initialize dispatch table.
+ //
+
+ FwPrint(ST_TEST_MSG);
+ FwPrint(ST_INTERRUPT_CONTROLLER_MSG);
+ ConnectInterrupts();
+ if (ExecuteTest((TestRoutine)InterruptControllerTest,LED_INTERRUPT)) {
+ return;
+ }
+ FwPrint(ST_TEST_MSG);
+ FwPrint(ST_KEYBOARD_CONTROLLER_MSG);
+ if (ExecuteTest((TestRoutine)InitKeyboardController,LED_KEYBOARD_CTRL)) {
+ return;
+ }
+ KeyboardInitialized=TRUE;
+ MoveCursorLeft(3);
+ FwPrint(" ");
+ MoveCursorLeft(3);
+ PutLedDisplay(LED_KEYBOARD_INIT);
+ if (Status=InitKeyboard()) {
+ FwPrint(ST_ERROR_MSG);
+ if (Status == TIME_OUT) {
+ FwPrint(ST_KEYBOARD_NOT_PRESENT_MSG);
+ }
+ if (LoopOnError) {
+ PutLedDisplay((LED_LOOP_ERROR << 16) | LED_KEYBOARD_INIT);
+ for (;;) {
+ InitKeyboard();
+ }
+ } else {
+ if (IgnoreErrors) {
+ return;
+ } else {
+ FwPrint(ST_HANG_MSG);
+ PutLedDisplay((LED_BLINK << 16) | LED_KEYBOARD_INIT); // does not return.
+ }
+ }
+ } else {
+ FwPrint(FW_OK_MSG);
+ }
+
+ //
+ // Test the serial port if it's not being used as the output device.
+ //
+
+ if (SerialOutput == FALSE) {
+ FwPrint(ST_TEST_MSG);
+ FwPrint(ST_SERIAL_LINE_MSG);
+ if (ExecuteTest((TestRoutine)RomSerialResetTest,LED_SERIAL_RESET)) {
+ return;
+ }
+ if (ExecuteTest((TestRoutine)RomSerial1RegistersTest,LED_SERIAL1_REG)) {
+ return;
+ }
+ if (ExecuteTest((TestRoutine)RomSerial2RegistersTest,LED_SERIAL2_REG)) {
+ return;
+ }
+ if (ExecuteTest((TestRoutine)RomSerial1LoopBackTest,LED_SERIAL1_LBACK)) {
+ return;
+ }
+ if (ExecuteTest((TestRoutine)RomSerial2LoopBackTest,LED_SERIAL2_LBACK)) {
+ return;
+ }
+ }
+ FwPrint(ST_TEST_MSG);
+ FwPrint(ST_PARALLEL_PORT_MSG);
+ if (ExecuteTest((TestRoutine)RomParallelRegistersTest,LED_PARALLEL_REG)) {
+ return;
+ }
+#ifndef DUO
+ FwPrint(ST_TEST_MSG);
+ FwPrint(ST_FLOPPY_MSG);
+ if (ExecuteTest((TestRoutine)RomFloppyResetTest,LED_FLOPPY_RESET)) {
+ return;
+ }
+ if (ExecuteTest((TestRoutine)RomFloppyRegistersTest,LED_FLOPPY_REG)) {
+ return;
+ }
+#endif
+ FwPrint(ST_TEST_MSG);
+ FwPrint(ST_SCSI_MSG);
+ if (ExecuteTest((TestRoutine)RomScsiResetTest,LED_SCSI_RESET)) {
+ return;
+ }
+ if (ExecuteTest((TestRoutine)RomScsiRegistersTest,LED_SCSI_REG)) {
+ return;
+ }
+ FwPrint(ST_TEST_MSG);
+ FwPrint(ST_ETHERNET_MSG);
+ if (ExecuteTest((TestRoutine)RomSonicResetTest,LED_SONIC_RESET)) {
+ return;
+ }
+ if (ExecuteTest((TestRoutine)RomSonicRegistersTest,LED_SONIC_REG)) {
+ return;
+ }
+
+ //
+ // Do a loopback test if a valid address was found in the NVRAM.
+ //
+
+ if (ValidEthernetAddress) {
+ FwPrint(ST_ETHERNET_ADDRESS_MSG);
+ j=0;
+ for (i=0;i<6;i++) {
+ String[j++]=TranslationTable[StationAddress[i]>>4];
+ String[j++]=TranslationTable[StationAddress[i]&0xF];
+ }
+ String[j]='\0';
+ FwPrint(String);
+ FwPrint(ST_ETHERNET_LOOPBACK_MSG);
+ if (ExecuteTest((TestRoutine)RomSonicLoopBackTest,LED_SONIC_LOOPBACK)) {
+ return;
+ }
+ }
+
+// RomSoundTest();
+
+ //
+ // Invalidate DMA translation table
+ //
+
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->TranslationInvalidate.Long,0);
+
+ FwPrint(ST_TEST_MSG);
+ FwPrint(ST_ISP_MSG);
+ if (ExecuteTest((TestRoutine)RomInitISP,LED_ISP)) {
+ return;
+ }
+ FwPrint(ST_TEST_MSG);
+ FwPrint(ST_RTC_MSG);
+ if (ExecuteTest((TestRoutine)RomRTCTest,LED_RTC)) {
+ return;
+ }
+
+ FwPrint(FW_CRLF_MSG);
+ //
+ // Disable Interrupts so that the firmware can be initialized
+ //
+
+ DisableInterrupts();
+}
+
+BOOLEAN
+ExecuteTest(
+ IN TestRoutine Test,
+ IN ULONG LedVal
+ )
+/*++
+
+Routine Description:
+
+ This routine executes the specified test. If the test fails and
+the loop-on-error bit is set it sets the dot in the LED and reexecutes
+the test for ever. If the loop-on-error bit is not set it will display
+an error message and hang blinking the test and subtest number in the LED.
+
+Arguments:
+
+ Test - Supplies a pointer to the rutine to execute.
+ LedVal - Subtest identifier to be displayed in the LED in case of error.
+
+Return Value:
+
+ if the test passes returns FALSE.
+ if the test fails:
+ if Normal Mode and not KeyboardInitialized blinks test and subtest number in LED and hangs.
+ if Normal Mode and KeyboardInitialized, prompts for keypress and then returns TRUE.
+ if LoopOnError mode reexecutes the test indefinitly and hangs.
+ if IgnoreErrors mode returns TRUE.
+
+--*/
+{
+ PutLedDisplay(LedVal);
+ if (Test()) {
+
+ //
+ // The test failed.
+ //
+
+ FwPrint(ST_ERROR_MSG);
+ if (LoopOnError) {
+ PutLedDisplay((LED_LOOP_ERROR << 16) | LedVal);
+ for (;;) {
+ Test();
+ }
+ } else {
+ if (IgnoreErrors) {
+ //
+ // Invalidate TT and disable interrupts.
+ //
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->TranslationInvalidate.Long,0);
+ DisableInterrupts();
+ return TRUE;
+ } else {
+ FwPrint(ST_HANG_MSG);
+ }
+ }
+ } else {
+
+ //
+ // display ...OK. and move the cursor left 3 chars
+ // so that if an error follows it overwrites OK.
+ //
+
+ FwPrint(FW_OK_MSG);
+ FwPrint("\x9B""3D");
+ return FALSE;
+ }
+}
+ VOID
+RomPutLine(
+ IN PCHAR String
+ )
+/*++
+
+Routine Description:
+
+ This routine displays the string in the video monitor or sends
+ it to a terminal trough the serial port during selftest.
+
+Arguments:
+
+ String - String to display
+
+Return Value:
+
+ None.
+
+--*/
+{
+ULONG Count;
+ if (DisplayOutput) {
+
+ //
+ // Display message on the video.
+ //
+
+ DisplayWrite(0,String,strlen(String),&Count);
+ }
+ if (SerialOutput) {
+
+ //
+ // Display message on serial Line.
+ //
+
+ while (*String) {
+ SerialBootWrite(*String,COMPORT2_VIRTUAL_BASE);
+ String++;
+ }
+ }
+}
+
+ULONG
+RomSerialRegistersTest(
+ IN ULONG SP_BASE
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the Serial port 2 registers can be writen and
+ read.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of errors found.
+
+--*/
+{
+ ULONG Errors=0;
+
+ //
+ // Test registers
+ //
+
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->LineControl,0xA5); // sets DLAB
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->TransmitBuffer,0xC); // write DL (lsb) for 9600
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->InterruptEnable,0x0); // write DL (msb) for 9600
+ CHECK_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->ReceiveBuffer,0xC) // check DL (lsb)
+ CHECK_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->InterruptEnable,0x0) // check DL (msb)
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->LineControl,0x3); // Clears DLAB & sets8 bit no parity 1 stop bit
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->InterruptEnable,0x0); // disable interrupts
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->FifoControl,0x0); // disable fifo
+ CHECK_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->InterruptEnable,0x0) // check Int enable
+ CHECK_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->LineControl,0x3)
+ return Errors;
+}
+
+ULONG
+RomSerialLoopBackTest(
+ IN ULONG SP_BASE
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the Serial port is operational.
+ It performs an internal loopback of the ACE.
+
+Arguments:
+
+ SP_BASE - Supplies the virtual address of the serial port.
+
+Return Value:
+
+ Number of Errors found.
+
+--*/
+{
+ ULONG Errors=0;
+ ULONG i;
+
+ //
+ // Set loopback mode.
+ //
+
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->ModemControl,0x18);
+ READ_REGISTER_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->LineStatus); // Clear status
+ READ_REGISTER_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->ReceiveBuffer); // Clear Data
+ for (i=0;i<256;i++) {
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->TransmitBuffer,(UCHAR)i); // write to port
+ TimerTicks=3;
+ while (((READ_REGISTER_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->LineStatus) & 1) == 0) && TimerTicks) {
+ }
+ if (TimerTicks) {
+ CHECK_UCHAR(&((PSP_READ_REGISTERS)SP_BASE)->ReceiveBuffer,(UCHAR)i) // read and check
+ } else {
+ Errors++; // Timeout
+ }
+ }
+
+ //
+ // clear loopback mode and enable Interrupt line so it's not floating
+ //
+
+ WRITE_REGISTER_UCHAR(&((PSP_WRITE_REGISTERS)SP_BASE)->ModemControl,0x08);
+ return Errors;
+}
+
+ULONG
+RomSerialResetTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the Serial port has been properly reset.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of errors found.
+
+--*/
+{
+ ULONG Errors=0;
+
+ //
+ // Check that was properly reset by checking the reset values.
+ //
+
+ CHECK_UCHAR(&SP1_READ->InterruptEnable, 0)
+ CHECK_UCHAR(&SP1_READ->InterruptId, 1)
+ CHECK_UCHAR(&SP1_READ->LineControl, 0)
+ CHECK_UCHAR(&SP1_READ->ModemControl, 0x8)
+
+ //
+ // Do the same with COM2
+ //
+
+ CHECK_UCHAR(&SP2_READ->InterruptEnable, 0)
+ CHECK_UCHAR(&SP2_READ->InterruptId, 1)
+ CHECK_UCHAR(&SP2_READ->LineControl, 0)
+ CHECK_UCHAR(&SP2_READ->ModemControl, 0x8)
+ return Errors;
+}
+
+ULONG
+RomSerial1RegistersTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the Serial port 1 registers can be writen and
+ read.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the number of errors found.
+
+--*/
+{
+ return RomSerialRegistersTest(COMPORT1_VIRTUAL_BASE);
+}
+
+ULONG
+RomSerial2RegistersTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the Serial port 1 registers can be writen and
+ read.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the number of errors found.
+
+--*/
+{
+ return RomSerialRegistersTest(COMPORT2_VIRTUAL_BASE);
+}
+
+ULONG
+RomSerial1LoopBackTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the Serial is operational.
+ It performs an internal loopback of the ACE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of Errors found.
+
+--*/
+{
+ return RomSerialLoopBackTest(COMPORT1_VIRTUAL_BASE);
+}
+
+ULONG
+RomSerial2LoopBackTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the Serial is operational.
+ It performs an internal loopback of the ACE.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of Errors found.
+
+--*/
+{
+ return RomSerialLoopBackTest(COMPORT2_VIRTUAL_BASE);
+}
+
+ULONG
+RomParallelRegistersTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the Parallel port registers can be writen and
+ read.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of errors found.
+
+--*/
+{
+ ULONG Errors=0;
+ UCHAR DataByte;
+
+ //
+ // Test registers. This only checks the static bits. Note: bit 2 of the
+ // status register and bit 5 of the control register are used in the second
+ // silicon.
+ //
+
+ DataByte = READ_REGISTER_UCHAR(&PARALLEL_READ->Status);
+ if ((DataByte & 0x1) != 0x1) {
+ Errors++;
+ }
+
+
+ DataByte = READ_REGISTER_UCHAR(&PARALLEL_READ->Control);
+ if ((DataByte & 0xC0) != 0xC0) {
+ Errors++;
+ }
+
+ return Errors;
+}
+
+#ifndef DUO
+ULONG
+RomScsiRegistersTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the NCR 53c94 SCSI controller registers can be writen and
+ read.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of errors found.
+
+--*/
+{
+ ULONG Errors=0;
+
+ //
+ // Test Registers
+ //
+
+ SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountLow,0xAA);
+ SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountHigh,0x55);
+ SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Command,0x80); // Issue a DMA NOP to load the counter
+ if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountLow) != 0xAA) { // check counter
+ Errors++;
+ }
+ if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountHigh) != 0x55) { // check counter
+ Errors++;
+ }
+ SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountLow,0x00);
+ SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountHigh,0x00);
+ SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Command,0x80); // Issue a DMA NOP to load the counter
+ if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountLow) != 0x00) { // check counter
+ Errors++;
+ }
+ if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,TransferCountHigh) != 0x00) { // check counter
+ Errors++;
+ }
+ SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Configuration1,0x57);
+ SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Configuration2,0x58);
+ if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Configuration1) != 0x57) { // check config1
+ Errors++;
+ }
+ if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Configuration2) != 0x58) { // check config2
+ Errors++;
+ }
+ SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Configuration1,0x00);
+ SCSI_WRITE((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Configuration2,0x00);
+ return Errors;
+}
+#else
+ULONG
+RomScsiRegistersTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the NCR C700 SCSI controller registers can be writen and
+ read.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of errors found.
+
+--*/
+{
+ ULONG Errors=0;
+ ULONG Entry;
+ UCHAR ByteLane;
+ UCHAR ScsiTestData[8] = {0x55,0xAA,0x11,0x22,0x44,0x88,0xFF,0x00};
+ UCHAR ScsiTestParity[8] = {0x8,0x0,0x8,0x8,0x0,0x0,0x8,0x0};
+ UCHAR Temp;
+ ULONG TempLong;
+ //
+ // Test SCSI 1 Registers
+ //
+
+ SCSI_WRITE_USHORT((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSP[0],0x5A0F); // write pattern to DSP pointer
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSPS[0],0xE1); // write pattern to DSPS0 pointer
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSPS[1],0xD2); // write pattern to DSPS0 pointer
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSPS[2],0xB4); // write pattern to DSPS0 pointer
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSPS[3],0x78); // write pattern to DSPS0 pointer
+ if ((Temp=SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSP[0])) != 0x0F) { // check low 4 register
+ FwPrint("\r\nRegister %s Expected %lx received %lx\r\n","DSP[0]",0xf,Temp);
+ return 1;
+ Errors++;
+ }
+ if ((Temp=SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSP[1])) != 0x5A) { // check low 4 register
+ FwPrint("\r\nRegister %s Expected %lx received %lx\r\n","DSP[1]",0x5A,Temp);
+ return 1;
+ Errors++;
+ }
+ if ((TempLong=SCSI_READ_ULONG((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,DSPS)) != 0x78B4D2E1) { // check low 4 register
+ FwPrint("\r\nRegister %s Expected %lx received %lx\r\n","DSPS",0x78B4D2E1,TempLong);
+ return 1;
+ Errors++;
+ }
+
+ //
+ // Test SCSI 2 Registers
+ //
+
+ SCSI_WRITE_USHORT((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSP[0],0x5A0F); // write pattern to DSP pointer
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSPS[0],0xE1); // write pattern to DSPS0 pointer
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSPS[1],0xD2); // write pattern to DSPS0 pointer
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSPS[2],0xB4); // write pattern to DSPS0 pointer
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSPS[3],0x78); // write pattern to DSPS0 pointer
+ if (SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSP[0]) != 0x0F) { // check low 4 register
+ FwPrint("Reg 22");
+ return 1;
+ Errors++;
+ }
+ if (SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSP[1]) != 0x5A) { // check low 4 register
+ FwPrint("Reg 33");
+ Errors++;
+ }
+ if (SCSI_READ_ULONG((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,DSPS) != 0x78B4D2E1) { // check low 4 register
+ FwPrint("Reg 44");
+ return 1;
+ Errors++;
+ }
+
+ //
+ // Test SCSI 1 DMA Fifo
+ //
+ for (ByteLane=0; ByteLane < 4; ByteLane++) {
+ //
+ // Select ByteLane
+ //
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST4,4+ByteLane);
+
+ //
+ // Write
+ //
+ for (Entry=0;Entry<8;Entry++) {
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST7,ScsiTestParity[Entry]);
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST6,ScsiTestData[Entry]);
+ }
+
+ //
+ // Read and check
+ //
+ for (Entry=0;Entry<8;Entry++) {
+ if ((Temp=SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST6)) != ScsiTestData[Entry]) {
+ FwPrint("Reg CTEST6 expected %lx received %lx\r\n", ScsiTestData[Entry], Temp);
+ return 1;
+ Errors++;
+ }
+ if (((Temp=SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST2))&0x8) != ScsiTestParity[Entry]) {
+ FwPrint("Reg CTEST2 expected %lx received %lx\r\n", ScsiTestParity[Entry], Temp);
+ return 1;
+ Errors++;
+ }
+ }
+ }
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST4,0);
+
+ //
+ // Test SCSI 2 DMA Fifo
+ //
+ for (ByteLane=0; ByteLane < 4; ByteLane++) {
+ //
+ // Select ByteLane
+ //
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST4,4+ByteLane);
+
+ //
+ // Write
+ //
+ for (Entry=0;Entry<8;Entry++) {
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST7,ScsiTestParity[Entry]);
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST6,ScsiTestData[Entry]);
+ }
+
+ //
+ // Read and check
+ //
+ for (Entry=0;Entry<8;Entry++) {
+ if ((Temp = SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST6)) != ScsiTestData[Entry]) {
+ FwPrint("Reg2 CTEST6 expected %lx received %lx\r\n", ScsiTestData[Entry], Temp);
+ return 1;
+ Errors++;
+ }
+ if (((Temp = SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST2))&0x8) != ScsiTestParity[Entry]) {
+ FwPrint("Reg2 CTEST2 expected %lx received %lx\r\n", ScsiTestParity[Entry], Temp);
+ return 1;
+ Errors++;
+ }
+ }
+ }
+ SCSI_WRITE_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST4,0);
+ return Errors;
+
+}
+
+#endif
+
+#ifndef DUO
+ULONG
+RomFloppyRegistersTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the Floppy controller registers can be writen and
+ read.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of errors found.
+
+--*/
+{
+ ULONG Errors=0;
+
+ //
+ // Test registers
+ //
+
+ WRITE_REGISTER_UCHAR(&FLOPPY_WRITE->DigitalOutput,0xec);
+ CHECK_UCHAR(&FLOPPY_READ->DigitalOutput,0xec )
+ WRITE_REGISTER_UCHAR(&FLOPPY_WRITE->DigitalOutput,0x7B);
+ CHECK_UCHAR(&FLOPPY_READ->DigitalOutput,0x7B )
+ WRITE_REGISTER_UCHAR(&FLOPPY_WRITE->DigitalOutput,0x08);
+ CHECK_UCHAR(&FLOPPY_READ->DigitalOutput, 0x08)
+ return Errors;
+}
+#endif
+
+ULONG
+RomSonicRegistersTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the Sonic registers can be writen and
+ read. It doesn't test all the accessible registers but all the
+ address bits are toggled.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of errors found.
+
+--*/
+{
+ ULONG Errors=0;
+ PSONIC_REGISTERS SonicBase = (volatile PSONIC_REGISTERS) NET_VIRTUAL_BASE;
+ USHORT Tmp;
+ //
+ // Test registers
+ //
+
+ WRITE_REGISTER_USHORT(&SonicBase->UTDA.Reg,0xAAAA);
+ WRITE_REGISTER_USHORT(&SonicBase->CRDA.Reg,0x5555);
+ WRITE_REGISTER_USHORT(&SonicBase->RRP.Reg,0x1E1E);
+ WRITE_REGISTER_USHORT(&SonicBase->RWP.Reg,0xC33C);
+ WRITE_REGISTER_USHORT(&SonicBase->WatchdogTimer0.Reg,0xFFFF);
+ WRITE_REGISTER_USHORT(&SonicBase->WatchdogTimer1.Reg,0x0000);
+ WRITE_REGISTER_USHORT(&SonicBase->FaeTally.Reg,0xFFFF); // clear counter
+ CHECK_USHORT(&SonicBase->UTDA.Reg, 0xAAAA)
+ CHECK_USHORT(&SonicBase->CRDA.Reg, 0x5555)
+ CHECK_USHORT(&SonicBase->RRP.Reg, 0x1E1E)
+ CHECK_USHORT(&SonicBase->RWP.Reg, 0xC33C)
+ CHECK_USHORT(&SonicBase->WatchdogTimer0.Reg, 0xFFFF)
+ CHECK_USHORT(&SonicBase->WatchdogTimer1.Reg, 0)
+ CHECK_USHORT(&SonicBase->FaeTally.Reg,0)
+ return Errors;
+}
+
+#ifndef DUO
+ULONG
+RomScsiResetTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the NCR 53c94 SCSI controller was properly reset.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of errors found.
+
+--*/
+{
+ ULONG Errors=0;
+
+ //
+ // Test that SCSI was properly reset
+ //
+
+ if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,Fifo) != 0) { // check Fifo
+ Errors++;
+ }
+ if (SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,FifoFlags) != 0 ) { // check Fifo flags
+ Errors++;
+ }
+ if ((SCSI_READ((PSCSI_REGISTERS)SCSI_VIRTUAL_BASE,ScsiStatus) & 0xF8) != 0) { // check status
+ Errors++;
+ }
+ return Errors;
+}
+#else
+ULONG
+RomScsiResetTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the NCR c700 SCSI controller was properly reset.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of errors found.
+
+--*/
+{
+ ULONG Errors=0;
+ ULONG Temp;
+ UCHAR Char;
+ USHORT Short;
+ //
+ // Test that SCSI 1 was properly reset
+ //
+
+ if ((Temp=SCSI_READ_ULONG((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,SCNTL0)) != 0xC0) { // check low 4 register
+ FwPrint("\r\nRegister %s received %lx\r\n","SCNTL0",Temp);
+ Errors++;
+ }
+ if ((Temp=SCSI_READ_ULONG((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,SCID)) != 0x0) { // check next 4 register
+ FwPrint("\r\nRegister %s received %lx\r\n","SCID",Temp);
+ Errors++;
+ }
+ if ((Char = SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST1)) != 0xF0) { // check next register
+ FwPrint("\r\nRegister %s received %lx\r\n","CTEST1",Char);
+ Errors++;
+ }
+//
+// This works on power up only.
+//
+// if ((Short=SCSI_READ_USHORT((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,CTEST2)) != 0x21) { // check next 2 register
+// FwPrint("\r\nRegister %s received %lx\r\n","CTEST2",Short);
+// Errors++;
+// }
+
+ SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,SSTAT0);
+ if ((Char=SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI1_VIRTUAL_BASE,ISTAT)) != 0x4) { // check next register
+ FwPrint("\r\nRegister %s received %lx\r\n","ISTAT",Char);
+ Errors++;
+ }
+
+ //
+ // Test that SCSI 2 was properly reset
+ //
+
+ if ((Temp=SCSI_READ_ULONG((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,SCNTL0)) != 0xC0) { // check low 4 register
+ FwPrint("\r\nRegister2 %s received %lx\r\n","SCNTL0",Temp);
+ Errors++;
+ }
+ if ((Temp=SCSI_READ_ULONG((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,SCID)) != 0x0) { // check next 4 register
+ FwPrint("\r\nRegister2 %s received %lx\r\n","SCID",Temp);
+ Errors++;
+ }
+ if ((Char = SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST1)) != 0xF0) { // check next register
+ FwPrint("\r\nRegister2 %s received %lx\r\n","CTEST1",Char);
+ Errors++;
+ }
+
+// if ((Short=SCSI_READ_USHORT((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,CTEST2)) != 0x21) { // check next 2 register
+// FwPrint("\r\nRegister2 %s received %lx\r\n","CTEST2",Short);
+// Errors++;
+// }
+
+ SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,SSTAT0);
+ if ((Char=SCSI_READ_UCHAR((PSIOP_REGISTERS)SCSI2_VIRTUAL_BASE,ISTAT)) != 0x4) { // check next register
+ FwPrint("\r\nRegister2 %s received %lx\r\n","ISTAT",Char);
+ Errors++;
+ }
+
+ return Errors;
+}
+#endif
+
+
+#ifndef DUO
+ULONG
+RomFloppyResetTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the Floppy controller has been properly reset.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of errors found.
+
+--*/
+{
+ ULONG Errors=0;
+
+ //
+ // Test that Floppy controller was properly reset
+ //
+
+ CHECK_UCHAR(&FLOPPY_READ->DigitalOutput, 0x8)
+ return Errors;
+}
+#endif
+
+ULONG
+RomSonicResetTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine verifies that the Sonic cotroller has been properly reset.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of errors found.
+
+--*/
+{
+ ULONG Errors=0;
+ PSONIC_REGISTERS SonicBase = (volatile PSONIC_REGISTERS) NET_VIRTUAL_BASE;
+ USHORT Tmp;
+ //
+ // Test that Sonic controller was properly reset
+ //
+
+ CHECK_USHORT(&SonicBase->Command.Reg, 0x94)
+ CHECK_USHORT(&SonicBase->TransmitControl.Reg, 0x101) // this line was commented out for duo
+ CHECK_USHORT(&SonicBase->InterruptStatus.Reg, 0x0)
+ CHECK_USHORT(&SonicBase->CamEnable.Reg, 0x0)
+ CHECK_USHORT(&SonicBase->ReceiveSequenceCounter.Reg, 0x0)
+ return Errors;
+}
+
+BOOLEAN
+ValidNvram(
+ OUT PUCHAR StationAddress
+ )
+/*++
+
+Routine Description:
+
+ This routine checks that the Nvram is operational.
+
+Arguments:
+
+ StationAddress - Pointer to struct to fill with the station address found in the
+ Nvram if it's there.
+
+Return Value:
+
+ TRUE if the Nvram contains valid configuration data.
+ FALSE Otherwise.
+
+--*/
+{
+ ULONG i,Errors=0;
+ ULONG CheckSum;
+ PUCHAR NVRamReadWrite = (PUCHAR) (NVRAM_PAGE0);
+ PUCHAR NVRamProtected = (PUCHAR) (NVRAM_PAGE1);
+ PUCHAR NVRamReadOnly = (PUCHAR) (NVRAM_PAGE2);
+
+ //
+ // Check the Station Address
+ //
+
+ CheckSum=0;
+ for (i=0;i<6;i++) {
+ CheckSum+=NVRamReadOnly[i];
+ if (CheckSum >= 256) { // carry
+ CheckSum++; // Add the carry
+ CheckSum &= 0xFF; // remove it from bit 9
+ }
+ }
+ if ((NVRamReadOnly[7]+CheckSum != 0xFF) || (NVRamReadOnly[6]!=0)) {
+ ValidEthernetAddress=FALSE;
+ return FALSE;
+ } else {
+ ValidEthernetAddress=TRUE;
+
+ //
+ // Copy the station address.
+ //
+
+ for (i=0;i<6;i++) {
+ StationAddress[i]=NVRamReadOnly[i];
+ }
+ return TRUE;
+ }
+}
+
+#ifndef DUO
+ULONG
+RomIOCacheTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine tests that the Jazz mctadr registers can be written and read.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ 0 if no errors found
+ number of errors otherwise
+
+--*/
+{
+ ULONG Errors=0,i,Block;
+
+ //
+ // Check the 32 data path between mctadr and r4000 by writting to the
+ // byte mask and forcing an invalidate afterwards.
+ //
+
+ for (Block=0;Block<8;Block++) {
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->CacheMaintenance.Long,Block<<2); // select cache block zero
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->LogicalTag.Long,0x80000001); // set LFN to zero
+ // page offsset to zero
+ // read from device
+ // and validate Tag
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->ByteMask.Long,0x0F0F0F0F); // set even words to valid.
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->PhysicalTag.Long,1); // set PFN to zero and validate Tag
+
+ //
+ // Write data in the IO cache.
+ //
+
+ for (i=0;i<4;i++) { // ?? 2 because of the bug in the mctadr, should be 4
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->CacheMaintenance.Long,(Block<<2)+i);// select line & Bank
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->BufferWindowLow.Long,Block+i);
+ }
+
+ //
+ // Read from memory (and flush buffers) at phys address zero which should match with the phys tag
+ // thus invalidating it and clearing the byte mask.
+ //
+
+ for (i=0;i<2;i++) {
+ CHECK_ULONG(0xA0000000+(i<<3),Block+i);
+ }
+ }
+ return Errors;
+}
+#else
+ULONG
+RomIOCacheTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine tests that the Duo mctadr registers can be written and read.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ 0 if no errors found
+ number of errors otherwise
+
+--*/
+{
+ ULONG Errors=0,i,Block;
+
+ //
+ // Check the 32 data path between mctadr and r4000 by writting to the
+ // byte mask and forcing an invalidate afterwards.
+ //
+
+ for (Block=0;Block<8;Block++) {
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IoCacheLogicalTag[Block].Long,0x80000001); // set LFN to zero
+ // page offsset to zero
+ // read from device
+ // and validate Tag
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IoCacheLowByteMask[Block].Long,0x0F0F0F0F); // set even words to valid.
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IoCacheHighByteMask[Block].Long,0x0F0F0F0F); // set even words to valid.
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IoCachePhysicalTag[Block].Long,1); // set PFN to zero and validate Tag
+
+ //
+ // Write data in the IO cache.
+ //
+
+ for (i=0;i<8;i++) { // for each buffer register
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->IoCacheBuffer[Block*8+i],Block+i);
+ }
+
+ //
+ // Read from memory (and flush buffers) at phys address zero which should match with the phys tag
+ // thus invalidating it and clearing the byte mask.
+ //
+
+ for (i=0;i<8;i++) {
+ CHECK_ULONG(0xA0000000+(i<<3),Block+i);
+ }
+ }
+ return Errors;
+}
+#endif
+
+ULONG
+InterruptControllerTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine tests that the mctadr registers can be written and read.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Errors=0,i=0;
+
+ TimerTicks=1; // set counter to 1
+
+ // write a zero for 1msec interval.
+
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->InterruptInterval.Long,0);
+ while (TimerTicks) { // test counter until it's zero
+ READ_REGISTER_UCHAR(0xBFC00000); // read from ROM to waste time
+ if (i++ == 0x1FFFF) { // if timeout
+ Errors++; // return errors
+ return Errors;
+ }
+ }
+ return Errors;
+}
+ VOID
+RomBeep(
+ )
+/*++
+
+Routine Description:
+
+ This routine makes the speaker beep for a seconf.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PutLedDisplay(LED_BEEP);
+ WRITE_REGISTER_UCHAR(&ISP->IntTimer1CommandMode,0xB6);
+ WRITE_REGISTER_UCHAR(&ISP->IntTimer1SpeakerTone,0x97); // LSB for 440hz
+ WRITE_REGISTER_UCHAR(&ISP->IntTimer1SpeakerTone,0x0A); // MSB for 440Hz
+ WRITE_REGISTER_UCHAR(&ISP->NMIStatus,3); // Do notforce NMI just enable the speaker beep!
+ while (TimerTicks>500) { // wait until counter reaches 500
+ }
+ WRITE_REGISTER_UCHAR(&ISP->NMIStatus,0); // Disable the speaker beep.
+}
+
+UCHAR
+ReadRTCRegister (
+ UCHAR Register
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the specified register of the RTC
+
+Arguments:
+
+ Register - Number of the register to read
+
+Return Value:
+
+ Returns the contents of the RTC register.
+
+--*/
+{
+ //
+ // Write the register number into the NMI register of the ISP
+ // and disable NMI
+ //
+
+ WRITE_REGISTER_UCHAR(&ISP->NMIEnable,Register | (1 << 7));
+
+ //
+ // Read the register
+ //
+
+ return READ_REGISTER_UCHAR((PUCHAR)RTC_VIRTUAL_BASE);
+}
+
+VOID
+WriteRTCRegister (
+ UCHAR Register,
+ UCHAR Value
+ )
+/*++
+
+Routine Description:
+
+ This routine writes the Value to the specified RTC register
+
+Arguments:
+
+ Register - Number of the register to write
+
+ Value - Value to write to the RTC register.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ //
+ // Write the register number into the NMI register of the ISP
+ // and disable NMI
+ //
+
+ WRITE_REGISTER_UCHAR(&ISP->NMIEnable,Register | (1 << 7));
+
+ //
+ // Write the register
+ //
+
+ WRITE_REGISTER_UCHAR((PUCHAR)RTC_VIRTUAL_BASE,Value);
+}
+ ULONG
+ReadTime(
+ )
+/*++
+
+Routine Description:
+
+ This routine reads the current time in the RTC.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of seconds since time zero = Jan 1st 1900 12:00:00PM
+
+--*/
+{
+ UCHAR DataByte;
+ UCHAR Minutes,Seconds;
+ ULONG TotalSeconds;
+
+ //
+ // Check for an Update In Progress
+ //
+
+ do {
+ DataByte=ReadRTCRegister(RTC_CONTROL_REGISTERA);
+ } while (((PRTC_CONTROL_REGISTER_A)(&DataByte))->UpdateInProgress==1);
+
+ //
+ // Read Time from RTC and compute seconds.
+ //
+
+ Minutes = ReadRTCRegister(RTC_MINUTE); // read minutes
+ Seconds = ReadRTCRegister(RTC_SECOND); // read seconds
+ TotalSeconds = (Minutes * 60) + Seconds; // compute seconds
+ return TotalSeconds;
+}
+
+ULONG
+RomRTCTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine checks that the RTC is operating correctly by reading
+ the time, waiting for a 1.1 seconds, reading time again and checking
+ that the two times differ in 1 or 2 seconds.
+
+ If the RTC is disabled, this routine enables it and sets the time
+ to 12:00:00pm Jan 1st 1900. The RTC is set in Binary count mode, and
+ 12h time format.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of errors found.
+
+--*/
+{
+ UCHAR DataByte;
+ ULONG Time;
+
+ DataByte = ReadRTCRegister(RTC_CONTROL_REGISTERA);
+ if (((PRTC_CONTROL_REGISTER_A)(&DataByte))->TimebaseDivisor != 0x2) { // test DV bits to see if rtc is counting.
+
+ //
+ // Enable counter
+ //
+
+ DataByte = 0;
+ ((PRTC_CONTROL_REGISTER_A)(&DataByte))->TimebaseDivisor = 2;
+ WriteRTCRegister(RTC_CONTROL_REGISTERA, DataByte);
+ Time = 0;
+ TimerTicks = 600; // set counter to 600
+ while (TimerTicks) { // Wait for an update to occur
+ }
+
+ //
+ // Set RTC to 24 hour format and binary mode. Set SET Bit
+ //
+
+ DataByte=0;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->HoursFormat = 1;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->DataMode = 1;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SetTime = 1;
+ WriteRTCRegister(RTC_CONTROL_REGISTERB, DataByte);
+
+ //
+ // RTC disabled set date to 1-1-1900 0h:0m:0
+ //
+
+ WriteRTCRegister(RTC_SECOND,0); //
+ WriteRTCRegister(RTC_MINUTE,0); // 12:00:00 PM
+ WriteRTCRegister(RTC_HOUR,0x12); //
+ WriteRTCRegister(RTC_DAY_OF_WEEK,1); //sunday
+ WriteRTCRegister(RTC_DAY_OF_MONTH,1); // 1st
+ WriteRTCRegister(RTC_MONTH,1); // january
+ WriteRTCRegister(RTC_YEAR,0); // 1900
+ WriteRTCRegister(RTC_SECOND_ALARM,0xFF); // Turn alarm
+ WriteRTCRegister(RTC_MINUTE_ALARM,0xFF); // off
+ WriteRTCRegister(RTC_HOUR_ALARM,0xFF); //
+
+ }
+
+ //
+ // Clear SET bit and put in binary mode
+ //
+
+ DataByte=0;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->HoursFormat = 1;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->DataMode = 1;
+ WriteRTCRegister(RTC_CONTROL_REGISTERB, DataByte);
+
+ for (DataByte=0;DataByte<2;DataByte++) { // do it twice in case Hour changes
+ Time = ReadTime(); // Read Current time
+ TimerTicks=1050; // set timeout to 1.05 seconds
+ RomBeep(); // Do a beep in the meantime for 500ms
+ while (TimerTicks) { // Wait for an update
+ } //
+ Time = ReadTime() - Time; // compute elapsed time
+ if ((Time == 1) || (Time == 2)) { // 1 or 2 seconds passed
+ return 0; // RTC counts properly
+ }
+ } // if it didn't work even the second time it's screw up.
+ return 1;
+}
+ULONG
+RomVideoMemory(
+ IN VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine tests the video memory.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Number of errors found.
+
+--*/
+
+{
+ ULONG VideoMemoryBaseAddress;
+
+#ifdef R3000
+ VideoMemoryBaseAddress=VIDEO_MEMORY_PHYSICAL_BASE,
+#else
+ VideoMemoryBaseAddress=VIDEO_MEMORY_VIRTUAL_BASE,
+#endif
+ WriteVideoMemoryAddressTest(VideoMemoryBaseAddress,
+ VIDEO_MEMORY_SIZE
+ );
+ return CheckVideoMemoryAddressTest(VideoMemoryBaseAddress,
+ VIDEO_MEMORY_SIZE
+ );
+}
+
+ULONG
+RomInitISP (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the EISA interrupt controller.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the number of errors found.
+
+--*/
+
+{
+
+ UCHAR DataByte;
+
+ ULONG InterruptLevel;
+
+ //
+ // Initialize the EISA interrupt controller. There are two cascaded
+ // interrupt controllers, each of which must initialized with 4 initialize
+ // control words.
+ //
+
+ DataByte = 0;
+ ((PINITIALIZATION_COMMAND_1) &DataByte)->Icw4Needed = 1;
+ ((PINITIALIZATION_COMMAND_1) &DataByte)->InitializationFlag = 1;
+
+ WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt1ControlPort0,DataByte);
+ WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt2ControlPort0,DataByte);
+
+ //
+ // The second intitialization control word sets the iterrupt vector to
+ // 0-15.
+ //
+
+ DataByte = 0;
+
+ WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt1ControlPort1,DataByte);
+
+ DataByte = 0x08;
+
+ WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt2ControlPort1,DataByte);
+
+ //
+ // The thrid initialization control word set the controls for slave mode.
+ // The master ICW3 uses bit position and the slave ICW3 uses a numberic.
+ //
+
+ DataByte = 1 << SLAVE_IRQL_LEVEL;
+
+ WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt1ControlPort1,DataByte);
+
+ DataByte = SLAVE_IRQL_LEVEL;
+
+ WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt2ControlPort1,DataByte);
+
+ //
+ // The fourth initialization control word is used to specify normal
+ // end-of-interrupt mode and not special-fully-nested mode.
+ //
+
+ DataByte = 0;
+ ((PINITIALIZATION_COMMAND_4) &DataByte)->I80x86Mode = 1;
+
+ WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt1ControlPort1,DataByte);
+ WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt2ControlPort1,DataByte);
+
+
+ //
+ // Mask all the interrupts.
+ //
+
+ WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt1ControlPort1,0xFF);
+ WRITE_REGISTER_UCHAR(&EISA_CONTROL->Interrupt2ControlPort1,0xFF);
+
+ //
+ // Check that the interrupt level is 7 (i.e. no interrupt is pending)
+ //
+#ifndef DUO
+ InterruptLevel=READ_REGISTER_UCHAR(&DMA_CONTROL->InterruptAcknowledge);
+ InterruptLevel=READ_REGISTER_UCHAR(&DMA_CONTROL->InterruptAcknowledge);
+ if (InterruptLevel == 0x07) {
+ return 0;
+ } else {
+ return 1;
+ }
+#else
+ InterruptLevel=READ_REGISTER_ULONG(&DMA_CONTROL->EisaInterruptAcknowledge);
+ InterruptLevel=READ_REGISTER_ULONG(&DMA_CONTROL->EisaInterruptAcknowledge);
+ if (InterruptLevel == 0x0) {
+ return 0;
+ } else {
+ FwPrint("\r\nEisa Interrupt level =%lx ",InterruptLevel);
+ return 1;
+ }
+#endif
+
+}
+
+
+VOID
+FwPrintVersion (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine prints the PROM version.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ FwPrint(ST_ARC_MULTIBOOT_MSG,*(PULONG)(PROM_ENTRY(2)));
+ FwPrint(ST_COPYRIGHT_MSG);
+ return;
+}
+
+
+#ifndef DUO
+VOID
+ReportJazzCacheErrorException(
+ IN ULONG CacheErr
+ )
+/*++
+
+Routine Description:
+
+ This routine prints cache error / parity information.
+
+Arguments:
+
+ CacheErr - R4000 CacheErr register.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG ParityDiag[3];
+ PULONG ParDiag;
+ ULONG IntSrc;
+ UCHAR String[128];
+
+ //
+ // Display cache error exception message
+ //
+ FwPrint(MON_CACHE_ERROR_MSG);
+ FwPrint(MON_EXCEPTION_MSG);
+
+ //
+ // Align ParDiag to a double word.
+ //
+ ParDiag = (PULONG) ((ULONG)(&ParityDiag[1]) & 0xFFFFFFF8);
+
+ if (((PCACHEERR)(&CacheErr))->EE == 1) {
+ //
+ // This is a parity error on the Memory or SysAd bus.
+ //
+ IntSrc = READ_REGISTER_ULONG(&DMA_CONTROL->InterruptSource.Long);
+ if (IntSrc & (1 << 8)) {
+ //
+ // This a parity error in memory.
+ // Display MFAR and Parity Diag.
+ //
+ LoadDoubleWord((ULONG)&DMA_CONTROL->ParityDiagnosticLow.Long,ParDiag);
+ sprintf(String,
+ MON_MEM_PARITY_FAILED_MSG,
+ READ_REGISTER_ULONG(&DMA_CONTROL->MemoryFailedAddress.Long),
+ *ParDiag,
+ *(ParDiag+1)
+ );
+ FwPrint(String);
+ return;
+ } else {
+ //
+ // The error occurred in the system bus.
+ //
+ FwPrint(MON_BUS_PARITY_ERROR);
+ return;
+ }
+ } else {
+ //
+ // Internal cache error.
+ //
+ sprintf(String,MON_CACHE_ERROR_REG_MSG,CacheErr);
+ FwPrint(String);
+ return;
+ }
+}
+#else
+VOID
+ReportDuoCacheErrorException(
+ IN ULONG CacheErr
+ )
+/*++
+
+Routine Description:
+
+ This routine prints cache error / ecc information.
+
+Arguments:
+
+ CacheErr - R4000 CacheErr register.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR String[128];
+ //
+ // Display cache error exception message
+ //
+ FwPrint(MON_CACHE_ERROR_MSG);
+ FwPrint(MON_EXCEPTION_MSG);
+ if (READ_REGISTER_ULONG(&DMA_CONTROL->WhoAmI.Long)) {
+ FwPrint(MON_PROCESSOR_B_EXCEPTION);
+ } else {
+ FwPrint(MON_PROCESSOR_A_EXCEPTION);
+ }
+ if (((PCACHEERR)(&CacheErr))->EE == 1) {
+ //
+ // The error occurred in the system bus.
+ //
+ FwPrint(MON_BUS_PARITY_ERROR);
+ return;
+ } else {
+ //
+ // Internal cache error.
+ //
+ sprintf(String,MON_CACHE_ERROR_REG_MSG, CacheErr);
+ FwPrint(String);
+ return;
+ }
+}
+#endif
diff --git a/private/ntos/fw/mips/selftest.h b/private/ntos/fw/mips/selftest.h
new file mode 100644
index 000000000..4afa2db0e
--- /dev/null
+++ b/private/ntos/fw/mips/selftest.h
@@ -0,0 +1,224 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ selftest.c
+
+Abstract:
+
+ This module contains definitions for selftest.c
+
+Author:
+
+ Lluis Abello (lluis) 03-Jan-1991
+
+Environment:
+
+
+Revision History:
+
+--*/
+//
+// Video Memory Test
+//
+
+#define VIDEO_MEMORY_SIZE 0x200000 // 2 MB
+#define DISPLAY_MEMORY_SIZE 0x100000 // 1 MB
+
+//
+// Memory test stuff
+//
+
+#define TESTED_KB (FW_TOP_ADDRESS>>10)
+#define KB_OF_MEMORY (MEMORY_SIZE>>10) //
+#define KB_PER_TEST 0x400 // 1024K at a time
+#define NVRAM_TEST_END 0x800
+
+typedef ULONG (* TestRoutine)(VOID);
+typedef VOID (* LED_ROUTINE)(ULONG);
+
+#ifndef DUO
+#define PROM_BASE (KSEG1_BASE | 0x1fc00000)
+#else
+#define PROM_BASE (EEPROM_VIRTUAL_BASE)
+#endif
+
+#define PROM_ENTRY(x) (PROM_BASE + ((x) * 8))
+
+#define PutLedDisplay ((LED_ROUTINE) PROM_ENTRY(14))
+//
+// Declare static variables
+//
+extern PUCHAR TranslationTable;
+extern UCHAR StationAddress[6];
+
+extern BOOLEAN LanAddress; // True if station address is OK False Otherwise
+extern BOOLEAN ConfigurationBit; // read value from diagnostic register
+extern BOOLEAN LoopOnError; // read value from diagnostic register
+extern BOOLEAN IgnoreErrors; // read value from diagnostic register
+extern BOOLEAN VideoReady; // True if display on video monitor
+
+extern volatile LONG TimerTicks; // Counter for timeouts
+
+//
+// Routine declaration.
+//
+BOOLEAN ExecuteTest(TestRoutine,ULONG);
+VOID RomPutLine(CHAR *);
+ULONG RomVideoMemory();
+ULONG RomReadMergeWrite();
+ULONG RomIOCacheTest();
+ULONG RomSonicResetTest();
+ULONG RomSonicLoopBackTest();
+ULONG RomFloppyResetTest();
+ULONG RomScsiResetTest();
+ULONG RomSerialResetTest();
+ULONG RomSerial1RegistersTest();
+ULONG RomSerial2RegistersTest();
+ULONG RomSerial1LoopBackTest();
+ULONG RomSerial2LoopBackTest();
+ULONG RomParallelRegistersTest();
+ULONG RomScsiRegistersTest();
+ULONG RomFloppyRegistersTest();
+ULONG RomSonicRegistersTest();
+ULONG InterruptControllerTest();
+ULONG ConnectInterrupts();
+ULONG DisableInterrupts();
+ULONG RomRTCTest();
+ULONG InitMouse();
+ULONG InitKeyboard();
+ULONG InitKeyboardController();
+ULONG RomNvramTest();
+VOID RomBeep();
+ULONG RomInitISP (VOID);
+
+#define CHECK_ULONG(Address,Value) if (READ_REGISTER_ULONG(Address) != Value) {\
+ Errors++;\
+ }
+#define CHECK_USHORT(Address,Value) if ((Tmp=READ_REGISTER_USHORT(Address)) != Value) { \
+ FwPrint("Expected %lx received %lx\r\n",Value,Tmp);\
+ Errors++;\
+ }
+#define CHECK_UCHAR(Address,Value) if (READ_REGISTER_UCHAR(Address) != Value) { \
+ Errors++;\
+ }
+
+
+#ifdef DUO
+
+typedef
+ULONG
+(*PPROCESSOR_TASK_ROUTINE) (
+ IN PVOID Data
+ );
+
+BOOLEAN
+WaitForIpInterrupt();
+
+VOID
+WaitForAsIpInterrupt();
+
+BOOLEAN
+WaitForBsIpInterrupt(
+ IN ULONG Timeout
+ );
+
+VOID
+ProcessorBMain(
+ );
+
+BOOLEAN
+ProcessorBSelftest(
+ IN VOID
+ );
+
+VOID
+WriteMemoryAddressTest(
+ ULONG StartAddress,
+ ULONG Size,
+ ULONG Xorpattern
+ );
+
+PULONG
+CheckMemoryAddressTest(
+ ULONG StartAddress,
+ ULONG Size,
+ ULONG Xorpattern,
+ ULONG LedDisplayValue
+ );
+
+VOID
+WriteVideoMemoryAddressTest(
+ ULONG StartAddress,
+ ULONG Size
+ );
+
+ULONG
+CheckVideoMemoryAddressTest(
+ ULONG StartAddress,
+ ULONG Size
+ );
+
+typedef struct _PROCESSOR_B_TASK_VECTOR {
+ PPROCESSOR_TASK_ROUTINE Routine;
+ PVOID Data;
+ ULONG ReturnValue;
+ } PROCESSOR_B_TASK_VECTOR, *PPROCESSOR_B_TASK_VECTOR;
+
+
+extern volatile PROCESSOR_B_TASK_VECTOR ProcessorBTask;
+
+typedef struct _PROCESSOR_B_TEST {
+ PPROCESSOR_TASK_ROUTINE Routine;
+ PVOID Data;
+ } PROCESSOR_B_TEST, *PPROCESSOR_B_TEST;
+
+//
+// Define data structures for each of processor B's tests.
+//
+
+typedef struct _MEMORY_TEST_DATA {
+ ULONG StartAddress;
+ ULONG Size;
+ ULONG XorPattern;
+ ULONG LedDisplayValue;
+ } MEMORY_TEST_DATA, *PMEMORY_TEST_DATA;
+
+ULONG
+ProcessorBMemoryTest(
+ IN PMEMORY_TEST_DATA MemoryData
+ );
+
+ULONG
+ProcessorBVideoMemoryTest(
+ IN PMEMORY_TEST_DATA MemoryData
+ );
+
+VOID
+ProcessorBSystemBoot(
+ IN VOID
+ );
+
+ULONG
+RomScsiResetTest(
+ IN VOID
+ );
+
+ULONG
+CoherencyTest(
+ IN PVOID CoherentPage
+ );
+
+BOOLEAN
+IsIpInterruptSet(
+ IN VOID
+ );
+
+VOID
+RestartProcessor(
+ IN PRESTART_BLOCK RestartBlock
+ );
+
+#endif
diff --git a/private/ntos/fw/mips/sonictst.c b/private/ntos/fw/mips/sonictst.c
new file mode 100644
index 000000000..30741fc32
--- /dev/null
+++ b/private/ntos/fw/mips/sonictst.c
@@ -0,0 +1,822 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ sonictst.c
+
+Abstract:
+
+ This module implements the SONIC ethernet test for the selftest.
+ The test consist in transmiting packets in loopback mode.
+
+Author:
+
+ Lluis Abello (lluis) 19-Feb-1991
+
+Environment:
+
+
+Revision History:
+
+--*/
+
+#include "fwp.h"
+#include "sonictst.h"
+#include "iodevice.h"
+#include "ioaccess.h"
+#include "fwstring.h"
+#ifdef DUO
+#include "duoint.h"
+#endif
+
+extern volatile ULONG TimerTicks;
+extern UCHAR * TranslationTable;
+
+ VOID
+MapDma(
+ ULONG VirtualAddress,
+ ULONG LogicalAddress,
+ ULONG Pages
+ )
+/*++
+
+Routine description:
+
+ This routine performs the I/O address maping by setting the
+ translation table.
+
+ Physical and Logical Addresses must be page aligned.
+
+Arguments:
+
+ VirtualAddress - Specifies the R4000 VirtualAddress.
+
+ Logical Address will be mapped to the physical
+ address that this Virtual Address Maps.
+
+ LogicalAdress - Address to map
+
+ Pages - Number of pages to map
+
+Return value:
+
+ None.
+--*/
+{
+PTRANSLATION_ENTRY TranslationTable;
+ULONG PageFrameNumber,LogicalPage,PhysicalAddress;
+ULONG i;
+ PhysicalAddress=VirtualAddress&0x0FFFFFFF; // Extract Physical Address from KSEG0-1
+ TranslationTable= (PTRANSLATION_ENTRY)((READ_REGISTER_ULONG(&DMA_CONTROL->TranslationBase.Long)) | 0xA0000000);
+
+ // Initialize pointer to base
+ // of Table to write the new entries.
+ // Make physical address virtual
+ // Non cached because we want it
+ // to be written to memory
+ LogicalPage= LogicalAddress>>12;
+ PageFrameNumber=PhysicalAddress&0x03FFF000;
+ for (i=0;i < Pages;i++) {
+ TranslationTable[LogicalPage+i].PageFrame=PageFrameNumber;
+ PageFrameNumber+=0x1000; // next page starts after 4Kb more
+ TranslationTable[LogicalPage+i].Fill=0;
+ }
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->TranslationLimit.Long,(LogicalPage+i) << 3);
+}
+ VOID
+AllocateReceiveDescriptors(
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates and initializes a chain of 3 Receive Descriptors.
+ The Receive Descriptors are linked in a circular queue so that the
+ pointers don't need to be changed any more. The last Receive descriptor
+ points to the first but it has the EOL flag set so it's the last on the
+ queue and therefore sonic will not use the following descriptor (first one)
+ until we free it. Once we process a received packet, the EOL flag must be
+ rotated to the next descriptor to make a new descriptor available.
+
+ In order to be able to use the link field from both physical (system soft)
+ and logical (sonic) address spaces the receive descriptors must have
+ the same alignment for both physical and logical addresses.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ULONG Link,i;
+ULONG LogicalReceiveDscr;
+ ReceiveDscrQueue.Base = (PRECEIVE_DESCRIPTOR) PHYS_RECEIVE_DSCR_ADDRESS;
+ LogicalReceiveDscr = LOGICAL_RECEIVE_DSCR_ADDRESS;
+ MapDma((ULONG)ReceiveDscrQueue.Base, // R4000 Address
+ LogicalReceiveDscr, // Logical Address
+ 1 // 1 page
+ );
+ //get 16 lower bits of address or offset
+ ReceiveDscrQueue.Current=Link=(ULONG)ReceiveDscrQueue.Base & 0xFFFF;
+ //
+ // Link first descriptor to the second one.
+ //
+ for (i=0;i<2;i++) {
+ Link += sizeof(RECEIVE_DESCRIPTOR);
+ (ReceiveDscrQueue.Base[i]).Link.Data=Link; // Link to next RD
+ (ReceiveDscrQueue.Base[i]).InUse.Data=AVAILABLE; // Make it avilable
+ }
+ //
+ // Link last descriptor to the first but mark it as EOL
+ //
+ (ReceiveDscrQueue.Base[2]).Link.Data=ReceiveDscrQueue.Current | EOL;
+ //
+ // Make it avilable
+ //
+ (ReceiveDscrQueue.Base[2]).InUse.Data=AVAILABLE;
+ ReceiveDscrQueue.Last=Link; // Keep track of the last one.
+ // we need only the upper bits to access a descriptor as Base | First
+ ReceiveDscrQueue.Base = (PRECEIVE_DESCRIPTOR)((ULONG) ReceiveDscrQueue.Base & 0xFFFF0000);
+ //
+ // Initialize sonic Receive descriptor pointers with the logical address
+ // of the descriptors.
+ //
+ WRITE_REGISTER_USHORT(&SONIC->URDA.Reg,(USHORT) (LogicalReceiveDscr >> 16));
+ WRITE_REGISTER_USHORT(&SONIC->CRDA.Reg,ReceiveDscrQueue.Current);
+}
+ VOID
+AllocateReceiveResources(
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates and initializes the Receive Resource area.
+ Two resources are allocated.
+ The pointer of each entry points to the Receive Buffers which are
+ also allocated by this routine. And the size of each buffer is also
+ set in the Recieve Resource word count entry.
+
+ Receive Buffers allocated are RBA_SIZE bytes long.
+
+ It also allocate room for the CAM descriptors. The CAM descriptor pointer
+ is pointed by CamDescriptor and resides inside the URRA segment.
+
+ The mapping Logical <-> Physical spaces is also done.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ULONG i;
+ULONG ReceivePhysBuffer; // Temporay pointer to a receive buffer area.
+ULONG ReceiveLogBuffer; // Temporary pointer to a logical address.
+//
+//Allocate memory for the receive descriptors + CAM Addresses + CAM enable.
+//
+ ReceivePhysRsrc = (PRECEIVE_RESOURCE) RECEIVE_PHYS_RSRC_ADDRESS;
+ ReceiveLogRsrc = (PRECEIVE_RESOURCE) RECEIVE_LOG_RSRC_ADDRESS;
+ MapDma((ULONG)ReceivePhysRsrc,
+ (ULONG)ReceiveLogRsrc,
+ 1
+ );
+//
+// Allocate Receive buffers in physical and logical spaces and map them.
+//
+ ReceivePhysBuffer= (ULONG) RECEIVE_PHYS_BUFFER_ADDRESS;
+ ReceiveLogBuffer= (ULONG) RECEIVE_LOG_BUFFER_ADDRESS;
+ MapDma(ReceivePhysBuffer,ReceiveLogBuffer,2);
+//
+// The Receive Buffers are contiguos in memory. Sonic will write
+// the logical address of the packets received. To translate this
+// logical address to a physical one what we do is to keep the
+// offset between these physical and logical addresses and then
+// we just need to add this offset to the logical address to
+// convert it to physical.
+//
+ ReceiveBufferTranslationOffset =ReceivePhysBuffer-ReceiveLogBuffer;
+//
+// for each receive resource, Write the logical
+// address of the receive buffer in the physical Receive resource.
+//
+ for (i=0; i < 3; i++) {
+ ReceivePhysRsrc[i].BufferPtr0.Data=ReceiveLogBuffer & 0xFFFF; //16 lower bits
+ ReceivePhysRsrc[i].BufferPtr1.Data=ReceiveLogBuffer >> 16; //16 upper bits
+ ReceivePhysRsrc[i].WordCount0.Data=((RBA_SIZE >>1) & 0xFFFF); //16 lower bits
+ ReceivePhysRsrc[i].WordCount1.Data=(RBA_SIZE >> 17); //16 upper bits
+ ReceiveLogBuffer += RBA_SIZE;
+ }
+//
+// Initialize the CamDescriptor to point to the end of the RRA
+//
+ PhysCamDescriptor=(PCAM_DESCRIPTOR)(&ReceivePhysRsrc[3]);
+ LogCamDescriptor=(PCAM_DESCRIPTOR)(&ReceiveLogRsrc[3]);
+//
+// Initialize sonic Resource Area pointers with the logical address mapped
+// to the physical Area.
+//
+ WRITE_REGISTER_USHORT(&SONIC->URRA.Reg,(USHORT) ((ULONG)ReceiveLogRsrc >> 16));
+ WRITE_REGISTER_USHORT(&SONIC->RSA.Reg,(ULONG)ReceiveLogRsrc & 0xFFFF);
+ WRITE_REGISTER_USHORT(&SONIC->REA.Reg,(ULONG)(&ReceiveLogRsrc[3]) & 0xFFFF);
+ WRITE_REGISTER_USHORT(&SONIC->RRP.Reg,(ULONG)ReceiveLogRsrc & 0xFFFF);
+ WRITE_REGISTER_USHORT(&SONIC->RWP.Reg,(ULONG)(&ReceiveLogRsrc[2]) & 0xFFFF);
+
+//
+// Set the lower boundary of the RBA to the maximum packet size.
+//
+ WRITE_REGISTER_USHORT(&SONIC->EOBC.Reg,MAX_PACKET_SIZE >> 1);
+//
+// Set The receive control register.
+//
+ WRITE_REGISTER_USHORT(&SONIC->ReceiveControl.Reg,RCR_ENDEC | RCR_RNT);
+}
+ VOID
+SetCamDescriptor(
+ )
+/*++
+
+Routine Description:
+
+ This routine Initializes the CAM descriptor area allocated by
+ "AllocateReceiveResources" and being pointed by PhysCamDescriptor.
+
+ The Address loaded in the CAM is the one fetched from the NVRAM.
+
+ It leaves everything ready to issue the Load CAM command.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ULONG i;
+//
+// Initialize CAM descriptor area.
+//
+ PhysCamDescriptor[0].EntryPointer.Data=0;
+ PhysCamDescriptor[0].Port0.Data=(StationAddress[1] << 8) |
+ (StationAddress[0]);
+ PhysCamDescriptor[0].Port1.Data=(StationAddress[3] << 8) |
+ (StationAddress[2]);
+ PhysCamDescriptor[0].Port2.Data=(StationAddress[5] << 8) |
+ (StationAddress[4]);
+// Set CAM Enable.
+ PhysCamDescriptor[1].EntryPointer.Data=1; // enable entry zero.
+
+ WRITE_REGISTER_USHORT(&SONIC->CamDscrCount.Reg,1); // only one entry.
+// Lower 16 bits offset from URRA
+ WRITE_REGISTER_USHORT(&SONIC->CamDscrPtr.Reg,(ULONG)LogCamDescriptor & 0xFFFF);
+}
+ VOID
+AllocateTransmitDescriptors(
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates and initializes a pool of Transmit Descriptors.
+ The Transmit Descriptors are set to be used one for each packet as they
+ have only room for one fragment.
+
+ The Descriptor fragment pointers are initialized to point to the
+ Transmit Buffer Area which is also allocated.
+ There is enough room allocated for each buffer for the bigest
+ ethernet packet.
+
+ To keep the physical addresses of the TBA we use the upper 16 bits
+ of the SONIC_ENTRY this is the field called 'Fill'.
+ This way we don't ahve any restriction in these pointers but we
+ have to deal with both, physical and logical.
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ULONG i;
+ULONG PhysTbaPtr,LogTbaPtr; // Transmit Buffer Area pointers
+//
+// Allocate memory for transmit descriptors and map it
+//
+ PhysTransmitDscr = (PTRANSMIT_DESCRIPTOR) PHYS_TRANSMIT_DSCR_ADDRESS;
+ LogicalTransmitDscr = (PTRANSMIT_DESCRIPTOR) LOGICAL_TRANSMIT_DSCR_ADDRESS;
+ MapDma((ULONG) PhysTransmitDscr,
+ (ULONG) LogicalTransmitDscr,
+ 1
+ );
+//
+// Allocate memory for Transmit Buffer are and map it.
+//
+ PhysTbaPtr = PHYS_TBA_ADDRESS;
+ LogTbaPtr = LOG_TBA_ADDRESS;
+ MapDma(PhysTbaPtr,LogTbaPtr,1);
+
+// Initialize fragment count to 1 (packets won't be scatered)
+
+ PhysTransmitDscr->FragCount.Data = 1;
+//
+// Initialize Logical pointers to TBA
+//
+ PhysTransmitDscr->FragPtr0.Data = LogTbaPtr & 0xFFFF;// lower 16 bits
+ PhysTransmitDscr->FragPtr1.Data = LogTbaPtr >> 16; // upper 16 bits
+//
+// Initialize Physical pointer to TBA
+//
+ PhysTransmitDscr->FragPtr0.Fill = PhysTbaPtr & 0xFFFF;// lower 16 bits
+ PhysTransmitDscr->FragPtr1.Fill = PhysTbaPtr >> 16; // upper 16 bits
+//
+// Unlink the packets, we will transmit one at a time.
+//
+ PhysTransmitDscr->Link.Data = EOL;
+ PhysTransmitDscr->Config.Data = TCR_POWC;
+
+//
+// Initialize UTDA register. This can be done here because the base address
+// of the Transmit Descriptor Area will not change.
+// CTDA must be set after a new packet is ready to be sent.
+//
+ WRITE_REGISTER_USHORT(&SONIC->UTDA.Reg,(USHORT)((ULONG)LogicalTransmitDscr>>16));
+}
+ VOID
+ComposeMessage(
+ ULONG Size,
+ UCHAR FirstValue
+ )
+/*++
+
+Routine Description:
+
+ This routine composes a message of the specified size.
+ It places the message in the buffer especified by the Transmit
+ Descriptor, and initializes the descriptor.
+
+Arguments:
+
+ Size - Size of the message in bytes, must be <= MAX_PACKET_SIZE
+ FirstValue - value of first Data byte in the packet.
+
+Return Value:
+
+ None.
+
+--*/
+{
+register ULONG i,j=0;
+PUCHAR MsgPtr; // Temporary pointer to the message area.
+//
+// Load pointer to packet
+//
+ MsgPtr= (PUCHAR) ((PhysTransmitDscr->FragPtr1.Fill << 16) | (PhysTransmitDscr->FragPtr0.Fill));
+
+
+ for (i=0; i<6; i++) {
+ MsgPtr[j]=StationAddress[i]; // copy Destination address to packet
+ MsgPtr[j+6]=StationAddress[i]; // copy Source address to packet
+ j++;
+ }
+ j+=6;
+//
+// Set size of message
+//
+ MsgPtr[j++] = Size >> 8; // upper 8 bits
+ MsgPtr[j++] = Size & 0xFF; // lower 8 bits
+//
+// Compose message
+//
+ for (i=0; i < Size; i++) {
+ MsgPtr[j++] = FirstValue++;
+ }
+//
+// Initialize other Transmit descriptor fields.
+//
+ PhysTransmitDscr->PktSize.Data = Size+6+6+2;
+ PhysTransmitDscr->FragSize.Data = Size+6+6+2;
+//
+// Initialize TDA registers with logical address.
+//
+ WRITE_REGISTER_USHORT(&SONIC->CTDA.Reg,((ULONG) LogicalTransmitDscr) & 0xFFFF);
+}
+ VOID
+SonicCheckError(
+ )
+/*++
+
+Routine Description:
+
+ This routine checks and reports error conditions after an interrupt.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ULONG ErrorValue;
+ SonicErrors++;
+ if (SonicStatus.InterruptID & INT_BR) { // Bus Retry.
+ ErrorValue= READ_REGISTER_ULONG(&DMA_CONTROL->Errortype.Long);
+//
+// Clear error by writing back the contents of the register.
+//
+ WRITE_REGISTER_ULONG(&DMA_CONTROL->Errortype.Long,ErrorValue);
+//
+// Read error registers to clear them
+//
+ ErrorValue= READ_REGISTER_ULONG(&DMA_CONTROL->MemoryFailedAddress.Long);
+ ErrorValue= READ_REGISTER_ULONG(&DMA_CONTROL->RemoteFailedAddress.Long);
+#ifndef DUO
+ ErrorValue= READ_REGISTER_ULONG(&DMA_CONTROL->ParityDiagnosticLow.Long);
+#else
+ ErrorValue= READ_REGISTER_ULONG(&DMA_CONTROL->EccDiagnostic);
+#endif
+
+ }
+}
+ BOOLEAN
+WaitForSonicInterrupt(
+ )
+/*++
+
+Routine Description:
+
+ This routine waits for a sonic interrupt by polling the Semaphore
+ It sets the TimerTicks variable to 20 and if it becomes zero
+ (at least 20 millisecond has passed) it time-out.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ FALSE if the interrupt ocurred.
+ TRUE otherwise.
+
+--*/
+{
+ULONG i;
+ TimerTicks=20;
+ while (TimerTicks) { // check for timeout
+ if (SonicIntSemaphore==0) { // if interrupt has ocurred
+ return FALSE; // return to process
+ }
+ }
+ return TRUE; // return if timeout.
+}
+ VOID
+InitSonic(
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the SONIC chip.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None
+
+--*/
+{
+
+#ifdef DUO
+//
+// Enable sonic interrupts in altera
+//
+ USHORT InterruptMask;
+
+ InterruptMask = READ_REGISTER_USHORT(&((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Enable);
+ WRITE_REGISTER_USHORT(&((PINTERRUPT_REGISTERS)INTERRUPT_VIRTUAL_BASE)->Enable,InterruptMask | (1 << 3));
+
+#endif
+
+
+
+//
+// Software Reset
+//
+ WRITE_REGISTER_USHORT(&SONIC->Command.Reg,CR_RST);
+// Set Hardware dependent configuration.
+ WRITE_REGISTER_USHORT(&SONIC->DataConfiguration.Reg,DATA_CONFIGURATION);
+// Clear Reset
+ WRITE_REGISTER_USHORT(&SONIC->Command.Reg,0);
+
+//
+// Initialize all these messy tables of descriptors...
+//
+ AllocateReceiveDescriptors();
+ AllocateReceiveResources();
+ SetCamDescriptor();
+ AllocateTransmitDescriptors();
+//
+// Set Interrupt Mask
+//
+ WRITE_REGISTER_USHORT(&SONIC->InterruptMask.Reg,( INT_BR |
+ INT_LCD |
+ INT_PKTRX |
+ INT_TXDN |
+ INT_TXER |
+ INT_RDE |
+ INT_RBE |
+ INT_RBAE |
+ INT_RFO));
+//
+//Issue Load CAM Command and wait for this interrupt.
+//
+ SonicStatus.ExpectedInt = INT_LCD; // Expect an INT_LCD interrupt.
+ SonicIntSemaphore=1;
+ WRITE_REGISTER_USHORT(&SONIC->Command.Reg,CR_LCAM);
+ if (WaitForSonicInterrupt()) {
+ FwPrint("Timeout waiting for sonic int\r\n");
+ SonicErrors++;
+ return;
+ }
+ if (SonicStatus.Status==DONE) {
+ SonicStatus.ExpectedInt=0; // clear expected interrupts.
+ } else {
+ FwPrint("Sonic status not DONE\r\n");
+ SonicErrors++;
+ }
+//
+// Issue the RRA Read Command
+//
+ WRITE_REGISTER_USHORT(&SONIC->Command.Reg,CR_RRA);
+ while (READ_REGISTER_USHORT(&SONIC->Command.Reg) & CR_RRA) { // Wait until the command is processed.
+ }
+//
+// Enable Reception.
+//
+ WRITE_REGISTER_USHORT(&SONIC->Command.Reg,CR_RXEN);
+ while (READ_REGISTER_USHORT(&SONIC->Command.Reg) & CR_RXDIS) { // wait until reception is enabled.
+ }
+}
+ VOID
+SonicInterrupt(
+ )
+/*++
+
+Routine Description:
+
+ This routine is the SONIC port service interrupt. It will be called from
+ the Trap Handler when getting an interrupt from the SONIC.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+register USHORT InterruptStatus,NotCleared;
+//
+// Read Interrupt Status register
+//
+ InterruptStatus= READ_REGISTER_USHORT(&SONIC->InterruptStatus.Reg);
+//
+// clear interrupt writing it back
+//
+ WRITE_REGISTER_USHORT(&SONIC->InterruptStatus.Reg,InterruptStatus);
+ InterruptStatus= InterruptStatus & (~INT_HBL); // clear HBL bit.
+ if (EXPECTED_INT && NO_OTHER_INT) {
+ if (InterruptStatus & INT_TXDN) {
+ //
+ // Packet Transmited
+ //
+ SonicStatus.ExpectedInt &= ~INT_TXDN; // clear expected bit.
+ // check if it was properly sent.
+ SonicStatus.TransmitControl=READ_REGISTER_USHORT(&SONIC->TransmitControl.Reg);
+ if (SonicStatus.TransmitControl & (TCR_BCM | TCR_EXC | TCR_FU | TCR_EXD)) {
+ //Error Transmiting
+ SonicStatus.Status=ERROR;
+ SonicStatus.InterruptID = InterruptStatus;
+ SonicIntSemaphore = 0; // signal that the interrupt occurred.
+ return;
+ }
+ }
+ if (InterruptStatus & INT_PKTRX) { // packet received
+ SonicStatus.ExpectedInt &= ~INT_PKTRX; // clear interrupt
+ }
+ if (InterruptStatus & INT_LCD) { // load cam interrupt
+ SonicStatus.ExpectedInt &= ~INT_LCD; // clear interrupt
+ }
+ if (SonicStatus.ExpectedInt) { // we still want another interrupt
+ return;
+ } else {
+ SonicStatus.Status=DONE;
+ SonicIntSemaphore = 0; // signal that the interrupt occurred.
+ return;
+ }
+ } else { // we got an interrupt not expected.
+ SonicStatus.InterruptID=InterruptStatus;
+ SonicStatus.TransmitControl=READ_REGISTER_USHORT(&SONIC->TransmitControl.Reg);
+ SonicStatus.Status=ERROR;
+ SonicIntSemaphore = 0; // signal that the interrupt ocurred.
+ return;
+ }
+}
+ ULONG
+SonicCheckReception(
+ )
+/*++
+
+Routine Description:
+
+ This routine compares the sent packet with the received one.
+ Makes the used Receive Descriptor available, and if the Receive Buffer
+ is full it makes the used receive resurce available.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ERROR - If errors are found
+ DONE - If no errors
+
+--*/
+{
+PUCHAR SentMsg,ReceivedMsg;
+USHORT ReceiveStatus,TransmitControl;
+ULONG PktSize,i;
+ if(CURRENT_DESCRIPTOR->InUse.Data) {
+ FwPrint("Descriptor in use\r\n");
+ SonicErrors++;
+ return ERROR;
+ }
+ ReceiveStatus=CURRENT_DESCRIPTOR->Status.Data;
+ if (ReceiveStatus & (RCR_MC | RCR_BC | RCR_COL | RCR_CRCR | RCR_FAER)) {
+ FwPrint("Receive status %lx \r\n",ReceiveStatus);
+ SonicErrors++;
+ return ERROR;
+ }
+ //
+ // Get ptr to packet and add the offset between Logical and Physical
+ // to obtain the physical ptr.
+ //
+ ReceivedMsg=(PUCHAR) (( (CURRENT_DESCRIPTOR->PktPtr1.Data << 16) |
+ (CURRENT_DESCRIPTOR->PktPtr0.Data))
+ + ReceiveBufferTranslationOffset);
+
+ SentMsg=(PUCHAR) (
+ (PhysTransmitDscr->FragPtr1.Fill << 16) |
+ PhysTransmitDscr->FragPtr0.Fill
+ );
+ PktSize=CURRENT_DESCRIPTOR->ByteCount.Data;
+ PktSize -=4; // don't check FCS field.
+ for (i=0;i<PktSize;i++) {
+ if (ReceivedMsg[i] != SentMsg[i]) {
+ FwPrint("\r\n Data mismatch, expected %02lx received %02lx \r\n",SentMsg[i],ReceivedMsg[i]);
+ SonicErrors++;
+ return ERROR;
+ }
+ }
+ //
+ // If we get here is because the packet was successfully received.
+ // Set the descriptor tables ready for the next packet.
+ //
+ if (ReceiveStatus & RCR_LPKT) { // last packet in RBA.
+ //
+ // Advance the RWP to free the used Rba again.
+ //
+ if (READ_REGISTER_USHORT(&SONIC->RWP.Reg)+sizeof(RECEIVE_RESOURCE) ==
+ READ_REGISTER_USHORT(&SONIC->REA.Reg)) {//if it's the last one
+ WRITE_REGISTER_USHORT(&SONIC->RWP.Reg,READ_REGISTER_USHORT(&SONIC->RSA.Reg));
+ // the new RWP points at the starting address.
+ } else {
+ WRITE_REGISTER_USHORT(&SONIC->RWP.Reg,READ_REGISTER_USHORT(&SONIC->RWP.Reg)+sizeof(RECEIVE_RESOURCE));
+ }
+ }
+ //
+ // Free Used Receive Descripor
+ //
+ CURRENT_DESCRIPTOR->InUse.Data=AVAILABLE; // make used desc available
+ ReceiveDscrQueue.Current=CURRENT_DESCRIPTOR->Link.Data; // First is the next
+ LAST_DESCRIPTOR->Link.Data &= NOT_EOL; // Last is not EOL any more.
+ ReceiveDscrQueue.Last=LAST_DESCRIPTOR->Link.Data; // Last is next one.
+ LAST_DESCRIPTOR->InUse.Data |= EOL; // New Last is EOL.
+ return DONE;
+}
+ VOID
+RomXTOA(
+ IN ULONG number,
+ OUT PSZ string
+ )
+/*++
+
+Routine Description:
+
+ This routine converts an ULONG to ASCII.
+ The conversion is done in HexaDecimal.
+
+Arguments:
+
+ number - Supplies the ULONG to convert.
+ string - PSZ where the result is placed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ULONG i;
+ for (i=7;i >= 0; i--) {
+ string[i]=TranslationTable[number&0xF];
+ number = number >> 4;
+ }
+ string[8]='\0';
+}
+ ULONG
+RomSonicLoopBackTest(
+ )
+/*++
+
+Routine Description:
+
+ This routine implements the SONIC loopback test for the selftest.
+ The Ethernet Controller is tested using a Loopback in the MAC.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns 0 if no errors are found.
+
+--*/
+{
+//
+// Note Packets are set to be 32 byte long so that they fit in the fifo.
+// This is done because at this point interrupts are dispatched trough
+// the Bootstrap Vector, reads from PROM take so long that the SONIC
+// will get Bus retry Errors.
+//
+ULONG i,MsgLength=MIN_DATA_LENGTH-32;
+CHAR String[64];
+ SonicErrors=0;
+ InitSonic();
+ if (SonicErrors) {
+ return SonicErrors;
+ }
+ for (i=0;i<16;i++) {
+ ComposeMessage(MsgLength,(UCHAR)i);
+ SonicStatus.ExpectedInt=INT_TXDN | INT_PKTRX;
+ // Issue the Transmit command.
+ SonicIntSemaphore=1;
+ WRITE_REGISTER_USHORT(&SONIC->Command.Reg,CR_TXP);
+ if (WaitForSonicInterrupt()) {
+ FwPrint("Timeout waiting for sonic int 2\r\n");
+ SonicErrors++;
+ return SonicErrors;
+ }
+ if (SonicStatus.Status==DONE) { // a packet has been sent and received.
+ if (SonicCheckReception()==ERROR) {
+ FwPrint(ST_RECEIVED_MSG);
+ return SonicErrors;
+ } else {
+ FwPrint(".");
+ }
+ } else {
+ SonicCheckError();
+ FwPrint("\r\nInt:%x Tx:%x",SonicStatus.InterruptID,SonicStatus.TransmitControl);
+ return SonicErrors;
+ }
+ }
+ return SonicErrors;
+}
diff --git a/private/ntos/fw/mips/sonictst.h b/private/ntos/fw/mips/sonictst.h
new file mode 100644
index 000000000..9ea0d367c
--- /dev/null
+++ b/private/ntos/fw/mips/sonictst.h
@@ -0,0 +1,246 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ sonictst.h
+
+Abstract:
+
+ This module contains the define constants for the SONIC ethernet controller
+ selftest in the jazz system.
+
+Author:
+
+ Lluis Abello (lluis) 19-Feb-1991
+
+Environment:
+
+
+Revision History:
+
+--*/
+
+#define LAN_MEMORY_ERROR 1
+#define LAN_ADDRESS_ERROR 2
+
+//
+// Transmit Control Register bit definitions
+//
+#define TCR_PTX (1 << 0)
+#define TCR_BCM (1 << 1)
+#define TCR_FU (1 << 2)
+#define TCR_PMB (1 << 3)
+#define TCR_OWC (1 << 5)
+#define TCR_EXC (1 << 6)
+#define TCR_CRSL (1 << 7)
+#define TCR_NCRS (1 << 8)
+#define TCR_DEF (1 << 9)
+#define TCR_EXD (1 << 10)
+#define TCR_EXDIS (1 << 12)
+#define TCR_CRCI (1 << 13)
+#define TCR_POWC (1 << 14)
+#define TCR_PINT (1 << 15)
+//
+// Receive Control Register
+//
+#define RCR_PRX (1 << 0) // Packet recived OK
+#define RCR_LBK (1 << 1) // Loopback packet received.
+#define RCR_FAER (1 << 2) // Frame alignament error.
+#define RCR_CRCR (1 << 3) // CRC Error
+#define RCR_COL (1 << 4) // Collision activity
+#define RCR_CRS (1 << 5) // Carrier sense activity
+#define RCR_LPKT (1 << 6) // Last packet in RBA
+#define RCR_BC (1 << 7) // Broadcast packet received
+#define RCR_MC (1 << 8) // Multicast packet received
+#define RCR_MAC (1 << 9) // MAC Loopback
+#define RCR_ENDEC (1 <<10) // ENDEC loopback
+#define RCR_TRANS (3 << 9) // Transceiver loopback
+#define RCR_AMC (1 <<11) // Accept all musticast packets
+#define RCR_PRO (1 <<12) // Physical promiscuious packets
+#define RCR_BRD (1 <<13) // Accept Broadcast packets
+#define RCR_RNT (1 <<14) // Accept Runt packets
+#define RCR_ERR (1 <<15) // Accept Packets with errors
+
+//
+// Data configuration register value.
+//
+#define DATA_CONFIGURATION 0x2439 // 0x2439
+
+//
+// Interrupt Mask Register and Interrupt Status Register bit definitions
+//
+#define INT_RFO (1 << 0) // receive fifo overrun
+#define INT_MP (1 << 1) // Missed Packed counter rollover
+#define INT_FAE (1 << 2) // Frame alignment error
+#define INT_CRC (1 << 3) // CRC tally counter rollover
+#define INT_RBAE (1 << 4) // Receive Buffer Area exceded
+#define INT_RBE (1 << 5) // Recive Buffers exhausted
+#define INT_RDE (1 << 6) // Recive descriptors exhausted
+#define INT_TC (1 << 7) // Timer complete
+#define INT_TXER (1 << 8) // Transmit error
+#define INT_TXDN (1 << 9) // Transmission done
+#define INT_PKTRX (1 << 10) // Packet received
+#define INT_PINT (1 << 11) // Programable interrupt
+#define INT_LCD (1 << 12) // Load CAM done.
+#define INT_HBL (1 << 13) // CD heartbeat lost
+#define INT_BR (1 << 14) // Bus retry
+//
+// Command register bit definitions.
+//
+#define CR_HTX (1 << 0) // Halt Transmission
+#define CR_TXP (1 << 1) // Transmit packets
+#define CR_RXDIS (1 << 2) // Receiver disable
+#define CR_RXEN (1 << 3) // receiver enable
+#define CR_STP (1 << 4) // stop timer
+#define CR_ST (1 << 5) // start timer
+#define CR_RST (1 << 7) // software reset
+#define CR_RRA (1 << 8) // read RRA
+#define CR_LCAM (1 << 9) // load CAM
+
+//
+// Resurce & Data tables structure definition.
+//
+typedef struct _SONIC_ENTRY {
+ USHORT Data; // all tables in memory
+ USHORT Fill; // trash the upper 16 bits
+ } SONIC_ENTRY;
+
+
+//
+// Receive Resource Area Format definition
+//
+
+typedef struct _RECEIVE_RESOURCE {
+ SONIC_ENTRY BufferPtr0;
+ SONIC_ENTRY BufferPtr1;
+ SONIC_ENTRY WordCount0;
+ SONIC_ENTRY WordCount1;
+ } RECEIVE_RESOURCE, * PRECEIVE_RESOURCE;
+
+//
+// Declare a variable that will point to the resource descriptor area.
+//
+PRECEIVE_RESOURCE ReceivePhysRsrc;
+PRECEIVE_RESOURCE ReceiveLogRsrc;
+//
+// Offset between physical and logical Receive Buffers to allow an easy
+// translation from logical to physical pointers to received packets.
+//
+ULONG ReceiveBufferTranslationOffset;
+
+#define RBA_SIZE 0x1000
+
+//
+// CAM_DESCRIPTOR format definition
+//
+typedef struct _CAM_DESCRIPTOR {
+ SONIC_ENTRY EntryPointer;
+ SONIC_ENTRY Port0;
+ SONIC_ENTRY Port1;
+ SONIC_ENTRY Port2;
+ } CAM_DESCRIPTOR;
+
+typedef CAM_DESCRIPTOR * PCAM_DESCRIPTOR;
+
+PCAM_DESCRIPTOR PhysCamDescriptor,LogCamDescriptor;
+
+//
+// Receive Descriptor Format definition.
+//
+typedef struct _RECEIVE_DESCRIPTOR {
+ SONIC_ENTRY Status;
+ SONIC_ENTRY ByteCount;
+ SONIC_ENTRY PktPtr0;
+ SONIC_ENTRY PktPtr1;
+ SONIC_ENTRY SeqNo;
+ SONIC_ENTRY Link;
+ SONIC_ENTRY InUse;
+ } RECEIVE_DESCRIPTOR;
+
+typedef RECEIVE_DESCRIPTOR * PRECEIVE_DESCRIPTOR;
+//
+// Receive Descriptor Field value definitions
+//
+
+#define AVAILABLE 0xFABA // Descriptor Available to SONIC
+#define IN_USE 0 // Descriptor being used by SONIC
+
+#define EOL 1 // To be ORed with the Link field to make the
+ // descriptor become the last one of the list
+#define NOT_EOL 0xFFFE // To be ANDed with the Link field to make the
+ // descriptor not be the last one of the list
+
+typedef struct _RECEIVE_DESCRIPTOR_QUEUE {
+ PRECEIVE_DESCRIPTOR Base;
+ ULONG Current;
+ ULONG Last;
+ } RECEIVE_DESCRIPTOR_QUEUE;
+
+RECEIVE_DESCRIPTOR_QUEUE ReceiveDscrQueue;
+#define CURRENT_DESCRIPTOR ((PRECEIVE_DESCRIPTOR)((ULONG) ReceiveDscrQueue.Base | ReceiveDscrQueue.Current))
+#define LAST_DESCRIPTOR ((PRECEIVE_DESCRIPTOR)((ULONG) ReceiveDscrQueue.Base | ReceiveDscrQueue.Last))
+
+//
+// Transmit Descriptor definition
+//
+
+typedef struct _TRANSMIT_DESCRIPTOR {
+ SONIC_ENTRY Status;
+ SONIC_ENTRY Config;
+ SONIC_ENTRY PktSize;
+ SONIC_ENTRY FragCount; // Must be 1. We don't need to scater
+ SONIC_ENTRY FragPtr0; // the paket in memory and this let's us define
+ SONIC_ENTRY FragPtr1; // a fixed size structure with only one pointer
+ SONIC_ENTRY FragSize; // and one size field per paket.
+ SONIC_ENTRY Link;
+ } TRANSMIT_DESCRIPTOR;
+
+typedef TRANSMIT_DESCRIPTOR * PTRANSMIT_DESCRIPTOR;
+
+PTRANSMIT_DESCRIPTOR PhysTransmitDscr;
+PTRANSMIT_DESCRIPTOR LogicalTransmitDscr;
+
+typedef struct _SONIC_DATA {
+ USHORT InterruptID;
+ USHORT ExpectedInt;
+ USHORT TransmitControl;
+ USHORT Status;
+ } SONIC_DATA,* PSONIC_DATA;
+
+volatile SONIC_DATA SonicStatus;
+//
+// Define status.
+//
+#define ERROR 1
+#define DONE 0
+//
+// Macro definition
+//
+
+#define EXPECTED_INT (InterruptStatus & SonicStatus.ExpectedInt)
+#define NO_OTHER_INT ((InterruptStatus & (~SonicStatus.ExpectedInt))==0)
+
+#define MAX_PACKET_SIZE 1520
+#define MAX_DATA_LENGTH 1500
+#define MIN_DATA_LENGTH 46
+
+
+//
+// Resources Logical & Physical addresses.
+//
+#define PHYS_RECEIVE_DSCR_ADDRESS 0xA0100000 // the lower 16 bits of both
+#define LOGICAL_RECEIVE_DSCR_ADDRESS 0x00000000 // Log & Phys add must match.
+#define RECEIVE_PHYS_RSRC_ADDRESS 0xA0101000
+#define RECEIVE_LOG_RSRC_ADDRESS 0x00001000
+#define RECEIVE_PHYS_BUFFER_ADDRESS 0xA0102000
+#define RECEIVE_LOG_BUFFER_ADDRESS 0x00002000
+#define PHYS_TRANSMIT_DSCR_ADDRESS 0xA0104000
+#define LOGICAL_TRANSMIT_DSCR_ADDRESS 0x00004000
+#define PHYS_TBA_ADDRESS 0xA0105000
+#define LOG_TBA_ADDRESS 0x00005000
+
+volatile ULONG SonicIntSemaphore;
+extern UCHAR StationAddress[6];
+ULONG SonicErrors;
diff --git a/private/ntos/fw/mips/stubs.c b/private/ntos/fw/mips/stubs.c
new file mode 100644
index 000000000..bb73f6d42
--- /dev/null
+++ b/private/ntos/fw/mips/stubs.c
@@ -0,0 +1,395 @@
+
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+
+Module Name:
+
+ stubs.c
+
+Abstract:
+
+ This module implements stub routines for the boot code.
+
+Author:
+
+ David N. Cutler (davec) 7-Nov-1990
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "ntos.h"
+#include "fwstring.h"
+
+//
+// Define global data.
+//
+
+ULONG BlDcacheFillSize = 32;
+KSPIN_LOCK KdpDebuggerLock;
+
+VOID
+KeBugCheck (
+ IN ULONG BugCheckCode
+ )
+
+/*++
+
+Routine Description:
+
+ This function crashes the system in a controlled manner.
+
+Arguments:
+
+ BugCheckCode - Supplies the reason for the bug check.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Print out the bug check code and break.
+ //
+
+ DbgPrint(ST_BUGCHECK_MSG, BugCheckCode);
+ while(TRUE) {
+ DbgBreakPoint();
+ };
+ return;
+}
+
+LARGE_INTEGER
+KeQueryPerformanceCounter (
+ OUT PLARGE_INTEGER Frequency OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is a stub for the kernel debugger and always returns a
+ value of zero.
+
+Arguments:
+
+ Frequency - Supplies an optional pointer to a variable which receives
+ the performance counter frequency in Hertz.
+
+Return Value:
+
+ A value of zero is returned.
+
+--*/
+
+{
+
+ LARGE_INTEGER Counter;
+
+ //
+ // Return the current system time as the function value.
+ //
+
+ Counter.LowPart = 0;
+ Counter.HighPart = 0;
+ return Counter;
+}
+
+VOID
+KeStallExecutionProcessor (
+ IN ULONG MicroSeconds
+ )
+
+/*++
+
+Routine Description:
+
+ This function stalls execution for the specified number of microseconds.
+
+Arguments:
+
+ MicroSeconds - Supplies the number of microseconds that execution is to be
+ stalled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ ULONG Index;
+ ULONG Limit;
+ PULONG Store;
+ ULONG Value;
+
+ //
+ // ****** begin temporary code ******
+ //
+ // This code must be replaced with a smarter version. For now it assumes
+ // an execution rate of 40,000,000 instructions per second and 4 instructions
+ // per iteration.
+ //
+
+ Store = &Value;
+ Limit = (MicroSeconds * 40 / 4);
+ for (Index = 0; Index < Limit; Index += 1) {
+ *Store = Index;
+ }
+ return;
+}
+
+BOOLEAN
+KeFreezeExecution (
+ IN PKTRAP_FRAME TrapFrame,
+ IN PEXCEPTION_RECORD ExceptionRecord
+ )
+
+/*++
+
+Routine Description:
+
+ This function freezes the execution of all other processors in the host
+ configuration and then returns to the caller. It is intended for use by
+ the kernel debugger.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Wether interrupts were previously enabled.
+
+--*/
+
+{
+ return FALSE;
+}
+
+VOID
+KeThawExecution (
+ IN KIRQL Irql
+ )
+
+/*++
+
+Routine Description:
+
+ This function unfreezes the execution of all other processors in the host
+ configuration and then returns to the caller. It is intended for use by
+ the kernel debugger.
+
+Arguments:
+
+ Irql - Supplies the level that the IRQL is to be lowered to after having
+ unfrozen the execution of all other processors.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ return;
+}
+
+PVOID
+MmDbgReadCheck (
+ IN PVOID VirtualAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a virtual address
+ which is valid (mapped) for read access.
+
+Arguments:
+
+ VirtualAddress - Supplies the virtual address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+
+ return VirtualAddress;
+}
+
+PVOID
+MmDbgTranslatePhysicalAddress (
+ IN PHYSICAL_ADDRESS PhysicalAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a physical address
+ which is valid (mapped).
+
+Arguments:
+
+ PhysicalAddress - Supplies the physical address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+
+ return (PVOID)PhysicalAddress.LowPart;
+}
+
+PVOID
+MmDbgWriteCheck (
+ IN PVOID VirtualAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the phyiscal address for a virtual address
+ which is valid (mapped) for write access.
+
+Arguments:
+
+ VirtualAddress - Supplies the virtual address to check.
+
+Return Value:
+
+ Returns NULL if the address is not valid or readable, otherwise
+ returns the physical address of the corresponding virtual address.
+
+--*/
+
+{
+ return VirtualAddress;
+}
+
+VOID
+RtlAssert(
+ IN PVOID FailedAssertion,
+ IN PVOID FileName,
+ IN ULONG LineNumber,
+ IN PCHAR Message OPTIONAL
+ )
+{
+
+ DbgPrint( ST_ASSERT_MSG );
+ while (TRUE) {
+ DbgBreakPoint();
+ }
+}
+
+VOID
+FwpFreeStub(
+ IN PVOID Buffer
+ )
+{
+}
+
+VOID
+FwpReservedRoutine(
+ VOID
+ )
+
+{
+ FwPrint(ST_UNIMPLEMENTED_ROUTINE_MSG);
+ return;
+}
+
+VOID
+RtlInitString(
+ OUT PSTRING DestinationString,
+ IN PCSZ SourceString OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ The RtlInitString function initializes an NT counted string.
+ The DestinationString is initialized to point to the SourceString
+ and the Length and MaximumLength fields of DestinationString are
+ initialized to the length of the SourceString, which is zero if
+ SourceString is not specified.
+
+Arguments:
+
+ DestinationString - Pointer to the counted string to initialize
+
+ SourceString - Optional pointer to a null terminated string that
+ the counted string is to point to.
+
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ DestinationString->Length = 0;
+ DestinationString->Buffer = (PCHAR)SourceString;
+ if (ARGUMENT_PRESENT( SourceString )) {
+ while (*SourceString++) {
+ DestinationString->Length++;
+ }
+
+ DestinationString->MaximumLength = (SHORT)(DestinationString->Length+1);
+ }
+ else {
+ DestinationString->MaximumLength = 0;
+ }
+}
+
+
+BOOLEAN
+KiTryToAcquireSpinLock (
+ IN PKSPIN_LOCK NotUsed
+ )
+{
+ return TRUE;
+}
+
+VOID
+KeSweepIcache (
+ IN BOOLEAN AllProcessors
+ )
+{
+ HalSweepIcache();
+ HalSweepDcache();
+}
+
+VOID
+KeFlushIoBuffers (
+ IN PMDL Mdl,
+ IN BOOLEAN ReadOperation,
+ IN BOOLEAN DmaOperation
+ )
+
+{
+ HalFlushIoBuffers (Mdl,ReadOperation,DmaOperation);
+}
diff --git a/private/ntos/fw/mips/subrout.s b/private/ntos/fw/mips/subrout.s
new file mode 100644
index 000000000..efddb59dc
--- /dev/null
+++ b/private/ntos/fw/mips/subrout.s
@@ -0,0 +1,63 @@
+// ----------------------------------------------------------------------------
+// Copyright (c) 1992 Olivetti
+//
+// File: subrout.s
+//
+// Description: Assembly subroutines used throughout the ROM.
+// ----------------------------------------------------------------------------
+
+//
+// include header files
+//
+
+#include <ksmips.h>
+
+ .text
+ .set noreorder
+
+
+// ----------------------------------------------------------------------------
+// PROCEDURE: StatusReg:
+//
+// DESCRIPTION: This function updates the CPU status register
+// ( CPU0 reg. 12 ).
+// The register is "&" with a0 and "|" with a1.
+// The old register value is returned to the calling
+// routine in v0.
+//
+//
+// ARGUMENTS: a0 & with Status register
+// a1 | with Status register
+//
+// RETURN: v0 Old Status register value
+//
+// ASSUMPTIONS: none
+//
+// CALLS: none
+//
+// GLOBALS: none
+//
+// NOTES: none
+// ----------------------------------------------------------------------------
+//
+LEAF_ENTRY(StatusReg)
+
+ .set noat
+
+//
+// The first argument is "&" and the second is "|" with the status register.
+//
+
+ mfc0 v0, psr // read status register
+ nop // required by mfc before using v0
+ nop // to avoid hazards
+ move t0, v0 // make a copy of it
+ and t0, t0, a0 // "&" with 1st parameter
+ or t0, t0, a1 // "|" with 2nd parameter
+ mtc0 t0, psr // write status register
+ nop
+ nop
+ j ra // return
+ nop // required by "j ra"
+
+.end StatusReg
diff --git a/private/ntos/fw/mips/x4trap.s b/private/ntos/fw/mips/x4trap.s
new file mode 100644
index 000000000..f567e29d3
--- /dev/null
+++ b/private/ntos/fw/mips/x4trap.s
@@ -0,0 +1,1068 @@
+#if defined(JAZZ) && defined(R4000)
+
+// TITLE("Interrupt and Exception Processing")
+//++
+//
+// Copyright (c) 1991 Microsoft Corporation
+//
+// Module Name:
+//
+// j4trap.s
+//
+// Abstract:
+//
+// This module implements the code necessary to field and process MIPS
+// interrupt and exception conditions during bootstrap.
+//
+// Author:
+//
+// David N. Cutler (davec) 21-Apr-1991
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+
+ SBTTL("Constant Value Definitions")
+//++
+//
+// The following are definitions of constants used in this module.
+//
+//--
+
+#define PSR_MASK (~((0x3 << PSR_KSU) | (1 << PSR_EXL))) // PSR exception mask
+
+//++
+//
+// Define dummy data allocation.
+//
+//--
+
+ .data
+ .space 4 //
+SavedK1Address:
+ .space 4 // address where to save k1 to return to fw.
+
+ SBTTL("General Exception Vector Routine")
+//++
+//
+// Routine Description:
+//
+// This routine is entered as the result of a general exception. The reason
+// for the exception is contained in the cause register. When this routine
+// is entered, interrupts are disabled.
+//
+// All exception that occur during the bootstrap process are treated as
+// if a breakpoint had occurred. This ultimately causes either the kernel
+// debugger or a stub routine provided by the bootstrap itself to be
+// invoked.
+//
+// The address of this routine is copied to the GEV in the SPB
+// so that the firmware jumps to this routine when a GeneralException
+// occurres. This routine must return to the address pointed by k1.
+// and leave the address where the firmware must return from the
+// exception in k0.
+//
+//
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KiGeneralException)
+ //
+ // No TLB Miss is supposed to occurr during the boot process
+ // The TbMiss handler is just the same general exception handler.
+ //
+ ALTERNATE_ENTRY(KiTbMiss)
+ START_REGION(KiGeneralExceptionStartAddress)
+
+ .set noreorder
+ .set noat
+ la k0,10f // transfer immediately to physical
+ j k0 //
+ nop //
+
+10: subu k0,sp,TrapFrameLength // allocate trap frame
+ sw sp,TrIntSp(k0) // save integer register sp
+ move sp,k0 // set new stack pointer
+ la k0,SavedK1Address // get address of where to save k1
+ sw k1,0(k0) // save firmware return address
+ sw gp,TrIntGp(sp) // save integer register gp
+ sw s8,TrIntS8(sp) // save integer register s8
+ sw ra,TrIntRa(sp) // save integer register ra
+ mfc0 s8,cause // get cause of exception
+ mfc0 k0,psr // get current processor status
+ mfc0 k1,epc // get exception PC
+ sw k0,TrPsr(sp) // save current PSR
+ sw k1,TrFir(sp) // save exception PC
+ bgez s8,20f // if gez, exception not in delay slot
+ move s8,sp // set address of trap frame
+ addu k1,k1,4 // compute address of exception
+20: j KiBreakpointException // finish in breakpoint code
+ nop // fill delay slot
+ .set at
+ .set reorder
+
+ END_REGION(KiGeneralExceptionEndAddress)
+
+ .end KiGeneralException
+
+ SBTTL("Breakpoint Dispatch")
+//++
+//
+// Routine Description:
+//
+// The following code is never executed. Its purpose is to allow the
+// kernel debugger to walk call frames backwards through an exception,
+// to support unwinding through exceptions for system services, and to
+// support get/set user context.
+//
+//--
+
+ NESTED_ENTRY(KiBreakpointDispatch, TrapFrameLength, zero);
+
+ .set noreorder
+ .set noat
+ sw sp,TrIntSp(sp) // save stack pointer
+ sw ra,TrIntRa(sp) // save return address
+ sw ra,TrFir(sp) // save return address
+ sw s8,TrIntS8(sp) // save frame pointer
+ sw gp,TrIntGp(sp) // save general pointer
+ move s8,sp // set frame pointer
+ .set at
+ .set reorder
+
+ PROLOGUE_END
+
+//++
+//
+// Routine Description:
+//
+// Control reaches here when a breakpoint exception code is read from the
+// cause register. When this routine is entered, interrupts are disabled.
+//
+// The function of this routine is to raise a breakpoint exception.
+//
+// N.B. Integer register v1 is not usuable in the first instuction of the
+// routine.
+//
+// Arguments:
+//
+// k0 - Supplies the current PSR with the EXL bit set.
+// k1 - Supplies the address of the faulting instruction.
+// gp - Supplies a pointer to the system short data area.
+// s8 - Supplies a pointer to the trap frame.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ ALTERNATE_ENTRY(KiBreakpointException)
+
+ GENERATE_TRAP_FRAME // save volatile machine state
+
+ addu a0,s8,TrExceptionRecord // compute exception record address
+ sw k1,ErExceptionAddress(a0) // save address of exception
+ lw t0,0(k1) // get actual breakpoint instruction
+
+ .set noreorder
+ .set noat
+ mfc0 k0,cause // get cause of exception
+ .set at
+ .set reorder
+
+ li t1,XCODE_BREAKPOINT // get exception code for breakpoint
+ li t2,STATUS_BREAKPOINT // set exception status code
+ and k0,k0,R4000_XCODE_MASK // isolate exception code
+ beq k0,t1,10f // if eq, breakpoint
+ move t2,k0 // set status to cause value
+10: sw t0,ErExceptionInformation(a0) // save breakpoint instruction
+ sw t2,ErExceptionCode(a0) //
+ sw zero,ErExceptionFlags(a0) // set exception flags
+ sw zero,ErExceptionRecord(a0) // set associated record
+ sw zero,ErNumberParameters(a0) // set number of parameters
+ jal KiExceptionDispatch // join common code
+ b 10b // dummy
+
+ .end KiBreakpointDispatch
+
+ SBTTL("Exception Dispatch")
+//++
+//
+// Routine Desription:
+//
+// Control is transfered to this routine to call the exception
+// dispatcher to resolve an exception.
+//
+// Arguments:
+//
+// a0 - Supplies a pointer to an exception record.
+//
+// s8 - Supplies a pointer to a trap frame.
+//
+// Return Value:
+//
+// There is no return from this routine.
+//
+//--
+
+ NESTED_ENTRY(KiExceptionDispatch, ExceptionFrameLength, zero)
+
+ subu sp,sp,ExceptionFrameLength // allocate exception frame
+ sw ra,ExIntRa(sp) // save return address
+ sw s0,ExIntS0(sp) // save integer registers s0 - s7
+ sw s1,ExIntS1(sp) //
+ sw s2,ExIntS2(sp) //
+ sw s3,ExIntS3(sp) //
+ sw s4,ExIntS4(sp) //
+ sw s5,ExIntS5(sp) //
+ sw s6,ExIntS6(sp) //
+ sw s7,ExIntS7(sp) //
+ sdc1 f20,ExFltF20(sp) // save floating registers f20 - f31
+ sdc1 f22,ExFltF22(sp) //
+ sdc1 f24,ExFltF24(sp) //
+ sdc1 f26,ExFltF26(sp) //
+ sdc1 f28,ExFltF28(sp) //
+ sdc1 f30,ExFltF30(sp) //
+
+ PROLOGUE_END
+
+//
+// Call the exception dispatcher.
+//
+
+ move a1,sp // set exception frame address
+ move a2,s8 // set trap frame address
+ move a3,zero // set previous processor mode
+ li t0,TRUE // set first chance TRUE
+ sw t0,ExArgs + (4 * 4)(sp) //
+ jal KiDispatchException // call exception dispatcher
+
+//
+// Restore the nonvolatile registers.
+//
+
+ lw s0,ExIntS0(sp) // restore integer registers s0 - s7
+ lw s1,ExIntS1(sp) //
+ lw s2,ExIntS2(sp) //
+ lw s3,ExIntS3(sp) //
+ lw s4,ExIntS4(sp) //
+ lw s5,ExIntS5(sp) //
+ lw s6,ExIntS6(sp) //
+ lw s7,ExIntS7(sp) //
+ ldc1 f20,ExFltF20(sp) // restore floating registers f20 - f31
+ ldc1 f22,ExFltF22(sp) //
+ ldc1 f24,ExFltF24(sp) //
+ ldc1 f26,ExFltF26(sp) //
+ ldc1 f28,ExFltF28(sp) //
+ ldc1 f30,ExFltF30(sp) //
+
+//
+// Exit from the exception.
+//
+
+ lw t0,TrPsr(s8) // get previous processor status
+ lw gp,TrIntGp(s8) // restore integer register gp
+ li t3,(1 << PSR_CU1) | (1 << PSR_EXL) // ****** r4000 errata
+
+ .set noreorder
+ .set noat
+ mtc0 t3,psr // ****** r4000 errata
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ mtc0 t0,psr // disable interrupts
+ nop // ****** r4000 errata
+ jal KiRestoreTrapFrame // restore volatile state
+ lw AT,TrIntAt(s8) // restore integer register at
+ move sp,s8 // trim stack to trap frame
+ la k0,SavedK1Address // get address of where to save k1
+ lw k1,(k0) // save firmware return address
+ lw k0,TrFir(sp) // get continuation address
+ lw s8,TrIntS8(sp) // restore integer register s8
+ lw ra,TrIntRa(sp) // restore return address
+ j k1 // return to firmware
+ lw sp,TrIntSp(sp) // restore stack pointer
+ .set at
+ .set reorder
+
+ .end KiExceptionDispatch
+
+ SBTTL("Fill Fixed Translation Buffer Entry")
+//++
+//
+// VOID
+// KeFillFixedEntryTb (
+// IN HARDWARE_PTE Pte[],
+// IN PVOID Virtual,
+// IN ULONG Index
+// )
+//
+// Routine Description:
+//
+// This function fills a fixed translation buffer entry.
+//
+// Arguments:
+//
+// Pte (a0) - Supplies a pointer to the page table entries that are to be
+// written into the TB.
+//
+// Virtual (a1) - Supplies the virtual address of the entry that is to
+// be filled in the translation buffer.
+//
+// Index (a2) - Supplies the index where the TB entry is to be written.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KeFillFixedEntryTb)
+
+ lw t0,0(a0) // get first PTE value
+ lw t1,4(a0) // get second PTE value
+
+ DISABLE_INTERRUPTS(t2) // disable interrupts
+
+ .set noreorder
+ .set noat
+ mfc0 t3,entryhi // get current PID and VPN2
+ srl a1,a1,ENTRYHI_VPN2 // isolate VPN2 of virtual address
+ sll a1,a1,ENTRYHI_VPN2 //
+ and t3,t3,0xff << ENTRYHI_PID // isolate current PID
+ or a1,t3,a1 // merge PID with VPN2 of virtual address
+ mtc0 a1,entryhi // set VPN2 and PID for probe
+ mtc0 t0,entrylo0 // set first PTE value
+ mtc0 t1,entrylo1 // set second PTE value
+ mtc0 a2,index // set TB entry index
+ nop // 1 cycle hazzard
+ tlbwi // overwrite indexed TB entry
+ nop // 3 cycle hazzard
+ .set at
+ .set reorder
+
+ ENABLE_INTERRUPTS(t2) // enable interrupts
+
+ j ra // return
+
+ .end KeFillFixedEntryTb
+
+ SBTTL("Flush Entire Translation Buffer")
+//++
+//
+// VOID
+// KiFlushEntireTb (
+// )
+//
+// Routine Description:
+//
+// This function flushes the random part of the translation buffer.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KiFlushEntireTb)
+
+ b KiFlushRandomTb // execute common code
+
+ .end KiFlushEntireTb
+
+ SBTTL("Flush Fixed Translation Buffer Entries")
+//++
+//
+// VOID
+// KiFlushFixedTb (
+// )
+//
+// Routine Description:
+//
+// This function is called to flush all the fixed entries from the
+// translation buffer.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KiFlushFixedTb)
+
+ li t0,FIXED_BASE // set base index of fixed TB entries
+ li t3,FIXED_ENTRIES // set number of fixed TB entries
+ b KiFlushTb //
+
+ .end KiFlushFixedTb
+
+ SBTTL("Flush Random Translation Buffer Entries")
+//++
+//
+// VOID
+// KiFlushRandomTb (
+// )
+//
+// Routine Description:
+//
+// This function is called to flush all the random entries from the TB.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KiFlushRandomTb)
+
+ li t0,FIXED_ENTRIES // set base index of random TB entries
+ li t3,(48 - FIXED_ENTRIES) // set number of random TB entries
+
+ ALTERNATE_ENTRY(KiFlushTb)
+
+ li t4,KSEG0_BASE // set high part of TB entry
+
+ DISABLE_INTERRUPTS(t2) // disable interrupts
+
+ .set noreorder
+ .set noat
+ addu t3,t0,t3 // set index of highest entry + 1
+ sll t0,t0,INDEX_INDEX // shift starting index into position
+ sll t3,t3,INDEX_INDEX // shift ending index into position
+ mfc0 t1,entryhi // save contents of entryhi
+ mtc0 zero,entrylo0 // set low part of TB entry
+ mtc0 zero,entrylo1 //
+ mtc0 t4,entryhi //
+ mtc0 t0,index // set TB entry index
+10: addu t0,t0,1 //
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ tlbwi // write TB entry
+ bne t0,t3,10b // if ne, more entries to flush
+ mtc0 t0,index // set TB entry index
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ mtc0 t1,entryhi // restore contents of entryhi
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ .set at
+ .set reorder
+
+ ENABLE_INTERRUPTS(t2) // enable interrupts
+
+ j ra // return
+
+ .end KiFlushRandomTb
+
+ SBTTL("Flush Single Translation Buffer Entry")
+//++
+//
+// VOID
+// KiFlushSingleTb (
+// IN BOOLEAN Invalid,
+// IN PVOID Virtual
+// )
+//
+// Routine Description:
+//
+// This function flushes a single entry from the translation buffer.
+//
+// Arguments:
+//
+// Invalid (a0) - Supplies a boolean variable that determines the reason
+// that the TB entry is being flushed.
+//
+// Virtual (a1) - Supplies the virtual address of the entry that is to
+// be flushed from the translation buffer.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KiFlushSingleTb)
+
+ DISABLE_INTERRUPTS(t0) // disable interrupts
+
+ .set noreorder
+ .set noat
+ srl t1,a1,ENTRYHI_VPN2 // clear all but VPN2 of virtual address
+ mfc0 t2,entryhi // get current PID and VPN2
+ sll t1,t1,ENTRYHI_VPN2 //
+ and t2,t2,0xff << ENTRYHI_PID // isolate current PID
+ or t1,t1,t2 // merge PID with VPN2 of virtual address
+ mtc0 t1,entryhi // set VPN2 and PID for probe
+ nop // 3 cycle hazzard
+ nop //
+ nop //
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ tlbp // probe for entry in TB
+ nop // 2 cycle hazzard
+ nop //
+ mfc0 t3,index // read result of probe
+ nop // 1 cycle hazzard
+ bltz t3,30f // if ltz, entry is not in TB
+ sll t1,a1,0x1f - (ENTRYHI_VPN2 - 1) // shift low bit of VPN into sign
+ bltzl t1,10f // if ltz, invalidate second PTE
+ mtc0 zero,entrylo1 // clear second PTE for flush
+ mtc0 zero,entrylo0 // clear first PTE for flush
+10: nop // 1 cycle hazzard
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ tlbwi // overwrite index TB entry
+ nop // 3 cycle hazzard
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ .set at
+ .set reorder
+
+30: ENABLE_INTERRUPTS(t0) // enable interrupts
+
+ j ra // return
+
+ .end KiFlushSingleTb
+
+ SBTTL("Probe Tb Entry")
+//++
+//
+// ULONG
+// KiProbeEntryTb (
+// IN PVOID VirtualAddress
+// )
+//
+// Routine Description:
+//
+// This function is called to determine if a specified entry is valid
+/// and within the fixed portion of the TB.
+//
+// Arguments:
+//
+// VirtualAddress - Supplies the virtual address to probe.
+//
+// Return Value:
+//
+// A value of TRUE is returned if the specified entry is valid and within
+// the fixed part of the TB. Otherwise, a value of FALSE is returned.
+//
+//--
+
+ LEAF_ENTRY(KiProbeEntryTb)
+
+ DISABLE_INTERRUPTS(t0) // disable interrupts
+
+
+ .set noreorder
+ .set noat
+ srl t1,a0,ENTRYHI_VPN2 // clear all but VPN2 of virtual address
+ mfc0 t2,entryhi // get current PID and VPN2
+ sll t1,t1,ENTRYHI_VPN2 //
+ and t2,t2,0xff << ENTRYHI_PID // isolate current PID
+ or t1,t1,t2 // merge PID with VPN2 of virtual address
+ mtc0 t1,entryhi // set VPN2 and PID for probe
+ nop // 3 cycle hazzard
+ nop //
+ nop //
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ tlbp // probe for entry in TB
+ nop // 2 cycle hazzard
+ nop //
+ mfc0 t2,index // read result of probe
+ nop // 1 cycle hazzard
+ bltz t2,20f // if ltz, entry is not in TB
+ li v0,FALSE // set to return failure
+ tlbr // read entry from TB
+ nop // 3 cycle hazzard
+ nop //
+ nop //
+ nop // ****** r4000 errata
+ nop // ****** r4000 errata
+ sll t1,a0,0x1f - (ENTRYHI_VPN2 - 1) // shift low bit of VPN into sign
+ bltzl t1,10f // if ltz, check second PTE
+ mfc0 t1,entrylo1 // get second PTE for probe
+ mfc0 t1,entrylo0 // get first PTE for probe
+10: nop // 1 cycle hazzard
+ sll t1,t1,0x1f - ENTRYLO_V // shift valid bit into sign position
+ bgez t1,20f // if geq, entry is not valid
+ srl t2,INDEX_INDEX // isolate index
+ and t2,t2,0x3f //
+ sltu v0,t2,FIXED_ENTRIES // check if entry in fixed part of TB
+ .set at
+ .set reorder
+
+20: ENABLE_INTERRUPTS(t0) // enable interrupts
+
+ .end KiProbeEntryTb
+
+ SBTTL("Read Tb Entry")
+//++
+//
+// VOID
+// KiReadEntryTb (
+// IN ULONG Index,
+// OUT PULONG EntryLo[],
+// OUT PULONG EntryHi
+// )
+//
+// Routine Description:
+//
+// This function is called to read an entry from the TB.
+//
+// Arguments:
+//
+// Index - Supplies the index of the entry to read.
+//
+// entrylo - Supplies a pointer to a array that receives the first and
+// second TB entry values.
+//
+// EntryHi - Supplies a pointer to a variable that receives the high
+// part of the TB entry.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KiReadEntryTb)
+
+ DISABLE_INTERRUPTS(t0) // disable interrupts
+
+ .set noreorder
+ .set noat
+ sll a0,INDEX_INDEX // shift index into position
+ mfc0 t1,entryhi // save entry high register
+ mtc0 a0,index // set TB entry index
+ nop //
+ nop // ****** r4000 errate
+ nop // ****** r4000 errate
+ nop // ****** r4000 errate
+ nop // ****** r4000 errate
+ tlbr // read entry from TB
+ nop // 3 cycle hazzard
+ nop //
+ nop //
+ nop // ****** r4000 errate
+ nop // ****** r4000 errate
+ mfc0 t2,entrylo0 // save first PTE value
+ mfc0 t3,entrylo1 // save second PTE value
+ mfc0 t4,entryhi // save entry high register
+ mtc0 t1,entryhi // restore entry high register
+ nop // ****** r4000 errate
+ nop // ****** r4000 errate
+ nop // ****** r4000 errate
+ nop // ****** r4000 errate
+ nop // ****** r4000 errate
+ .set at
+ .set reorder
+
+ ENABLE_INTERRUPTS(t0) // enable interrupts
+
+ sw t2,0(a1) // set first PTE value
+ sw t3,4(a1) // set second PTE value
+ sw t4,0(a2) // set entry high register value
+ j ra // return
+
+ .end KiReadEntryTb
+
+ SBTTL("Flush Write Buffer")
+//++
+//
+// VOID
+// KeFlushWriteBuffer (
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function flushes the write buffer on the current processor.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KeFlushWriteBuffer)
+
+ j ra // return
+
+ .end KeFlushWritebuffer
+
+//++
+//
+// BOOLEAN
+// KiDisableInterrupts (
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function disables interrupts and returns whether interrupts
+// were previously enabled.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// A boolean value that determines whether interrupts were previously
+// enabled (TRUE) or disabled(FALSE).
+//
+//--
+
+ LEAF_ENTRY(KiDisableInterrupts)
+
+ .set noreorder
+ .set noat
+
+ mfc0 t0,psr // get current processor status
+ li t1,~(1 << PSR_IE) // set interrupt enable mask
+ and t2,t1,t0 // clear interrupt enable
+ mtc0 t2,psr // disable interrupts
+ and v0,t0,1 << PSR_IE // iosolate current interrupt enable
+ srl v0,v0,PSR_IE //
+
+ .set at
+ .set reorder
+
+ j ra // return
+
+ .end KiDisableInterrupts
+
+ SBTTL("Restore Interrupts")
+//++
+//
+// VOID
+// KiRestoreInterrupts (
+// IN BOOLEAN Enable
+// )
+//
+// Routine Description:
+//
+// This function restores the interrupt enable that was returned by
+// the disable interrupts function.
+//
+// Arguments:
+//
+// Enable (a0) - Supplies the interrupt enable value.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KiRestoreInterrupts)
+
+ .set noreorder
+ .set noat
+
+ mfc0 t0,psr // get current processor status
+ sll t1,a0,PSR_IE // shift previous enable into position
+ or t1,t1,t0 // merge previous enable
+ mtc0 t1,psr // restore previous interrupt enable
+ nop //
+
+ .set at
+ .set reorder
+
+ j ra // return
+
+ .end KiRestoreInterrupts
+
+
+ SBTTL("Generate Trap Frame")
+//++
+//
+// Routine Desription:
+//
+// This routine is called to save the volatile integer and floating
+// registers in a trap frame.
+//
+// N.B. This routine uses a special argument passing mechanism and destroys
+// no registers. It is assumed that integer register AT is saved by the
+// caller.
+//
+// Arguments:
+//
+// s8 - Supplies a pointer to the base of an trap frame.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KiGenerateTrapFrame)
+
+ sw v0,TrIntV0(s8) // save integer register v0
+ sw v1,TrIntV1(s8) // save integer register v1
+ mflo v1 // save lo integer register
+ sw v1,TrIntLo(s8) //
+ mfhi v1 // save hi integer register
+ sw v1,TrIntHi(s8) //
+ lw v1,TrIntV1(s8) // restore integer register v1
+ sw a0,TrIntA0(s8) // save integer registers a0 - a3
+ sw a1,TrIntA1(s8) //
+ sw a2,TrIntA2(s8) //
+ sw a3,TrIntA3(s8) //
+ sw t0,TrIntT0(s8) // save integer registers t0 - t9
+ sw t1,TrIntT1(s8) //
+ sw t2,TrIntT2(s8) //
+ sw t3,TrIntT3(s8) //
+ sw t4,TrIntT4(s8) //
+ sw t5,TrIntT5(s8) //
+ sw t6,TrIntT6(s8) //
+ sw t7,TrIntT7(s8) //
+ sw t8,TrIntT8(s8) //
+ sw t9,TrIntT9(s8) //
+
+#if defined(R3000)
+
+ swc1 f0,TrFltF0(s8) // save floating register f0
+
+#endif
+
+#if defined(R4000)
+
+ sdc1 f0,TrFltF0(s8) // save floating register f0
+
+#endif
+
+ b KiSaveVolatileFloatState // save remainder of state
+
+ .end KiGenerateTrapFrame
+
+ SBTTL("Restore Trap Frame")
+//++
+//
+// Routine Description:
+//
+// This routine is called to restore the volatile integer and floating
+// registers from a trap frame.
+//
+// N.B. This routine uses a special argument passing mechanism and destroys
+// no registers. It is assumed that integer register AT is restored by
+// the caller.
+//
+// Arguments:
+//
+// sp - Supplies a pointer to an exception frame.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KiRestoreTrapFrame)
+
+ lw v0,TrIntV0(s8) // restore integer register v0
+ lw v1,TrIntV1(s8) // restore integer register v1
+ lw a0,TrIntA0(s8) // restore integer registers a0 - a3
+ lw a1,TrIntA1(s8) //
+ lw a2,TrIntA2(s8) //
+ lw a3,TrIntA3(s8) //
+ lw t0,TrIntLo(s8) // restore lo and hi integer registers
+ lw t1,TrIntHi(s8) //
+ mtlo t0 //
+ mthi t1 //
+ lw t0,TrIntT0(s8) // restore integer registers t0 - t9
+ lw t1,TrIntT1(s8) //
+ lw t2,TrIntT2(s8) //
+ lw t3,TrIntT3(s8) //
+ lw t4,TrIntT4(s8) //
+ lw t5,TrIntT5(s8) //
+ lw t6,TrIntT6(s8) //
+ lw t7,TrIntT7(s8) //
+ lw t8,TrIntT8(s8) //
+ lw t9,TrIntT9(s8) //
+
+#if defined(R3000)
+
+ lwc1 f0,TrFltF0(s8) // restore floating register f0
+
+#endif
+
+#if defined(R4000)
+
+ ldc1 f0,TrFltF0(s8) // restore floating register f0
+
+#endif
+
+ b KiRestoreVolatileFloatState // restore remainder of state
+
+ .end KiRestoreTrapFrame
+
+
+ SBTTL("Save Volatile Floating Registers")
+//++
+//
+// Routine Desription:
+//
+// This routine is called to save the volatile floating registers.
+//
+// N.B. This routine uses a special argument passing mechanism and destroys
+// no registers. It is assumed that floating register f0 is saved by the
+// caller.
+//
+// Arguments:
+//
+// s8 - Supplies a pointer to a trap frame.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KiSaveVolatileFloatState)
+
+#if defined(R3000)
+
+ swc1 f1,TrFltF1(s8) // save floating register f1 - f19
+ swc1 f2,TrFltF2(s8) //
+ swc1 f3,TrFltF3(s8) //
+ swc1 f4,TrFltF4(s8) //
+ swc1 f5,TrFltF5(s8) //
+ swc1 f6,TrFltF6(s8) //
+ swc1 f7,TrFltF7(s8) //
+ swc1 f8,TrFltF8(s8) //
+ swc1 f9,TrFltF9(s8) //
+ swc1 f10,TrFltF10(s8) //
+ swc1 f11,TrFltF11(s8) //
+ swc1 f12,TrFltF12(s8) //
+ swc1 f13,TrFltF13(s8) //
+ swc1 f14,TrFltF14(s8) //
+ swc1 f15,TrFltF15(s8) //
+ swc1 f16,TrFltF16(s8) //
+ swc1 f17,TrFltF17(s8) //
+ swc1 f18,TrFltF18(s8) //
+ swc1 f19,TrFltF19(s8) //
+
+#endif
+
+#if defined(R4000)
+
+ sdc1 f2,TrFltF2(s8) // save floating register f2 - f19
+ sdc1 f4,TrFltF4(s8) //
+ sdc1 f6,TrFltF6(s8) //
+ sdc1 f8,TrFltF8(s8) //
+ sdc1 f10,TrFltF10(s8) //
+ sdc1 f12,TrFltF12(s8) //
+ sdc1 f14,TrFltF14(s8) //
+ sdc1 f16,TrFltF16(s8) //
+ sdc1 f18,TrFltF18(s8) //
+
+#endif
+
+ j ra // return
+
+ .end KiSaveVolatileFloatState)
+
+ SBTTL("Restore Volatile Floating Registers")
+//++
+//
+// Routine Desription:
+//
+// This routine is called to restore the volatile floating registers.
+//
+// N.B. This routine uses a special argument passing mechanism and destroys
+// no registers. It is assumed that floating register f0 is restored by
+// the caller.
+//
+// Arguments:
+//
+// s8 - Supplies a pointer to a trap frame.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KiRestoreVolatileFloatState)
+
+#if defined(R3000)
+
+ lwc1 f1,TrFltF1(s8) // restore floating registers f1 - f19
+ lwc1 f2,TrFltF2(s8) //
+ lwc1 f3,TrFltF3(s8) //
+ lwc1 f4,TrFltF4(s8) //
+ lwc1 f5,TrFltF5(s8) //
+ lwc1 f6,TrFltF6(s8) //
+ lwc1 f7,TrFltF7(s8) //
+ lwc1 f8,TrFltF8(s8) //
+ lwc1 f9,TrFltF9(s8) //
+ lwc1 f10,TrFltF10(s8) //
+ lwc1 f11,TrFltF11(s8) //
+ lwc1 f12,TrFltF12(s8) //
+ lwc1 f13,TrFltF13(s8) //
+ lwc1 f14,TrFltF14(s8) //
+ lwc1 f15,TrFltF15(s8) //
+ lwc1 f16,TrFltF16(s8) //
+ lwc1 f17,TrFltF17(s8) //
+ lwc1 f18,TrFltF18(s8) //
+ lwc1 f19,TrFltF19(s8) //
+
+#endif
+
+#if defined(R4000)
+
+ ldc1 f2,TrFltF2(s8) // restore floating registers f2 - f19
+ ldc1 f4,TrFltF4(s8) //
+ ldc1 f6,TrFltF6(s8) //
+ ldc1 f8,TrFltF8(s8) //
+ ldc1 f10,TrFltF10(s8) //
+ ldc1 f12,TrFltF12(s8) //
+ ldc1 f14,TrFltF14(s8) //
+ ldc1 f16,TrFltF16(s8) //
+ ldc1 f18,TrFltF18(s8) //
+
+#endif
+
+ j ra // return
+
+ .end KiRestoreVolatileFloatState
+#endif
diff --git a/private/ntos/fw/mips/xxfonts.c b/private/ntos/fw/mips/xxfonts.c
new file mode 100644
index 000000000..bd949e09b
--- /dev/null
+++ b/private/ntos/fw/mips/xxfonts.c
@@ -0,0 +1,1661 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ xxfonts.c
+
+Abstract:
+
+ This module contains the font tables to display characters in a frame
+ buffer.
+
+Author:
+
+ David N. Cutler (davec) 27-Apr-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+
+unsigned char FwUsFont2[1536] = {
+
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 ! */
+ 0X00, /* 00000000 ! */
+ 0X08, /* 00001000 ! */
+ 0X08, /* 00001000 ! */
+ 0X08, /* 00001000 ! */
+ 0X08, /* 00001000 ! */
+ 0X08, /* 00001000 ! */
+ 0X08, /* 00001000 ! */
+ 0X08, /* 00001000 ! */
+ 0X08, /* 00001000 ! */
+ 0X00, /* 00000000 ! */
+ 0X08, /* 00001000 ! */
+ 0X00, /* 00000000 ! */
+ 0X00, /* 00000000 ! */
+ 0X00, /* 00000000 ! */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 " */
+ 0X00, /* 00000000 " */
+ 0X24, /* 00100100 " */
+ 0X24, /* 00100100 " */
+ 0X24, /* 00100100 " */
+ 0X00, /* 00000000 " */
+ 0X00, /* 00000000 " */
+ 0X00, /* 00000000 " */
+ 0X00, /* 00000000 " */
+ 0X00, /* 00000000 " */
+ 0X00, /* 00000000 " */
+ 0X00, /* 00000000 " */
+ 0X00, /* 00000000 " */
+ 0X00, /* 00000000 " */
+ 0X00, /* 00000000 " */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 # */
+ 0X00, /* 00000000 # */
+ 0X00, /* 00000000 # */
+ 0X12, /* 00010010 # */
+ 0X12, /* 00010010 # */
+ 0X3f, /* 00111111 # */
+ 0X12, /* 00010010 # */
+ 0X12, /* 00010010 # */
+ 0X3f, /* 00111111 # */
+ 0X12, /* 00010010 # */
+ 0X12, /* 00010010 # */
+ 0X00, /* 00000000 # */
+ 0X00, /* 00000000 # */
+ 0X00, /* 00000000 # */
+ 0X00, /* 00000000 # */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 $ */
+ 0X00, /* 00000000 $ */
+ 0X00, /* 00000000 $ */
+ 0X08, /* 00001000 $ */
+ 0X3e, /* 00111110 $ */
+ 0X09, /* 00001001 $ */
+ 0X09, /* 00001001 $ */
+ 0X3e, /* 00111110 $ */
+ 0X48, /* 01001000 $ */
+ 0X48, /* 01001000 $ */
+ 0X3e, /* 00111110 $ */
+ 0X08, /* 00001000 $ */
+ 0X00, /* 00000000 $ */
+ 0X00, /* 00000000 $ */
+ 0X00, /* 00000000 $ */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 % */
+ 0X00, /* 00000000 % */
+ 0X42, /* 01000010 % */
+ 0X25, /* 00100101 % */
+ 0X25, /* 00100101 % */
+ 0X12, /* 00010010 % */
+ 0X08, /* 00001000 % */
+ 0X08, /* 00001000 % */
+ 0X24, /* 00100100 % */
+ 0X52, /* 01010010 % */
+ 0X52, /* 01010010 % */
+ 0X21, /* 00100001 % */
+ 0X00, /* 00000000 % */
+ 0X00, /* 00000000 % */
+ 0X00, /* 00000000 % */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 & */
+ 0X00, /* 00000000 & */
+ 0X0e, /* 00001110 & */
+ 0X11, /* 00010001 & */
+ 0X11, /* 00010001 & */
+ 0X11, /* 00010001 & */
+ 0X0e, /* 00001110 & */
+ 0X11, /* 00010001 & */
+ 0X51, /* 01010001 & */
+ 0X21, /* 00100001 & */
+ 0X31, /* 00110001 & */
+ 0X4e, /* 01001110 & */
+ 0X00, /* 00000000 & */
+ 0X00, /* 00000000 & */
+ 0X00, /* 00000000 & */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 ' */
+ 0X00, /* 00000000 ' */
+ 0X38, /* 00111000 ' */
+ 0X18, /* 00011000 ' */
+ 0X04, /* 00000100 ' */
+ 0X00, /* 00000000 ' */
+ 0X00, /* 00000000 ' */
+ 0X00, /* 00000000 ' */
+ 0X00, /* 00000000 ' */
+ 0X00, /* 00000000 ' */
+ 0X00, /* 00000000 ' */
+ 0X00, /* 00000000 ' */
+ 0X00, /* 00000000 ' */
+ 0X00, /* 00000000 ' */
+ 0X00, /* 00000000 ' */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 ( */
+ 0X00, /* 00000000 ( */
+ 0X10, /* 00010000 ( */
+ 0X08, /* 00001000 ( */
+ 0X08, /* 00001000 ( */
+ 0X04, /* 00000100 ( */
+ 0X04, /* 00000100 ( */
+ 0X04, /* 00000100 ( */
+ 0X04, /* 00000100 ( */
+ 0X08, /* 00001000 ( */
+ 0X08, /* 00001000 ( */
+ 0X10, /* 00010000 ( */
+ 0X00, /* 00000000 ( */
+ 0X00, /* 00000000 ( */
+ 0X00, /* 00000000 ( */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 ) */
+ 0X00, /* 00000000 ) */
+ 0X04, /* 00000100 ) */
+ 0X08, /* 00001000 ) */
+ 0X08, /* 00001000 ) */
+ 0X10, /* 00010000 ) */
+ 0X10, /* 00010000 ) */
+ 0X10, /* 00010000 ) */
+ 0X10, /* 00010000 ) */
+ 0X08, /* 00001000 ) */
+ 0X08, /* 00001000 ) */
+ 0X04, /* 00000100 ) */
+ 0X00, /* 00000000 ) */
+ 0X00, /* 00000000 ) */
+ 0X00, /* 00000000 ) */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 * */
+ 0X00, /* 00000000 * */
+ 0X00, /* 00000000 * */
+ 0X00, /* 00000000 * */
+ 0X00, /* 00000000 * */
+ 0X22, /* 00100010 * */
+ 0X14, /* 00010100 * */
+ 0X7f, /* 01111111 * */
+ 0X14, /* 00010100 * */
+ 0X22, /* 00100010 * */
+ 0X00, /* 00000000 * */
+ 0X00, /* 00000000 * */
+ 0X00, /* 00000000 * */
+ 0X00, /* 00000000 * */
+ 0X00, /* 00000000 * */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 + */
+ 0X00, /* 00000000 + */
+ 0X00, /* 00000000 + */
+ 0X00, /* 00000000 + */
+ 0X08, /* 00001000 + */
+ 0X08, /* 00001000 + */
+ 0X08, /* 00001000 + */
+ 0X7f, /* 01111111 + */
+ 0X08, /* 00001000 + */
+ 0X08, /* 00001000 + */
+ 0X08, /* 00001000 + */
+ 0X00, /* 00000000 + */
+ 0X00, /* 00000000 + */
+ 0X00, /* 00000000 + */
+ 0X00, /* 00000000 + */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 , */
+ 0X00, /* 00000000 , */
+ 0X00, /* 00000000 , */
+ 0X00, /* 00000000 , */
+ 0X00, /* 00000000 , */
+ 0X00, /* 00000000 , */
+ 0X00, /* 00000000 , */
+ 0X00, /* 00000000 , */
+ 0X00, /* 00000000 , */
+ 0X00, /* 00000000 , */
+ 0X1c, /* 00011100 , */
+ 0X0c, /* 00001100 , */
+ 0X02, /* 00000010 , */
+ 0X00, /* 00000000 , */
+ 0X00, /* 00000000 , */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 - */
+ 0X00, /* 00000000 - */
+ 0X00, /* 00000000 - */
+ 0X00, /* 00000000 - */
+ 0X00, /* 00000000 - */
+ 0X00, /* 00000000 - */
+ 0X00, /* 00000000 - */
+ 0X7f, /* 01111111 - */
+ 0X00, /* 00000000 - */
+ 0X00, /* 00000000 - */
+ 0X00, /* 00000000 - */
+ 0X00, /* 00000000 - */
+ 0X00, /* 00000000 - */
+ 0X00, /* 00000000 - */
+ 0X00, /* 00000000 - */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 . */
+ 0X00, /* 00000000 . */
+ 0X00, /* 00000000 . */
+ 0X00, /* 00000000 . */
+ 0X00, /* 00000000 . */
+ 0X00, /* 00000000 . */
+ 0X00, /* 00000000 . */
+ 0X00, /* 00000000 . */
+ 0X00, /* 00000000 . */
+ 0X00, /* 00000000 . */
+ 0X08, /* 00001000 . */
+ 0X1c, /* 00011100 . */
+ 0X08, /* 00001000 . */
+ 0X00, /* 00000000 . */
+ 0X00, /* 00000000 . */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 / */
+ 0X00, /* 00000000 / */
+ 0X40, /* 01000000 / */
+ 0X40, /* 01000000 / */
+ 0X20, /* 00100000 / */
+ 0X10, /* 00010000 / */
+ 0X08, /* 00001000 / */
+ 0X04, /* 00000100 / */
+ 0X02, /* 00000010 / */
+ 0X01, /* 00000001 / */
+ 0X01, /* 00000001 / */
+ 0X01, /* 00000001 / */
+ 0X00, /* 00000000 / */
+ 0X00, /* 00000000 / */
+ 0X00, /* 00000000 / */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 0 */
+ 0X00, /* 00000000 0 */
+ 0X0c, /* 00001100 0 */
+ 0X12, /* 00010010 0 */
+ 0X21, /* 00100001 0 */
+ 0X21, /* 00100001 0 */
+ 0X21, /* 00100001 0 */
+ 0X21, /* 00100001 0 */
+ 0X21, /* 00100001 0 */
+ 0X21, /* 00100001 0 */
+ 0X12, /* 00010010 0 */
+ 0X0c, /* 00001100 0 */
+ 0X00, /* 00000000 0 */
+ 0X00, /* 00000000 0 */
+ 0X00, /* 00000000 0 */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 1 */
+ 0X00, /* 00000000 1 */
+ 0X08, /* 00001000 1 */
+ 0X0c, /* 00001100 1 */
+ 0X0a, /* 00001010 1 */
+ 0X08, /* 00001000 1 */
+ 0X08, /* 00001000 1 */
+ 0X08, /* 00001000 1 */
+ 0X08, /* 00001000 1 */
+ 0X08, /* 00001000 1 */
+ 0X08, /* 00001000 1 */
+ 0X3e, /* 00111110 1 */
+ 0X00, /* 00000000 1 */
+ 0X00, /* 00000000 1 */
+ 0X00, /* 00000000 1 */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 2 */
+ 0X00, /* 00000000 2 */
+ 0X3e, /* 00111110 2 */
+ 0X41, /* 01000001 2 */
+ 0X41, /* 01000001 2 */
+ 0X40, /* 01000000 2 */
+ 0X20, /* 00100000 2 */
+ 0X10, /* 00010000 2 */
+ 0X0c, /* 00001100 2 */
+ 0X02, /* 00000010 2 */
+ 0X01, /* 00000001 2 */
+ 0X7f, /* 01111111 2 */
+ 0X00, /* 00000000 2 */
+ 0X00, /* 00000000 2 */
+ 0X00, /* 00000000 2 */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 3 */
+ 0X00, /* 00000000 3 */
+ 0X7f, /* 01111111 3 */
+ 0X40, /* 01000000 3 */
+ 0X20, /* 00100000 3 */
+ 0X10, /* 00010000 3 */
+ 0X38, /* 00111000 3 */
+ 0X40, /* 01000000 3 */
+ 0X40, /* 01000000 3 */
+ 0X40, /* 01000000 3 */
+ 0X41, /* 01000001 3 */
+ 0X3e, /* 00111110 3 */
+ 0X00, /* 00000000 3 */
+ 0X00, /* 00000000 3 */
+ 0X00, /* 00000000 3 */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 4 */
+ 0X00, /* 00000000 4 */
+ 0X20, /* 00100000 4 */
+ 0X30, /* 00110000 4 */
+ 0X28, /* 00101000 4 */
+ 0X24, /* 00100100 4 */
+ 0X22, /* 00100010 4 */
+ 0X21, /* 00100001 4 */
+ 0X7f, /* 01111111 4 */
+ 0X20, /* 00100000 4 */
+ 0X20, /* 00100000 4 */
+ 0X20, /* 00100000 4 */
+ 0X00, /* 00000000 4 */
+ 0X00, /* 00000000 4 */
+ 0X00, /* 00000000 4 */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 5 */
+ 0X00, /* 00000000 5 */
+ 0X7f, /* 01111111 5 */
+ 0X01, /* 00000001 5 */
+ 0X01, /* 00000001 5 */
+ 0X3d, /* 00111101 5 */
+ 0X43, /* 01000011 5 */
+ 0X40, /* 01000000 5 */
+ 0X40, /* 01000000 5 */
+ 0X40, /* 01000000 5 */
+ 0X41, /* 01000001 5 */
+ 0X3e, /* 00111110 5 */
+ 0X00, /* 00000000 5 */
+ 0X00, /* 00000000 5 */
+ 0X00, /* 00000000 5 */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 6 */
+ 0X00, /* 00000000 6 */
+ 0X3c, /* 00111100 6 */
+ 0X02, /* 00000010 6 */
+ 0X01, /* 00000001 6 */
+ 0X01, /* 00000001 6 */
+ 0X3d, /* 00111101 6 */
+ 0X43, /* 01000011 6 */
+ 0X41, /* 01000001 6 */
+ 0X41, /* 01000001 6 */
+ 0X41, /* 01000001 6 */
+ 0X3e, /* 00111110 6 */
+ 0X00, /* 00000000 6 */
+ 0X00, /* 00000000 6 */
+ 0X00, /* 00000000 6 */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 7 */
+ 0X00, /* 00000000 7 */
+ 0X7f, /* 01111111 7 */
+ 0X40, /* 01000000 7 */
+ 0X40, /* 01000000 7 */
+ 0X20, /* 00100000 7 */
+ 0X10, /* 00010000 7 */
+ 0X08, /* 00001000 7 */
+ 0X04, /* 00000100 7 */
+ 0X04, /* 00000100 7 */
+ 0X02, /* 00000010 7 */
+ 0X02, /* 00000010 7 */
+ 0X00, /* 00000000 7 */
+ 0X00, /* 00000000 7 */
+ 0X00, /* 00000000 7 */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 8 */
+ 0X00, /* 00000000 8 */
+ 0X3e, /* 00111110 8 */
+ 0X41, /* 01000001 8 */
+ 0X41, /* 01000001 8 */
+ 0X41, /* 01000001 8 */
+ 0X3e, /* 00111110 8 */
+ 0X41, /* 01000001 8 */
+ 0X41, /* 01000001 8 */
+ 0X41, /* 01000001 8 */
+ 0X41, /* 01000001 8 */
+ 0X3e, /* 00111110 8 */
+ 0X00, /* 00000000 8 */
+ 0X00, /* 00000000 8 */
+ 0X00, /* 00000000 8 */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 9 */
+ 0X00, /* 00000000 9 */
+ 0X3e, /* 00111110 9 */
+ 0X41, /* 01000001 9 */
+ 0X41, /* 01000001 9 */
+ 0X41, /* 01000001 9 */
+ 0X61, /* 01100001 9 */
+ 0X5e, /* 01011110 9 */
+ 0X40, /* 01000000 9 */
+ 0X40, /* 01000000 9 */
+ 0X20, /* 00100000 9 */
+ 0X1e, /* 00011110 9 */
+ 0X00, /* 00000000 9 */
+ 0X00, /* 00000000 9 */
+ 0X00, /* 00000000 9 */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 : */
+ 0X00, /* 00000000 : */
+ 0X00, /* 00000000 : */
+ 0X00, /* 00000000 : */
+ 0X00, /* 00000000 : */
+ 0X08, /* 00001000 : */
+ 0X1c, /* 00011100 : */
+ 0X08, /* 00001000 : */
+ 0X00, /* 00000000 : */
+ 0X00, /* 00000000 : */
+ 0X08, /* 00001000 : */
+ 0X1c, /* 00011100 : */
+ 0X08, /* 00001000 : */
+ 0X00, /* 00000000 : */
+ 0X00, /* 00000000 : */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 ; */
+ 0X00, /* 00000000 ; */
+ 0X00, /* 00000000 ; */
+ 0X00, /* 00000000 ; */
+ 0X00, /* 00000000 ; */
+ 0X08, /* 00001000 ; */
+ 0X1c, /* 00011100 ; */
+ 0X08, /* 00001000 ; */
+ 0X00, /* 00000000 ; */
+ 0X00, /* 00000000 ; */
+ 0X1c, /* 00011100 ; */
+ 0X0c, /* 00001100 ; */
+ 0X02, /* 00000010 ; */
+ 0X00, /* 00000000 ; */
+ 0X00, /* 00000000 ; */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 < */
+ 0X00, /* 00000000 < */
+ 0X20, /* 00100000 < */
+ 0X10, /* 00010000 < */
+ 0X08, /* 00001000 < */
+ 0X04, /* 00000100 < */
+ 0X02, /* 00000010 < */
+ 0X02, /* 00000010 < */
+ 0X04, /* 00000100 < */
+ 0X08, /* 00001000 < */
+ 0X10, /* 00010000 < */
+ 0X20, /* 00100000 < */
+ 0X00, /* 00000000 < */
+ 0X00, /* 00000000 < */
+ 0X00, /* 00000000 < */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 = */
+ 0X00, /* 00000000 = */
+ 0X00, /* 00000000 = */
+ 0X00, /* 00000000 = */
+ 0X00, /* 00000000 = */
+ 0X00, /* 00000000 = */
+ 0X7f, /* 01111111 = */
+ 0X00, /* 00000000 = */
+ 0X00, /* 00000000 = */
+ 0X7f, /* 01111111 = */
+ 0X00, /* 00000000 = */
+ 0X00, /* 00000000 = */
+ 0X00, /* 00000000 = */
+ 0X00, /* 00000000 = */
+ 0X00, /* 00000000 = */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 > */
+ 0X00, /* 00000000 > */
+ 0X02, /* 00000010 > */
+ 0X04, /* 00000100 > */
+ 0X08, /* 00001000 > */
+ 0X10, /* 00010000 > */
+ 0X20, /* 00100000 > */
+ 0X20, /* 00100000 > */
+ 0X10, /* 00010000 > */
+ 0X08, /* 00001000 > */
+ 0X04, /* 00000100 > */
+ 0X02, /* 00000010 > */
+ 0X00, /* 00000000 > */
+ 0X00, /* 00000000 > */
+ 0X00, /* 00000000 > */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 ? */
+ 0X00, /* 00000000 ? */
+ 0X3e, /* 00111110 ? */
+ 0X41, /* 01000001 ? */
+ 0X41, /* 01000001 ? */
+ 0X40, /* 01000000 ? */
+ 0X20, /* 00100000 ? */
+ 0X10, /* 00010000 ? */
+ 0X08, /* 00001000 ? */
+ 0X08, /* 00001000 ? */
+ 0X00, /* 00000000 ? */
+ 0X08, /* 00001000 ? */
+ 0X00, /* 00000000 ? */
+ 0X00, /* 00000000 ? */
+ 0X00, /* 00000000 ? */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 @ */
+ 0X00, /* 00000000 @ */
+ 0X3e, /* 00111110 @ */
+ 0X41, /* 01000001 @ */
+ 0X41, /* 01000001 @ */
+ 0X79, /* 01111001 @ */
+ 0X45, /* 01000101 @ */
+ 0X65, /* 01100101 @ */
+ 0X59, /* 01011001 @ */
+ 0X01, /* 00000001 @ */
+ 0X01, /* 00000001 @ */
+ 0X3e, /* 00111110 @ */
+ 0X00, /* 00000000 @ */
+ 0X00, /* 00000000 @ */
+ 0X00, /* 00000000 @ */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 A */
+ 0X00, /* 00000000 A */
+ 0X08, /* 00001000 A */
+ 0X14, /* 00010100 A */
+ 0X22, /* 00100010 A */
+ 0X41, /* 01000001 A */
+ 0X41, /* 01000001 A */
+ 0X41, /* 01000001 A */
+ 0X7f, /* 01111111 A */
+ 0X41, /* 01000001 A */
+ 0X41, /* 01000001 A */
+ 0X41, /* 01000001 A */
+ 0X00, /* 00000000 A */
+ 0X00, /* 00000000 A */
+ 0X00, /* 00000000 A */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 B */
+ 0X00, /* 00000000 B */
+ 0X3f, /* 00111111 B */
+ 0X42, /* 01000010 B */
+ 0X42, /* 01000010 B */
+ 0X42, /* 01000010 B */
+ 0X3e, /* 00111110 B */
+ 0X42, /* 01000010 B */
+ 0X42, /* 01000010 B */
+ 0X42, /* 01000010 B */
+ 0X42, /* 01000010 B */
+ 0X3f, /* 00111111 B */
+ 0X00, /* 00000000 B */
+ 0X00, /* 00000000 B */
+ 0X00, /* 00000000 B */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 C */
+ 0X00, /* 00000000 C */
+ 0X3e, /* 00111110 C */
+ 0X41, /* 01000001 C */
+ 0X01, /* 00000001 C */
+ 0X01, /* 00000001 C */
+ 0X01, /* 00000001 C */
+ 0X01, /* 00000001 C */
+ 0X01, /* 00000001 C */
+ 0X01, /* 00000001 C */
+ 0X41, /* 01000001 C */
+ 0X3e, /* 00111110 C */
+ 0X00, /* 00000000 C */
+ 0X00, /* 00000000 C */
+ 0X00, /* 00000000 C */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 D */
+ 0X00, /* 00000000 D */
+ 0X3f, /* 00111111 D */
+ 0X42, /* 01000010 D */
+ 0X42, /* 01000010 D */
+ 0X42, /* 01000010 D */
+ 0X42, /* 01000010 D */
+ 0X42, /* 01000010 D */
+ 0X42, /* 01000010 D */
+ 0X42, /* 01000010 D */
+ 0X42, /* 01000010 D */
+ 0X3f, /* 00111111 D */
+ 0X00, /* 00000000 D */
+ 0X00, /* 00000000 D */
+ 0X00, /* 00000000 D */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 E */
+ 0X00, /* 00000000 E */
+ 0X7e, /* 01111110 E */
+ 0X02, /* 00000010 E */
+ 0X02, /* 00000010 E */
+ 0X02, /* 00000010 E */
+ 0X1e, /* 00011110 E */
+ 0X02, /* 00000010 E */
+ 0X02, /* 00000010 E */
+ 0X02, /* 00000010 E */
+ 0X02, /* 00000010 E */
+ 0X7e, /* 01111110 E */
+ 0X00, /* 00000000 E */
+ 0X00, /* 00000000 E */
+ 0X00, /* 00000000 E */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 F */
+ 0X00, /* 00000000 F */
+ 0X7e, /* 01111110 F */
+ 0X02, /* 00000010 F */
+ 0X02, /* 00000010 F */
+ 0X02, /* 00000010 F */
+ 0X1e, /* 00011110 F */
+ 0X02, /* 00000010 F */
+ 0X02, /* 00000010 F */
+ 0X02, /* 00000010 F */
+ 0X02, /* 00000010 F */
+ 0X02, /* 00000010 F */
+ 0X00, /* 00000000 F */
+ 0X00, /* 00000000 F */
+ 0X00, /* 00000000 F */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 G */
+ 0X00, /* 00000000 G */
+ 0X3e, /* 00111110 G */
+ 0X41, /* 01000001 G */
+ 0X01, /* 00000001 G */
+ 0X01, /* 00000001 G */
+ 0X01, /* 00000001 G */
+ 0X71, /* 01110001 G */
+ 0X41, /* 01000001 G */
+ 0X41, /* 01000001 G */
+ 0X41, /* 01000001 G */
+ 0X3e, /* 00111110 G */
+ 0X00, /* 00000000 G */
+ 0X00, /* 00000000 G */
+ 0X00, /* 00000000 G */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 H */
+ 0X00, /* 00000000 H */
+ 0X41, /* 01000001 H */
+ 0X41, /* 01000001 H */
+ 0X41, /* 01000001 H */
+ 0X41, /* 01000001 H */
+ 0X7f, /* 01111111 H */
+ 0X41, /* 01000001 H */
+ 0X41, /* 01000001 H */
+ 0X41, /* 01000001 H */
+ 0X41, /* 01000001 H */
+ 0X41, /* 01000001 H */
+ 0X00, /* 00000000 H */
+ 0X00, /* 00000000 H */
+ 0X00, /* 00000000 H */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 I */
+ 0X00, /* 00000000 I */
+ 0X3e, /* 00111110 I */
+ 0X08, /* 00001000 I */
+ 0X08, /* 00001000 I */
+ 0X08, /* 00001000 I */
+ 0X08, /* 00001000 I */
+ 0X08, /* 00001000 I */
+ 0X08, /* 00001000 I */
+ 0X08, /* 00001000 I */
+ 0X08, /* 00001000 I */
+ 0X3e, /* 00111110 I */
+ 0X00, /* 00000000 I */
+ 0X00, /* 00000000 I */
+ 0X00, /* 00000000 I */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 J */
+ 0X00, /* 00000000 J */
+ 0X78, /* 01111000 J */
+ 0X20, /* 00100000 J */
+ 0X20, /* 00100000 J */
+ 0X20, /* 00100000 J */
+ 0X20, /* 00100000 J */
+ 0X20, /* 00100000 J */
+ 0X20, /* 00100000 J */
+ 0X20, /* 00100000 J */
+ 0X21, /* 00100001 J */
+ 0X1e, /* 00011110 J */
+ 0X00, /* 00000000 J */
+ 0X00, /* 00000000 J */
+ 0X00, /* 00000000 J */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 K */
+ 0X00, /* 00000000 K */
+ 0X41, /* 01000001 K */
+ 0X21, /* 00100001 K */
+ 0X11, /* 00010001 K */
+ 0X09, /* 00001001 K */
+ 0X07, /* 00000111 K */
+ 0X05, /* 00000101 K */
+ 0X09, /* 00001001 K */
+ 0X11, /* 00010001 K */
+ 0X21, /* 00100001 K */
+ 0X41, /* 01000001 K */
+ 0X00, /* 00000000 K */
+ 0X00, /* 00000000 K */
+ 0X00, /* 00000000 K */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 L */
+ 0X00, /* 00000000 L */
+ 0X01, /* 00000001 L */
+ 0X01, /* 00000001 L */
+ 0X01, /* 00000001 L */
+ 0X01, /* 00000001 L */
+ 0X01, /* 00000001 L */
+ 0X01, /* 00000001 L */
+ 0X01, /* 00000001 L */
+ 0X01, /* 00000001 L */
+ 0X01, /* 00000001 L */
+ 0X7f, /* 01111111 L */
+ 0X00, /* 00000000 L */
+ 0X00, /* 00000000 L */
+ 0X00, /* 00000000 L */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 M */
+ 0X00, /* 00000000 M */
+ 0X41, /* 01000001 M */
+ 0X41, /* 01000001 M */
+ 0X63, /* 01100011 M */
+ 0X55, /* 01010101 M */
+ 0X55, /* 01010101 M */
+ 0X49, /* 01001001 M */
+ 0X49, /* 01001001 M */
+ 0X41, /* 01000001 M */
+ 0X41, /* 01000001 M */
+ 0X41, /* 01000001 M */
+ 0X00, /* 00000000 M */
+ 0X00, /* 00000000 M */
+ 0X00, /* 00000000 M */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 N */
+ 0X00, /* 00000000 N */
+ 0X41, /* 01000001 N */
+ 0X41, /* 01000001 N */
+ 0X43, /* 01000011 N */
+ 0X45, /* 01000101 N */
+ 0X49, /* 01001001 N */
+ 0X51, /* 01010001 N */
+ 0X61, /* 01100001 N */
+ 0X41, /* 01000001 N */
+ 0X41, /* 01000001 N */
+ 0X41, /* 01000001 N */
+ 0X00, /* 00000000 N */
+ 0X00, /* 00000000 N */
+ 0X00, /* 00000000 N */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 O */
+ 0X00, /* 00000000 O */
+ 0X3e, /* 00111110 O */
+ 0X41, /* 01000001 O */
+ 0X41, /* 01000001 O */
+ 0X41, /* 01000001 O */
+ 0X41, /* 01000001 O */
+ 0X41, /* 01000001 O */
+ 0X41, /* 01000001 O */
+ 0X41, /* 01000001 O */
+ 0X41, /* 01000001 O */
+ 0X3e, /* 00111110 O */
+ 0X00, /* 00000000 O */
+ 0X00, /* 00000000 O */
+ 0X00, /* 00000000 O */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 P */
+ 0X00, /* 00000000 P */
+ 0X3f, /* 00111111 P */
+ 0X41, /* 01000001 P */
+ 0X41, /* 01000001 P */
+ 0X41, /* 01000001 P */
+ 0X3f, /* 00111111 P */
+ 0X01, /* 00000001 P */
+ 0X01, /* 00000001 P */
+ 0X01, /* 00000001 P */
+ 0X01, /* 00000001 P */
+ 0X01, /* 00000001 P */
+ 0X00, /* 00000000 P */
+ 0X00, /* 00000000 P */
+ 0X00, /* 00000000 P */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 Q */
+ 0X00, /* 00000000 Q */
+ 0X3e, /* 00111110 Q */
+ 0X41, /* 01000001 Q */
+ 0X41, /* 01000001 Q */
+ 0X41, /* 01000001 Q */
+ 0X41, /* 01000001 Q */
+ 0X41, /* 01000001 Q */
+ 0X41, /* 01000001 Q */
+ 0X49, /* 01001001 Q */
+ 0X51, /* 01010001 Q */
+ 0X3e, /* 00111110 Q */
+ 0X40, /* 01000000 Q */
+ 0X00, /* 00000000 Q */
+ 0X00, /* 00000000 Q */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 R */
+ 0X00, /* 00000000 R */
+ 0X3f, /* 00111111 R */
+ 0X41, /* 01000001 R */
+ 0X41, /* 01000001 R */
+ 0X41, /* 01000001 R */
+ 0X3f, /* 00111111 R */
+ 0X09, /* 00001001 R */
+ 0X11, /* 00010001 R */
+ 0X21, /* 00100001 R */
+ 0X41, /* 01000001 R */
+ 0X41, /* 01000001 R */
+ 0X00, /* 00000000 R */
+ 0X00, /* 00000000 R */
+ 0X00, /* 00000000 R */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 S */
+ 0X00, /* 00000000 S */
+ 0X3e, /* 00111110 S */
+ 0X41, /* 01000001 S */
+ 0X01, /* 00000001 S */
+ 0X01, /* 00000001 S */
+ 0X3e, /* 00111110 S */
+ 0X40, /* 01000000 S */
+ 0X40, /* 01000000 S */
+ 0X40, /* 01000000 S */
+ 0X41, /* 01000001 S */
+ 0X3e, /* 00111110 S */
+ 0X00, /* 00000000 S */
+ 0X00, /* 00000000 S */
+ 0X00, /* 00000000 S */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 T */
+ 0X00, /* 00000000 T */
+ 0X7f, /* 01111111 T */
+ 0X08, /* 00001000 T */
+ 0X08, /* 00001000 T */
+ 0X08, /* 00001000 T */
+ 0X08, /* 00001000 T */
+ 0X08, /* 00001000 T */
+ 0X08, /* 00001000 T */
+ 0X08, /* 00001000 T */
+ 0X08, /* 00001000 T */
+ 0X08, /* 00001000 T */
+ 0X00, /* 00000000 T */
+ 0X00, /* 00000000 T */
+ 0X00, /* 00000000 T */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 U */
+ 0X00, /* 00000000 U */
+ 0X41, /* 01000001 U */
+ 0X41, /* 01000001 U */
+ 0X41, /* 01000001 U */
+ 0X41, /* 01000001 U */
+ 0X41, /* 01000001 U */
+ 0X41, /* 01000001 U */
+ 0X41, /* 01000001 U */
+ 0X41, /* 01000001 U */
+ 0X41, /* 01000001 U */
+ 0X3e, /* 00111110 U */
+ 0X00, /* 00000000 U */
+ 0X00, /* 00000000 U */
+ 0X00, /* 00000000 U */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 V */
+ 0X00, /* 00000000 V */
+ 0X41, /* 01000001 V */
+ 0X41, /* 01000001 V */
+ 0X41, /* 01000001 V */
+ 0X22, /* 00100010 V */
+ 0X22, /* 00100010 V */
+ 0X22, /* 00100010 V */
+ 0X14, /* 00010100 V */
+ 0X14, /* 00010100 V */
+ 0X14, /* 00010100 V */
+ 0X08, /* 00001000 V */
+ 0X00, /* 00000000 V */
+ 0X00, /* 00000000 V */
+ 0X00, /* 00000000 V */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 W */
+ 0X00, /* 00000000 W */
+ 0X41, /* 01000001 W */
+ 0X41, /* 01000001 W */
+ 0X41, /* 01000001 W */
+ 0X41, /* 01000001 W */
+ 0X49, /* 01001001 W */
+ 0X49, /* 01001001 W */
+ 0X49, /* 01001001 W */
+ 0X49, /* 01001001 W */
+ 0X55, /* 01010101 W */
+ 0X22, /* 00100010 W */
+ 0X00, /* 00000000 W */
+ 0X00, /* 00000000 W */
+ 0X00, /* 00000000 W */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 X */
+ 0X00, /* 00000000 X */
+ 0X41, /* 01000001 X */
+ 0X41, /* 01000001 X */
+ 0X22, /* 00100010 X */
+ 0X14, /* 00010100 X */
+ 0X08, /* 00001000 X */
+ 0X08, /* 00001000 X */
+ 0X14, /* 00010100 X */
+ 0X22, /* 00100010 X */
+ 0X41, /* 01000001 X */
+ 0X41, /* 01000001 X */
+ 0X00, /* 00000000 X */
+ 0X00, /* 00000000 X */
+ 0X00, /* 00000000 X */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 Y */
+ 0X00, /* 00000000 Y */
+ 0X41, /* 01000001 Y */
+ 0X41, /* 01000001 Y */
+ 0X22, /* 00100010 Y */
+ 0X14, /* 00010100 Y */
+ 0X08, /* 00001000 Y */
+ 0X08, /* 00001000 Y */
+ 0X08, /* 00001000 Y */
+ 0X08, /* 00001000 Y */
+ 0X08, /* 00001000 Y */
+ 0X08, /* 00001000 Y */
+ 0X00, /* 00000000 Y */
+ 0X00, /* 00000000 Y */
+ 0X00, /* 00000000 Y */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 Z */
+ 0X00, /* 00000000 Z */
+ 0X7f, /* 01111111 Z */
+ 0X40, /* 01000000 Z */
+ 0X20, /* 00100000 Z */
+ 0X10, /* 00010000 Z */
+ 0X08, /* 00001000 Z */
+ 0X04, /* 00000100 Z */
+ 0X02, /* 00000010 Z */
+ 0X01, /* 00000001 Z */
+ 0X01, /* 00000001 Z */
+ 0X7f, /* 01111111 Z */
+ 0X00, /* 00000000 Z */
+ 0X00, /* 00000000 Z */
+ 0X00, /* 00000000 Z */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 [ */
+ 0X00, /* 00000000 [ */
+ 0X3c, /* 00111100 [ */
+ 0X04, /* 00000100 [ */
+ 0X04, /* 00000100 [ */
+ 0X04, /* 00000100 [ */
+ 0X04, /* 00000100 [ */
+ 0X04, /* 00000100 [ */
+ 0X04, /* 00000100 [ */
+ 0X04, /* 00000100 [ */
+ 0X04, /* 00000100 [ */
+ 0X3c, /* 00111100 [ */
+ 0X00, /* 00000000 [ */
+ 0X00, /* 00000000 [ */
+ 0X00, /* 00000000 [ */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 \ */
+ 0X00, /* 00000000 \ */
+ 0X01, /* 00000001 \ */
+ 0X02, /* 00000010 \ */
+ 0X02, /* 00000010 \ */
+ 0X04, /* 00000100 \ */
+ 0X08, /* 00001000 \ */
+ 0X08, /* 00001000 \ */
+ 0X10, /* 00010000 \ */
+ 0X20, /* 00100000 \ */
+ 0X20, /* 00100000 \ */
+ 0X40, /* 01000000 \ */
+ 0X00, /* 00000000 \ */
+ 0X00, /* 00000000 \ */
+ 0X00, /* 00000000 \ */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 ] */
+ 0X00, /* 00000000 ] */
+ 0X1e, /* 00011110 ] */
+ 0X10, /* 00010000 ] */
+ 0X10, /* 00010000 ] */
+ 0X10, /* 00010000 ] */
+ 0X10, /* 00010000 ] */
+ 0X10, /* 00010000 ] */
+ 0X10, /* 00010000 ] */
+ 0X10, /* 00010000 ] */
+ 0X10, /* 00010000 ] */
+ 0X1e, /* 00011110 ] */
+ 0X00, /* 00000000 ] */
+ 0X00, /* 00000000 ] */
+ 0X00, /* 00000000 ] */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 ^ */
+ 0X00, /* 00000000 ^ */
+ 0X08, /* 00001000 ^ */
+ 0X14, /* 00010100 ^ */
+ 0X22, /* 00100010 ^ */
+ 0X41, /* 01000001 ^ */
+ 0X00, /* 00000000 ^ */
+ 0X00, /* 00000000 ^ */
+ 0X00, /* 00000000 ^ */
+ 0X00, /* 00000000 ^ */
+ 0X00, /* 00000000 ^ */
+ 0X00, /* 00000000 ^ */
+ 0X00, /* 00000000 ^ */
+ 0X00, /* 00000000 ^ */
+ 0X00, /* 00000000 ^ */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 _ */
+ 0X00, /* 00000000 _ */
+ 0X00, /* 00000000 _ */
+ 0X00, /* 00000000 _ */
+ 0X00, /* 00000000 _ */
+ 0X00, /* 00000000 _ */
+ 0X00, /* 00000000 _ */
+ 0X00, /* 00000000 _ */
+ 0X00, /* 00000000 _ */
+ 0X00, /* 00000000 _ */
+ 0X00, /* 00000000 _ */
+ 0X00, /* 00000000 _ */
+ 0X7f, /* 01111111 _ */
+ 0X00, /* 00000000 _ */
+ 0X00, /* 00000000 _ */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 ` */
+ 0X00, /* 00000000 ` */
+ 0X0e, /* 00001110 ` */
+ 0X0c, /* 00001100 ` */
+ 0X10, /* 00010000 ` */
+ 0X00, /* 00000000 ` */
+ 0X00, /* 00000000 ` */
+ 0X00, /* 00000000 ` */
+ 0X00, /* 00000000 ` */
+ 0X00, /* 00000000 ` */
+ 0X00, /* 00000000 ` */
+ 0X00, /* 00000000 ` */
+ 0X00, /* 00000000 ` */
+ 0X00, /* 00000000 ` */
+ 0X00, /* 00000000 ` */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 a */
+ 0X00, /* 00000000 a */
+ 0X00, /* 00000000 a */
+ 0X00, /* 00000000 a */
+ 0X00, /* 00000000 a */
+ 0X3e, /* 00111110 a */
+ 0X40, /* 01000000 a */
+ 0X40, /* 01000000 a */
+ 0X7e, /* 01111110 a */
+ 0X41, /* 01000001 a */
+ 0X61, /* 01100001 a */
+ 0X5e, /* 01011110 a */
+ 0X00, /* 00000000 a */
+ 0X00, /* 00000000 a */
+ 0X00, /* 00000000 a */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 b */
+ 0X00, /* 00000000 b */
+ 0X01, /* 00000001 b */
+ 0X01, /* 00000001 b */
+ 0X01, /* 00000001 b */
+ 0X3d, /* 00111101 b */
+ 0X43, /* 01000011 b */
+ 0X41, /* 01000001 b */
+ 0X41, /* 01000001 b */
+ 0X41, /* 01000001 b */
+ 0X43, /* 01000011 b */
+ 0X3d, /* 00111101 b */
+ 0X00, /* 00000000 b */
+ 0X00, /* 00000000 b */
+ 0X00, /* 00000000 b */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 c */
+ 0X00, /* 00000000 c */
+ 0X00, /* 00000000 c */
+ 0X00, /* 00000000 c */
+ 0X00, /* 00000000 c */
+ 0X3e, /* 00111110 c */
+ 0X41, /* 01000001 c */
+ 0X01, /* 00000001 c */
+ 0X01, /* 00000001 c */
+ 0X01, /* 00000001 c */
+ 0X41, /* 01000001 c */
+ 0X3e, /* 00111110 c */
+ 0X00, /* 00000000 c */
+ 0X00, /* 00000000 c */
+ 0X00, /* 00000000 c */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 d */
+ 0X00, /* 00000000 d */
+ 0X40, /* 01000000 d */
+ 0X40, /* 01000000 d */
+ 0X40, /* 01000000 d */
+ 0X5e, /* 01011110 d */
+ 0X61, /* 01100001 d */
+ 0X41, /* 01000001 d */
+ 0X41, /* 01000001 d */
+ 0X41, /* 01000001 d */
+ 0X61, /* 01100001 d */
+ 0X5e, /* 01011110 d */
+ 0X00, /* 00000000 d */
+ 0X00, /* 00000000 d */
+ 0X00, /* 00000000 d */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 e */
+ 0X00, /* 00000000 e */
+ 0X00, /* 00000000 e */
+ 0X00, /* 00000000 e */
+ 0X00, /* 00000000 e */
+ 0X3e, /* 00111110 e */
+ 0X41, /* 01000001 e */
+ 0X41, /* 01000001 e */
+ 0X7f, /* 01111111 e */
+ 0X01, /* 00000001 e */
+ 0X01, /* 00000001 e */
+ 0X3e, /* 00111110 e */
+ 0X00, /* 00000000 e */
+ 0X00, /* 00000000 e */
+ 0X00, /* 00000000 e */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 f */
+ 0X00, /* 00000000 f */
+ 0X38, /* 00111000 f */
+ 0X44, /* 01000100 f */
+ 0X44, /* 01000100 f */
+ 0X04, /* 00000100 f */
+ 0X04, /* 00000100 f */
+ 0X1f, /* 00011111 f */
+ 0X04, /* 00000100 f */
+ 0X04, /* 00000100 f */
+ 0X04, /* 00000100 f */
+ 0X04, /* 00000100 f */
+ 0X00, /* 00000000 f */
+ 0X00, /* 00000000 f */
+ 0X00, /* 00000000 f */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 g */
+ 0X00, /* 00000000 g */
+ 0X00, /* 00000000 g */
+ 0X00, /* 00000000 g */
+ 0X00, /* 00000000 g */
+ 0X5e, /* 01011110 g */
+ 0X21, /* 00100001 g */
+ 0X21, /* 00100001 g */
+ 0X21, /* 00100001 g */
+ 0X1e, /* 00011110 g */
+ 0X01, /* 00000001 g */
+ 0X3e, /* 00111110 g */
+ 0X41, /* 01000001 g */
+ 0X41, /* 01000001 g */
+ 0X3e, /* 00111110 g */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 h */
+ 0X00, /* 00000000 h */
+ 0X01, /* 00000001 h */
+ 0X01, /* 00000001 h */
+ 0X01, /* 00000001 h */
+ 0X3d, /* 00111101 h */
+ 0X43, /* 01000011 h */
+ 0X41, /* 01000001 h */
+ 0X41, /* 01000001 h */
+ 0X41, /* 01000001 h */
+ 0X41, /* 01000001 h */
+ 0X41, /* 01000001 h */
+ 0X00, /* 00000000 h */
+ 0X00, /* 00000000 h */
+ 0X00, /* 00000000 h */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 i */
+ 0X00, /* 00000000 i */
+ 0X00, /* 00000000 i */
+ 0X08, /* 00001000 i */
+ 0X00, /* 00000000 i */
+ 0X0c, /* 00001100 i */
+ 0X08, /* 00001000 i */
+ 0X08, /* 00001000 i */
+ 0X08, /* 00001000 i */
+ 0X08, /* 00001000 i */
+ 0X08, /* 00001000 i */
+ 0X3e, /* 00111110 i */
+ 0X00, /* 00000000 i */
+ 0X00, /* 00000000 i */
+ 0X00, /* 00000000 i */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 j */
+ 0X00, /* 00000000 j */
+ 0X00, /* 00000000 j */
+ 0X20, /* 00100000 j */
+ 0X00, /* 00000000 j */
+ 0X38, /* 00111000 j */
+ 0X20, /* 00100000 j */
+ 0X20, /* 00100000 j */
+ 0X20, /* 00100000 j */
+ 0X20, /* 00100000 j */
+ 0X20, /* 00100000 j */
+ 0X21, /* 00100001 j */
+ 0X21, /* 00100001 j */
+ 0X21, /* 00100001 j */
+ 0X1e, /* 00011110 j */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 k */
+ 0X00, /* 00000000 k */
+ 0X01, /* 00000001 k */
+ 0X01, /* 00000001 k */
+ 0X01, /* 00000001 k */
+ 0X41, /* 01000001 k */
+ 0X31, /* 00110001 k */
+ 0X0d, /* 00001101 k */
+ 0X03, /* 00000011 k */
+ 0X0d, /* 00001101 k */
+ 0X31, /* 00110001 k */
+ 0X41, /* 01000001 k */
+ 0X00, /* 00000000 k */
+ 0X00, /* 00000000 k */
+ 0X00, /* 00000000 k */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 l */
+ 0X00, /* 00000000 l */
+ 0X0c, /* 00001100 l */
+ 0X08, /* 00001000 l */
+ 0X08, /* 00001000 l */
+ 0X08, /* 00001000 l */
+ 0X08, /* 00001000 l */
+ 0X08, /* 00001000 l */
+ 0X08, /* 00001000 l */
+ 0X08, /* 00001000 l */
+ 0X08, /* 00001000 l */
+ 0X3e, /* 00111110 l */
+ 0X00, /* 00000000 l */
+ 0X00, /* 00000000 l */
+ 0X00, /* 00000000 l */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 m */
+ 0X00, /* 00000000 m */
+ 0X00, /* 00000000 m */
+ 0X00, /* 00000000 m */
+ 0X00, /* 00000000 m */
+ 0X37, /* 00110111 m */
+ 0X49, /* 01001001 m */
+ 0X49, /* 01001001 m */
+ 0X49, /* 01001001 m */
+ 0X49, /* 01001001 m */
+ 0X49, /* 01001001 m */
+ 0X41, /* 01000001 m */
+ 0X00, /* 00000000 m */
+ 0X00, /* 00000000 m */
+ 0X00, /* 00000000 m */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 n */
+ 0X00, /* 00000000 n */
+ 0X00, /* 00000000 n */
+ 0X00, /* 00000000 n */
+ 0X00, /* 00000000 n */
+ 0X3d, /* 00111101 n */
+ 0X43, /* 01000011 n */
+ 0X41, /* 01000001 n */
+ 0X41, /* 01000001 n */
+ 0X41, /* 01000001 n */
+ 0X41, /* 01000001 n */
+ 0X41, /* 01000001 n */
+ 0X00, /* 00000000 n */
+ 0X00, /* 00000000 n */
+ 0X00, /* 00000000 n */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 o */
+ 0X00, /* 00000000 o */
+ 0X00, /* 00000000 o */
+ 0X00, /* 00000000 o */
+ 0X00, /* 00000000 o */
+ 0X3e, /* 00111110 o */
+ 0X41, /* 01000001 o */
+ 0X41, /* 01000001 o */
+ 0X41, /* 01000001 o */
+ 0X41, /* 01000001 o */
+ 0X41, /* 01000001 o */
+ 0X3e, /* 00111110 o */
+ 0X00, /* 00000000 o */
+ 0X00, /* 00000000 o */
+ 0X00, /* 00000000 o */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 p */
+ 0X00, /* 00000000 p */
+ 0X00, /* 00000000 p */
+ 0X00, /* 00000000 p */
+ 0X00, /* 00000000 p */
+ 0X3d, /* 00111101 p */
+ 0X43, /* 01000011 p */
+ 0X41, /* 01000001 p */
+ 0X41, /* 01000001 p */
+ 0X41, /* 01000001 p */
+ 0X43, /* 01000011 p */
+ 0X3d, /* 00111101 p */
+ 0X01, /* 00000001 p */
+ 0X01, /* 00000001 p */
+ 0X01, /* 00000001 p */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 q */
+ 0X00, /* 00000000 q */
+ 0X00, /* 00000000 q */
+ 0X00, /* 00000000 q */
+ 0X00, /* 00000000 q */
+ 0X5e, /* 01011110 q */
+ 0X61, /* 01100001 q */
+ 0X41, /* 01000001 q */
+ 0X41, /* 01000001 q */
+ 0X41, /* 01000001 q */
+ 0X61, /* 01100001 q */
+ 0X5e, /* 01011110 q */
+ 0X40, /* 01000000 q */
+ 0X40, /* 01000000 q */
+ 0X40, /* 01000000 q */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 r */
+ 0X00, /* 00000000 r */
+ 0X00, /* 00000000 r */
+ 0X00, /* 00000000 r */
+ 0X00, /* 00000000 r */
+ 0X39, /* 00111001 r */
+ 0X46, /* 01000110 r */
+ 0X42, /* 01000010 r */
+ 0X02, /* 00000010 r */
+ 0X02, /* 00000010 r */
+ 0X02, /* 00000010 r */
+ 0X02, /* 00000010 r */
+ 0X00, /* 00000000 r */
+ 0X00, /* 00000000 r */
+ 0X00, /* 00000000 r */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 s */
+ 0X00, /* 00000000 s */
+ 0X00, /* 00000000 s */
+ 0X00, /* 00000000 s */
+ 0X00, /* 00000000 s */
+ 0X3e, /* 00111110 s */
+ 0X41, /* 01000001 s */
+ 0X01, /* 00000001 s */
+ 0X3e, /* 00111110 s */
+ 0X40, /* 01000000 s */
+ 0X41, /* 01000001 s */
+ 0X3e, /* 00111110 s */
+ 0X00, /* 00000000 s */
+ 0X00, /* 00000000 s */
+ 0X00, /* 00000000 s */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 t */
+ 0X00, /* 00000000 t */
+ 0X00, /* 00000000 t */
+ 0X04, /* 00000100 t */
+ 0X04, /* 00000100 t */
+ 0X3f, /* 00111111 t */
+ 0X04, /* 00000100 t */
+ 0X04, /* 00000100 t */
+ 0X04, /* 00000100 t */
+ 0X04, /* 00000100 t */
+ 0X44, /* 01000100 t */
+ 0X38, /* 00111000 t */
+ 0X00, /* 00000000 t */
+ 0X00, /* 00000000 t */
+ 0X00, /* 00000000 t */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 u */
+ 0X00, /* 00000000 u */
+ 0X00, /* 00000000 u */
+ 0X00, /* 00000000 u */
+ 0X00, /* 00000000 u */
+ 0X21, /* 00100001 u */
+ 0X21, /* 00100001 u */
+ 0X21, /* 00100001 u */
+ 0X21, /* 00100001 u */
+ 0X21, /* 00100001 u */
+ 0X21, /* 00100001 u */
+ 0X5e, /* 01011110 u */
+ 0X00, /* 00000000 u */
+ 0X00, /* 00000000 u */
+ 0X00, /* 00000000 u */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 v */
+ 0X00, /* 00000000 v */
+ 0X00, /* 00000000 v */
+ 0X00, /* 00000000 v */
+ 0X00, /* 00000000 v */
+ 0X41, /* 01000001 v */
+ 0X41, /* 01000001 v */
+ 0X22, /* 00100010 v */
+ 0X22, /* 00100010 v */
+ 0X14, /* 00010100 v */
+ 0X14, /* 00010100 v */
+ 0X08, /* 00001000 v */
+ 0X00, /* 00000000 v */
+ 0X00, /* 00000000 v */
+ 0X00, /* 00000000 v */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 w */
+ 0X00, /* 00000000 w */
+ 0X00, /* 00000000 w */
+ 0X00, /* 00000000 w */
+ 0X00, /* 00000000 w */
+ 0X41, /* 01000001 w */
+ 0X41, /* 01000001 w */
+ 0X49, /* 01001001 w */
+ 0X49, /* 01001001 w */
+ 0X49, /* 01001001 w */
+ 0X55, /* 01010101 w */
+ 0X22, /* 00100010 w */
+ 0X00, /* 00000000 w */
+ 0X00, /* 00000000 w */
+ 0X00, /* 00000000 w */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 x */
+ 0X00, /* 00000000 x */
+ 0X00, /* 00000000 x */
+ 0X00, /* 00000000 x */
+ 0X00, /* 00000000 x */
+ 0X41, /* 01000001 x */
+ 0X22, /* 00100010 x */
+ 0X14, /* 00010100 x */
+ 0X08, /* 00001000 x */
+ 0X14, /* 00010100 x */
+ 0X22, /* 00100010 x */
+ 0X41, /* 01000001 x */
+ 0X00, /* 00000000 x */
+ 0X00, /* 00000000 x */
+ 0X00, /* 00000000 x */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 y */
+ 0X00, /* 00000000 y */
+ 0X00, /* 00000000 y */
+ 0X00, /* 00000000 y */
+ 0X00, /* 00000000 y */
+ 0X21, /* 00100001 y */
+ 0X21, /* 00100001 y */
+ 0X21, /* 00100001 y */
+ 0X21, /* 00100001 y */
+ 0X21, /* 00100001 y */
+ 0X31, /* 00110001 y */
+ 0X2e, /* 00101110 y */
+ 0X20, /* 00100000 y */
+ 0X21, /* 00100001 y */
+ 0X1e, /* 00011110 y */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 z */
+ 0X00, /* 00000000 z */
+ 0X00, /* 00000000 z */
+ 0X00, /* 00000000 z */
+ 0X00, /* 00000000 z */
+ 0X7f, /* 01111111 z */
+ 0X20, /* 00100000 z */
+ 0X10, /* 00010000 z */
+ 0X08, /* 00001000 z */
+ 0X04, /* 00000100 z */
+ 0X02, /* 00000010 z */
+ 0X7f, /* 01111111 z */
+ 0X00, /* 00000000 z */
+ 0X00, /* 00000000 z */
+ 0X00, /* 00000000 z */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 { */
+ 0X00, /* 00000000 { */
+ 0X70, /* 01110000 { */
+ 0X08, /* 00001000 { */
+ 0X08, /* 00001000 { */
+ 0X10, /* 00010000 { */
+ 0X0c, /* 00001100 { */
+ 0X0c, /* 00001100 { */
+ 0X10, /* 00010000 { */
+ 0X08, /* 00001000 { */
+ 0X08, /* 00001000 { */
+ 0X70, /* 01110000 { */
+ 0X00, /* 00000000 { */
+ 0X00, /* 00000000 { */
+ 0X00, /* 00000000 { */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 | */
+ 0X00, /* 00000000 | */
+ 0X08, /* 00001000 | */
+ 0X08, /* 00001000 | */
+ 0X08, /* 00001000 | */
+ 0X08, /* 00001000 | */
+ 0X08, /* 00001000 | */
+ 0X08, /* 00001000 | */
+ 0X08, /* 00001000 | */
+ 0X08, /* 00001000 | */
+ 0X08, /* 00001000 | */
+ 0X08, /* 00001000 | */
+ 0X00, /* 00000000 | */
+ 0X00, /* 00000000 | */
+ 0X00, /* 00000000 | */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 } */
+ 0X00, /* 00000000 } */
+ 0X07, /* 00000111 } */
+ 0X08, /* 00001000 } */
+ 0X08, /* 00001000 } */
+ 0X04, /* 00000100 } */
+ 0X18, /* 00011000 } */
+ 0X18, /* 00011000 } */
+ 0X04, /* 00000100 } */
+ 0X08, /* 00001000 } */
+ 0X08, /* 00001000 } */
+ 0X07, /* 00000111 } */
+ 0X00, /* 00000000 } */
+ 0X00, /* 00000000 } */
+ 0X00, /* 00000000 } */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 ~ */
+ 0X00, /* 00000000 ~ */
+ 0X46, /* 01000110 ~ */
+ 0X49, /* 01001001 ~ */
+ 0X31, /* 00110001 ~ */
+ 0X00, /* 00000000 ~ */
+ 0X00, /* 00000000 ~ */
+ 0X00, /* 00000000 ~ */
+ 0X00, /* 00000000 ~ */
+ 0X00, /* 00000000 ~ */
+ 0X00, /* 00000000 ~ */
+ 0X00, /* 00000000 ~ */
+ 0X00, /* 00000000 ~ */
+ 0X00, /* 00000000 ~ */
+ 0X00, /* 00000000 ~ */
+ 0X00, /* 00000000 */
+
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X18, /* 00011000 */
+ 0X3c, /* 00111100 */
+ 0X3c, /* 00111100 */
+ 0X3c, /* 00111100 */
+ 0X18, /* 00011000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+ 0X00, /* 00000000 */
+};
+
diff --git a/private/ntos/fw/mips/xxirql.s b/private/ntos/fw/mips/xxirql.s
new file mode 100644
index 000000000..b773a4ab7
--- /dev/null
+++ b/private/ntos/fw/mips/xxirql.s
@@ -0,0 +1,89 @@
+// TITLE("Manipulate Interrupt Request Level")
+//++
+//
+// Copyright (c) 1990 Microsoft Corporation
+//
+// Module Name:
+//
+// manpirql.s
+//
+// Abstract:
+//
+// This module implements the code necessary to lower and raise the current
+// Interrupt Request Level (IRQL).
+//
+//
+// Author:
+//
+// David N. Cutler (davec) 12-Aug-1990
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+#include "ksmips.h"
+
+ SBTTL("Lower Interrupt Request Level")
+//++
+//
+// VOID
+// KeLowerIrql (
+// KIRQL NewIrql
+// )
+//
+// Routine Description:
+//
+// This function lowers the current IRQL to the specified value.
+//
+// Arguments:
+//
+// NewIrql (a0) - Supplies the new IRQL value.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KeLowerIrql)
+
+ j ra // return
+
+ .end KeLowerIrql
+
+ SBTTL("Raise Interrupt Request Level")
+//++
+//
+// VOID
+// KeRaiseIrql (
+// KIRQL NewIrql,
+// PKIRQL OldIrql
+// )
+//
+// Routine Description:
+//
+// This function raises the current IRQL to the specified value and returns
+// the old IRQL value.
+//
+// Arguments:
+//
+// NewIrql (a0) - Supplies the new IRQL value.
+//
+// OldIrql (a1) - Supplies a pointer to a variable that recieves the old
+// IRQL value.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(KeRaiseIrql)
+
+ j ra // return
+
+ .end KeRaiseIrql
diff --git a/private/ntos/fw/mips/xxldfont.c b/private/ntos/fw/mips/xxldfont.c
new file mode 100644
index 000000000..1f1b5f36d
--- /dev/null
+++ b/private/ntos/fw/mips/xxldfont.c
@@ -0,0 +1,267 @@
+/*++
+
+Copyright (c) 1992 Microsoft Corporation
+
+Module Name:
+
+ xxldfont.c
+
+Abstract:
+
+ This module contains the font table for the line drawing font.
+
+Author:
+
+ David M. Robinson (davidro) 9-April-1991
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+
+unsigned char FwLdFont[40*5] = {
+
+ 0X08, /* 00001000 ³ */
+ 0X08, /* 00001000 ³ */
+ 0X08, /* 00001000 ³ */
+ 0X08, /* 00001000 ³ */
+ 0X08, /* 00001000 ³ */
+
+ 0X08, /* 00001000 ´ */
+ 0X08, /* 00001000 ´ */
+ 0X0f, /* 00001111 ´ */
+ 0X08, /* 00001000 ´ */
+ 0X08, /* 00001000 ´ */
+
+ 0X08, /* 00001000 µ */
+ 0X0f, /* 00001111 µ */
+ 0X08, /* 00001000 µ */
+ 0X0f, /* 00001111 µ */
+ 0X08, /* 00001000 µ */
+
+ 0X14, /* 00010100 ¶ */
+ 0X14, /* 00010100 ¶ */
+ 0X17, /* 00010111 ¶ */
+ 0X14, /* 00010100 ¶ */
+ 0X14, /* 00010100 ¶ */
+
+ 0X00, /* 00000000 · */
+ 0X00, /* 00000000 · */
+ 0X1f, /* 00011111 · */
+ 0X14, /* 00010100 · */
+ 0X14, /* 00010100 · */
+
+ 0X00, /* 00000000 ¸ */
+ 0X0f, /* 00001111 ¸ */
+ 0X08, /* 00001000 ¸ */
+ 0X0f, /* 00001111 ¸ */
+ 0X08, /* 00001000 ¸ */
+
+ 0X14, /* 00010100 ¹ */
+ 0X17, /* 00010111 ¹ */
+ 0X10, /* 00010000 ¹ */
+ 0X17, /* 00010111 ¹ */
+ 0X14, /* 00010100 ¹ */
+
+ 0X14, /* 00010100 º */
+ 0X14, /* 00010100 º */
+ 0X14, /* 00010100 º */
+ 0X14, /* 00010100 º */
+ 0X14, /* 00010100 º */
+
+ 0X00, /* 00000000 » */
+ 0X1f, /* 00011111 » */
+ 0X10, /* 00010000 » */
+ 0X17, /* 00010111 » */
+ 0X14, /* 00010100 » */
+
+ 0X14, /* 00010100 ¼ */
+ 0X17, /* 00010111 ¼ */
+ 0X10, /* 00010000 ¼ */
+ 0X1f, /* 00011111 ¼ */
+ 0X00, /* 00000000 ¼ */
+
+ 0X14, /* 00010100 ½ */
+ 0X14, /* 00010100 ½ */
+ 0X1f, /* 00011111 ½ */
+ 0X00, /* 00000000 ½ */
+ 0X00, /* 00000000 ½ */
+
+ 0X08, /* 00001000 ¾ */
+ 0X0f, /* 00001111 ¾ */
+ 0X08, /* 00001000 ¾ */
+ 0X0f, /* 00001111 ¾ */
+ 0X00, /* 00000000 ¾ */
+
+ 0X00, /* 00000000 ¿ */
+ 0X00, /* 00000000 ¿ */
+ 0X0f, /* 00001111 ¿ */
+ 0X08, /* 00001000 ¿ */
+ 0X08, /* 00001000 ¿ */
+
+ 0X08, /* 00001000 À */
+ 0X08, /* 00001000 À */
+ 0Xf8, /* 11111000 À */
+ 0X00, /* 00000000 À */
+ 0X00, /* 00000000 À */
+
+ 0X08, /* 00001000 Á */
+ 0X08, /* 00001000 Á */
+ 0Xff, /* 11111111 Á */
+ 0X00, /* 00000000 Á */
+ 0X00, /* 00000000 Á */
+
+ 0X00, /* 00000000 Â */
+ 0X00, /* 00000000 Â */
+ 0Xff, /* 11111111 Â */
+ 0X08, /* 00001000 Â */
+ 0X08, /* 00001000 Â */
+
+ 0X08, /* 00001000 Ã */
+ 0X08, /* 00001000 Ã */
+ 0Xf8, /* 11111000 Ã */
+ 0X08, /* 00001000 Ã */
+ 0X08, /* 00001000 Ã */
+
+ 0X00, /* 00000000 Ä */
+ 0X00, /* 00000000 Ä */
+ 0Xff, /* 11111111 Ä */
+ 0X00, /* 00000000 Ä */
+ 0X00, /* 00000000 Ä */
+
+ 0X08, /* 00001000 Å */
+ 0X08, /* 00001000 Å */
+ 0Xff, /* 11111111 Å */
+ 0X08, /* 00001000 Å */
+ 0X08, /* 00001000 Å */
+
+ 0X08, /* 00001000 Æ */
+ 0Xf8, /* 11111000 Æ */
+ 0X08, /* 00001000 Æ */
+ 0Xf8, /* 11111000 Æ */
+ 0X08, /* 00001000 Æ */
+
+ 0X14, /* 00010100 Ç */
+ 0X14, /* 00010100 Ç */
+ 0Xf4, /* 11110100 Ç */
+ 0X14, /* 00010100 Ç */
+ 0X14, /* 00010100 Ç */
+
+ 0X14, /* 00010100 È */
+ 0Xf4, /* 11110100 È */
+ 0X04, /* 00000100 È */
+ 0Xfc, /* 11111100 È */
+ 0X00, /* 00000000 È */
+
+ 0X00, /* 00000000 É */
+ 0Xfc, /* 11111100 É */
+ 0X04, /* 00000100 É */
+ 0Xf4, /* 11110100 É */
+ 0X14, /* 00010100 É */
+
+ 0X14, /* 00010100 Ê */
+ 0Xf7, /* 11110111 Ê */
+ 0X00, /* 00000000 Ê */
+ 0Xff, /* 11111111 Ê */
+ 0X00, /* 00000000 Ê */
+
+ 0X00, /* 00000000 Ë */
+ 0Xff, /* 11111111 Ë */
+ 0X00, /* 00000000 Ë */
+ 0Xf7, /* 11110111 Ë */
+ 0X14, /* 00010100 Ë */
+
+ 0X14, /* 00010100 Ì */
+ 0Xf4, /* 11110100 Ì */
+ 0X04, /* 00000100 Ì */
+ 0Xf4, /* 11110100 Ì */
+ 0X14, /* 00010100 Ì */
+
+ 0X00, /* 00000000 Í */
+ 0Xff, /* 11111111 Í */
+ 0X00, /* 00000000 Í */
+ 0Xff, /* 11111111 Í */
+ 0X00, /* 00000000 Í */
+
+ 0X14, /* 00010100 Î */
+ 0Xf7, /* 11110111 Î */
+ 0X00, /* 00000000 Î */
+ 0Xf7, /* 11110111 Î */
+ 0X14, /* 00010100 Î */
+
+ 0X08, /* 00001000 Ï */
+ 0Xff, /* 11111111 Ï */
+ 0X00, /* 00000000 Ï */
+ 0Xff, /* 11111111 Ï */
+ 0X00, /* 00000000 Ï */
+
+ 0X14, /* 00010100 Ð */
+ 0X14, /* 00010100 Ð */
+ 0Xff, /* 11111111 Ð */
+ 0X00, /* 00000000 Ð */
+ 0X00, /* 00000000 Ð */
+
+ 0X00, /* 00000000 Ñ */
+ 0Xff, /* 11111111 Ñ */
+ 0X00, /* 00000000 Ñ */
+ 0Xff, /* 11111111 Ñ */
+ 0X08, /* 00001000 Ñ */
+
+ 0X00, /* 00000000 Ò */
+ 0X00, /* 00000000 Ò */
+ 0Xff, /* 11111111 Ò */
+ 0X14, /* 00010100 Ò */
+ 0X14, /* 00010100 Ò */
+
+ 0X14, /* 00010100 Ó */
+ 0X14, /* 00010100 Ó */
+ 0Xfc, /* 11111100 Ó */
+ 0X00, /* 00000000 Ó */
+ 0X00, /* 00000000 Ó */
+
+ 0X08, /* 00001000 Ô */
+ 0Xf8, /* 11111000 Ô */
+ 0X08, /* 00001000 Ô */
+ 0Xf8, /* 11111000 Ô */
+ 0X00, /* 00000000 Ô */
+
+ 0X00, /* 00000000 Õ */
+ 0Xf8, /* 11111000 Õ */
+ 0X08, /* 00001000 Õ */
+ 0Xf8, /* 11111000 Õ */
+ 0X08, /* 00001000 Õ */
+
+ 0X00, /* 00000000 Ö */
+ 0X00, /* 00000000 Ö */
+ 0Xfc, /* 11111100 Ö */
+ 0X14, /* 00010100 Ö */
+ 0X14, /* 00010100 Ö */
+
+ 0X14, /* 00010100 × */
+ 0X14, /* 00010100 × */
+ 0Xff, /* 11111111 × */
+ 0X14, /* 00010100 × */
+ 0X14, /* 00010100 × */
+
+ 0X08, /* 00001000 Ø */
+ 0Xff, /* 11111111 Ø */
+ 0X08, /* 00001000 Ø */
+ 0Xff, /* 11111111 Ø */
+ 0X08, /* 00001000 Ø */
+
+ 0X08, /* 00001000 Ù */
+ 0X08, /* 00001000 Ù */
+ 0X0f, /* 00001111 Ù */
+ 0X00, /* 00000000 Ù */
+ 0X00, /* 00000000 Ù */
+
+ 0X00, /* 00000000 Ú */
+ 0X00, /* 00000000 Ú */
+ 0Xf8, /* 11111000 Ú */
+ 0X08, /* 00001000 Ú */
+ 0X08, /* 00001000 Ú */
+};