diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/fw/mips | |
download | NT4.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 '')
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, ¤tIrql); + + // + // 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 Ú */ +}; |