summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halalpha
diff options
context:
space:
mode:
authorAdam <you@example.com>2020-05-17 05:51:50 +0200
committerAdam <you@example.com>2020-05-17 05:51:50 +0200
commite611b132f9b8abe35b362e5870b74bce94a1e58e (patch)
treea5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nthals/halalpha
downloadNT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst
NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip
Diffstat (limited to 'private/ntos/nthals/halalpha')
-rw-r--r--private/ntos/nthals/halalpha/28f008sa.c317
-rw-r--r--private/ntos/nthals/halalpha/29f040.c420
-rw-r--r--private/ntos/nthals/halalpha/adjust.c149
-rw-r--r--private/ntos/nthals/halalpha/allstart.c55
-rw-r--r--private/ntos/nthals/halalpha/alphaio.s1368
-rw-r--r--private/ntos/nthals/halalpha/am29f400.c543
-rw-r--r--private/ntos/nthals/halalpha/am29f400.h97
-rw-r--r--private/ntos/nthals/halalpha/apecs.c337
-rw-r--r--private/ntos/nthals/halalpha/apecs.h647
-rw-r--r--private/ntos/nthals/halalpha/apecserr.c1542
-rw-r--r--private/ntos/nthals/halalpha/apecsio.s701
-rw-r--r--private/ntos/nthals/halalpha/axintsup.c763
-rw-r--r--private/ntos/nthals/halalpha/bios.c105
-rw-r--r--private/ntos/nthals/halalpha/cache.c225
-rw-r--r--private/ntos/nthals/halalpha/cia.c769
-rw-r--r--private/ntos/nthals/halalpha/cia.h1141
-rw-r--r--private/ntos/nthals/halalpha/ciaaddr.c567
-rw-r--r--private/ntos/nthals/halalpha/ciaerr.c1642
-rw-r--r--private/ntos/nthals/halalpha/ciaio.s2820
-rw-r--r--private/ntos/nthals/halalpha/ciamapio.c154
-rw-r--r--private/ntos/nthals/halalpha/cmos8k.c246
-rw-r--r--private/ntos/nthals/halalpha/cmos8k.h32
-rw-r--r--private/ntos/nthals/halalpha/devintr.s71
-rw-r--r--private/ntos/nthals/halalpha/ebsgdma.c2307
-rw-r--r--private/ntos/nthals/halalpha/ebsgdma.h180
-rw-r--r--private/ntos/nthals/halalpha/eeprom8k.c391
-rw-r--r--private/ntos/nthals/halalpha/eisaprof.c517
-rw-r--r--private/ntos/nthals/halalpha/eisasup.c1477
-rw-r--r--private/ntos/nthals/halalpha/environ.c952
-rw-r--r--private/ntos/nthals/halalpha/environ.h167
-rw-r--r--private/ntos/nthals/halalpha/errframe.h697
-rw-r--r--private/ntos/nthals/halalpha/errplat.h774
-rw-r--r--private/ntos/nthals/halalpha/ev4cache.c488
-rw-r--r--private/ntos/nthals/halalpha/ev4int.c1013
-rw-r--r--private/ntos/nthals/halalpha/ev4ints.s272
-rw-r--r--private/ntos/nthals/halalpha/ev4mchk.c709
-rw-r--r--private/ntos/nthals/halalpha/ev4mem.s146
-rw-r--r--private/ntos/nthals/halalpha/ev4parit.c336
-rw-r--r--private/ntos/nthals/halalpha/ev4prof.c591
-rw-r--r--private/ntos/nthals/halalpha/ev5cache.c475
-rw-r--r--private/ntos/nthals/halalpha/ev5int.c440
-rw-r--r--private/ntos/nthals/halalpha/ev5ints.s397
-rw-r--r--private/ntos/nthals/halalpha/ev5mchk.c677
-rw-r--r--private/ntos/nthals/halalpha/ev5mem.s231
-rw-r--r--private/ntos/nthals/halalpha/ev5prof.c741
-rw-r--r--private/ntos/nthals/halalpha/flash8k.c323
-rw-r--r--private/ntos/nthals/halalpha/flash8k.h130
-rw-r--r--private/ntos/nthals/halalpha/flashdrv.c23
-rw-r--r--private/ntos/nthals/halalpha/fwreturn.c255
-rw-r--r--private/ntos/nthals/halalpha/gru.h84
-rw-r--r--private/ntos/nthals/halalpha/haldebug.c58
-rw-r--r--private/ntos/nthals/halalpha/haldump.c83
-rw-r--r--private/ntos/nthals/halalpha/halisa.h89
-rw-r--r--private/ntos/nthals/halalpha/halp.h1095
-rw-r--r--private/ntos/nthals/halalpha/halpal.s276
-rw-r--r--private/ntos/nthals/halalpha/halpcsl.h187
-rw-r--r--private/ntos/nthals/halalpha/halprof.c179
-rw-r--r--private/ntos/nthals/halalpha/halprof.h77
-rw-r--r--private/ntos/nthals/halalpha/haltsup.s110
-rw-r--r--private/ntos/nthals/halalpha/halvfont.h233
-rw-r--r--private/ntos/nthals/halalpha/halvga.h72
-rw-r--r--private/ntos/nthals/halalpha/idle.s62
-rw-r--r--private/ntos/nthals/halalpha/info.c180
-rw-r--r--private/ntos/nthals/halalpha/inithal.c1052
-rw-r--r--private/ntos/nthals/halalpha/intsup.s256
-rw-r--r--private/ntos/nthals/halalpha/ioproc.c104
-rw-r--r--private/ntos/nthals/halalpha/iousage.c527
-rw-r--r--private/ntos/nthals/halalpha/iousage.h85
-rw-r--r--private/ntos/nthals/halalpha/isaaddr.h75
-rw-r--r--private/ntos/nthals/halalpha/lca4.c657
-rw-r--r--private/ntos/nthals/halalpha/lca4.h669
-rw-r--r--private/ntos/nthals/halalpha/lca4err.c1153
-rw-r--r--private/ntos/nthals/halalpha/lcaioacc.s746
-rw-r--r--private/ntos/nthals/halalpha/memory.c575
-rw-r--r--private/ntos/nthals/halalpha/nvenv.c533
-rw-r--r--private/ntos/nthals/halalpha/nvram.c1452
-rw-r--r--private/ntos/nthals/halalpha/nvram.h215
-rw-r--r--private/ntos/nthals/halalpha/pciesc.c477
-rw-r--r--private/ntos/nthals/halalpha/pcip.h178
-rw-r--r--private/ntos/nthals/halalpha/pcisio.c483
-rw-r--r--private/ntos/nthals/halalpha/pcisup.c2453
-rw-r--r--private/ntos/nthals/halalpha/pcrtc.c381
-rw-r--r--private/ntos/nthals/halalpha/pcrtc.h166
-rw-r--r--private/ntos/nthals/halalpha/pcserial.c596
-rw-r--r--private/ntos/nthals/halalpha/pcspeakr.c136
-rw-r--r--private/ntos/nthals/halalpha/perf8254.c457
-rw-r--r--private/ntos/nthals/halalpha/perfcntr.c260
-rw-r--r--private/ntos/nthals/halalpha/t2.c760
-rw-r--r--private/ntos/nthals/halalpha/t2.h550
-rw-r--r--private/ntos/nthals/halalpha/vga.c608
90 files changed, 47809 insertions, 0 deletions
diff --git a/private/ntos/nthals/halalpha/28f008sa.c b/private/ntos/nthals/halalpha/28f008sa.c
new file mode 100644
index 000000000..487a908d8
--- /dev/null
+++ b/private/ntos/nthals/halalpha/28f008sa.c
@@ -0,0 +1,317 @@
+#include "halp.h"
+#include "arccodes.h"
+#include "flash8k.h"
+
+#define I28F008SA_DEVICE_SIZE 0x100000
+
+#define SET_READ_ARRAY 0xff
+#define SET_BYTE_WRITE 0x40
+#define SET_ERASE_BLOCK 0x20
+#define CONFIRM_ERASE_BLOCK 0xd0
+#define READ_STATUS 0x70
+#define RESET_STATUS 0x50
+#define ID_REQUEST 0x90
+
+#define MANUFACTURER_ID 0x89
+#define DEVICE_ID 0xa2
+
+#define BLOCK_SIZE 0x10000
+#define BLANK_DATA 0xff
+
+#define TIMEOUT_VALUE 5000000
+
+#define STATUS_READY 0x80
+#define STATUS_ERASE_SUSP 0x40
+#define STATUS_ERASE_ERR 0x20
+#define STATUS_WRITE_ERR 0x10
+#define STATUS_VPP_LOW 0x08
+#define STATUS_CMD_SEQ_ERR (STATUS_WRITE_ERR | STATUS_READ_ERR)
+
+//
+// Local function prototypes
+//
+PFLASH_DRIVER
+I28F008SA_Initialize(
+ IN PUCHAR NvRamPtr
+ );
+
+ARC_STATUS
+I28F008SA_SetReadMode(
+ IN PUCHAR Address
+ );
+
+ARC_STATUS
+I28F008SA_WriteByte(
+ IN PUCHAR Address,
+ IN UCHAR Data
+ );
+
+ARC_STATUS
+I28F008SA_EraseBlock(
+ IN PUCHAR Address
+ );
+
+ARC_STATUS
+I28F008SA_CheckStatus(
+ IN PUCHAR Address,
+ FLASH_OPERATIONS Operation
+ );
+
+PUCHAR
+I28F008SA_BlockAlign(
+ IN PUCHAR Address
+ );
+
+UCHAR
+I28F008SA_ReadByte(
+ IN PUCHAR Address
+ );
+
+BOOLEAN
+I28F008SA_OverwriteCheck(
+ IN UCHAR OldData,
+ IN UCHAR NewData
+ );
+
+ULONG
+I28F008SA_BlockSize(
+ IN PUCHAR Address
+ );
+
+ULONG
+I28F008SA_GetLastError(
+ VOID
+ );
+
+static
+VOID
+I28F008SA_SetLastError(
+ ULONG FlashStatus
+ );
+
+FLASH_DRIVER I28F008SA_DriverInformation = {
+ "Intel 28F008SA",
+ I28F008SA_SetReadMode, // SetReadModeFunction
+ I28F008SA_WriteByte, // WriteByteFunction
+ I28F008SA_EraseBlock, // EraseBlockFunction
+ I28F008SA_BlockAlign, // AlignBlockFunction
+ I28F008SA_ReadByte, // ReadByteFunction
+ I28F008SA_OverwriteCheck, // OverwriteCheckFunction
+ I28F008SA_BlockSize, // BlockSizeFunction
+ I28F008SA_GetLastError, // GetLastErrorFunction
+ I28F008SA_DEVICE_SIZE, // DeviceSize
+ BLANK_DATA // ErasedData
+ };
+
+static ULONG I28F008SA_LastError;
+
+PFLASH_DRIVER
+I28F008SA_Initialize(
+ IN PUCHAR NvRamPtr
+ )
+{
+ PFLASH_DRIVER ReturnDriver = NULL;
+ UCHAR ManufacturerID;
+ UCHAR DeviceID;
+
+ NvRamPtr = I28F008SA_BlockAlign(NvRamPtr);
+
+ WRITE_CONFIG_RAM_DATA(NvRamPtr, ID_REQUEST);
+
+ ManufacturerID = READ_CONFIG_RAM_DATA(NvRamPtr);
+ DeviceID = READ_CONFIG_RAM_DATA((PUCHAR)((ULONG)NvRamPtr + 1));
+
+ if ((ManufacturerID == MANUFACTURER_ID) && (DeviceID == DEVICE_ID)) {
+ I28F008SA_LastError = 0;
+ I28F008SA_SetReadMode(NvRamPtr);
+ ReturnDriver = &I28F008SA_DriverInformation;
+ }
+
+ return ReturnDriver;
+}
+
+ARC_STATUS
+I28F008SA_SetReadMode(
+ IN PUCHAR NvRamPtr
+ )
+{
+ WRITE_CONFIG_RAM_DATA(NvRamPtr, SET_READ_ARRAY);
+ HalpMb();
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+I28F008SA_WriteByte(
+ IN PUCHAR NvRamPtr,
+ IN UCHAR Data
+ )
+{
+ ARC_STATUS ReturnStatus;
+
+ I28F008SA_SetReadMode(NvRamPtr);
+
+ WRITE_CONFIG_RAM_DATA(NvRamPtr, SET_BYTE_WRITE);
+ WRITE_CONFIG_RAM_DATA(NvRamPtr, Data);
+
+ ReturnStatus = I28F008SA_CheckStatus(NvRamPtr, FlashByteWrite);
+
+ I28F008SA_SetReadMode(NvRamPtr);
+
+ return ReturnStatus;
+}
+
+ARC_STATUS
+I28F008SA_EraseBlock (
+ IN PUCHAR NvRamPtr
+ )
+{
+ ARC_STATUS ReturnStatus;
+
+ WRITE_CONFIG_RAM_DATA(NvRamPtr, SET_ERASE_BLOCK);
+ WRITE_CONFIG_RAM_DATA(NvRamPtr, CONFIRM_ERASE_BLOCK);
+
+ ReturnStatus = I28F008SA_CheckStatus(NvRamPtr, FlashEraseBlock);
+
+ I28F008SA_SetReadMode(NvRamPtr);
+
+ return ReturnStatus;
+}
+
+ARC_STATUS
+I28F008SA_CheckStatus (
+ IN PUCHAR NvRamPtr,
+ IN FLASH_OPERATIONS Operation
+ )
+{
+ ARC_STATUS ReturnStatus = EIO;
+ ULONG Timeout;
+ UCHAR FlashStatus;
+
+ //
+ // Keep reading the status until the device is done with its
+ // current operation.
+ //
+ Timeout = TIMEOUT_VALUE;
+ do {
+ WRITE_CONFIG_RAM_DATA(NvRamPtr, READ_STATUS);
+ FlashStatus = READ_CONFIG_RAM_DATA(NvRamPtr);
+ KeStallExecutionProcessor(1);
+ Timeout--;
+ } while (((FlashStatus & 0x80) == 0) && (Timeout > 0));
+
+ //
+ // Check the status for the operation requested.
+ //
+ switch(Operation) {
+ case FlashByteWrite:
+ if ((FlashStatus & 0x18) == 0) {
+ ReturnStatus = ESUCCESS;
+ } else {
+ I28F008SA_SetLastError(FlashStatus & 0x18);
+ }
+ break;
+ case FlashEraseBlock:
+ if (((FlashStatus & 0x28) == 0) && ((FlashStatus & 0x30) != 0x30)) {
+ ReturnStatus = ESUCCESS;
+ } else {
+ I28F008SA_SetLastError(FlashStatus & 0x28);
+ }
+ break;
+ }
+ if ((FlashStatus & 0x80) == 0) {
+ ReturnStatus = EIO;
+ I28F008SA_SetLastError(0);
+ }
+
+ //
+ // Clear the flash status register
+ // This is a silent operation. The status that gets returned is the
+ // status of the real operation as determined above.
+ //
+ WRITE_CONFIG_RAM_DATA(NvRamPtr, RESET_STATUS);
+ Timeout = TIMEOUT_VALUE;
+ do {
+ WRITE_CONFIG_RAM_DATA(NvRamPtr, READ_STATUS);
+ FlashStatus = READ_CONFIG_RAM_DATA(NvRamPtr);
+ KeStallExecutionProcessor(1);
+ Timeout--;
+ } while (((FlashStatus & 0x80) == 0) && (Timeout > 0));
+
+ return ReturnStatus;
+}
+
+PUCHAR
+I28F008SA_BlockAlign(
+ IN PUCHAR Address
+ )
+{
+ return (PUCHAR)((ULONG)Address & ~(BLOCK_SIZE-1));
+}
+
+UCHAR
+I28F008SA_ReadByte(
+ IN PUCHAR Address
+ )
+{
+ return READ_CONFIG_RAM_DATA(Address);
+}
+
+BOOLEAN
+I28F008SA_OverwriteCheck(
+ IN UCHAR OldData,
+ IN UCHAR NewData
+ )
+/*++
+
+Return Value:
+
+ Zero if OldData can be overwritten with NewData.
+ Non-zero if device must be erased to write NewData.
+
+--*/
+{
+ return (~OldData & NewData) ? FALSE : TRUE;
+}
+
+ULONG
+I28F008SA_BlockSize(
+ IN PUCHAR Address
+ )
+/*++
+
+Return Value:
+
+ The block size of the device. This is a constant because all
+ blocks in the 28f008sa are the same size.
+
+--*/
+{
+ return BLOCK_SIZE;
+}
+
+ULONG
+I28F008SA_GetLastError(
+ VOID
+ )
+{
+ return I28F008SA_LastError;
+}
+
+static
+VOID
+I28F008SA_SetLastError(
+ ULONG FlashStatus
+ )
+{
+ I28F008SA_LastError = ERROR_UNKNOWN;
+ if (FlashStatus == 0)
+ I28F008SA_LastError = ERROR_TIMEOUT;
+ if (FlashStatus & STATUS_WRITE_ERR)
+ I28F008SA_LastError = ERROR_WRITE_ERROR;
+ if (FlashStatus & STATUS_ERASE_ERR)
+ I28F008SA_LastError = ERROR_ERASE_ERROR;
+ if (FlashStatus & STATUS_VPP_LOW)
+ I28F008SA_LastError = ERROR_VPP_LOW;
+}
+
diff --git a/private/ntos/nthals/halalpha/29f040.c b/private/ntos/nthals/halalpha/29f040.c
new file mode 100644
index 000000000..331b32584
--- /dev/null
+++ b/private/ntos/nthals/halalpha/29f040.c
@@ -0,0 +1,420 @@
+/*++
+
+File: 29f040.c
+
+Purpose: Firmware/HAL driver for AMD Am29F040 512kB flash device.
+
+--*/
+
+#include "halp.h"
+#include "arccodes.h"
+#include "flash8k.h"
+
+#define Am29F040_DEVICE_SIZE 0x80000
+#define Am29F080_DEVICE_SIZE 0x100000
+
+#define Am29F040_DEVICE_NAME "AMD Am29F040"
+#define Am29F080_DEVICE_NAME "AMD Am29F080"
+
+#define COMMAND_OFFSET 0x5555
+
+#define COMMAND_PREFIX_OFFSET1 (COMMAND_OFFSET)
+#define COMMAND_PREFIX_COMMAND1 0xaa
+
+#define COMMAND_PREFIX_OFFSET2 0x2aaa
+#define COMMAND_PREFIX_COMMAND2 0x55
+
+#define SET_READ_ARRAY 0xf0 // write to COMMAND_ADDRESS
+#define SET_BYTE_WRITE 0xa0 // write to COMMAND_ADDRESS
+#define SET_ERASE 0x80 // write to COMMAND_ADDRESS
+#define CONFIRM_ERASE_BLOCK 0x30 // write to the base address of the block
+#define ID_REQUEST 0x90 // write to COMMAND_ADDRESS
+
+#define MANUFACTURER_ID 0x01
+#define Am29F040_DEVICE_ID 0xa4
+#define Am29F080_DEVICE_ID 0xd5
+
+#define BLOCK_SIZE 0x10000
+#define BLANK_DATA 0xff
+
+#define TIMEOUT_VALUE 5000000
+
+#define COMMAND_PREFIX(address) { \
+ PUCHAR PrefixAddress1; \
+ PUCHAR PrefixAddress2; \
+ PrefixAddress1 = PrefixAddress2 = Am29F040_BlockAlign(address); \
+ PrefixAddress1 = (PUCHAR)((ULONG)PrefixAddress1 + COMMAND_PREFIX_OFFSET1); \
+ PrefixAddress2 = (PUCHAR)((ULONG)PrefixAddress2 + COMMAND_PREFIX_OFFSET2); \
+ WRITE_CONFIG_RAM_DATA(PrefixAddress1, COMMAND_PREFIX_COMMAND1); \
+ HalpMb(); \
+ WRITE_CONFIG_RAM_DATA(PrefixAddress2, COMMAND_PREFIX_COMMAND2); \
+ HalpMb(); \
+ }
+
+#define COMMAND_ADDRESS(address) \
+ ((PUCHAR)(((ULONG)(BLOCK_ALIGN(address)) + (COMMAND_OFFSET))))
+
+#define BLOCK_ALIGN(address) \
+ ((PUCHAR)((ULONG)(address) & ~(BLOCK_SIZE-1)))
+
+//
+// Local function prototypes
+//
+PFLASH_DRIVER
+Am29F040_Initialize(
+ IN PUCHAR NvRamPtr
+ );
+
+ARC_STATUS
+Am29F040_SetReadMode(
+ IN PUCHAR Address
+ );
+
+ARC_STATUS
+Am29F040_WriteByte(
+ IN PUCHAR Address,
+ IN UCHAR Data
+ );
+
+ARC_STATUS
+Am29F040_EraseBlock(
+ IN PUCHAR Address
+ );
+
+ARC_STATUS
+Am29F040_CheckStatus(
+ IN PUCHAR Address,
+ IN UCHAR Data,
+ IN FLASH_OPERATIONS Operation
+ );
+
+PUCHAR
+Am29F040_BlockAlign(
+ IN PUCHAR Address
+ );
+
+UCHAR
+Am29F040_ReadByte(
+ IN PUCHAR Address
+ );
+
+BOOLEAN
+Am29F040_OverwriteCheck(
+ IN UCHAR OldData,
+ IN UCHAR NewData
+ );
+
+ULONG
+Am29F040_BlockSize(
+ IN PUCHAR Address
+ );
+
+ULONG
+Am29F040_GetLastError(
+ VOID
+ );
+
+static
+VOID
+Am29F040_SetLastError(
+ ULONG FlashStatus
+ );
+
+FLASH_DRIVER Am29F040_DriverInformation = {
+ Am29F040_DEVICE_NAME,
+ Am29F040_SetReadMode, // SetReadModeFunction
+ Am29F040_WriteByte, // WriteByteFunction
+ Am29F040_EraseBlock, // EraseBlockFunction
+ Am29F040_BlockAlign, // AlignBlockFunction
+ Am29F040_ReadByte, // ReadByteFunction
+ Am29F040_OverwriteCheck, // OverwriteCheckFunction
+ Am29F040_BlockSize, // BlockSizeFunction
+ Am29F040_GetLastError, // GetLastErrorFunction
+ Am29F040_DEVICE_SIZE, // DeviceSize
+ BLANK_DATA // ErasedData
+ };
+
+FLASH_DRIVER Am29F080_DriverInformation = {
+ Am29F080_DEVICE_NAME,
+ Am29F040_SetReadMode, // SetReadModeFunction
+ Am29F040_WriteByte, // WriteByteFunction
+ Am29F040_EraseBlock, // EraseBlockFunction
+ Am29F040_BlockAlign, // AlignBlockFunction
+ Am29F040_ReadByte, // ReadByteFunction
+ Am29F040_OverwriteCheck, // OverwriteCheckFunction
+ Am29F040_BlockSize, // BlockSizeFunction
+ Am29F040_GetLastError, // GetLastErrorFunction
+ Am29F080_DEVICE_SIZE, // DeviceSize
+ BLANK_DATA // ErasedData
+ };
+
+
+static ULONG Am29F040_LastError;
+
+PFLASH_DRIVER
+Am29F040_Initialize(
+ IN PUCHAR NvRamPtr
+ )
+{
+ PFLASH_DRIVER ReturnDriver = NULL;
+ UCHAR ManufacturerID;
+ UCHAR DeviceID;
+
+ NvRamPtr = Am29F040_BlockAlign(NvRamPtr);
+
+ COMMAND_PREFIX(NvRamPtr);
+ WRITE_CONFIG_RAM_DATA(COMMAND_ADDRESS(NvRamPtr), ID_REQUEST);
+
+ ManufacturerID = READ_CONFIG_RAM_DATA(NvRamPtr);
+ DeviceID = READ_CONFIG_RAM_DATA((PUCHAR)((ULONG)NvRamPtr + 1));
+
+ if ((ManufacturerID == MANUFACTURER_ID) &&
+ (DeviceID == Am29F040_DEVICE_ID)) {
+
+ Am29F040_LastError = 0;
+ Am29F040_SetReadMode(NvRamPtr);
+ ReturnDriver = &Am29F040_DriverInformation;
+ }
+
+ return ReturnDriver;
+}
+
+PFLASH_DRIVER
+Am29F080_Initialize(
+ IN PUCHAR NvRamPtr
+ )
+{
+ PFLASH_DRIVER ReturnDriver = NULL;
+ UCHAR ManufacturerID;
+ UCHAR DeviceID;
+
+ NvRamPtr = Am29F040_BlockAlign(NvRamPtr);
+
+ COMMAND_PREFIX(NvRamPtr);
+ WRITE_CONFIG_RAM_DATA(COMMAND_ADDRESS(NvRamPtr), ID_REQUEST);
+
+ ManufacturerID = READ_CONFIG_RAM_DATA(NvRamPtr);
+ DeviceID = READ_CONFIG_RAM_DATA((PUCHAR)((ULONG)NvRamPtr + 1));
+
+ if ((ManufacturerID == MANUFACTURER_ID) &&
+ (DeviceID == Am29F080_DEVICE_ID)) {
+
+ Am29F040_LastError = 0;
+ Am29F040_SetReadMode(NvRamPtr);
+ ReturnDriver = &Am29F080_DriverInformation;
+ }
+
+ return ReturnDriver;
+}
+
+ARC_STATUS
+Am29F040_SetReadMode(
+ IN PUCHAR NvRamPtr
+ )
+{
+ COMMAND_PREFIX(NvRamPtr);
+ WRITE_CONFIG_RAM_DATA(COMMAND_ADDRESS(NvRamPtr), SET_READ_ARRAY);
+
+ return ESUCCESS;
+}
+
+ARC_STATUS
+Am29F040_WriteByte(
+ IN PUCHAR NvRamPtr,
+ IN UCHAR Data
+ )
+{
+ ARC_STATUS ReturnStatus;
+
+ Am29F040_SetReadMode(NvRamPtr);
+
+ COMMAND_PREFIX(NvRamPtr);
+ WRITE_CONFIG_RAM_DATA(COMMAND_ADDRESS(NvRamPtr), SET_BYTE_WRITE);
+ WRITE_CONFIG_RAM_DATA(NvRamPtr, Data);
+
+ ReturnStatus = Am29F040_CheckStatus(NvRamPtr, Data, FlashByteWrite);
+
+ Am29F040_SetReadMode(NvRamPtr);
+
+ return ReturnStatus;
+}
+
+ARC_STATUS
+Am29F040_EraseBlock (
+ IN PUCHAR NvRamPtr
+ )
+{
+ ARC_STATUS ReturnStatus;
+
+ NvRamPtr = Am29F040_BlockAlign(NvRamPtr);
+
+ COMMAND_PREFIX(NvRamPtr);
+ WRITE_CONFIG_RAM_DATA(COMMAND_ADDRESS(NvRamPtr), SET_ERASE);
+ COMMAND_PREFIX(NvRamPtr);
+ WRITE_CONFIG_RAM_DATA(COMMAND_ADDRESS(NvRamPtr), CONFIRM_ERASE_BLOCK);
+
+ ReturnStatus = Am29F040_CheckStatus(NvRamPtr, 0xff, FlashEraseBlock);
+
+ Am29F040_SetReadMode(NvRamPtr);
+
+ return ReturnStatus;
+}
+
+ARC_STATUS
+Am29F040_CheckStatus (
+ IN PUCHAR NvRamPtr,
+ IN UCHAR Data,
+ IN FLASH_OPERATIONS Operation
+ )
+{
+ ARC_STATUS ReturnStatus = EIO;
+ BOOLEAN StopReading = FALSE;
+ UCHAR FlashStatus;
+ ULONG Timeout;
+
+#if 0
+ //
+ // Keep reading the status until the device is done with its
+ // current operation.
+ //
+ do {
+ FlashStatus = READ_CONFIG_RAM_DATA(NvRamPtr);
+ if (FlashStatus & 0x20) {
+ StopReading = TRUE;
+ FlashStatus = READ_CONFIG_RAM_DATA(NvRamPtr);
+ }
+ } while (!StopReading && (((FlashStatus ^ Data) & 0x80) != 0));
+
+ if ((FlashStatus ^ Data) != 0) {
+ ReturnStatus = ESUCCESS;
+ } else {
+ ReturnStatus = EIO;
+ }
+
+ return ReturnStatus;
+#else
+ //
+ // If we are doing an erase command, check whether the erase command
+ // was accepted. This is supposed to happen within the first 100 usec.
+ //
+
+ if (Operation == FlashEraseBlock) {
+ Timeout = TIMEOUT_VALUE;
+
+ while (((READ_CONFIG_RAM_DATA(NvRamPtr) & 0x08) != 0x08) &&
+ (Timeout > 0)) {
+ KeStallExecutionProcessor(1);
+ Timeout--;
+ }
+
+ if (Timeout == 0) {
+ ReturnStatus = EIO;
+ Am29F040_SetLastError(0);
+ return ReturnStatus;
+ }
+ }
+
+ //
+ // Now wait for the actual status
+ //
+ Timeout = TIMEOUT_VALUE;
+ do {
+ FlashStatus = READ_CONFIG_RAM_DATA(NvRamPtr);
+
+ if (((FlashStatus ^ Data) & 0x80) == 0) {
+ ReturnStatus = ESUCCESS;
+ break;
+ }
+
+ if (FlashStatus & 0x20) {
+ if (((READ_CONFIG_RAM_DATA(NvRamPtr) ^ Data) & 0x80) == 0) {
+ ReturnStatus = ESUCCESS;
+ break;
+ } else {
+ ReturnStatus = EIO;
+ Am29F040_SetLastError(Operation | 0x80000000);
+ break;
+ }
+ }
+ KeStallExecutionProcessor(1);
+ Timeout--;
+ } while (Timeout > 0);
+
+ if (Timeout == 0) {
+ ReturnStatus = EIO;
+ Am29F040_SetLastError(0);
+ }
+
+ return ReturnStatus;
+#endif
+}
+
+PUCHAR
+Am29F040_BlockAlign(
+ IN PUCHAR Address
+ )
+{
+ return BLOCK_ALIGN(Address);
+}
+
+UCHAR
+Am29F040_ReadByte(
+ IN PUCHAR Address
+ )
+{
+ return READ_CONFIG_RAM_DATA(Address);
+}
+
+BOOLEAN
+Am29F040_OverwriteCheck(
+ IN UCHAR OldData,
+ IN UCHAR NewData
+ )
+/*++
+
+Return Value:
+
+ TRUE if OldData can be overwritten with NewData.
+ FALSE if OldData must be erased before writing NewData.
+
+--*/
+{
+ return (~OldData & NewData) ? FALSE : TRUE;
+}
+
+ULONG
+Am29F040_BlockSize(
+ IN PUCHAR Address
+ )
+{
+ return BLOCK_SIZE;
+}
+
+ULONG
+Am29F040_GetLastError(
+ VOID
+ )
+{
+ return Am29F040_LastError;
+}
+
+static
+VOID
+Am29F040_SetLastError(
+ ULONG FlashStatus
+ )
+{
+ Am29F040_LastError = ERROR_UNKNOWN;
+ if (FlashStatus == 0) {
+ Am29F040_LastError = ERROR_TIMEOUT;
+ } else {
+ switch(FlashStatus & ~0x80000000) {
+ case FlashByteWrite:
+ Am29F040_LastError = ERROR_WRITE_ERROR;
+ break;
+ case FlashEraseBlock:
+ Am29F040_LastError = ERROR_ERASE_ERROR;
+ break;
+ }
+ }
+}
diff --git a/private/ntos/nthals/halalpha/adjust.c b/private/ntos/nthals/halalpha/adjust.c
new file mode 100644
index 000000000..cc8aa4e84
--- /dev/null
+++ b/private/ntos/nthals/halalpha/adjust.c
@@ -0,0 +1,149 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ adjust.c
+
+Abstract:
+
+ This module contains platform-independent slot resource adjust routines.
+
+Author:
+
+ Eric Rehm 6-January-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE,HalpAdjustResourceListUpperLimits)
+#endif
+
+VOID
+HalpAdjustResourceListUpperLimits (
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList,
+ IN LARGE_INTEGER MaximumPortAddress,
+ IN LARGE_INTEGER MaximumMemoryAddress,
+ IN ULONG MaximumInterruptVector,
+ IN ULONG MaximumDmaChannel
+ )
+/*++
+
+Routine Description:
+
+ Adjust a pResource list with respect to the upper bounds supplied.
+ (A resource is changed only if it execceds the maximum.)
+
+Arguments:
+
+ pResouceList - Resource list to be checked.
+
+ MaximumPortAddress - Maximum I/O port allowed.
+
+ MaximumMemoryAddress - Maximum I/O memory address allowed.
+
+ MaximumInterruptVector - Maximum interrupt vector allowed.
+
+ MaximumDmaChannel - Maximum dma channel allowed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PIO_RESOURCE_REQUIREMENTS_LIST CompleteList;
+ PIO_RESOURCE_LIST ResourceList;
+ PIO_RESOURCE_DESCRIPTOR Descriptor;
+ ULONG alt, cnt;
+
+
+ //
+ // Walk each ResourceList and shrink any values to system limits
+ //
+
+ CompleteList = *pResourceList;
+ ResourceList = CompleteList->List;
+
+ for (alt=0; alt < CompleteList->AlternativeLists; alt++) {
+ Descriptor = ResourceList->Descriptors;
+ for (cnt = ResourceList->Count; cnt; cnt--) {
+
+ //
+ // Make sure descriptor limits fall within the
+ // CompleteList->InterfaceType & CompleteList->BusNumber.
+ //
+ //
+
+ switch (Descriptor->Type) {
+ case CmResourceTypePort:
+ if (Descriptor->u.Port.MaximumAddress.QuadPart >
+ MaximumPortAddress.QuadPart) {
+
+ Descriptor->u.Port.MaximumAddress = MaximumPortAddress;
+ }
+
+ break;
+
+ case CmResourceTypeInterrupt:
+ if (Descriptor->u.Interrupt.MaximumVector >
+ MaximumInterruptVector ) {
+
+ Descriptor->u.Interrupt.MaximumVector =
+ MaximumInterruptVector;
+ }
+ break;
+
+ case CmResourceTypeMemory:
+ if (Descriptor->u.Memory.MaximumAddress.QuadPart >
+ MaximumMemoryAddress.QuadPart) {
+
+ Descriptor->u.Memory.MaximumAddress =
+ MaximumMemoryAddress;
+ }
+ break;
+
+ case CmResourceTypeDma:
+ if (Descriptor->u.Dma.MaximumChannel >
+ MaximumDmaChannel ) {
+
+ Descriptor->u.Dma.MaximumChannel =
+ MaximumDmaChannel;
+ }
+ break;
+
+#if DBG
+ default:
+ DbgPrint ("HalAdjustResourceList: Unkown resource type\n");
+ break;
+#endif
+ }
+
+ //
+ // Next descriptor
+ //
+ Descriptor++;
+ }
+
+ //
+ // Next Resource List
+ //
+ ResourceList = (PIO_RESOURCE_LIST) Descriptor;
+ }
+
+}
+
diff --git a/private/ntos/nthals/halalpha/allstart.c b/private/ntos/nthals/halalpha/allstart.c
new file mode 100644
index 000000000..9bb5501bc
--- /dev/null
+++ b/private/ntos/nthals/halalpha/allstart.c
@@ -0,0 +1,55 @@
+/*++
+
+Copyright (c) 1994 Microsoft Corporation
+
+Module Name:
+
+ allstart.c
+
+Abstract:
+
+
+ This module implements the platform specific operations that must be
+ performed after all processors have been started.
+
+Author:
+
+ John Vert (jvert) 23-Jun-1994
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+BOOLEAN
+HalAllProcessorsStarted (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function executes platform specific operations that must be
+ performed after all processors have been started. It is called
+ for each processor in the host configuration.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If platform specific operations are successful, then return TRUE.
+ Otherwise, return FALSE.
+
+--*/
+
+{
+ return TRUE;
+}
diff --git a/private/ntos/nthals/halalpha/alphaio.s b/private/ntos/nthals/halalpha/alphaio.s
new file mode 100644
index 000000000..ce9dd652b
--- /dev/null
+++ b/private/ntos/nthals/halalpha/alphaio.s
@@ -0,0 +1,1368 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ alphaio.s
+
+
+Abstract:
+
+ The module contains the functions to turn quasi virtual
+ addresses into an Alpha superpage virtual address
+ and then read or write based on the request.
+ (We are using EV4 64-bit superpage mode.)
+
+Author:
+
+ Joe Notarangelo 25-Oct-1993
+
+Environment:
+
+ Executes in kernel mode.
+
+Revision History:
+
+ 12-Jul-1994 - Eric Rehm - Added dense space I/O
+
+ 27-July-1994 - Sameer Dekate
+
+ Make a common file for all machines and optimize Read/Write
+ register buffer routines. Made a common routine with different
+ entry points for READ & WRITE_REGISTER_BUFFER routines
+
+--*/
+
+#include "chipset.h"
+#include "halalpha.h"
+
+
+
+ SBTTL( "Read I/O byte" )
+//++
+//
+// UCHAR
+// READ_REGISTER_UCHAR(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a byte location in PCI bus memory or I/O space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the I/O byte to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from I/O space.
+//
+//--
+
+ LEAF_ENTRY(READ_REGISTER_UCHAR)
+
+ ALTERNATE_ENTRY(READ_PORT_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get byte we need if eisa
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ ldiq t4, -0x4000 // 0xffff ffff ffff c000
+ sll t4, 28, t4 // 0xffff fc00 0000 0000
+ or t0, t4, t0 // superpage mode
+
+ mb
+ ldl v0, (t0) // get the longword
+ extbl v0, t3, v0 // get correct byte if eisa
+
+ ret zero, (ra) // return
+
+//
+// Dense space access: QVA is an offset into dense space
+//
+
+2:
+ and a0, 3, t3 // get byte we need
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, 3, a0 // clear <1:0> to get aligned longword
+
+ ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
+ or a0, t0, a0 // superpage mode: add offset to base
+
+ ldl v0, (a0) // get the longword
+ extbl v0, t3, v0 // get correct byte
+
+ ret zero, (ra) // return
+
+ .end READ_REGISTER_UCHAR
+
+
+ SBTTL( "Read I/O word(16 bits)" )
+//++
+//
+// USHORT
+// READ_REGISTER_USHORT(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a word location in PCI bus memory or I/O space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the I/O word to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from I/O space.
+//
+//--
+
+ LEAF_ENTRY(READ_REGISTER_USHORT)
+
+ ALTERNATE_ENTRY(READ_PORT_USHORT)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get word
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_WORD_LEN, t0 // or in the byte enables
+
+ mb
+ ldl v0, (t0) // get the longword
+ extwl v0,t3,v0 // get the correct word
+
+ ret zero, (ra) // return
+
+//
+// Dense space access: QVA is an offset into dense space
+//
+
+2:
+ and a0, 3, t3 // get word we need
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, 3, a0 // clear <1:0> to get aligned longword
+
+ ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
+ or a0,t0, a0 // superpage mode: add offset to base
+
+ ldl v0, (a0) // get the longword
+ extwl v0, t3, v0 // get correct word
+
+ ret zero, (ra) // return
+
+ .end READ_REGISTER_USHORT
+
+
+ SBTTL( "Read I/O longword(32 bits)" )
+//++
+//
+// ULONG
+// READ_REGISTER_ULONG(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a longword location in PCI bus memory or I/O space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the I/O longword to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from I/O space.
+//
+//--
+
+ LEAF_ENTRY(READ_REGISTER_ULONG)
+
+ ALTERNATE_ENTRY(READ_PORT_ULONG)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_LONG_LEN, t0 // or in the byte enables
+
+ mb
+ ldl v0, (t0) // read the longword
+
+ ret zero, (ra) // return
+
+//
+// Dense space access: QVA is an offset into dense space
+//
+
+2:
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
+ or a0, t0, a0 // superpage mode: add offset to base
+
+ ldl v0, (a0) // get the longword
+
+ ret zero, (ra) // return
+
+ .end READ_REGISTER_ULONG
+
+ SBTTL( "Write I/O byte" )
+//++
+//
+// VOID
+// WRITE_REGISTER_UCHAR(
+// IN PVOID RegisterQva,
+// IN UCHAR Value
+// )
+//
+// Routine Description:
+//
+// Writes a byte location in PCI bus memory or I/O space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the I/O byte to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_REGISTER_UCHAR)
+
+ ALTERNATE_ENTRY(WRITE_PORT_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get byte we need if eisa
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ or t0, t4, t0 // superpage mode
+
+ insbl a1,t3,t4 // put the byte in the correct position
+ stl t4, (t0) // write the byte
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Dense space access: QVA is an offset into dense space
+//
+
+2:
+ and a0, 3, t3 // get byte we need if eisa
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, 3, a0 // clear <1:0> to get aligned longword
+
+ ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
+ or a0, t0, a0 // superpage mode: add offset to base
+
+ ldl t1, (a0) // get the long
+ mskbl t1, t3, t1 // mask the proper byte
+ insbl a1, t3, t2 // put byte into position
+ bis t1, t2, t1 // merge byte in result
+ stl t1, (a0) // store the result
+ mb // order the write
+
+ ret zero, (ra) // return
+
+ .end WRITE_REGISTER_UCHAR
+
+
+ SBTTL( "Write I/O word (16 bits)" )
+//++
+//
+// VOID
+// WRITE_REGISTER_USHORT(
+// IN PVOID RegisterQva,
+// IN USHORT Value
+// )
+//
+// Routine Description:
+//
+// Writes a word location in PCI bus memory or I/O space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the I/O word to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_REGISTER_USHORT)
+
+ ALTERNATE_ENTRY(WRITE_PORT_USHORT)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get word
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_WORD_LEN, t0 // or in the byte enables
+
+ inswl a1,t3,t2 // put the word in the correct place
+ stl t2, (t0) // write the word
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Dense space access: QVA is an offset into dense space
+//
+
+2:
+ and a0, 3, t3 // get byte we need if eisa
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, 3, a0 // clear <1:0> to get aligned longword
+
+ ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
+ or a0, t0, a0 // superpage mode: add offset to base
+
+ ldl t1, (a0) // get the long
+ mskwl t1, t3, t1 // mask the proper word
+ inswl a1, t3, t2 // put word into position
+ bis t1, t2, t1 // merge in result
+ stl t1, (a0) // store the result
+ mb // order the write
+
+ ret zero, (ra) // return
+
+ .end WRITE_REGISTER_USHORT
+
+
+ SBTTL( "Write I/O longword (32 bits)" )
+//++
+//
+// VOID
+// WRITE_REGISTER_ULONG(
+// IN PVOID RegisterQva,
+// IN ULONG Value
+// )
+//
+// Routine Description:
+//
+// Writes a longword location in PCI bus memory or I/O space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the I/O longword to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_REGISTER_ULONG)
+
+ ALTERNATE_ENTRY(WRITE_PORT_ULONG)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_LONG_LEN, t0 // or in the byte enables
+
+ stl a1, (t0) // write the longword
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Dense space access: QVA is an offset into dense space
+//
+
+2:
+ zap a0, 0xf0, a0 // clear <63:32>
+ ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
+ or a0, t0, a0 // superpage mode: add offset to base
+
+ stl a1, (a0) // store the longword
+ mb // order the write
+
+ ret zero, (ra) // return
+
+ .end WRITE_REGISTER_ULONG
+
+
+//++
+//
+// VOID
+// READ_PORT_BUFFER_UCHAR(
+// IN PVOID PortQva,
+// IN PUCHAR Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Read multiple bytes from the specified port address into the
+// destination buffer.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to read.
+//
+// Buffer(a1) - Supplies a pointer to the buffer to fill with
+// the data read from the port.
+//
+// Count(a2) - Supplies the number of bytes to read.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_BUFFER_UCHAR)
+
+ and a0, 3, t3 // get byte we need if eisa
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ ldiq t4, -0x4000 // t4=ffff ffff ffff c000
+ sll t4, 28, t4 // t4=ffff fc00 0000 0000
+ or t0, t4, t0 // superpage mode
+
+ beq a2, 3f // if count==0 return
+2:
+ ldl v0, (t0) // get the longword
+ subl a2, 1, a2 // decrement count
+ extbl v0,t3,v0 // get the correct byte
+ stb v0,(a1) // cheat and let the assembler do it
+ addl a1, 1, a1 // next byte in buffer
+ bne a2, 2b // while count != 0
+3:
+ ret zero, (ra) // return
+
+ .end READ_PORT_BUFFER_UCHAR
+
+
+ SBTTL( "Read Buffer from Port Space in Ushorts")
+//++
+//
+// VOID
+// READ_PORT_BUFFER_USHORT(
+// IN PVOID PortQva,
+// IN PUSHORT Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Read multiple words from the specified port address into the
+// destination buffer.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to read.
+//
+// Buffer(a1) - Supplies a pointer to the buffer to fill with
+// the data read from the port.
+//
+// Count(a2) - Supplies the number of words to read.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_BUFFER_USHORT)
+
+ and a0, 3, t3 // get word we need
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ ldiq t4, -0x4000 // t4=ffff ffff ffff c000
+ sll t4, 28, t4 // t4=ffff fc00 0000 0000
+ or t0, t4, t0 // superpage mode
+ or t0, IO_WORD_LEN, t0 // or in the byte enables
+
+ beq a2, 3f // if count==0 return
+2:
+ ldl v0, (t0) // get the longword
+ subl a2, 1, a2 // decrement count
+ extwl v0,t3,v0 // get the correct word
+ stw v0,(a1) // cheat and let the assembler do it
+ addl a1, 2, a1 // next word in buffer
+ bne a2, 2b // while count != 0
+3:
+ ret zero, (ra) // return
+
+ .end READ_PORT_BUFFER_USHORT
+
+ SBTTL( "Read Buffer from Port Space in Ulongs")
+//++
+//
+// VOID
+// READ_PORT_BUFFER_ULONG(
+// IN PVOID PortQva,
+// IN PULONG Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Read multiple longwords from the specified port address into the
+// destination buffer.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to read.
+//
+// Buffer(a1) - Supplies a pointer to the buffer to fill with
+// the data read from the port.
+//
+// Count(a2) - Supplies the number of longwords to read.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_BUFFER_ULONG)
+
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+
+ ldiq t4, -0x4000 // t4=ffff ffff ffff c000
+ sll t4, 28, t4 // t4=ffff fc00 0000 0000
+ or t0, t4, t0 // superpage mode
+ or t0, IO_LONG_LEN, t0 // or in the byte enables
+
+ beq a2, 3f // if count==0 return
+2:
+ ldl v0, (t0) // get the longword
+ subl a2, 1, a2 // decrement count
+ stl v0,(a1) // cheat and let the assembler do it
+ addl a1, 4, a1 // next word in buffer
+ bne a2, 2b // while count != 0
+3:
+ ret zero, (ra) // return
+
+ .end READ_PORT_BUFFER_ULONG
+
+
+ SBTTL( "Write Buffer to Port Space in Uchars")
+//++
+//
+// VOID
+// WRITE_PORT_BUFFER_UCHAR(
+// IN PVOID PortQva,
+// IN PUCHAR Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Write multiple bytes from the source buffer to the specified port
+// address.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to write.
+//
+// Buffer(a1) - Supplies a pointer to the buffer containing the data
+// to write to the port.
+//
+// Count(a2) - Supplies the number of bytes to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_BUFFER_UCHAR)
+
+ and a0, 3, t3 // get byte we need if eisa
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ ldiq t4, -0x4000 // t4=ffff ffff ffff c000
+ sll t4, 28, t4 // t4=ffff fc00 0000 0000
+ or t0, t4, t0 // superpage mode
+
+ beq a2, 3f // if count==0 return
+2:
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ subl a2, 1, a2 // decrement count
+ extbl t1, a1, t1 // extract appropriate byte
+ addl a1, 1, a1 // increment buffer pointer
+ insbl t1, t3, t1 // put byte to appropriate lane
+ stl t1, 0(t0) // store to port
+ mb // push writes off chip
+ bne a2, 2b // while count != 0
+
+3:
+ ret zero, (ra) // return
+
+ .end WRITE_PORT_BUFFER_UCHAR
+
+ SBTTL( "Write Buffer to Port Space in Ushorts")
+//++
+//
+// VOID
+// WRITE_PORT_BUFFER_USHORT(
+// IN PVOID PortQva,
+// IN PSHORT Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Write multiple words from the source buffer to the specified port
+// address.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to write.
+//
+// Buffer(a1) - Supplies a pointer to the buffer containing the data
+// to write to the port.
+//
+// Count(a2) - Supplies the number of words to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_BUFFER_USHORT)
+
+ and a0, 3, t3 // get word we need
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ ldiq t4, -0x4000 // t4=ffff ffff ffff c000
+ sll t4, 28, t4 // t4=ffff fc00 0000 0000
+ or t0, t4, t0 // superpage mode
+ or t0, IO_WORD_LEN, t0 // or in the byte enables
+
+ beq a2, 3f // if count==0 return
+2:
+ ldq_u t1, 0(a1) // get quad surrounding word
+ subl a2, 1, a2 // decrement count
+ extwl t1, a1, t1 // extract appropriate word
+ addl a1, 2, a1 // increment buffer pointer
+ inswl t1, t3, t1 // put word in appropriate lane
+ stl t1, 0(t0) // store to port
+ mb // push writes off chip
+ bne a2, 2b // while count != 0
+
+3:
+ ret zero, (ra) // return
+
+ .end WRITE_PORT_BUFFER_USHORT
+
+
+ SBTTL( "Write Buffer to Port Space in Ulongs")
+//++
+//
+// VOID
+// WRITE_PORT_BUFFER_ULONG(
+// IN PVOID PortQva,
+// IN PULONG Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Write multiple longwords from the source buffer to the specified port
+// address.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to write.
+//
+// Buffer(a1) - Supplies a pointer to the buffer containing the data
+// to write to the port.
+//
+// Count(a2) - Supplies the number of longwords to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_BUFFER_ULONG)
+
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ ldiq t4, -0x4000 // t4=ffff ffff ffff c000
+ sll t4, 28, t4 // t4=ffff fc00 0000 0000
+ or t0, t4, t0 // superpage mode
+ or t0, IO_LONG_LEN, t0 // or in the byte enables
+
+ beq a2, 3f // if count==0 return
+2:
+ ldl t1, 0(a1) // a1 must be longword aligned
+ subl a2, 1, a2 // decrement count
+ stl t1, 0(t0) // store to port
+ mb // push writes off chip
+ addl a1, 4, a1 // increment buffer
+ bne a2, 2b // while count != 0
+
+3:
+ ret zero, (ra) // return
+
+ .end WRITE_PORT_BUFFER_ULONG
+
+
+ SBTTL( "Read Buffer from PCI Memory Space in Uchars")
+//++
+//
+// VOID
+// READ_REGISTER_BUFFER_UXXXXX(
+// IN PVOID RegisterQva,
+// IN PUCHAR Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Copies a buffer from PCI Memory Space to an in-memory buffer.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the starting QVA of the memory space buffer.
+//
+// Buffer(a1) - Supplies a pointer to the in-memory buffer to receive
+// the copied data.
+//
+// Count(a2) - Supplies the number of bytes, words or longwords to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(READ_REGISTER_BUFFER_ULONG)
+
+ sll a2, 1, a2 // convert number of longs to words
+
+ ALTERNATE_ENTRY(READ_REGISTER_BUFFER_USHORT)
+
+
+ sll a2, 1, a2 // convert number of words to chars
+
+ ALTERNATE_ENTRY(READ_REGISTER_BUFFER_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ beq t1, 1f // if (eq) go do sparse space
+
+//
+// Dense space access: QVA is an offset into dense space
+// Set IO address in t0
+//
+ ldil t8, 1 // DENSE FLAG
+ zap a0, 0xf0, a0 // clear <63:32>
+ ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
+ or a0, t0, t0 // superpage mode: add offset to base
+
+ ldil a3, 1 // Offset to next byte
+ ldil a4, 4 // Offset to next long
+ ldil a5, 0 // LONG LEN ENABLE
+
+ br zero 2f // go do the actual transfer
+
+//
+// Sparse memory
+// Set IO address in t0
+//
+
+1:
+ ldil t8, 0 // SPARSE FLAG
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ ldiq t4, -0x4000 // 0xffff ffff ffff c000
+ sll t4, 28, t4 // 0xffff fc00 0000 0000
+ or t0, t4, t0 // superpage mode
+
+ ldil a3, IO_BYTE_OFFSET // Offset to next byte
+ ldil a4, IO_LONG_OFFSET // Offset to next long
+ ldil a5, IO_LONG_LEN // LONG LEN ENABLE
+
+//
+// Do the ACTUAL TRANSFER
+// a2 = count in characters
+//
+
+2:
+ beq a2, 60f // if count == 0 goto 60f (return)
+
+//
+// Check alignment of src and destn
+//
+
+ and a0, 3, t3 // source alignment = t3
+ and a1, 3, t2 // destination alignment = t2
+ xor t2, t3, t4 // t4 = t2 xor t3
+ bne t4, 70f // if (t4!=0) do unaligned copy
+ // else do byte copies till alignment
+
+ beq t3, 20f // if t3==0 go do long word copies
+ // else do byte copies till alignment
+
+//
+// Src and Destn are not longword aligned but have same alignment
+// (sympathetically aligned) copy till alignment
+//
+
+10:
+ beq a2, 60f // if count == 0 goto 60f (return)
+ beq t8, 11f // if not DENSE goto 11f
+ bic t0, 3, t9 // clear bits <1:0> of src
+ ldl v0, 0(t9) // get the longword
+ br zero, 12f
+11:
+ ldl v0, 0(t0) // get the longword
+12:
+ subl a2, 1, a2 // decrement count
+ extbl v0, t3,v0 // get the correct byte
+ stb v0, (a1) // cheat and let the assembler do it
+ addq t0, a3, t0 // next I/O address
+ addl a1, 1, a1 // next byte in buffer
+ addl t3, 1, t3 // next byte in lane
+ and t3, 3, t3 // longword lanes
+ bne t3, 10b // while unaligned
+
+//
+// Src and Destn have same alignment and are longword aligned
+//
+
+20:
+ srl a2, 2, t3 // t3= #longwords to move
+ beq t3, 40f // if #longwords == 0 goto 40f
+ or t0, a5, t0 // We will now do LONG READS
+
+30:
+ ldl v0, 0(t0) // get the longword
+ subl t3, 1, t3 // decrement long word count
+ stl v0, (a1) // store the longword at destn
+ addq t0, a4, t0 // next I/O address
+ addl a1, 4, a1 // next longword in buffer
+ bne t3, 30b // while #longwords > 0
+
+//
+// Do byte copies of remaining data uncopied
+//
+ bic t0, a5, t0 // We will now do BYTE READS
+40:
+ and a2, 3, a2 // remaining Bytes to copy
+ beq a2, 60f // if count == 0 goto 60f
+
+50:
+ beq t8, 51f // if not DENSE goto 51f
+ bic t0, 3, t9 // clear bits <1:0> of src
+ ldl v0, 0(t9) // get the longword
+ br zero, 52f
+51:
+ ldl v0, 0(t0) // get the longword
+52:
+ subl a2, 1, a2 // decrement count
+ extbl v0, t3,v0 // get the correct byte
+ stb v0, (a1) // cheat and let the assembler do it
+ addl a1, 1, a1 // next byte in buffer
+ addq t0, a3, t0 // next I/O address
+ addl t3, 1, t3 // next byte in lane
+ and t3, 3, t3 // longword lanes
+ bne a2, 50b // while count > 0
+
+60:
+ ret zero, (ra) // return
+
+
+//
+// source IO alignment != destination memory alignment
+// move enough bytes to longword align the IO source
+// then move 32bit (longwords) storing unaligned into memory
+// then move residual bytes
+//
+// Align src IO addresses; unaligned destn memory
+//
+
+70:
+ beq t3, 90f // branch if source is long aligned
+//
+// Move bytes until IO src is at a longword boundary or bytes exhausted
+//
+
+80:
+ beq a2, 130f // if count == 0 goto 130f (return)
+ beq t8, 81f // if not DENSE goto 81f
+ bic t0, 3, t9 // clear bits <1:0> of src
+ ldl v0, 0(t9) // get the longword
+ br zero, 82f
+81:
+ ldl v0, 0(t0) // get the longword
+82:
+ subl a2, 1, a2 // decrement count
+ extbl v0, t3,v0 // get the correct byte
+ stb v0, (a1) // cheat and let the assembler do it
+ addl a1, 1, a1 // next byte in buffer
+ addq t0, a3, t0 // next I/O address
+ addl t3, 1, t3 // next byte in lane
+ and t3, 3, t3 // longword lanes
+ bne t3, 80b // while unaligned
+
+//
+// aligned IO source, unaligned memory destination
+//
+
+90:
+ srl a2, 3, t3 // quadwords to move
+ beq t3, 110f // if no quads finish with bytes copies
+
+ or t0, a5, t0 // We will now do LONG READS
+
+100:
+ //
+ // Decoding for Comment:
+ // S= sign, X= overwritten byte, V= Valid byte,assume destn align a1= 2
+ //
+ ldl t1, 0(t0) // load LW 0 from IO src SSSS 4321
+ ldq_u t4, 0(a1) // load destn merge XXVV VVVV
+ ldq_u t5, 7(a1) // load destn next merge VVXX XXXX
+ subl t3, 1, t3 // decrement quadwords to move
+
+ addq t0, a4, t0 // add LONG OFFSET to t0
+ ldl t2, 0(t0) // load LW 1 from IO src SSSS 8765
+
+ mskql t4, a1, t4 // mask low LW for merge 00VV VVVV
+ mskqh t5, a1, t5 // mask high LW for merge VV00 0000
+
+ zap t1, 0xf0, t1 // clear high LW for long 0 0000 4321
+ sll t2, 32, t2 // get long 1 to high longword 8765 0000
+ bis t1, t2, t1 // merge read quadword together8765 4321
+
+ addq t0, a4, t0 // increment to next long
+
+ insql t1, a1, t6 // position low QW for merge 2100 0000
+ insqh t1, a1, t7 // position high QW for merge 0087 6543
+
+ bis t4, t6, t4 // merge new data, low QW 21VV VVVV
+ bis t5, t7, t5 // merge new data, high QW VV87 6543
+
+ stq_u t5, 7(a1) // write high quadword
+ stq_u t4, 0(a1) // write low quadword
+
+ lda a1, 8(a1) // increment memory pointer
+ bne t3, 100b // while quadwords to move
+
+//
+// Do byte copies of the remaining data not yet copied
+//
+ bic t0, a5, t0 // We will now do BYTE READS
+110:
+ and a2, 7, a2 // remaining bytes to copy
+ beq a2, 130f // if count == 0 goto 130f (return)
+
+120:
+ beq t8, 121f // if not DENSE goto 121f
+ bic t0, 3, t9 // clear bits <1:0> of src
+ ldl v0, 0(t9) // get the longword
+ br zero, 122f
+121:
+ ldl v0, 0(t0) // get the longword
+122:
+ subl a2, 1, a2 // decrement count
+ extbl v0, t3,v0 // get the correct byte
+ stb v0, (a1) // cheat and let the assembler do it
+ addl a1, 1, a1 // next byte in buffer
+ addq t0, a3, t0 // next I/O address
+ addl t3, 1, t3 // next byte in lane
+ and t3, 3, t3 // longword lanes
+ bne a2, 120b // while count != 0
+
+130:
+ ret zero, (ra) // return
+
+ .end READ_REGISTER_BUFFER_ULONG // end for UCHAR & USHORT
+
+
+
+ SBTTL( "Write Buffer to PCI Memory Space in Uchars")
+//++
+//
+// VOID
+// WRITE_REGISTER_BUFFER_UXXXXX(
+// IN PVOID RegisterQva,
+// IN PUCHAR Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Copies an in-memory buffer to a PCI Memory Space buffer.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the starting QVA of the memory space buffer.
+//
+// Buffer(a1) - Supplies a pointer to the in-memory source buffer.
+//
+// Count(a2) - Supplies the number of bytes, words to longwords to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+ LEAF_ENTRY(WRITE_REGISTER_BUFFER_ULONG)
+
+ sll a2, 1, a2 // convert number of longs to words
+
+ ALTERNATE_ENTRY(WRITE_REGISTER_BUFFER_USHORT)
+
+ sll a2, 1, a2 // convert number of words to chars
+
+ ALTERNATE_ENTRY(WRITE_REGISTER_BUFFER_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ beq t1, 1f // if (eq) go do sparse space
+
+//
+// Dense space access: QVA is an offset into dense space
+// Set IO address in t0
+//
+
+ ldil t7, 1 // DENSE FLAG
+ zap a0, 0xf0, a0 // clear <63:32>
+ ldiq t0, PCI_DENSE_BASE_PHYSICAL_SUPERPAGE
+ or a0, t0, t0 // superpage mode: add offset to base
+
+ ldil a3, 1 // Offset to next byte
+ ldil a4, 4 // Offset to next long
+ ldil a5, 0 // LONG LEN ENABLE
+
+ br zero, 2f // go do the actual transfer
+
+//
+// Sparse Space
+// Set IO address in t0
+//
+
+1:
+ ldil t7, 0 // SPARSE FLAG
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ ldiq t4, -0x4000 // 0xffff ffff ffff c000
+ sll t4, 28, t4 // 0xffff fc00 0000 0000
+ or t0, t4, t0 // superpage mode
+
+ ldil a3, IO_BYTE_OFFSET // Offset to next byte
+ ldil a4, IO_LONG_OFFSET // Offset to next long
+ ldil a5, IO_LONG_LEN // LONG LEN ENABLE
+
+//
+// Do the ACTUAL TRANSFER
+// a2 = count in characters
+//
+
+2:
+ beq a2, 60f // if count == 0 goto 60f (return)
+
+//
+// Check alignment of src and destn
+//
+ and a0, 3, t3 // destn alignment = t3
+ and a1, 3, t2 // src alignment = t2
+ xor t2, t3, t4 // t4 = t2 xor t3
+ bne t4, 70f // if (t4!=0) do unaligned copy
+ // else do byte copies till alignment
+
+ beq t3, 20f // if t3==0 go do longword copies
+ // else do byte copies till alignment
+
+//
+// Src and Destn are not longword aligned but have same alignment
+// (sympathetically aligned) copy till alignment
+//
+
+10:
+ beq a2, 60f // if count == 0 goto 60f (return)
+
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ subl a2, 1, a2 // decrement count
+ extbl t1, a1, t1 // extract appropriate byte
+ addl a1, 1, a1 // increment buffer pointer
+ insbl t1, t3, t1 // get proper lane
+
+ beq t7, 11f // if not DENSE goto 11f
+
+//
+// Read\modify\write for DENSE space I/O
+//
+ bic t0, 3, t9 // clear bits <1:0> of dest
+ ldl t10, 0(t9) // read dest long
+ mskbl t10, t3, t10 // poke out the byte we will write
+ bis t10, t1, t1 // merge in our byte
+ stl t1, 0(t9) // commit it
+
+ br zero, 12f
+
+//
+// We're in SPARSE space, so simply perform the write
+//
+11:
+ stl t1, 0(t0) // store byte to buffer (BYTE ENABLED)
+
+12:
+ addq t0, a3, t0 // increment I/O buffer
+ addl t3, 1, t3 // increment bytelane
+ and t3, 3, t3 // longwords only
+ bne t3, 10b // loop while not long aligned
+
+//
+// Src and Destn have same alignment and are longword aligned
+//
+
+20:
+ srl a2, 2, t3 // t3= #longwords to move
+ beq t3, 40f // if #longwords == 0 goto 40f
+ or t0, a5, t0 // We will now do LONG WRITE
+
+30:
+ ldl t1, 0(a1) // get the longword
+ addl a1, 4, a1 // increment buffer pointer
+ subl t3, 1, t3 // decrement #longwords by 1
+ stl t1, 0(t0) // store long to buffer
+ addq t0, a4, t0 // increment I/O buffer
+ bne t3, 30b // while #longwords > 0
+
+//
+// Do byte copies of remaining data uncopied
+//
+ bic t0, a5, t0 // Stop doing LONG WRITE
+
+40:
+ and a2, 3, a2 // remaining Bytes to copy
+ beq a2, 60f // if count == 0 goto 60f (return)
+
+50:
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ subl a2, 1, a2 // decrement count
+ extbl t1, a1, t1 // extract appropriate byte
+ addl a1, 1, a1 // increment buffer pointer
+ insbl t1, t3, t1 // get proper lane
+
+ beq t7, 51f // if not DENSE goto 51f
+
+//
+// Read\modify\write for DENSE space I/O
+//
+ bic t0, 3, t9 // clear bits <1:0> of dest
+ ldl t10, 0(t9) // read dest long
+ mskbl t10, t3, t10 // poke out the byte we will write
+ bis t10, t1, t1 // merge in our byte
+ stl t1, 0(t9) // commit it
+
+ br zero, 52f
+
+//
+// We're in SPARSE space, so simply perform the write
+//
+51:
+ stl t1, 0(t0) // store to buffer
+
+52:
+ addq t0, a3, t0 // increment I/O buffer
+ addl t3, 1, t3 // increment bytelane
+ and t3, 3, t3 // longwords only
+ bne a2, 50b // while count != 0
+
+60:
+ mb // push writes off chip
+ ret zero, (ra) // return
+
+//
+// destn IO alignment != Src memory alignment
+// move enough bytes to longword align the IO destn
+// then move 32bit (longwords) reading unaligned data from memory
+// then move residual bytes
+//
+
+70:
+ beq t3, 90f // branch if destn is long aligned
+
+//
+// Move bytes until IO destn is at a longword boundary or bytes exhausted
+//
+
+80:
+ beq a2, 130f // if count == 0 goto 130f (return)
+
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ extbl t1, a1, t1 // extract appropriate byte
+ insbl t1, t3, t1 // get proper lane
+
+ beq t7, 81f // if not DENSE goto 81f
+
+//
+// Read\modify\write for DENSE space I/O
+//
+ bic t0, 3, t9 // clear bits <1:0> of dest
+ ldl t10, 0(t9) // read dest long
+ mskbl t10, t3, t10 // poke out the byte we will write
+ bis t10, t1, t1 // merge in our byte
+ stl t1, 0(t9) // commit it
+
+ br zero, 82f
+
+//
+// We're in SPARSE space, so simply perform the write
+//
+81:
+ stl t1, 0(t0) // store byte to buffer (BYTE ENABLED)
+
+82:
+ subl a2, 1, a2 // decrement count
+ addl a1, 1, a1 // increment buffer pointer
+ addq t0, a3, t0 // increment I/O buffer
+ addl t3, 1, t3 // increment bytelane
+ and t3, 3, t3 // longwords only
+ bne t3, 80b // loop if not long aligned
+
+//
+// aligned IO destn, unaligned memory src
+//
+
+90:
+ srl a2, 3, t3 // t3 = quadwords to move
+ beq t3, 110f // if no quads finish with bytes copies
+
+ or t0, a5, t0 // We will now do LONG WRITES
+
+100:
+ ldq_u t1, 0(a1) // load low source quadword
+ ldq_u t2, 7(a1) // load high source quadword
+ extql t1, a1, t1 // extract low portion of quadword
+ extqh t2, a1, t2 // extract high portion of quadword
+ or t1, t2, t1 // merge to get the source quadword
+ stl t1, 0(t0) // store the long word (LONG ENABLED)
+
+ lda a1, 8(a1) // next source quadword
+ srl t1, 32, t1 // get high longword into position
+ subl t3, 1, t3 // decrement number of quadwords to move
+ addq t0, a4, t0 // add LONG OFFSET to t0
+ stl t1, (t0) // store the second long word
+
+ addq t0, a4, t0 // increment to next dest. long
+ bne t3, 100b // while quadwords to move
+//
+// Do byte copies of the remaining data not yet copied
+//
+ bic t0, a5, t0 // We will now do BYTE WRITES
+110:
+ and a2, 7, a2 // remaining Bytes to copy
+ beq a2, 130f // if count == 0 goto 130f (return)
+
+120:
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ subl a2, 1, a2 // decrement count
+ extbl t1, a1, t1 // extract appropriate byte
+ addl a1, 1, a1 // increment buffer pointer
+ insbl t1, t3, t1 // get proper lane
+
+ beq t7, 121f // if not DENSE goto 122f
+
+//
+// Read\modify\write for DENSE space I/O
+//
+ bic t0, 3, t9 // clear bits <1:0> of dest
+ ldl t10, 0(t9) // read dest long
+ mskbl t10, t3, t10 // poke out the byte we will write
+ bis t10, t1, t1 // merge in our byte
+ stl t1, 0(t9) // commit it
+
+ br zero, 122f
+
+//
+// We're in SPARSE space, so simply perform the write
+//
+121:
+ stl t1, 0(t0) // store byte to buffer (BYTE ENABLED)
+
+122:
+ addq t0, a3, t0 // increment I/O buffer
+ addl t3, 1, t3 // increment bytelane
+ and t3, 3, t3 // longwords only
+ bne a2, 120b // while count != 0
+
+130:
+ mb // push writes off chip
+ ret zero, (ra) // return
+
+ .end WRITE_REGISTER_BUFFER_ULONG // end for UCHAR & USHORT
+
+
diff --git a/private/ntos/nthals/halalpha/am29f400.c b/private/ntos/nthals/halalpha/am29f400.c
new file mode 100644
index 000000000..319583a84
--- /dev/null
+++ b/private/ntos/nthals/halalpha/am29f400.c
@@ -0,0 +1,543 @@
+/*++
+
+Copyright (c) 1995 Digital Equipment Corporation
+
+Module Name:
+
+ am29f400.c
+
+Abstract:
+
+ This module contains the platform independent code to access the AMD
+ flash ROM part AM29F400.
+
+Author:
+
+ Wim Colgate, 5/12/95
+
+Environment:
+
+ Firmware/Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "arccodes.h"
+#include <flash8k.h>
+#include "flashbus.h"
+#include "am29f400.h"
+
+//
+// External prototypes
+//
+
+VOID pWriteFlashByte(
+ IN ULONG FlashOffset,
+ IN UCHAR Data
+ );
+
+UCHAR pReadFlashByte(
+ IN ULONG FlashOffset
+ );
+
+//
+// Local function prototypes
+//
+
+PFLASH_DRIVER
+Am29F400_Initialize(
+ IN ULONG FlashOffset
+ );
+
+ARC_STATUS
+Am29F400_SetReadMode(
+ IN PUCHAR FlashOffset
+ );
+
+ARC_STATUS
+Am29F400_WriteByte(
+ IN PUCHAR FlashOffset,
+ IN UCHAR Data
+ );
+
+ARC_STATUS
+Am29F400_EraseSector(
+ IN PUCHAR FlashOffset
+ );
+
+ARC_STATUS
+Am29F400_CheckStatus(
+ IN PUCHAR FlashOffset,
+ IN FLASH_OPERATIONS Operation,
+ IN UCHAR OptionalData
+ );
+
+PUCHAR
+Am29F400_SectorAlign(
+ IN PUCHAR FlashOffset
+ );
+
+UCHAR
+Am29F400_ReadByte(
+ IN PUCHAR FlashOffset
+ );
+
+BOOLEAN
+Am29F400_OverwriteCheck(
+ IN UCHAR OldData,
+ IN UCHAR NewData
+ );
+
+ULONG
+Am29F400_SectorSize(
+ IN PUCHAR FlashOffset
+ );
+
+FLASH_DRIVER Am29F400_DriverInformation = {
+ "AMD Am29F400",
+ Am29F400_SetReadMode, // SetReadModeFunction
+ Am29F400_WriteByte, // WriteByteFunction
+ Am29F400_EraseSector, // EraseSectorFunction
+ Am29F400_SectorAlign, // AlignSectorFunction
+ Am29F400_ReadByte, // ReadByteFunction
+ Am29F400_OverwriteCheck, // OverwriteCheckFunction
+ Am29F400_SectorSize, // SectorSizeFunction
+// NULL, // Get last error
+ Am29F400_DEVICE_SIZE, // DeviceSize
+ Am29F400_ERASED_DATA // What an erased data looks like
+ };
+
+//
+// This variable tells us which bank of 8K 'nvram' are we using
+// The LX3 nvram is actually two separate 8K sections of the FLASH ROM.
+// One living at 0x4000, the other at 0x6000.
+//
+// This is NOT a QVA (which will is aliased by HalpCMOSBase in common
+// code. Rather it is an offset within the FLASH ROM where the NVRAM lives.
+//
+
+extern PVOID HalpCMOSRamBase;
+ULONG Am29F400NVRAMBase;
+
+
+static UCHAR am29F400_GetSectorNumber(
+ IN PUCHAR FlashOffset
+ )
+/*++
+
+Routine Description:
+
+ This routine figures out which sector number we are in (for use in
+ clearing the sector...)
+
+Arguments:
+
+ FlashOffset - offset within the flash ROM.
+
+Return Value:
+
+ The sector number within the range of the offset.
+
+--*/
+{
+ ULONG Offset = (ULONG)FlashOffset;
+
+ if (Offset < SECTOR_1_BASE) {
+ return 0;
+ } else if (Offset < SECTOR_2_BASE) {
+ return 1;
+ } else if (Offset < SECTOR_3_BASE) {
+ return 2;
+ } else if (Offset < SECTOR_4_BASE) {
+ return 3;
+ } else {
+
+ //
+ // All other sectors are 0x10000, 0x20000, etc, so shift right by 64K,
+ // Then add the preceding section offset's
+ //
+
+ return (UCHAR)((Offset >> 16) + 3);
+ }
+
+ return 0;
+
+}
+
+
+PFLASH_DRIVER
+Am29F400_Initialize(
+ IN ULONG FlashOffset
+ )
+/*++
+
+Routine Description:
+
+ This routine spanks the FLASH ROM with the auto select command, which
+ allows us to make sure that the device is what we think it is.
+
+Arguments:
+
+ FlashOffset - offset within the flash ROM.
+
+Return Value:
+
+ NULL for no driver, or the address of the FLASH_DRIVER structure for
+ this driver.
+
+--*/
+{
+ PFLASH_DRIVER ReturnDriver = NULL;
+ UCHAR ManufacturerID;
+ UCHAR DeviceID;
+ UCHAR temp;
+
+ Am29F400_SetReadMode((PUCHAR)SECTOR_2_BASE); // first 8K section (NVRAM)
+
+ HalpStallExecution(50); // wkc -- GACK! what a bogus part
+
+ pWriteFlashByte(COMMAND_ADDR1, COMMAND_DATA1);
+ pWriteFlashByte(COMMAND_ADDR2, COMMAND_DATA2);
+ pWriteFlashByte(COMMAND_ADDR3, COMMAND_DATA3_AUTOSELECT);
+
+ //
+ // Get manufacturer and device ID. Note spec says device ID lives
+ // at byte 1, but empirical evidence says it is at byte 2.
+ //
+
+ ManufacturerID = Am29F400_ReadByte((PUCHAR)0x00);
+ DeviceID = Am29F400_ReadByte((PUCHAR)0x02);
+
+#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
+ DbgPrint("Manufacturer ID (expect 0x1) %x\n", ManufacturerID);
+ DbgPrint("Device ID (expect 0xab) %x\n", DeviceID);
+#endif
+
+ if ((ManufacturerID == MANUFACTURER_ID) && (DeviceID == DEVICE_ID)) {
+ Am29F400_SetReadMode(0x0);
+ Am29F400_SetReadMode((PUCHAR)SECTOR_2_BASE);
+
+ // wkcfix -- check which NVRAM section we should use.
+ // currently use the first one setup in the HalpMapIoSpace() routine.
+
+ Am29F400NVRAMBase = (ULONG)HalpCMOSRamBase;
+ ReturnDriver = &Am29F400_DriverInformation;
+ }
+
+#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
+ if (ReturnDriver == NULL) {
+ DbgPrint("FLASH part unknown; AMD Am29F400 not loaded\n");
+ }
+#endif
+
+ return ReturnDriver;
+}
+
+
+ARC_STATUS
+Am29F400_SetReadMode(
+ IN PUCHAR FlashOffset
+ )
+/*++
+
+Routine Description:
+
+ This routine spanks the FLASH ROM with the read reset routine.
+
+Arguments:
+
+ FlashOffset - offset within the flash ROM -- but not used.
+
+Return Value:
+
+ The value of the check status routine (EIO or ESUCCESS)
+
+--*/
+{
+
+ pWriteFlashByte((ULONG)FlashOffset, COMMAND_READ_RESET);
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+Am29F400_WriteByte(
+ IN PUCHAR FlashOffset,
+ IN UCHAR Data
+ )
+/*++
+
+Routine Description:
+
+ This routine spanks the FLASH ROM with the program command, then calls
+ the check status routine -- then resets the device to read.
+
+Arguments:
+
+ FlashOffset - offset within the flash ROM.
+ Data - the data byte to write.
+
+Return Value:
+
+ The value of the check status routine (EIO or ESUCCESS)
+
+--*/
+{
+ ARC_STATUS ReturnStatus;
+
+ pWriteFlashByte(COMMAND_ADDR1, COMMAND_DATA1);
+ pWriteFlashByte(COMMAND_ADDR2, COMMAND_DATA2);
+ pWriteFlashByte(COMMAND_ADDR3, COMMAND_DATA3_PROGRAM);
+
+ ASSERT((FlashOffset >= (PUCHAR)0x4000) && (FlashOffset < (PUCHAR)0x8000));
+
+ pWriteFlashByte((ULONG)FlashOffset, Data);
+
+ ReturnStatus = Am29F400_CheckStatus(FlashOffset, FlashByteWrite, Data);
+
+ Am29F400_SetReadMode(FlashOffset);
+
+ return ReturnStatus;
+}
+
+
+ARC_STATUS
+Am29F400_EraseSector(
+ IN PUCHAR FlashOffset
+ )
+/*++
+
+Routine Description:
+
+ This routine spanks the FLASH ROM with the erase sector command, then calls
+ the check status routine
+
+Arguments:
+
+ FlashOffset - offset within the flash ROM.
+
+Return Value:
+
+ The value of the check status routine (EIO or ESUCCESS)
+
+--*/
+{
+ ARC_STATUS ReturnStatus;
+ UCHAR ReadBack;
+ ULONG Count = MAX_FLASH_READ_ATTEMPTS;
+
+ Am29F400_SetReadMode(FlashOffset);
+
+ pWriteFlashByte(COMMAND_ADDR1, COMMAND_DATA1);
+ pWriteFlashByte(COMMAND_ADDR2, COMMAND_DATA2);
+ pWriteFlashByte(COMMAND_ADDR3, COMMAND_DATA3);
+ pWriteFlashByte(COMMAND_ADDR4, COMMAND_DATA4);
+ pWriteFlashByte(COMMAND_ADDR5, COMMAND_DATA5);
+ pWriteFlashByte((ULONG)FlashOffset, COMMAND_DATA6_SECTOR_ERASE);
+
+ HalpStallExecution(80); // short stall for erase command to take
+
+ ReturnStatus = Am29F400_CheckStatus(FlashOffset,
+ FlashEraseSector,
+ 0xff);
+
+ Am29F400_SetReadMode(FlashOffset);
+
+ return ReturnStatus;
+
+}
+
+
+ARC_STATUS
+Am29F400_CheckStatus (
+ IN PUCHAR FlashOffset,
+ IN FLASH_OPERATIONS Operation,
+ IN UCHAR OptionalData
+ )
+/*++
+
+Routine Description:
+
+ This routine checks the status of the flashbus operation. The operation
+ may be specific, so different actions may be taken.
+
+Arguments:
+
+ FlashOffset - offset within the flash ROM.
+ Opertaion - the operation performed on the FlashOffset.
+ OptionalData - an optional data value that may be needed for verification.
+
+Return Value:
+
+ EIO for faiure
+ ESUCCESS for success
+
+--*/
+{
+ ARC_STATUS ReturnStatus = EIO;
+ UCHAR FlashRead;
+ ULONG Count = 0;
+ ULONG DataOK = FALSE;
+
+ while ((DataOK == FALSE) && (Count < MAX_FLASH_READ_ATTEMPTS)) {
+
+ FlashRead = Am29F400_ReadByte(FlashOffset);
+
+ //
+ // Both FlashByteWrite & FlashEraseBlock checks use polling
+ // algorithm found on page 1-131 of the AMD part specification
+ //
+
+ if ((FlashRead & 0x80) == (OptionalData & 0x80)) {
+ DataOK = TRUE;
+ } else if (FlashRead & 0x20) {
+ FlashRead = Am29F400_ReadByte(FlashOffset);
+ if ((FlashRead & 0x80) == (OptionalData & 0x80)) {
+ DataOK = TRUE;
+ } else {
+ break;
+ }
+ }
+ Count++;
+ }
+
+ if (DataOK == TRUE) {
+ ReturnStatus = ESUCCESS;
+ }
+
+ return ReturnStatus;
+}
+
+
+PUCHAR
+Am29F400_SectorAlign(
+ IN PUCHAR FlashOffset
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the base offset that the current offset within
+ a sector of the flash ROM.
+
+Arguments:
+
+ FlashOffset - offset within the flash ROM.
+
+Return Value:
+
+ The base offset of the current sector -- as defined by the FlashOffset.
+
+--*/
+{
+ ULONG Offset = (ULONG)FlashOffset;
+
+ if (Offset < SECTOR_2_BASE) {
+ return (PUCHAR)SECTOR_1_BASE;
+ } else if (Offset < SECTOR_3_BASE) {
+ return (PUCHAR)SECTOR_2_BASE;
+ } else if (Offset < SECTOR_4_BASE) {
+ return (PUCHAR)SECTOR_3_BASE;
+ } else if (Offset < SECTOR_5_BASE) {
+ return (PUCHAR)SECTOR_4_BASE;
+ } else {
+ return (PUCHAR)(ULONG)(Offset & ~(SECTOR_5_SIZE-1));
+ }
+}
+
+
+UCHAR
+Am29F400_ReadByte(
+ IN PUCHAR FlashOffset
+ )
+/*++
+
+Routine Description:
+
+ This routine spanks the FLASH ROM with the read command, then calls
+ the read flash bus function.
+
+Arguments:
+
+ FlashOffset - offset within the flash ROM.
+
+
+Return Value:
+
+ The character at the appropriate location.
+
+--*/
+{
+ UCHAR ReturnVal;
+
+ //
+ // Assume Read mode is on
+ //
+
+ ReturnVal = pReadFlashByte((ULONG)FlashOffset);
+
+ return ReturnVal;
+}
+
+
+BOOLEAN
+Am29F400_OverwriteCheck(
+ IN UCHAR OldData,
+ IN UCHAR NewData
+ )
+/*++
+
+Routine Description:
+
+ This routine returns if we can safely overwrite an existing data
+ with new data. Flash Rom's can go from 1-->1, 1-->0 and 0-->0, but
+ cannot go from 0-->1.
+
+Return Value:
+
+
+ TRUE if we can safely overwrite
+ FALSE if we cannot safely overwrite
+
+--*/
+{
+ return ((NewData & ~OldData) == 0) ? TRUE: FALSE;
+}
+
+
+ULONG
+Am29F400_SectorSize(
+ IN PUCHAR FlashOffset
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the size of the sector that the offset is within.
+
+Arguments:
+
+ FlashOffset - offset within the flash ROM.
+
+
+Return Value:
+
+ The block size of the sector.
+
+--*/
+{
+ if (FlashOffset < (PUCHAR)SECTOR_2_BASE) {
+ return SECTOR_1_SIZE;
+ } else if (FlashOffset < (PUCHAR)SECTOR_3_BASE) {
+ return SECTOR_2_SIZE;
+ } else if (FlashOffset < (PUCHAR)SECTOR_4_BASE) {
+ return SECTOR_3_SIZE;
+ } else if (FlashOffset < (PUCHAR)SECTOR_5_BASE) {
+ return SECTOR_4_SIZE;
+ } else {
+ return SECTOR_5_SIZE;
+ }
+}
diff --git a/private/ntos/nthals/halalpha/am29f400.h b/private/ntos/nthals/halalpha/am29f400.h
new file mode 100644
index 000000000..61e3f1774
--- /dev/null
+++ b/private/ntos/nthals/halalpha/am29f400.h
@@ -0,0 +1,97 @@
+#ifndef _AM29F400_H_
+#define _AM29F400_H_
+
+//
+// The AMD is a full 1/2 megabyte broken into the following sectors:
+//
+// 0x00000 .. 0x03fff -- > Section 1 // SROM
+// 0x04000 .. 0x05fff -- > Section 2 // NVRAM_0
+// 0x06000 .. 0x07fff -- > Section 3 // NVRAM_1
+// 0x08000 .. 0x0ffff -- > Section 4 // DROM
+// 0x10000 .. 0x1ffff -- > Section 5 // ARC starts here
+// 0x20000 .. 0x2ffff -- > Section 6
+// 0x30000 .. 0x3ffff -- > Section 7
+// 0x40000 .. 0x4ffff -- > Section 8
+// 0x50000 .. 0x5ffff -- > Section 8
+// 0x60000 .. 0x6ffff -- > Section 9
+// 0x70000 .. 0x7ffff -- > Section 10
+
+//
+// Name the blocks
+//
+
+#define SECTOR_1_BASE 0x0
+#define SECTOR_2_BASE 0x4000
+#define SECTOR_3_BASE 0x6000
+#define SECTOR_4_BASE 0x8000
+#define SECTOR_5_BASE 0x10000
+
+#define SECTOR_1_SIZE (SECTOR_2_BASE - SECTOR_1_BASE)
+#define SECTOR_2_SIZE (SECTOR_3_BASE - SECTOR_2_BASE)
+#define SECTOR_3_SIZE (SECTOR_4_BASE - SECTOR_3_BASE)
+#define SECTOR_4_SIZE (SECTOR_5_BASE - SECTOR_4_BASE)
+#define SECTOR_5_SIZE 0x10000
+#define ARC_SECTOR_SIZE SECTOR_5_SIZE
+
+//
+// The largest addressable offset
+//
+
+#define Am29F400_DEVICE_SIZE 0x7ffff
+
+//
+// What an erased data byte looks like
+//
+
+#define Am29F400_ERASED_DATA 0xff
+
+//
+// The command writing sequence for read/auto select/write
+//
+
+#define COMMAND_READ_RESET 0xf0
+
+#define COMMAND_ADDR1 0xaaaa
+#define COMMAND_DATA1 0xaa
+
+#define COMMAND_ADDR2 0x5555
+#define COMMAND_DATA2 0x55
+
+#define COMMAND_ADDR3 0xaaaa
+#define COMMAND_DATA3_READ 0xf0 // then {addr,data}
+#define COMMAND_DATA3_AUTOSELECT 0x90
+#define COMMAND_DATA3_PROGRAM 0xA0 // then {addr,data}
+#define COMMAND_DATA3 0x80 // for the additional ops
+
+//
+// and additional bus cyles for chip and sector erase
+//
+
+#define COMMAND_ADDR4 0xaaaa
+#define COMMAND_DATA4 0xaa
+
+#define COMMAND_ADDR5 0x5555
+#define COMMAND_DATA5 0x55
+
+// for SECTOR ERASE, the addr is the sector number
+#define COMMAND_DATA6_SECTOR_ERASE 0x30
+
+#define COMMAND_ADDR6 0xaaaa
+#define COMMAND_DATA6_CHIP_ERASE 0x10
+
+//
+// This is the Am29F400 made by AMD
+//
+
+#define MANUFACTURER_ID 0x01
+#define DEVICE_ID 0xab
+
+//
+// Max attempts
+//
+
+#define MAX_FLASH_READ_ATTEMPTS 0x800000
+
+#include "pflash.h"
+
+#endif // _AM29F400_H_
diff --git a/private/ntos/nthals/halalpha/apecs.c b/private/ntos/nthals/halalpha/apecs.c
new file mode 100644
index 000000000..7c5a5918a
--- /dev/null
+++ b/private/ntos/nthals/halalpha/apecs.c
@@ -0,0 +1,337 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ apecs.c
+
+Abstract:
+
+ This module implements functions that are specific to the APECS
+ chip-set.
+
+Author:
+
+ Joe Notarangelo 18-Oct-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#include "apecs.h"
+
+VOID
+DumpEpic(
+ VOID
+ );
+
+//
+// Globals
+//
+
+//
+// Parity checking is a tri-state variable, unknown == all f's. Which means
+// Keep checking disabled until we can determine what we want to set it to,
+// which then means 1 or 0.
+//
+
+extern ULONG HalDisablePCIParityChecking;
+
+
+VOID
+HalpApecsInitializeSfwWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ APECS_WINDOW_NUMBER WindowNumber
+ )
+/*++
+
+Routine Description:
+
+ Initialize the DMA Control software window registers for the specified
+ DMA Window.
+
+Arguments:
+
+ WindowRegisters - Supplies a pointer to the software window control.
+
+ WindowNumber - Supplies the window number initialized. (0 = Isa Dma
+ Window, 1 = Master Dma Window).
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ switch( WindowNumber ){
+
+ //
+ // The ISA DMA Window.
+ //
+
+ case ApecsIsaWindow:
+
+ WindowRegisters->WindowBase = (PVOID)ISA_DMA_WINDOW_BASE;
+ WindowRegisters->WindowSize = ISA_DMA_WINDOW_SIZE;
+ WindowRegisters->TranslatedBaseRegister =
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->TranslatedBase1Register;
+ WindowRegisters->WindowBaseRegister =
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciBase1Register;
+ WindowRegisters->WindowMaskRegister =
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciMask1Register;
+ WindowRegisters->WindowTbiaRegister =
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->TbiaRegister;
+
+ break;
+
+ case ApecsMasterWindow:
+
+ WindowRegisters->WindowBase = (PVOID)MASTER_DMA_WINDOW_BASE;
+ WindowRegisters->WindowSize = MASTER_DMA_WINDOW_SIZE;
+ WindowRegisters->TranslatedBaseRegister =
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->TranslatedBase2Register;
+ WindowRegisters->WindowBaseRegister =
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciBase2Register;
+ WindowRegisters->WindowMaskRegister =
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciMask2Register;
+ WindowRegisters->WindowTbiaRegister =
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->TbiaRegister;
+
+ break;
+
+ default:
+
+#if DBG
+
+ DbgPrint( "ApecsInitializeSfwWindow: Bad Window Number = %x\n",
+ WindowNumber );
+
+#endif //DBG
+
+ break;
+
+ }
+
+ return;
+}
+
+
+VOID
+HalpApecsProgramDmaWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ PVOID MapRegisterBase
+ )
+/*++
+
+Routine Description:
+
+ Program the control windows in the hardware so that DMA can be started
+ to the DMA window.
+
+Arguments:
+
+ WindowRegisters - Supplies a pointer to the software window register
+ control structure.
+
+ MapRegisterBase - Supplies the logical address of the scatter/gather
+ array in system memory.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ EPIC_ECSR Ecsr;
+ EPIC_PCIBASE PciBase;
+ EPIC_PCIMASK PciMask;
+ EPIC_TBASE TBase;
+ PVOID RegisterQva;
+
+ PciBase.Reserved = 0;
+ PciBase.Wenr = 1;
+ PciBase.Sgen = 1;
+ PciBase.BaseValue = (ULONG)(WindowRegisters->WindowBase) >> 20;
+
+ PciMask.Reserved = 0;
+ PciMask.MaskValue = (WindowRegisters->WindowSize >> 20) - 1;
+
+ TBase.Reserved = 0;
+ TBase.TBase = (ULONG)(MapRegisterBase) >> 10;
+
+#if DBG
+
+ //
+ // Dump the EPIC registers.
+ //
+
+ DumpEpic();
+
+#endif //DBG
+
+ //
+ // Clear the window base, temporarily disabling transactions to this
+ // DMA window.
+ //
+
+ WRITE_EPIC_REGISTER( WindowRegisters->WindowBaseRegister, (ULONG)0 );
+
+ //
+ // Now program the window by writing the translated base, then the size
+ // of the window in the mask register and finally the window base,
+ // enabling both the window and scatter gather.
+ //
+
+ WRITE_EPIC_REGISTER( WindowRegisters->TranslatedBaseRegister,
+ *(PULONG)&TBase );
+
+ WRITE_EPIC_REGISTER( WindowRegisters->WindowMaskRegister,
+ *(PULONG)&PciMask );
+
+ WRITE_EPIC_REGISTER( WindowRegisters->WindowBaseRegister,
+ *(PULONG)&PciBase );
+
+ //
+ // Invalidate any translations that might have existed for this window.
+ //
+
+ WRITE_EPIC_REGISTER( WindowRegisters->WindowTbiaRegister, 0 );
+
+ //
+ // Enable the translation buffer inside of the EPIC.
+ //
+
+ RtlZeroMemory( &Ecsr, sizeof(EPIC_ECSR) );
+ Ecsr.Tenb = 1;
+
+ //
+ // Tri state parity checking - keep disabled if not determined
+ // yet. otherwise, Whack the PCI parity disable bit with the stored
+ // value
+ //
+
+ if (HalDisablePCIParityChecking == 0xffffffff) {
+ Ecsr.Dpec = 1;
+ } else {
+ Ecsr.Dpec = HalDisablePCIParityChecking;
+ }
+
+#if HALDBG
+ if (HalDisablePCIParityChecking == 0) {
+ DbgPrint("apecs: PCI Parity Checking ON\n");
+ } else if (HalDisablePCIParityChecking == 1) {
+ DbgPrint("apecs: PCI Parity Checking OFF\n");
+ } else {
+ DbgPrint("apecs: PCI Parity Checking OFF - not set by ARC yet\n");
+ }
+#endif
+
+ RegisterQva =
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister;
+ WRITE_EPIC_REGISTER( RegisterQva,
+ *(PULONG)&Ecsr );
+
+#if DBG
+
+ //
+ // Dump the EPIC registers.
+ //
+
+ DumpEpic();
+
+#endif //DBG
+
+ return;
+}
+
+ULONG
+READ_EPIC_REGISTER(
+ PVOID
+ );
+
+#if DBG
+
+VOID
+DumpEpic(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Read the interesting EPIC registers and print them to the debug port.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PVOID RegisterQva;
+ ULONG Value;
+
+ DbgPrint( "Dumping the EPIC registers\n" );
+
+ RegisterQva =
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister;
+ Value = READ_EPIC_REGISTER( RegisterQva );
+ DbgPrint( "ECSR = %x\n", Value );
+
+ RegisterQva =
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->TranslatedBase1Register;
+ Value = READ_EPIC_REGISTER( RegisterQva );
+ DbgPrint( "TBASE1 = %x\n", Value );
+
+ RegisterQva =
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->TranslatedBase2Register;
+ Value = READ_EPIC_REGISTER( RegisterQva );
+ DbgPrint( "TBASE2 = %x\n", Value );
+
+ RegisterQva = &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciBase1Register;
+ Value = READ_EPIC_REGISTER( RegisterQva );
+ DbgPrint( "PCIBASE1 = %x\n", Value );
+
+ RegisterQva = &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciBase2Register;
+ Value = READ_EPIC_REGISTER( RegisterQva );
+ DbgPrint( "PCIBASE2 = %x\n", Value );
+
+ RegisterQva = &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciMask1Register;
+ Value = READ_EPIC_REGISTER( RegisterQva );
+ DbgPrint( "PCIMASK1 = %x\n", Value );
+
+ RegisterQva = &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciMask2Register;
+ Value = READ_EPIC_REGISTER( RegisterQva );
+ DbgPrint( "PCIMASK2 = %x\n", Value );
+
+ RegisterQva = &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->Haxr0;
+ Value = READ_EPIC_REGISTER( RegisterQva );
+ DbgPrint( "HAXR0 = %x\n", Value );
+
+ RegisterQva = &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->Haxr1;
+ Value = READ_EPIC_REGISTER( RegisterQva );
+ DbgPrint( "HAXR1 = %x\n", Value );
+
+ RegisterQva = &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->Haxr2;
+ Value = READ_EPIC_REGISTER( RegisterQva );
+ DbgPrint( "HAXR2 = %x\n", Value );
+
+ DbgPrint( "--end EPIC dump\n\n" );
+
+ return;
+
+}
+
+#endif //DBG
diff --git a/private/ntos/nthals/halalpha/apecs.h b/private/ntos/nthals/halalpha/apecs.h
new file mode 100644
index 000000000..97b24809d
--- /dev/null
+++ b/private/ntos/nthals/halalpha/apecs.h
@@ -0,0 +1,647 @@
+/*++
+
+Copyright (c) 1993, 1996 Digital Equipment Corporation
+
+Module Name:
+
+ apecs.h
+
+Abstract:
+
+ This file defines the structures and definitions common to all
+ APECS-based platforms.
+
+Author:
+
+ Joe Notarangelo 12-Oct-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Chao Chen 31-Aug-1995 Fix the broken Comanche register data structure.
+ Gene Morgan 27-Feb-1996 Add missing Comanche register defns
+
+--*/
+
+#ifndef _APECSH_
+#define _APECSH_
+
+
+//
+// Define QVA constants for APECS.
+//
+
+#if !defined(QVA_ENABLE)
+
+#define QVA_ENABLE (0xA0000000) // Identify VA as a QVA
+
+#endif //!QVA_ENABLE
+
+#define QVA_SELECTORS (0xE0000000) // QVA identification mask
+
+#define IO_BIT_SHIFT 0x05 // Bits to shift QVA
+
+#define IO_BYTE_OFFSET 0x20 // Offset to next byte
+#define IO_SHORT_OFFSET 0x40 // Offset to next short
+#define IO_LONG_OFFSET 0x80 // Offset to next long
+
+#define IO_BYTE_LEN 0x00 // Byte length
+#define IO_WORD_LEN 0x08 // Word length
+#define IO_TRIBYTE_LEN 0x10 // TriByte length
+#define IO_LONG_LEN 0x18 // Longword length
+
+//
+// Define size of I/O and memory space for APECS
+//
+
+#define PCI_MAX_IO_ADDRESS 0xFFFFFF // 16 Mb of IO Space
+
+#define PCI_MAX_SPARSE_MEMORY_ADDRESS ((128*1024*1024) - 1)
+#define PCI_MIN_DENSE_MEMORY_ADDRESS PCI_MAX_SPARSE_MEMORY_ADDRESS + 1
+#define PCI_MAX_DENSE_MEMORY_ADDRESS (0xa0000000 -1) // 2.5 Gb
+
+//
+// Constant used by dense space I/O routines
+//
+
+#define PCI_DENSE_BASE_PHYSICAL_SUPERPAGE 0xfffffc0300000000
+
+#if !defined(_LANGUAGE_ASSEMBLY)
+
+//
+// QVA
+// HAL_MAKE_QVA(
+// ULONGLONG PhysicalAddress
+// )
+//
+// Routine Description:
+//
+// This macro returns the Qva for a physical address in system space.
+//
+// Arguments:
+//
+// PhysicalAddress - Supplies a 64-bit physical address.
+//
+// Return Value:
+//
+// The Qva associated with the physical address.
+//
+
+#define HAL_MAKE_QVA(PA) \
+ ( (PVOID)( QVA_ENABLE | (ULONG)((PA) >> IO_BIT_SHIFT) ) )
+
+
+//
+// Define physical address spaces for APECS.
+//
+
+#define APECS_COMANCHE_BASE_PHYSICAL ((ULONGLONG)0x180000000)
+#define APECS_EPIC_BASE_PHYSICAL ((ULONGLONG)0x1A0000000)
+#define APECS_PCI_INTACK_BASE_PHYSICAL ((ULONGLONG)0x1B0000000)
+#define APECS_PCI_IO_BASE_PHYSICAL ((ULONGLONG)0x1C0000000)
+#define APECS_PCI_CONFIG_BASE_PHYSICAL ((ULONGLONG)0x1E0000000)
+#define APECS_PCI_MEMORY_BASE_PHYSICAL ((ULONGLONG)0x200000000)
+#define APECS_PCI_DENSE_BASE_PHYSICAL ((ULONGLONG)0x300000000)
+
+#define APECS_PCI_CONFIG_BASE_QVA (HAL_MAKE_QVA(APECS_PCI_CONFIG_BASE_PHYSICAL))
+
+#define EPIC_HAXR1_BASE_PHYSICAL ((ULONGLONG)0x1A00001A0)
+#define EPIC_HAXR2_BASE_PHYSICAL ((ULONGLONG)0x1A00001C0)
+#define EPIC_HAXR1_QVA (HAL_MAKE_QVA(EPIC_HAXR1_BASE_PHYSICAL))
+#define EPIC_HAXR2_QVA (HAL_MAKE_QVA(EPIC_HAXR2_BASE_PHYSICAL))
+
+
+//
+// Define COMANCHE CSRs.
+//
+
+
+#define APECS_COMANCHE_BASE_QVA (HAL_MAKE_QVA(APECS_COMANCHE_BASE_PHYSICAL))
+
+//
+// N.B. The structure below defines the address offsets of the control
+// registers when used with the base QVA. It does NOT define the
+// size or structure of the individual registers.
+//
+
+typedef struct _COMANCHE_CSRS{
+ UCHAR GeneralControlRegister;
+ UCHAR Reserved;
+ UCHAR ErrorAndDiagnosticStatusRegister;
+ UCHAR TagEnableRegister;
+ UCHAR ErrorLowAddressRegister;
+ UCHAR ErrorHighAddressRegister;
+ UCHAR Ldx_lLowAddressRegister;
+ UCHAR Ldx_lHighAddressRegister;
+ UCHAR Reserved1[8];
+ UCHAR GlobalTimingRegister;
+ UCHAR RefreshTimingRegister;
+ UCHAR VideoFramePointerRegister;
+ UCHAR PresenceDetectLowDataRegister;
+ UCHAR PresenceDetectHighDataRegister;
+ UCHAR Reserved2[43];
+ UCHAR Bank0BaseAddressRegister;
+ UCHAR Bank1BaseAddressRegister;
+ UCHAR Bank2BaseAddressRegister;
+ UCHAR Bank3BaseAddressRegister;
+ UCHAR Bank4BaseAddressRegister;
+ UCHAR Bank5BaseAddressRegister;
+ UCHAR Bank6BaseAddressRegister;
+ UCHAR Bank7BaseAddressRegister;
+ UCHAR Bank8BaseAddressRegister;
+ UCHAR Reserved3[7];
+ UCHAR Bank0ConfigurationRegister;
+ UCHAR Bank1ConfigurationRegister;
+ UCHAR Bank2ConfigurationRegister;
+ UCHAR Bank3ConfigurationRegister;
+ UCHAR Bank4ConfigurationRegister;
+ UCHAR Bank5ConfigurationRegister;
+ UCHAR Bank6ConfigurationRegister;
+ UCHAR Bank7ConfigurationRegister;
+ UCHAR Bank8ConfigurationRegister;
+ UCHAR Reserved4[7];
+ UCHAR Bank0TimingRegisterA;
+ UCHAR Bank1TimingRegisterA;
+ UCHAR Bank2TimingRegisterA;
+ UCHAR Bank3TimingRegisterA;
+ UCHAR Bank4TimingRegisterA;
+ UCHAR Bank5TimingRegisterA;
+ UCHAR Bank6TimingRegisterA;
+ UCHAR Bank7TimingRegisterA;
+ UCHAR Bank8TimingRegisterA;
+ UCHAR Reserved5[7];
+ UCHAR Bank0TimingRegisterB;
+ UCHAR Bank1TimingRegisterB;
+ UCHAR Bank2TimingRegisterB;
+ UCHAR Bank3TimingRegisterB;
+ UCHAR Bank4TimingRegisterB;
+ UCHAR Bank5TimingRegisterB;
+ UCHAR Bank6TimingRegisterB;
+ UCHAR Bank7TimingRegisterB;
+ UCHAR Bank8TimingRegisterB;
+} COMANCHE_CSRS, *PCOMANCHE_CSRS;
+
+//
+// Define formats of useful COMANCHE registers.
+//
+
+//
+// Error Diagnostic and Status Register
+//
+typedef union _COMANCHE_EDSR{
+ struct{
+ ULONG Losterr: 1;
+ ULONG Bctaperr: 1;
+ ULONG Bctcperr: 1;
+ ULONG Nxmerr: 1;
+ ULONG Dmacause: 1;
+ ULONG Viccause: 1;
+ ULONG Creqcause: 3;
+ ULONG Reserved: 4;
+ ULONG Pass2: 1;
+ ULONG Ldxllock: 1;
+ ULONG Wrpend: 1;
+ };
+ ULONG all;
+} COMANCHE_EDSR, *PCOMANCHE_EDSR;
+
+//
+// General Control Register
+//
+typedef union _COMANCHE_GCR {
+ struct {
+ ULONG Reserved1: 1;
+ ULONG Sysarb: 2;
+ ULONG Reserved2: 1;
+ ULONG Widemem: 1;
+ ULONG Bcen: 1;
+ ULONG Bcnoalloc: 1;
+ ULONG Bclongwr: 1;
+ ULONG Bcigntflag: 1;
+ ULONG Bcfrctflag: 1;
+ ULONG Bcfrcd: 1;
+ ULONG Bcfrcz: 1;
+ ULONG Bcfrcp: 1;
+ ULONG Bcbadap: 1;
+ ULONG Reserved3: 2;
+ };
+ ULONG all;
+} COMANCHE_GCR, *PCOMANCHE_GCR;
+
+//
+// Tag Enable Register
+//
+typedef union _COMANCHE_TER {
+ struct {
+ ULONG Tagen: 16; // Bit zero is reserved and MBZ
+ };
+ ULONG all;
+} COMANCHE_TER, *PCOMANCHE_TER;
+
+//
+// Bank<n> Base Address Register [0..8]
+//
+typedef union _COMANCHE_BASE_ADDRESS_REGISTER {
+ struct {
+ ULONG Reserved: 5;
+ ULONG BaseAdr: 11;
+ };
+ ULONG all;
+} COMANCHE_BASE_ADDRESS_REGISTER, *PCOMANCHE_BASE_ADDRESS_REGISTER;
+
+//
+// Bank<n> Configuration Register [0..8]
+//
+typedef union _COMANCHE_BANK_CONFIGURATION_REGISTER {
+ struct {
+ ULONG SetValid: 1;
+ ULONG SetSize: 4;
+ ULONG SetSubEna: 1;
+ ULONG SetColSel: 3;
+ ULONG Reserved: 7;
+ };
+ ULONG all;
+}COMANCHE_BANK_CONFIGURATION_REGISTER, *PCOMANCHE_BANK_CONFIGURATION_REGISTER;
+
+
+//
+// Define EPIC CSRs.
+//
+
+
+#define APECS_EPIC_BASE_QVA (HAL_MAKE_QVA(APECS_EPIC_BASE_PHYSICAL))
+
+//
+// N.B. The structure below defines the address offsets of the control
+// registers when used with the base QVA. It does NOT define the
+// size or structure of the individual registers.
+//
+
+typedef struct _EPIC_CSRS{
+ UCHAR EpicControlAndStatusRegister;
+ UCHAR SysbusErrorAddressRegister;
+ UCHAR PciErrorAddressRegister;
+ UCHAR DummyRegister1;
+ UCHAR DummyRegister2;
+ UCHAR DummyRegister3;
+ UCHAR TranslatedBase1Register;
+ UCHAR TranslatedBase2Register;
+ UCHAR PciBase1Register;
+ UCHAR PciBase2Register;
+ UCHAR PciMask1Register;
+ UCHAR PciMask2Register;
+ UCHAR Haxr0;
+ UCHAR Haxr1;
+ UCHAR Haxr2;
+ UCHAR DummyRegister4;
+ UCHAR TlbTag0Register;
+ UCHAR TlbTag1Register;
+ UCHAR TlbTag2Register;
+ UCHAR TlbTag3Register;
+ UCHAR TlbTag4Register;
+ UCHAR TlbTag5Register;
+ UCHAR TlbTag6Register;
+ UCHAR TlbTag7Register;
+ UCHAR TlbData0Register;
+ UCHAR TlbData1Register;
+ UCHAR TlbData2Register;
+ UCHAR TlbData3Register;
+ UCHAR TlbData4Register;
+ UCHAR TlbData5Register;
+ UCHAR TlbData6Register;
+ UCHAR TlbData7Register;
+ UCHAR TbiaRegister;
+} EPIC_CSRS, *PEPIC_CSRS;
+
+//
+// Define formats of useful EPIC registers. Note that P1 is a vestige,
+// and direct access for P2 definitions are the default.
+//
+
+typedef union _EPIC_ECSR{
+
+ struct{
+ ULONG Tenb: 1;
+ ULONG Prst: 1;
+ ULONG Penb: 1;
+ ULONG Dcei: 1;
+ ULONG Rsvd1: 1;
+ ULONG Iort: 1;
+ ULONG Lost: 1;
+ ULONG Rdwr: 1;
+ ULONG Ddpe: 1;
+ ULONG Iope: 1;
+ ULONG Tabt: 1;
+ ULONG Ndev: 1;
+ ULONG Cmrd: 1;
+ ULONG Umrd: 1;
+ ULONG Iptl: 1;
+ ULONG Merr: 1;
+ ULONG DisRdByp: 2;
+ ULONG Rsvd2: 14;
+ } P1;
+ struct{
+ ULONG Tenb: 1;
+ ULONG Rsvd1: 1;
+ ULONG Penb: 1;
+ ULONG Dcei: 1;
+ ULONG Dpec: 1;
+ ULONG Iort: 1;
+ ULONG Lost: 1;
+ ULONG Rsvd2: 1;
+ ULONG Ddpe: 1;
+ ULONG Iope: 1;
+ ULONG Tabt: 1;
+ ULONG Ndev: 1;
+ ULONG Cmrd: 1;
+ ULONG Umrd: 1;
+ ULONG Iptl: 1;
+ ULONG Merr: 1;
+ ULONG DisRdByp: 2;
+ ULONG Pcmd: 4;
+ ULONG Rsvd3: 9;
+ ULONG Pass2: 1;
+ };
+ ULONG all;
+} EPIC_ECSR, *PEPIC_ECSR;
+
+typedef struct _EPIC_PCIMASK{
+ ULONG Reserved: 20;
+ ULONG MaskValue: 12;
+} EPIC_PCIMASK, *PEPIC_PCIMASK;
+
+typedef struct _EPIC_PCIBASE{
+ ULONG Reserved: 18;
+ ULONG Sgen: 1;
+ ULONG Wenr: 1;
+ ULONG BaseValue: 12;
+} EPIC_PCIBASE, *PEPIC_PCIBASE;
+
+typedef struct _EPIC_TBASE{
+ ULONG Reserved: 9;
+ ULONG TBase: 23;
+} EPIC_TBASE, *PEPIC_TBASE;
+
+
+//
+// DMA Window Values.
+//
+// The APECs will be initialized to allow 2 DMA windows.
+// The first window will be for the use of of ISA devices and DMA slaves
+// and therefore must have logical addresses below 16MB.
+// The second window will be for bus masters (non-ISA) and so may be
+// above 16MB.
+//
+// The arrangement of the windows will be as follows:
+//
+// Window Logical Start Address Window Size
+// ------ --------------------- -----------
+// Isa 8MB 8MB
+// Master 16MB 16MB
+//
+
+#define ISA_DMA_WINDOW_BASE (__8MB)
+#define ISA_DMA_WINDOW_SIZE (__8MB)
+
+#define MASTER_DMA_WINDOW_BASE (__16MB)
+#define MASTER_DMA_WINDOW_SIZE (__16MB)
+
+
+//
+// Define the software control registers for a DMA window.
+//
+
+typedef struct _WINDOW_CONTROL_REGISTERS{
+ PVOID WindowBase;
+ ULONG WindowSize;
+ PVOID TranslatedBaseRegister;
+ PVOID WindowBaseRegister;
+ PVOID WindowMaskRegister;
+ PVOID WindowTbiaRegister;
+} WINDOW_CONTROL_REGISTERS, *PWINDOW_CONTROL_REGISTERS;
+
+//
+// Define types of windows.
+//
+
+typedef enum _APECS_WINDOW_NUMBER{
+ ApecsIsaWindow,
+ ApecsMasterWindow
+} APECS_WINDOW_NUMBER, *PAPECS_WINDOW_NUMBER;
+
+//
+// Define APECS Window Control routines.
+//
+
+VOID
+HalpApecsInitializeSfwWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ APECS_WINDOW_NUMBER WindowNumber
+ );
+
+VOID
+HalpApecsProgramDmaWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ PVOID MapRegisterBase
+ );
+
+
+//
+// VOID
+// INITIALIZE_ISA_DMA_CONTROL(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters
+// )
+//
+// Routine Description:
+//
+// Initialize the DMA Control software window registers for the ISA
+// DMA window.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window control.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INITIALIZE_ISA_DMA_CONTROL( WR ) \
+ HalpApecsInitializeSfwWindow( (WR), ApecsIsaWindow );
+
+
+//
+// VOID
+// INITIALIZE_MASTER_DMA_CONTROL(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters
+// )
+//
+// Routine Description:
+//
+// Initialize the DMA Control software window registers for the ISA
+// DMA window.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window control.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INITIALIZE_MASTER_DMA_CONTROL( WR ) \
+ HalpApecsInitializeSfwWindow( (WR), ApecsMasterWindow );
+
+
+//
+// VOID
+// INITIALIZE_DMA_WINDOW(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters,
+// PTRANSLATION_ENTRY MapRegisterBase
+// )
+//
+// Routine Description:
+//
+// Program the control windows so that DMA can be started to the
+// DMA window.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window register
+// control structure.
+//
+// MapRegisterBase - Supplies the logical address of the scatter/gather
+// array in system memory.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INITIALIZE_DMA_WINDOW( WR, MRB ) \
+ HalpApecsProgramDmaWindow( (WR), (MRB) );
+
+
+//
+// VOID
+// INVALIDATE_DMA_TRANSLATIONS(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters
+// )
+//
+// Routine Description:
+//
+// Invalidate all of the cached translations for a DMA window.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window control
+// registers.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INVALIDATE_DMA_TRANSLATIONS( WR ) \
+ WRITE_EPIC_REGISTER( \
+ ((PWINDOW_CONTROL_REGISTERS)WR)->WindowTbiaRegister, 0 );
+
+
+//
+// Define the format of a translation entry aka a scatter/gather entry
+// or map register.
+//
+typedef struct _TRANSLATION_ENTRY{
+ ULONG Valid: 1;
+ ULONG Pfn: 31;
+ ULONG Reserved;
+} TRANSLATION_ENTRY, *PTRANSLATION_ENTRY;
+
+
+
+//
+// VOID
+// HAL_MAKE_VALID_TRANSLATION(
+// PTRANSLATION_ENTRY Entry,
+// ULONG PageFrameNumber
+// )
+//
+// Routine Description:
+//
+// Make the scatter/gather entry pointed to by Entry valid with
+// a translation to the page indicated by PageFrameNumber.
+//
+// Arguments:
+//
+// Entry - Supplies a pointer to the translation entry to make valid.
+//
+// PageFrameNumber - Supplies the page frame of the valid translation.
+//
+// Return Value:
+//
+// None.
+//
+
+#define HAL_MAKE_VALID_TRANSLATION( ENTRY, PFN ) \
+ { \
+ (ENTRY)->Valid = 1; \
+ (ENTRY)->Pfn = PFN; \
+ (ENTRY)->Reserved = 0; \
+ }
+
+
+//
+// VOID
+// HAL_INVALIDATE_TRANSLATION(
+// PTRANSLATION_ENTRY Entry
+// )
+//
+// Routine Description:
+//
+// Invalidate the translation indicated by Entry.
+//
+// Arguments:
+//
+// Entry - Supplies a pointer to the translation to be invalidated.
+//
+// Return Value:
+//
+// None.
+//
+
+#define HAL_INVALIDATE_TRANSLATION( ENTRY ) \
+ (ENTRY)->Valid = 0;
+
+//
+// APECS-specific functions.
+//
+
+VOID
+WRITE_COMANCHE_REGISTER(
+ IN PVOID RegisterQva,
+ IN ULONG Value
+ );
+
+ULONG
+READ_COMANCHE_REGISTER(
+ IN PVOID RegisterQva
+ );
+
+VOID
+WRITE_EPIC_REGISTER(
+ IN PVOID RegisterQva,
+ IN ULONG Value
+ );
+
+ULONG
+READ_EPIC_REGISTER(
+ IN PVOID RegisterQva
+ );
+
+#endif //!_LANGUAGE_ASSEMBLY
+
+#endif //_APECSH_
diff --git a/private/ntos/nthals/halalpha/apecserr.c b/private/ntos/nthals/halalpha/apecserr.c
new file mode 100644
index 000000000..5464a8936
--- /dev/null
+++ b/private/ntos/nthals/halalpha/apecserr.c
@@ -0,0 +1,1542 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ apecserr.c
+
+Abstract:
+
+ This module implements error handling (machine checks and error
+ interrupts) for machines based on the APECS chip-set.
+
+Author:
+
+ Joe Notarangelo 14-Feb-1994
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+ Chao Chen 31-Aug-1995 Added in ECC correctable error handling.
+
+ Balakumar.N 26-Sep-1995 added Uncorrectable Error Logging code and
+ merged Chao's changes to handle correctable error.
+
+--*/
+
+#include "halp.h"
+#include "apecs.h"
+#include "stdio.h"
+
+//
+// Declare the extern variable UncorrectableError declared in
+// inithal.c.
+//
+extern PERROR_FRAME PUncorrectableError;
+
+//
+// Define the context structure for use by interrupt service routines.
+//
+
+typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)(
+ PKINTERRUPT InterruptObject,
+ PVOID ServiceContext
+ );
+
+
+VOID
+HalpSetMachineCheckEnables(
+ IN BOOLEAN DisableMachineChecks,
+ IN BOOLEAN DisableProcessorCorrectables,
+ IN BOOLEAN DisableSystemCorrectables
+ );
+
+VOID
+HalpApecsReportFatalError(
+ VOID
+ );
+
+ULONG
+HalpSimm(
+ ULONGLONG Address
+ );
+
+VOID
+HalpApecsCorrectableError(
+ VOID
+ );
+
+VOID
+HalpApecsConfig(
+ PAPECS_CONFIGURATION Config
+ );
+
+// jnfix - temp count
+ULONG CorrectedMemoryReads = 0;
+#define MAX_ERROR_STRING 128
+
+extern ULONG HalDisablePCIParityChecking;
+
+
+VOID
+HalpInitializeMachineChecks(
+ IN BOOLEAN ReportCorrectableErrors
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes machine check handling for an APECS-based
+ system by clearing all pending errors in the COMANCHE and EPIC and
+ enabling correctable errors according to the callers specification.
+
+Arguments:
+
+ ReportCorrectableErrors - Supplies a boolean value which specifies
+ if correctable error reporting should be
+ enabled.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Dummy;
+ EPIC_ECSR Ecsr;
+ COMANCHE_EDSR Edsr;
+
+ //
+ // Clear the lost error bit in the Comanche EDSR.
+ //
+
+ Edsr.all = 0;
+ Edsr.Losterr = 1;
+ WRITE_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorAndDiagnosticStatusRegister,
+ Edsr.all );
+
+ //
+ // Unlock the other error bits of the EDSR by reading the error address
+ // registers.
+ //
+
+ Dummy = READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorHighAddressRegister
+ );
+
+ Dummy = READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorLowAddressRegister
+ );
+
+ //
+ // Clear all of the error bits in the Epic ECSR. Set correctable error
+ // reporting as requested.
+ //
+
+ Ecsr.all = READ_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister );
+
+ //
+ // For the common registers, simply set them - common in that the P1
+ // definition matches the P2 definition (same structure offset).
+ //
+
+ Ecsr.Merr = 1;
+ Ecsr.Iptl = 1;
+ Ecsr.Umrd = 1;
+ Ecsr.Cmrd = 1;
+ Ecsr.Ndev = 1;
+ Ecsr.Tabt = 1;
+ Ecsr.Iope = 1;
+ Ecsr.Ddpe = 1;
+ Ecsr.Lost = 1;
+ Ecsr.Iort = 1;
+
+ if( ReportCorrectableErrors == TRUE ){
+ Ecsr.Dcei = 0;
+ } else {
+ Ecsr.Dcei = 1;
+ }
+
+ if (HalDisablePCIParityChecking == 0xffffffff) {
+ Ecsr.Dpec = 1;
+ } else {
+ Ecsr.Dpec = HalDisablePCIParityChecking;
+ }
+#if HALDBG
+ if (HalDisablePCIParityChecking == 0) {
+ DbgPrint("apecserr: PCI Parity Checking ON\n");
+ } else if (HalDisablePCIParityChecking == 1) {
+ DbgPrint("apecserr: PCI Parity Checking OFF\n");
+ } else {
+ DbgPrint("apecserr: PCI Parity Checking OFF - not set by ARC yet\n");
+ }
+#endif
+
+ WRITE_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister,
+ Ecsr.all );
+
+ //
+ // Set the machine check enables with the EV4.
+ //
+
+ if( ReportCorrectableErrors == TRUE ){
+ HalpSetMachineCheckEnables( FALSE, FALSE, FALSE );
+ } else {
+ HalpSetMachineCheckEnables( FALSE, TRUE, TRUE );
+ }
+
+ return;
+
+}
+
+VOID
+HalpReadApecsErrorRegisters(
+ VOID
+ )
+{
+ COMANCHE_EDSR Edsr;
+ EPIC_ECSR Ecsr;
+ ULONG ErrorAddress;
+ ULONG ErrorHighAddress;
+ ULONG ErrorLowAddress;
+ ULONG Pear;
+ ULONG Sear;
+ ULONG SystemErrorAddress;
+ PAPECS_UNCORRECTABLE_FRAME apecserr = NULL;
+
+ if(PUncorrectableError){
+ apecserr = (PAPECS_UNCORRECTABLE_FRAME)
+ PUncorrectableError->UncorrectableFrame.RawSystemInformation;
+ }
+
+ if(apecserr)
+ HalpApecsConfig( &apecserr->Configuration);
+
+ //
+ // Read both of the error registers. It is possible that more
+ // than one error was reported simulataneously.
+ //
+
+ Edsr.all = READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorAndDiagnosticStatusRegister );
+
+ Ecsr.all = READ_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister );
+
+
+ //
+ // Read all of the relevant error address registers.
+ //
+
+ ErrorLowAddress = READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorLowAddressRegister );
+
+ ErrorHighAddress = READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorHighAddressRegister);
+
+ ErrorAddress = ((ULONG)(ErrorHighAddress) << 21) +
+ ((ULONG)(ErrorLowAddress) << 5);
+
+ Sear = READ_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->SysbusErrorAddressRegister );
+
+ SystemErrorAddress = (ULONG)(Sear) << 2;
+
+ Pear = READ_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciErrorAddressRegister );
+
+ //
+ // Fill in the Apecs uncorrectbale frame
+ //
+ if(apecserr)
+ apecserr->ComancheEdsr = Edsr.all;
+
+ if( PUncorrectableError &&
+ ( (Edsr.Bctaperr == 1) ||
+ (Edsr.Bctcperr == 1) ||
+ (Edsr.Nxmerr == 1) ) ) {
+ PUncorrectableError->UncorrectableFrame.PhysicalAddress =
+ ErrorAddress;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ PhysicalAddressValid = 1;
+
+ PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
+ MEMORY_SPACE;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ MemoryErrorSource = SYSTEM_MEMORY;
+ }
+
+ if(apecserr)
+ apecserr->EpicEcsr = Ecsr.all;
+
+ if( PUncorrectableError &&
+ ( (Ecsr.Merr == 1) ||
+ (Ecsr.Umrd == 1) ) ) {
+
+ PUncorrectableError->UncorrectableFrame.PhysicalAddress =
+ SystemErrorAddress;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ PhysicalAddressValid = 1;
+
+ PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
+ MEMORY_SPACE;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ MemoryErrorSource = SYSTEM_MEMORY;
+ }
+
+ if( PUncorrectableError &&
+ ( (Ecsr.Ndev == 1) ||
+ (Ecsr.Tabt == 1) ||
+ (Ecsr.Iope == 1) ||
+ (Ecsr.Ddpe == 1) ||
+ (Ecsr.Iptl == 1) ||
+ (Ecsr.Iort == 1) ) ){
+
+ PUncorrectableError->UncorrectableFrame.PhysicalAddress =
+ Pear;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ PhysicalAddressValid = 1;
+
+ PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
+ IO_SPACE;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ MemoryErrorSource = 0;
+ }
+
+ if(apecserr){
+ apecserr->EpicPciErrAddr = Pear;
+ apecserr->EpicSysErrAddr = SystemErrorAddress;
+ apecserr->ComancheErrAddr = ErrorAddress;
+ }
+
+ return;
+
+}
+
+
+BOOLEAN
+HalpPlatformMachineCheck(
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PKEXCEPTION_FRAME ExceptionFrame,
+ IN PKTRAP_FRAME TrapFrame
+ )
+/*++
+
+Routine Description:
+
+ This routine is given control when an hard error is acknowledged
+ by the APECS chipset. The routine is given the chance to
+ correct and dismiss the error.
+
+Arguments:
+
+ ExceptionRecord - Supplies a pointer to the exception record generated
+ at the point of the exception.
+
+ ExceptionFrame - Supplies a pointer to the exception frame generated
+ at the point of the exception.
+
+ TrapFrame - Supplies a pointer to the trap frame generated
+ at the point of the exception.
+
+Return Value:
+
+ TRUE is returned if the machine check has been handled and dismissed -
+ indicating that execution can continue. FALSE is return otherwise.
+
+--*/
+{
+ COMANCHE_EDSR Edsr;
+ EPIC_ECSR Ecsr;
+
+ PAPECS_UNCORRECTABLE_FRAME apecserr = NULL;
+
+ //
+ // Check if there are any memory errors pending in the Comanche.
+ //
+ // A lost error, tag parity, tag control or non-existent memory
+ // error indicates a non-dismissable error.
+ //
+
+ HalpReadApecsErrorRegisters();
+
+ if(PUncorrectableError)
+ apecserr = (PAPECS_UNCORRECTABLE_FRAME)
+ PUncorrectableError->UncorrectableFrame.RawSystemInformation;
+
+ if(apecserr == NULL){
+ Edsr.all = READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->
+ ErrorAndDiagnosticStatusRegister );
+
+ Ecsr.all = READ_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->
+ EpicControlAndStatusRegister );
+
+ }
+ else {
+
+ Edsr.all = apecserr->ComancheEdsr;
+
+ Ecsr.all = apecserr->EpicEcsr;
+ }
+
+ if( (Edsr.Losterr == 1) ||
+ (Edsr.Bctaperr == 1) ||
+ (Edsr.Bctcperr == 1) ||
+ (Edsr.Nxmerr == 1) ){
+
+ goto FatalError;
+
+ }
+
+ //
+ // Check if there are any non-recoverable I/O errors.
+ //
+ // Memory errors, invalid page table lookups, uncorrectable
+ // memory errors, target aborts, io parity errors, dma parity
+ // errors, lost errors, and retry timeouts are all considered
+ // non-dismissable errors.
+ //
+
+ if( (Ecsr.Merr == 1) ||
+ (Ecsr.Iptl == 1) ||
+ (Ecsr.Umrd == 1) ||
+ (Ecsr.Tabt == 1) ||
+ (Ecsr.Iope == 1) ||
+ (Ecsr.Ddpe == 1) ||
+ (Ecsr.Iort == 1) ){
+
+ goto FatalError;
+
+ }
+
+ //
+ // A Pass1 APECS chip bug will erroneously report a lost operation,
+ // so, if a Pass1 chip, then ignore the error.
+ //
+
+ if ( (Ecsr.Lost == 1) && (Ecsr.Pass2 == 1)) {
+ goto FatalError;
+ }
+
+ //
+ // Check for a PCI configuration read error. An error is a
+ // candidate if the I/O controller has signalled a NoDevice error.
+ //
+
+ if( Ecsr.Ndev == 1 ){
+
+ //
+ // So far, the error looks like a PCI configuration space read
+ // that accessed a device that does not exist. In order to fix
+ // this up we expect that the faulting instruction or the instruction
+ // previous to the faulting instruction must be a load with v0 as
+ // the destination register. If this condition is met then simply
+ // update v0 in the register set and return. However, be careful
+ // not to re-execute the load.
+ //
+ // jnfix - add condition to check if Rb contains the superpage
+ // address for config space?
+
+ ALPHA_INSTRUCTION FaultingInstruction;
+ BOOLEAN PreviousInstruction = FALSE;
+ BOOLEAN WasLost = (Ecsr.Lost == 1 ? TRUE : FALSE);
+
+ FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir);
+ if( (FaultingInstruction.Memory.Ra != V0_REG) ||
+ (FaultingInstruction.Memory.Opcode != LDL_OP) ){
+
+ //
+ // Faulting instruction did not match, try the previous
+ // instruction.
+ //
+
+ PreviousInstruction = TRUE;
+
+ FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir - 4);
+ if( (FaultingInstruction.Memory.Ra != V0_REG) ||
+ (FaultingInstruction.Memory.Opcode != LDL_OP) ){
+
+ //
+ // No match, we can't fix this up.
+ //
+
+ goto FatalError;
+ }
+ }
+
+ //
+ // The error has matched all of our conditions. Fix it up by
+ // writing the value 0xffffffff into the destination of the load.
+ //
+
+ TrapFrame->IntV0 = (ULONGLONG)0xffffffffffffffff;
+
+ //
+ // If the faulting instruction was the load the restart execution
+ // at the instruction after the load.
+ //
+
+ if( PreviousInstruction == FALSE ){
+ TrapFrame->Fir += 4;
+ }
+
+ //
+ // Clear the error condition in the ECSR.
+ //
+
+ Ecsr.all = READ_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister);
+
+ Ecsr.Ndev = 1;
+ Ecsr.Dcei = 1;
+
+ if (WasLost) {
+ Ecsr.Lost = 1;
+ }
+
+ WRITE_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister,
+ Ecsr.all );
+
+ return TRUE;
+
+ } //endif Ecsr.Ndev == 1
+
+
+ //
+ // Handle any ECC correctable errors.
+ //
+
+ if( Ecsr.Cmrd ) {
+
+ //
+ // Handle the error and then clear the error bit.
+ //
+
+ HalpApecsCorrectableError();
+ Ecsr.Cmrd = 0;
+ Ecsr.Lost = 0;
+
+ //
+ // If there are no other outstanding errors, then return.
+ //
+
+ if ( Ecsr.all )
+ return TRUE;
+ }
+
+ //
+ // A Pass1 APECS chip bug will erroneously report a lost operation,
+ // so, if a Pass1 chip, then ignore the error.
+ //
+
+ if ( (Ecsr.Lost == 1) && (Ecsr.Pass2 == 1)) {
+ goto FatalError;
+ }
+
+ //
+ // The system is not well and cannot continue reliable execution.
+ // Print some useful messages and return FALSE to indicate that the error
+ // was not handled.
+ //
+
+FatalError:
+
+ if(PUncorrectableError) {
+ PUncorrectableError->UncorrectableFrame.Flags.SystemInformationValid =
+ 1;
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+ sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
+ "Uncorrectable Error From Apecs Chipset Detected");
+ }
+
+ HalpApecsReportFatalError();
+
+ return FALSE;
+
+}
+
+
+VOID
+HalpApecsErrorInterrupt(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine is entered as a result of an error interrupt on the
+ APECS chipset. This function determines if the error is fatal
+ or recoverable and if recoverable performs the recovery and
+ error logging.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ COMANCHE_EDSR Edsr;
+ EPIC_ECSR Ecsr;
+ PAPECS_UNCORRECTABLE_FRAME apecserr = NULL;
+
+ HalpReadApecsErrorRegisters();
+
+ if(PUncorrectableError)
+ apecserr = (PAPECS_UNCORRECTABLE_FRAME)
+ PUncorrectableError->UncorrectableFrame.RawSystemInformation;
+
+ if(apecserr == NULL){
+ Edsr.all = READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->
+ ErrorAndDiagnosticStatusRegister );
+
+ Ecsr.all = READ_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->
+ EpicControlAndStatusRegister );
+
+ }
+ else {
+
+ Edsr.all = apecserr->ComancheEdsr;
+
+ Ecsr.all = apecserr->EpicEcsr;
+ }
+
+ //
+ // Any error from the COMANCHE represents a fatal condition.
+ //
+
+ if( (Edsr.Losterr == 1) ||
+ (Edsr.Bctaperr == 1) ||
+ (Edsr.Bctcperr == 1) ||
+ (Edsr.Nxmerr == 1) ){
+
+ goto FatalErrorInterrupt;
+
+ }
+
+ //
+ // Almost any error from the EPIC is also fatal. The only exception
+ // is the correctable memory read error. Any other error is fatal.
+ //
+
+ if( (Ecsr.Merr == 1) ||
+ (Ecsr.Iptl == 1) ||
+ (Ecsr.Umrd == 1) ||
+ (Ecsr.Tabt == 1) ||
+ (Ecsr.Ndev == 1) ||
+ (Ecsr.Iope == 1) ||
+ (Ecsr.Ddpe == 1) ||
+ (Ecsr.Iort == 1) ){
+
+ goto FatalErrorInterrupt;
+
+ }
+
+ //
+ // A Pass1 APECS chip bug will erroneously report a lost operation,
+ // so, if a Pass1 chip, then ignore the error.
+ //
+
+ if ( (Ecsr.Lost == 1) && (Ecsr.Pass2 == 1)) {
+ goto FatalErrorInterrupt;
+ }
+
+ //
+ // The error may be correctable. If the correctable error bit is
+ // set in the ECSR then log the error and clear the condition.
+ //
+
+ if( Ecsr.Cmrd == 1 ){
+
+ ULONG Sear;
+ ULONGLONG SystemErrorAddress;
+
+ CorrectedMemoryReads += 1;
+
+ Sear = READ_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->SysbusErrorAddressRegister );
+
+ SystemErrorAddress = (ULONGLONG)(Sear) << 2;
+
+ //jnfix - temporary debug logging only
+#if (DBG) || (HALDBG)
+
+ if( (CorrectedMemoryReads % 32) == 0 ){
+ DbgPrint( "APECS: CorrectedMemoryReads = %d, Address = 0x%Lx\n",
+ CorrectedMemoryReads,
+ SystemErrorAddress );
+ }
+
+#endif //DBG || HALDBG
+
+ //
+ // Clear the error condition.
+ //
+
+ WRITE_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister,
+ Ecsr.all
+ );
+
+ return;
+
+ } //endif Ecsr.Cmrd == 1
+
+//
+// The interrupt indicates a fatal system error.
+// Display information about the error and shutdown the machine.
+//
+
+FatalErrorInterrupt:
+
+ HalpApecsReportFatalError();
+
+//jnfix - add some of the address registers?
+//
+// Add the address of the error frame as 4th parameter.
+//
+ KeBugCheckEx( DATA_BUS_ERROR,
+ Edsr.all,
+ Ecsr.all,
+ 0,
+ (ULONG)PUncorrectableError );
+
+
+}
+
+
+VOID
+HalpApecsReportFatalError(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function reports and interprets a fatal hardware error on
+ the APECS chipset. The COMANCHE Error and Diagnostic Status Register
+ and the EPIC Error and Status Register are read to determine how
+ to interpret the error.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ COMANCHE_EDSR Edsr;
+ EPIC_ECSR Ecsr;
+ ULONGLONG ErrorAddress;
+ ULONG ErrorHighAddress;
+ ULONG ErrorLowAddress;
+ ULONG Pear;
+ ULONG Sear;
+ ULONGLONG SystemErrorAddress;
+ UCHAR OutBuffer[MAX_ERROR_STRING];
+ PAPECS_UNCORRECTABLE_FRAME apecserr = NULL;
+ PEXTENDED_ERROR PExtErr = NULL;
+
+ //
+ // Begin the error output by acquiring ownership of the display
+ // and printing the dreaded banner.
+ //
+
+ HalAcquireDisplayOwnership(NULL);
+
+ HalDisplayString( "\nFatal system hardware error.\n\n" );
+
+ //
+ // Extract register values to report from Error Frame.
+ //
+ if(PUncorrectableError){
+ apecserr = (PAPECS_UNCORRECTABLE_FRAME)
+ PUncorrectableError->UncorrectableFrame.RawSystemInformation;
+ PExtErr = &PUncorrectableError->UncorrectableFrame.ErrorInformation;
+ }
+
+ if(apecserr == NULL){
+ Edsr.all = READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->
+ ErrorAndDiagnosticStatusRegister );
+
+ Ecsr.all = READ_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->
+ EpicControlAndStatusRegister );
+
+ ErrorLowAddress = READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorLowAddressRegister );
+
+ ErrorHighAddress = READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->ErrorHighAddressRegister);
+
+ ErrorAddress = ((ULONGLONG)(ErrorHighAddress) << 21) +
+ ((ULONGLONG)(ErrorLowAddress) << 5);
+
+ Sear = READ_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->SysbusErrorAddressRegister );
+
+ SystemErrorAddress = (ULONGLONG)(Sear) << 2;
+
+ Pear = READ_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->PciErrorAddressRegister );
+
+ }
+ else {
+
+ Edsr.all = apecserr->ComancheEdsr;
+
+ Ecsr.all = apecserr->EpicEcsr;
+
+ Pear = apecserr->EpicPciErrAddr;
+ SystemErrorAddress = apecserr->EpicSysErrAddr;
+ ErrorAddress = apecserr->ComancheErrAddr;
+ }
+
+
+
+ //
+ // Interpret any errors from the COMANCHE EDSR.
+ //
+
+ sprintf( OutBuffer, "Comanche EDSR = 0x%x\n", Edsr.all );
+ HalDisplayString( OutBuffer );
+
+ if( Edsr.Bctaperr == 1 ){
+
+ if(PExtErr){
+ PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
+ 1;
+
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+ sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
+ "B-Cache Tag Address Parity Error");
+
+ PUncorrectableError->UncorrectableFrame.Flags.MemoryErrorSource =
+ SYSTEM_CACHE;
+ //
+ // At present the HalpSimm routine doesn't do anything
+ // it expected to be fixed in the near future.
+ //
+ PExtErr->CacheError.Flags.CacheSimmValid = 1;
+ PExtErr->CacheError.CacheSimm = HalpSimm(ErrorAddress);
+ HalpGetProcessorInfo(&PExtErr->CacheError.ProcessorInfo);
+ if( Edsr.Dmacause == 1 ){
+ PExtErr->CacheError.TransferType = BUS_DMA_OP;
+ }
+ if( Edsr.Viccause == 1 ){
+ PExtErr->CacheError.TransferType = VICTIM_WRITE;
+ }
+
+ }
+
+ sprintf( OutBuffer,
+ "Bcache Tag Address Parity Error, Address: %Lx, SIMM = %d\n",
+ ErrorAddress, HalpSimm(ErrorAddress) );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ if( Edsr.Bctcperr == 1 ){
+
+ if(PExtErr){
+ PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
+ 1;
+
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+ sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
+ "B-Cache Tag Control Parity Error");
+
+ PUncorrectableError->UncorrectableFrame.Flags.MemoryErrorSource =
+ SYSTEM_CACHE;
+ //
+ // At present the HalpSimm routine doesn't do anything
+ // it is expected to be fixed in the near future.
+ //
+ PExtErr->CacheError.Flags.CacheSimmValid = 1;
+ PExtErr->CacheError.CacheSimm = HalpSimm(ErrorAddress);
+ HalpGetProcessorInfo(&PExtErr->CacheError.ProcessorInfo);
+ if( Edsr.Dmacause == 1 ){
+ PExtErr->CacheError.TransferType = BUS_DMA_OP;
+ }
+ if( Edsr.Viccause == 1 ){
+ PExtErr->CacheError.TransferType = VICTIM_WRITE;
+ }
+
+
+ }
+
+
+ sprintf( OutBuffer,
+ "Bcache Tag Control Parity Error, Address: %Lx, SIMM = %d\n",
+ ErrorAddress, HalpSimm(ErrorAddress) );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ if( Edsr.Nxmerr == 1 ){
+
+ if(PExtErr){
+ PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
+ 1;
+
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+ sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
+ "Non-existent memory error");
+
+ PUncorrectableError->UncorrectableFrame.Flags.MemoryErrorSource =
+ SYSTEM_MEMORY;
+ //
+ // At present the HalpSimm routine doesn't do anything
+ // it expected to be fixed in the near future.
+ //
+ PExtErr->MemoryError.Flags.MemorySimmValid = 1;
+ PExtErr->MemoryError.MemorySimm = HalpSimm(ErrorAddress);
+ HalpGetProcessorInfo(&PExtErr->MemoryError.ProcessorInfo);
+ if( Edsr.Dmacause == 1 ){
+ PExtErr->MemoryError.TransferType = BUS_DMA_OP;
+ }
+ if( Edsr.Viccause == 1 ){
+ PExtErr->MemoryError.TransferType = VICTIM_WRITE;
+ }
+
+
+ }
+
+ sprintf( OutBuffer,
+ "Non-existent memory error, Address: %Lx\n",
+ ErrorAddress );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ if( (Edsr.Bctaperr == 1) || (Edsr.Bctcperr == 1) ||
+ (Edsr.Nxmerr == 1) ){
+
+ if( Edsr.Dmacause == 1 ){
+ HalDisplayString( "Error caused on DMA.\n" );
+ }
+
+ if( Edsr.Viccause == 1 ){
+ HalDisplayString( "Victim write caused error.\n" );
+ }
+
+ }
+
+ if( Edsr.Losterr == 1 ){
+ HalDisplayString( "Multiple Cache/Memory errors.\n" );
+ }
+
+ //
+ // Interpret any errors from the EPIC Ecsr.
+ //
+
+ sprintf( OutBuffer, "EPIC ECSR = 0x%lx\n", Ecsr.all );
+ HalDisplayString( OutBuffer );
+
+ if( Ecsr.Iort == 1 ){
+
+ if(PExtErr){
+ PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
+ 1;
+
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+ sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
+ "PCI Retry timeout error");
+ PExtErr->IoError.Interface = PCIBus;
+
+ //
+ // Since APECS supports only one PCI Bus we will simply set
+ // the busnumber to 0.
+ //
+ PExtErr->IoError.BusNumber = 0;
+
+ }
+
+ sprintf( OutBuffer,
+ "PCI Retry timeout error, PCI Address: 0x%x\n",
+ Pear );
+ HalDisplayString( OutBuffer );
+
+ }
+
+ if( Ecsr.Ddpe == 1 ){
+
+ if(PExtErr){
+ PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
+ 1;
+
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+ sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
+ "DMA Data Parity Error");
+ PExtErr->IoError.Interface = PCIBus;
+
+ //
+ // Since APECS supports only one PCI Bus we will simply set
+ // the busnumber to 0.
+ //
+ PExtErr->IoError.BusNumber = 0;
+
+ }
+ sprintf( OutBuffer,
+ "DMA Data Parity Error at PCI Address: 0x%x\n",
+ Pear );
+ HalDisplayString( OutBuffer );
+
+ }
+
+ if( Ecsr.Iope == 1 ){
+
+ if(PExtErr){
+ PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
+ 1;
+
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+ sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
+ "I/O Data Parity Error");
+ PExtErr->IoError.Interface = PCIBus;
+
+ //
+ // Since APECS supports only one PCI Bus we will simply set
+ // the busnumber to 0.
+ //
+ PExtErr->IoError.BusNumber = 0;
+
+ }
+ sprintf( OutBuffer,
+ "I/O Data Parity Error at PCI Address: 0x%x\n",
+ Pear );
+ HalDisplayString( OutBuffer );
+
+ }
+
+ if( Ecsr.Tabt == 1 ){
+
+ if(PExtErr){
+ PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
+ 1;
+
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+ sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
+ "Target Abort Error");
+ PExtErr->IoError.Interface = PCIBus;
+
+ //
+ // Since APECS supports only one PCI Bus we will simply set
+ // the busnumber to 0.
+ //
+ PExtErr->IoError.BusNumber = 0;
+
+ }
+ sprintf( OutBuffer,
+ "Target Abort Error at PCI Address: 0x%x\n",
+ Pear );
+ HalDisplayString( OutBuffer );
+
+ }
+
+ if( Ecsr.Ndev == 1 ){
+
+ if(PExtErr){
+ PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
+ 1;
+
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+ sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
+ "No Device Error");
+ PExtErr->IoError.Interface = PCIBus;
+
+ //
+ // Since APECS supports only one PCI Bus we will simply set
+ // the busnumber to 0.
+ //
+ PExtErr->IoError.BusNumber = 0;
+
+ }
+ sprintf( OutBuffer,
+ "No Device Error at PCI Address: 0x%x\n",
+ Pear );
+ HalDisplayString( OutBuffer );
+
+ }
+
+ if( Ecsr.Iptl == 1 ){
+
+ if(PExtErr){
+ PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
+ 1;
+
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+ sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
+ "Invalid Page Table Lookup");
+ PExtErr->IoError.Interface = PCIBus;
+
+ //
+ // Since APECS supports only one PCI Bus we will simply set
+ // the busnumber to 0.
+ //
+ PExtErr->IoError.BusNumber = 0;
+
+ }
+ sprintf( OutBuffer,
+ "Invalid Page Table Lookup at PCI Address: 0x%x\n",
+ Pear );
+ HalDisplayString( OutBuffer );
+
+ }
+
+ if( Ecsr.Umrd == 1 ){
+
+ if(PExtErr){
+ PUncorrectableError->UncorrectableFrame.Flags.ExtendedErrorValid =
+ 1;
+
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+ sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
+ "memory read error");
+
+ PUncorrectableError->UncorrectableFrame.Flags.MemoryErrorSource =
+ SYSTEM_MEMORY;
+ //
+ // At present the HalpSimm routine doesn't do anything
+ // it expected to be fixed in the near future.
+ //
+ PExtErr->MemoryError.Flags.MemorySimmValid = 1;
+ PExtErr->MemoryError.MemorySimm = HalpSimm(ErrorAddress);
+ HalpGetProcessorInfo(&PExtErr->MemoryError.ProcessorInfo);
+
+
+ }
+ sprintf( OutBuffer,
+ "Uncorrectable memory read error, System Address: 0x%Lx\n",
+ SystemErrorAddress );
+ HalDisplayString( OutBuffer );
+
+ }
+
+
+ if( Ecsr.Merr == 1 ){
+
+ sprintf( OutBuffer,
+ "Memory error, System Address: 0x%Lx\n",
+ SystemErrorAddress );
+ HalDisplayString( OutBuffer );
+
+ }
+
+ if( Ecsr.Lost == 1 ){
+ HalDisplayString( "Multiple I/O errors detected.\n" );
+ }
+
+ return;
+
+}
+
+ULONG
+HalpSimm(
+ ULONGLONG Address
+ )
+/*++
+
+Routine Description:
+
+ Return the number of the SIMM corresponding to the supplied physical
+ address.
+
+Arguments:
+
+ Address - Supplies the physical address of a byte in memory.
+
+Return Value:
+
+ The number of the SIMM that contains the byte of physical memory is
+ returned. If the Address does not fit within a SIMM or the SIMM number
+ cannot be determined 0xffffffff is returned.
+
+--*/
+{
+
+//jnfix - see if this can be determined exclusively from memory registers
+//jnfix - or is this platform-dependent
+
+ return( 0xffffffff );
+
+}
+
+
+VOID
+HalpApecsCorrectableError(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Handle ECC correctable errors from the APECS.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ static ERROR_FRAME Frame;
+ static APECS_CORRECTABLE_FRAME ApecsFrame;
+
+ ERROR_FRAME TempFrame;
+ PCORRECTABLE_ERROR CorrPtr;
+ PBOOLEAN ErrorlogBusy;
+ PULONG DispatchCode;
+ PKINTERRUPT InterruptObject;
+ PKSPIN_LOCK ErrorlogSpinLock;
+ EPIC_ECSR Ecsr;
+ ULONG Sear;
+ ULONGLONG SystemErrorAddress;
+
+ //
+ // Read the Epic control and status register.
+ //
+
+ Ecsr.all = READ_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister );
+
+ //
+ // Get the system address. Note, bits 2-4 of the address not available.
+ //
+
+ Sear = READ_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->SysbusErrorAddressRegister );
+
+ SystemErrorAddress = (ULONGLONG)Sear << 2;
+
+#if (DBG) || (HALDBG)
+
+ if( (CorrectedMemoryReads % 32) == 0 ){
+ DbgPrint("APECS: CorrectedMemoryReads = %d, Address = 0x%Lx\n",
+ CorrectedMemoryReads,
+ SystemErrorAddress );
+ }
+
+#endif
+
+ //
+ // Get the interrupt object.
+ //
+
+ DispatchCode = (PULONG)(PCR->InterruptRoutine[CORRECTABLE_VECTOR]);
+ InterruptObject = CONTAINING_RECORD(DispatchCode,
+ KINTERRUPT,
+ DispatchCode);
+
+ //
+ // Set various pointers so we can use them later.
+ //
+
+ CorrPtr = &TempFrame.CorrectableFrame;
+ ErrorlogBusy = (PBOOLEAN)((PUCHAR)InterruptObject->ServiceContext +
+ sizeof(PERROR_FRAME));
+ ErrorlogSpinLock = (PKSPIN_LOCK)((PUCHAR)ErrorlogBusy + sizeof(PBOOLEAN));
+
+ //
+ // Update the number of correctable errors.
+ //
+
+ CorrectedMemoryReads += 1;
+
+ //
+ // Clear the data structures that we will use.
+ //
+
+ RtlZeroMemory(&TempFrame, sizeof(ERROR_FRAME));
+
+ //
+ // Fill in the error frame information.
+ //
+
+ TempFrame.Signature = ERROR_FRAME_SIGNATURE;
+ TempFrame.FrameType = CorrectableFrame;
+ TempFrame.VersionNumber = ERROR_FRAME_VERSION;
+ TempFrame.SequenceNumber = CorrectedMemoryReads;
+ TempFrame.PerformanceCounterValue =
+ KeQueryPerformanceCounter(NULL).QuadPart;
+
+ //
+ // Check for lost error.
+ //
+
+ if( Ecsr.Lost ) {
+
+ //
+ // Since the error registers are locked from a previous error,
+ // we don't know where the error came from. Mark everything
+ // as UNIDENTIFIED.
+ //
+
+ CorrPtr->Flags.LostCorrectable = 1;
+ CorrPtr->Flags.LostAddressSpace = UNIDENTIFIED;
+ CorrPtr->Flags.LostMemoryErrorSource = UNIDENTIFIED;
+ }
+
+ //
+ // Either a DMA read or DMA TLB read ECC error. We can't tell
+ // since the EPIC chip doesn't provid enough information. Just
+ // log everything as a DMA ECC error.
+ //
+
+ CorrPtr->Flags.AddressSpace = MEMORY_SPACE;
+ CorrPtr->Flags.ExtendedErrorValid = 1;
+ CorrPtr->Flags.MemoryErrorSource = SYSTEM_MEMORY;
+ CorrPtr->ErrorInformation.MemoryError.TransferType = BUS_DMA_READ;
+
+ //
+ // Get the physical address where the error occurred.
+ //
+
+ CorrPtr->Flags.PhysicalAddressValid = 1;
+ CorrPtr->PhysicalAddress = SystemErrorAddress;
+
+ //
+ // Scrub the error if it's any type of memory error.
+ //
+
+ if (CorrPtr->Flags.AddressSpace == MEMORY_SPACE &&
+ CorrPtr->Flags.PhysicalAddressValid )
+ CorrPtr->Flags.ScrubError = 1;
+
+ //
+ // Acquire the spinlock.
+ //
+
+ KiAcquireSpinLock(ErrorlogSpinLock);
+
+ //
+ // Check to see if an errorlog operation is in progress already.
+ //
+
+ if (!*ErrorlogBusy) {
+
+ //
+ // The error is expected to be a corrected ECC error on a DMA or
+ // Scatter/Gather TLB read. Read the error registers relevant
+ // to this error.
+ //
+
+ ApecsFrame.EpicEcsr = Ecsr.all;
+
+ ApecsFrame.EpicSysErrAddr = Sear;
+
+ //
+ // Read the CIA configuration registers for logging information.
+ //
+
+ ApecsFrame.Configuration.ApecsRev = Ecsr.Pass2;
+ HalpApecsConfig( &ApecsFrame.Configuration );
+
+ //
+ // Set the raw system information.
+ //
+
+ CorrPtr->RawSystemInformationLength = sizeof(APECS_CORRECTABLE_FRAME);
+ CorrPtr->RawSystemInformation = &ApecsFrame;
+
+ //
+ // Set the raw processor information. Disregard at the moment.
+ //
+
+ CorrPtr->RawProcessorInformationLength = 0;
+
+ //
+ // Set reporting processor information. Disregard at the moment.
+ //
+
+ CorrPtr->Flags.ProcessorInformationValid = 0;
+
+ //
+ // Set system information. Disregard at the moment.
+ //
+
+ CorrPtr->Flags.SystemInformationValid = 0;
+
+ //
+ // Copy the information that we need to log.
+ //
+
+ RtlCopyMemory(&Frame,
+ &TempFrame,
+ sizeof(ERROR_FRAME));
+
+ //
+ // Put frame into ISR service context.
+ //
+
+ *(PERROR_FRAME *)InterruptObject->ServiceContext = &Frame;
+
+ } else {
+
+ //
+ // An errorlog operation is in progress already. We will
+ // set various lost bits and then get out without doing
+ // an actual errorloging call.
+ //
+
+ Frame.CorrectableFrame.Flags.LostCorrectable = TRUE;
+ Frame.CorrectableFrame.Flags.LostAddressSpace =
+ TempFrame.CorrectableFrame.Flags.AddressSpace;
+ Frame.CorrectableFrame.Flags.LostMemoryErrorSource =
+ TempFrame.CorrectableFrame.Flags.MemoryErrorSource;
+ }
+
+ //
+ // Release the spinlock.
+ //
+
+ KiReleaseSpinLock(ErrorlogSpinLock);
+
+ //
+ // Dispatch to the secondary correctable interrupt service routine.
+ // The assumption here is that if this interrupt ever happens, then
+ // some driver enabled it, and the driver should have the ISR connected.
+ //
+
+ ((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)(
+ InterruptObject,
+ InterruptObject->ServiceContext);
+
+ //
+ // Clear lost and correctable error bit.
+ //
+
+ if (Ecsr.Lost) {
+
+ Ecsr.all = 0;
+ Ecsr.Cmrd = 1;
+ Ecsr.Lost = 1;
+
+ } else {
+
+ Ecsr.all = 0;
+ Ecsr.Cmrd = 1;
+ }
+
+ WRITE_EPIC_REGISTER(
+ &((PEPIC_CSRS)(APECS_EPIC_BASE_QVA))->EpicControlAndStatusRegister,
+ Ecsr.all);
+
+ return;
+}
+
+
+VOID
+HalpApecsConfig(
+ PAPECS_CONFIGURATION Config
+ )
+/*++
+
+Routine Description:
+
+ Reads in the configuration registers from the Comanche chip.
+
+Arguments:
+
+ Pointer to the configuration frame.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Read in all the registers.
+ //
+
+ Config->CGcr =
+ READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->GeneralControlRegister
+ );
+
+ Config->CTer =
+ READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->TagEnableRegister
+ );
+
+ Config->CGtr =
+ READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->GlobalTimingRegister
+ );
+
+ Config->CRtr =
+ READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->RefreshTimingRegister
+ );
+
+ Config->CBank0 =
+ READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank0ConfigurationRegister
+ );
+
+ Config->CBank1 =
+ READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank1ConfigurationRegister
+ );
+
+ Config->CBank2 =
+ READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank2ConfigurationRegister
+ );
+
+ Config->CBank3 =
+ READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank3ConfigurationRegister
+ );
+
+ Config->CBank4 =
+ READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank4ConfigurationRegister
+ );
+
+ Config->CBank5 =
+ READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank5ConfigurationRegister
+ );
+
+ Config->CBank6 =
+ READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank6ConfigurationRegister
+ );
+
+ Config->CBank7 =
+ READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank7ConfigurationRegister
+ );
+
+ Config->CBank8 =
+ READ_COMANCHE_REGISTER(
+ &((PCOMANCHE_CSRS)(APECS_COMANCHE_BASE_QVA))->Bank8ConfigurationRegister
+ );
+}
diff --git a/private/ntos/nthals/halalpha/apecsio.s b/private/ntos/nthals/halalpha/apecsio.s
new file mode 100644
index 000000000..9ae932d10
--- /dev/null
+++ b/private/ntos/nthals/halalpha/apecsio.s
@@ -0,0 +1,701 @@
+
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ apecsio.s
+
+
+Abstract:
+
+ This contains assembler code routines for the Alpha AXP Eval Board eb64+.
+
+ The module contains the functions to turn quasi virtual
+ addresses into an Alpha superpage virtual address
+ and then read or write based on the request.
+ (We are using EV4 64-bit superpage mode.)
+
+Author:
+
+ Joe Notarangelo 25-Oct-1993
+
+Environment:
+
+ Executes in kernel mode.
+
+Revision History:
+
+ Sameer Dekate 28-July-1994
+
+ Made a common file alphaio.s for machine independent routines.
+
+
+--*/
+
+#include "apecs.h"
+#include "halalpha.h"
+
+
+
+ SBTTL( "Write Control Register" )
+//++
+//
+// VOID
+// WRITE_EPIC_REGISTER(
+// IN PVOID RegisterQva,
+// IN ULONG Value
+// )
+//
+// Routine Description:
+//
+// Write a control register in the APECS memory or PCI controller
+// (COMANCHE and EPIC respectively).
+//
+// Arguments:
+//
+// RegisterQva(a0) - QVA of control register to be written.
+//
+// Value(a1) - Longword value to be written to the control register.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_EPIC_REGISTER)
+
+ ALTERNATE_ENTRY(WRITE_COMANCHE_REGISTER)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, 5, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ or t0, t4, t0 // superpage mode
+
+ .set volatile
+
+ stl a1, (t0) // write the longword
+ ldl t4, (t0) // read the the longword, to force
+ // consistency (EPIC chip bug).
+ mb // order the write
+ .set novolatile
+
+ ret zero, (ra) // return
+
+2: // flag bad QVAs
+ BREAK_DEBUG_STOP // take a breakpoint
+ ret zero, (ra) // return
+
+ .end WRITE_EPIC_REGISTER
+
+
+ SBTTL( "Read Control Register" )
+//++
+//
+// ULONG
+// READ_EPIC_REGISTER(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Read a control register in the APECS memory or PCI controller
+// (COMANCHE and EPIC respectively).
+//
+// Arguments:
+//
+// RegisterQva(a0) - QVA of control register to be written.
+//
+// Return Value:
+//
+// v0 - Return the value read from the control register.
+//
+//--
+
+ LEAF_ENTRY(READ_EPIC_REGISTER)
+
+ ALTERNATE_ENTRY(READ_COMANCHE_REGISTER)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, 5, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ or t0, t4, t0 // superpage mode
+
+ ldl v0, (t0) // read the register
+
+ ret zero, (ra) // return
+
+2: // flag bad QVAs
+ BREAK_DEBUG_STOP // take a breakpoint
+
+ ret zero, (ra) // return
+
+ .end READ_EPIC_REGISTER
+
+
+//
+// Values and structures used to access configuration space.
+//
+
+//
+// Define the QVA for the Configuration Cycle Type register within the
+// IOC. Physical Address = 1 A000 01C0
+//
+
+#define EPIC_HAXR2_QVA (0xad00000e)
+
+//
+// Define the configuration routines stack frame.
+//
+
+ .struct 0
+CfgRa: .space 8 // return address
+CfgA0: .space 8 // saved ConfigurationAddress
+CfgA1: .space 8 // saved ConfigurationData/CycleType
+CfgA2: .space 8 // saved ConfigurationCycleType
+CfgFrameLength:
+
+
+//++
+//
+// ULONG
+// READ_CONFIG_UCHAR(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read an unsigned byte from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read.
+//
+// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - This routine follows a protocol for reading from PCI configuration
+// space that allows the HAL or firmware to fixup and continue
+// execution if no device exists at the configuration target address.
+// The protocol requires 2 rules:
+// (1) The configuration space load must use a destination register
+// of v0
+// (2) The instruction immediately following the configuration space
+// load must use v0 as an operand (it must consume the value
+// returned by the load)
+//
+//--
+
+ NESTED_ENTRY( READ_CONFIG_UCHAR, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Merge the configuration cycle type into the HAXR2 register within
+// the EPIC.
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+ stq a1, CfgA1(sp) // save configuration cycle type
+
+ ldil a0, EPIC_HAXR2_QVA // address of HAXR2
+ bsr ra, READ_EPIC_REGISTER // read current value
+
+ ldq a1, CfgA1(sp) // restore configuration cycle type
+ bic v0, 0x3, t0 // clear config cycle type field
+ bis a1, t0, a1 // merge config cycle type
+ ldil a0, EPIC_HAXR2_QVA // address of HAXR2
+ bsr ra, WRITE_EPIC_REGISTER // write updated HAXR2
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 0x3, t3 // capture byte lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_BYTE_LEN, t0 // or in the byte enables
+
+ ldl v0, (t0) // read the longword
+ extbl v0, t3, v0 // return byte from requested lane
+ // also, consume loaded value to cause
+ // a pipeline stall
+2: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end READ_CONFIG_UCHAR
+
+//++
+//
+// VOID
+// WRITE_CONFIG_UCHAR(
+// ULONG ConfigurationAddress,
+// UCHAR ConfigurationData,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read an unsigned byte from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA to write.
+//
+// ConfigurationData(a1) - Supplies the data to be written.
+//
+// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// None.
+//
+// N.B. - The configuration address must exist within the address space
+// allocated to an existing PCI device. Otherwise, the access
+// below will initiate an unrecoverable machine check.
+//
+//--
+
+ NESTED_ENTRY( WRITE_CONFIG_UCHAR, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Merge the configuration cycle type into the HAXR2 register within
+// the EPIC.
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+ stq a1, CfgA1(sp) // save configuration data
+ stq a2, CfgA2(sp) // save configuration cycle type
+
+ ldil a0, EPIC_HAXR2_QVA // address of HAXR2
+ bsr ra, READ_EPIC_REGISTER // read current value
+
+ ldq a1, CfgA2(sp) // restore configuration cycle type
+ bic v0, 0x3, t0 // clear config cycle type field
+ bis a1, t0, a1 // merge config cycle type
+ ldil a0, EPIC_HAXR2_QVA // address of HAXR2
+ bsr ra, WRITE_EPIC_REGISTER // write updated HAXR2
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address and data.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+ ldq a1, CfgA1(sp) // restore configuration data
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 0x3, t3 // capture byte lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_BYTE_LEN, t0 // or in the byte length indicator
+
+ insbl a1, t3, t4 // put byte in the appropriate lane
+ stl t4, (t0) // write the configuration byte
+ mb // synchronize
+
+2: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end WRITE_CONFIG_UCHAR
+
+//++
+//
+// ULONG
+// READ_CONFIG_USHORT(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read a longword from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of quadword to be read.
+//
+// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - This routine follows a protocol for reading from PCI configuration
+// space that allows the HAL or firmware to fixup and continue
+// execution if no device exists at the configuration target address.
+// The protocol requires 2 rules:
+// (1) The configuration space load must use a destination register
+// of v0
+// (2) The instruction immediately following the configuration space
+// load must use v0 as an operand (it must consume the value
+// returned by the load)
+//--
+
+ NESTED_ENTRY( READ_CONFIG_USHORT, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Merge the configuration cycle type into the HAXR2 register within
+// the EPIC.
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+ stq a1, CfgA1(sp) // save configuration cycle type
+
+ ldil a0, EPIC_HAXR2_QVA // address of HAXR2
+ bsr ra, READ_EPIC_REGISTER // read current value
+
+ ldq a1, CfgA1(sp) // restore configuration cycle type
+ bic v0, 0x3, t0 // clear config cycle type field
+ bis a1, t0, a1 // merge config cycle type
+ ldil a0, EPIC_HAXR2_QVA // address of HAXR2
+ bsr ra, WRITE_EPIC_REGISTER // write updated HAXR2
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 0x3, t3 // capture word offset
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_WORD_LEN, t0 // or in the byte enables
+
+ ldl v0, (t0) // read the longword
+ extwl v0, t3, v0 // return word from requested lanes
+ // also, consume loaded value to cause
+ // a pipeline stall
+2: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end READ_CONFIG_USHORT
+
+//++
+//
+// VOID
+// WRITE_CONFIG_USHORT(
+// ULONG ConfigurationAddress,
+// USHORT ConfigurationData,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read a longword from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA to write.
+//
+// ConfigurationData(a1) - Supplies the data to be written.
+//
+// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - The configuration address must exist within the address space
+// allocated to an existing PCI device. Otherwise, the access
+// below will initiate an unrecoverable machine check.
+//
+//--
+
+ NESTED_ENTRY( WRITE_CONFIG_USHORT, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Merge the configuration cycle type into the HAXR2 register within
+// the EPIC.
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+ stq a1, CfgA1(sp) // save configuration data
+ stq a2, CfgA2(sp) // save configuration cycle type
+
+ ldil a0, EPIC_HAXR2_QVA // address of HAXR2
+ bsr ra, READ_EPIC_REGISTER // read current value
+
+ ldq a1, CfgA2(sp) // restore configuration cycle type
+ bic v0, 0x3, t0 // clear config cycle type field
+ bis a1, t0, a1 // merge config cycle type
+ ldil a0, EPIC_HAXR2_QVA // address of HAXR2
+ bsr ra, WRITE_EPIC_REGISTER // write updated HAXR2
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address and data.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+ ldq a1, CfgA1(sp) // restore configuration data
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 0x3, t3 // capture word offset
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_WORD_LEN, t0 // or in the byte enables
+
+ inswl a1, t3, t4 // put data to appropriate lane
+ stl t4, (t0) // read the longword
+ mb // synchronize
+2: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end WRITE_CONFIG_USHORT
+
+//++
+//
+// ULONG
+// READ_CONFIG_ULONG(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read a longword from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of quadword to be read.
+//
+// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - This routine follows a protocol for reading from PCI configuration
+// space that allows the HAL or firmware to fixup and continue
+// execution if no device exists at the configuration target address.
+// The protocol requires 2 rules:
+// (1) The configuration space load must use a destination register
+// of v0
+// (2) The instruction immediately following the configuration space
+// load must use v0 as an operand (it must consume the value
+// returned by the load)
+//--
+
+ NESTED_ENTRY( READ_CONFIG_ULONG, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Merge the configuration cycle type into the HAXR2 register within
+// the EPIC.
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+ stq a1, CfgA1(sp) // save configuration cycle type
+
+ ldil a0, EPIC_HAXR2_QVA // address of HAXR2
+ bsr ra, READ_EPIC_REGISTER // read current value
+
+ ldq a1, CfgA1(sp) // restore configuration cycle type
+ bic v0, 0x3, t0 // clear config cycle type field
+ bis a1, t0, a1 // merge config cycle type
+ ldil a0, EPIC_HAXR2_QVA // address of HAXR2
+ bsr ra, WRITE_EPIC_REGISTER // write updated HAXR2
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_LONG_LEN, t0 // or in the byte enables
+
+ ldl v0, (t0) // read the longword
+ bis v0, zero, t1 // consume loaded value to cause
+ // a pipeline stall
+2: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end READ_CONFIG_ULONG
+
+
+//++
+//
+// VOID
+// WRITE_CONFIG_ULONG(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationData,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read a longword from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA to write.
+//
+// ConfigurationData(a1) - Supplies the data to be written.
+//
+// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - The configuration address must exist within the address space
+// allocated to an existing PCI device. Otherwise, the access
+// below will initiate an unrecoverable machine check.
+//
+//--
+
+ NESTED_ENTRY( WRITE_CONFIG_ULONG, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Merge the configuration cycle type into the HAXR2 register within
+// the EPIC.
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+ stq a1, CfgA1(sp) // save configuration data
+ stq a2, CfgA2(sp) // save configuration cycle type
+
+ ldil a0, EPIC_HAXR2_QVA // address of HAXR2
+ bsr ra, READ_EPIC_REGISTER // read current value
+
+ ldq a1, CfgA2(sp) // restore configuration cycle type
+ bic v0, 0x3, t0 // clear config cycle type field
+ bis a1, t0, a1 // merge config cycle type
+ ldil a0, EPIC_HAXR2_QVA // address of HAXR2
+ bsr ra, WRITE_EPIC_REGISTER // write updated HAXR2
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address and data.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+ ldq a1, CfgA1(sp) // restore configuration data
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_LONG_LEN, t0 // or in the byte enables
+
+ stl a1, (t0) // write the longword
+ mb // synchronize
+2: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end WRITE_CONFIG_ULONG
diff --git a/private/ntos/nthals/halalpha/axintsup.c b/private/ntos/nthals/halalpha/axintsup.c
new file mode 100644
index 000000000..031241f5d
--- /dev/null
+++ b/private/ntos/nthals/halalpha/axintsup.c
@@ -0,0 +1,763 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ eisasup.c
+
+Abstract:
+
+ The module provides the EISA bus support for Alpha systems.
+
+Author:
+
+ Jeff Havens (jhavens) 19-Jun-1991
+ Miche Baker-Harvey (miche) 13-May-1992
+ Jeff McLeman (DEC) 1-Jun-1992
+
+Revision History:
+
+ 11-Mar-1993 Joe Mitchell (DEC)
+ Added support for NMI interrupts: Added interrupt service routine
+ HalHandleNMI. Added code to HalpCreateEisaStructures to initialize
+ NMI interrupts.
+
+ 22-Jul-1992 Jeff McLeman (mcleman)
+ Removed eisa xfer routines, since this is done in JXHWSUP
+
+ 02-Jul-92 Jeff McLeman (mcleman)
+ Removed alphadma.h header file. This file was not needed since
+ the DMA structure is described in the eisa header. Also add
+ a note describing eisa references in this module.
+
+ 13-May-92 Stole file jxebsup.c and converted for Alpha/Jensen
+
+
+--*/
+
+
+#include "halp.h"
+#include "eisa.h"
+
+//
+// Define the context structure for use by the interrupt routine.
+//
+
+typedef BOOLEAN (*PSECONDARY_DISPATCH)(
+ PVOID InterruptRoutine,
+ PKTRAP_FRAME TrapFrame
+ );
+
+//
+// Declare the interupt structure and spinlock for the intermediate EISA
+// interrupt dispachter.
+//
+
+KINTERRUPT HalpEisaInterrupt;
+
+/* [jrm 3/8/93] Add support for NMI interrupts */
+
+//
+// The following is the interrupt object used for DMA controller interrupts.
+// DMA controller interrupts occur when a memory parity error occurs or a
+// programming error occurs to the DMA controller.
+//
+
+KINTERRUPT HalpEisaNmiInterrupt;
+
+UCHAR EisaNMIMsg[] = "NMI: Eisa IOCHKERR board x\n";
+
+//
+// The following function is called when an EISA NMI occurs.
+//
+
+BOOLEAN
+HalHandleNMI(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ );
+
+//
+// Define save area for EISA interrupt mask registers and level\edge control
+// registers.
+//
+
+UCHAR HalpEisaInterrupt1Mask;
+UCHAR HalpEisaInterrupt2Mask;
+UCHAR HalpEisaInterrupt1Level;
+UCHAR HalpEisaInterrupt2Level;
+
+
+BOOLEAN
+HalpInitializeEisaInterrupts (
+//HalpCreateEisaStructures (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the structures necessary for EISA operations
+ and connects the intermediate interrupt dispatcher. It also initializes the
+ EISA interrupt controller.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the second level interrupt dispatcher is connected, then a value of
+ TRUE is returned. Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+
+ UCHAR DataByte;
+ KIRQL oldIrql;
+
+ //
+ // Initialize the EISA NMI interrupt.
+ //
+
+ KeInitializeInterrupt( &HalpEisaNmiInterrupt,
+ HalHandleNMI,
+ NULL,
+ NULL,
+ EISA_NMI_VECTOR,
+ EISA_NMI_LEVEL,
+ EISA_NMI_LEVEL,
+ LevelSensitive,
+ FALSE,
+ 0,
+ FALSE
+ );
+
+ //
+ // Don't fail if the interrupt cannot be connected.
+ //
+
+ KeConnectInterrupt( &HalpEisaNmiInterrupt );
+
+ //
+ // Clear the Eisa NMI disable bit. This bit is the high order of the
+ // NMI enable register.
+ //
+
+ DataByte = 0;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->NmiEnable,
+ DataByte
+ );
+
+ //
+ // Enable Software-Generated NMI interrupts by setting bit 1 of port 0x461.
+ //
+
+ DataByte = 0x02;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl,
+ DataByte
+ );
+
+ //
+ // Initialize the EISA interrupt dispatcher for EISA I/O interrupts.
+ //
+
+ KeInitializeInterrupt( &HalpEisaInterrupt,
+ HalpEisaInterruptHandler,
+ (PVOID) HalpEisaIntAckBase,
+ (PKSPIN_LOCK)NULL,
+ PIC_VECTOR,
+ EISA_DEVICE_LEVEL,
+ EISA_DEVICE_LEVEL,
+ LevelSensitive,
+ TRUE,
+ 0,
+ FALSE
+ );
+
+ if (!KeConnectInterrupt( &HalpEisaInterrupt )) {
+
+ return(FALSE);
+ }
+
+ //
+ // Raise the IRQL while the EISA interrupt controller is initalized.
+ //
+
+ KeRaiseIrql(EISA_DEVICE_LEVEL, &oldIrql);
+
+
+ //
+ // 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_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ DataByte
+ );
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ DataByte
+ );
+
+ //
+ // The second intitialization control word sets the iterrupt vector to
+ // 0-15.
+ //
+
+ DataByte = 0;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ DataByte = 0x08;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->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_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ DataByte = SLAVE_IRQL_LEVEL;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->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_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ DataByte
+ );
+
+
+ //
+ // Disable all of the interrupts except the slave.
+ //
+
+ HalpEisaInterrupt1Mask = ~(1 << SLAVE_IRQL_LEVEL);
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpEisaInterrupt1Mask
+ );
+
+ HalpEisaInterrupt2Mask = 0xFF;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ HalpEisaInterrupt2Mask
+ );
+
+ //
+ // Initialize the edge/level register masks to 0 which is the default
+ // edge sensitive value.
+ //
+
+ HalpEisaInterrupt1Level = 0;
+ HalpEisaInterrupt2Level = 0;
+
+ //
+ // Restore IRQL level.
+ //
+
+ KeLowerIrql(oldIrql);
+
+ //
+ // Initialize the DMA mode registers to a default value.
+ // Disable all of the DMA channels except channel 4 which is the
+ // cascade of channels 0-3.
+ //
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Dma1BasePort.AllMask,
+ 0x0F
+ );
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort.AllMask,
+ 0x0E
+ );
+
+ return(TRUE);
+}
+
+BOOLEAN
+HalpEisaDispatch(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext,
+ IN PKTRAP_FRAME TrapFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is entered as the result of an interrupt being generated
+ via the vector that is connected to an interrupt object that describes
+ the EISA device interrupts. Its function is to call the second
+ level interrupt dispatch routine and acknowledge the interrupt at the EISA
+ controller.
+
+ This service routine should be connected as follows:
+
+ KeInitializeInterrupt(&Interrupt, HalpEisaDispatch,
+ EISA_VIRTUAL_BASE,
+ (PKSPIN_LOCK)NULL, EISA_LEVEL, EISA_LEVEL, EISA_LEVEL,
+ LevelSensitive, TRUE, 0, FALSE);
+ KeConnectInterrupt(&Interrupt);
+
+Arguments:
+
+ Interrupt - Supplies a pointer to the interrupt object.
+
+ ServiceContext - Supplies a pointer to the EISA interrupt acknowledge
+ register.
+
+ TrapFrame - Supplies a pointer to the trap frame for this interrupt.
+
+Return Value:
+
+ Returns the value returned from the second level routine.
+
+--*/
+
+{
+ UCHAR interruptVector;
+ PKPRCB Prcb;
+ BOOLEAN returnValue;
+ USHORT PCRInOffset;
+ UCHAR Int1Isr;
+ UCHAR Int2Isr;
+
+ //
+ // Acknowledge the Interrupt controller and receive the returned
+ // interrupt vector.
+ //
+
+ interruptVector = HalpAcknowledgeEisaInterrupt(ServiceContext);
+
+
+ if ((interruptVector & 0x07) == 0x07) {
+
+ //
+ // Check for a passive release by looking at the inservice register.
+ // If there is a real IRQL7 interrupt, just go along normally. If there
+ // is not, then it is a passive release. So just dismiss it.
+ //
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ 0x0B
+ );
+
+ Int1Isr = READ_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0);
+
+ //
+ // do second controller
+ //
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ 0x0B
+ );
+
+ Int2Isr = READ_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0);
+
+
+ if (!(Int2Isr & 0x80) && !(Int1Isr & 0x80)) {
+
+ //
+ // Clear the master controller to clear situation
+ //
+
+ if (!(Int2Isr & 0x80)) {
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ }
+
+ return;
+
+ }
+
+
+ }
+
+ //
+ // Dispatch to the secondary interrupt service routine.
+ //
+ PCRInOffset = interruptVector + EISA_VECTORS;
+
+
+ returnValue = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[PCRInOffset])(
+ PCR->InterruptRoutine[PCRInOffset],
+ TrapFrame
+ );
+
+ //
+ // Dismiss the interrupt in the EISA interrupt controllers.
+ //
+
+ //
+ // If this is a cascaded interrupt then the interrupt must be dismissed in
+ // both controlles.
+ //
+
+ if (interruptVector & 0x08) {
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ }
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ return(returnValue);
+
+}
+
+VOID
+HalpDisableEisaInterrupt(
+ IN ULONG Vector
+ )
+
+/*++
+
+Routine Description:
+
+ This function Disables the EISA bus specified EISA bus interrupt.
+
+Arguments:
+
+ Vector - Supplies the vector of the ESIA interrupt that is Disabled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Calculate the EISA interrupt vector.
+ //
+
+ Vector -= EISA_VECTORS;
+
+ //
+ // Determine if this vector is for interrupt controller 1 or 2.
+ //
+
+ if (Vector & 0x08) {
+
+ //
+ // The interrupt is in controller 2.
+ //
+
+ Vector &= 0x7;
+
+ HalpEisaInterrupt2Mask |= (UCHAR) 1 << Vector;
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ HalpEisaInterrupt2Mask
+ );
+
+ } else {
+
+ //
+ // The interrupt is in controller 1.
+ //
+
+ Vector &= 0x7;
+
+ //
+ // never disable IRQL2, it is the slave interrupt
+ //
+
+ if (Vector != SLAVE_IRQL_LEVEL) {
+ HalpEisaInterrupt1Mask |= (ULONG) 1 << Vector;
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpEisaInterrupt1Mask
+ );
+ }
+
+ }
+
+}
+
+VOID
+HalpEnableEisaInterrupt(
+ IN ULONG Vector,
+ IN KINTERRUPT_MODE InterruptMode
+ )
+
+/*++
+
+Routine Description:
+
+ This function enables the EISA bus specified EISA bus interrupt and sets
+ the level/edge register to the requested value.
+
+Arguments:
+
+ Vector - Supplies the vector of the ESIA interrupt that is enabled.
+
+ InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
+ Latched.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Calculate the EISA interrupt vector.
+ //
+
+ Vector -= EISA_VECTORS;
+
+ //
+ // Determine if this vector is for interrupt controller 1 or 2.
+ //
+
+ if (Vector & 0x08) {
+
+ //
+ // The interrupt is in controller 2.
+ //
+
+ Vector &= 0x7;
+
+ HalpEisaInterrupt2Mask &= (UCHAR) ~(1 << Vector);
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ HalpEisaInterrupt2Mask
+ );
+
+ //
+ // Set the level/edge control register.
+ //
+
+ if (InterruptMode == LevelSensitive) {
+
+ HalpEisaInterrupt2Level |= (UCHAR) (1 << Vector);
+
+ } else {
+
+ HalpEisaInterrupt2Level &= (UCHAR) ~(1 << Vector);
+
+ }
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2EdgeLevel,
+ HalpEisaInterrupt2Level
+ );
+
+ } else {
+
+ //
+ // The interrupt is in controller 1.
+ //
+
+ Vector &= 0x7;
+
+ HalpEisaInterrupt1Mask &= (UCHAR) ~(1 << Vector);
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpEisaInterrupt1Mask
+ );
+
+ //
+ // Set the level/edge control register.
+ //
+
+ if (InterruptMode == LevelSensitive) {
+
+ HalpEisaInterrupt1Level |= (UCHAR) (1 << Vector);
+
+ } else {
+
+ HalpEisaInterrupt1Level &= (UCHAR) ~(1 << Vector);
+
+ }
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1EdgeLevel,
+ HalpEisaInterrupt1Level
+ );
+ }
+
+}
+
+BOOLEAN
+HalHandleNMI(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ )
+/*++
+
+Routine Description:
+
+ This function is called when an EISA NMI occurs. It print the appropriate
+ status information and bugchecks.
+
+Arguments:
+
+ Interrupt - Supplies a pointer to the interrupt object
+
+ ServiceContext - Bug number to call bugcheck with.
+
+Return Value:
+
+ Returns TRUE.
+
+--*/
+{
+ UCHAR StatusByte;
+ UCHAR EisaPort;
+ ULONG port;
+ ULONG AddressSpace = 1; // 1 = I/O address space
+ BOOLEAN Status;
+ PHYSICAL_ADDRESS BusAddress;
+ PHYSICAL_ADDRESS TranslatedAddress;
+
+ StatusByte =
+ READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->NmiStatus);
+
+ if (StatusByte & 0x80) {
+ HalDisplayString ("NMI: Parity Check / Parity Error\n");
+ }
+
+ if (StatusByte & 0x40) {
+ HalDisplayString ("NMI: Channel Check / IOCHK\n");
+ }
+
+ //
+ // This is an Eisa machine, check for extnded nmi information...
+ //
+
+ StatusByte = READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl);
+
+ if (StatusByte & 0x80) {
+ HalDisplayString ("NMI: Fail-safe timer\n");
+ }
+
+ if (StatusByte & 0x40) {
+ HalDisplayString ("NMI: Bus Timeout\n");
+ }
+
+ if (StatusByte & 0x20) {
+ HalDisplayString ("NMI: Software NMI generated\n");
+ }
+
+ //
+ // Look for any Eisa expansion board. See if it asserted NMI.
+ //
+
+ BusAddress.HighPart = 0;
+
+ for (EisaPort = 0; EisaPort <= 0xf; EisaPort++)
+ {
+ BusAddress.LowPart = (EisaPort << 12) + 0xC80;
+
+ Status = HalTranslateBusAddress(Eisa, // InterfaceType
+ 0, // BusNumber
+ BusAddress,
+ &AddressSpace, // 1=I/O address space
+ &TranslatedAddress); // QVA
+ if (Status == FALSE)
+ {
+ UCHAR pbuf[80];
+ sprintf(pbuf,
+ "Unable to translate bus address %x for EISA slot %d\n",
+ BusAddress.LowPart, EisaPort);
+ HalDisplayString(pbuf);
+ KeBugCheck(NMI_HARDWARE_FAILURE);
+ }
+
+ port = TranslatedAddress.LowPart;
+
+ WRITE_PORT_UCHAR ((PUCHAR) port, 0xff);
+ StatusByte = READ_PORT_UCHAR ((PUCHAR) port);
+
+ if ((StatusByte & 0x80) == 0) {
+ //
+ // Found valid Eisa board, Check to see if it's
+ // if IOCHKERR is asserted.
+ //
+
+ StatusByte = READ_PORT_UCHAR ((PUCHAR) port+4);
+ if (StatusByte & 0x2) {
+ EisaNMIMsg[25] = (EisaPort > 9 ? 'A'-10 : '0') + EisaPort;
+ HalDisplayString (EisaNMIMsg);
+ }
+ }
+ }
+
+#if 0
+ // Reset NMI interrupts (for debugging purposes only).
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, 0x00);
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->ExtendedNmiResetControl, 0x02);
+#endif
+
+ KeBugCheck(NMI_HARDWARE_FAILURE);
+ return(TRUE);
+}
diff --git a/private/ntos/nthals/halalpha/bios.c b/private/ntos/nthals/halalpha/bios.c
new file mode 100644
index 000000000..52b5dc898
--- /dev/null
+++ b/private/ntos/nthals/halalpha/bios.c
@@ -0,0 +1,105 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ bios.c
+
+Abstract:
+
+ This module implements ROM BIOS call support for Alpha AXP NT.
+
+Author:
+
+ Eric Rehm (rehm@zso.dec.com) 9-December-1993
+
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "arccodes.h"
+#include "alpharef.h"
+#include "fwcallbk.h"
+
+
+//
+// Static data.
+//
+// none.
+
+
+BOOLEAN
+HalCallBios (
+ IN ULONG BiosCommand,
+ IN OUT PULONG pEax,
+ IN OUT PULONG pEbx,
+ IN OUT PULONG pEcx,
+ IN OUT PULONG pEdx,
+ IN OUT PULONG pEsi,
+ IN OUT PULONG pEdi,
+ IN OUT PULONG pEbp
+ )
+
+/*++
+
+Routine Description:
+
+ This function invokes specified ROM BIOS code by executing
+ "INT BiosCommand." A callback to the i386 emulator loaded by
+ the firmware accomplishes this task. This function always
+ returns success reguardless of the result of the BIOS call.
+
+
+Arguments:
+
+ BiosCommand - specifies which ROM BIOS function to invoke.
+
+ BiosArguments - specifies a pointer to the context which will be used
+ to invoke ROM BIOS.
+
+Return Value:
+
+ TRUE if function succees, FALSE otherwise.
+
+--*/
+{
+
+ X86_BIOS_ARGUMENTS context;
+
+ context.Edi = *pEdi;
+ context.Esi = *pEsi;
+ context.Eax = *pEax;
+ context.Ebx = *pEbx;
+ context.Ecx = *pEcx;
+ context.Edx = *pEdx;
+ context.Ebp = *pEbp;
+
+ //
+ // Now call the firmware to actually perform the int 10 operation.
+ //
+
+ VenCallBios(BiosCommand, &context);
+
+ //
+ // fill in struct with any return values from the context
+ //
+
+ *pEdi = context.Edi;
+ *pEsi = context.Esi;
+ *pEax = context.Eax;
+ *pEbx = context.Ebx;
+ *pEcx = context.Ecx;
+ *pEdx = context.Edx;
+ *pEbp = context.Ebp;
+
+
+ //
+ // Indicate success
+ //
+
+ return TRUE;
+}
+
diff --git a/private/ntos/nthals/halalpha/cache.c b/private/ntos/nthals/halalpha/cache.c
new file mode 100644
index 000000000..c9d997f70
--- /dev/null
+++ b/private/ntos/nthals/halalpha/cache.c
@@ -0,0 +1,225 @@
+/*++
+
+Copyright (c) 1996 Digital Equipment Corporation
+
+Module Name:
+
+ cache.c
+
+Abstract:
+
+ Provides routine to compute the backup cache size
+
+Author:
+
+ Bala Nagarajan 5-Jan-1996
+ Adopted from Mark Baxter's user level code.
+
+Environment:
+
+ Phase 0 initialization only
+ Also Called from the firmware.
+
+--*/
+
+#include "halp.h"
+
+
+
+#define __1KB (1024)
+#define __128KB (128 * 1024)
+
+#define THRESHOLD_RPCC_PERCENT 120 // percent value
+
+static
+ULONG
+HalpTimeTheBufferAccess(
+ PUCHAR DataBuffer,
+ ULONG NumberOfAccess,
+ ULONG CacheSizeLimit,
+ ULONG CacheStride
+ )
+/*++
+
+Routine Description :
+
+ This function times the main loop that the HalpGetBCacheSize uses.
+ This is a separate function because we want to time the
+ access accurately with exactly one load in the loop.
+
+Arguments:
+
+ DataBuffer - Start address of the buffer.
+
+ NumberOfAccess - Total Nubmer of Access that needs to be made
+
+ CacheSizeLimit - The Current Cache size that is being checked
+
+ CacheStride - The stride value to access the buffer.
+
+Return Value:
+
+ The time taken to access the buffer with specified number of access.
+
+--*/
+{
+ ULONG MemoryLocation;
+ ULONG CacheSizeMask;
+ ULONG startRpcc;
+ ULONG endRpcc;
+
+ for(MemoryLocation = 0; MemoryLocation < CacheSizeLimit ;
+ MemoryLocation += CacheStride){
+ *(volatile ULONG * const)(&DataBuffer[MemoryLocation]) ;
+ }
+
+ CacheSizeMask = CacheSizeLimit - 1;
+
+ startRpcc = __RCC();
+ for ( MemoryLocation = 0;
+ NumberOfAccess > 0;
+ NumberOfAccess--, MemoryLocation += CacheStride) {
+ *(volatile LONG *)&(DataBuffer[MemoryLocation & CacheSizeMask] );
+ }
+ endRpcc = __RCC();
+
+ return (endRpcc - startRpcc);
+
+}
+
+
+ULONG
+HalpGetBCacheSize(
+ ULONGLONG ContiguousPhysicalMemorySize
+ )
+/*++
+
+Routine Description:
+
+ This function computes the size of the direct mapped backup cache.
+
+ This code checks for cache sizes from 128KB to the physical memory
+ size in steps of multiple of 2. In systems that has no cache or cache
+ larger than physical memory (!!) this algorithm will report the cache
+ size to be Zero. Since the cache size
+ is now being used only for the Secondary Page Coloring mechanism, and
+ since page coloring mechanism does not make any sense in a machine
+ without a direct mapped backup cache, the size of the cache does not
+ really affect system performance in any way.
+ [Note: Page Coloring Mechanism is used to reduce cache conflicts
+ between adjacent pages of a process in a direct mapped backup cache.]
+ In case where the cache is larger than memory itself (!!!! How often
+ have you encountered such a machine??), I think the entire page
+ coloring mechanism can break. Because you now have more colors
+ than total number of pages, meaning, there are some colors which
+ has no pages.
+
+Arguments:
+
+ ContiguousPhysicalMemorySize - The size of the physical memory.
+
+Return Value:
+
+ The size of the Backup cache in Bytes.
+
+--*/
+{
+ ULONG CacheSizeLimit = 128*__1KB;
+ ULONG NumberOfAccess;
+ ULONG CacheStride = 32*__1KB ;
+ ULONG CacheSize;
+ ULONG BaseLineElapsedRpcc;
+ ULONG ThresholdRpcc;
+ ULONG CurSizeElapsedRpcc;
+ PUCHAR DataBuffer;
+
+
+ //
+ // Set DataBuffer to point to KSEG0
+ //
+ DataBuffer = (PUCHAR) KSEG0_BASE;
+
+ //
+ // Compute the number of access we will make for each buffer
+ // size. Assume that for the largest buffer size we will make
+ // only one pass.
+ // NOTE: hopefully the division will limit the number of access to
+ // within a ULONG.
+ //
+
+ NumberOfAccess = (ULONG)(ContiguousPhysicalMemorySize/CacheStride);
+
+#if DBG
+ DbgPrint("HalpGetBCacheSize: Memory Size = %lu Bytes, "
+ "Number of Access = %lu\n",
+ ContiguousPhysicalMemorySize, NumberOfAccess);
+#endif
+ //
+ // Compute the baseline Rpcc.
+ // We touch only every cachestride(32KB) memory locations.
+ // We do this because we want to make sure that the entire set
+ // of the 3-way set associative on chip 96KB secondary cache gets
+ // filled in. This also means that we need to make the lower limit
+ // on the Bcache to be something greater than the OnChip
+ // secondary cache.
+ // First we touch all the locations to bring them into the
+ // cache before computing the baseline
+ //
+
+ BaseLineElapsedRpcc = HalpTimeTheBufferAccess(DataBuffer,
+ NumberOfAccess,
+ CacheSizeLimit, CacheStride);
+
+ //
+ // Compute the threshold Rpcc to equal to 120% of the baseline
+ // Rpcc
+ //
+ ThresholdRpcc = (BaseLineElapsedRpcc * THRESHOLD_RPCC_PERCENT) / 100;
+
+ while(CacheSizeLimit <= ContiguousPhysicalMemorySize){
+
+ CurSizeElapsedRpcc = HalpTimeTheBufferAccess(DataBuffer, NumberOfAccess,
+ CacheSizeLimit, CacheStride);
+
+#if DBG
+ DbgPrint("HalpGetBCacheSize: Size = %3ld%s"
+ " ElapsedRpcc = %7lu Threshold = %7lu\n",
+ (( CacheSizeLimit < __1MB) ?
+ ( CacheSizeLimit/__1KB) :
+ ( CacheSizeLimit /__1MB) ),
+ (( CacheSizeLimit < __1MB) ?
+ "KB" : "MB" ),
+ CurSizeElapsedRpcc,
+ ThresholdRpcc
+ );
+#endif
+
+ //
+ // if the current elapsed Rpcc is greater than threshold rpcc
+ //
+ if(CurSizeElapsedRpcc > ThresholdRpcc ){
+ break;
+ }
+ CacheSize = CacheSizeLimit;
+
+ CacheSizeLimit *= 2;
+ }
+
+ //
+ // In the following case the chance that this is a cacheless machine
+ // is very high, so we will return CacheSize to be Zero.
+ //
+ if(CacheSizeLimit >= ContiguousPhysicalMemorySize)
+ CacheSize = 0;
+
+#if DBG
+ DbgPrint("HalpGetBCacheSize: Cache Size = %lu Bytes\n",
+ CacheSize);
+#endif
+
+ //
+ // return cache size in number of bytes.
+ //
+ return (CacheSize);
+}
+
diff --git a/private/ntos/nthals/halalpha/cia.c b/private/ntos/nthals/halalpha/cia.c
new file mode 100644
index 000000000..cfdc6ce52
--- /dev/null
+++ b/private/ntos/nthals/halalpha/cia.c
@@ -0,0 +1,769 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ cia.c
+
+Abstract:
+
+ This module implements functions that are specific to the CIA ASIC.
+ The CIA ASIC is a control ASIC for cache, memory, and PCI on EV5-based
+ systems.
+
+Author:
+
+ Joe Notarangelo 26-Jul-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#include "cia.h"
+
+BOOLEAN CiaInitialized = FALSE;
+
+//
+// The revision of the CIA. Software visible differences exist between
+// passes of the CIA. The revision is determined once at the start of
+// run-time and used in places where the software must diverge.
+//
+
+ULONG HalpCiaRevision = CIA_REVISION_1;
+
+
+VOID
+HalpInitializeCia(
+ PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+/*++
+
+Routine Description:
+
+ Initialize the CIA.
+
+Arguments:
+
+ LoaderBlock - Supplies a pointer to the loader parameter block.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CIA_CONFIG CiaConfig;
+ CIA_CONTROL CiaControl;
+ CIA_ERR CiaError;
+ CIA_WBASE Wbase;
+ CIA_TBASE Tbase;
+ CIA_WMASK Wmask;
+ CIA_TBIA Tbia;
+
+ //
+ // Read the CIA revision.
+ //
+ // N.B. The revision must be read assuming pass 1 CIA.
+ //
+ // N.B. The revision must be determined before reading PCI configuration.
+ //
+
+ HalpCiaRevision =
+ READ_CIA_REGISTER(
+ &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaRevision );
+
+#if HALDBG
+
+ DbgPrint( "Cia Revision = 0x%x\n", HalpCiaRevision );
+
+#endif //HALDBG
+
+ //
+ // Initialize CIA Control.
+ //
+
+ CiaControl.all =
+ READ_CIA_REGISTER(
+ &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl );
+
+ //
+ // Set CIA to optimal setting according to Paul Lemmon.
+ //
+
+ CiaControl.PciEn = 1;
+ CiaControl.PciLockEn = 0;
+ CiaControl.PciLoopEn = 1;
+ CiaControl.FstBbEn = 0;
+ CiaControl.PciMstEn = 1;
+ CiaControl.PciMemEn = 1;
+
+ //
+ // Specifically disable PCI parity checking so firmware would work.
+ // Parity can be re-enabled later by the HAL for the OS.
+ //
+
+ CiaControl.AddrPeEn = 0;
+ CiaControl.PerrEn = 0;
+
+ CiaControl.FillErrEn = 1;
+ CiaControl.MchkErrEn = 1;
+ CiaControl.EccChkEn = 1;
+ CiaControl.AssertIdleBc = 0;
+ CiaControl.ConIdleBc = 1;
+ CiaControl.CsrIoaBypass = 0;
+ CiaControl.IoFlushReqEn = 0;
+ CiaControl.CpuFlushReqEn = 0;
+ CiaControl.ArbEv5En = 0;
+
+ //
+ // Old revisions of CIA should have ArbLink off since it doesn't work.
+ //
+
+ if (HalpCiaRevision < CIA_REVISION_3) {
+
+ CiaControl.EnArbLink = 0;
+ } else {
+
+ CiaControl.EnArbLink = 1;
+ }
+
+ CiaControl.RdType = 0;
+ CiaControl.RlType = 1;
+ CiaControl.RmType = 2;
+ CiaControl.EnDmaRdPerf = 0;
+
+ WRITE_CIA_REGISTER( &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl,
+ CiaControl.all );
+
+ //
+ // Initialize CIA Config. Turn on the performance enhancement features of
+ // CIA2. No-op for rev 1 CIA.
+ //
+
+ CiaConfig.all =
+ READ_CIA_REGISTER(
+ &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCnfg );
+
+ CiaConfig.IoaBwen = 0;
+ CiaConfig.PciDwen = 1;
+
+ WRITE_CIA_REGISTER( &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCnfg,
+ CiaConfig.all );
+
+ //
+ // Disable all of the scatter/gather windows.
+ //
+
+ Wbase.all = 0;
+ Wbase.Wen = 0;
+
+ WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase0,
+ Wbase.all );
+
+ WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase1,
+ Wbase.all );
+
+ WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase2,
+ Wbase.all );
+
+ WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase3,
+ Wbase.all );
+
+ //
+ // Invalidate all of the TLB Entries:
+ //
+
+ Tbia.all = 0;
+ Tbia.InvalidateType = InvalidateAll;
+
+ //
+ // Perform the invalidation.
+ //
+
+ WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbia,
+ Tbia.all );
+
+ //
+ // Clear any pending error bits in the CIA_ERR register:
+ //
+
+ CiaError.all = 0; // Clear all bits
+
+ CiaError.CorErr = 1; // Correctable error
+ CiaError.UnCorErr = 1; // Uncorrectable error
+ CiaError.CpuPe = 1; // Ev5 bus parity error
+ CiaError.MemNem = 1; // Nonexistent memory error
+ CiaError.PciSerr = 1; // PCI bus serr detected
+ CiaError.PciPerr = 1; // PCI bus perr detected
+ CiaError.PciAddrPe = 1; // PCI bus address parity error
+ CiaError.RcvdMasAbt = 1; // Pci Master Abort
+ CiaError.RcvdTarAbt = 1; // Pci Target Abort
+ CiaError.PaPteInv = 1; // Invalid Pte
+ CiaError.FromWrtErr = 1; // Invalid write to flash rom
+ CiaError.IoaTimeout = 1; // Io Timeout occurred
+ CiaError.LostCorErr = 1; // Lost correctable error
+ CiaError.LostUnCorErr = 1; // Lost uncorrectable error
+ CiaError.LostCpuPe = 1; // Lost Ev5 bus parity error
+ CiaError.LostMemNem = 1; // Lost Nonexistent memory error
+ CiaError.LostPciPerr = 1; // Lost PCI bus perr detected
+ CiaError.LostPciAddrPe = 1; // Lost PCI bus address parity error
+ CiaError.LostRcvdMasAbt = 1; // Lost Pci Master Abort
+ CiaError.LostRcvdTarAbt = 1; // Lost Pci Target Abort
+ CiaError.LostPaPteInv = 1; // Lost Invalid Pte
+ CiaError.LostFromWrtErr = 1; // Lost Invalid write to flash rom
+ CiaError.LostIoaTimeout = 1; // Lost Io Timeout occurred
+ CiaError.ErrValid = 1; // Self explanatory
+
+ WRITE_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr,
+ CiaError.all
+ );
+
+
+#if defined(CIA_PASS1)
+
+ {
+
+ ULONG Allocated;
+ PTRANSLATION_ENTRY MapRegister;
+ ULONG MaxPhysicalAddress;
+ ULONG NumberOfPages;
+ BOOLEAN __64KAlignment;
+ ULONG i;
+
+
+ //
+ // Create a special scatter/gather window to use for diagnostic
+ // DMAs that we can use to insure that the TLB is flushed of any
+ // other entries.
+ //
+
+ //
+ // Allocate a page of memory to hold the scatter/gather entries.
+ //
+
+ Allocated = HalpAllocPhysicalMemory( LoaderBlock,
+ MaxPhysicalAddress = __1GB - 1,
+ NumberOfPages = 1,
+ __64KAlignment = TRUE ); // FALSE );
+
+ //
+ // Make the first 32 entries in the new table valid, point them
+ // to the first 32 pages in memory.
+ //
+
+ MapRegister = (PTRANSLATION_ENTRY)(Allocated | KSEG0_BASE);
+
+ for( i=0; i < 32; i++ ){
+
+ ULONG Pfn = 0x700000 >> PAGE_SHIFT;
+
+ HAL_MAKE_VALID_TRANSLATION( MapRegister, Pfn );
+ MapRegister += 1;
+
+ Pfn += 1;
+
+ }
+
+ //
+ // Enable window 3 for the diagnostic dmas to the special scatter/gather
+ // table. Base of the window in PCI space is 32MB, size of the window
+ // is 1MB.
+ //
+
+ Wbase.all = 0;
+ Wbase.Wen = 1;
+ Wbase.SgEn = 1;
+ Wbase.Wbase = (ULONG)(__1MB * 32) >> 20;
+
+ Wmask.all = 0;
+ Wmask.Wmask = 0;
+
+ Tbase.all = 0;
+ Tbase.Tbase = (ULONG)(Allocated) >> 10;
+
+ WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbase3,
+ Tbase.all );
+
+ WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wmask3,
+ Wmask.all );
+
+ WRITE_CIA_REGISTER( &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase3,
+ Wbase.all );
+
+ }
+
+
+#endif //CIA_PASS1
+
+ CiaInitialized = TRUE;
+
+}
+
+
+VOID
+HalpCiaInitializeSfwWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ CIA_WINDOW_NUMBER WindowNumber
+ )
+/*++
+
+Routine Description:
+
+ Initialize the DMA Control software window registers for the specified
+ DMA Window.
+
+Arguments:
+
+ WindowRegisters - Supplies a pointer to the software window control.
+
+ WindowNumber - Supplies the window number initialized. (0 = Isa Dma
+ Window, 1 = Master Dma Window).
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ switch( WindowNumber ){
+
+ //
+ // The ISA DMA Window.
+ //
+
+ case CiaIsaWindow:
+
+ WindowRegisters->WindowBase = (PVOID)ISA_DMA_WINDOW_BASE;
+ WindowRegisters->WindowSize = ISA_DMA_WINDOW_SIZE;
+ WindowRegisters->TranslatedBaseRegister =
+ &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbase1;
+ WindowRegisters->WindowBaseRegister =
+ &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase1;
+ WindowRegisters->WindowMaskRegister =
+ &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wmask1;
+ WindowRegisters->WindowTbiaRegister =
+ &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbia;
+
+ break;
+
+ case CiaMasterWindow:
+
+ WindowRegisters->WindowBase = (PVOID)MASTER_DMA_WINDOW_BASE;
+ WindowRegisters->WindowSize = MASTER_DMA_WINDOW_SIZE;
+ WindowRegisters->TranslatedBaseRegister =
+ &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbase0;
+ WindowRegisters->WindowBaseRegister =
+ &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase0;
+ WindowRegisters->WindowMaskRegister =
+ &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wmask0;
+ WindowRegisters->WindowTbiaRegister =
+ &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbia;
+
+ break;
+
+ default:
+
+#if HALDBG
+
+ DbgPrint( "CiaInitializeSfwWindow: Bad Window Number = %x\n",
+ WindowNumber );
+
+#endif //HALDBG
+
+ break;
+
+ }
+
+ return;
+}
+
+
+VOID
+HalpCiaProgramDmaWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ PVOID MapRegisterBase
+ )
+/*++
+
+Routine Description:
+
+ Program the control windows in the hardware so that DMA can be started
+ to the DMA window.
+
+Arguments:
+
+ WindowRegisters - Supplies a pointer to the software window register
+ control structure.
+
+ MapRegisterBase - Supplies the logical address of the scatter/gather
+ array in system memory.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CIA_WBASE Wbase;
+ CIA_TBASE Tbase;
+ CIA_WMASK Wmask;
+
+ //
+ // Program the windows as specified by the caller.
+ //
+
+ Wbase.all = 0;
+ Wbase.Wen = 1;
+ Wbase.SgEn = 1;
+ Wbase.Wbase = (ULONG)(WindowRegisters->WindowBase) >> 20;
+
+ Wmask.all = 0;
+ Wmask.Wmask = (WindowRegisters->WindowSize >> 20) - 1;
+
+ Tbase.all = 0;
+ Tbase.Tbase = (ULONG)MapRegisterBase >> 10;
+
+ //
+ // Dump the CIA registers.
+ //
+
+#if HALDBG
+
+ DumpCia( CiaScatterGatherRegisters );
+
+#endif //HALDBG
+
+ //
+ // Clear the window base, temporarily disabling transactions to this
+ // DMA window.
+ //
+
+ WRITE_CIA_REGISTER( WindowRegisters->WindowBaseRegister, 0 );
+
+ //
+ // Now program the window by writing the translated base, then the size
+ // of the window in the mask register and finally the window base,
+ // enabling both the window and scatter gather.
+ //
+
+ WRITE_CIA_REGISTER( WindowRegisters->TranslatedBaseRegister,
+ Tbase.all );
+
+ WRITE_CIA_REGISTER( WindowRegisters->WindowMaskRegister,
+ Wmask.all );
+
+ WRITE_CIA_REGISTER( WindowRegisters->WindowBaseRegister,
+ Wbase.all );
+
+ //
+ // Flush the volatile entries in the CIA's scatter/gather Tlb.
+ //
+
+ HalpCiaInvalidateTlb( WindowRegisters, InvalidateVolatile );
+
+ //
+ // Dump the CIA registers.
+ //
+
+#if HALDBG
+
+ DumpCia( CiaScatterGatherRegisters | CiaGeneralRegisters );
+
+#endif //HALDBG
+
+ return;
+}
+
+
+VOID
+HalpCiaInvalidateTlb(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ CIA_INVALIDATE_TYPE InvalidateType
+ )
+/*++
+
+Routine Description:
+
+ Invalidate the DMA Scatter/Gather TLB in the CIA. The TLB is invalidated
+ whenever the scatter/gather translation entries are modified.
+
+Arguments:
+
+ WindowRegisters - Supplies a pointer to the software window register
+ control structure.
+
+ InvalidateType - Supplies the type of invalidate the caller requires.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Perform the invalidation based on the pass of the CIA.
+ //
+
+ if( HalpCiaRevision == CIA_REVISION_1 ){
+
+ ULONG LoopbackAddress;
+ ULONG i;
+
+ //
+ // Perform 8 reads to PCI Dense space through the special loopback
+ // scatter/gather window to invalidate each entry in the CIA TLB.
+ // Each TLB fill prefetches 4 entries so our 8 reads must each be
+ // 32K bytes apart.
+ //
+
+ LoopbackAddress = __1MB * 32;
+
+ HalpMb();
+
+ for( i=0; i < 8; i++ ){
+
+ ULONG dummy;
+
+ dummy = READ_REGISTER_ULONG( (PULONG)LoopbackAddress );
+
+ LoopbackAddress += __1K * 32;
+
+ }
+
+ HalpMb();
+
+ } else {
+
+ CIA_TBIA Tbia;
+
+ //
+ // Set the invalidate as specified by the flush type.
+ //
+
+ Tbia.all = 0;
+ Tbia.InvalidateType = InvalidateType;
+
+ //
+ // Perform the invalidation.
+ //
+
+ WRITE_CIA_REGISTER( WindowRegisters->WindowTbiaRegister, Tbia.all );
+
+ } //end if( HalpCiaRevision == CIA_REVISION_1 )
+
+}
+
+
+#if HALDBG
+
+VOID
+DumpCia(
+ CIA_REGISTER_CLASS RegistersToDump
+ )
+/*++
+
+Routine Description:
+
+ Read the interesting Cia registers and print them to the debug port.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PVOID RegisterQva;
+ ULONG Value;
+
+ DbgPrint( "CIA Register Dump: \n" );
+
+ //
+ // Dump the CIA General Control registers.
+ //
+
+ if( (RegistersToDump & CiaGeneralRegisters) != 0 ){
+
+ RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaRevision;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "CiaRevision = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->PciLat;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "PciLat = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "CiaCtrl = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCnfg;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "CiaCnfg = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->HaeMem;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "HaeMem = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->HaeIo;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "HaeIo = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->ConfigType;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "ConfigType = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CackEn;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "CackEn = 0x%x\n", Value );
+
+ }
+
+ //
+ // Dump the CIA Error registers.
+ //
+
+ if( (RegistersToDump & CiaErrorRegisters) != 0 ){
+
+ RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CpuErr0;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "CpuErr0 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CpuErr1;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "CpuErr1 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "CiaErr = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaStat;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "CiaStat = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->ErrMask;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "ErrMask = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaSyn;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "CiaSyn = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->MemErr0;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "MemErr0 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->MemErr1;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "MemErr1 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr0;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "PciErr0 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr1;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "PciErr1 = 0x%x\n", Value );
+
+ }
+
+ //
+ // Dump the PCI Scatter/Gather registers.
+ //
+
+ if( (RegistersToDump & CiaScatterGatherRegisters) != 0 ){
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbia;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "Tbia = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase0;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "Wbase0 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wmask0;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "Wmask0 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbase0;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "Tbase0 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase1;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "Wbase1 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wmask1;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "Wmask1 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbase1;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "Tbase1 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase2;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "Wbase2 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wmask2;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "Wmask2 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbase2;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "Tbase2 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wbase3;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "Wbase3 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Wmask3;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "Wmask3 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Tbase3;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "Tbase3 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->Dac;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "Dac = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->LtbTag0;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "LtbTag0 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->LtbTag1;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "LtbTag1 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->LtbTag2;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "LtbTag2 = 0x%x\n", Value );
+
+ RegisterQva = &((PCIA_SG_CSRS)(CIA_SG_CSRS_QVA))->LtbTag3;
+ Value = READ_CIA_REGISTER( RegisterQva );
+ DbgPrint( "LtbTag3 = 0x%x\n", Value );
+ }
+
+
+ DbgPrint( "--end CIA Register dump\n\n" );
+
+ return;
+
+}
+
+#endif //HALDBG
+
diff --git a/private/ntos/nthals/halalpha/cia.h b/private/ntos/nthals/halalpha/cia.h
new file mode 100644
index 000000000..510b02c96
--- /dev/null
+++ b/private/ntos/nthals/halalpha/cia.h
@@ -0,0 +1,1141 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ cia.h
+
+Abstract:
+
+ This file defines the structures and definitions for the CIA ASIC.
+
+Author:
+
+ Steve Brooks 30-Jun-1994
+ Joe Notarangelo 30-Jun-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Chao Chen 31-Aug-1995 Add in new data structures for misc cia registers.
+
+--*/
+
+#ifndef _CIAH_
+#define _CIAH_
+
+
+//
+// CIA Revision definitions.
+//
+
+#define CIA_REVISION_1 (0)
+#define CIA_REVISION_2 (1)
+#define CIA_REVISION_3 (2)
+
+
+//
+// Define QVA constants.
+//
+
+#if !defined(QVA_ENABLE)
+
+#define QVA_ENABLE (0xA0000000) // Identify VA as a QVA
+
+#endif //QVA_ENABLE
+
+#define QVA_SELECTORS (0xE0000000) // QVA identification mask
+
+#define IO_BIT_SHIFT 0x05 // Bits to shift QVA
+
+#define IO_BYTE_OFFSET 0x20 // Offset to next byte
+#define IO_SHORT_OFFSET 0x40 // Offset to next short
+#define IO_LONG_OFFSET 0x80 // Offset to next long
+
+#define IO_BYTE_LEN 0x00 // Byte length
+#define IO_WORD_LEN 0x08 // Word length
+#define IO_TRIBYTE_LEN 0x10 // TriByte length
+#define IO_LONG_LEN 0x18 // Longword length
+
+//
+// Define size of I/O and memory space for the CIA.
+// Assume that the HAE==0.
+//
+
+#define PCI_MAX_IO_ADDRESS (__64MB - 1) // I/O: 0 - 64MB
+#define PCI_MAX_SPARSE_MEMORY_ADDRESS (__512MB - 1) // Mem: 0 - 512MB
+#define PCI_MIN_DENSE_MEMORY_ADDRESS PCI_MAX_SPARSE_MEMORY_ADDRESS + 1
+#define PCI_MAX_DENSE_MEMORY_ADDRESS (__2GB + __512MB - 1) // Dense: .5 - 2.5 Gb
+
+//
+// Defines for cia correctable errors.
+//
+
+#define CIA_IO_WRITE_ECC 0x2
+#define CIA_DMA_READ_ECC 0x6
+#define CIA_DMA_WRITE_ECC 0x7
+#define CIA_IO_READ_ECC 0xb
+#define CIA_PROCESSOR_CACHE_ECC 0x2
+#define CIA_SYSTEM_CACHE_ECC 0x3
+
+#if !defined(_LANGUAGE_ASSEMBLY)
+
+#define CIA_QVA_PHYSICAL_BASE ((ULONGLONG)0x8400000000)
+
+//
+// QVA
+// HAL_MAKE_QVA(
+// ULONGLONG PhysicalAddress
+// )
+//
+// Routine Description:
+//
+// This macro returns the Qva for a physical address in system space.
+//
+// Arguments:
+//
+// PhysicalAddress - Supplies a 64-bit physical address.
+//
+// Return Value:
+//
+// The Qva associated with the physical address.
+//
+
+#define HAL_MAKE_QVA(PA) \
+ ( (PVOID)( QVA_ENABLE | \
+ (ULONG)( (PA - CIA_QVA_PHYSICAL_BASE) >> IO_BIT_SHIFT) ) )
+
+
+//
+// Define physical address space for CIA.
+//
+
+#define CIA_PCI_SPARSE_MEMORY_PHYSICAL ((ULONGLONG)0x8400000000)
+#define CIA_PCI_SPARSE_IO_PHYSICAL ((ULONGLONG)0x8580000000)
+#define CIA_PCI_DENSE_MEMORY_PHYSICAL ((ULONGLONG)0x8600000000)
+#define CIA_PCI_CONFIGURATION_PHYSICAL ((ULONGLONG)0x8700000000)
+#define CIA_PCI_INTACK_PHYSICAL ((ULONGLONG)0x8720000000)
+#define CIA_MAIN_CSRS_PHYSICAL ((ULONGLONG)0x8740000000)
+
+#define CIA_PCI_CONFIG_BASE_QVA (HAL_MAKE_QVA(CIA_PCI_CONFIGURATION_PHYSICAL))
+#define CIA_PCI_SPARSE_IO_QVA (HAL_MAKE_QVA(CIA_PCI_SPARSE_IO_PHYSICAL))
+#define CIA_PCI_SPARSE_MEMORY_QVA (HAL_MAKE_QVA(CIA_PCI_SPARSE_MEMORY_PHYSICAL))
+#define CIA_PCI_INTACK_QVA (HAL_MAKE_QVA(CIA_PCI_INTACK_PHYSICAL))
+
+//
+// Define the classes of CIA registers.
+//
+
+typedef enum _CIA_REGISTER_CLASS{
+ CiaGeneralRegisters = 0x1,
+ CiaErrorRegisters = 0x2,
+ CiaScatterGatherRegisters = 0x4,
+ CiaAllRegisters = 0xffffffff
+} CIA_REGISTER_CLASS, *PCIA_REGISTER_CLASS;
+
+//
+// Define the structures to access the CIA general csrs.
+//
+
+#define CIA_GENERAL_CSRS_PHYSICAL ((ULONGLONG)0x8740000080)
+#define CIA_GENERAL_CSRS_QVA HAL_MAKE_QVA(CIA_GENERAL_CSRS_PHYSICAL)
+
+typedef struct _CIA_GENERAL_CSRS{
+ UCHAR CiaRevision; // (80) PCI Revision
+ UCHAR Filler1; // (a0)
+ UCHAR PciLat; // (c0) PCI Latency
+ UCHAR Filler2; // (e0)
+ UCHAR CiaCtrl; // (100) CIA control
+ UCHAR Filler3[1]; // (120)
+ UCHAR CiaCnfg; // (140) CIA config
+ UCHAR Filler4[21]; // (160 - 3e0)
+ UCHAR HaeMem; // (400) Host address extension, sparse memory
+ UCHAR Filler5; // (420)
+ UCHAR HaeIo; // (440) Host address extension, space i/o
+ UCHAR Filler6; // (460)
+ UCHAR ConfigType; // (480) Configuration register
+ UCHAR Filler7[11]; // (4a0 - 5e0)
+ UCHAR CackEn; // (600) CIA Acknowledgement
+} CIA_GENERAL_CSRS, *PCIA_GENERAL_CSRS;
+
+extern ULONG HalpCiaRevision; // global containing CIA revision id
+
+typedef union _CIA_REVISION{
+ struct{
+ ULONG CiaRev: 8; // CIA Revision Id
+ ULONG Reserved: 24; //
+ };
+ ULONG all;
+} CIA_REVISION, *PCIA_REVISION;
+
+typedef union _CIA_PCI_LAT{
+ struct{
+ ULONG Reserved0: 8; //
+ ULONG Latency: 8; // PCI Master Latency timer (in PCI clocks)
+ ULONG Reserved1: 16; //
+ };
+ ULONG all;
+} CIA_PCI_LAT, *PCIA_PCI_LAT;
+
+typedef union _CIA_CONTROL{
+ struct{
+ ULONG PciEn: 1; // PCI Reset Enable
+ ULONG PciLockEn: 1; // Enables PCI locking of CIA
+ ULONG PciLoopEn: 1; // Enables CIA as a target
+ ULONG FstBbEn: 1; // Enables fast back to back PCI
+ ULONG PciMstEn: 1; // Enables initiating PCI transactions
+ ULONG PciMemEn: 1; // Enables CIA response to PCI transactions
+ ULONG PciReq64: 1; // Enables initiating 64-bit PCI
+ ULONG PciAck64: 1; // Enables accepting 64-bit PCI transactions
+ ULONG AddrPeEn: 1; // Enables PCI address parity checking
+ ULONG PerrEn: 1; // Enables PCI data parity checking
+ ULONG FillErrEn: 1; // Enables fill error assertion
+ ULONG MchkErrEn: 1; // Enables machine check error assertion
+ ULONG EccChkEn: 1; // Enables ECC error checking
+ ULONG AssertIdleBc: 1; // ????
+ ULONG ConIdleBc: 1; // ????
+ ULONG CsrIoaBypass: 1; // Allow CIA to bypass I/O address queue
+ ULONG IoFlushReqEn: 1; // Enables CIA to accept flush requests
+ ULONG CpuFlushReqEn: 1; // Enables CIA to accept CPU flush requests
+ ULONG ArbEv5En: 1; // Enables EV5 bypass path to memory and io
+ ULONG EnArbLink: 1; // Enable CPU memory reads to link
+ ULONG RdType: 2; // Controls memory pre-fetch algorithm
+ ULONG Reserved1: 2; //
+ ULONG RlType: 2; // Controls memory line pre-fetch algorithm
+ ULONG Reserved2: 2; //
+ ULONG RmType: 2; // Controls memory multiple pre-fetch
+ ULONG Reserved3: 1; //
+ ULONG EnDmaRdPerf: 1; // ????
+ };
+ ULONG all;
+} CIA_CONTROL, *PCIA_CONTROL;
+
+
+typedef union _CIA_CONFIG{
+ struct{
+ ULONG IoaBwen: 1; // EV56 byte/word I/O access enable
+ ULONG Reserved0: 3;
+ ULONG PciMwen: 1; // PCI target monster window enable
+ ULONG PciDwen: 1; // 2nd PCI target DMA write buffer enable
+ ULONG Reserved1: 2;
+ ULONG PciWlen: 1; // CIA link consecutive writes into a
+ ULONG Reserved2: 23; // single PCI transaction.
+ };
+ ULONG all;
+} CIA_CONFIG, *PCIA_CONFIG;
+
+typedef union _CIA_HAE_MEM{
+ struct{
+ ULONG Reserved0: 2; //
+ ULONG Region3: 6; // sets HAE for region 3
+ ULONG Reserved1: 3; //
+ ULONG Region2: 5; // sets HAE for region 2
+ ULONG Reserved: 13; //
+ ULONG Region1: 3; // sets HAE for region 1
+ };
+ ULONG all;
+} CIA_HAE_MEM, *PCIA_HAE_MEM;
+
+typedef union _CIA_HAE_IO{
+ struct{
+ ULONG Reserved0: 25; //
+ ULONG HaeIo: 7; // sets HAE for i/o space
+ };
+ ULONG all;
+} CIA_HAE_IO, *PCIA_HAE_IO;
+
+typedef union _CIA_CONFIG_TYPE{
+ struct{
+ ULONG Cfg: 2; // PCI<10> config address
+ ULONG Reserved0: 30; //
+ };
+ ULONG all;
+} CIA_CONFIG_TYPE, *PCIA_CONFIG_TYPE;
+
+typedef union _CIA_CACK_EN{
+ struct{
+ ULONG CackEn: 4; // Controls CIA acks to EV5
+ ULONG Reserved0: 28; //
+ };
+ ULONG all;
+} CIA_CACK_EN, *PCIA_CACK_EN;
+
+
+//
+// Define the structures and definitions for the CIA diagnostic registers.
+//
+
+#define CIA_DIAG_CSRS_PHYSICAL ((ULONGLONG)0x8740002000)
+#define CIA_DIAG_CSRS_QVA HAL_MAKE_QVA(CIA_DIAG_CSRS_PHYSICAL)
+
+typedef struct _CIA_DIAG_CSRS{
+ UCHAR CiaDiag; // (2000) Diagnostic Control register
+ UCHAR Filler[127]; // (2020-2fe0)
+ UCHAR DiagCheck; // (3000) Diagnostic Check register
+
+} CIA_DIAG_CSRS, *PCIA_DIAG_CSRS;
+
+typedef union _CIA_DIAG {
+ struct{
+ ULONG FromWrtEn: 1; // Flash ROM write enable bit
+ ULONG UseCheck: 1; // use known ecc pattern for writes
+ ULONG Reserved0: 26; //
+ ULONG FpePci: 2; // Force bad parity to PCI bus (if != 0)
+ ULONG Reserved1: 1; //
+ ULONG FpeToEv5: 1; // Force bad parity to the EV5 bus
+ };
+ ULONG all;
+
+} CIA_DIAG, *PCIA_DIAG;
+
+typedef union _CIA_DIAG_CHECK {
+ struct{
+ ULONG DiagCheck: 8; // ECC pattern to use when UseCheck bit set
+ ULONG Reserved: 24;
+ };
+ ULONG all;
+
+} CIA_DIAG_CHECK, *PCIA_DIAG_CHECK;
+
+//
+// Define the structures and definitions for the CIA performance registers.
+//
+
+typedef union _CIA_PERF_MONITOR{
+ struct{
+ ULONG LowCount: 16; // Low Counter Value
+ ULONG HighCount: 16; // High Counter Value
+ };
+ ULONG all;
+} CIA_PERF_MONITOR, *PCIA_PERF_MONITOR;
+
+typedef union _CIA_PERF_CONTROL{
+ struct{
+ ULONG LowSelect: 8; // Low Counter - event to count
+ ULONG Reserved1: 5; //
+ ULONG LowCountClear: 1; // Clear low counter value
+ ULONG LowErrStop: 1; // Stop low counter
+ ULONG LowCountStart: 1; // Start low counter
+ ULONG HighSelect: 8; // High Counter - event to count
+ ULONG Reserved2: 5; //
+ ULONG HighCountClear: 1; // Clear high counter value
+ ULONG HighErrStop: 1; // Stop high counter
+ ULONG HighCountStart: 1; // Start high counter
+ };
+ ULONG all;
+} CIA_PERF_CONTROL, *PCIA_PERF_CONTROL;
+
+typedef enum _CIA_PERF_SELECTS{
+ CiaUseHigh32 = 0x00,
+ CiaClockCycles = 0x01,
+ CiaRefreshCycles = 0x02,
+ CiaEv5CmdAcks = 0x10,
+ CiaEv5Reads = 0x11,
+ CiaEv5ReadMiss = 0x12,
+ CiaEv5ReadMissModify = 0x13,
+ CiaEv5BcacheVictimAcks = 0x14,
+ CiaEv5LockAcks = 0x15,
+ CiaEv5MbAcks = 0x16,
+ CiaEv5Fetch = 0x17,
+ CiaEv5WriteBlocks = 0x18,
+ CiaEv5MemoryCmds = 0x20,
+ CiaEv5IoCmds = 0x21,
+ CiaEv5IoReadCmds = 0x22,
+ CiaEv5IoWriteCmds = 0x23,
+ CiaSystemCommands = 0x24,
+ CiaEv5SystemReads = 0x25,
+ CiaEv5SystemFlushes = 0x26,
+ CiaReceivedNoAck = 0x27,
+ CiaReceivedScacheAck = 0x28,
+ CiaReceivedBcacheAck = 0x29,
+ CiaDmaReadsTotal = 0x30,
+ CiaDmaReads = 0x31,
+ CiaDmaReadLines = 0x32,
+ CiaDmaReadMultiples = 0x33,
+ CiaDmaWritesTotal = 0x34,
+ CiaDmaWrites = 0x35,
+ CiaDmaWriteInvalidates = 0x36,
+ CiaDmaDualAddressCycles = 0x37,
+ CiaDmaCycleRetries = 0x38,
+ CiaIoCycleRetries = 0x39,
+ CiaPciLocks = 0x40,
+ CiaEv5LockAccesses = 0x41,
+ CiaDmaVictimHit = 0x42,
+ CiaRefillTlb = 0x50,
+ CiaSingleBitEccErrors = 0x60
+} CIA_PERF_SELECTORS, *PCIA_PERF_SELECTORS;
+
+
+//
+// Define the structures and definitions for the CIA error registers.
+//
+
+
+#define CIA_ERROR_CSRS_PHYSICAL ((ULONGLONG)0x8740008000)
+#define CIA_ERROR_CSRS_QVA HAL_MAKE_QVA(CIA_ERROR_CSRS_PHYSICAL)
+
+typedef struct _CIA_ERROR_CSRS{
+ UCHAR CpuErr0; // (8000) CPU errors
+ UCHAR Filler0; // (8020)
+ UCHAR CpuErr1; // (8040) CPU errors
+ UCHAR Filler1[13]; // (8060 - 81e0)
+ UCHAR CiaErr; // (8200) Cia errors
+ UCHAR Filler2; // (8020)
+ UCHAR CiaStat; // (8240) Cia error status
+ UCHAR Filler3; // (8060)
+ UCHAR ErrMask; // (8280) Masks off specified errors
+ UCHAR Filler4[3]; // (82a0 - 82e0)
+ UCHAR CiaSyn; // (8300) CIA error syndrome
+ UCHAR Filler5[7]; // (8320 - 83e0)
+ UCHAR MemErr0; // (8400) Memory errors
+ UCHAR Filler6; // (8420)
+ UCHAR MemErr1; // (8440) Memory errors
+ UCHAR Filler7[29]; // (8460 - 87e0)
+ UCHAR PciErr0; // (8800) PCI errors
+ UCHAR Filler8; // (8820)
+ UCHAR PciErr1; // (8840) PCI errors
+ UCHAR Filler9; // (8860)
+ UCHAR PciErr2; // (8880) PCI errors
+} CIA_ERROR_CSRS, *PCIA_ERROR_CSRS;
+
+typedef union _CIA_CPU_ERR0{
+ struct{
+ ULONG Reserved: 4; //
+ ULONG Addr: 28; // CPU addresss bus contents on EV5 error
+ };
+ ULONG all;
+} CIA_CPU_ERR0, *PCIA_CPU_ERR0;
+
+typedef union _CIA_CPU_ERR1{
+ struct{
+ ULONG Addr34_32: 3; // address bits 34-32
+ ULONG Reserved0: 4; //
+ ULONG Addr39: 1; // address bit 39
+ ULONG Cmd: 4; // Cpu address command bus value
+ ULONG Int4Valid: 4; // Contains Int4 valid bits from CPU bus
+ ULONG Reserved1: 5; //
+ ULONG AddrCmdPar: 1; // Contains CPU bus parity bit
+ ULONG Reserved2: 8; //
+ ULONG Fpe_2_Ev5: 1; // ????
+ ULONG CpuPe: 1; // Indicates CPU interface detected parity
+ };
+ ULONG all;
+} CIA_CPU_ERR1, *PCIA_CPU_ERR1;
+
+typedef union _CIA_ERR{
+ struct{
+ ULONG CorErr: 1; // Correctable error
+ ULONG UnCorErr: 1; // Uncorrectable error
+ ULONG CpuPe: 1; // Ev5 bus parity error
+ ULONG MemNem: 1; // Nonexistent memory error
+ ULONG PciSerr: 1; // PCI bus serr detected
+ ULONG PciPerr: 1; // PCI bus perr detected
+ ULONG PciAddrPe: 1; // PCI bus address parity error
+ ULONG RcvdMasAbt: 1; // Pci Master Abort
+ ULONG RcvdTarAbt: 1; // Pci Target Abort
+ ULONG PaPteInv: 1; // Invalid Pte
+ ULONG FromWrtErr: 1; // Invalid write to flash rom
+ ULONG IoaTimeout: 1; // Io Timeout occurred
+ ULONG Reserved0: 4; //
+ ULONG LostCorErr: 1; // Lost correctable error
+ ULONG LostUnCorErr: 1; // Lost uncorrectable error
+ ULONG LostCpuPe: 1; // Lost Ev5 bus parity error
+ ULONG LostMemNem: 1; // Lost Nonexistent memory error
+ ULONG Reserved1: 1; //
+ ULONG LostPciPerr: 1; // Lost PCI bus perr detected
+ ULONG LostPciAddrPe: 1; // Lost PCI bus address parity error
+ ULONG LostRcvdMasAbt: 1; // Lost Pci Master Abort
+ ULONG LostRcvdTarAbt: 1; // Lost Pci Target Abort
+ ULONG LostPaPteInv: 1; // Lost Invalid Pte
+ ULONG LostFromWrtErr: 1; // Lost Invalid write to flash rom
+ ULONG LostIoaTimeout: 1; // Lost Io Timeout occurred
+ ULONG Reserved2: 3; //
+ ULONG ErrValid: 1; // Self explanatory
+ };
+ ULONG all;
+} CIA_ERR, *PCIA_ERR;
+
+#define CIA_ERR_FATAL_MASK 0x00000ffe
+#define CIA_ERR_LOST_MASK 0x0fff0000
+
+typedef union _CIA_STAT{
+ struct{
+ ULONG PciStatus: 2; // Pci Status
+ ULONG Reserved0: 1; //
+ ULONG MemSource: 1; // 0=ev5 1=Pci
+ ULONG IoaValid: 4; // Valid bits for Io command address queue
+ ULONG CpuQueue: 3; // Valid bits for Cpu command address queue
+ ULONG TlbMiss: 1; // Tlb Miss refill in progress
+ ULONG DmSt: 4; // state machine values
+ ULONG PaCpuRes: 2; // Ev5 response for DMA
+ ULONG Reserved1: 14; //
+ };
+ ULONG all;
+} CIA_STAT, *PCIA_STAT;
+
+
+typedef union _CIA_ERR_MASK{
+ struct{
+ ULONG CorErr: 1; // Enable Correctable error
+ ULONG UnCorErr: 1; // Enable Uncorrectable error
+ ULONG CpuPe: 1; // Enable Ev5 bus parity error
+ ULONG MemNem: 1; // Enable Nonexistent memory error
+ ULONG PciSerr: 1; // Enable PCI bus serr detected
+ ULONG PciPerr: 1; // Enable PCI bus perr detected
+ ULONG PciAddrPe: 1; // Enable PCI bus address parity error
+ ULONG RcvdMasAbt: 1; // Enable Pci Master Abort
+ ULONG RcvdTarAbt: 1; // Enable Pci Target Abort
+ ULONG PaPteInv: 1; // Enable Invalid Pte
+ ULONG FromWrtErr: 1; // Enable Invalid write to flash rom
+ ULONG IoaTimeout: 1; // Enable Io Timeout occurred
+ ULONG Reserved0: 20; //
+ };
+ ULONG all;
+} CIA_ERR_MASK, *PCIA_ERR_MASK;
+
+typedef union _CIA_SYN{
+ struct{
+ ULONG EccSyndrome: 8; // Ecc syndrome
+ ULONG Reserved0: 24; //
+ };
+ ULONG all;
+} CIA_SYN, *PCIA_SYN;
+
+typedef union _CIA_MEM_ERR0{
+ struct{
+ ULONG Reserved0: 4; //
+ ULONG Addr31_4: 28; // Memory port address bits
+ };
+ ULONG all;
+} CIA_MEM_ERR0, *PCIA_MEM_ERR0;
+
+typedef union _CIA_MEM_ERR1{
+ struct{
+ ULONG Addr33_32: 2; // memory port address bits
+ ULONG Reserved0: 5; //
+ ULONG Addr39: 1; // Address bit 39
+ ULONG MemPortCmd: 4; // Memory port command
+ ULONG MemPortMask: 4; // Mask bits when error occurred
+ ULONG SeqSt: 4; // Memory sequencer state
+ ULONG MemPortSrc: 1; // 0=cpu, 1=dma
+ ULONG Reserved1: 3; //
+ ULONG SetSel: 5; // Indicates active memory set
+ ULONG Reserved2: 3; //
+ };
+ ULONG all;
+} CIA_MEM_ERR1, *PCIA_MEM_ERR1;
+
+typedef union _CIA_PCI_ERR0{
+ struct{
+ ULONG Cmd: 4; // Pci command
+ ULONG LockState: 1; // Indicates CIA locked
+ ULONG DacCycle: 1; // indicates PCI dual address cycle
+ ULONG Reserved0: 2; //
+ ULONG Window: 4; // Selected DMA window
+ ULONG Reserved1: 4; //
+ ULONG MasterState: 4; // State of PCI master
+ ULONG TargetState: 3; // State of PCI target
+ ULONG Reserved2: 9; //
+ };
+ ULONG all;
+} CIA_PCI_ERR0, *PCIA_PCI_ERR0;
+
+typedef struct _CIA_PCI_ERR1{
+ ULONG PciAddress; // Pci Address
+} CIA_PCI_ERR1, *PCIA_PCI_ERR1;
+
+typedef struct _CIA_PCI_ERR2{
+ ULONG PciAddress; // Pci Address
+} CIA_PCI_ERR2, *PCIA_PCI_ERR2;
+
+//
+// Define the structures and definitions for the CIA memory registers.
+//
+
+#define CIA_MEMORY_CSRS_PHYSICAL ((ULONGLONG)0x8750000000)
+#define CIA_MEMORY_CSRS_QVA HAL_MAKE_QVA(CIA_MEMORY_CSRS_PHYSICAL)
+
+typedef struct _CIA_MEMORY_CSRS{
+ UCHAR Mcr; // (0000) MCR register
+ UCHAR Filler0[47]; // (0020 - 05e0)
+ UCHAR Mba0; // (0600) Mba0 register
+ UCHAR Filler1[3]; // (0620 - 0660)
+ UCHAR Mba2; // (0680) Mba2 register
+ UCHAR Filler2[3]; // (06a0 - 06e0)
+ UCHAR Mba4; // (0700) Mba4 register
+ UCHAR Filler3[3]; // (0720 - 0760)
+ UCHAR Mba6; // (0780) Mba6 register
+ UCHAR Filler4[3]; // (07a0 - 07e0)
+ UCHAR Mba8; // (0800) Mba8 register
+ UCHAR Filler5[3]; // (0820 - 0860)
+ UCHAR MbaA; // (0880) MbaA register
+ UCHAR Filler6[3]; // (08a0 - 08e0)
+ UCHAR MbaC; // (0900) MbaC register
+ UCHAR Filler7[3]; // (0920 - 960)
+ UCHAR MbaE; // (0980) MbaE register
+ UCHAR Filler8[8]; // (0a00 - ae0)
+ UCHAR Tmg0; // (0b00) Tmg0 register
+ UCHAR Filer9; // (0b20)
+ UCHAR Tmg1; // (0b40) Tmg1 register
+ UCHAR Filer10; // (0b60)
+ UCHAR Tmg2; // (0b80) Tmg2 register
+} CIA_MEMORY_CSRS, *PCIA_MEMORY_CSRS;
+
+//
+// Define structures and definitions for Memory control registers:
+//
+
+typedef union _CIA_MCR{
+ struct{
+ ULONG MemSize: 1; // Memory path width (256 vs. 128)
+ ULONG Reserved1: 3; //
+ ULONG CacheSize: 3; // Bcache size
+ ULONG Reserved2: 1; //
+ ULONG RefRate: 10; // Memory refresh rate
+ ULONG RefBurst: 2; // Refresh configuration
+ ULONG TmgR0: 2; // Row address setup control
+ ULONG LongCbrCas: 1; // CAS pulse width
+ ULONG Reserved3: 3; //
+ ULONG DelayIdleBc: 2; // ??
+ ULONG Reserved4: 1; //
+ ULONG EarlyIdleBc: 1; // ??
+ ULONG Reserved5: 2; //
+ };
+ ULONG all;
+} CIA_MCR, *PCIA_MCR;
+
+typedef union _CIA_MBA{
+ struct{
+ ULONG MbaS0Valid: 1; // Indiates side 0 of bank is valid
+ ULONG MbaRowType: 2; // Row and column configuration
+ ULONG Reserved1: 1; //
+ ULONG MbaMask: 5; // Comparision Mask
+ ULONG Reserved2: 6; //
+ ULONG MbaS1Valid: 1; // Indicates side 1 of bank is valid
+ ULONG MbaPattern: 10; // Address decode pattern
+ ULONG Reserved3: 2; //
+ ULONG MbaTiming: 2; // TMGx CSR select
+ ULONG Reserved4: 2; //
+ };
+ ULONG all;
+} CIA_MBA, *PCIA_MBA;
+
+typedef union _CIA_TMG{
+ struct{
+ ULONG TmgR1: 2; // Read starting, data delay
+ ULONG TmgR2: 2; // Row address hold
+ ULONG TmgR3: 2; // Read cycle time
+ ULONG TmgR4: 2; // Read, CAS assertion delay
+ ULONG TmgR5: 2; // Read, CAS pulse width
+ ULONG TmgR6: 2; // Read, column address hold
+ ULONG TmgW1: 2; // Write, data delay
+ ULONG TmgW4: 3; // Write, CAS assertion delay
+ ULONG TmgPre: 1; // RAS precharge delay
+ ULONG TmgV3: 2; // Write, cycle time
+ ULONG TmgV4: 3; // Linked victim, CAS assertion delay
+ ULONG Reserved1: 1; //
+ ULONG TmgV5: 2; // Victim/Write, CAS pulse width
+ ULONG TmgV6: 2; // Victim/Write, Column address hold
+ ULONG TmgRv: 2; // Read to victim start delay
+ ULONG TmgRdDelay: 2; // Read data delay
+ };
+ ULONG all;
+} CIA_TMG, *PCIA_TMG;
+
+//
+// Define structures and definitions for Scatter/Gather control registers:
+//
+
+#define CIA_SCATTER_GATHER_CSRS_PHYSICAL ((ULONGLONG)0x8760000100)
+#define CIA_SG_CSRS_QVA (HAL_MAKE_QVA(CIA_SCATTER_GATHER_CSRS_PHYSICAL))
+
+typedef struct _CIA_SG_CSRS{
+ UCHAR Tbia; // (100) Translation buffer invalidate all
+ UCHAR Filler0[23]; // (120-3e0)
+ UCHAR Wbase0; // (400) Base address, DMA window 0
+ UCHAR Filler1; // (420)
+ UCHAR Wmask0; // (440) Mask Register, DMA window 0
+ UCHAR Filler2; // (460)
+ UCHAR Tbase0; // (480) Translation Base, DMA window 0
+ UCHAR Filler3[3]; // (4a0 - 4e0)
+ UCHAR Wbase1; // (500) Base address, DMA window 1
+ UCHAR Filler4; // (520)
+ UCHAR Wmask1; // (540) Mask Register, DMA window 1
+ UCHAR Filler5; // (560)
+ UCHAR Tbase1; // (580) Translation Base, DMA window 1
+ UCHAR Filler6[3]; // (5a0 - 5e0)
+ UCHAR Wbase2; // (600) Base address, DMA window 2
+ UCHAR Filler7; // (620)
+ UCHAR Wmask2; // (640) Mask Register, DMA window 2
+ UCHAR Filler8; // (660)
+ UCHAR Tbase2; // (680) Translation Base, DMA window 2
+ UCHAR Filler9[3]; // (6a0 - 6e0)
+ UCHAR Wbase3; // (700) Base address, DMA window 3
+ UCHAR Filler10; // (720)
+ UCHAR Wmask3; // (740) Mask Register, DMA window 3
+ UCHAR Filler11; // (760)
+ UCHAR Tbase3; // (780) Translation Base, DMA window 3
+ UCHAR Filler12; // (7a0)
+ UCHAR Dac; // (7c0) Window DAC Base
+ UCHAR Filler13; // (7e0)
+ UCHAR LtbTag0; // (800) Lockable Translation Buffer Tag 0
+ UCHAR Filler14; // (820)
+ UCHAR LtbTag1; // (840) Lockable Translation Buffer Tag 1
+ UCHAR Filler15; // (860)
+ UCHAR LtbTag2; // (880) Lockable Translation Buffer Tag 2
+ UCHAR Filler16; // (8a0)
+ UCHAR LtbTag3; // (8c0) Lockable Translation Buffer Tag 3
+ UCHAR Filler17; // (8e0)
+ UCHAR TbTag0; // (900) Translation Buffer Tag 0
+ UCHAR Filler18; // (920)
+ UCHAR TbTag1; // (940) Translation Buffer Tag 1
+ UCHAR Filler19; // (960)
+ UCHAR TbTag2; // (980) Translation Buffer Tag 2
+ UCHAR Filler20; // (9a0)
+ UCHAR TbTag3; // (9c0) Translation Buffer Tag 3
+ UCHAR Filler21; // (9e0)
+ UCHAR Tb0Page0; // (1000) Translation Buffer 0 Page 0
+ UCHAR Filler22; // (1020)
+ UCHAR Tb0Page1; // (1040) Translation Buffer 0 Page 1
+ UCHAR Filler23; // (1060)
+ UCHAR Tb0Page2; // (1080) Translation Buffer 0 Page 2
+ UCHAR Filler24; // (10a0)
+ UCHAR Tb0Page3; // (10c0) Translation Buffer 0 Page 3
+ UCHAR Filler25; // (10e0)
+ UCHAR Tb1Page0; // (1100) Translation Buffer 1 Page 0
+ UCHAR Filler26; // (1120)
+ UCHAR Tb1Page1; // (1140) Translation Buffer 1 Page 1
+ UCHAR Filler27; // (1160)
+ UCHAR Tb1Page2; // (1180) Translation Buffer 1 Page 2
+ UCHAR Filler28; // (11a0)
+ UCHAR Tb1Page3; // (11c0) Translation Buffer 1 Page 3
+ UCHAR Filler29; // (11e0)
+ UCHAR Tb2Page0; // (1200) Translation Buffer 2 Page 0
+ UCHAR Filler30; // (1220)
+ UCHAR Tb2Page1; // (1240) Translation Buffer 2 Page 1
+ UCHAR Filler31; // (1260)
+ UCHAR Tb2Page2; // (1280) Translation Buffer 2 Page 2
+ UCHAR Filler32; // (12a0)
+ UCHAR Tb2Page3; // (12c0) Translation Buffer 2 Page 3
+ UCHAR Filler33; // (12e0)
+ UCHAR Tb3Page0; // (1300) Translation Buffer 3 Page 0
+ UCHAR Filler34; // (1320)
+ UCHAR Tb3Page1; // (1340) Translation Buffer 3 Page 1
+ UCHAR Filler35; // (1360)
+ UCHAR Tb3Page2; // (1380) Translation Buffer 3 Page 2
+ UCHAR Filler36; // (13a0)
+ UCHAR Tb3Page3; // (13c0) Translation Buffer 3 Page 3
+ UCHAR Filler37; // (13e0)
+ UCHAR Tb4Page0; // (1400) Translation Buffer 4 Page 0
+ UCHAR Filler38; // (1420)
+ UCHAR Tb4Page1; // (1440) Translation Buffer 4 Page 1
+ UCHAR Filler39; // (1460)
+ UCHAR Tb4Page2; // (1480) Translation Buffer 4 Page 2
+ UCHAR Filler40; // (14a0)
+ UCHAR Tb4Page3; // (14c0) Translation Buffer 4 Page 3
+ UCHAR Filler41; // (14e0)
+ UCHAR Tb5Page0; // (1500) Translation Buffer 5 Page 0
+ UCHAR Filler42; // (1520)
+ UCHAR Tb5Page1; // (1540) Translation Buffer 5 Page 1
+ UCHAR Filler43; // (1560)
+ UCHAR Tb5Page2; // (1580) Translation Buffer 5 Page 2
+ UCHAR Filler44; // (15a0)
+ UCHAR Tb5Page3; // (15c0) Translation Buffer 5 Page 3
+ UCHAR Filler45; // (15e0)
+ UCHAR Tb6Page0; // (1600) Translation Buffer 6 Page 0
+ UCHAR Filler46; // (1620)
+ UCHAR Tb6Page1; // (1640) Translation Buffer 6 Page 1
+ UCHAR Filler47; // (1660)
+ UCHAR Tb6Page2; // (1680) Translation Buffer 6 Page 2
+ UCHAR Filler48; // (16a0)
+ UCHAR Tb6Page3; // (16c0) Translation Buffer 6 Page 3
+ UCHAR Filler49; // (16e0)
+ UCHAR Tb7Page0; // (1700) Translation Buffer 7 Page 0
+ UCHAR Filler50; // (1720
+ UCHAR Tb7Page1; // (1740) Translation Buffer 7 Page 1
+ UCHAR Filler51; // (1760)
+ UCHAR Tb7Page2; // (1780) Translation Buffer 7 Page 2
+ UCHAR Filler52; // (17a0)
+ UCHAR Tb7Page3; // (17c0) Translation Buffer 7 Page 3
+
+} CIA_SG_CSRS, *PCIA_SG_CSRS;
+
+
+typedef union _CIA_TBIA{
+ struct{
+ ULONG InvalidateType: 2; // Type of invalidation
+ ULONG Reserved0: 30; //
+ };
+ ULONG all;
+} CIA_TBIA, *PCIA_TBIA;
+
+typedef union _CIA_WBASE{
+ struct{
+ ULONG Wen: 1; // Window enable
+ ULONG SgEn: 1; // Scatter Gather enable
+ ULONG MemcsEn: 1; // Memory Cs Enable
+ ULONG DacEn: 1; // DAC Enable
+ ULONG Reserved0: 16; //
+ ULONG Wbase: 12; // Base address of DMA window
+ };
+ ULONG all;
+} CIA_WBASE, *PCIA_WBASE;
+
+typedef union _CIA_WMASK{
+ struct{
+ ULONG Reserved0: 20; //
+ ULONG Wmask: 12; // Window mask
+ };
+ ULONG all;
+} CIA_WMASK, *PCIA_WMASK;
+
+typedef union _CIA_TBASE{
+ struct{
+ ULONG Reserved0: 8; //
+ ULONG Tbase: 24; // Translation base address
+ };
+ ULONG all;
+} CIA_TBASE, *PCIA_TBASE;
+
+typedef union _CIA_LTB_TAG{
+ struct{
+ ULONG Valid: 1;
+ ULONG Locked: 1;
+ ULONG Dac: 1;
+ ULONG Reserved0: 12;
+ ULONG TbTag: 17;
+ };
+ ULONG all;
+} CIA_LTB_TAG, *PCIA_LTB_TAG;
+
+typedef union _CIA_TB_TAG{
+ struct{
+ ULONG Valid: 1;
+ ULONG Reserved0: 1;
+ ULONG Dac: 1;
+ ULONG Reserved1: 12;
+ ULONG TbTag: 17;
+ };
+ ULONG all;
+} CIA_TB_TAG, *PCIA_TB_TAG;
+
+
+//
+// DMA Window Values.
+//
+// The CIA will be initialized to allow 2 DMA windows.
+// The first window will be for the use of of ISA devices and DMA slaves
+// and therefore must have logical addresses below 16MB.
+// The second window will be for bus masters (non-ISA) and so may be
+// above 16MB.
+//
+// The arrangement of the windows will be as follows:
+//
+// Window Logical Start Address Window Size
+// ------ --------------------- -----------
+// Isa 8MB 8MB
+// Master 16MB 16MB
+//
+
+#define ISA_DMA_WINDOW_BASE (__8MB)
+#define ISA_DMA_WINDOW_SIZE (__8MB)
+
+#define MASTER_DMA_WINDOW_BASE (__16MB)
+#define MASTER_DMA_WINDOW_SIZE (__16MB)
+
+
+//
+// Define the software control registers for a DMA window.
+//
+
+typedef struct _WINDOW_CONTROL_REGISTERS{
+ PVOID WindowBase;
+ ULONG WindowSize;
+ PVOID TranslatedBaseRegister;
+ PVOID WindowBaseRegister;
+ PVOID WindowMaskRegister;
+ PVOID WindowTbiaRegister;
+} WINDOW_CONTROL_REGISTERS, *PWINDOW_CONTROL_REGISTERS;
+
+//
+// Define types of windows.
+//
+
+typedef enum _CIA_WINDOW_NUMBER{
+ CiaIsaWindow,
+ CiaMasterWindow
+} CIA_WINDOW_NUMBER, *PCIA_WINDOW_NUMBER;
+
+//
+// Define the types of invalidates that can be performed by the CIA.
+//
+
+typedef enum _CIA_INVALIDATE_TYPE{
+ InvalidateNoop = 0x0,
+ InvalidateLocked = 0x1,
+ InvalidateVolatile = 0x2,
+ InvalidateAll = 0x3
+} CIA_INVALIDATE_TYPE, *PCIA_INVALIDATE_TYPE;
+
+//
+// Define CIA Window Control routines.
+//
+
+VOID
+HalpCiaInitializeSfwWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ CIA_WINDOW_NUMBER WindowNumber
+ );
+
+VOID
+HalpCiaProgramDmaWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ PVOID MapRegisterBase
+ );
+
+VOID
+HalpCiaInvalidateTlb(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ CIA_INVALIDATE_TYPE InvalidateType
+ );
+
+VOID
+WRITE_CIA_REGISTER(
+ PVOID,
+ ULONGLONG
+ );
+
+ULONG
+READ_CIA_REGISTER(
+ PVOID
+ );
+
+VOID
+WRITE_GRU_REGISTER(
+ PVOID,
+ ULONGLONG
+ );
+
+ULONG
+READ_GRU_REGISTER(
+ PVOID
+ );
+
+ULONG
+INTERRUPT_ACKNOWLEDGE(
+ PVOID
+ );
+
+BOOLEAN
+HalpCiaUncorrectableError(
+ VOID
+ );
+
+VOID
+HalpCiaReportFatalError(
+ VOID
+ );
+
+BOOLEAN
+HalpCiaMachineCheck(
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PKEXCEPTION_FRAME ExceptionFrame,
+ IN PKTRAP_FRAME TrapFrame
+ );
+
+VOID
+HalpInitializeCia(
+ PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+VOID
+HalpInitializeCiaMachineChecks(
+ IN BOOLEAN ReportCorrectableErrors,
+ IN BOOLEAN PciParityChecking
+ );
+
+#if HALDBG
+
+VOID
+DumpCia(
+ CIA_REGISTER_CLASS RegistersToDump
+ );
+
+#endif //HALDBG
+
+
+//
+// VOID
+// INITIALIZE_ISA_DMA_CONTROL(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters
+// )
+//
+// Routine Description:
+//
+// Initialize the DMA Control software window registers for the ISA
+// DMA window.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window control.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INITIALIZE_ISA_DMA_CONTROL( WR ) \
+ HalpCiaInitializeSfwWindow( (WR), CiaIsaWindow );
+
+
+//
+// VOID
+// INITIALIZE_MASTER_DMA_CONTROL(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters
+// )
+//
+// Routine Description:
+//
+// Initialize the DMA Control software window registers for the ISA
+// DMA window.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window control.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INITIALIZE_MASTER_DMA_CONTROL( WR ) \
+ HalpCiaInitializeSfwWindow( (WR), CiaMasterWindow );
+
+
+//
+// VOID
+// INITIALIZE_DMA_WINDOW(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters,
+// PTRANSLATION_ENTRY MapRegisterBase
+// )
+//
+// Routine Description:
+//
+// Program the control windows so that DMA can be started to the
+// DMA window.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window register
+// control structure.
+//
+// MapRegisterBase - Supplies the logical address of the scatter/gather
+// array in system memory.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INITIALIZE_DMA_WINDOW( WR, MRB ) \
+ HalpCiaProgramDmaWindow( (WR), (MRB) );
+
+
+//
+// VOID
+// INVALIDATE_DMA_TRANSLATIONS(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters
+// )
+//
+// Routine Description:
+//
+// Invalidate all of the cached translations for a DMA window.
+//
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window control
+// registers.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INVALIDATE_DMA_TRANSLATIONS( WR ) \
+ HalpCiaInvalidateTlb( (WR), InvalidateAll );
+
+
+//
+// Define the format of a translation entry aka a scatter/gather entry
+// or map register.
+//
+
+typedef struct _TRANSLATION_ENTRY{
+ ULONG Valid: 1;
+ ULONG Pfn: 31;
+ ULONG Reserved;
+} TRANSLATION_ENTRY, *PTRANSLATION_ENTRY;
+
+
+
+//
+// VOID
+// HAL_MAKE_VALID_TRANSLATION(
+// PTRANSLATION_ENTRY Entry,
+// ULONG PageFrameNumber
+// )
+//
+// Routine Description:
+//
+// Make the scatter/gather entry pointed to by Entry valid with
+// a translation to the page indicated by PageFrameNumber.
+//
+// Arguments:
+//
+// Entry - Supplies a pointer to the translation entry to make valid.
+//
+// PageFrameNumber - Supplies the page frame of the valid translation.
+//
+// Return Value:
+//
+// None.
+//
+
+#define HAL_MAKE_VALID_TRANSLATION( ENTRY, PFN ) \
+ { \
+ (ENTRY)->Valid = 1; \
+ (ENTRY)->Pfn = PFN; \
+ (ENTRY)->Reserved = 0; \
+ }
+
+
+//
+// VOID
+// HAL_INVALIDATE_TRANSLATION(
+// PTRANSLATION_ENTRY Entry
+// )
+//
+// Routine Description:
+//
+// Invalidate the translation indicated by Entry.
+//
+// Arguments:
+//
+// Entry - Supplies a pointer to the translation to be invalidated.
+//
+// Return Value:
+//
+// None.
+//
+
+#define HAL_INVALIDATE_TRANSLATION( ENTRY ) \
+ (ENTRY)->Valid = 0;
+
+#endif //!_LANGUAGE_ASSEMBLY
+
+#endif //_CIAH_
diff --git a/private/ntos/nthals/halalpha/ciaaddr.c b/private/ntos/nthals/halalpha/ciaaddr.c
new file mode 100644
index 000000000..52d53a696
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ciaaddr.c
@@ -0,0 +1,567 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ ciaaddr.c
+
+Abstract:
+
+ This module contains the platform dependent code to create bus addreses
+ and QVAs for the Alcor system.
+
+Author:
+
+ Joe Notarangelo 30-Jun-1994
+ Steve Brooks 30-Jun-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+
+
+typedef PVOID QUASI_VIRTUAL_ADDRESS;
+
+QUASI_VIRTUAL_ADDRESS
+HalCreateQva(
+ IN PHYSICAL_ADDRESS PA,
+ IN PVOID VA
+ );
+
+
+BOOLEAN
+HalpTranslateSystemBusAddress(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ 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:
+
+ BusHandler - Registered BUSHANDLER for the target configuration space
+ Supplies the bus handler (bus no, interface type).
+
+ RootHandler - Registered BUSHANDLER for the orginating
+ HalTranslateBusAddress request.
+
+ BusAddress - Supplies the bus relative address.
+
+ AddressSpace - Supplies the address space number for the device: 0 for
+ memory and 1 for I/O space. If the desired access mode is user mode,
+ then bit 1 must be TRUE.
+
+ TranslatedAddress - Supplies a pointer to return the translated address
+
+
+Notes:
+
+ This is a variation of what began in the MIPS code. The intel code often
+ assumes that if an address is in I/O space, the bottom 32 bits of the
+ physical address can be used "like" a virtual address, and are returned
+ to the user. This doesn't work on MIPs machines where physical
+ addresses can be larger than 32 bits.
+
+ Since we are using superpage addresses for I/O on Alpha, we can do
+ almost what is done on intel. If AddressSpace is equal to 0 or 1, then
+ we assume the user is doing kernel I/O and we call HalCreateQva to
+ build a Quasi Virtual Address and return that to the caller. We then
+ set AddressSpace to a 1, so that the caller will not call MmMapIoSpace.
+ The Caller will use the low 32 bits of the physical address we return
+ as the VA. (Which we built a QVA in).
+
+ If the caller wants to access EISA I/O or Memory through user mode, then
+ the caller must set bit 1 in AddressSpace to a 1 (AddressSpace=2 or 3,
+ depending on whether EISA I/O or Memory), then the caller is returned the
+ 34 bit Physical address. The caller will then call MmMapIoSpace, or
+ ZwMapViewOfSection which in turn calls HalCreateQva to build a QVA out
+ of a VA mapped through the page tables.
+
+ **** Note ****
+
+ The QVA in user mode can only be used via the user-mode access macros.
+
+
+
+Return Value:
+
+ A return value of TRUE indicates that a system physical address
+ corresponding to the supplied bus relative address and bus address
+ number has been returned in TranslatedAddress.
+
+ A return value of FALSE occurs if the translation for the address was
+ not possible
+
+--*/
+
+{
+ INTERFACE_TYPE InterfaceType = BusHandler->InterfaceType;
+ ULONG BusNumber = BusHandler->BusNumber;
+
+ PVOID va = 0; // note, this is used for a placeholder
+
+ //
+ // The buses available on Alcor are EISA and PCI.
+ // We support any translations for ISA devices as well,
+ // since they can plug into EISA slots just fine.
+ //
+
+ if (InterfaceType != Isa &&
+ InterfaceType != Eisa &&
+ InterfaceType != PCIBus) {
+
+ //
+ // Not on this system; return nothing.
+ //
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+
+ }
+
+ //
+ // Determine the address based on whether the bus address is in I/O space
+ // or bus memory space.
+ //
+
+ switch ( (ADDRESS_SPACE_TYPE)(*AddressSpace) ) {
+
+ case BusMemory:
+
+ //
+ // The address is in PCI memory space, kernel mode.
+ //
+
+ switch( InterfaceType ) {
+
+ case Isa:
+
+ //
+ // Can't go above 16MB (24 Bits) for Isa Buses
+ //
+
+ if( BusAddress.LowPart >= __16MB ){
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+
+ }
+
+ break;
+
+ case PCIBus: {
+
+ if ( BusAddress.LowPart > PCI_MAX_DENSE_MEMORY_ADDRESS ) {
+
+ //
+ // Unsupported dense PCI bus address.
+ //
+#if HALDBG
+ DbgPrint ("Unsupported PCI address %x:%x\n",
+ BusAddress.HighPart,
+ BusAddress.LowPart);
+#endif
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+ }
+ else if( BusAddress.LowPart >= PCI_MIN_DENSE_MEMORY_ADDRESS &&
+ BusAddress.LowPart <= PCI_MAX_DENSE_MEMORY_ADDRESS ) {
+
+#if HALDBG
+ DbgPrint ("Translating PCI kernel dense address %x:%x\n",
+ BusAddress.HighPart,
+ BusAddress.LowPart);
+#endif
+ //
+ // Bus Address is in dense PCI memory space
+ //
+
+ //
+ // QVA, as such, is simply the PCI bus address
+ //
+
+ TranslatedAddress->LowPart = BusAddress.LowPart;
+
+ //
+ // clear high longword for QVA
+ //
+
+ TranslatedAddress->HighPart = 0;
+
+ //
+ // dont let the user call MmMapIoSpace
+ //
+
+ *AddressSpace = 1;
+
+ return (TRUE);
+
+
+ }
+
+ //
+ // Bus Address is in sparse PCI memory space
+ //
+
+
+#if HALDBG
+ DbgPrint ("Translating PCI kernel sparse address %x:%x\n",
+ BusAddress.HighPart,
+ BusAddress.LowPart);
+#endif
+
+ break;
+ } // case PCIBus
+
+ case Eisa:
+
+ break;
+
+ } // switch( InterfaceType )
+
+ //
+ // Start with the base physical address and add the
+ // bus address by converting it to the physical address.
+ //
+
+ TranslatedAddress->QuadPart = CIA_PCI_SPARSE_MEMORY_PHYSICAL;
+ TranslatedAddress->QuadPart +=
+ ((ULONGLONG)BusAddress.LowPart << IO_BIT_SHIFT);
+
+ //
+ // Now call HalCreateQva. This will create a QVA
+ // that we'll return to the caller. Then we will implicitly set
+ // AddressSpace to a 1. The caller then will not call MmMapIoSpace
+ // and will use the address we return as a VA.
+ //
+
+ TranslatedAddress->LowPart = (ULONG)HalCreateQva(
+ *TranslatedAddress,
+ va);
+ TranslatedAddress->HighPart = 0; // clear high longword for QVA
+
+ *AddressSpace = 1; // don't let the user call
+ // MmMapIoSpace
+ return(TRUE);
+
+ case BusIo:
+
+ //
+ // The address is in PCI I/O space, kernel mode.
+ //
+
+ switch( InterfaceType ) {
+
+ case Isa:
+
+ //
+ // Can't go above 64KB (16 Bits) for Isa Buses
+ //
+
+ if( BusAddress.LowPart >= __64K ){
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+
+ }
+
+ break;
+
+ case PCIBus:
+
+ //
+ // PCI IO space is always below 64MB (26 Bits) BusAddress
+ // If the address cannot be mapped, just return FALSE.
+ //
+
+ if( BusAddress.LowPart >= __64MB ){
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+
+ }
+
+ break;
+
+ case Eisa:
+
+ break;
+
+ } // switch( InterfaceType )
+
+ //
+ // Start with the base physical address and add the
+ // bus address by converting it to the physical address.
+ //
+
+ TranslatedAddress->QuadPart = CIA_PCI_SPARSE_IO_PHYSICAL;
+ TranslatedAddress->QuadPart +=
+ ((ULONGLONG)BusAddress.LowPart << IO_BIT_SHIFT);
+
+ //
+ // Now call HalCreateQva. This will create a QVA
+ // that we'll return to the caller. Then we will implicitly set
+ // AddressSpace to a 1. The caller then will not call MmMapIoSpace
+ // and will use the address we return as a VA.
+
+ TranslatedAddress->LowPart = (ULONG)HalCreateQva(
+ *TranslatedAddress,
+ va);
+ TranslatedAddress->HighPart = 0; // clear high longword for QVA
+
+ *AddressSpace = 1; // make sure user doesn't call
+ // MmMapIoSpace.
+ return(TRUE);
+
+ case UserBusMemory:
+
+ //
+ // The address is in PCI memory space, user mode.
+ //
+
+ //
+ // Start with the base physical address and add the
+ // bus address by converting it to the physical address.
+ //
+
+
+ TranslatedAddress->QuadPart = CIA_PCI_SPARSE_MEMORY_PHYSICAL;
+ TranslatedAddress->QuadPart |= EV5_USER_IO_ADDRESS_SPACE;
+ TranslatedAddress->QuadPart += (BusAddress.LowPart << IO_BIT_SHIFT);
+
+ *AddressSpace = 0; // Let the user call MmMapIoSpace
+
+ return(TRUE);
+
+ case UserBusIo:
+
+ //
+ // The address is in PCI I/O space, user mode.
+ //
+
+ //
+ // Start with the base physical address and add the
+ // bus address by converting it to the physical address.
+ //
+
+ TranslatedAddress->QuadPart = CIA_PCI_SPARSE_IO_PHYSICAL;
+ TranslatedAddress->QuadPart |= EV5_USER_IO_ADDRESS_SPACE;
+ TranslatedAddress->QuadPart += (BusAddress.LowPart << IO_BIT_SHIFT);
+
+ *AddressSpace = 0; // Let the user call MmMapIoSpace
+
+ return(TRUE);
+
+ case KernelPciDenseMemory:
+ case UserPciDenseMemory:
+
+ //
+ // The address is in PCI memory space, user mode.
+ //
+
+ //
+ // Start with the base physical address and add the
+ // bus address by converting it to the physical address.
+ //
+
+ TranslatedAddress->QuadPart = CIA_PCI_DENSE_MEMORY_PHYSICAL;
+ TranslatedAddress->QuadPart |= EV5_USER_IO_ADDRESS_SPACE;
+ TranslatedAddress->QuadPart += BusAddress.LowPart;
+
+ *AddressSpace = 0; // Let the user call MmMapIoSpace
+
+ return(TRUE);
+
+ default:
+
+ //
+ // Unsupported address space.
+ //
+
+ *AddressSpace = 0;
+ TranslatedAddress->LowPart = 0;
+ return(FALSE);
+
+ }
+}
+
+PVOID
+HalCreateQva(
+ IN PHYSICAL_ADDRESS PA,
+ IN PVOID VA
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called two ways. First, from HalTranslateBusAddress,
+ if the caller is going to run in kernel mode and use superpages.
+ The second way is if the user is going to access in user mode.
+ MmMapIoSpace or ZwViewMapOfSection will call this.
+
+ If the input parameter VA is zero, then we assume super page and build
+ a QUASI virtual address that is only usable by calling the hal I/O
+ access routines.
+
+ if the input parameter VA is non-zero, we assume the user has either
+ called MmMapIoSpace or ZwMapViewOfSection and will use the user mode
+ access macros.
+
+ If the PA is not a sparse I/O space address (PCI I/O, PCI Memory),
+ then return the VA as the QVA.
+
+Arguments:
+
+ PA - the physical address generated by HalTranslateBusAddress
+
+ VA - the virtual address returned by MmMapIoSpace
+
+Return Value:
+
+ The returned value is a quasi virtual address in that it can be
+ added to and subtracted from, but it cannot be used to access the
+ bus directly. The top bits are set so that we can trap invalid
+ accesses in the memory management subsystem. All access should be
+ done through the Hal Access Routines in *ioacc.s if it was a superpage
+ kernel mode access. If it is usermode, then the user mode access
+ macros must be used.
+
+--*/
+{
+
+ PHYSICAL_ADDRESS PhysicalOffset;
+ PVOID qva;
+
+ if( (PA.QuadPart >= CIA_PCI_DENSE_MEMORY_PHYSICAL) &&
+ (PA.QuadPart <= (CIA_PCI_DENSE_MEMORY_PHYSICAL +
+ PCI_MAX_DENSE_MEMORY_ADDRESS)) ){
+
+ //
+ // Kernel-mode physical dense address, return VA.
+ //
+
+ return(VA);
+
+ } else if( (PA.QuadPart >=
+ (CIA_PCI_DENSE_MEMORY_PHYSICAL | EV5_USER_IO_ADDRESS_SPACE) ) &&
+ (PA.QuadPart <
+ (CIA_PCI_DENSE_MEMORY_PHYSICAL | EV5_USER_IO_ADDRESS_SPACE +
+ PCI_MAX_DENSE_MEMORY_ADDRESS) ) ){
+
+ //
+ // User-mode physical dense address, return VA.
+ //
+
+ return(VA);
+
+ } else {
+
+ //
+ // The physical address is within one of the sparse I/O spaces.
+ //
+
+ if (VA == 0) {
+
+ PhysicalOffset.QuadPart = PA.QuadPart - CIA_QVA_PHYSICAL_BASE;
+ qva = (PVOID)(PhysicalOffset.QuadPart >> IO_BIT_SHIFT);
+ } else {
+
+ qva = (PVOID)((ULONG)VA >> IO_BIT_SHIFT);
+ }
+
+ qva = (PVOID)((ULONG)qva | QVA_ENABLE);
+
+ return(qva);
+ }
+
+
+}
+
+
+PVOID
+HalDereferenceQva(
+ PVOID Qva,
+ INTERFACE_TYPE InterfaceType,
+ ULONG BusNumber
+ )
+/*++
+
+Routine Description:
+
+ This function performs the inverse of the HalCreateQva for I/O addresses
+ that are memory-mapped (i.e. the quasi-virtual address was created from
+ a virtual address rather than a physical address).
+
+Arguments:
+
+ Qva - Supplies the quasi-virtual address to be converted back to a
+ virtual address.
+
+ InterfaceType - Supplies the interface type of the bus to which the
+ Qva pertains.
+
+ BusNumber - Supplies the bus number of the bus to which the Qva pertains.
+
+Return Value:
+
+ The Virtual Address from which the quasi-address was originally created
+ is returned.
+
+--*/
+{
+
+ //
+ // For Alcor we support three bus types:
+ //
+ // Isa
+ // Eisa
+ // PCIBus
+ //
+
+ switch (InterfaceType ){
+
+ case Isa:
+ case Eisa:
+ case PCIBus:
+
+ //
+ // Support PCI Dense space: check to see if it's really
+ // a QVA.
+ //
+
+ if ( ((ULONG) Qva & QVA_SELECTORS) == QVA_ENABLE ) {
+ return( (PVOID)( (ULONG)Qva << IO_BIT_SHIFT ) );
+ } else {
+ return (Qva);
+ }
+
+ break;
+
+ default:
+
+ return NULL;
+ }
+}
diff --git a/private/ntos/nthals/halalpha/ciaerr.c b/private/ntos/nthals/halalpha/ciaerr.c
new file mode 100644
index 000000000..ef984011e
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ciaerr.c
@@ -0,0 +1,1642 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ ciaerr.c
+
+Abstract:
+
+ This module implements error handling functions for the CIA ASIC.
+
+Author:
+
+ Joe Notarangelo 26-Jul-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#include "cia.h"
+#include "stdio.h"
+
+//
+// Externals and globals.
+//
+
+//
+// Declare the extern variable UncorrectableError declared in
+// inithal.c.
+//
+extern PERROR_FRAME PUncorrectableError;
+
+extern ULONG HalDisablePCIParityChecking;
+ULONG CiaCorrectedErrors = 0;
+
+//
+// Define the context structure for use by interrupt service routines.
+//
+
+typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)(
+ PKINTERRUPT InterruptObject,
+ PVOID ServiceContext
+ );
+
+//
+// Function prototypes.
+//
+
+VOID
+HalpSetMachineCheckEnables(
+ IN BOOLEAN DisableMachineChecks,
+ IN BOOLEAN DisableProcessorCorrectables,
+ IN BOOLEAN DisableSystemCorrectables
+ );
+
+VOID
+HalpUpdateMces(
+ IN BOOLEAN ClearMachineCheck,
+ IN BOOLEAN ClearCorrectableError
+ );
+
+//
+// Allocate a flag that indicates when a PCI Master Abort is expected.
+// PCI Master Aborts are signaled on configuration reads to non-existent
+// PCI slots. A non-zero value indicates that a Master Abort is expected.
+//
+
+ULONG HalpMasterAbortExpected = 0;
+
+
+VOID
+HalpInitializeCiaMachineChecks(
+ IN BOOLEAN ReportCorrectableErrors,
+ IN BOOLEAN PciParityChecking
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes machine check handling for a CIA-based
+ system by clearing all pending errors in the CIA registers and
+ enabling correctable errors according to the callers specification.
+
+Arguments:
+
+ ReportCorrectableErrors - Supplies a boolean value which specifies
+ if correctable error reporting should be
+ enabled.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ CIA_CONTROL CiaControl;
+ CIA_ERR CiaError;
+ CIA_ERR_MASK CiaErrMask;
+
+ //
+ // Clear any pending error bits in the CIA_ERR register:
+ //
+
+ CiaError.all = 0; // Clear all bits
+
+ CiaError.CorErr = 1; // Correctable error
+ CiaError.UnCorErr = 1; // Uncorrectable error
+ CiaError.CpuPe = 1; // Ev5 bus parity error
+ CiaError.MemNem = 1; // Nonexistent memory error
+ CiaError.PciSerr = 1; // PCI bus serr detected
+ CiaError.PciPerr = 1; // PCI bus perr detected
+ CiaError.PciAddrPe = 1; // PCI bus address parity error
+ CiaError.RcvdMasAbt = 1; // Pci Master Abort
+ CiaError.RcvdTarAbt = 1; // Pci Target Abort
+ CiaError.PaPteInv = 1; // Invalid Pte
+ CiaError.FromWrtErr = 1; // Invalid write to flash rom
+ CiaError.IoaTimeout = 1; // Io Timeout occurred
+ CiaError.LostCorErr = 1; // Lost correctable error
+ CiaError.LostUnCorErr = 1; // Lost uncorrectable error
+ CiaError.LostCpuPe = 1; // Lost Ev5 bus parity error
+ CiaError.LostMemNem = 1; // Lost Nonexistent memory error
+ CiaError.LostPciPerr = 1; // Lost PCI bus perr detected
+ CiaError.LostPciAddrPe = 1; // Lost PCI bus address parity error
+ CiaError.LostRcvdMasAbt = 1; // Lost Pci Master Abort
+ CiaError.LostRcvdTarAbt = 1; // Lost Pci Target Abort
+ CiaError.LostPaPteInv = 1; // Lost Invalid Pte
+ CiaError.LostFromWrtErr = 1; // Lost Invalid write to flash rom
+ CiaError.LostIoaTimeout = 1; // Lost Io Timeout occurred
+ CiaError.ErrValid = 1; // Self explanatory
+
+ WRITE_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr,
+ CiaError.all
+ );
+
+ //
+ // Set the Mask Bits in the CIA_MASK register:
+ //
+
+ CiaErrMask.all = 0; // Clear all bits
+
+ CiaErrMask.UnCorErr = 1; // Enable Uncorrectable error
+ CiaErrMask.CpuPe = 1; // Enable Ev5 bus parity error
+ CiaErrMask.MemNem = 1; // Enable Nonexistent memory error
+ CiaErrMask.PciSerr = 1; // Enable PCI bus serr detected
+ CiaErrMask.RcvdMasAbt = 1; // Enable Pci Master Abort
+ CiaErrMask.RcvdTarAbt = 1; // Enable Pci Target Abort
+ CiaErrMask.PaPteInv = 1; // Enable Invalid Pte
+ CiaErrMask.FromWrtErr = 1; // Enable Invalid write to flash rom
+ CiaErrMask.IoaTimeout = 1; // Enable Io Timeout occurred
+
+ //
+ // Determine PCI parity checking.
+ //
+
+ CiaControl.all = READ_CIA_REGISTER(
+ &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl );
+
+ if (PciParityChecking == FALSE) {
+
+ CiaControl.AddrPeEn = 0; // Disable PCI address parity checking
+ CiaControl.PerrEn = 0; // Disable PCI data parity checking
+
+ CiaErrMask.PciPerr = 0; // Disable PCI bus perr detected
+ CiaErrMask.PciAddrPe = 0; // Disable PCI bus address parity error
+
+ } else {
+
+ CiaControl.AddrPeEn = PciParityChecking;
+ CiaControl.PerrEn = PciParityChecking;
+
+ CiaErrMask.PciPerr = PciParityChecking;
+ CiaErrMask.PciAddrPe = PciParityChecking;
+
+ }
+
+ CiaErrMask.CorErr = (ReportCorrectableErrors == TRUE);
+
+ WRITE_CIA_REGISTER( &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl,
+ CiaControl.all
+ );
+
+ WRITE_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->ErrMask,
+ CiaErrMask.all
+ );
+
+ //
+ // Set the machine check enables within the EV5.
+ //
+
+ if( ReportCorrectableErrors == TRUE ){
+
+ HalpSetMachineCheckEnables( FALSE, FALSE, FALSE );
+
+ } else {
+
+ HalpSetMachineCheckEnables( FALSE, TRUE, TRUE );
+ }
+
+ return;
+
+}
+
+#define MAX_ERROR_STRING 128
+
+
+BOOLEAN
+HalpCiaUncorrectableError(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Read the CIA error register and determine if an uncorrectable error
+ is latched in the error bits.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE is returned if an uncorrectable error has been detected. FALSE
+ is returned otherwise.
+
+--*/
+{
+ CIA_ERR CiaError;
+
+
+ CiaError.all = READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr );
+
+ //
+ // If no error is valid then an uncorrectable error was not detected.
+ //
+
+ if( CiaError.ErrValid == 0 ){
+ return FALSE;
+ }
+
+ //
+ // Check each of the individual uncorrectable error bits, if any is set
+ // then return TRUE.
+ //
+
+ if( (CiaError.UnCorErr == 1) ||
+ (CiaError.CpuPe == 1) ||
+ (CiaError.MemNem == 1) ||
+ (CiaError.PciSerr == 1) ||
+ (CiaError.PciPerr == 1) ||
+ (CiaError.PciAddrPe == 1) ||
+ (CiaError.RcvdMasAbt == 1) ||
+ (CiaError.RcvdTarAbt == 1) ||
+ (CiaError.PaPteInv == 1) ||
+ (CiaError.FromWrtErr == 1) ||
+ (CiaError.IoaTimeout == 1) ){
+
+ return TRUE;
+
+ }
+
+ //
+ // None of the uncorrectable error conditions were detected.
+ //
+
+ return FALSE;
+
+}
+
+
+VOID
+HalpBuildCiaConfigurationFrame(
+ PCIA_CONFIGURATION pConfiguration
+ )
+{
+ pConfiguration->CiaRev = READ_CIA_REGISTER(
+ &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaRevision );
+
+ pConfiguration->CiaCtrl = READ_CIA_REGISTER(
+ &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl );
+
+ pConfiguration->Mcr = READ_CIA_REGISTER(
+ &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Mcr );
+
+ pConfiguration->Mba0 = READ_CIA_REGISTER(
+ &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Mba0 );
+
+ pConfiguration->Mba2 = READ_CIA_REGISTER(
+ &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Mba2 );
+
+ pConfiguration->Mba4 = READ_CIA_REGISTER(
+ &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Mba4 );
+
+ pConfiguration->Mba6 = READ_CIA_REGISTER(
+ &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Mba6 );
+
+ pConfiguration->Mba8 = READ_CIA_REGISTER(
+ &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Mba8 );
+
+ pConfiguration->MbaA = READ_CIA_REGISTER(
+ &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->MbaA );
+
+ pConfiguration->MbaC = READ_CIA_REGISTER(
+ &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->MbaC );
+
+ pConfiguration->MbaE = READ_CIA_REGISTER(
+ &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->MbaE );
+
+ pConfiguration->Tmg0 = READ_CIA_REGISTER(
+ &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Tmg0 );
+
+ pConfiguration->Tmg1 = READ_CIA_REGISTER(
+ &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Tmg1 );
+
+ pConfiguration->Tmg2 = READ_CIA_REGISTER(
+ &((PCIA_MEMORY_CSRS)(CIA_MEMORY_CSRS_QVA))->Tmg2 );
+
+}
+
+
+VOID
+HalpCiaReportFatalError(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function reports and interprets a fatal hardware error
+ detected by the CIA chipset. It is assumed that HalGetDisplayOwnership()
+ has been called prior to this function.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UCHAR OutBuffer[ MAX_ERROR_STRING ];
+ CIA_ERR CiaError;
+ CIA_STAT CiaStat;
+ CIA_SYN CiaSyn;
+ CIA_CONTROL CiaControl;
+ CIA_MEM_ERR0 MemErr0;
+ CIA_MEM_ERR1 MemErr1;
+ CIA_PCI_ERR0 PciErr0;
+ CIA_PCI_ERR1 PciErr1;
+ CIA_PCI_ERR2 PciErr2;
+ CIA_CPU_ERR0 CpuErr0;
+ CIA_CPU_ERR1 CpuErr1;
+
+ PUNCORRECTABLE_ERROR uncorr = NULL;
+ PCIA_UNCORRECTABLE_FRAME ciauncorr = NULL;
+ PEXTENDED_ERROR PExtErr;
+
+ //
+ // We will Build the uncorrectable error frame as we read
+ // the registers to report the error to the blue screen.
+ // We generate the extended error frame as we generate
+ // extended messages to print to the screen.
+ //
+
+ if(PUncorrectableError){
+ uncorr = (PUNCORRECTABLE_ERROR)
+ &PUncorrectableError->UncorrectableFrame;
+ ciauncorr = (PCIA_UNCORRECTABLE_FRAME)
+ PUncorrectableError->UncorrectableFrame.RawSystemInformation;
+ PExtErr = &PUncorrectableError->UncorrectableFrame.ErrorInformation;
+ }
+ if(uncorr){
+ uncorr->Flags.ProcessorInformationValid = 1;
+ HalpGetProcessorInfo(&uncorr->ReportingProcessor);
+ }
+
+ if(ciauncorr)
+ HalpBuildCiaConfigurationFrame(&ciauncorr->Configuration);
+ //
+ // Read the CIA Error register and decode its contents:
+ //
+
+ CiaError.all = (ULONG)READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr
+ );
+
+ if(ciauncorr)
+ ciauncorr->CiaErr = CiaError.all ;
+
+ //
+ // Read the rest of the error registers and then unlock them by
+ // writing to CIA_ERR
+ //
+
+ CiaStat.all = (ULONG)READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaStat
+ );
+
+
+ CiaSyn.all = (ULONG)READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaSyn
+ );
+
+
+ MemErr0.all = (ULONG)READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->MemErr0
+ );
+
+
+ MemErr1.all = (ULONG)READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->MemErr1
+ );
+
+
+ PciErr0.all = (ULONG)READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr0
+ );
+
+
+ PciErr1.PciAddress = (ULONG)READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr1
+ );
+
+ PciErr2.PciAddress = (ULONG)READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr2
+ );
+
+ CpuErr0.all = (ULONG)READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CpuErr0
+ );
+
+
+ CpuErr1.all = (ULONG)READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CpuErr1
+ );
+
+ CiaControl.all = READ_CIA_REGISTER(
+ &((PCIA_GENERAL_CSRS)(CIA_GENERAL_CSRS_QVA))->CiaCtrl);
+
+ if(ciauncorr){
+ ciauncorr->CiaStat = CiaStat.all;
+ ciauncorr->CiaSyn = CiaSyn.all;
+ ciauncorr->MemErr0 = MemErr0.all;
+ ciauncorr->MemErr1 = MemErr1.all;
+ ciauncorr->PciErr0 = PciErr0.all;
+ ciauncorr->PciErr1 = PciErr1.PciAddress;
+
+ ciauncorr->PciErr2 = (ULONG)READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr2
+ );
+ ciauncorr->CpuErr0 = CpuErr0.all;
+
+ ciauncorr->CpuErr1 = CpuErr1.all;
+
+ ciauncorr->ErrMask = (ULONG)READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->ErrMask
+ );
+
+ }
+
+ WRITE_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr,
+ CiaError.all
+ );
+
+
+ sprintf( OutBuffer, "CIA_CTRL : %08x\n", CiaControl.all );
+ HalDisplayString( OutBuffer );
+ DbgPrint( OutBuffer );
+
+ sprintf( OutBuffer, "CIA_ERR : %08x\n", CiaError.all );
+ HalDisplayString( OutBuffer );
+ DbgPrint( OutBuffer );
+
+ sprintf( OutBuffer, "CIA_STAT : %08x\n", CiaStat.all );
+ HalDisplayString( OutBuffer );
+ DbgPrint( OutBuffer );
+
+ sprintf( OutBuffer, "CIA_SYN : %08x\n", CiaSyn.all );
+ HalDisplayString( OutBuffer );
+ DbgPrint( OutBuffer );
+
+ sprintf( OutBuffer, "PCI_ERR0 : %08x\n", PciErr0.all );
+ HalDisplayString( OutBuffer );
+ DbgPrint( OutBuffer );
+
+ sprintf( OutBuffer, "PCI_ERR1 : %08x\n", PciErr1.PciAddress );
+ HalDisplayString( OutBuffer );
+ DbgPrint( OutBuffer );
+
+ sprintf( OutBuffer, "PCI_ERR2 : %08x\n", PciErr2.PciAddress );
+ HalDisplayString( OutBuffer );
+ DbgPrint( OutBuffer );
+
+ sprintf( OutBuffer, "CPU_ERR0 : %08x\n", CpuErr0.all );
+ HalDisplayString( OutBuffer );
+ DbgPrint( OutBuffer );
+
+ sprintf( OutBuffer, "CPU_ERR1 : %08x\n", CpuErr1.all );
+ HalDisplayString( OutBuffer );
+ DbgPrint( OutBuffer );
+
+ sprintf( OutBuffer, "MEM_ERR0 : %08x\n", MemErr0.all );
+ HalDisplayString( OutBuffer );
+ DbgPrint( OutBuffer );
+
+ sprintf( OutBuffer, "MEM_ERR1 : %08x\n", MemErr1.all );
+ HalDisplayString( OutBuffer );
+ DbgPrint( OutBuffer );
+
+ //
+ // If no valid error then no interpretation.
+ //
+
+ if ( CiaError.ErrValid == 0 ){
+
+ return; // No CIA error detected
+
+ }
+
+ //
+ // Interpret any detected errors:
+ //
+
+ if ( CiaError.UnCorErr == 1 ){
+
+ sprintf( OutBuffer,
+ "CIA Uncorrectable ECC error, Addr=%x%x, Cmd=%x\n",
+ CpuErr1.Addr34_32, // bits 34:32
+ CpuErr0.Addr, // bits 31:4
+ CpuErr1.Cmd
+ );
+ if(uncorr){
+ uncorr->Flags.ErrorStringValid = 1;
+ strcpy( uncorr->ErrorString, OutBuffer);
+ }
+
+ } else if ( CiaError.CpuPe == 1 ){
+
+ sprintf( OutBuffer,
+ "EV5 bus parity error, Addr=%x%x, Cmd=%x\n",
+ CpuErr1.Addr34_32, // bits 34:32
+ CpuErr0.Addr, // bits 31:4
+ CpuErr1.Cmd
+ );
+ if(uncorr){
+ uncorr->Flags.ErrorStringValid = 1;
+ strcpy( uncorr->ErrorString, OutBuffer);
+ }
+
+ } else if ( CiaError.MemNem == 1 ){
+
+ sprintf( OutBuffer,
+ "CIA Access to non-existent memory, Source=%s, Addr=%x%x\n",
+ MemErr1.MemPortSrc == 1 ? "DMA" : "CPU",
+ MemErr1.MemPortSrc == 1 ? 0 : MemErr1.Addr33_32,
+ MemErr1.MemPortSrc == 1 ? PciErr1.PciAddress : MemErr0.Addr31_4
+ );
+ if(uncorr){
+ uncorr->Flags.ErrorStringValid = 1;
+ strcpy( uncorr->ErrorString, OutBuffer);
+ }
+
+ } else if ( CiaError.PciSerr == 1 ){
+
+ sprintf( OutBuffer,
+ "PCI bus SERR detected, Cmd=%x, Window=%d, Addr=%x\n",
+ PciErr0.Cmd,
+ PciErr0.Window,
+ PciErr1.PciAddress
+ );
+
+ if(uncorr){
+ uncorr->Flags.ErrorStringValid = 1;
+ strcpy( uncorr->ErrorString, OutBuffer);
+ uncorr->Flags.AddressSpace = IO_SPACE;
+ uncorr->Flags.PhysicalAddressValid = 1;
+ uncorr->PhysicalAddress = PciErr1.PciAddress;
+
+ uncorr->Flags.ExtendedErrorValid = 1;
+ PExtErr->IoError.Interface = PCIBus;
+ PExtErr->IoError.BusNumber = 0;
+ PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress;
+ }
+
+ } else if ( CiaError.PciPerr == 1 ){
+
+ sprintf( OutBuffer,
+ "PCI bus Data Parity error, Cmd=%x, Window=%d, Addr=%x\n",
+ PciErr0.Cmd,
+ PciErr0.Window,
+ PciErr1.PciAddress
+ );
+
+ if(uncorr){
+ uncorr->Flags.ErrorStringValid = 1;
+ strcpy( uncorr->ErrorString, OutBuffer);
+ uncorr->Flags.AddressSpace = IO_SPACE;
+ uncorr->Flags.PhysicalAddressValid = 1;
+ uncorr->PhysicalAddress = PciErr1.PciAddress;
+
+ uncorr->Flags.ExtendedErrorValid = 1;
+ PExtErr->IoError.Interface = PCIBus;
+ PExtErr->IoError.BusNumber = 0;
+ PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress;
+ }
+
+ } else if ( CiaError.PciAddrPe == 1 ){
+
+ sprintf( OutBuffer,
+ "Pci bus Address Parity error, Cmd=%x, Window=%x, Addr=%x\n",
+ PciErr0.Cmd,
+ PciErr0.Window,
+ PciErr1.PciAddress
+ );
+ if(uncorr){
+ uncorr->Flags.ErrorStringValid = 1;
+ strcpy( uncorr->ErrorString, OutBuffer);
+ uncorr->Flags.AddressSpace = IO_SPACE;
+ uncorr->Flags.PhysicalAddressValid = 1;
+ uncorr->PhysicalAddress = PciErr1.PciAddress;
+
+ uncorr->Flags.ExtendedErrorValid = 1;
+ PExtErr->IoError.Interface = PCIBus;
+ PExtErr->IoError.BusNumber = 0;
+ PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress;
+ }
+
+ } else if ( CiaError.RcvdMasAbt == 1 ){
+
+ sprintf( OutBuffer,
+ "PCI Master abort occurred, Cmd=%x, Window=%x, Addr=%x\n",
+ PciErr0.Cmd,
+ PciErr0.Window,
+ PciErr1.PciAddress
+ );
+ if(uncorr){
+ uncorr->Flags.ErrorStringValid = 1;
+ strcpy( uncorr->ErrorString, OutBuffer);
+ uncorr->Flags.AddressSpace = IO_SPACE;
+ uncorr->Flags.PhysicalAddressValid = 1;
+ uncorr->PhysicalAddress = PciErr1.PciAddress;
+
+ uncorr->Flags.ExtendedErrorValid = 1;
+ PExtErr->IoError.Interface = PCIBus;
+ PExtErr->IoError.BusNumber = 0;
+ PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress;
+ }
+
+ } else if ( CiaError.RcvdTarAbt == 1 ){
+
+ sprintf( OutBuffer,
+ "PCI Target abort occurred, Cmd=%x, Window=%x, Addr=%x\n",
+ PciErr0.Cmd,
+ PciErr0.Window,
+ PciErr1.PciAddress
+ );
+ if(uncorr){
+ uncorr->Flags.ErrorStringValid = 1;
+ strcpy( uncorr->ErrorString, OutBuffer);
+ uncorr->Flags.AddressSpace = IO_SPACE;
+ uncorr->Flags.PhysicalAddressValid = 1;
+ uncorr->PhysicalAddress = PciErr1.PciAddress;
+
+ uncorr->Flags.ExtendedErrorValid = 1;
+ PExtErr->IoError.Interface = PCIBus;
+ PExtErr->IoError.BusNumber = 0;
+ PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress;
+ }
+
+ } else if ( CiaError.PaPteInv == 1 ){
+
+ sprintf( OutBuffer,
+ "Invalid Scatter/Gather PTE, Cmd=%x, Window=%x, Addr=%x\n",
+ PciErr0.Cmd,
+ PciErr0.Window,
+ PciErr1.PciAddress
+ );
+ if(uncorr){
+ uncorr->Flags.ErrorStringValid = 1;
+ strcpy( uncorr->ErrorString, OutBuffer);
+ uncorr->Flags.AddressSpace = IO_SPACE;
+ uncorr->Flags.PhysicalAddressValid = 1;
+ uncorr->PhysicalAddress = PciErr1.PciAddress;
+
+ uncorr->Flags.ExtendedErrorValid = 1;
+ PExtErr->IoError.Interface = PCIBus;
+ PExtErr->IoError.BusNumber = 0;
+ PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress;
+ }
+
+ } else if ( CiaError.FromWrtErr == 1 ){
+
+ sprintf( OutBuffer,
+ "Write to Flash ROM with FROM_WRT_EN clear"
+ );
+ if(uncorr){
+ uncorr->Flags.ErrorStringValid = 1;
+ strcpy( uncorr->ErrorString, OutBuffer);
+ }
+
+ } else if ( CiaError.IoaTimeout == 1){
+
+ sprintf( OutBuffer,
+ "PCI bus I/O timeout occurred, Cmd=%x, Window=%x, Addr=%x\n",
+ PciErr0.Cmd,
+ PciErr0.Window,
+ PciErr1.PciAddress
+ );
+ if(uncorr){
+ uncorr->Flags.ErrorStringValid = 1;
+ strcpy( uncorr->ErrorString, OutBuffer);
+ uncorr->Flags.AddressSpace = IO_SPACE;
+ uncorr->Flags.PhysicalAddressValid = 1;
+ uncorr->PhysicalAddress = PciErr1.PciAddress;
+
+ uncorr->Flags.ExtendedErrorValid = 1;
+ PExtErr->IoError.Interface = PCIBus;
+ PExtErr->IoError.BusNumber = 0;
+ PExtErr->IoError.BusAddress.LowPart = PciErr1.PciAddress;
+ }
+ }
+
+
+ //
+ // Output the detected error message:
+ //
+
+ HalDisplayString( "\n" );
+ HalDisplayString( OutBuffer );
+
+#if HALDBG
+ DbgPrint( OutBuffer );
+#endif
+
+
+ //
+ // Check for lost errors and output message if any occurred:
+ //
+
+ if ( (CiaError.all & CIA_ERR_LOST_MASK) != 0 ){
+
+ HalDisplayString("\nCIA Lost errors were detected\n\n");
+ }
+
+ return; // Fatal error detected
+}
+
+
+BOOLEAN
+HalpCiaMachineCheck(
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PKEXCEPTION_FRAME ExceptionFrame,
+ IN PKTRAP_FRAME TrapFrame
+ )
+/*++
+
+Routine Description:
+
+ This routine is given control when an hard error is acknowledged
+ by the CIA chipset. The routine is given the chance to
+ correct and dismiss the error.
+
+Arguments:
+
+ ExceptionRecord - Supplies a pointer to the exception record generated
+ at the point of the exception.
+
+ ExceptionFrame - Supplies a pointer to the exception frame generated
+ at the point of the exception.
+
+ TrapFrame - Supplies a pointer to the trap frame generated
+ at the point of the exception.
+
+Return Value:
+
+ TRUE is returned if the machine check has been handled and dismissed -
+ indicating that execution can continue. FALSE is return otherwise.
+
+--*/
+{
+ CIA_ERR CiaError;
+
+ //
+ // Read the CIA error register to determine the source of the
+ // error.
+ //
+
+ CiaError.all = READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr );
+
+#if HALDBG
+
+ DbgPrint( "Cia Mchk: 0x%x\n", CiaError.all );
+
+#endif //HALDBG
+
+ //
+ // Check that an error is valid. If it is not this is a pretty
+ // weird fatal condition.
+ //
+
+ if( CiaError.ErrValid == 0 ){
+ DbgPrint( "Error reported but error valid = 0, CiaErr = 0x%x\n",
+ CiaError.all );
+ goto FatalError;
+ }
+
+ //
+ // Check for any uncorrectable error other than a master abort
+ // on a PCI transaction. Any of these other errors indicate a
+ // fatal condition.
+ //
+
+ if( (CiaError.UnCorErr == 1) || // Uncorrectable error
+ (CiaError.CpuPe == 1) || // Ev5 bus parity error
+ (CiaError.MemNem == 1) || // Nonexistent memory error
+ (CiaError.PciSerr == 1) || // PCI bus serr detected
+ (CiaError.PciPerr == 1) || // PCI bus perr detected
+ (CiaError.PciAddrPe == 1) || // PCI bus address parity error
+ (CiaError.RcvdTarAbt == 1) || // Pci Target Abort
+ (CiaError.PaPteInv == 1) || // Invalid Pte
+ (CiaError.FromWrtErr == 1) || // Invalid write to flash rom
+ (CiaError.IoaTimeout == 1) || // Io Timeout occurred
+ (CiaError.LostUnCorErr == 1) || // Lost uncorrectable error
+ (CiaError.LostCpuPe == 1) || // Lost Ev5 bus parity error
+ (CiaError.LostMemNem == 1) || // Lost Nonexistent memory error
+ (CiaError.LostPciPerr == 1) || // Lost PCI bus perr detected
+ (CiaError.LostPciAddrPe == 1) || // Lost PCI address parity error
+ (CiaError.LostRcvdMasAbt == 1) || // Lost Pci Master Abort
+ (CiaError.LostRcvdTarAbt == 1) || // Lost Pci Target Abort
+ (CiaError.LostPaPteInv == 1) || // Lost Invalid Pte
+ (CiaError.LostFromWrtErr == 1) || // Lost Invalid write to flash rom
+ (CiaError.LostIoaTimeout == 1) // Lost Io Timeout occurred
+ ){
+ DbgPrint( "Explicit fatal error, CiaErr = 0x%x\n",
+ CiaError.all );
+ goto FatalError;
+ }
+
+ //
+ // Check for a PCI configuration read error. The CIA experiences
+ // a master abort on a read to a non-existent PCI slot.
+ //
+
+ if( (CiaError.RcvdMasAbt == 1) && (HalpMasterAbortExpected != 0) ){
+
+ //
+ // So far, the error looks like a PCI configuration space read
+ // that accessed a device that does not exist. In order to fix
+ // this up we expect that the original faulting instruction must
+ // be a load with v0 as the destination register. Unfortunately,
+ // machine checks are not precise exceptions so we may have exectued
+ // many instructions since the faulting load. For EV5 a pair of
+ // memory barrier instructions following the load will stall the pipe
+ // waiting for load completion before the second memory barrier can
+ // be issued. Therefore, we expect the exception PC to point to either
+ // the load instruction of one of the two memory barriers. We will
+ // assume that if the exception pc is not an mb that instead it
+ // points to the load that machine checked. We must be careful to
+ // not reexectute the load.
+ //
+
+ ALPHA_INSTRUCTION FaultingInstruction;
+ BOOLEAN PreviousInstruction = FALSE;
+
+ FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir);
+ if( FaultingInstruction.Memory.Opcode != MEMSPC_OP ){
+
+ //
+ // Exception pc does not point to a memory barrier, return
+ // to the instruction after the exception pc.
+ //
+
+ TrapFrame->Fir += 4;
+
+ }
+
+ //
+ // The error has matched all of our conditions. Fix it up by
+ // writing the value 0xffffffff into the destination of the load.
+ //
+
+ TrapFrame->IntV0 = (ULONGLONG)0xffffffffffffffff;
+
+ //
+ // Clear the error condition in CIA_ERR.
+ //
+
+ CiaError.all = 0;
+ CiaError.RcvdMasAbt = 1;
+ CiaError.ErrValid = 1;
+ WRITE_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr,
+ CiaError.all );
+
+ return TRUE;
+
+ } //end if( (CiaError.RcvdMasAbt == 1) && (HalpMasterAbortExpected != 0) )
+
+ DbgPrint( "Unexpected master abort\n" );
+
+//
+// The system is not well and cannot continue reliable execution.
+// Print some useful messages and return FALSE to indicate that the error
+// was not handled.
+//
+
+FatalError:
+
+ DbgPrint( "Handling fatal error\n" );
+
+ //
+ // Clear the error condition in the MCES register.
+ //
+
+ HalpUpdateMces( TRUE, TRUE );
+
+ //
+ // Proceed to display the error.
+ //
+
+ HalAcquireDisplayOwnership(NULL);
+
+ //
+ // Display the dreaded banner.
+ //
+
+ HalDisplayString( "\nFatal system hardware error.\n\n" );
+
+
+ HalpCiaReportFatalError();
+
+ return( FALSE );
+
+}
+
+BOOLEAN
+HalpTranslateSynToEcc(
+ PULONG Syndrome
+ )
+/*++
+
+Routine Description:
+
+ Translate a syndrome code to ECC error bit code.
+
+Arguments:
+
+ Syndrome - pointer to the syndrome.
+
+Return Value:
+
+ True if a data bit is in error. False otherwise.
+
+--*/
+{
+ static UCHAR SynToEccTable[0xff] = {0, };
+ static BOOLEAN SynToEccTableInitialized = FALSE;
+ ULONG Temp;
+
+ //
+ // Initialize the table.
+ //
+
+ if (!SynToEccTableInitialized) {
+
+ SynToEccTableInitialized = TRUE;
+
+ //
+ // Fill in the table.
+ //
+
+ SynToEccTable[0x01] = 0;
+ SynToEccTable[0x02] = 1;
+ SynToEccTable[0x04] = 2;
+ SynToEccTable[0x08] = 3;
+ SynToEccTable[0x10] = 4;
+ SynToEccTable[0x20] = 5;
+ SynToEccTable[0x40] = 6;
+ SynToEccTable[0x80] = 7;
+ SynToEccTable[0xce] = 0;
+ SynToEccTable[0xcb] = 1;
+ SynToEccTable[0xd3] = 2;
+ SynToEccTable[0xd5] = 3;
+ SynToEccTable[0xd6] = 4;
+ SynToEccTable[0xd9] = 5;
+ SynToEccTable[0xda] = 6;
+ SynToEccTable[0xdc] = 7;
+ SynToEccTable[0x23] = 8;
+ SynToEccTable[0x25] = 9;
+ SynToEccTable[0x26] = 10;
+ SynToEccTable[0x29] = 11;
+ SynToEccTable[0x2a] = 12;
+ SynToEccTable[0x2c] = 13;
+ SynToEccTable[0x31] = 14;
+ SynToEccTable[0x34] = 15;
+ SynToEccTable[0x0e] = 16;
+ SynToEccTable[0x0b] = 17;
+ SynToEccTable[0x13] = 18;
+ SynToEccTable[0x15] = 19;
+ SynToEccTable[0x16] = 20;
+ SynToEccTable[0x19] = 21;
+ SynToEccTable[0x1a] = 22;
+ SynToEccTable[0x1c] = 23;
+ SynToEccTable[0xe3] = 24;
+ SynToEccTable[0xe5] = 25;
+ SynToEccTable[0xe6] = 26;
+ SynToEccTable[0xe9] = 27;
+ SynToEccTable[0xea] = 28;
+ SynToEccTable[0xec] = 29;
+ SynToEccTable[0xf1] = 30;
+ SynToEccTable[0xf4] = 31;
+ SynToEccTable[0x4f] = 32;
+ SynToEccTable[0x4a] = 33;
+ SynToEccTable[0x52] = 34;
+ SynToEccTable[0x54] = 35;
+ SynToEccTable[0x57] = 36;
+ SynToEccTable[0x58] = 37;
+ SynToEccTable[0x5b] = 38;
+ SynToEccTable[0x5d] = 39;
+ SynToEccTable[0xa2] = 40;
+ SynToEccTable[0xa4] = 41;
+ SynToEccTable[0xa7] = 42;
+ SynToEccTable[0xa8] = 43;
+ SynToEccTable[0xab] = 44;
+ SynToEccTable[0xad] = 45;
+ SynToEccTable[0xb0] = 46;
+ SynToEccTable[0xb5] = 47;
+ SynToEccTable[0x8f] = 48;
+ SynToEccTable[0x8a] = 49;
+ SynToEccTable[0x92] = 50;
+ SynToEccTable[0x94] = 51;
+ SynToEccTable[0x97] = 52;
+ SynToEccTable[0x98] = 53;
+ SynToEccTable[0x9b] = 54;
+ SynToEccTable[0x9d] = 55;
+ SynToEccTable[0x62] = 56;
+ SynToEccTable[0x64] = 57;
+ SynToEccTable[0x67] = 58;
+ SynToEccTable[0x68] = 59;
+ SynToEccTable[0x6b] = 60;
+ SynToEccTable[0x6d] = 61;
+ SynToEccTable[0x70] = 62;
+ SynToEccTable[0x75] = 63;
+ }
+
+ //
+ // Tranlate the syndrome code.
+ //
+
+ Temp = *Syndrome;
+ *Syndrome = SynToEccTable[Temp];
+
+ //
+ // Is it a data bit or a check bit in error?
+ //
+
+ if (Temp == 0x01 || Temp == 0x02 || Temp == 0x04 || Temp == 0x08 ||
+ Temp == 0x10 || Temp == 0x20 || Temp == 0x40 || Temp == 0x80) {
+
+ return FALSE;
+
+ } else {
+
+ return TRUE;
+ }
+}
+
+
+
+VOID
+HalpCiaErrorInterrupt(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Handle a CIA correctable error interrupt.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ static ERROR_FRAME Frame;
+ static CIA_CORRECTABLE_FRAME AlcorFrame;
+
+ ERROR_FRAME TempFrame;
+ PCORRECTABLE_ERROR CorrPtr;
+ PBOOLEAN ErrorlogBusy;
+ PULONG DispatchCode;
+ ULONG Syndrome;
+ PKINTERRUPT InterruptObject;
+ PKSPIN_LOCK ErrorlogSpinLock;
+
+ CIA_ERR CiaError;
+ CIA_STAT CiaStat;
+ CIA_SYN CiaSyn;
+ CIA_MEM_ERR0 MemErr0;
+ CIA_MEM_ERR1 MemErr1;
+ CIA_PCI_ERR0 PciErr0;
+ CIA_PCI_ERR1 PciErr1;
+ CIA_PCI_ERR2 PciErr2;
+
+ //
+ // The error is expected to be a corrected ECC error on a DMA or
+ // Scatter/Gather TLB read/write. Read the error registers relevant
+ // to this error.
+ //
+
+ CiaError.all = READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr );
+
+ //
+ // Check if an error is latched into the CIA.
+ //
+
+ if( CiaError.ErrValid == 0 ){
+
+#if HALDBG
+
+ DbgPrint( "Cia error interrupt without valid CIA error\n" );
+
+#endif //HALDBG
+
+ return;
+ }
+
+ //
+ // Check for the correctable error bit.
+ //
+
+ if( CiaError.CorErr == 0 ){
+
+#if HALDBG
+
+ DbgPrint( "Cia error interrupt without correctable error indicated\n" );
+
+#endif //HALDBG
+
+ }
+
+ //
+ // Real error, get the interrupt object.
+ //
+
+ DispatchCode = (PULONG)(PCR->InterruptRoutine[CORRECTABLE_VECTOR]);
+ InterruptObject = CONTAINING_RECORD(DispatchCode,
+ KINTERRUPT,
+ DispatchCode);
+
+ //
+ // Set various pointers so we can use them later.
+ //
+
+ CorrPtr = &TempFrame.CorrectableFrame;
+ ErrorlogBusy = (PBOOLEAN)((PUCHAR)InterruptObject->ServiceContext +
+ sizeof(PERROR_FRAME));
+ ErrorlogSpinLock = (PKSPIN_LOCK)((PUCHAR)ErrorlogBusy + sizeof(PBOOLEAN));
+
+ //
+ // Clear the data structures that we will use.
+ //
+
+ RtlZeroMemory(&TempFrame, sizeof(ERROR_FRAME));
+
+ //
+ // Increment the number of CIA correctable errors.
+ //
+
+ CiaCorrectedErrors += 1;
+
+ CiaStat.all = READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaStat );
+
+ CiaSyn.all = READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaSyn );
+
+ MemErr0.all = READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->MemErr0 );
+
+ MemErr1.all = READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->MemErr1 );
+
+ PciErr0.all = READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr0 );
+
+ PciErr1.PciAddress = READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr1 );
+
+ PciErr2.PciAddress = READ_CIA_REGISTER(
+ &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->PciErr2 );
+
+
+ //
+ // Print a correctable error message to the debugger.
+ //
+
+#if HALDBG
+ DbgPrint( "CIA Correctable Error Number %d, state follows: \n",
+ CiaCorrectedErrors );
+ DbgPrint( "\tCIA_ERR : 0x%x\n", CiaError.all );
+ DbgPrint( "\tCIA_STAT: 0x%x\n", CiaStat.all );
+ DbgPrint( "\tCIA_SYN : 0x%x\n", CiaSyn.all );
+ DbgPrint( "\tCIA_MEM0: 0x%x\n", MemErr0.all );
+ DbgPrint( "\tCIA_MEM1: 0x%x\n", MemErr1.all );
+ DbgPrint( "\tPCI_ERR0: 0x%x\n", PciErr0.all );
+#endif //HALDBG
+
+ //
+ // Fill in the error frame information.
+ //
+
+ TempFrame.Signature = ERROR_FRAME_SIGNATURE;
+ TempFrame.FrameType = CorrectableFrame;
+ TempFrame.VersionNumber = ERROR_FRAME_VERSION;
+ TempFrame.SequenceNumber = CiaCorrectedErrors;
+ TempFrame.PerformanceCounterValue =
+ KeQueryPerformanceCounter(NULL).QuadPart;
+
+ //
+ // Check for lost error.
+ //
+
+ if( CiaError.LostCorErr ) {
+
+ //
+ // Since the error registers are locked from a previous error,
+ // we don't know where the error came from. Mark everything
+ // as UNIDENTIFIED.
+ //
+
+ CorrPtr->Flags.LostCorrectable = 1;
+ CorrPtr->Flags.LostAddressSpace = UNIDENTIFIED;
+ CorrPtr->Flags.LostMemoryErrorSource = UNIDENTIFIED;
+ }
+
+ //
+ // Set error bit error masks.
+ //
+
+ CorrPtr->Flags.ErrorBitMasksValid = 1;
+ Syndrome = CiaSyn.all;
+
+ if ( HalpTranslateSynToEcc(&Syndrome) )
+ CorrPtr->DataBitErrorMask = 1 << Syndrome;
+ else
+ CorrPtr->CheckBitErrorMask = 1 << Syndrome;
+
+ //
+ // Determine error type.
+ //
+ switch (CiaStat.DmSt) {
+
+ case CIA_IO_WRITE_ECC:
+
+ //
+ // I/O write ECC error occurred.
+ //
+
+ CorrPtr->Flags.AddressSpace = IO_SPACE;
+
+ CorrPtr->Flags.ExtendedErrorValid = 1;
+ CorrPtr->ErrorInformation.IoError.Interface = PCIBus;
+ CorrPtr->ErrorInformation.IoError.BusNumber = 0;
+ CorrPtr->ErrorInformation.IoError.BusAddress.LowPart= PciErr1.PciAddress;
+ CorrPtr->ErrorInformation.IoError.TransferType = BUS_IO_WRITE;
+ break;
+
+ case CIA_DMA_READ_ECC:
+
+ CorrPtr->Flags.AddressSpace = MEMORY_SPACE;
+ CorrPtr->Flags.ExtendedErrorValid = 1;
+
+ //
+ // Where did the error come from?
+ //
+
+ if ( CiaStat.PaCpuRes == CIA_PROCESSOR_CACHE_ECC ) {
+
+ //
+ // Correctable error comes from processor cache.
+ //
+
+ CorrPtr->Flags.MemoryErrorSource = PROCESSOR_CACHE;
+
+ //
+ // DMA read or TLB miss error occurred.
+ //
+
+ if ( CiaStat.TlbMiss )
+ CorrPtr->ErrorInformation.CacheError.TransferType = TLB_MISS_READ;
+ else
+ CorrPtr->ErrorInformation.CacheError.TransferType = BUS_DMA_READ;
+
+ } else if ( CiaStat.PaCpuRes == CIA_SYSTEM_CACHE_ECC ) {
+
+ //
+ // Correctable error comes from system cache.
+ //
+
+ CorrPtr->Flags.MemoryErrorSource = SYSTEM_CACHE;
+
+ //
+ // DMA read or TLB miss error occurred.
+ //
+
+ if ( CiaStat.TlbMiss )
+ CorrPtr->ErrorInformation.CacheError.TransferType = TLB_MISS_READ;
+ else
+ CorrPtr->ErrorInformation.CacheError.TransferType = BUS_DMA_READ;
+
+ } else {
+
+ //
+ // Correctable error comes from system memory.
+ //
+
+ CorrPtr->Flags.MemoryErrorSource = SYSTEM_MEMORY;
+
+ //
+ // DMA read or TLB miss error occurred.
+ //
+
+ if ( CiaStat.TlbMiss )
+ CorrPtr->ErrorInformation.MemoryError.TransferType = TLB_MISS_READ;
+ else
+ CorrPtr->ErrorInformation.MemoryError.TransferType = BUS_DMA_READ;
+ }
+
+ break;
+
+ case CIA_DMA_WRITE_ECC:
+
+ CorrPtr->Flags.AddressSpace = MEMORY_SPACE;
+ CorrPtr->Flags.ExtendedErrorValid = 1;
+
+ //
+ // Where did the error come from?
+ //
+
+ if ( CiaStat.PaCpuRes == CIA_PROCESSOR_CACHE_ECC ) {
+
+ //
+ // Correctable error comes from processor cache.
+ //
+
+ CorrPtr->Flags.MemoryErrorSource = PROCESSOR_CACHE;
+
+ //
+ // DMA write or TLB miss error occurred.
+ //
+
+ if ( CiaStat.TlbMiss )
+ CorrPtr->ErrorInformation.CacheError.TransferType = TLB_MISS_WRITE;
+ else
+ CorrPtr->ErrorInformation.CacheError.TransferType = BUS_DMA_WRITE;
+
+ } else if ( CiaStat.PaCpuRes == CIA_SYSTEM_CACHE_ECC ) {
+
+ //
+ // Correctable error comes from system cache.
+ //
+
+ CorrPtr->Flags.MemoryErrorSource = SYSTEM_CACHE;
+
+ //
+ // DMA write or TLB miss error occurred.
+ //
+
+ if ( CiaStat.TlbMiss )
+ CorrPtr->ErrorInformation.CacheError.TransferType = TLB_MISS_WRITE;
+ else
+ CorrPtr->ErrorInformation.CacheError.TransferType = BUS_DMA_WRITE;
+
+ } else {
+
+ //
+ // Correctable error comes from system memory.
+ //
+
+ CorrPtr->Flags.MemoryErrorSource = SYSTEM_MEMORY;
+
+ //
+ // DMA write or TLB miss error occurred.
+ //
+
+ if ( CiaStat.TlbMiss )
+ CorrPtr->ErrorInformation.MemoryError.TransferType = TLB_MISS_WRITE;
+ else
+ CorrPtr->ErrorInformation.MemoryError.TransferType = BUS_DMA_WRITE;
+
+ //
+ //
+ }
+
+ break;
+
+ case CIA_IO_READ_ECC:
+
+ //
+ // I/O read ECC error occurred.
+ //
+
+ CorrPtr->Flags.AddressSpace = IO_SPACE;
+
+ CorrPtr->Flags.ExtendedErrorValid = 1;
+ CorrPtr->ErrorInformation.IoError.Interface = PCIBus;
+ CorrPtr->ErrorInformation.IoError.BusNumber = 0;
+ CorrPtr->ErrorInformation.IoError.BusAddress.LowPart= PciErr1.PciAddress;
+ CorrPtr->ErrorInformation.IoError.TransferType = BUS_IO_READ;
+ break;
+
+ default:
+
+ //
+ // Something strange happened. Don't know where the error occurred.
+ //
+
+ CorrPtr->Flags.AddressSpace = UNIDENTIFIED;
+ break;
+ }
+
+ //
+ // Get the physical address where the error occurred.
+ //
+
+ CorrPtr->Flags.PhysicalAddressValid = 1;
+ CorrPtr->PhysicalAddress = (MemErr1.all & 0xff) << 32;
+ CorrPtr->PhysicalAddress |= MemErr0.all;
+
+ //
+ // Get bits 7:0 of the address from the PCI address.
+ //
+
+ CorrPtr->PhysicalAddress |= PciErr1.PciAddress & 0xff;
+
+ //
+ // Scrub the error if it's any type of memory error.
+ //
+
+ if ( CorrPtr->Flags.AddressSpace == MEMORY_SPACE &&
+ CorrPtr->Flags.PhysicalAddressValid )
+ CorrPtr->Flags.ScrubError = 1;
+
+ //
+ // Acquire the spinlock.
+ //
+
+ KiAcquireSpinLock(ErrorlogSpinLock);
+
+ //
+ // Check to see if an errorlog operation is in progress already.
+ //
+
+ if (!*ErrorlogBusy) {
+
+ //
+ // The error is expected to be a corrected ECC error on a DMA or
+ // Scatter/Gather TLB read/write. Read the error registers relevant
+ // to this error.
+ //
+
+ AlcorFrame.CiaErr = CiaError.all;
+
+ AlcorFrame.CiaStat = CiaStat.all;
+
+ AlcorFrame.CiaSyn = CiaSyn.all;
+
+ AlcorFrame.MemErr0 = MemErr0.all;
+
+ AlcorFrame.MemErr1 = MemErr1.all;
+
+ AlcorFrame.PciErr0 = PciErr0.all;
+
+ AlcorFrame.PciErr1 = PciErr1.PciAddress;
+
+ AlcorFrame.PciErr2 = PciErr2.PciAddress;
+
+ //
+ // Read the CIA configuration registers for logging information.
+ //
+
+ AlcorFrame.Configuration.CiaRev =
+ READ_CIA_REGISTER( &((PCIA_GENERAL_CSRS)
+ (CIA_GENERAL_CSRS_QVA))->CiaRevision );
+
+ AlcorFrame.Configuration.CiaCtrl =
+ READ_CIA_REGISTER( &((PCIA_GENERAL_CSRS)
+ (CIA_GENERAL_CSRS_QVA))->CiaCtrl );
+
+ AlcorFrame.Configuration.Mcr =
+ READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS)
+ (CIA_MEMORY_CSRS_QVA))->Mcr );
+
+ AlcorFrame.Configuration.Mba0 =
+ READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS)
+ (CIA_MEMORY_CSRS_QVA))->Mba0 );
+
+ AlcorFrame.Configuration.Mba2 =
+ READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS)
+ (CIA_MEMORY_CSRS_QVA))->Mba2 );
+
+ AlcorFrame.Configuration.Mba4 =
+ READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS)
+ (CIA_MEMORY_CSRS_QVA))->Mba4 );
+
+ AlcorFrame.Configuration.Mba6 =
+ READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS)
+ (CIA_MEMORY_CSRS_QVA))->Mba6 );
+
+ AlcorFrame.Configuration.Mba8 =
+ READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS)
+ (CIA_MEMORY_CSRS_QVA))->Mba8 );
+
+ AlcorFrame.Configuration.MbaA =
+ READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS)
+ (CIA_MEMORY_CSRS_QVA))->MbaA );
+
+ AlcorFrame.Configuration.MbaC =
+ READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS)
+ (CIA_MEMORY_CSRS_QVA))->MbaC );
+
+ AlcorFrame.Configuration.MbaE =
+ READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS)
+ (CIA_MEMORY_CSRS_QVA))->MbaE );
+
+ AlcorFrame.Configuration.Tmg0 =
+ READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS)
+ (CIA_MEMORY_CSRS_QVA))->Tmg0 );
+
+ AlcorFrame.Configuration.Tmg1 =
+ READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS)
+ (CIA_MEMORY_CSRS_QVA))->Tmg1 );
+
+ AlcorFrame.Configuration.Tmg2 =
+ READ_CIA_REGISTER( &((PCIA_MEMORY_CSRS)
+ (CIA_MEMORY_CSRS_QVA))->Tmg2 );
+
+ AlcorFrame.Configuration.CacheCnfg =
+ PCR->SecondLevelCacheSize;
+
+ //
+ // Set the raw system information.
+ //
+
+ CorrPtr->RawSystemInformationLength = sizeof(CIA_CORRECTABLE_FRAME);
+ CorrPtr->RawSystemInformation = &AlcorFrame;
+
+ //
+ // Set the raw processor information. Disregard at the moment.
+ //
+
+ CorrPtr->RawProcessorInformationLength = 0;
+
+ //
+ // Set reporting processor information. Disregard at the moment.
+ //
+
+ CorrPtr->Flags.ProcessorInformationValid = 0;
+
+ //
+ // Set system information. Disregard at the moment.
+ //
+
+ CorrPtr->Flags.SystemInformationValid = 0;
+
+ //
+ // Copy the information that we need to log.
+ //
+
+ RtlCopyMemory(&Frame,
+ &TempFrame,
+ sizeof(ERROR_FRAME));
+
+ //
+ // Put frame into ISR service context.
+ //
+
+ *(PERROR_FRAME *)InterruptObject->ServiceContext = &Frame;
+
+ } else {
+
+ //
+ // An errorlog operation is in progress already. We will
+ // set various lost bits and then get out without doing
+ // an actual errorloging call.
+ //
+
+ Frame.CorrectableFrame.Flags.LostCorrectable = TRUE;
+ Frame.CorrectableFrame.Flags.LostAddressSpace =
+ TempFrame.CorrectableFrame.Flags.AddressSpace;
+ Frame.CorrectableFrame.Flags.LostMemoryErrorSource =
+ TempFrame.CorrectableFrame.Flags.MemoryErrorSource;
+ }
+
+ //
+ // Release the spinlock.
+ //
+
+ KiReleaseSpinLock(ErrorlogSpinLock);
+
+ //
+ // Dispatch to the secondary correctable interrupt service routine.
+ // The assumption here is that if this interrupt ever happens, then
+ // some driver enabled it, and the driver should have the ISR connected.
+ //
+
+ ((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)(
+ InterruptObject,
+ InterruptObject->ServiceContext
+ );
+
+
+ //
+ // Clear the corrected error status bit and return to continue
+ // execution.
+ //
+
+ CiaError.all = 0;
+ CiaError.CorErr = 1;
+ WRITE_CIA_REGISTER( &((PCIA_ERROR_CSRS)(CIA_ERROR_CSRS_QVA))->CiaErr,
+ CiaError.all );
+
+ return;
+
+}
diff --git a/private/ntos/nthals/halalpha/ciaio.s b/private/ntos/nthals/halalpha/ciaio.s
new file mode 100644
index 000000000..073a25ea6
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ciaio.s
@@ -0,0 +1,2820 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ ciaio.s
+
+Abstract:
+
+ This module implements the I/O access routines for the CIA ASIC.
+
+ The module contains the functions to turn quasi virtual
+ addresses into an Alpha superpage virtual address
+ and then read or write based on the request.
+
+Author:
+
+ Steve Brooks 1-Jul-1994
+ Joe Notarangelo 1-Jul-1994
+
+Environment:
+
+ Executes in kernel mode.
+
+Revision History:
+
+
+--*/
+
+#include "cia.h"
+#include "halalpha.h"
+
+
+//
+// Superpage VAs
+//
+// The following constants are used to construct the physical addresses
+// used to access i/o space.
+//
+// assembler BUGBUG:
+//
+// The following values are hacks to get around the intelligent
+// Alpha assemblers. Instead of sign extending 16 bit quantities greater
+// than 32K-1, the assembler generates a ldah/lda pair to load exactly
+// the sixteen bit quantity specified, without sign extending.
+//
+// By specifying the quantity as a negative number, the assembler allows
+// a single lda instruction, with sign extension.
+//
+
+#define CIA_DENSE_MEM_SVA -0x37a0 // negative of 0xc860
+#define CIA_SPARSE_MEM_SVA -0x3800 // negative of 0xc800
+#define CIA_SPARSE_IO_SVA -0x37a8 // negative of 0xc858
+#define CIA_PCI_CONFIG_SVA -0x3790 // negative of 0xc870
+#define CIA_REGISTER_SVA -0x3790 // negative of 0xc870
+#define CIA_PCI_INTACK_SVA -0x378e // negative of 0xc872
+
+
+ SBTTL( "Read byte from PCI memory" )
+//++
+//
+// UCHAR
+// READ_REGISTER_UCHAR(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a byte location in PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the I/O byte to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from I/O space.
+//
+//--
+
+ LEAF_ENTRY(READ_REGISTER_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get byte lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+//
+// Sparse space access.
+//
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800
+ sll t4, 28, t4 // 0xffff fc80 0000 0000
+ or t0, t4, t0 // superpage mode
+
+ ldl v0, (t0) // get the longword
+ extbl v0, t3, v0 // get correct byte if eisa
+
+ ret zero, (ra) // return
+
+//
+// Dense space access.
+//
+
+10:
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, 3, t3 // capture byte offset
+ bic a0, 3, a0 // clear byte offset
+ lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860
+ sll t0, 28, t0 // 0xffff fc86 0000 0000
+ bis t0, a0, t0 // 0xffff fc86 xxxx xxxx
+ mb // ensure all writes are visible
+ ldl v0, 0(t0) // read from dense space
+ extbl v0, t3, v0 // extract appropriate byte
+
+ ret zero, (ra) // return
+
+ .end READ_REGISTER_UCHAR
+
+
+
+ SBTTL( "Read byte from PCI sparse i/o" )
+//++
+//
+// UCHAR
+// READ_PORT_UCHAR(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a byte location in PCI bus sparse i/o space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the I/O byte to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from I/O space.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get byte lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff c858 0000
+ sll t4, 28, t4 // 0xffff fc85 8000 0000
+ or t0, t4, t0 // superpage mode
+
+ mb // ensure all writes are visible
+ ldl v0, (t0) // get the longword
+ extbl v0, t3, v0 // get correct byte if eisa
+
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+10:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ldil v0, 0xffffffff // return fixed value
+
+ ret zero, (ra) // return to caller
+
+ .end READ_PORT_UCHAR
+
+
+ SBTTL( "Read short from PCI memory" )
+//++
+//
+// UCHAR
+// READ_REGISTER_USHORT(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a short location in PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the memory short to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from PCI memory.
+//
+//--
+
+ LEAF_ENTRY(READ_REGISTER_USHORT)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get short lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+//
+// Sparse space access.
+//
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800
+ sll t4, 28, t4 // 0xffff fc80 0000 0000
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_WORD_LEN, t0 // set size to short
+
+ mb // ensure all writes are visible
+ ldl v0, (t0) // get the longword
+ extwl v0, t3, v0 // get correct byte if eisa
+
+ ret zero, (ra) // return
+
+//
+// Dense space access.
+//
+
+10:
+ zap a0, 0xf0, a0 // clear <63:32>
+ and a0, 3, t3 // capture byte offset
+ bic a0, 3, a0 // clear byte offset
+ lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860
+ sll t0, 28, t0 // 0xffff fc86 0000 0000
+ bis t0, a0, t0 // 0xffff fc86 xxxx xxxx
+ ldl v0, 0(t0) // read from dense space
+ extwl v0, t3, v0 // extract appropriate word
+
+ ret zero, (ra) // return
+
+ .end READ_REGISTER_USHORT
+
+
+ SBTTL( "Read short from PCI sparse I/O" )
+//++
+//
+// UCHAR
+// READ_PORT_USHORT(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a short location in PCI bus sparse i/o space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the i/o short to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from PCI I/O.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_USHORT)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get short lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858
+ sll t4, 28, t4 // 0xffff fc85 8000 0000
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_WORD_LEN, t0 // set size to short
+
+ mb // ensure all writes are visible
+ ldl v0, (t0) // get the longword
+ extwl v0, t3, v0 // get correct byte if eisa
+
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+10:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ldil v0, 0xffffffff // return fixed value
+
+ ret zero, (ra) // return to caller
+
+ .end READ_PORT_USHORT
+
+
+ SBTTL( "Read long from PCI memory" )
+//++
+//
+// UCHAR
+// READ_REGISTER_ULONG(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a long location in PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the memory long to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from PCI memory.
+//
+//--
+
+ LEAF_ENTRY(READ_REGISTER_ULONG)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+//
+// Sparse space access.
+//
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800
+ sll t4, 28, t4 // 0xffff fc80 0000 0000
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_LONG_LEN, t0 // set size to long
+
+ mb // ensure all writes are visible
+ ldl v0, (t0) // get the longword
+
+ ret zero, (ra) // return
+
+//
+// Dense space access.
+//
+
+10:
+ zap a0, 0xf0, a0 // clear <63:32>
+ lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860
+ sll t0, 28, t0 // 0xffff fc86 0000 0000
+ bis t0, a0, t0 // 0xffff fc86 xxxx xxxx
+ ldl v0, 0(t0) // read from dense space
+
+ ret zero, (ra) // return
+
+ .end READ_REGISTER_ULONG
+
+
+ SBTTL( "Read long from PCI sparse I/O" )
+//++
+//
+// UCHAR
+// READ_PORT_ULONG(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Reads a long location in PCI bus sparse i/o space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the i/o long to read.
+//
+// Return Value:
+//
+// v0 - Returns the value read from PCI I/O.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_ULONG)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get short lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c800
+ sll t4, 28, t4 // 0xffff fc80 0000 0000
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_LONG_LEN, t0 // set size to short
+
+ mb // ensure all writes are visible
+ ldl v0, (t0) // get the longword
+
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+10:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ldil v0, 0xffffffff // return fixed value
+
+ ret zero, (ra) // return to caller
+
+ .end READ_PORT_ULONG
+
+
+ SBTTL( "Write byte to PCI memory" )
+//++
+//
+// VOID
+// WRITE_REGISTER_UCHAR(
+// IN PVOID RegisterQva
+// IN UCHAR Value
+// )
+//
+// Routine Description:
+//
+// Write a byte location to PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the memory byte to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_REGISTER_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get byte lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+//
+// Sparse space access.
+//
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800
+ sll t4, 28, t4 // 0xffff fc80 0000 0000
+ or t0, t4, t0 // superpage mode
+
+ insbl a1, t3, v0 // insert to proper byte lane
+ stl v0, (t0) // store the longword
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Dense space access.
+//
+
+10:
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, 3, a0 // clear byte offset
+ lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860
+ sll t0, 28, t0 // 0xffff fc86 0000 0000
+ bis t0, a0, t0 // 0xffff fc86 xxxx xxxx
+
+ ldl t1, (t0) // get the long
+ mskbl t1, t3, t1 // mask the proper byte
+
+ insbl a1, t3, a1 // insert to appropriate byte lane
+ bis a1, t1, a1 // merge byte in result
+ stl a1, (t0) // write to dense space
+ mb // order subsequent reads/writes
+
+ ret zero, (ra) // return
+
+ .end WRITE_REGISTER_UCHAR
+
+
+ SBTTL( "Write byte to PCI sparse i/o" )
+//++
+//
+// VOID
+// WRITE_PORT_UCHAR(
+// IN PVOID RegisterQva
+// IN UCHAR Value
+// )
+//
+// Routine Description:
+//
+// Write a byte location to PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the memory byte to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get byte lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858
+ sll t4, 28, t4 // 0xffff fc85 8000 0000
+ or t0, t4, t0 // superpage mode
+
+ insbl a1, t3, v0 // insert to proper byte lane
+ stl v0, (t0) // store the longword
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+10:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ret zero, (ra) // return to caller
+
+ .end WRITE_PORT_UCHAR
+
+
+ SBTTL( "Write short to PCI memory" )
+//++
+//
+// VOID
+// WRITE_REGISTER_USHORT(
+// IN PVOID RegisterQva
+// IN UCHAR Value
+// )
+//
+// Routine Description:
+//
+// Write a short to PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the memory short to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_REGISTER_USHORT)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get short lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+//
+// Sparse space access.
+//
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800
+ sll t4, 28, t4 // 0xffff fc80 0000 0000
+ or t0, t4, t0 // superpage mode
+
+ bis t0, IO_WORD_LEN, t0 // set size to short
+
+ inswl a1, t3, v0 // insert to proper short lane
+ stl v0, (t0) // store the longword
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Dense space access.
+//
+
+10:
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, 3, a0 // clear byte offset
+ lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860
+ sll t0, 28, t0 // 0xffff fc86 0000 0000
+ bis t0, a0, t0 // 0xffff fc86 xxxx xxxx
+ ldl t1, (t0) // get the long
+ mskwl t1, t3, t1 // mask the proper word
+ inswl a1, t3, a1 // insert to appropriate short lane
+ bis a1, t1, a1 // merge in result
+ stl a1, (t0) // write to dense space
+ mb // order subsequent reads/writes
+
+ ret zero, (ra) // return
+
+ .end WRITE_REGISTER_USHORT
+
+
+ SBTTL( "Write short to PCI sparse i/o" )
+//++
+//
+// VOID
+// WRITE_PORT_USHORT(
+// IN PVOID RegisterQva
+// IN UCHAR Value
+// )
+//
+// Routine Description:
+//
+// Write a byte location to PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the memory byte to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_USHORT)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 3, t3 // get short lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858
+ sll t4, 28, t4 // 0xffff fc85 8000 0000
+ or t0, t4, t0 // superpage mode
+
+ bis t0, IO_WORD_LEN, t0 // set size to short
+
+ inswl a1, t3, v0 // insert to proper short lane
+ stl v0, (t0) // store the longword
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+10:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ret zero, (ra) // return to caller
+
+ .end WRITE_PORT_USHORT
+
+
+
+ SBTTL( "Write long to PCI memory" )
+//++
+//
+// VOID
+// WRITE_REGISTER_ULONG(
+// IN PVOID RegisterQva
+// IN UCHAR Value
+// )
+//
+// Routine Description:
+//
+// Write a long to PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the memory long to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_REGISTER_ULONG)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+//
+// Sparse space access.
+//
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800
+ sll t4, 28, t4 // 0xffff fc80 0000 0000
+ or t0, t4, t0 // superpage mode
+
+ bis t0, IO_LONG_LEN, t0 // set size to long
+
+ stl a1, (t0) // store the longword
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Dense space access.
+//
+
+10:
+ zap a0, 0xf0, a0 // clear <63:32>
+ lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860
+ sll t0, 28, t0 // 0xffff fc86 0000 0000
+ bis t0, a0, t0 // 0xffff fc86 xxxx xxxx
+ stl a1, 0(t0) // write to dense space
+ mb // order subsequent reads/writes
+
+ ret zero, (ra) // return
+
+ .end WRITE_REGISTER_ULONG
+
+
+ SBTTL( "Write long to PCI sparse i/o" )
+//++
+//
+// VOID
+// WRITE_PORT_ULONG(
+// IN PVOID RegisterQva
+// IN UCHAR Value
+// )
+//
+// Routine Description:
+//
+// Write a long to PCI bus sparse memory space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of the I/O long to write.
+//
+// Value(a1) - Supplies the value written to I/O space.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_ULONG)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858
+ sll t4, 28, t4 // 0xffff fc85 8000 0000
+ or t0, t4, t0 // superpage mode
+
+ bis t0, IO_LONG_LEN, t0 // set size to long
+
+ stl a1, (t0) // store the longword
+ mb // order the write
+
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+10:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ret zero, (ra) // return to caller
+
+ .end WRITE_PORT_ULONG
+
+
+ SBTTL( "Write CIA Register" )
+//++
+//
+// VOID
+// WRITE_CIA_REGISTER(
+// IN PVOID RegisterQva,
+// IN ULONG Value
+// )
+//
+// Routine Description:
+//
+// Write a CIA control register.
+//
+// Arguments:
+//
+// RegisterQva(a0) - QVA of control register to be written.
+//
+// Value(a1) - Longword value to be written to the control register.
+//
+// Return Value:
+//
+// None.
+//
+// N.B. Since the physical address of the CIA CSRS exceed the 34 bit
+// capacity of the QVAs, the QVA values of the CIA CSRS specify
+// the offset of the QVAs from the CIA CSR base address (87.4000.0000)
+//--
+
+ LEAF_ENTRY(WRITE_CIA_REGISTER)
+
+ ALTERNATE_ENTRY(WRITE_GRU_REGISTER)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, 5, t0 //
+ lda t4, CIA_REGISTER_SVA(zero) // 0xffff ffff ffff c870
+ sll t4, 28, t4 // 0xffff fc87 0000 0000
+ or t0, t4, t0 // superpage mode
+ stl a1, (t0) // write the longword
+ mb // order the write
+ ret zero, (ra) // return
+
+10:
+ BREAK_DEBUG_STOP // take a breakpoint
+ ret zero, (ra) // return
+
+ .end WRITE_CIA_REGISTER
+
+
+ SBTTL( "Read Control Register" )
+//++
+//
+// ULONG
+// READ_CIA_REGISTER(
+// IN PVOID RegisterQva
+// )
+//
+// Routine Description:
+//
+// Read a CIA Control register
+//
+// Arguments:
+//
+// RegisterQva(a0) - QVA of control register to be written.
+//
+// Return Value:
+//
+// v0 - Return the value read from the control register.
+//
+//--
+
+ LEAF_ENTRY(READ_CIA_REGISTER)
+
+ ALTERNATE_ENTRY(READ_GRU_REGISTER)
+
+//
+// Generate the superpage address of the requested CIA register.
+//
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 20f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, 5, t0 //
+ lda t4, CIA_REGISTER_SVA(zero) // 0xffff ffff ffff c870
+ sll t4, 28, t4 // 0xffff fc87 0000 0000
+ or t0, t4, t0 // superpage mode
+
+//
+// Read the CIA revision saved in a global variable.
+//
+
+ lda t1, HalpCiaRevision // get revision id global address
+ ldl t1, 0(t1) // get revision id
+ bne t1, 10f // if ne, not pass 1 CIA
+
+//
+// Pass 1 CIA required the following work-around to avoid IBOX timeout
+// errors.
+//
+
+ ldil t5, 100 // iterations to wait for istream
+ // prefetches to settle
+
+1:
+ subl t5, 1, t5 // decrement wait count
+ bgt t5, 2f // continue wait until count = 0
+
+ mb // wait for write buffer
+ ldl v0, (t0) // read the register
+ bis v0, zero, v0 // wait for read to complete
+
+2:
+ bgt t5, 1b // if gt, still waiting
+
+ ret zero, (ra) // return
+
+//
+// Perform the read of the requested CIA register and return.
+//
+
+10:
+ ldl v0, (t0) // read the register
+
+ ret zero, (ra) // return
+
+//
+// The requested CIA register address is bogus. Stop in the debugger so
+// we can find the culprit.
+//
+
+20: // flag bad QVAs
+ BREAK_DEBUG_STOP // take a breakpoint
+
+ ret zero, (ra) // return
+
+ .end READ_CIA_REGISTER
+
+
+ SBTTL( "Read Buffer from Port Space in Uchars")
+//++
+//
+// VOID
+// READ_PORT_BUFFER_UCHAR(
+// IN PVOID PortQva,
+// IN PUCHAR Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Read multiple bytes from the specified port address into the
+// destination buffer.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to read.
+//
+// Buffer(a1) - Supplies a pointer to the buffer to fill with
+// the data read from the port.
+//
+// Count(a2) - Supplies the number of bytes to read.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_BUFFER_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 30f // if ne, iff failed
+
+ and a0, 3, t3 // get byte we need if eisa
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858
+ sll t4, 28, t4 // 0xffff fc85 8000 0000
+ or t0, t4, t0 // superpage mode
+
+10: beq a2, 20f // while count > 0
+
+ ldl v0, (t0) // get the longword
+ subl a2, 1, a2 // decrement count
+ extbl v0,t3,v0 // get the correct byte
+ stb v0,(a1) // cheat and let the assembler do it
+ addl a1, 1, a1 // next byte in buffer
+ br zero, 10b // end while
+20:
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+30:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ldil v0, 0xffffffff // return fixed value
+
+ ret zero, (ra) // return to caller
+
+ .end READ_PORT_BUFFER_UCHAR
+
+
+ SBTTL( "Read Buffer from Port Space in Ushorts")
+//++
+//
+// VOID
+// READ_PORT_BUFFER_USHORT(
+// IN PVOID PortQva,
+// IN PUSHORT Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Read multiple words from the specified port address into the
+// destination buffer.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to read.
+//
+// Buffer(a1) - Supplies a pointer to the buffer to fill with
+// the data read from the port.
+//
+// Count(a2) - Supplies the number of words to read.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_BUFFER_USHORT)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 30f // if ne, iff failed
+
+ and a0, 3, t3 // get word we need
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858
+ sll t4, 28, t4 // 0xffff fc85 8000 0000
+ or t0, t4, t0 // superpage mode
+ or t0, IO_WORD_LEN, t0 // or in the byte enables
+
+10: beq a2, 20f // while count > 0
+
+ ldl v0, (t0) // get the longword
+ subl a2, 1, a2 // decrement count
+ extwl v0,t3,v0 // get the correct word
+ stw v0,(a1) // cheat and let the assembler do it
+ addl a1, 2, a1 // next word in buffer
+ br zero, 10b // end while
+20:
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+30:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ldil v0, 0xffffffff // return fixed value
+
+ ret zero, (ra) // return to caller
+
+ .end READ_PORT_BUFFER_USHORT
+
+ SBTTL( "Read Buffer from Port Space in Ulongs")
+//++
+//
+// VOID
+// READ_PORT_BUFFER_ULONG(
+// IN PVOID PortQva,
+// IN PULONG Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Read multiple longwords from the specified port address into the
+// destination buffer.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to read.
+//
+// Buffer(a1) - Supplies a pointer to the buffer to fill with
+// the data read from the port.
+//
+// Count(a2) - Supplies the number of longwords to read.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(READ_PORT_BUFFER_ULONG)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 30f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+
+ lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858
+ sll t4, 28, t4 // 0xffff fc85 8000 0000
+ or t0, t4, t0 // superpage mode
+ or t0, IO_LONG_LEN, t0 // or in the byte enables
+
+10: beq a2, 20f // while count > 0
+
+ ldl v0, (t0) // get the longword
+ subl a2, 1, a2 // decrement count
+ stl v0,(a1) // cheat and let the assembler do it
+ addl a1, 4, a1 // next word in buffer
+ br zero, 10b // end while
+20:
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+30:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ldil v0, 0xffffffff // return fixed value
+
+ ret zero, (ra) // return to caller
+
+ .end READ_PORT_BUFFER_ULONG
+
+
+ SBTTL( "Write Buffer to Port Space in Uchars")
+//++
+//
+// VOID
+// WRITE_PORT_BUFFER_UCHAR(
+// IN PVOID PortQva,
+// IN PUCHAR Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Write multiple bytes from the source buffer to the specified port
+// address.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to write.
+//
+// Buffer(a1) - Supplies a pointer to the buffer containing the data
+// to write to the port.
+//
+// Count(a2) - Supplies the number of bytes to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_BUFFER_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 30f // if ne, iff failed
+
+ and a0, 3, t3 // get byte we need if eisa
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858
+ sll t4, 28, t4 // 0xffff fc85 8000 0000
+ or t0, t4, t0 // superpage mode
+
+10: beq a2, 20f // copy while a2 > 0
+
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ subl a2, 1, a2 // decrement count
+ extbl t1, a1, t1 // extract appropriate byte
+ addl a1, 1, a1 // increment buffer pointer
+ insbl t1, t3, t1 // put byte to appropriate lane
+ stl t1, 0(t0) // store to port
+ mb // push writes off chip
+ br zero, 10b // end while
+
+20:
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+30:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ret zero, (ra) // return to caller
+
+
+ .end WRITE_PORT_BUFFER_UCHAR
+
+ SBTTL( "Write Buffer to Port Space in Ushorts")
+//++
+//
+// VOID
+// WRITE_PORT_BUFFER_USHORT(
+// IN PVOID PortQva,
+// IN PSHORT Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Write multiple words from the source buffer to the specified port
+// address.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to write.
+//
+// Buffer(a1) - Supplies a pointer to the buffer containing the data
+// to write to the port.
+//
+// Count(a2) - Supplies the number of words to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_BUFFER_USHORT)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 30f // if ne, iff failed
+
+ and a0, 3, t3 // get word we need
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858
+ sll t4, 28, t4 // 0xffff fc85 8000 0000
+ or t0, t4, t0 // superpage mode
+ or t0, IO_WORD_LEN, t0 // or in the byte enables
+
+10: beq a2, 20f // copy while a2 > 0
+
+ ldq_u t1, 0(a1) // get quad surrounding word
+ subl a2, 1, a2 // decrement count
+ extwl t1, a1, t1 // extract appropriate word
+ addl a1, 2, a1 // increment buffer pointer
+ inswl t1, t3, t1 // put word in appropriate lane
+ stl t1, 0(t0) // store to port
+ mb // push the write off the chip
+ br zero, 10b // end while
+
+20:
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+30:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ret zero, (ra) // return to caller
+
+ .end WRITE_PORT_BUFFER_USHORT
+
+
+ SBTTL( "Write Buffer to Port Space in Ulongs")
+//++
+//
+// VOID
+// WRITE_PORT_BUFFER_ULONG(
+// IN PVOID PortQva,
+// IN PULONG Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Write multiple longwords from the source buffer to the specified port
+// address.
+//
+// Arguments:
+//
+// PortQva(a0) - Supplies the QVA of the port to write.
+//
+// Buffer(a1) - Supplies a pointer to the buffer containing the data
+// to write to the port.
+//
+// Count(a2) - Supplies the number of longwords to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_PORT_BUFFER_ULONG)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 30f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858
+ sll t4, 28, t4 // 0xffff fc85 8000 0000
+ or t0, t4, t0 // superpage mode
+ or t0, IO_LONG_LEN, t0 // or in the byte enables
+
+10: beq a2, 20f // copy while a2 > 0
+
+ ldl t1, 0(a1) // a1 must be longword aligned
+ subl a2, 1, a2 // decrement count
+ stl t1, 0(t0) // store to port
+ mb // push write off the chip
+ addl a1, 4, a1 // increment buffer
+ br zero, 10b // end while
+
+20:
+ ret zero, (ra) // return
+
+//
+// Illegal access, did not use a QVA.
+//
+
+30:
+
+#if DBG
+
+ BREAK_DEBUG_STOP // take a breakpoint
+
+#endif //DBG
+
+ ret zero, (ra) // return to caller
+
+ .end WRITE_PORT_BUFFER_ULONG
+
+
+ SBTTL( "Read Buffer from PCI Memory Space in Uchars")
+//++
+//
+// VOID
+// READ_REGISTER_BUFFER_UXXXXX(
+// IN PVOID RegisterQva,
+// IN PUCHAR Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Copies a buffer from PCI Memory Space to an in-memory buffer.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the starting QVA of the memory space buffer.
+//
+// Buffer(a1) - Supplies a pointer to the in-memory buffer to receive
+// the copied data.
+//
+// Count(a2) - Supplies the number of bytes, words or longwords to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(READ_REGISTER_BUFFER_ULONG)
+
+ sll a2, 1, a2 // convert number of longs to words
+
+ ALTERNATE_ENTRY(READ_REGISTER_BUFFER_USHORT)
+
+
+ sll a2, 1, a2 // convert number of words to chars
+
+ ALTERNATE_ENTRY(READ_REGISTER_BUFFER_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ beq t1, 1f // if (eq) go do sparse space
+
+//
+// Dense space access: QVA is an offset into dense space
+// Set IO address in t0
+//
+ ldil t8, 1 // DENSE FLAG
+ zap a0, 0xf0, a0 // clear <63:32>
+ lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860
+ sll t0, 28, t0 // 0xffff fc86 0000 0000
+ or a0, t0, t0 // superpage mode: add offset to base
+
+ ldil a3, 1 // Offset to next byte
+ ldil a4, 4 // Offset to next long
+ ldil a5, 0 // LONG LEN ENABLE
+
+ br zero 2f // go do the actual transfer
+
+//
+// Sparse memory
+// Set IO address in t0
+//
+
+1:
+ ldil t8, 0 // SPARSE FLAG
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800
+ sll t4, 28, t4 // 0xffff fc80 0000 0000
+ or t0, t4, t0 // superpage mode
+
+ ldil a3, IO_BYTE_OFFSET // Offset to next byte
+ ldil a4, IO_LONG_OFFSET // Offset to next long
+ ldil a5, IO_LONG_LEN // LONG LEN ENABLE
+
+//
+// Do the ACTUAL TRANSFER
+// a2 = count in characters
+//
+
+2:
+ beq a2, 60f // if count == 0 goto 60f (return)
+
+//
+// Check alignment of src and destn
+//
+
+ and a0, 3, t3 // source alignment = t3
+ and a1, 3, t2 // destination alignment = t2
+ xor t2, t3, t4 // t4 = t2 xor t3
+ bne t4, 70f // if (t4!=0) do unaligned copy
+ // else do byte copies till alignment
+
+ beq t3, 20f // if t3==0 go do long word copies
+ // else do byte copies till alignment
+
+//
+// Src and Destn are not longword aligned but have same alignment
+// (sympathetically aligned) copy till alignment
+//
+
+10:
+ beq a2, 60f // if count == 0 goto 60f (return)
+ beq t8, 11f // if not DENSE goto 11f
+ bic t0, 3, t9 // clear bits <1:0> of src
+ ldl v0, 0(t9) // get the longword
+ br zero, 12f
+11:
+ ldl v0, 0(t0) // get the longword
+12:
+ subl a2, 1, a2 // decrement count
+ extbl v0, t3,v0 // get the correct byte
+ stb v0, (a1) // cheat and let the assembler do it
+ addq t0, a3, t0 // next I/O address
+ addl a1, 1, a1 // next byte in buffer
+ addl t3, 1, t3 // next byte in lane
+ and t3, 3, t3 // longword lanes
+ bne t3, 10b // while unaligned
+
+//
+// Src and Destn have same alignment and are longword aligned
+//
+
+20:
+ srl a2, 2, t3 // t3= #longwords to move
+ beq t3, 40f // if #longwords == 0 goto 40f
+ or t0, a5, t0 // We will now do LONG READS
+
+30:
+ ldl v0, 0(t0) // get the longword
+ subl t3, 1, t3 // decrement long word count
+ stl v0, (a1) // store the longword at destn
+ addq t0, a4, t0 // next I/O address
+ addl a1, 4, a1 // next longword in buffer
+ bne t3, 30b // while #longwords > 0
+
+//
+// Do byte copies of remaining data uncopied
+//
+ bic t0, a5, t0 // We will now do BYTE READS
+40:
+ and a2, 3, a2 // remaining Bytes to copy
+ beq a2, 60f // if count == 0 goto 60f
+
+50:
+ beq t8, 51f // if not DENSE goto 51f
+ bic t0, 3, t9 // clear bits <1:0> of src
+ ldl v0, 0(t9) // get the longword
+ br zero, 52f
+51:
+ ldl v0, 0(t0) // get the longword
+52:
+ subl a2, 1, a2 // decrement count
+ extbl v0, t3,v0 // get the correct byte
+ stb v0, (a1) // cheat and let the assembler do it
+ addl a1, 1, a1 // next byte in buffer
+ addq t0, a3, t0 // next I/O address
+ addl t3, 1, t3 // next byte in lane
+ and t3, 3, t3 // longword lanes
+ bne a2, 50b // while count > 0
+
+60:
+ ret zero, (ra) // return
+
+
+//
+// source IO alignment != destination memory alignment
+// move enough bytes to longword align the IO source
+// then move 32bit (longwords) storing unaligned into memory
+// then move residual bytes
+//
+// Align src IO addresses; unaligned destn memory
+//
+
+70:
+ beq t3, 90f // branch if source is long aligned
+//
+// Move bytes until IO src is at a longword boundary or bytes exhausted
+//
+
+80:
+ beq a2, 130f // if count == 0 goto 130f (return)
+ beq t8, 81f // if not DENSE goto 81f
+ bic t0, 3, t9 // clear bits <1:0> of src
+ ldl v0, 0(t9) // get the longword
+ br zero, 82f
+81:
+ ldl v0, 0(t0) // get the longword
+82:
+ subl a2, 1, a2 // decrement count
+ extbl v0, t3,v0 // get the correct byte
+ stb v0, (a1) // cheat and let the assembler do it
+ addl a1, 1, a1 // next byte in buffer
+ addq t0, a3, t0 // next I/O address
+ addl t3, 1, t3 // next byte in lane
+ and t3, 3, t3 // longword lanes
+ bne t3, 80b // while unaligned
+
+//
+// aligned IO source, unaligned memory destination
+//
+
+90:
+ srl a2, 3, t3 // quadwords to move
+ beq t3, 110f // if no quads finish with bytes copies
+
+ or t0, a5, t0 // We will now do LONG READS
+
+100:
+ //
+ // Decoding for Comment:
+ // S= sign, X= overwritten byte, V= Valid byte,assume destn align a1= 2
+ //
+ ldl t1, 0(t0) // load LW 0 from IO src SSSS 4321
+ ldq_u t4, 0(a1) // load destn merge XXVV VVVV
+ ldq_u t5, 7(a1) // load destn next merge VVXX XXXX
+ subl t3, 1, t3 // decrement quadwords to move
+
+ addq t0, a4, t0 // add LONG OFFSET to t0
+ ldl t2, 0(t0) // load LW 1 from IO src SSSS 8765
+
+ mskql t4, a1, t4 // mask low LW for merge 00VV VVVV
+ mskqh t5, a1, t5 // mask high LW for merge VV00 0000
+
+ zap t1, 0xf0, t1 // clear high LW for long 0 0000 4321
+ sll t2, 32, t2 // get long 1 to high longword 8765 0000
+ bis t1, t2, t1 // merge read quadword together8765 4321
+
+ addq t0, a4, t0 // increment to next long
+
+ insql t1, a1, t6 // position low QW for merge 2100 0000
+ insqh t1, a1, t7 // position high QW for merge 0087 6543
+
+ bis t4, t6, t4 // merge new data, low QW 21VV VVVV
+ bis t5, t7, t5 // merge new data, high QW VV87 6543
+
+ stq_u t5, 7(a1) // write high quadword
+ stq_u t4, 0(a1) // write low quadword
+
+ lda a1, 8(a1) // increment memory pointer
+ bne t3, 100b // while quadwords to move
+
+//
+// Do byte copies of the remaining data not yet copied
+//
+ bic t0, a5, t0 // We will now do BYTE READS
+110:
+ and a2, 7, a2 // remaining bytes to copy
+ beq a2, 130f // if count == 0 goto 130f (return)
+
+120:
+ beq t8, 121f // if not DENSE goto 121f
+ bic t0, 3, t9 // clear bits <1:0> of src
+ ldl v0, 0(t9) // get the longword
+ br zero, 122f
+121:
+ ldl v0, 0(t0) // get the longword
+122:
+ subl a2, 1, a2 // decrement count
+ extbl v0, t3,v0 // get the correct byte
+ stb v0, (a1) // cheat and let the assembler do it
+ addl a1, 1, a1 // next byte in buffer
+ addq t0, a3, t0 // next I/O address
+ addl t3, 1, t3 // next byte in lane
+ and t3, 3, t3 // longword lanes
+ bne a2, 120b // while count != 0
+
+130:
+ ret zero, (ra) // return
+
+ .end READ_REGISTER_BUFFER_ULONG // end for UCHAR & USHORT
+
+
+
+ SBTTL( "Write Buffer to PCI Memory Space in Uchars")
+//++
+//
+// VOID
+// WRITE_REGISTER_BUFFER_UXXXXX(
+// IN PVOID RegisterQva,
+// IN PUCHAR Buffer,
+// IN ULONG Count
+// )
+//
+// Routine Description:
+//
+// Copies an in-memory buffer to a PCI Memory Space buffer.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the starting QVA of the memory space buffer.
+//
+// Buffer(a1) - Supplies a pointer to the in-memory source buffer.
+//
+// Count(a2) - Supplies the number of bytes, words to longwords to write.
+//
+// Return Value:
+//
+// None.
+//
+//--
+ LEAF_ENTRY(WRITE_REGISTER_BUFFER_ULONG)
+
+ sll a2, 1, a2 // convert number of longs to words
+
+ ALTERNATE_ENTRY(WRITE_REGISTER_BUFFER_USHORT)
+
+ sll a2, 1, a2 // convert number of words to chars
+
+ ALTERNATE_ENTRY(WRITE_REGISTER_BUFFER_UCHAR)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ beq t1, 1f // if (eq) go do sparse space
+
+//
+// Dense space access: QVA is an offset into dense space
+// Set IO address in t0
+//
+
+ ldil t7, 1 // DENSE FLAG
+ zap a0, 0xf0, a0 // clear <63:32>
+ lda t0, CIA_DENSE_MEM_SVA(zero) // 0xffff ffff ffff c860
+ sll t0, 28, t0 // 0xffff fc86 0000 0000
+ or a0, t0, t0 // superpage mode: add offset to base
+
+ ldil a3, 1 // Offset to next byte
+ ldil a4, 4 // Offset to next long
+ ldil a5, 0 // LONG LEN ENABLE
+
+ br zero, 2f // go do the actual transfer
+
+//
+// Sparse Space
+// Set IO address in t0
+//
+
+1:
+ ldil t7, 0 // SPARSE FLAG
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 // t0 contains VA<33:0>
+ lda t4, CIA_SPARSE_MEM_SVA(zero) // 0xffff ffff ffff c800
+ sll t4, 28, t4 // 0xffff fc80 0000 0000
+ or t0, t4, t0 // superpage mode
+
+ ldil a3, IO_BYTE_OFFSET // Offset to next byte
+ ldil a4, IO_LONG_OFFSET // Offset to next long
+ ldil a5, IO_LONG_LEN // LONG LEN ENABLE
+
+//
+// Do the ACTUAL TRANSFER
+// a2 = count in characters
+//
+
+2:
+ beq a2, 60f // if count == 0 goto 60f (return)
+
+//
+// Check alignment of src and destn
+//
+ and a0, 3, t3 // destn alignment = t3
+ and a1, 3, t2 // src alignment = t2
+ xor t2, t3, t4 // t4 = t2 xor t3
+ bne t4, 70f // if (t4!=0) do unaligned copy
+ // else do byte copies till alignment
+
+ beq t3, 20f // if t3==0 go do longword copies
+ // else do byte copies till alignment
+
+//
+// Src and Destn are not longword aligned but have same alignment
+// (sympathetically aligned) copy till alignment
+//
+
+10:
+ beq a2, 60f // if count == 0 goto 60f (return)
+
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ subl a2, 1, a2 // decrement count
+ extbl t1, a1, t1 // extract appropriate byte
+ addl a1, 1, a1 // increment buffer pointer
+ insbl t1, t3, t1 // get proper lane
+
+ beq t7, 11f // if not DENSE goto 11f
+
+//
+// Read\modify\write for DENSE space I/O
+//
+ bic t0, 3, t9 // clear bits <1:0> of dest
+ ldl t10, 0(t9) // read dest long
+ mskbl t10, t3, t10 // poke out the byte we will write
+ bis t10, t1, t1 // merge in our byte
+ stl t1, 0(t9) // commit it
+
+ br zero, 12f
+
+//
+// We're in SPARSE space, so simply perform the write
+//
+11:
+ stl t1, 0(t0) // store byte to buffer (BYTE ENABLED)
+
+12:
+ addq t0, a3, t0 // increment I/O buffer
+ addl t3, 1, t3 // increment bytelane
+ and t3, 3, t3 // longwords only
+ bne t3, 10b // loop while not long aligned
+
+//
+// Src and Destn have same alignment and are longword aligned
+//
+
+20:
+ srl a2, 2, t3 // t3= #longwords to move
+ beq t3, 40f // if #longwords == 0 goto 40f
+ or t0, a5, t0 // We will now do LONG WRITE
+
+30:
+ ldl t1, 0(a1) // get the longword
+ addl a1, 4, a1 // increment buffer pointer
+ subl t3, 1, t3 // decrement #longwords by 1
+ stl t1, 0(t0) // store long to buffer
+ addq t0, a4, t0 // increment I/O buffer
+ bne t3, 30b // while #longwords > 0
+
+//
+// Do byte copies of remaining data uncopied
+//
+ bic t0, a5, t0 // Stop doing LONG WRITE
+
+40:
+ and a2, 3, a2 // remaining Bytes to copy
+ beq a2, 60f // if count == 0 goto 60f (return)
+
+50:
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ subl a2, 1, a2 // decrement count
+ extbl t1, a1, t1 // extract appropriate byte
+ addl a1, 1, a1 // increment buffer pointer
+ insbl t1, t3, t1 // get proper lane
+
+ beq t7, 51f // if not DENSE goto 51f
+
+//
+// Read\modify\write for DENSE space I/O
+//
+ bic t0, 3, t9 // clear bits <1:0> of dest
+ ldl t10, 0(t9) // read dest long
+ mskbl t10, t3, t10 // poke out the byte we will write
+ bis t10, t1, t1 // merge in our byte
+ stl t1, 0(t9) // commit it
+
+ br zero, 52f
+
+//
+// We're in SPARSE space, so simply perform the write
+//
+51:
+ stl t1, 0(t0) // store to buffer
+
+52:
+ addq t0, a3, t0 // increment I/O buffer
+ addl t3, 1, t3 // increment bytelane
+ and t3, 3, t3 // longwords only
+ bne a2, 50b // while count != 0
+
+60:
+ mb // push writes off chip
+ ret zero, (ra) // return
+
+//
+// destn IO alignment != Src memory alignment
+// move enough bytes to longword align the IO destn
+// then move 32bit (longwords) reading unaligned data from memory
+// then move residual bytes
+//
+
+70:
+ beq t3, 90f // branch if destn is long aligned
+
+//
+// Move bytes until IO destn is at a longword boundary or bytes exhausted
+//
+
+80:
+ beq a2, 130f // if count == 0 goto 130f (return)
+
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ extbl t1, a1, t1 // extract appropriate byte
+ insbl t1, t3, t1 // get proper lane
+
+ beq t7, 81f // if not DENSE goto 81f
+
+//
+// Read\modify\write for DENSE space I/O
+//
+ bic t0, 3, t9 // clear bits <1:0> of dest
+ ldl t10, 0(t9) // read dest long
+ mskbl t10, t3, t10 // poke out the byte we will write
+ bis t10, t1, t1 // merge in our byte
+ stl t1, 0(t9) // commit it
+
+ br zero, 82f
+
+//
+// We're in SPARSE space, so simply perform the write
+//
+81:
+ stl t1, 0(t0) // store byte to buffer (BYTE ENABLED)
+
+82:
+ subl a2, 1, a2 // decrement count
+ addl a1, 1, a1 // increment buffer pointer
+ addq t0, a3, t0 // increment I/O buffer
+ addl t3, 1, t3 // increment bytelane
+ and t3, 3, t3 // longwords only
+ bne t3, 80b // loop if not long aligned
+
+//
+// aligned IO destn, unaligned memory src
+//
+
+90:
+ srl a2, 3, t3 // t3 = quadwords to move
+ beq t3, 110f // if no quads finish with bytes copies
+
+ or t0, a5, t0 // We will now do LONG WRITES
+
+100:
+ ldq_u t1, 0(a1) // load low source quadword
+ ldq_u t2, 7(a1) // load high source quadword
+ extql t1, a1, t1 // extract low portion of quadword
+ extqh t2, a1, t2 // extract high portion of quadword
+ or t1, t2, t1 // merge to get the source quadword
+ stl t1, 0(t0) // store the long word (LONG ENABLED)
+
+ lda a1, 8(a1) // next source quadword
+ srl t1, 32, t1 // get high longword into position
+ subl t3, 1, t3 // decrement number of quadwords to move
+ addq t0, a4, t0 // add LONG OFFSET to t0
+ stl t1, (t0) // store the second long word
+
+ addq t0, a4, t0 // increment to next dest. long
+ bne t3, 100b // while quadwords to move
+//
+// Do byte copies of the remaining data not yet copied
+//
+ bic t0, a5, t0 // We will now do BYTE WRITES
+110:
+ and a2, 7, a2 // remaining Bytes to copy
+ beq a2, 130f // if count == 0 goto 130f (return)
+
+120:
+ ldq_u t1, 0(a1) // get quad surrounding byte
+ subl a2, 1, a2 // decrement count
+ extbl t1, a1, t1 // extract appropriate byte
+ addl a1, 1, a1 // increment buffer pointer
+ insbl t1, t3, t1 // get proper lane
+
+ beq t7, 121f // if not DENSE goto 122f
+
+//
+// Read\modify\write for DENSE space I/O
+//
+ bic t0, 3, t9 // clear bits <1:0> of dest
+ ldl t10, 0(t9) // read dest long
+ mskbl t10, t3, t10 // poke out the byte we will write
+ bis t10, t1, t1 // merge in our byte
+ stl t1, 0(t9) // commit it
+
+ br zero, 122f
+
+//
+// We're in SPARSE space, so simply perform the write
+//
+121:
+ stl t1, 0(t0) // store byte to buffer (BYTE ENABLED)
+
+122:
+ addq t0, a3, t0 // increment I/O buffer
+ addl t3, 1, t3 // increment bytelane
+ and t3, 3, t3 // longwords only
+ bne a2, 120b // while count != 0
+
+130:
+ mb // push writes off chip
+ ret zero, (ra) // return
+
+ .end WRITE_REGISTER_BUFFER_ULONG // end for UCHAR & USHORT
+
+
+//
+// Values and structures used to access configuration space.
+//
+
+//
+// Define the QVA for the CIA Configuration Cycle Type register
+//
+// Physical address is 87 4000 0480. The QVA specifies the offset from
+// the base of the CIA CSRS (87.4000.0000) since the physical address of
+// the CSRS exceeds the capacity of a QVA.
+//
+
+#define CIA_CFG_QVA (0xba000024)
+#define CIA_ERR_QVA (0xba000410)
+
+//
+// Define the configuration routines stack frame.
+//
+
+ .struct 0
+CfgRa: .space 8 // return address
+CfgA0: .space 8 // saved ConfigurationAddress
+CfgA1: .space 8 // saved ConfigurationData/CycleType
+CfgA2: .space 8 // saved ConfigurationCycleType
+CfgFrameLength:
+
+
+//++
+//
+// ULONG
+// READ_CONFIG_UCHAR(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read an unsigned byte from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read.
+//
+// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - This routine follows a protocol for reading from PCI configuration
+// space that allows the HAL or firmware to fixup and continue
+// execution if no device exists at the configuration target address.
+// The protocol requires 2 rules:
+// (1) The configuration space load must use a destination register
+// of v0
+// (2) The instruction immediately following the configuration space
+// load must use v0 as an operand (it must consume the value
+// returned by the load)
+//
+//--
+
+ NESTED_ENTRY( READ_CONFIG_UCHAR, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Write the configuration cycle type (a1) into the CIA CFG register
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+
+ ldil a0, CIA_CFG_QVA // offset of CIA CFG register
+ bsr ra, WRITE_CIA_REGISTER // write the cycle type
+
+//
+// Set the flag indicating that a PCI master abort may be expected by
+// the machine check handler.
+//
+ lda t0, HalpMasterAbortExpected // get address of flag
+ bis zero, 1, t1 // get a non-zero flag value
+ DISABLE_INTERRUPTS // sequence cannot be interrupted
+ stl t1, 0(t0) // store the non-zero flag
+ mb // order the write
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 0x3, t3 // capture byte lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ lda t4, CIA_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c870
+ sll t4, 28, t4 // 0xffff fc87 0000 0000
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_BYTE_LEN, t0 // or in the byte enables
+
+ .set noreorder // cannot reorder these instructions
+
+ ldl v0, (t0) // read the longword
+ mb // stall the pipe waiting for mchk
+ mb //
+ extbl v0, t3, v0 // return byte from requested lane
+
+ .set reorder // reordering can begin again
+
+//
+// If this is not a pass 1 CIA then skip the work-around code.
+//
+
+ lda t1, HalpCiaRevision // get address of CIA revision
+ ldl t1, 0(t1) // load CIA revision
+ bne t1, 10f // if ne, not pass 1
+
+//
+// CIA Pass 1 will not machine check if no device exists. Instead we must
+// check the CIA error register that indicates a master abort occurred.
+//
+
+ bis v0, zero, t10 // save v0, special calling std
+
+ ldil a0, CIA_ERR_QVA // offset of CIA_ERR register
+ bsr ra, READ_CIA_REGISTER // read error register
+
+ srl v0, 31, t0 // get error valid bit
+ bis t10, zero, v0 // restore read value
+ blbc t0, 10f // if lbc, no error use read data
+
+ ldil a0, CIA_ERR_QVA // offset of CIA_ERR register
+ ldil a1, -1 // clear all bits mask
+ bsr ra, WRITE_CIA_REGISTER // clear pending errors
+
+ ldil v0, -1 // show no device present
+ extbl v0, 0, v0 // return 0xff
+
+//
+// Set the flag indicating that a PCI master abort is not expected.
+//
+
+10:
+ lda t0, HalpMasterAbortExpected // get address of flag
+ stl zero, 0(t0) // clear flag
+ ENABLE_INTERRUPTS // re-enable interrupts
+
+//
+// Restore the frame and return.
+//
+
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end READ_CONFIG_UCHAR
+
+//++
+//
+// VOID
+// WRITE_CONFIG_UCHAR(
+// ULONG ConfigurationAddress,
+// UCHAR ConfigurationData,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Write an unsigned byte to PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA to write.
+//
+// ConfigurationData(a1) - Supplies the data to be written.
+//
+// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// None.
+//
+// N.B. - The configuration address must exist within the address space
+// allocated to an existing PCI device. Otherwise, the access
+// below will initiate an unrecoverable machine check.
+//
+//--
+
+ NESTED_ENTRY( WRITE_CONFIG_UCHAR, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Write the configuration cycle type to the CIA CFG register
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+ stq a1, CfgA1(sp) // save configuration data
+
+ bis a2, a2, a1 // put the cycle type in a1
+ ldil a0, CIA_CFG_QVA // offset of CIA CFG register
+ bsr ra, WRITE_CIA_REGISTER // write cycle type to CFG
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address and data.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+ ldq a1, CfgA1(sp) // restore configuration data
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 0x3, t3 // capture byte lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ lda t4, CIA_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c870
+ sll t4, 28, t4 // 0xffff fc87 0000 0000
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_BYTE_LEN, t0 // or in the byte length indicator
+
+ insbl a1, t3, t4 // put byte in the appropriate lane
+ stl t4, (t0) // write the configuration byte
+ mb // synchronize
+
+10: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end WRITE_CONFIG_UCHAR
+
+//++
+//
+// ULONG
+// READ_CONFIG_USHORT(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read a short from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of quadword to be read.
+//
+// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - This routine follows a protocol for reading from PCI configuration
+// space that allows the HAL or firmware to fixup and continue
+// execution if no device exists at the configuration target address.
+// The protocol requires 2 rules:
+// (1) The configuration space load must use a destination register
+// of v0
+// (2) The instruction immediately following the configuration space
+// load must use v0 as an operand (it must consume the value
+// returned by the load)
+//--
+
+ NESTED_ENTRY( READ_CONFIG_USHORT, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Write the configuration cycle type (in a1) into the CIA CFG register
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+
+ ldil a0, CIA_CFG_QVA // offset of CFG register
+ bsr ra, WRITE_CIA_REGISTER // write cycle type to CFG register
+
+//
+// Set the flag indicating that a PCI master abort may be expected by
+// the machine check handler.
+//
+ lda t0, HalpMasterAbortExpected // get address of flag
+ bis zero, 1, t1 // get a non-zero flag value
+ DISABLE_INTERRUPTS // sequence cannot be interrupted
+ stl t1, 0(t0) // store the non-zero flag
+ mb // order the write
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 0x3, t3 // capture word offset
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ lda t4, CIA_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c870
+ sll t4, 28, t4 // 0xffff fc87 0000 0000
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_WORD_LEN, t0 // or in the byte enables
+
+ .set noreorder // cannot reorder these instructions
+
+ ldl v0, (t0) // read the longword
+ mb // stall the pipe waiting for mchk
+ mb //
+ extwl v0, t3, v0 // return word from requested lanes
+
+ .set reorder // reordering can begin again
+
+//
+// If this is not a pass 1 CIA then skip the work-around code.
+//
+
+ lda t1, HalpCiaRevision // get address of CIA revision
+ ldl t1, 0(t1) // load CIA revision
+ bne t1, 10f // if ne, not pass 1
+
+//
+// CIA Pass 1 will not machine check if no device exists. Instead we must check
+// the CIA error register that indicates a master abort occurred.
+//
+
+ bis v0, zero, t10 // save v0, special calling std
+
+ ldil a0, CIA_ERR_QVA // offset of CIA_ERR register
+ bsr ra, READ_CIA_REGISTER // read error register
+
+ srl v0, 31, t0 // get error valid bit
+ bis t10, zero, v0 // restore read value
+ blbc t0, 10f // if lbc, no error use read data
+
+ ldil a0, CIA_ERR_QVA // offset of CIA_ERR register
+ ldil a1, -1 // clear all bits mask
+ bsr ra, WRITE_CIA_REGISTER // clear pending errors
+
+ ldil v0, -1 // show no device present
+ extwl v0, 0, v0 // return 0xffff
+
+//
+// Set the flag indicating that a PCI master abort is not expected.
+//
+
+10:
+ lda t0, HalpMasterAbortExpected // get address of flag
+ stl zero, 0(t0) // clear flag
+ ENABLE_INTERRUPTS // re-enable interrupts
+
+//
+// Restore the frame and return.
+//
+
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end READ_CONFIG_USHORT
+
+//++
+//
+// VOID
+// WRITE_CONFIG_USHORT(
+// ULONG ConfigurationAddress,
+// USHORT ConfigurationData,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Write a short to PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA to write.
+//
+// ConfigurationData(a1) - Supplies the data to be written.
+//
+// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - The configuration address must exist within the address space
+// allocated to an existing PCI device. Otherwise, the access
+// below will initiate an unrecoverable machine check.
+//
+//--
+
+ NESTED_ENTRY( WRITE_CONFIG_USHORT, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Write the configuration cycle type (a2) into the CFG register
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+ stq a1, CfgA1(sp) // save configuration data
+
+ bis a2, a2, a1 // put the cycle type in a1
+ ldil a0, CIA_CFG_QVA // offset of CFG register
+ bsr ra, WRITE_CIA_REGISTER // write config type to CFG
+
+//
+// Perform the write to configuration space after restoring the
+// configuration space address and data.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+ ldq a1, CfgA1(sp) // restore configuration data
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 0x3, t3 // capture word offset
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ lda t4, CIA_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c870
+ sll t4, 28, t4 // 0xffff fc87 0000 0000
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_WORD_LEN, t0 // or in the byte enables
+
+ inswl a1, t3, t4 // put data to appropriate lane
+ stl t4, (t0) // read the longword
+ mb // synchronize
+10: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end WRITE_CONFIG_USHORT
+
+//++
+//
+// ULONG
+// READ_CONFIG_ULONG(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read a longword from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of quadword to be read.
+//
+// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - This routine follows a protocol for reading from PCI configuration
+// space that allows the HAL or firmware to fixup and continue
+// execution if no device exists at the configuration target address.
+// The protocol requires 2 rules:
+// (1) The configuration space load must use a destination register
+// of v0
+// (2) The instruction immediately following the configuration space
+// load must use v0 as an operand (it must consume the value
+// returned by the load)
+//--
+
+ NESTED_ENTRY( READ_CONFIG_ULONG, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Write the configuration cycle type (a1) to the CIA CFG register
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+
+ ldil a0, CIA_CFG_QVA // offset of CIA CFG register
+ bsr ra, WRITE_CIA_REGISTER // write cycle type to CFG
+
+//
+// Set the flag indicating that a PCI master abort may be expected by
+// the machine check handler.
+//
+ lda t0, HalpMasterAbortExpected // get address of flag
+ bis zero, 1, t1 // get a non-zero flag value
+ DISABLE_INTERRUPTS // sequence cannot be interrupted
+ stl t1, 0(t0) // store the non-zero flag
+ mb // order the write
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ lda t4, CIA_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c870
+ sll t4, 28, t4 // 0xffff fc87 0000 0000
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_LONG_LEN, t0 // or in the byte enables
+
+ .set noreorder // cannot reorder these instructions
+
+ ldl v0, (t0) // read the longword
+ mb // stall the pipe waiting for mchk
+ mb //
+
+ .set reorder // reordering can begin again
+
+//
+// If this is not a pass 1 CIA then skip the work-around code.
+//
+
+ lda t1, HalpCiaRevision // get address of CIA revision
+ ldl t1, 0(t1) // load CIA revision
+ bne t1, 10f // if ne, not pass 1
+
+//
+// CIA Pass 1 will not machine check if no device exists. Instead we must check
+// the CIA error register that indicates a master abort occurred.
+//
+
+ bis v0, zero, t10 // save v0, special calling std
+
+ ldil a0, CIA_ERR_QVA // offset of CIA_ERR register
+ bsr ra, READ_CIA_REGISTER // read error register
+
+ srl v0, 31, t0 // get error valid bit
+ bis t10, zero, v0 // restore read value
+ blbc t0, 10f // if lbc, no error use read data
+
+ ldil a0, CIA_ERR_QVA // offset of CIA_ERR register
+ ldil a1, -1 // clear all bits mask
+ bsr ra, WRITE_CIA_REGISTER // clear pending errors
+
+ ldil v0, -1 // show no device present
+
+//
+// Set the flag indicating that a PCI master abort is not expected.
+//
+
+10:
+ lda t0, HalpMasterAbortExpected // get address of flag
+ stl zero, 0(t0) // clear flag
+ ENABLE_INTERRUPTS // re-enable interrupts
+
+//
+// Restore the frame and return.
+//
+
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end READ_CONFIG_ULONG
+
+
+//++
+//
+// VOID
+// WRITE_CONFIG_ULONG(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationData,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read a longword from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA to write.
+//
+// ConfigurationData(a1) - Supplies the data to be written.
+//
+// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - The configuration address must exist within the address space
+// allocated to an existing PCI device. Otherwise, the access
+// below will initiate an unrecoverable machine check.
+//
+//--
+
+ NESTED_ENTRY( WRITE_CONFIG_ULONG, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Write the configuration cycle type to the CIA CFG register
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+ stq a1, CfgA1(sp) // save configuration data
+
+ ldil a0, CIA_CFG_QVA // offset of CIA CFG register
+ bis a2, a2, a1 // cycle type in a1
+ bsr ra, WRITE_CIA_REGISTER // write cycle type to CFG
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address and data.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+ ldq a1, CfgA1(sp) // restore configuration data
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 10f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ lda t4, CIA_PCI_CONFIG_SVA(zero) // 0xffff ffff ffff c870
+ sll t4, 28, t4 // 0xffff fc87 0000 0000
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_LONG_LEN, t0 // or in the byte enables
+
+ stl a1, (t0) // write the longword
+ mb // synchronize
+10: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end WRITE_CONFIG_ULONG
+
+
+//++
+//
+// ULONG
+// INTERRUPT_ACKNOWLEDGE(
+// VOID
+// )
+//
+// Routine Description:
+//
+// Perform an interrupt acknowledge cycle on the PCI bus.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// (v0) Returns the vector returned by the interrupt acknowledge
+// read.
+//
+//--
+
+ LEAF_ENTRY( INTERRUPT_ACKNOWLEDGE )
+
+ lda t0, CIA_PCI_INTACK_SVA(zero) // 0xffff ffff ffff c872
+ sll t0, 28, t0 // 0xffff fc87 2000 0000
+
+ ldl v0, 0(t0) // perform intack, get vector
+
+ ret zero, (ra) // return
+
+ .end INTERRUPT_ACKNOWLEDGE
+
+
+//++
+//
+// VOID
+// CIA_INVALIDATE_TLB(
+// VOID
+// )
+//
+// Routine Description:
+//
+// Invalidate the TLB for the CIA scatter/gather.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+//jnfix - big warnings - this is a special work-around for CIA invalidate bug
+//jnfix - the 3rd DMA window is set up so that by convention with this code
+//jnfix - offset 0x10 within the firware PAL is overwritten
+
+#define CIA_TBIA_SVA -0x378a // negative of 0xc876
+#define CIA_DIAG_SVA -0x3794 // negative of 0xc86c
+
+ LEAF_ENTRY( CIA_INVALIDATE_TLB )
+
+ ldil t0, 0x100 // get stall count
+
+ lda t1, CIA_TBIA_SVA(zero) // 0xffff ffff ffff c876
+ sll t1, 28, t1 // 0xffff fc87 6000 0000
+ lda t1, 0x100(t1) // 0xffff fc87 6000 0100
+
+ lda t2, CIA_DIAG_SVA(zero) // 0xffff ffff ffff c86c
+ sll t2, 28, t2 // 0xffff fc86 c000 0000
+ lda t2, 0x10(t2) // 0xffff fc86 c000 0010
+
+ lda t3, CIA_SPARSE_IO_SVA(zero) // 0xffff ffff ffff c858
+ sll t3, 28, t3 // 0xffff fc85 8000 0000
+ lda t4, 0x70(zero) // get port 0x70
+ sll t4, 5, t4 // shift into position
+ bis t3, t4, t3 // merge in port address
+
+ ldil t4, 0x3 // get tlb invalidate value
+
+ DISABLE_INTERRUPTS // sequence cannot be interrupted
+
+10:
+ subq t0, 1, t0 // decrement stall count
+ bgt t0, 20f // if gt, continue stall
+
+ mb // clear write buffer
+
+ stl zero, 0(t3) // do i/o write
+ wmb // issue wmb
+
+ stl zero, 0(t2) // issue diagnostic write
+ wmb // issue wmb
+
+ stl t4, 0(t1) // issue invalidate
+ mb // flush write buffer
+
+20:
+ bgt t0, 10b // continue stall loop
+
+ ENABLE_INTERRUPTS // re-enable interrupts
+
+ ret zero, (ra) // return
+
+ .end CIA_INVALIDATE_TLB
+
diff --git a/private/ntos/nthals/halalpha/ciamapio.c b/private/ntos/nthals/halalpha/ciamapio.c
new file mode 100644
index 000000000..6174c7ba0
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ciamapio.c
@@ -0,0 +1,154 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ ciamapio.c
+
+Abstract:
+
+ This module contains the functions to map HAL-accessed I/O addresses
+ on CIA-based systems.
+
+Author:
+
+ Joe Notarangelo 30-Jun-1994
+ Steve Brooks 30-Jun-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "isaaddr.h"
+
+//
+// Define global data used to locate the EISA control space.
+//
+
+PVOID HalpEisaControlBase;
+PVOID HalpEisaIntAckBase;
+PVOID HalpPciIrQva;
+PVOID HalpPciImrQva;
+PVOID HalpCMOSRamBase;
+
+
+BOOLEAN
+HalpMapIoSpace (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine maps the HAL I/O space for a Alcor system using
+ the Quasi VA mechanism.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the initialization is successfully completed, than a value of TRUE
+ is returned. Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+ PVOID PciIoSpaceBase;
+
+ //
+ // Map base addresses in QVA space.
+ //
+
+ PciIoSpaceBase = HAL_MAKE_QVA( CIA_PCI_SPARSE_IO_PHYSICAL );
+
+ HalpEisaControlBase = PciIoSpaceBase;
+ HalpEisaIntAckBase = HAL_MAKE_QVA( CIA_PCI_INTACK_PHYSICAL );
+
+ //
+ // Map CMOS RAM address.
+ //
+
+ HalpCMOSRamBase = (PVOID)((ULONG)PciIoSpaceBase + CMOS_ISA_PORT_ADDRESS);
+
+ //
+ // Map the real-time clock registers.
+ //
+
+ HalpRtcAddressPort = (PVOID)((ULONG)PciIoSpaceBase + RTC_ISA_ADDRESS_PORT);
+ HalpRtcDataPort = (PVOID)((ULONG)PciIoSpaceBase + RTC_ISA_DATA_PORT);
+
+ return TRUE;
+
+}
+
+ULONG
+HalpMapDebugPort(
+ IN ULONG ComPort,
+ OUT PULONG ReadQva,
+ OUT PULONG WriteQva
+ )
+/*++
+
+Routine Description:
+
+ This routine maps the debug com port so that the kernel debugger
+ may function - if called it is called very earlier in the boot sequence.
+
+Arguments:
+
+ ComPort - Supplies the number of the com port to use as the debug port.
+
+ ReadQva - Receives the QVA used to access the read registers of the debug
+ port.
+
+ WriteQva - Receives the QVA used to access the write registers of the
+ debug port.
+
+Return Value:
+
+ Returns the base bus address of the device used as the debug port.
+
+--*/
+{
+ ULONG ComPortAddress;
+ ULONG PortQva;
+
+ //
+ // Compute the port address, based on the desired com port.
+ //
+
+ switch( ComPort ){
+
+ case 1:
+
+ ComPortAddress = COM1_ISA_PORT_ADDRESS;
+ break;
+
+ case 2:
+ default:
+
+ ComPortAddress = COM2_ISA_PORT_ADDRESS;
+
+ }
+
+ //
+ // Return the QVAs for read and write access.
+ //
+
+ PortQva = (ULONG)HAL_MAKE_QVA(CIA_PCI_SPARSE_IO_PHYSICAL) + ComPortAddress;
+
+ *ReadQva = PortQva;
+ *WriteQva = PortQva;
+
+ return ComPortAddress;
+
+}
diff --git a/private/ntos/nthals/halalpha/cmos8k.c b/private/ntos/nthals/halalpha/cmos8k.c
new file mode 100644
index 000000000..6de80feb1
--- /dev/null
+++ b/private/ntos/nthals/halalpha/cmos8k.c
@@ -0,0 +1,246 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ xxnvram.c
+
+Abstract:
+
+ This module implements the device-specific routines necessary to
+ Read and Write the Non Volatile RAM containing the system environment
+ variables. The routines implemented here are:
+
+ HalpReadNVRamBuffer() - copy data from NVRAM into memory
+ HalpWriteNVRamBuffer() - write memory data to NVRAM
+ HalpCopyNVRamBuffer() - move data within the NVRAM
+
+Author:
+
+ Steve Brooks 5-Oct 93
+
+
+Revision History:
+
+
+--*/
+
+
+#include "halp.h"
+#include "cmos8k.h"
+
+#include "arccodes.h"
+
+//
+// Local function prototypes.
+//
+
+ARC_STATUS
+HalpReadNVRamBuffer (
+ OUT PCHAR DataPtr,
+ IN PCHAR NvRamPtr,
+ IN ULONG Length
+ );
+
+ARC_STATUS
+HalpWriteNVRamBuffer (
+ IN PCHAR NvRamPtr,
+ IN PCHAR DataPtr,
+ IN ULONG Length
+ );
+
+ARC_STATUS
+HalpCopyNVRamBuffer (
+ IN PCHAR NvDestPtr,
+ IN PCHAR NvSrcPtr,
+ IN ULONG Length
+ );
+
+#ifdef AXP_FIRMWARE
+
+#pragma alloc_text(DISTEXT, HalpReadNVRamBuffer )
+#pragma alloc_text(DISTEXT, HalpWriteNVRamBuffer )
+#pragma alloc_text(DISTEXT, HalpCopyNVRamBuffer )
+
+#endif
+
+
+//
+//
+//
+ARC_STATUS HalpReadNVRamBuffer (
+ OUT PCHAR DataPtr,
+ IN PCHAR NvRamPtr,
+ IN ULONG Length )
+
+/*++
+
+Routine Description:
+
+ This routine Reads data from the NVRam into main memory
+
+Arguments:
+
+ DataPtr - Pointer to memory location to receive data
+ NvRamPtr - Pointer (qva) to NVRam location to read data from
+ Length - Number of bytes of data to transfer
+
+Return Value:
+
+ ESUCCESS if the operation succeeds.
+
+--*/
+{
+ ULONG PageSelect, ByteSelect;
+
+ PageSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT;
+ ByteSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;
+
+ WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect);
+ while ( Length -- )
+ {
+ *DataPtr++ = READ_CONFIG_RAM_DATA(NvRamPtr);
+ NvRamPtr ++;
+
+ ByteSelect = (ByteSelect + 1) & CONFIG_RAM_BYTE_MASK;
+ if (ByteSelect == 0)
+ {
+ PageSelect++;
+ WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect);
+ }
+ }
+
+ return(ESUCCESS);
+}
+
+//
+//
+//
+ARC_STATUS HalpWriteNVRamBuffer (
+ IN PCHAR NvRamPtr,
+ IN PCHAR DataPtr,
+ IN ULONG Length )
+
+/*++
+
+Routine Description:
+
+ This routine Writes data from memory into the NVRam
+
+Arguments:
+
+ NvRamPtr - Pointer (qva) to NVRam location to write data into
+ DataPtr - Pointer to memory location of data to be written
+ Length - Number of bytes of data to transfer
+
+Return Value:
+
+ ESUCCESS if the operation succeeds.
+
+--*/
+{
+ ULONG PageSelect, ByteSelect;
+
+ PageSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT;
+ ByteSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;
+
+ WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect);
+ while ( Length -- )
+ {
+ WRITE_CONFIG_RAM_DATA(NvRamPtr, *DataPtr);
+ NvRamPtr ++;
+ DataPtr ++;
+
+ ByteSelect = (ByteSelect + 1) & CONFIG_RAM_BYTE_MASK;
+ if (ByteSelect == 0)
+ {
+ PageSelect++;
+ WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect);
+ }
+ }
+
+ return(ESUCCESS);
+}
+
+//
+//
+//
+ARC_STATUS HalpCopyNVRamBuffer (
+ IN PCHAR NvDestPtr,
+ IN PCHAR NvSrcPtr,
+ IN ULONG Length )
+/*++
+
+Routine Description:
+
+ This routine copies data between two locations within the NVRam. It is
+ the callers responsibility to assure that the destination region does not
+ overlap the src region i.e. if the regions overlap, NvSrcPtr > NvDestPtr.
+
+Arguments:
+
+ NvDestPtr - Pointer (qva) to NVRam location to write data into
+ NvSrcPtr - Pointer (qva) to NVRam location of data to copy
+ Length - Number of bytes of data to transfer
+
+Return Value:
+
+ ESUCCESS if the operation succeeds.
+
+--*/
+
+{
+ ULONG PageSelect0, ByteSelect0; // Src Pointer Page & offset
+ ULONG PageSelect1, ByteSelect1; // Dest Pointer Page & offset
+
+
+ PageSelect0 = (NvSrcPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT;
+ ByteSelect0 = (NvSrcPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;
+
+ PageSelect1 = (NvDestPtr-(PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT;
+ ByteSelect1 = (NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;
+
+ WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect0);
+ while ( Length -- )
+ {
+ UCHAR AChar;
+
+ //
+ // Check the Page select for the src pointer, and write the
+ // select register if necessary:
+ //
+ if (ByteSelect0 == 0)
+ {
+ PageSelect0++;
+ }
+ if ( PageSelect0 != PageSelect1 )
+ {
+ WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect0);
+ }
+
+ AChar = READ_CONFIG_RAM_DATA(NvSrcPtr);
+ ByteSelect0 = (ByteSelect0 + 1) & CONFIG_RAM_BYTE_MASK;
+
+ //
+ // Check the page select for the dest pointer, and write
+ // the select register if necessary:
+ //
+ if (ByteSelect1 == 0)
+ {
+ PageSelect1++;
+ }
+ if ( PageSelect1 != PageSelect0 )
+ {
+ WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect1);
+ }
+
+ WRITE_CONFIG_RAM_DATA(NvDestPtr, AChar);
+ ByteSelect1 = (ByteSelect1 + 1) & CONFIG_RAM_BYTE_MASK;
+
+ NvSrcPtr ++;
+ NvDestPtr ++;
+ }
+
+ return(ESUCCESS);
+}
diff --git a/private/ntos/nthals/halalpha/cmos8k.h b/private/ntos/nthals/halalpha/cmos8k.h
new file mode 100644
index 000000000..192730a32
--- /dev/null
+++ b/private/ntos/nthals/halalpha/cmos8k.h
@@ -0,0 +1,32 @@
+//
+// Non-volatile ram layout.
+//
+
+//
+// The value of HalpCMOSRamBase must be set at initialization
+//
+
+#define CONFIG_RAM_PAGE_SELECT ((PUCHAR)HalpCMOSRamBase + 0x0400)
+#define CONFIG_RAM_PAGE_COUNT 32
+#define CONFIG_RAM_PAGE_SIZE 256
+#define CONFIG_RAM_PAGE_MASK ((CONFIG_RAM_PAGE_COUNT - 1) << 8)
+#define CONFIG_RAM_PAGE_SHIFT 8
+#define CONFIG_RAM_BYTE_MASK (CONFIG_RAM_PAGE_SIZE - 1)
+
+
+// To address any byte of the CMOS 8K configuration RAM, the PAGE select
+// address bits from from I/O register at CONFIG_RAM_PAGE_SELECT are
+// OR'd with the lower address bits. Use the following macro to write
+// the page select register:
+
+#define WRITE_CONFIG_RAM_PAGE_SELECT(page) \
+ WRITE_PORT_UCHAR((PUCHAR)CONFIG_RAM_PAGE_SELECT, \
+ (UCHAR)(page & (CONFIG_RAM_PAGE_COUNT - 1)))
+
+#define WRITE_CONFIG_RAM_DATA(boffset,data) \
+ WRITE_PORT_UCHAR((PUCHAR)((ULONG)(HalpCMOSRamBase) | \
+ ((ULONG)boffset & CONFIG_RAM_BYTE_MASK)), (data & 0xff))
+
+#define READ_CONFIG_RAM_DATA(boffset) \
+ READ_PORT_UCHAR((PUCHAR)((ULONG)(HalpCMOSRamBase) | \
+ ((ULONG)boffset & CONFIG_RAM_BYTE_MASK)))
diff --git a/private/ntos/nthals/halalpha/devintr.s b/private/ntos/nthals/halalpha/devintr.s
new file mode 100644
index 000000000..63c17df5a
--- /dev/null
+++ b/private/ntos/nthals/halalpha/devintr.s
@@ -0,0 +1,71 @@
+// TITLE("First Level Device Interrupt Handlers")
+//++
+//
+// Copyright (c) 1994 Digital Equipment Corporation
+//
+// Module Name:
+//
+// devintr.s
+//
+// Abstract:
+//
+// This module implements first level device interrupt handlers for
+// systems that need to capture the trap frame for interrupt handling.
+//
+// Author:
+//
+// Joe Notarangelo 19-Sep-1994
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+#include "halalpha.h"
+
+ SBTTL("Device Interrupt")
+//++
+//
+// VOID
+// HalpDeviceInterrupt(
+// IN PKINTERRUPT Interrupt,
+// IN PVOID ServiceContext
+// )
+//
+// Routine Description:
+//
+// This function is executed as the result of a device interrupt.
+// The function is responsible for capturing the trap frame and calling
+// the system-specific device interrupt dispatcher.
+//
+// N.B. This function exists only to capture the trap frame and forward
+// the interrupt to HalpDeviceDispatch.
+//
+// Arguments:
+//
+// Interrupt (a0) - Supplies a pointer to the interrupt object.
+//
+// ServiceContext (a1) - Supplies a pointer to the service context for
+// Sable interrupts.
+//
+// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for
+// the interrupt.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpDeviceInterrupt)
+
+ bis fp, zero, a2 // capture trap frame as argument
+ br zero, HalpDeviceDispatch // dispatch the interrupt
+
+ ret zero, (ra) // will never get here
+
+ .end HalpDeviceInterrupt
+
diff --git a/private/ntos/nthals/halalpha/ebsgdma.c b/private/ntos/nthals/halalpha/ebsgdma.c
new file mode 100644
index 000000000..e50fe05bb
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ebsgdma.c
@@ -0,0 +1,2307 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ ebsgdma.c
+
+Abstract:
+
+ This module contains the hardware dependent routines to support
+ Io Adapters, Map Registers, and Common buffers for Scatter/Gather
+ Eisa/Isa bus Alpha AXP systems. The systems supported must include
+ support for 2 scatter/gather windows. Originally, this module will
+ support APECS- and LCA-based systems.
+
+Author:
+
+ Joe Notarangelo 11-Oct-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Dick Bissen (DEC) 01-Nov-1993
+ Forced scatter/gather tables to be aligned with table size
+
+ Joe Notarangelo 24-Nov-1993
+ Do not program DMA controllers for ISA masters in IoMapTransfer and
+ IoFlushAdapterBuffers. Previous code did so if the device was an
+ Isa device without regard to whether or not it was a master device.
+
+ Joe Notarangelo 02-Feb-1994
+ Various bug fixes. Don't adjust mapRegister in IoMapTransfer and
+ IoFlushAdapterBuffers. Fix alignment adjustment code for Isa
+ machines. Initialize map registers to zero. Initialize bitmap
+ for map allocations by calling RtlClearAllBits. Add debugging
+ prints to fit new module haldebug.c
+
+--*/
+
+#include "halp.h"
+#include "pci.h"
+#include "pcip.h"
+
+
+//
+// There are 2 map register adapters that are created to control access
+// to each of the 2 mapping windows that exist for APECS and LCA.
+//
+// The first adapter (IsaMapAdapter) controls access to the first mapping
+// windows which maps 8MB : 16MB-1 in bus space. The window is chosen
+// to be as large as possible and must be below 16MB to support ISA
+// bus masters and the standard EISA/ISA dma controllers.
+//
+// The second adapter (MasterMapAdapter) controls access to the second
+// mapping windows which maps a large region in bus space that may
+// begin above 16MB. This window is used for bus masters that are not
+// constrained by the ISA 24-bit limit.
+//
+
+PMAP_REGISTER_ADAPTER HalpIsaMapAdapter = NULL;
+PMAP_REGISTER_ADAPTER HalpMasterMapAdapter = NULL;
+
+//
+// Pointer to superpage address memory for map registers.
+//
+
+PTRANSLATION_ENTRY HalpIsaMapRegisterBase = NULL;
+PTRANSLATION_ENTRY HalpMasterMapRegisterBase = NULL;
+
+//
+// Control structures for each of the map register windows.
+//
+
+WINDOW_CONTROL_REGISTERS HalpIsaWindowControl;
+WINDOW_CONTROL_REGISTERS HalpMasterWindowControl;
+
+
+
+//
+// Local function prototypes.
+//
+
+IO_ALLOCATION_ACTION
+HalpAllocationRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ );
+
+PMAP_REGISTER_ADAPTER
+HalpAllocateMapAdapter(
+ IN PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ IN HAL_ADAPTER_TYPE AdapterType,
+ IN PTRANSLATION_ENTRY MapRegisterBase
+ );
+
+PADAPTER_OBJECT
+HalpAllocateAdapter(
+ VOID
+ );
+
+BOOLEAN
+HalpAllocateMapRegisters(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG NumberOfMapRegisters,
+ IN BOOLEAN MapAdapterLocked
+ );
+
+BOOLEAN
+HalpCreateDmaStructures (
+ PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the structures necessary for DMA operations.
+ Specifically, this routine allocates the physical pages to be used
+ to contain the scatter/gather entries for all DMA.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ TRUE is returned.
+
+--*/
+
+{
+ ULONG Allocated;
+ ULONG ByteSize;
+ ULONG MaxPhysicalAddress;
+
+ //
+ // Initialize the window control structures for each of the 2
+ // DMA windows.
+ //
+
+ INITIALIZE_ISA_DMA_CONTROL( &HalpIsaWindowControl );
+ INITIALIZE_MASTER_DMA_CONTROL( &HalpMasterWindowControl );
+
+ //
+ // Insure that the maximum address allocated will guarantee that the
+ // entirety of each allocation can be accessed via the 32-bit superpage.
+ //
+
+ MaxPhysicalAddress = __1GB - 1;
+
+ //
+ // Allocate the pages to contain the scatter/gather entries for the
+ // ISA DMA region (logical address range 8MB: 16MB-1).
+ //
+
+ ByteSize = ((HalpIsaWindowControl.WindowSize / PAGE_SIZE) *
+ sizeof(TRANSLATION_ENTRY)) + PAGE_SIZE-1;
+
+ //
+ // Memory allocation for the Isa scatter/gather table will always
+ // align on a 8K boundry.
+ //
+
+ Allocated = HalpAllocPhysicalMemory( LoaderBlock,
+ MaxPhysicalAddress,
+ ByteSize >> PAGE_SHIFT,
+ FALSE );
+
+ ASSERT( Allocated != 0 );
+
+ HalpIsaMapRegisterBase = (PTRANSLATION_ENTRY)(Allocated | KSEG0_BASE);
+
+ RtlZeroMemory( HalpIsaMapRegisterBase,
+ (ByteSize >> PAGE_SHIFT) << PAGE_SHIFT );
+
+ //
+ // Allocate the pages to contain the scatter/gather entries for the
+ // bus master DMA region. Allocation of scatter/gather tables MUST
+ // be aligned based on the size of the scatter/gather table (16k).
+ //
+
+ ByteSize = ((HalpMasterWindowControl.WindowSize / PAGE_SIZE) *
+ sizeof(TRANSLATION_ENTRY)) + PAGE_SIZE-1;
+
+ //
+ // Allocated on an aligned 64k boundry will ensure table alignment
+ // on a 16K boundry for a 16MB window size.
+ //
+
+ Allocated = HalpAllocPhysicalMemory( LoaderBlock,
+ MaxPhysicalAddress,
+ ByteSize >> PAGE_SHIFT,
+ TRUE );
+
+ ASSERT( Allocated != 0 );
+
+ HalpMasterMapRegisterBase = (PTRANSLATION_ENTRY)(Allocated | KSEG0_BASE);
+
+ RtlZeroMemory( HalpMasterMapRegisterBase,
+ (ByteSize >> PAGE_SHIFT) << PAGE_SHIFT );
+
+ //
+ // Perform any Eisa/Isa initialization.
+ //
+
+ HalpEisaInitializeDma();
+
+ //
+ // Program the DMA windows to reflect the translations.
+ //
+
+ INITIALIZE_DMA_WINDOW( &HalpMasterWindowControl,
+ (PVOID)( (ULONG)HalpMasterMapRegisterBase &
+ ~KSEG0_BASE ) );
+
+ INITIALIZE_DMA_WINDOW( &HalpIsaWindowControl,
+ (PVOID)( (ULONG)HalpIsaMapRegisterBase &
+ ~KSEG0_BASE ) );
+
+ return TRUE;
+}
+
+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. Eisa/Isa bus types and all master
+ devices are supported for the system.
+
+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 adapter object or NULL if an adapter could not
+ be created.
+
+--*/
+
+{
+ ULONG MaximumMapRegistersPerChannel;
+ PADAPTER_OBJECT adapterObject;
+ PBUS_HANDLER BusHandler;
+ PPCIPBUSDATA PciBusData;
+
+ //
+ // Make sure this is the correct version.
+ //
+
+ if (DeviceDescription->Version > DEVICE_DESCRIPTION_VERSION1) {
+
+ return(NULL);
+
+ }
+
+ //
+ // If the device is not a bus master, then it must be an ISA, EISA
+ // or PCI device on hardware bus 0. PCI devices on hardware busses
+ // other than 0 cannot support slave DMA devices because the DMAC
+ // needed to support slave DMA is part of the ISA/EISA bridge, (which
+ // is located on h/w bus 0).
+ //
+
+ if( DeviceDescription->Master != TRUE ){
+
+ //
+ // This device requires slave DMA h/w support. Determine which
+ // type of device it is.
+ //
+
+ switch( DeviceDescription->InterfaceType ){
+
+ case Isa:
+ case Eisa:
+
+ //
+ // The ISA/EISA bridge implements the DMA controller logic
+ // needed to support slave DMA.
+ //
+
+ break;
+
+ case PCIBus:
+
+ //
+ // Get the bus handler for the PCI bus.
+ //
+
+ BusHandler = HaliHandlerForBus(
+ PCIBus,
+ DeviceDescription->BusNumber
+ );
+
+ //
+ // If a bus handler does not exist, then there is a s/w bug
+ // somewhere. Just return failure.
+ //
+
+ if( BusHandler == NULL ){
+
+ return NULL;
+
+ }
+
+ //
+ // Get a pointer to the PCI private bus data for this bus.
+ // The h/w bus number is located therein.
+ //
+
+ PciBusData = (PPCIPBUSDATA)BusHandler->BusData;
+
+ //
+ // The DMA controller we use to support slave DMA is located
+ // on the ISA/EISA bridge in h/w bus 0. If this PCI bus is
+ // not located on h/w bus 0, return failure.
+ //
+
+ if( PciBusData->HwBusNumber != 0 ){
+
+ return NULL;
+
+ }
+
+ break;
+
+ default:
+
+ //
+ // We only support ISA, EISA and PCI slave DMA.
+ //
+
+ return NULL;
+
+ }
+
+ }
+
+ //
+ // Create an EISA adapter if this device is an ISA device
+ // or is not a master device.
+ //
+
+ if( (DeviceDescription->Master != TRUE) ||
+ (DeviceDescription->InterfaceType == Isa ) ){
+
+ //
+ // Allocate the Isa Map Register Adapter if it has not
+ // already been allocated.
+ //
+
+ if( HalpIsaMapAdapter == NULL ){
+ HalpIsaMapAdapter = HalpAllocateMapAdapter(
+ &HalpIsaWindowControl,
+ IsaAdapter,
+ HalpIsaMapRegisterBase );
+ if( HalpIsaMapAdapter == NULL ){
+ return NULL;
+ }
+ }
+
+ adapterObject = HalpAllocateEisaAdapter(
+ DeviceDescription,
+ NumberOfMapRegisters );
+
+ if( adapterObject == NULL ){
+ return NULL;
+ }
+
+ adapterObject->Type = IsaAdapter;
+ adapterObject->MapAdapter = HalpIsaMapAdapter;
+ adapterObject->MapRegisterBase = NULL;
+ adapterObject->NumberOfMapRegisters = 0;
+
+ } else {
+
+ //
+ // Allocate the master map register adapter if it has not
+ // already been allocated.
+ //
+
+ if( HalpMasterMapAdapter == NULL ){
+ HalpMasterMapAdapter = HalpAllocateMapAdapter(
+ &HalpMasterWindowControl,
+ BusMasterAdapter,
+ HalpMasterMapRegisterBase );
+ if( HalpMasterMapAdapter == NULL ){
+ return NULL;
+ }
+ }
+
+ //
+ // Allocate an adapter for this master device.
+ //
+
+ adapterObject = HalpAllocateAdapter();
+
+ if( adapterObject == NULL ){
+ return NULL;
+ }
+
+ //
+ // Initialize the adapter object.
+ //
+
+ adapterObject->Type = BusMasterAdapter;
+ adapterObject->MasterDevice = TRUE;
+ adapterObject->MapAdapter = HalpMasterMapAdapter;
+ adapterObject->MapRegisterBase = NULL;
+ adapterObject->NumberOfMapRegisters = 0;
+
+ //
+ // Calculate maximum number of map registers for this adapter.
+ //
+
+ if (NumberOfMapRegisters != NULL) {
+
+ //
+ // Return number of map registers requested based on the maximum
+ // transfer length.
+ //
+
+ *NumberOfMapRegisters = BYTES_TO_PAGES(
+ DeviceDescription->MaximumLength ) + 1;
+
+ //
+ // Limit the number of map registers to no more than 1/4 of all
+ // of the map registers available for this DMA window.
+ //
+
+ MaximumMapRegistersPerChannel =
+ (HalpMasterMapAdapter->WindowSize >> PAGE_SHIFT) / 4;
+ if( *NumberOfMapRegisters > MaximumMapRegistersPerChannel ){
+ *NumberOfMapRegisters = MaximumMapRegistersPerChannel;
+ }
+
+ adapterObject->MapRegistersPerChannel = *NumberOfMapRegisters;
+
+ } else {
+
+ adapterObject->MapRegistersPerChannel = 0;
+
+ }
+ }
+
+ return(adapterObject);
+}
+
+PMAP_REGISTER_ADAPTER
+HalpAllocateMapAdapter(
+ IN PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ IN HAL_ADAPTER_TYPE AdapterType,
+ IN PTRANSLATION_ENTRY MapRegisterBase
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates and initializes the structure for the bus
+ master map register adapter.
+
+Arguments:
+
+ WindowRegisters - Supplies a pointer to the software window control
+ registers that describes the DMA window associated
+ with this map adapter.
+
+ AdapterType - Supplies the type of the adapter.
+
+ MapRegisterBase - Supplies the starting virtual address of the map
+ registers for this adapter.
+
+Return Value:
+
+ Returns the pointer to the allocated and initialized map
+ adapter if allocation was successful, NULL otherwise.
+
+--*/
+
+{
+ ULONG NumberMapRegisters;
+ ULONG Size;
+ PMAP_REGISTER_ADAPTER mapAdapter;
+
+ Size = sizeof(MAP_REGISTER_ADAPTER);
+
+ NumberMapRegisters = WindowRegisters->WindowSize / PAGE_SIZE;
+
+ //
+ // Add size of bitmap. Size of bitmap is the number of bytes required,
+ // computed by dividing map registers by 8 (>>3) and then rounding up
+ // to the nearest value divisible by 4.
+ //
+
+ Size += sizeof(RTL_BITMAP) + (( ((NumberMapRegisters+7) >> 3) + 3) & ~3);
+
+ //
+ // Allocate the map register adapter.
+ //
+
+ mapAdapter = ExAllocatePool( NonPagedPool, Size );
+
+ if( mapAdapter == NULL ){
+ return NULL;
+ }
+
+ //
+ // Initialize the fields within the map adapter structure.
+ //
+
+ mapAdapter->Type = AdapterType;
+
+ KeInitializeSpinLock( &mapAdapter->SpinLock );
+ InitializeListHead( &mapAdapter->RegisterWaitQueue );
+
+ mapAdapter->MapRegisterBase = MapRegisterBase;
+ mapAdapter->NumberOfMapRegisters = NumberMapRegisters;
+ mapAdapter->MapRegisterAllocation = (PRTL_BITMAP)(mapAdapter + 1);
+ RtlInitializeBitMap( mapAdapter->MapRegisterAllocation,
+ (PULONG)((PCHAR)(mapAdapter->MapRegisterAllocation) +
+ sizeof(RTL_BITMAP)),
+ NumberMapRegisters );
+ RtlClearAllBits( mapAdapter->MapRegisterAllocation );
+
+
+ mapAdapter->WindowBase = WindowRegisters->WindowBase;
+ mapAdapter->WindowSize = WindowRegisters->WindowSize;
+
+ mapAdapter->WindowControl = WindowRegisters;
+
+ return mapAdapter;
+}
+
+NTSTATUS
+HalAllocateAdapterChannel(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PWAIT_CONTEXT_BLOCK Wcb,
+ IN ULONG NumberOfMapRegisters,
+ IN PDRIVER_CONTROL ExecutionRoutine
+ )
+/*++
+
+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.
+
+ Wcb - Supplies a wait context block for saving the allocation parameters.
+ The DeviceObject, CurrentIrp and DeviceContext should be initalized.
+
+ 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.
+
+Return Value:
+
+ Returns STATUS_SUCESS unless too many map registers are requested.
+
+Notes:
+
+ Note that this routine MUST be invoked at DISPATCH_LEVEL or above.
+
+--*/
+
+{
+ IO_ALLOCATION_ACTION Action;
+ BOOLEAN Busy = FALSE;
+ PMAP_REGISTER_ADAPTER MapAdapter;
+
+ //
+ // Begin by obtaining a pointer to the map register adapter associated
+ // with this request.
+ //
+
+ MapAdapter = AdapterObject->MapAdapter;
+
+ DebugPrint( (HALDBG_MAPREG,
+ "\nHalAllocateAdapter, Adapter=%x, MapA=%x, Maps=%x\n",
+ AdapterObject, MapAdapter, NumberOfMapRegisters) );
+
+ //
+ // Initialize the device object's wait context block in case this device
+ // must wait before being able to allocate the adapter.
+ //
+
+ Wcb->DeviceRoutine = ExecutionRoutine;
+ Wcb->NumberOfMapRegisters = NumberOfMapRegisters;
+
+ //
+ // Allocate the adapter object for this particular device. If the
+ // adapter cannot be allocated because it has already been allocated
+ // to another device, then return to the caller now; otherwise,
+ // continue.
+ //
+
+ if (!KeInsertDeviceQueue( &AdapterObject->ChannelWaitQueue,
+ &Wcb->WaitQueueEntry )) {
+
+ //
+ // The adapter was not busy so it has been allocated. Now check
+ // to see whether this driver wishes to allocate any map registers.
+ // If so, then queue the device object to the master adapter queue
+ // to wait for them to become available. If the driver wants map
+ // registers, ensure that this adapter has enough total map registers
+ // to satisfy the request.
+ //
+
+ AdapterObject->CurrentWcb = Wcb;
+ AdapterObject->NumberOfMapRegisters = Wcb->NumberOfMapRegisters;
+
+ if (NumberOfMapRegisters != 0) {
+
+ //
+ // Validate that the requested number of map registers is
+ // within the maximum limit.
+ //
+
+ if (NumberOfMapRegisters > MapAdapter->NumberOfMapRegisters) {
+ AdapterObject->NumberOfMapRegisters = 0;
+ IoFreeAdapterChannel(AdapterObject);
+ return(STATUS_INSUFFICIENT_RESOURCES);
+ }
+
+ Busy = HalpAllocateMapRegisters( AdapterObject,
+ NumberOfMapRegisters,
+ FALSE );
+
+ }
+
+ //
+ // If there were either enough map registers available or no map
+ // registers needed to be allocated, invoke the driver's execution
+ // routine now.
+ //
+
+ if (Busy == FALSE) {
+
+ Action = ExecutionRoutine( Wcb->DeviceObject,
+ Wcb->CurrentIrp,
+ AdapterObject->MapRegisterBase,
+ Wcb->DeviceContext
+ );
+
+ //
+ // If the driver wishes to keep the map registers then set the
+ // number allocated to zero and set the action to deallocate
+ // object.
+ //
+
+ if (Action == DeallocateObjectKeepRegisters) {
+ AdapterObject->NumberOfMapRegisters = 0;
+ Action = DeallocateObject;
+ }
+
+ //
+ // If the driver would like to have the adapter deallocated,
+ // then deallocate any map registers allocated and then release
+ // the adapter object.
+ //
+
+ if (Action == DeallocateObject) {
+ IoFreeAdapterChannel( AdapterObject );
+ }
+
+ } else {
+
+ DebugPrint( (HALDBG_MAPREG,
+ "No map registers available, Adapter= %x, Maps= %x\n",
+ AdapterObject, NumberOfMapRegisters) );
+
+ }
+
+ } else {
+
+ DebugPrint( (HALDBG_MAPREG,
+ "Device Queue is busy, AdapterObject = %x\n",
+ AdapterObject) );
+
+ }
+
+ return(STATUS_SUCCESS);
+
+}
+
+BOOLEAN
+HalpAllocateMapRegisters(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG NumberOfMapRegisters,
+ IN BOOLEAN MapAdapterLocked
+ )
+/*++
+
+Routine Description:
+
+ Allocate the requested number of contiguous map registers from
+ the Map adapter.
+
+Arguments:
+
+ AdapterObject - Supplies a pointer to the adapter object for which the
+ map registers are to be allocated.
+
+ NumberOfMapRegisters - Supplies the number of map registers to allocate.
+
+ MapAdapterLocked - Supplies a boolean which indicates if the map adapter
+ for the AdapterObject is already locked.
+
+Return Value:
+
+ The value returned indicates if the map registers are busy.
+ The value FALSE is returned if the map registers were allocated.
+ Otherwise, the Adapter is put on the register wait queue for its
+ associated map adapter and TRUE is returned.
+
+--*/
+{
+ ULONG AllocationMask;
+ BOOLEAN Busy = FALSE;
+ ULONG ExtentBegin;
+ ULONG HintIndex;
+ KIRQL Irql;
+ ULONG MapRegisterIndex;
+ PMAP_REGISTER_ADAPTER mapAdapter;
+
+ //
+ // Some devices do DMA prefetch. This is bad since it will cause certain
+ // chipsets to generate a PFN error because a map register has not been
+ // allocated and validated. To fix this, we'll put in a hack. We'll
+ // allocate one extra map register and map it to some junk page to avoid
+ // this nasty problem.
+ //
+
+ NumberOfMapRegisters += 1;
+
+ //
+ // Acquire a pointer to the map adapter that contains the map registers
+ // for the adapter.
+ //
+
+ mapAdapter = AdapterObject->MapAdapter;
+
+ //
+ // Lock the map register bit map and the adapter queue in the
+ // master adapter object.
+ //
+
+ if( MapAdapterLocked == FALSE ){
+ KeAcquireSpinLock( &mapAdapter->SpinLock, &Irql );
+ }
+
+ MapRegisterIndex = MAXULONG;
+
+ if (IsListEmpty( &mapAdapter->RegisterWaitQueue)) {
+
+ //
+ // If this is an Isa machine and the requested DMA is for an
+ // Isa device then we must be careful that the DMA does not cross
+ // a 64K boundary on the bus.
+ //
+
+ if( (HalpBusType == MACHINE_TYPE_ISA) &&
+ (mapAdapter->Type == IsaAdapter) ){
+
+ ASSERT( (NumberOfMapRegisters * PAGE_SIZE) <= __64K );
+
+ //
+ // This is an Isa allocation, guarantee that the allocation
+ // of map registers will not span a 64K boundary. We do this by
+ // looking for a contiguous allocation of:
+ // NumberOfMapRegisters * 2 - 1
+ // Any allocation of this size will guarantee that:
+ // (a) The allocation fits before the next 64K boundary or
+ // (b) The allocation can be made on the next 64K boundary.
+ //
+ // N.B. - This algorithm depends on RtlFindClear* to find
+ // the first available extent of cleared bits.
+ //
+
+ ExtentBegin = RtlFindClearBits(
+ mapAdapter->MapRegisterAllocation,
+ NumberOfMapRegisters + 7,
+ 0 );
+
+ if( ExtentBegin != -1 ){
+
+ //
+ // Compute the hint index. If ExtentBegin + NumberOfMaps
+ // does not cross a 64K boundary then ExtentBegin will be
+ // the hint index. Otherwise, align the hint to the next
+ // 64K boundary above ExtentBegin.
+ //
+
+ AllocationMask = (__64K >> PAGE_SHIFT) - 1;
+ HintIndex = (ExtentBegin+AllocationMask) & ~AllocationMask;
+
+ MapRegisterIndex = RtlFindClearBitsAndSet(
+ mapAdapter->MapRegisterAllocation,
+ NumberOfMapRegisters,
+ HintIndex );
+
+ }
+
+
+ } else {
+
+ //
+ // This allocation is not subject to the Isa 64K restriction.
+ //
+
+ ExtentBegin = RtlFindClearBits(
+ mapAdapter->MapRegisterAllocation,
+ NumberOfMapRegisters + 7,
+ 0 );
+
+ AllocationMask = (__64K >> PAGE_SHIFT) - 1;
+
+ HintIndex = (ExtentBegin + AllocationMask) & ~AllocationMask;
+
+ MapRegisterIndex = RtlFindClearBitsAndSet(
+ mapAdapter->MapRegisterAllocation,
+ NumberOfMapRegisters,
+ HintIndex );
+
+ } //endif HalpBusType == MACHINE_TYPE_ISA
+
+ } //endif IsListEmpty
+
+ if (MapRegisterIndex == MAXULONG) {
+
+ //
+ // There were not enough free map registers. Queue this request
+ // on the map adapter where it will wait until some registers
+ // are deallocated.
+ //
+
+ InsertTailList( &mapAdapter->RegisterWaitQueue,
+ &AdapterObject->AdapterQueue );
+ Busy = TRUE;
+
+ }
+
+ //
+ // Unlock the map adapter (unless locked by the caller).
+ //
+
+ if( MapAdapterLocked == FALSE ){
+ KeReleaseSpinLock( &mapAdapter->SpinLock, Irql );
+ }
+
+ //
+ // If map registers were allocated, return the index of the first
+ // map register in the contiguous extent.
+ //
+
+ if( Busy == FALSE ){
+ AdapterObject->MapRegisterBase =
+ (PVOID) ((PTRANSLATION_ENTRY) mapAdapter->MapRegisterBase
+ + MapRegisterIndex);
+ }
+
+ return Busy;
+
+}
+
+PADAPTER_OBJECT
+HalpAllocateAdapter(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine allocates and initializes an adapter object to represent an
+ adapter or a DMA controller on the system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The function value is a pointer to the allocated adapter object.
+
+--*/
+
+{
+
+ PADAPTER_OBJECT AdapterObject;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ ULONG Size;
+ HANDLE Handle;
+ NTSTATUS Status;
+
+ //
+ // Begin by initializing the object attributes structure to be used when
+ // creating the adapter object.
+ //
+
+ InitializeObjectAttributes( &ObjectAttributes,
+ NULL,
+ OBJ_PERMANENT,
+ (HANDLE) NULL,
+ (PSECURITY_DESCRIPTOR) NULL
+ );
+
+ Size = sizeof( ADAPTER_OBJECT );
+
+ //
+ // Now create the adapter object.
+ //
+
+ Status = ObCreateObject( KernelMode,
+ *((POBJECT_TYPE *)IoAdapterObjectType),
+ &ObjectAttributes,
+ KernelMode,
+ (PVOID) NULL,
+ Size,
+ 0,
+ 0,
+ (PVOID *)&AdapterObject );
+
+ //
+ // Reference the object.
+ //
+
+ if (NT_SUCCESS(Status)) {
+
+ Status = ObReferenceObjectByPointer(
+ AdapterObject,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ *IoAdapterObjectType,
+ KernelMode
+ );
+
+ }
+
+ //
+ // If the adapter object was successfully created, then attempt to insert
+ // it into the the object table.
+ //
+
+ if (NT_SUCCESS( Status )) {
+
+ Status = ObInsertObject( AdapterObject,
+ NULL,
+ FILE_READ_DATA | FILE_WRITE_DATA,
+ 0,
+ (PVOID *) NULL,
+ &Handle );
+
+ if (NT_SUCCESS( Status )) {
+
+ ZwClose(Handle);
+
+ //
+ // Initialize the adapter object itself.
+ //
+
+ AdapterObject->Type = IO_TYPE_ADAPTER;
+ AdapterObject->Size = (USHORT) Size;
+
+ //
+ // Initialize the channel wait queue for this
+ // adapter.
+ //
+
+ KeInitializeDeviceQueue( &AdapterObject->ChannelWaitQueue );
+
+ } else {
+
+ //
+ // An error was incurred for some reason. Set the return value
+ // to NULL.
+ //
+
+ AdapterObject = (PADAPTER_OBJECT) NULL;
+ }
+
+ } else {
+
+ AdapterObject = (PADAPTER_OBJECT) NULL;
+
+ }
+
+ return AdapterObject;
+
+}
+
+
+
+PVOID
+HalAllocateCrashDumpRegisters(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PULONG NumberOfMapRegisters
+ )
+/*++
+
+Routine Description:
+
+ This routine is called during the crash dump disk driver's initialization
+ to allocate a number map registers permanently.
+
+Arguments:
+
+ AdapterObject - Pointer to the adapter control object to allocate to the
+ driver.
+ NumberOfMapRegisters - Number of map registers requested and updated to
+ show number actually allocated.
+
+Return Value:
+
+ Returns a pointer to the allocated map register base.
+
+--*/
+
+{
+ ULONG AllocationMask;
+ PMAP_REGISTER_ADAPTER MapAdapter;
+ ULONG HintIndex;
+ ULONG MapRegisterIndex;
+ ULONG ExtentBegin;
+
+ //
+ // Begin by obtaining a pointer to the map adapter associated with this
+ // request.
+ //
+
+ MapAdapter = AdapterObject->MapAdapter;
+
+ //
+ // Ensure that this adapter has enough total map registers to satisfy
+ // the request.
+ //
+
+ if (*NumberOfMapRegisters > MapAdapter->NumberOfMapRegisters) {
+ AdapterObject->NumberOfMapRegisters = 0;
+ return NULL;
+ }
+
+ MapRegisterIndex = (ULONG)-1;
+
+ //
+ // If this is an Isa machine and the requested DMA is for an
+ // Isa device then we must be areful that the DMA does not cross
+ // a 64K boundary on the bus.
+ //
+
+ if( (HalpBusType == MACHINE_TYPE_ISA) &&
+ (MapAdapter->Type == IsaAdapter) ){
+
+ //
+ // This is an Isa allocation, guarantee that the allocation
+ // of map registers will not span a 64K boundary. We do this by
+ // looking for a consiguous allocation of:
+ // NumberOfMapRegisters * 2 - 1
+ // Any allocation of this size will guarantee that:
+ // (a) The allocation fitst before the next 64K boundary or
+ // (b) The allocation can be made on the next 64K boundary.
+ //
+ // N.B. - This algorithm depends on RtlFindClear* to find
+ // the first available extent of cleared bits.
+ //
+
+ ExtentBegin = RtlFindClearBits(
+ MapAdapter->MapRegisterAllocation,
+ (*NumberOfMapRegisters * 2) - 1,
+ 0 );
+ if( ExtentBegin != -1){
+
+ //
+ // Compute the hint index. If ExtentBegin + NumberOfMaps
+ // does not cross a 64K boundary then ExtentBegin will be
+ // the hint index. Otherwise, align the hint to the next
+ // 64K boundary above ExtentBegin.
+ //
+
+ AllocationMask = (__64K >> PAGE_SHIFT) - 1;
+ HintIndex = ExtentBegin;
+
+ if( (ExtentBegin + *NumberOfMapRegisters) >
+ ((ExtentBegin + AllocationMask) & ~AllocationMask) ){
+
+ //
+ // Allocation would have spanned a 64K boundary.
+ // Round up to next 64K boundary.
+ //
+
+ HintIndex = (ExtentBegin+AllocationMask) & ~AllocationMask;
+
+ }
+
+ MapRegisterIndex = RtlFindClearBitsAndSet(
+ MapAdapter->MapRegisterAllocation,
+ *NumberOfMapRegisters,
+ HintIndex );
+
+ }
+
+ } else {
+
+ //
+ // This allocation is not subject to the Isa 64K restriction.
+ //
+
+ HintIndex = 0;
+
+ MapRegisterIndex = RtlFindClearBitsAndSet(
+ MapAdapter->MapRegisterAllocation,
+ *NumberOfMapRegisters,
+ 0 );
+
+ }
+
+ if (MapRegisterIndex == (ULONG)-1) {
+
+ //
+ // Not enough free map registers were found, so they were busy
+ // being used by the system when it crashed. Force the appropriate
+ // number to be "allocated" at the base by simply overjamming the
+ // bits and return the base map register as the start.
+ //
+
+ RtlSetBits(
+ MapAdapter->MapRegisterAllocation,
+ HintIndex,
+ *NumberOfMapRegisters
+ );
+ MapRegisterIndex = HintIndex;
+
+ }
+
+ //
+ // Calculate the map register base from the allocated map
+ // register and base of the master adapter object.
+ //
+
+ AdapterObject->MapRegisterBase = (PVOID) ((PTRANSLATION_ENTRY) MapAdapter->MapRegisterBase + MapRegisterIndex);
+
+ return AdapterObject->MapRegisterBase;
+}
+
+
+
+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
+
+--+*/
+
+{
+ IO_ALLOCATION_ACTION Action;
+ BOOLEAN Busy = FALSE;
+ KIRQL Irql;
+ LONG MapRegisterIndex;
+ PLIST_ENTRY Packet;
+ PWAIT_CONTEXT_BLOCK Wcb;
+ PMAP_REGISTER_ADAPTER mapAdapter;
+
+
+ //
+ // Deallocate the extra map register that we originally allocated to fix
+ // the DMA prefetch problem.
+ //
+
+ NumberOfMapRegisters += 1;
+
+ //
+ // Begin by getting the address of the map register adapter.
+ //
+
+ mapAdapter = AdapterObject->MapAdapter;
+
+ DebugPrint( (HALDBG_MAPREG,
+ "IoFreeMapRegisters, Adapter=%x, MapA=%x, Maps=%x\n",
+ AdapterObject, mapAdapter, NumberOfMapRegisters) );
+
+ MapRegisterIndex = (PTRANSLATION_ENTRY) MapRegisterBase -
+ (PTRANSLATION_ENTRY) mapAdapter->MapRegisterBase;
+
+ //
+ // Acquire the map adapter spinlock which locks the adapter queue and the
+ // bit map for the map registers.
+ //
+
+ KeAcquireSpinLock(&mapAdapter->SpinLock, &Irql);
+
+ //
+ // Return the registers to the bit map.
+ //
+
+ RtlClearBits( mapAdapter->MapRegisterAllocation,
+ MapRegisterIndex,
+ NumberOfMapRegisters
+ );
+
+ //
+ // Process any requests waiting for map registers in the adapter queue.
+ // Requests are processed until a request cannot be satisfied or until
+ // there are no more requests in the queue.
+ //
+
+ while(TRUE) {
+
+ if ( IsListEmpty(&mapAdapter->RegisterWaitQueue) ){
+ break;
+ }
+
+ Packet = RemoveHeadList( &mapAdapter->RegisterWaitQueue );
+ AdapterObject = CONTAINING_RECORD( Packet,
+ ADAPTER_OBJECT,
+ AdapterQueue
+ );
+ DebugPrint( (HALDBG_MAPREG,
+ "IoFreeMaps, waking Adapter=%x\n", AdapterObject) );
+
+ Wcb = AdapterObject->CurrentWcb;
+
+ //
+ // Attempt to allocate the map registers.
+ //
+
+ Busy = HalpAllocateMapRegisters( AdapterObject,
+ Wcb->NumberOfMapRegisters,
+ TRUE );
+
+ if( Busy == TRUE ){
+ DebugPrint( (HALDBG_MAPREG,
+ "IoFreeMaps, Not enough maps, Adapter=%x, Maps=%x\n",
+ AdapterObject, Wcb->NumberOfMapRegisters) );
+ break;
+ }
+
+ KeReleaseSpinLock( &mapAdapter->SpinLock, Irql );
+
+ //
+ // Invoke the driver's execution routine now.
+ //
+
+ Action = Wcb->DeviceRoutine( Wcb->DeviceObject,
+ Wcb->CurrentIrp,
+ AdapterObject->MapRegisterBase,
+ Wcb->DeviceContext );
+
+ //
+ // If the driver wishes to keep the map registers then set the number
+ // allocated to zero and set the action to deallocate object.
+ //
+
+ if (Action == DeallocateObjectKeepRegisters) {
+ AdapterObject->NumberOfMapRegisters = 0;
+ Action = DeallocateObject;
+ }
+
+ //
+ // If the driver would like to have the adapter deallocated,
+ // then deallocate any map registers allocated and then release
+ // the adapter object.
+ //
+
+ if (Action == DeallocateObject) {
+
+ //
+ // The map registers are deallocated here rather than in
+ // IoFreeAdapterChannel. This limits the number of times
+ // this routine can be called recursively possibly overflowing
+ // the stack. The worst case occurs if there is a pending
+ // request for the adapter that uses map registers and whos
+ // excution routine decallocates the adapter. In that case if
+ // there are no requests in the map adapter queue, then
+ // IoFreeMapRegisters will get called again.
+ //
+
+ if (AdapterObject->NumberOfMapRegisters != 0) {
+
+ //
+ // Deallocate the map registers and clear the count so that
+ // IoFreeAdapterChannel will not deallocate them again.
+ //
+
+ KeAcquireSpinLock( &mapAdapter->SpinLock, &Irql );
+
+ MapRegisterIndex =
+ (PTRANSLATION_ENTRY)AdapterObject->MapRegisterBase -
+ (PTRANSLATION_ENTRY)mapAdapter->MapRegisterBase;
+
+ RtlClearBits( mapAdapter->MapRegisterAllocation,
+ MapRegisterIndex,
+ AdapterObject->NumberOfMapRegisters
+ );
+
+ AdapterObject->NumberOfMapRegisters = 0;
+
+ KeReleaseSpinLock( &mapAdapter->SpinLock, Irql );
+
+ }
+
+ IoFreeAdapterChannel( AdapterObject );
+ }
+
+ KeAcquireSpinLock( &mapAdapter->SpinLock, &Irql );
+
+ }
+
+ KeReleaseSpinLock( &mapAdapter->SpinLock, Irql );
+}
+
+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.
+
+--*/
+
+{
+ PKDEVICE_QUEUE_ENTRY Packet;
+ PMAP_REGISTER_ADAPTER mapAdapter;
+ BOOLEAN Busy = FALSE;
+ IO_ALLOCATION_ACTION Action;
+ PWAIT_CONTEXT_BLOCK Wcb;
+ KIRQL Irql;
+ LONG MapRegisterNumber;
+
+ //
+ // Begin by getting the address of the map register adapter.
+ //
+
+ mapAdapter = AdapterObject->MapAdapter;
+
+ DebugPrint( (HALDBG_MAPREG,
+ "IoFreeChannel, Adapter=%x, MapAdapter=%x\n",
+ AdapterObject, mapAdapter) );
+
+ //
+ // Pull requests of the adapter's device wait queue as long as the
+ // adapter is free and there are sufficient map registers available.
+ //
+
+ while( TRUE ){
+
+ //
+ // Begin by checking to see whether there are any map registers that
+ // need to be deallocated. If so, then deallocate them now.
+ //
+
+ if (AdapterObject->NumberOfMapRegisters != 0) {
+ IoFreeMapRegisters( AdapterObject,
+ AdapterObject->MapRegisterBase,
+ AdapterObject->NumberOfMapRegisters
+ );
+ }
+
+ //
+ // Simply remove the next entry from the adapter's device wait queue.
+ // If one was successfully removed, allocate any map registers that it
+ // requires and invoke its execution routine.
+ //
+
+ Packet = KeRemoveDeviceQueue( &AdapterObject->ChannelWaitQueue );
+ if (Packet == NULL) {
+
+ //
+ // There are no more requests break out of the loop.
+ //
+
+ break;
+ }
+
+ Wcb = CONTAINING_RECORD( Packet,
+ WAIT_CONTEXT_BLOCK,
+ WaitQueueEntry );
+
+ AdapterObject->CurrentWcb = Wcb;
+ AdapterObject->NumberOfMapRegisters = Wcb->NumberOfMapRegisters;
+
+ DebugPrint( (HALDBG_MAPREG,
+ "IoFreeChannel, waking for Maps=%x\n",
+ Wcb->NumberOfMapRegisters) );
+
+ //
+ // Check to see whether this driver wishes to allocate any map
+ // registers. If so, then queue the device object to the master
+ // adapter queue to wait for them to become available. If the driver
+ // wants map registers, ensure that this adapter has enough total
+ // map registers to satisfy the request.
+ //
+
+ if (Wcb->NumberOfMapRegisters != 0) {
+
+ Busy = HalpAllocateMapRegisters( AdapterObject,
+ Wcb->NumberOfMapRegisters,
+ FALSE );
+
+ }
+
+ //
+ // If there were either enough map registers available or no map
+ // registers needed to be allocated, invoke the driver's execution
+ // routine now.
+ //
+
+ if (Busy == FALSE) {
+
+ AdapterObject->CurrentWcb = Wcb;
+ Action = Wcb->DeviceRoutine( Wcb->DeviceObject,
+ Wcb->CurrentIrp,
+ AdapterObject->MapRegisterBase,
+ Wcb->DeviceContext );
+
+ //
+ // If the execution routine would like to have the adapter
+ // deallocated, then release the adapter object.
+ //
+
+ if (Action == KeepObject) {
+
+ //
+ // This request wants to keep the channel a while so break
+ // out of the loop.
+ //
+
+ break;
+ }
+
+ //
+ // If the driver wants to keep the map registers then set the
+ // number allocated to 0. This keeps the deallocation routine
+ // from deallocating them.
+ //
+
+ if (Action == DeallocateObjectKeepRegisters) {
+ AdapterObject->NumberOfMapRegisters = 0;
+ }
+
+ } else {
+
+ //
+ // This request did not get the requested number of map registers so
+ // out of the loop.
+ //
+
+ DebugPrint( (HALDBG_MAPREG,
+ "IoFreeChannel, not enough maps, Adapter=%x, Maps=%x\n",
+ AdapterObject, Wcb->NumberOfMapRegisters) );
+
+ break;
+ }
+ }
+}
+
+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.
+
+N.B. - The MapRegisterBase must point to the mapping intended for
+ the start virtual address of the Mdl.
+
+--*/
+
+{
+ ULONG NumberOfPages;
+ ULONG Offset;
+ PULONG PageFrameNumber;
+ ULONG i;
+ PMAP_REGISTER_ADAPTER mapAdapter;
+ PTRANSLATION_ENTRY mapRegister;
+ PHYSICAL_ADDRESS ReturnAddress;
+
+ DebugPrint( (HALDBG_IOMT,
+ "\nIoMT: CurrentVA = %x, Length = %x, WriteToDevice = %x\n",
+ CurrentVa, *Length, WriteToDevice ) );
+
+ //
+ // Determine the Map Register Adapter.
+ //
+
+ mapAdapter = NULL;
+
+ if( AdapterObject == NULL ){
+
+ //
+ // The caller did not supply the adapter object, we will determine
+ // the map adapter by matching the MapRegisterBase to the ranges
+ // allocated for each map adapter.
+ //
+
+ if( (HalpIsaMapAdapter != NULL) &&
+ (MapRegisterBase >= HalpIsaMapAdapter->MapRegisterBase) &&
+ ((PTRANSLATION_ENTRY)MapRegisterBase <
+ (PTRANSLATION_ENTRY)HalpIsaMapAdapter->MapRegisterBase +
+ HalpIsaMapAdapter->NumberOfMapRegisters ) ){
+
+ mapAdapter = HalpIsaMapAdapter;
+
+ }
+
+ if( (HalpMasterMapAdapter != NULL) &&
+ (MapRegisterBase >= HalpMasterMapAdapter->MapRegisterBase) &&
+ ((PTRANSLATION_ENTRY)MapRegisterBase <
+ (PTRANSLATION_ENTRY)HalpMasterMapAdapter->MapRegisterBase +
+ HalpMasterMapAdapter->NumberOfMapRegisters ) ){
+
+ mapAdapter = HalpMasterMapAdapter;
+
+ }
+
+ } else {
+
+ //
+ // The adapter object has been provided and will always have
+ // a pointer to the map adapter.
+ //
+
+ mapAdapter = AdapterObject->MapAdapter;
+
+ }
+
+ ASSERT( mapAdapter != NULL );
+
+ //
+ // Begin by determining where in the buffer this portion of the operation
+ // is taking place.
+ //
+
+ Offset = BYTE_OFFSET( (PCHAR)CurrentVa - (PCHAR)Mdl->StartVa );
+ DebugPrint( (HALDBG_IOMT, "Offset (1) = %x\n", Offset ) );
+
+ //
+ // Compute number of pages that this transfer spans.
+ //
+
+ NumberOfPages = (Offset + *Length + PAGE_SIZE - 1) >> PAGE_SHIFT;
+ DebugPrint( (HALDBG_IOMT, "NumberOfPages = %x\n", NumberOfPages ) );
+
+ //
+ // Compute a pointer to the page frame of the starting page of the transfer.
+ //
+
+ PageFrameNumber = (PULONG) (Mdl + 1);
+ PageFrameNumber += ( ((PCHAR) CurrentVa - (PCHAR) Mdl->StartVa)
+ >> PAGE_SHIFT );
+
+ //
+ // Compute a pointer to the map register that maps the starting page of
+ // the transfer.
+ //
+
+ mapRegister = MapRegisterBase;
+
+ //
+ // For each page, establish the mapping in the scatter/gather tables.
+ //
+
+ for (i = 0; i < NumberOfPages; i++) {
+ HAL_MAKE_VALID_TRANSLATION( mapRegister, *PageFrameNumber );
+ DebugPrint( (HALDBG_IOMT,
+ "Validate: *PageFrameNumber = %x, mapRegister = %x\n",
+ *PageFrameNumber, mapRegister ) );
+ PageFrameNumber += 1;
+ mapRegister += 1;
+ }
+
+ //
+ // If the operation is a write to device (transfer from memory to device),
+ // we will validate the extra map register so we don't generate a PFN
+ // error due to DMA prefetch by some devices.
+ //
+
+ if (WriteToDevice) {
+ PageFrameNumber -= 1;
+ HAL_MAKE_VALID_TRANSLATION( mapRegister, *PageFrameNumber );
+ }
+
+ //
+ // Synchronize the scatter/gather entry writes with any subsequent writes
+ // to the device.
+ //
+
+ HalpMb(); //jnfix - create HalpWmb();
+
+ //
+ // Invalidate any cached translations in the DMA window.
+ //
+
+ INVALIDATE_DMA_TRANSLATIONS( mapAdapter->WindowControl );
+
+ //
+ // Set the offset to point to the map register plus the offset.
+ //
+
+ Offset += ((PTRANSLATION_ENTRY) MapRegisterBase -
+ (PTRANSLATION_ENTRY) mapAdapter->MapRegisterBase) << PAGE_SHIFT;
+
+ Offset += (ULONG)mapAdapter->WindowBase;
+ DebugPrint( (HALDBG_IOMT, "Offset(3) = %x\n", Offset ) );
+
+ if( (AdapterObject != NULL) &&
+ (AdapterObject->Type == IsaAdapter) &&
+ (AdapterObject->MasterDevice != TRUE) ){
+
+ //
+ // Start the EISA DMA controller.
+ //
+
+ HalpMapEisaTransfer(
+ AdapterObject,
+ Offset,
+ *Length,
+ WriteToDevice
+ );
+
+ }
+
+ ReturnAddress.QuadPart = Offset;
+ return(ReturnAddress);
+}
+
+
+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 adapter object buffers and 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 NumberOfPages;
+ ULONG Offset;
+ BOOLEAN Result;
+ ULONG i;
+ PMAP_REGISTER_ADAPTER mapAdapter;
+ PTRANSLATION_ENTRY mapRegister;
+
+ DebugPrint( (HALDBG_IOMT,
+ "\nIoFlush: CurrentVA = %x, Length = %x, WriteToDevice = %x\n",
+ CurrentVa, Length, WriteToDevice ) );
+
+ //
+ // Determine the Map Register Adapter.
+ //
+
+ mapAdapter = NULL;
+
+ if( AdapterObject == NULL ){
+
+ //
+ // The caller did not supply the adapter object, we will determine
+ // the map adapter by matching the MapRegisterBase to the ranges
+ // allocated for each map adapter.
+ //
+
+ if( (HalpIsaMapAdapter != NULL) &&
+ (MapRegisterBase >= HalpIsaMapAdapter->MapRegisterBase) &&
+ ((PTRANSLATION_ENTRY)MapRegisterBase <
+ (PTRANSLATION_ENTRY)HalpIsaMapAdapter->MapRegisterBase +
+ HalpIsaMapAdapter->NumberOfMapRegisters ) ){
+
+ mapAdapter = HalpIsaMapAdapter;
+
+ }
+
+ if( (HalpMasterMapAdapter != NULL) &&
+ (MapRegisterBase >= HalpMasterMapAdapter->MapRegisterBase) &&
+ ((PTRANSLATION_ENTRY)MapRegisterBase <
+ (PTRANSLATION_ENTRY)HalpMasterMapAdapter->MapRegisterBase +
+ HalpMasterMapAdapter->NumberOfMapRegisters ) ){
+
+ mapAdapter = HalpMasterMapAdapter;
+
+ }
+
+ } else {
+
+ //
+ // The adapter object has been provided and will always have
+ // a pointer to the map adapter.
+ //
+
+ mapAdapter = AdapterObject->MapAdapter;
+
+ }
+
+ //
+ // Set the result of the flush to success.
+ //
+
+ Result = TRUE;
+
+ //
+ // If this is an Isa compatiable adapter or an adapter that uses
+ // the ISA/EISA Dma controllers then use the standard routines
+ // to clear the Dma controller.
+ //
+
+ if( (AdapterObject != NULL) &&
+ (AdapterObject->Type == IsaAdapter) &&
+ (AdapterObject->MasterDevice != TRUE) ){
+
+ Result = HalpFlushEisaAdapter( AdapterObject,
+ Mdl,
+ MapRegisterBase,
+ CurrentVa,
+ Length,
+ WriteToDevice );
+ }
+
+ //
+ // The Mdl->StartVa must point to a page boundary.
+ //
+
+ ASSERT( ( (ULONG)Mdl->StartVa & (PAGE_SIZE-1) ) == 0 );
+
+ //
+ // Compute the starting offset of the transfer.
+ //
+
+ Offset = BYTE_OFFSET( (PCHAR)CurrentVa - (PCHAR)Mdl->StartVa );
+
+ //
+ // Compute the number of pages that this transfer spanned.
+ //
+
+ NumberOfPages = (Offset + Length + PAGE_SIZE-1) >> PAGE_SHIFT;
+
+ //
+ // Compute a pointer to the first translation entry that mapped this
+ // transfer.
+ //
+
+ mapRegister = (PTRANSLATION_ENTRY)MapRegisterBase;
+
+ //
+ // Mark each translation as invalid.
+ //
+
+ for( i=0; i < NumberOfPages; i++ ){
+ HAL_INVALIDATE_TRANSLATION( mapRegister );
+ DebugPrint( (HALDBG_IOMT,
+ "Invalidate mapRegister = %x, PageFrame=%x\n",
+ mapRegister, (PTRANSLATION_ENTRY)mapRegister->Pfn) );
+ mapRegister += 1;
+ }
+
+ if( WriteToDevice ){
+ HAL_INVALIDATE_TRANSLATION( mapRegister );
+ }
+
+ //
+ // Invalidate any cached translations in the DMA window.
+ //
+
+ INVALIDATE_DMA_TRANSLATIONS( mapAdapter->WindowControl );
+
+ //
+ // Synchronize the updated translations with any subsequent device
+ // accesses.
+ // Also, synchronize any reads of the newly written DMA data by
+ // ensuring this processors view of memory is coherent.
+ // jnfix - actually this second task must be handled by HalFlushIoBuffers
+ //
+
+ HalpMb();
+
+ return Result;
+
+}
+
+ULONG
+HalReadDmaCounter(
+ IN PADAPTER_OBJECT AdapterObject
+ )
+/*++
+
+Routine Description:
+
+ This function reads the DMA counter and returns the number of bytes left
+ to be transfered.
+
+Arguments:
+
+ AdapterObject - Supplies a pointer to the adapter object to be read.
+
+Return Value:
+
+ Returns the number of bytes still be be transfered.
+
+--*/
+
+{
+
+ //
+ // If this is an Isa compatiable adapter or an adapter that uses
+ // the ISA/EISA Dma controllers then use the standard routines
+ // to return the Dma count.
+ //
+
+ if( AdapterObject->Type == IsaAdapter ){
+
+ return HalpReadEisaDmaCounter( AdapterObject );
+
+ }
+
+ return 0;
+
+}
+
+
+PVOID
+HalAllocateCommonBuffer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG Length,
+ OUT PPHYSICAL_ADDRESS LogicalAddress,
+ IN BOOLEAN CacheEnabled
+ )
+/*++
+
+Routine Description:
+
+ This function allocates the memory for a common buffer and maps so that it
+ can be accessed by a master device and the CPU.
+
+Arguments:
+
+ AdapterObject - Supplies a pointer to the adapter object used by this
+ device.
+
+ Length - Supplies the length of the common buffer to be allocated.
+
+ LogicalAddress - Returns the logical address of the common buffer.
+
+ CacheEnable - Indicates whether the memeory is cached or not.
+
+Return Value:
+
+ Returns the virtual address of the common buffer. If the buffer cannot be
+ allocated then NULL is returned.
+
+--*/
+
+{
+ PVOID virtualAddress;
+ PVOID mapRegisterBase;
+ ULONG numberOfMapRegisters;
+ ULONG mappedLength;
+ WAIT_CONTEXT_BLOCK wcb;
+ KEVENT allocationEvent;
+ NTSTATUS status;
+ PMDL mdl;
+ KIRQL irql;
+ PHYSICAL_ADDRESS MaxPhysicalAddress;
+
+ numberOfMapRegisters = BYTES_TO_PAGES(Length);
+
+ //
+ // Allocate the actual buffer and limit its physical address
+ // below 1GB. The 1GB limitation guarantees that the buffer will
+ // be accessible via 32-bit superpage.
+ //
+
+ MaxPhysicalAddress.HighPart = 0;
+ MaxPhysicalAddress.LowPart = __1GB - 1;
+ virtualAddress = MmAllocateContiguousMemory( Length, MaxPhysicalAddress );
+
+ if (virtualAddress == NULL) {
+
+ return(virtualAddress);
+
+ }
+
+ //
+ // Initialize an event.
+ //
+
+ KeInitializeEvent( &allocationEvent, NotificationEvent, FALSE);
+
+ //
+ // Initialize the wait context block. Use the device object to indicate
+ // where the map register base should be stored.
+ //
+
+ wcb.DeviceObject = &mapRegisterBase;
+ wcb.CurrentIrp = NULL;
+ wcb.DeviceContext = &allocationEvent;
+
+ //
+ // Allocate the adapter and the map registers.
+ //
+
+ KeRaiseIrql(DISPATCH_LEVEL, &irql);
+
+ status = HalAllocateAdapterChannel(
+ AdapterObject,
+ &wcb,
+ numberOfMapRegisters,
+ HalpAllocationRoutine
+ );
+
+ KeLowerIrql(irql);
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Cleanup and return NULL.
+ //
+
+ MmFreeContiguousMemory( virtualAddress );
+ return(NULL);
+
+ }
+
+ //
+ // Wait for the map registers to be allocated.
+ //
+
+ status = KeWaitForSingleObject(
+ &allocationEvent,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL
+ );
+
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Cleanup and return NULL.
+ //
+
+ MmFreeContiguousMemory( virtualAddress );
+ return(NULL);
+
+ }
+
+ //
+ // Create an mdl to use with call to I/O map transfer.
+ //
+
+ mdl = IoAllocateMdl(
+ virtualAddress,
+ Length,
+ FALSE,
+ FALSE,
+ NULL
+ );
+
+ MmBuildMdlForNonPagedPool(mdl);
+
+ //
+ // Map the transfer so that the controller can access the memory.
+ //
+
+ mappedLength = Length;
+ *LogicalAddress = IoMapTransfer(
+ NULL,
+ mdl,
+ mapRegisterBase,
+ virtualAddress,
+ &mappedLength,
+ TRUE
+ );
+
+ IoFreeMdl(mdl);
+
+ if (mappedLength < Length) {
+
+ //
+ // Cleanup and indicate that the allocation failed.
+ //
+
+ HalFreeCommonBuffer(
+ AdapterObject,
+ Length,
+ *LogicalAddress,
+ virtualAddress,
+ FALSE
+ );
+
+ return(NULL);
+ }
+
+ //
+ // The allocation completed successfully.
+ //
+
+ return(virtualAddress);
+
+}
+
+VOID
+HalFreeCommonBuffer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG Length,
+ IN PHYSICAL_ADDRESS LogicalAddress,
+ IN PVOID VirtualAddress,
+ IN BOOLEAN CacheEnabled
+ )
+/*++
+
+Routine Description:
+
+ This function frees a common buffer and all of the resouces it uses.
+
+Arguments:
+
+ AdapterObject - Supplies a pointer to the adapter object used by this
+ device.
+
+ Length - Supplies the length of the common buffer. This should be the same
+ value used for the allocation of the buffer.
+
+ LogicalAddress - Supplies the logical address of the common buffer. This
+ must be the same value return by HalAllocateCommonBuffer.
+
+ VirtualAddress - Supplies the virtual address of the common buffer. This
+ must be the same value return by HalAllocateCommonBuffer.
+
+ CacheEnable - Indicates whether the memeory is cached or not.
+
+Return Value:
+
+ None
+
+--*/
+
+{
+ PMAP_REGISTER_ADAPTER mapAdapter;
+ PTRANSLATION_ENTRY mapRegisterBase;
+ ULONG mapRegisterIndex;
+ ULONG numberOfMapRegisters;
+
+ mapAdapter = AdapterObject->MapAdapter;
+
+ //
+ // Calculate the number of map registers, the map register index and
+ // the map register base.
+ //
+
+ numberOfMapRegisters = ADDRESS_AND_SIZE_TO_SPAN_PAGES( VirtualAddress,
+ Length );
+ mapRegisterIndex = (LogicalAddress.LowPart - (ULONG)mapAdapter->WindowBase)
+ >> PAGE_SHIFT;
+
+ mapRegisterBase = (PTRANSLATION_ENTRY) mapAdapter->MapRegisterBase
+ + mapRegisterIndex;
+
+ //
+ // Free the map registers.
+ //
+
+ IoFreeMapRegisters(
+ AdapterObject,
+ (PVOID) mapRegisterBase,
+ numberOfMapRegisters
+ );
+
+ //
+ // Free the memory for the common buffer.
+ //
+
+ MmFreeContiguousMemory( VirtualAddress );
+
+ return;
+
+}
+
+
+BOOLEAN
+HalFlushCommonBuffer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG Length,
+ IN PHYSICAL_ADDRESS LogicalAddress,
+ IN PVOID VirtualAddress
+ )
+/*++
+
+Routine Description:
+
+ This function is called to flush any hardware adapter buffers when the
+ driver needs to read data written by an I/O master device to a common
+ buffer.
+
+Arguments:
+
+ AdapterObject - Supplies a pointer to the adapter object used by this
+ device.
+
+ Length - Supplies the length of the common buffer. This should be the same
+ value used for the allocation of the buffer.
+
+ LogicalAddress - Supplies the logical address of the common buffer. This
+ must be the same value return by HalAllocateCommonBuffer.
+
+ VirtualAddress - Supplies the virtual address of the common buffer. This
+ must be the same value return by HalAllocateCommonBuffer.
+
+Return Value:
+
+ Returns TRUE if no errors were detected; otherwise, FALSE is return.
+
+--*/
+
+{
+
+ return(TRUE);
+
+}
+
+IO_ALLOCATION_ACTION
+HalpAllocationRoutine (
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID MapRegisterBase,
+ IN PVOID Context
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called by HalAllocateAdapterChannel when sufficent resources
+ are available to the driver. This routine saves the MapRegisterBase,
+ and set the event pointed to by the context parameter.
+
+Arguments:
+
+ DeviceObject - Supplies a pointer where the map register base should be
+ stored.
+
+ 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:
+
+ DeallocateObjectKeepRegisters - Indicates the adapter should be freed
+ and mapregisters should remain allocated after return.
+
+--*/
+
+{
+
+ UNREFERENCED_PARAMETER(Irp);
+
+ *((PVOID *) DeviceObject) = MapRegisterBase;
+
+ (VOID) KeSetEvent( (PKEVENT) Context, 0L, FALSE );
+
+ return(DeallocateObjectKeepRegisters);
+}
diff --git a/private/ntos/nthals/halalpha/ebsgdma.h b/private/ntos/nthals/halalpha/ebsgdma.h
new file mode 100644
index 000000000..2548b8134
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ebsgdma.h
@@ -0,0 +1,180 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ ebsgdma.h
+
+Abstract:
+
+ This file defines the data structures for scatter/gather DMA
+ support for Eisa/Isa bus systems.
+
+Author:
+
+ Joe Notarangelo 12-Oct-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#ifndef _EBSGDMA_
+#define _EBSGDMA_
+
+#include "eisa.h"
+
+
+//
+// Define the structures for Io Adapters.
+//
+
+typedef enum _HAL_ADAPTER_TYPE{
+ IsaAdapter,
+ BusMasterAdapter
+} HAL_ADAPTER_TYPE, *PHAL_ADAPTER_TYPE;
+
+typedef struct _MAP_REGISTER_ADAPTER{
+
+ //
+ // The type of the map register adapter.
+ //
+
+ HAL_ADAPTER_TYPE Type;
+
+ //
+ // Access control for allocating map registers.
+ // The SpinLock guarantees exclusive access to this adapter.
+ // The RegisterWaitQueue is a list of adapters waiting for
+ // map registers. The spinlock is also used to grant exclusive
+ // access to other resources which may be shared by the adapters
+ // that have this map adapter in common (in particular, access to the
+ // DMA controller hardware in Eisa/Isa machines).
+ //
+
+ KSPIN_LOCK SpinLock;
+ LIST_ENTRY RegisterWaitQueue;
+
+ //
+ // MapRegisterBase is the base address of the scatter/gather entry
+ // array. NumberOfMapRegisters is the number of scatter/gather entries
+ // allocated for this adapter. MapRegisterAllocation points to the
+ // allocation bitmap for the scatter/gather entry array.
+ //
+
+ PVOID MapRegisterBase;
+ ULONG NumberOfMapRegisters;
+ PRTL_BITMAP MapRegisterAllocation;
+
+ //
+ // WindowBase is the base bus address of the DMA window controlled
+ // by this adapter. WindowSize is the size of the window in bytes.
+ //
+
+ PVOID WindowBase;
+ ULONG WindowSize;
+
+ //
+ // WindowControl is a pointer to the window control registers
+ // structure that defines the QVAs of the window registers.
+ //
+
+ PVOID WindowControl;
+
+} MAP_REGISTER_ADAPTER, *PMAP_REGISTER_ADAPTER;
+
+
+typedef struct _ADAPTER_OBJECT{
+
+ //
+ // Object header fields, type and size.
+ ///
+
+ CSHORT ObjectType;
+ CSHORT Size;
+
+ //
+ // The type of the adapter, either an adapter that requires Isa
+ // support or an adapter that does not.
+ //
+
+ HAL_ADAPTER_TYPE Type;
+
+ //
+ // Pointer to the adapter that controls the map registers for this
+ // adapter.
+ //
+
+ PMAP_REGISTER_ADAPTER MapAdapter;
+
+ //
+ // Indicate if this is a master device or not.
+ //
+
+ BOOLEAN MasterDevice;
+
+ //
+ // The maximum map registers for this adapter.
+ //
+
+ ULONG MapRegistersPerChannel;
+
+ //
+ // The map registers currently allocated to this adapter, the base
+ // address and the number. The number will be the number desired for
+ // allocation if this adapter is waiting on the map adapters queue.
+ //
+
+ PVOID MapRegisterBase;
+ ULONG NumberOfMapRegisters;
+
+ //
+ // The device queue for waiters trying to all allocate this adapter.
+ //
+
+ KDEVICE_QUEUE ChannelWaitQueue;
+
+ //
+ // The wait context block of the driver that has currently allocated
+ // the adapter.
+ //
+
+ struct _WAIT_CONTEXT_BLOCK *CurrentWcb;
+
+ //
+ // The list entry used when this adapter is queue to a map adapter,
+ // waiting for map registers.
+ //
+
+ LIST_ENTRY AdapterQueue;
+
+ //
+ // Values describing the programming of a DMA channel for this
+ // adapter. The values describe the programming for a standard PC
+ // DMA controller.
+ //
+ // AdapterBaseVa - pointer to base address of DMA controller.
+ // AdapterNumber - the number of the DMA controller.
+ // ChannelNumber - the DMA channel number used by the adapter.
+ // AdapterMode - the mode used to program the DMA channel.
+ // ExtendedMode - the value used to program extended mode for the channel.
+ // SingleMaskPort - port address for unmasking the DMA controller.
+ // PagePort - port address of the page register for the DMA channel.
+ //
+
+ PVOID AdapterBaseVa;
+ UCHAR AdapterNumber;
+ UCHAR ChannelNumber;
+ UCHAR AdapterMode;
+ DMA_EXTENDED_MODE ExtendedMode;
+ PUCHAR PagePort;
+ BOOLEAN Width16Bits;
+
+} ADAPTER_OBJECT;
+
+#endif //_EBSGDMA_
diff --git a/private/ntos/nthals/halalpha/eeprom8k.c b/private/ntos/nthals/halalpha/eeprom8k.c
new file mode 100644
index 000000000..c4e73260f
--- /dev/null
+++ b/private/ntos/nthals/halalpha/eeprom8k.c
@@ -0,0 +1,391 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ eeprom8k.c
+
+Abstract:
+
+ This module implements the device-specific routines necessary to
+ Read and Write the Electrically Eraseable Programmable Read Only
+ Memory (EEPROM) containing the system environment variables. Note
+ that this module is used in exclusion of CMOS NVram support for the
+ same variables.
+
+ This module assumes that a standard PC NVRAM interface to the EEPROM
+ is being provided (for example the one provide by the Intel ESC
+ chip). This interface gives a 256 byte NVRAM page window into the
+ device. The current NVRAM page is selected through a page select
+ register.
+
+ Parts support by this module include:
+
+ Xicor X2864A
+
+ The routines implemented here are:
+
+ HalpReadNVRamBuffer() - copy data from NVRAM into memory
+ HalpWriteNVRamBuffer() - write memory data to NVRAM
+ HalpCopyNVRamBuffer() - move data within the NVRAM
+
+Author:
+
+ Steve Brooks 5-Oct 93
+
+
+Revision History:
+
+ Steve Jenness 10-Nov 93
+ Joe Notarangelo 10-Nov 93
+ Matthew Buchman 09-May 96 Stall instead of polling for Write complete.
+ Scott Lee 23-Sept-96 Use original write algorithm and add a check
+ for the last write.
+
+--*/
+
+
+#include "halp.h"
+#include "cmos8k.h" // This is ok for eeprom8k.c
+
+#include "arccodes.h"
+
+#ifdef HAL_DBG
+ULONG EepromDebug = 0;
+#define EepromDbgPrint(x) if (EepromDebug) DbgPrint(x)
+#else
+#define EepromDbgPrint(x)
+#endif //HAL_DBG
+
+//
+// Routine prototypes.
+//
+
+ARC_STATUS
+HalpReadNVRamBuffer (
+ OUT PCHAR DataPtr,
+ IN PCHAR NvRamPtr,
+ IN ULONG Length
+ );
+
+ARC_STATUS
+HalpWriteNVRamBuffer (
+ IN PCHAR NvRamPtr,
+ IN PCHAR DataPtr,
+ IN ULONG Length
+ );
+
+ARC_STATUS
+HalpCopyNVRamBuffer (
+ IN PCHAR NvDestPtr,
+ IN PCHAR NvSrcPtr,
+ IN ULONG Length
+ );
+
+
+
+ARC_STATUS
+HalpReadNVRamBuffer (
+ OUT PCHAR DataPtr,
+ IN PCHAR NvRamPtr,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads data from the EEPROM into main memory.
+
+Arguments:
+
+ DataPtr - Pointer to memory location to receive data
+ NvRamPtr - Pointer (qva) to EEPROM location to read data from
+ Length - Number of bytes of data to transfer
+
+Return Value:
+
+ ESUCCESS if the operation succeeds.
+
+--*/
+{
+ ULONG PageSelect, ByteSelect;
+
+ PageSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT;
+ ByteSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;
+
+ WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect);
+ while ( Length -- )
+ {
+ *DataPtr++ = READ_CONFIG_RAM_DATA(NvRamPtr);
+ NvRamPtr ++;
+
+ ByteSelect = (ByteSelect + 1) & CONFIG_RAM_BYTE_MASK;
+ if (ByteSelect == 0)
+ {
+ PageSelect++;
+ WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect);
+ }
+ }
+
+ return(ESUCCESS);
+}
+
+ARC_STATUS
+HalpWriteNVRamBuffer (
+ IN PCHAR NvRamPtr,
+ IN PCHAR DataPtr,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine Writes data from memory into the EEPROM. EEPROM page
+ mode write is used.
+
+ N.B. - This routine could have problems if interrupts are enabled
+ and the writing time between two bytes is over 20uSec.
+
+ N.B. - The ESC provides the NVRAM interface on 256
+ byte NVRAM pages. The EEPROM internally uses 16byte pages for
+ grouped programming. A EEPROM 16byte page commits (programs into
+ the EEPROM) in the same amount of time as a single byte does.
+ A EEPROM page has to be committed before switching to another
+ page. This is true if only 1 byte is written or all 16.
+
+ N.B. - This routine assumes that the base address of the 256 byte
+ page buffer is on a 256 byte boundary.
+
+ N.B. - With the increase in processor speed and compiler technology,
+ we seem to violate a time increment that must occur between
+ Writes followed by Reads. This results in invaliding the
+ last write of the page. By first waiting the amount of a
+ write cycle, (specified in the Data Sheet as 5ms) after the last
+ write before reading, we don't run into this problem.
+
+ N.B. - The last write algorithm used did not worked with the 120 nsec part.
+ We have reverted back to the original algorithm and added a
+ modification. On the last write, if it is on a 256 byte page
+ boundary, do not increment and write the page select. Doing so will
+ cause the verification of the last write to fail.
+
+Arguments:
+
+ NvRamPtr - Pointer (qva) to EEPROM location to write data into
+ DataPtr - Pointer to memory location of data to be written
+ Length - Number of bytes of data to transfer
+
+Return Value:
+
+ ESUCCESS if the operation succeeds.
+
+--*/
+{
+ ULONG PageSelect;
+
+#define EEPROM_PAGE_SIZE 16
+#define EEPROM_OFFSET_MASK 0xF
+
+ ULONG EepromPageDataValid = FALSE;
+ UCHAR EepromPageData[EEPROM_PAGE_SIZE];
+ ULONG EepromPageOffset = 0;
+
+ BOOLEAN ByteWritten = FALSE;
+ PCHAR LastWrittenByteAddress;
+ ULONG LastWrittenByteValue;
+
+ //
+ // Calculate which NVRAM 256 byte page to select first.
+ //
+
+ PageSelect = (NvRamPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT;
+ WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect);
+
+ //
+ // Loop until no more data to write.
+ //
+
+ while ( (Length --) != 0) {
+
+ //
+ // If the current page of EEPROM data hasn't been read from the
+ // device, do so now. The whole EEPROM page is read at once so
+ // that it doesn't interfere with the EEPROM programming timeout.
+ //
+
+ if (EepromPageDataValid == FALSE) {
+ PCHAR TmpNvRamPtr = NvRamPtr;
+
+ EepromPageOffset = (ULONG)NvRamPtr & EEPROM_OFFSET_MASK;
+
+ while (EepromPageOffset < EEPROM_PAGE_SIZE) {
+ EepromPageData[EepromPageOffset++] =
+ READ_CONFIG_RAM_DATA(TmpNvRamPtr);
+ TmpNvRamPtr++;
+ }
+
+ EepromPageDataValid = TRUE;
+ EepromPageOffset = (ULONG)NvRamPtr & EEPROM_OFFSET_MASK;
+ }
+
+ //
+ // If the EEPROM data matches the data to be written, short-circuit
+ // the write. This potentially saves lots of time.
+ // If the data is different, write it and remember that a byte
+ // was written for the NOT-DATA polling done later.
+ //
+
+ if (EepromPageData[EepromPageOffset] != *DataPtr) {
+
+ WRITE_CONFIG_RAM_DATA(NvRamPtr, *DataPtr);
+ ByteWritten = TRUE;
+ LastWrittenByteValue = *DataPtr;
+ LastWrittenByteAddress = NvRamPtr;
+
+ EepromDbgPrint( "." );
+ } else {
+ EepromDbgPrint( "o" );
+ }
+
+ EepromPageOffset ++;
+ NvRamPtr ++;
+ DataPtr ++;
+
+ //
+ // If we're stepping into the next EEPROM 16 byte page first make
+ // sure that the data for the previous page has been programmed.
+ // Invalidate the current EEPROM page data buffer so that the next
+ // page will be read in (for the short-circuit above).
+ //
+
+ if (EepromPageOffset >= EEPROM_PAGE_SIZE) {
+ if (ByteWritten == TRUE) {
+ while((READ_CONFIG_RAM_DATA(LastWrittenByteAddress) & 0xff) !=
+ (UCHAR)(LastWrittenByteValue & 0xff));
+ ByteWritten = FALSE;
+ }
+ EepromPageDataValid = FALSE;
+ }
+
+ //
+ // If we are stepping into the next NVRAM 256 byte page, switch
+ // the NVRAM page select. Don't step into the next page on the
+ // last write, however.
+ //
+
+ if ((Length != 0) &&
+ (((ULONG)NvRamPtr & CONFIG_RAM_BYTE_MASK) == 0 ) ) {
+ PageSelect++;
+ WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect);
+ }
+ }
+
+ //
+ // Poll until the last byte written is programmed into the EEPROM.
+ //
+
+ if (ByteWritten == TRUE) {
+ while((READ_CONFIG_RAM_DATA(LastWrittenByteAddress) & 0xff) !=
+ (UCHAR)(LastWrittenByteValue & 0xff));
+ }
+
+ return(ESUCCESS);
+}
+
+ARC_STATUS
+HalpCopyNVRamBuffer (
+ IN PCHAR NvDestPtr,
+ IN PCHAR NvSrcPtr,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This routine copies data between two locations within the EEPROM. It is
+ the callers responsibility to assure that the destination region does not
+ overlap the src region i.e. if the regions overlap, NvSrcPtr > NvDestPtr.
+
+ This routine does not use page mode access since we're unsure that
+ we can guarantee the 20uSec inter-byte timing required during a
+ page write. Currently, each byte is written and then checked for
+ commit into the EEPROM.
+
+ N.B. - This routine has not been optimized like HalpWriteNVRamBuffer.
+
+ N.B. - This routine doesn't appear to be used anywhere in either the
+ firmware, the HAL, or the kernel. It might not work.
+
+Arguments:
+
+ NvDestPtr - Pointer (qva) to NVRam location to write data into
+ NvSrcPtr - Pointer (qva) to NVRam location of data to copy
+ Length - Number of bytes of data to transfer
+
+Return Value:
+
+ ESUCCESS if the operation succeeds.
+
+--*/
+
+{
+ ULONG PageSelect0, ByteSelect0; // Src Pointer Page & offset
+ ULONG PageSelect1, ByteSelect1; // Dest Pointer Page & offset
+
+
+ PageSelect0 = (NvSrcPtr - (PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT;
+ ByteSelect0 = (NvSrcPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;
+
+ PageSelect1 = (NvDestPtr-(PUCHAR)HalpCMOSRamBase) >> CONFIG_RAM_PAGE_SHIFT;
+ ByteSelect1 = (NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;
+
+ WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect0);
+ while ( Length -- )
+ {
+ UCHAR AChar;
+
+ //
+ // Check the Page select for the src pointer, and write the
+ // select register if necessary:
+ //
+ if (ByteSelect0 == 0)
+ {
+ PageSelect0++;
+ }
+ if ( PageSelect0 != PageSelect1 )
+ {
+ WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect0);
+ }
+
+ AChar = READ_CONFIG_RAM_DATA(NvSrcPtr);
+ ByteSelect0 = (ByteSelect0 + 1) & CONFIG_RAM_BYTE_MASK;
+
+ //
+ // Check the page select for the dest pointer, and write
+ // the select register if necessary:
+ //
+ if (ByteSelect1 == 0)
+ {
+ PageSelect1++;
+ }
+ if ( PageSelect1 != PageSelect0 )
+ {
+ WRITE_CONFIG_RAM_PAGE_SELECT(PageSelect1);
+ }
+
+ WRITE_CONFIG_RAM_DATA(NvDestPtr, AChar);
+
+ while ( READ_CONFIG_RAM_DATA(NvDestPtr) != AChar )
+ ;
+ ByteSelect1 = (ByteSelect1 + 1) & CONFIG_RAM_BYTE_MASK;
+
+ NvSrcPtr ++;
+ NvDestPtr ++;
+ }
+
+ return(ESUCCESS);
+}
diff --git a/private/ntos/nthals/halalpha/eisaprof.c b/private/ntos/nthals/halalpha/eisaprof.c
new file mode 100644
index 000000000..71350f4f6
--- /dev/null
+++ b/private/ntos/nthals/halalpha/eisaprof.c
@@ -0,0 +1,517 @@
+/*++
+
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ eisaprof.c
+
+Abstract:
+
+ This module handles the Profile Counter and all Profile counter functions
+ for the standard EISA interval timer.
+
+Author:
+
+ Jeff McLeman (mcleman) 05-June-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+ Rod Gamache [DEC] 9-Mar-1993
+ Fix profile clock.
+
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+#include "halprof.h"
+
+//
+// Define global data.
+//
+
+//
+// Values used for Profile Clock
+//
+
+// Convert the interval to rollover count for 8254 timer. Since
+// the 8254 counts down a 16 bit value at the clock rate of 1.193 MHZ,
+// the computation is:
+//
+// RolloverCount = (Interval * 0.0000001) * (1193 * 1000000)
+// = Interval * .1193
+// = Interval * 1193 / 10000
+
+#define PROFILE_INTERVAL 1193
+#define PROFILE_INTERVALS_PER_100NS 10000/1193
+#define MIN_PROFILE_TICKS 4
+#define MAX_PROFILE_TICKS 0x10000 // 16 bit counter (zero is max)
+
+//
+// Since the profile timer interrupts at a frequency of 1.193 MHZ, we
+// have .1193 intervals each 100ns. So we need a more reasonable value.
+// If we compute the timer based on 1600ns intervals, we get 16 * .1193 or
+// about 1.9 ticks per 16 intervals.
+//
+// We round this to 2 ticks per 1600ns intervals.
+//
+
+#define PROFILE_TIMER_1600NS_TICKS 2
+
+//
+// Default Profile Interval to be about 1ms.
+//
+
+ULONG HalpProfileInterval = PROFILE_TIMER_1600NS_TICKS * PROFILE_INTERVALS_PER_100NS * 10000 / 16; // ~1ms
+
+//
+// Default Number of Profile Clock Ticks per sample
+//
+
+ULONG HalpNumberOfTicks = 1;
+
+//
+// Define the profile interrupt object.
+//
+
+PKINTERRUPT HalpProfileInterruptObject;
+
+//
+// Declare profile interrupt handler.
+//
+
+BOOLEAN
+HalpProfileInterrupt(
+ PKSERVICE_ROUTINE InterruptRoutine,
+ PVOID ServiceContext,
+ PKTRAP_FRAME TrapFrame
+ );
+
+//
+// Function prototypes.
+//
+
+BOOLEAN
+HalQueryProfileInterval(
+ IN KPROFILE_SOURCE Source
+ );
+
+NTSTATUS
+HalSetProfileSourceInterval(
+ IN KPROFILE_SOURCE ProfileSource,
+ IN OUT ULONG *Interval
+ );
+
+//
+// Function definitions.
+//
+
+
+NTSTATUS
+HalpProfileSourceInformation (
+ OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG ReturnedLength
+ )
+/*++
+
+Routine Description:
+
+ Returns the HAL_PROFILE_SOURCE_INFORMATION for this processor.
+
+Arguments:
+
+ Buffer - output buffer
+ BufferLength - length of buffer on input
+ ReturnedLength - The length of data returned
+
+Return Value:
+
+ STATUS_SUCCESS
+ STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
+ currently needed.
+
+--*/
+{
+ PHAL_PROFILE_SOURCE_INFORMATION SourceInfo;
+ NTSTATUS Status;
+
+
+ if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INFORMATION)) {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ return Status;
+ }
+
+ SourceInfo = (PHAL_PROFILE_SOURCE_INFORMATION)Buffer;
+ SourceInfo->Supported = HalQueryProfileInterval(SourceInfo->Source);
+
+ if (SourceInfo->Supported) {
+ SourceInfo->Interval = HalpProfileInterval * HalpNumberOfTicks;
+ }
+
+ Status = STATUS_SUCCESS;
+ return Status;
+}
+
+
+NTSTATUS
+HalpProfileSourceInterval (
+ OUT PVOID Buffer,
+ IN ULONG BufferLength
+ )
+/*++
+
+Routine Description:
+
+ Returns the HAL_PROFILE_SOURCE_INTERVAL for this processor.
+
+Arguments:
+
+ Buffer - output buffer
+ BufferLength - length of buffer on input
+
+Return Value:
+
+ STATUS_SUCCESS
+ STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
+ currently needed.
+
+--*/
+{
+ PHAL_PROFILE_SOURCE_INTERVAL Interval;
+ NTSTATUS Status;
+
+
+ if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INTERVAL)) {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ return Status;
+ }
+
+ Interval = (PHAL_PROFILE_SOURCE_INTERVAL)Buffer;
+ Status = HalSetProfileSourceInterval(Interval->Source,
+ &Interval->Interval);
+ return Status;
+}
+
+
+VOID
+HalpInitializeProfiler(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Initialize the profiler by setting initial values and connecting
+ the profile interrupt.
+
+Arguments:
+
+ InterfaceType - Supplies the interface type of the bus on which the
+ profiler will be connected.
+
+ BusNumber - Supplies the number of the bus on which the profiler will
+ be connected.
+
+ BusInterruptLevel - Supplies the bus interrupt level to connect the
+ profile interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ KAFFINITY Affinity;
+ KIRQL Irql;
+ ULONG Vector;
+
+ //
+ // Get the interrupt vector and synchronization Irql.
+ //
+
+ Vector = HalGetInterruptVector( Eisa,
+ 0,
+ 0,
+ 0,
+ &Irql,
+ &Affinity );
+
+ IoConnectInterrupt( &HalpProfileInterruptObject,
+ (PKSERVICE_ROUTINE)HalpProfileInterrupt,
+ NULL,
+ NULL,
+ Vector,
+ Irql,
+ Irql,
+ Latched,
+ FALSE,
+ Affinity,
+ FALSE );
+
+ return;
+}
+
+
+BOOLEAN
+HalpProfileInterrupt(
+ PKSERVICE_ROUTINE InterruptRoutine,
+ PVOID ServiceContext,
+ PKTRAP_FRAME TrapFrame
+ )
+/*++
+
+Routine Description:
+
+ This routine is entered as a result of an interrupt generated by
+ the profile timer. Its function is to acknowlege the interrupt and
+ transfer control to the standard system routine to update the
+ system profile time.
+
+Arguments:
+
+ InterruptRoutine - not used.
+
+ ServiceContext - not used.
+
+ TrapFrame - Supplies a pointer to the trap frame for the profile interrupt.
+
+Returned Value:
+
+ None
+
+--*/
+{
+
+ //
+ // See if profiling is active
+ //
+
+ if ( HAL_PCR->ProfileCount ) {
+
+ //
+ // Check to see if the interval has expired
+ // If it has then call the kernel routine for profile
+ // and reset the count, else return.
+
+
+ if ( !(--HAL_PCR->ProfileCount) ) {
+
+ KeProfileInterrupt( TrapFrame );
+ HAL_PCR->ProfileCount = HalpNumberOfTicks;
+
+ }
+ }
+
+ return TRUE;
+
+}
+
+
+BOOLEAN
+HalQueryProfileInterval(
+ IN KPROFILE_SOURCE ProfileSource
+ )
+
+/*++
+
+Routine Description:
+
+ Given a profile source, returns whether or not that source is
+ supported.
+
+Arguments:
+
+ Source - Supplies the profile source
+
+Return Value:
+
+ TRUE - Profile source is supported
+
+ FALSE - Profile source is not supported
+
+--*/
+
+{
+ if (ProfileSource == ProfileTime)
+ return(TRUE);
+ else
+ return(FALSE);
+}
+
+
+NTSTATUS
+HalSetProfileSourceInterval(
+ IN KPROFILE_SOURCE ProfileSource,
+ IN OUT ULONG *Interval
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the profile interval for a specified profile source
+
+Arguments:
+
+ ProfileSource - Supplies the profile source
+
+ Interval - Supplies the specified profile interval
+ Returns the actual profile interval
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+{
+ if (ProfileSource != ProfileTime)
+ return(STATUS_NOT_IMPLEMENTED);
+
+ //
+ // Set the interval.
+ //
+
+ *Interval = HalSetProfileInterval(*Interval);
+
+ //
+ // We're done.
+ //
+
+ return(STATUS_SUCCESS);
+}
+
+
+ULONG
+HalSetProfileInterval (
+ IN ULONG Interval
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the profile interrupt interval.
+
+Arguments:
+
+ Interval - Supplies the desired profile interval in 100ns units.
+
+Return Value:
+
+ The actual profile interval.
+
+--*/
+
+{
+
+ HalpProfileInterval = (Interval/16) * PROFILE_TIMER_1600NS_TICKS;
+
+ HalpProfileInterval = ( HalpProfileInterval < MIN_PROFILE_TICKS ) ?
+ MIN_PROFILE_TICKS : HalpProfileInterval;
+
+ return HalpProfileInterval * PROFILE_INTERVALS_PER_100NS;
+}
+
+
+VOID
+HalStartProfileInterrupt (
+ KPROFILE_SOURCE ProfileSource
+ )
+
+/*++
+
+Routine Description:
+
+ This routine turns on the profile interrupt.
+
+ N.B. This routine must be called at PROCLK_LEVEL while holding the
+ profile lock.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (ProfileSource != ProfileTime)
+ return;
+
+ //
+ // Assume that we only need 1 clock tick before we collect data
+ //
+
+ HalpNumberOfTicks = 1;
+
+ if ( HalpProfileInterval > MAX_PROFILE_TICKS ) {
+
+ HalpNumberOfTicks = HalpProfileInterval / (MAX_PROFILE_TICKS / 4);
+ HalpNumberOfTicks = 4 * HalpNumberOfTicks;
+ HalpProfileInterval = MAX_PROFILE_TICKS / 4;
+
+ }
+
+ //
+ // Set current profile count and interval.
+ //
+
+ HAL_PCR->ProfileCount = HalpNumberOfTicks;
+
+ PIC_PROFILER_ON(HalpProfileInterval);
+
+ return;
+}
+
+
+VOID
+HalStopProfileInterrupt (
+ KPROFILE_SOURCE ProfileSource
+ )
+
+/*++
+
+Routine Description:
+
+ This routine turns off the profile interrupt.
+
+ N.B. This routine must be called at PROCLK_LEVEL while holding the
+ profile lock.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ if (ProfileSource != ProfileTime)
+ return;
+
+ //
+ // Clear the current profile count and turn off the profiler timer.
+ //
+
+ HAL_PCR->ProfileCount = 0;
+
+ PIC_PROFILER_OFF();
+
+ return;
+}
diff --git a/private/ntos/nthals/halalpha/eisasup.c b/private/ntos/nthals/halalpha/eisasup.c
new file mode 100644
index 000000000..4f907fa1d
--- /dev/null
+++ b/private/ntos/nthals/halalpha/eisasup.c
@@ -0,0 +1,1477 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ eisasup.c
+
+Abstract:
+
+ The module provides the platform-independent
+ EISA bus support for Alpha systems.
+
+Author:
+
+ Jeff Havens (jhavens) 19-Jun-1991
+ Miche Baker-Harvey (miche) 13-May-1992
+ Jeff McLeman (DEC) 1-Jun-1992
+
+Revision History:
+
+
+--*/
+
+
+#include "halp.h"
+#include "eisa.h"
+
+
+//
+// Define save area for ESIA adapter objects.
+//
+
+PADAPTER_OBJECT HalpEisaAdapter[8];
+
+//
+// This value indicates if Eisa DMA is supported on this system.
+//
+
+BOOLEAN HalpEisaDma;
+
+
+VOID
+HalpEisaInitializeDma(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Initialize DMA support for Eisa/Isa systems.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UCHAR DataByte;
+
+ //
+ // Determine if Eisa DMA is supported.
+ //
+
+ HalpEisaDma = FALSE;
+
+ WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort.Channel2, 0x55);
+ DataByte = READ_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort.Channel2);
+
+ if (DataByte == 0x55) {
+ HalpEisaDma = TRUE;
+ }
+}
+
+
+PADAPTER_OBJECT
+HalpAllocateEisaAdapter(
+ IN PDEVICE_DESCRIPTION DeviceDescriptor,
+ OUT PULONG NumberOfMapRegisters
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the appropriate adapter object for the device defined
+ in the device description structure. This code works for Isa and Eisa
+ systems.
+
+Arguments:
+
+ DeviceDescriptor - Supplies a description of the device.
+
+ NumberOfMapRegisters - Returns the maximum number of map registers which
+ may be allocated by the device driver.
+
+Return Value:
+
+ A pointer to the requested adapter object or NULL if an adapter could not
+ be created.
+
+--*/
+
+{
+ PADAPTER_OBJECT adapterObject;
+ PVOID adapterBaseVa;
+ ULONG channelNumber;
+ ULONG controllerNumber;
+ DMA_EXTENDED_MODE extendedMode;
+ UCHAR adapterMode;
+ ULONG numberOfMapRegisters;
+ BOOLEAN useChannel;
+ ULONG maximumLength;
+ UCHAR DataByte;
+
+ useChannel = TRUE;
+
+ //
+ // Support for ISA local bus machines:
+ // If the driver is a Master but really does not want a channel since it
+ // is using the local bus DMA, just don't use an ISA channel.
+ //
+
+ if (DeviceDescriptor->InterfaceType == Isa &&
+ DeviceDescriptor->DmaChannel > 7) {
+
+ useChannel = FALSE;
+ }
+
+ //
+ // Limit the maximum length to 2 GB this is done so that the BYTES_TO_PAGES
+ // macro works correctly.
+ //
+
+ maximumLength = DeviceDescriptor->MaximumLength & 0x7fffffff;
+
+ //
+ // Channel 4 cannot be used since it is used for chaining. Return null if
+ // it is requested.
+ //
+
+ if (DeviceDescriptor->DmaChannel == 4 && useChannel) {
+ return(NULL);
+ }
+
+ //
+ // Determine the number of map registers required based on the maximum
+ // transfer length. Limit the maximum transfer to 64K.
+ //
+
+#define MAXIMUM_ISA_MAP_REGISTER (__64K >> PAGE_SHIFT)
+
+ numberOfMapRegisters = BYTES_TO_PAGES(maximumLength) + 1;
+ numberOfMapRegisters = numberOfMapRegisters > MAXIMUM_ISA_MAP_REGISTER ?
+ MAXIMUM_ISA_MAP_REGISTER : numberOfMapRegisters;
+
+ //
+ // 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) HalpEisaControlBase)->Dma1BasePort;
+
+ } else {
+
+ controllerNumber = 2;
+ adapterBaseVa = &((PEISA_CONTROL) HalpEisaControlBase)->Dma2BasePort;
+
+ }
+
+ //
+ // Determine if a new adapter object is necessary. If so then allocate it.
+ //
+
+ if (useChannel && HalpEisaAdapter[DeviceDescriptor->DmaChannel] != NULL) {
+
+ adapterObject = HalpEisaAdapter[DeviceDescriptor->DmaChannel];
+
+ if (numberOfMapRegisters > adapterObject->MapRegistersPerChannel) {
+ adapterObject->MapRegistersPerChannel = numberOfMapRegisters;
+ }
+
+ } else {
+
+ //
+ // Allocate an adapter object.
+ //
+
+ adapterObject = HalpAllocateAdapter();
+
+ if (adapterObject == NULL) {
+ return(NULL);
+ }
+
+ if (useChannel == TRUE) {
+ HalpEisaAdapter[DeviceDescriptor->DmaChannel] = adapterObject;
+ }
+
+ //
+ // Set the maximum number of map registers for this channel bus on
+ // the number requested and the type of device.
+ //
+
+ adapterObject->MapRegistersPerChannel = numberOfMapRegisters;
+
+ //
+ // Establish the base va used to program the DMA controller.
+ //
+
+ adapterObject->AdapterBaseVa = adapterBaseVa;
+
+ }
+
+ *NumberOfMapRegisters = adapterObject->MapRegistersPerChannel;
+
+ if (DeviceDescriptor->Master) {
+ adapterObject->MasterDevice = TRUE;
+ } else {
+ adapterObject->MasterDevice = FALSE;
+ }
+
+ //
+ // If the channel number is not used then we are finished. The rest of
+ // the work deals with channels.
+ //
+
+ if (useChannel == FALSE) {
+ return(adapterObject);
+ }
+
+ //
+ // Setup the pointers to all the random registers.
+ //
+
+ adapterObject->ChannelNumber = (UCHAR) channelNumber;
+
+ if (controllerNumber == 1) {
+
+ switch ((UCHAR)channelNumber) {
+
+ case 0:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel0;
+ break;
+
+ case 1:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel1;
+ break;
+
+ case 2:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel2;
+ break;
+
+ case 3:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel3;
+ break;
+ }
+
+ //
+ // Set the adapter number.
+ //
+
+ adapterObject->AdapterNumber = 1;
+
+ //
+ // Save the extended mode register address.
+ //
+
+ adapterBaseVa =
+ &((PEISA_CONTROL) HalpEisaControlBase)->Dma1ExtendedModePort;
+
+ } else {
+
+ switch (channelNumber) {
+ case 1:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel5;
+ break;
+
+ case 2:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel6;
+ break;
+
+ case 3:
+ adapterObject->PagePort = (PUCHAR) &((PDMA_PAGE) 0)->Channel7;
+ break;
+ }
+
+ //
+ // Set the adapter number.
+ //
+
+ adapterObject->AdapterNumber = 2;
+
+ //
+ // Save the extended mode register address.
+ //
+ adapterBaseVa =
+ &((PEISA_CONTROL) HalpEisaControlBase)->Dma2ExtendedModePort;
+
+ }
+
+
+ adapterObject->Width16Bits = FALSE;
+
+ if (HalpEisaDma) {
+
+ //
+ // Initialzie the extended mode port.
+ //
+
+ *((PUCHAR) &extendedMode) = 0;
+ extendedMode.ChannelNumber = (UCHAR)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:
+ ObDereferenceObject( adapterObject );
+ return(NULL);
+
+ }
+
+ switch (DeviceDescriptor->DmaWidth) {
+ case Width8Bits:
+ extendedMode.TransferSize = BY_BYTE_8_BITS;
+ break;
+
+ case Width16Bits:
+ extendedMode.TransferSize = BY_BYTE_16_BITS;
+
+ //
+ // Note Width16bits should not be set here because there is no need
+ // to shift the address and the transfer count.
+ //
+
+ break;
+
+ case Width32Bits:
+ extendedMode.TransferSize = BY_BYTE_32_BITS;
+ break;
+
+ default:
+ ObDereferenceObject( adapterObject );
+ return(NULL);
+
+ }
+
+ //
+ // Save the extended mode in the adapter.
+ // Then write the extended mode value for this channel.
+ //
+
+ adapterObject->ExtendedMode = *((PDMA_EXTENDED_MODE)&extendedMode);
+
+ WRITE_PORT_UCHAR( adapterBaseVa, *((PUCHAR) &extendedMode));
+
+ } else if (DeviceDescriptor->Master == FALSE) {
+
+
+ switch (DeviceDescriptor->DmaWidth) {
+ case Width8Bits:
+
+ //
+ // The channel must use controller 1.
+ //
+
+ if (controllerNumber != 1) {
+ ObDereferenceObject( adapterObject );
+ return(NULL);
+ }
+
+ break;
+
+ case Width16Bits:
+
+ //
+ // The channel must use controller 2.
+ //
+
+ if (controllerNumber != 2) {
+ ObDereferenceObject( adapterObject );
+ return(NULL);
+ }
+
+ adapterObject->Width16Bits = TRUE;
+ break;
+
+ default:
+ ObDereferenceObject( adapterObject );
+ return(NULL);
+
+ }
+ }
+
+ //
+ // 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;
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | adapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = adapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_PORT_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;
+
+ return(adapterObject);
+}
+
+BOOLEAN
+HalpMapEisaTransfer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG LogicalAddress,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is invoked to perform the actual programming of the
+ DMA controllers to perform a transfer for Eisa/Isa systems.
+
+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.
+
+ LogicalAddress - Supplies the logical address of the transfer.
+
+Return Value:
+
+ Returns a boolean identifying if the operation was successful.
+
+--*/
+
+{
+ KIRQL Irql;
+ UCHAR adapterMode;
+ PUCHAR bytePointer;
+ UCHAR dataByte;
+ ULONG logicalAddress;
+ ULONG transferLength;
+
+ logicalAddress = LogicalAddress;
+ transferLength = Length;
+
+ //
+ // Determine the mode based on the transfer direction.
+ //
+
+ adapterMode = AdapterObject->AdapterMode;
+ ((PDMA_EISA_MODE) &adapterMode)->TransferType = (UCHAR) (WriteToDevice ?
+ WRITE_TRANSFER : READ_TRANSFER);
+
+ bytePointer = (PUCHAR) &logicalAddress;
+
+ //
+ // Check to see if this request is for a master I/O card.
+ //
+
+//jnfix - this code not in Jensen
+ if( ((PDMA_EISA_MODE)&adapterMode)->RequestMode == CASCADE_REQUEST_MODE) {
+
+ //
+ // Set the mode, disable the request and return.
+ //
+
+ if( AdapterObject->AdapterNumber == 1 ){
+
+ //
+ // Request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_REGISTER_UCHAR( &dmaControl->SingleMask,
+ (UCHAR)(DMA_CLEARMASK | AdapterObject->ChannelNumber) );
+
+ } else {
+
+ //
+ // Request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_REGISTER_UCHAR( &dmaControl->Mode, adapterMode );
+
+ //
+ // Unmask the DMA channel.
+ //
+
+ WRITE_REGISTER_UCHAR( &dmaControl->SingleMask,
+ (UCHAR)(DMA_CLEARMASK | AdapterObject->ChannelNumber) );
+
+ }
+
+ return TRUE;
+
+ }
+
+ if (AdapterObject->Width16Bits) {
+
+ //
+ // If this is a 16 bit transfer then adjust the length and the address
+ // for the 16 bit DMA mode.
+ //
+
+ transferLength >>= 1;
+
+ }
+
+ //
+ // Grab the spinlock for the system DMA controller.
+ //
+
+ KeAcquireSpinLock( &AdapterObject->MapAdapter->SpinLock, &Irql );
+
+ //
+ // Determine the controller number based on the Adapter number.
+ //
+
+ if (AdapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[0]
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[1]
+ );
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) +
+ (ULONG)AdapterObject->PagePort,
+ bytePointer[2]
+ );
+
+ if (HalpEisaDma) {
+
+ //
+ // Write the high page register with zero value. This enable a
+ // special mode which allows ties the page register and base
+ // count into a single 24 bit address register.
+ //
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) +
+ (ULONG)AdapterObject->PagePort,
+ 0
+ );
+ }
+
+ //
+ // Notify DMA chip of the length to transfer.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) & 0xff)
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) >> 8)
+ );
+
+
+ //
+ // Set the DMA chip to read or write mode; and unmask it.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ WRITE_PORT_UCHAR( &dmaControl->Mode, adapterMode );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[0]
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseAddress,
+ bytePointer[1]
+ );
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageLowPort) +
+ (ULONG)AdapterObject->PagePort,
+ bytePointer[2]
+ );
+
+ if (HalpEisaDma) {
+
+ //
+ // Write the high page register with zero value. This enable
+ // a special mode which allows ties the page register and base
+ // count into a single 24 bit address register.
+ //
+
+ WRITE_PORT_UCHAR(
+ ((PUCHAR) &((PEISA_CONTROL) HalpEisaControlBase)->DmaPageHighPort) +
+ (ULONG)AdapterObject->PagePort,
+ 0
+ );
+ }
+
+ //
+ // Notify DMA chip of the length to transfer.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) & 0xff)
+ );
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount,
+ (UCHAR) ((transferLength - 1) >> 8)
+ );
+
+
+ //
+ // Set the DMA chip to read or write mode; and unmask it.
+ //
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_CLEARMASK | AdapterObject->ChannelNumber)
+ );
+
+ }
+
+ KeReleaseSpinLock (&AdapterObject->MapAdapter->SpinLock, Irql);
+
+ return TRUE;
+}
+
+
+BOOLEAN
+HalpFlushEisaAdapter(
+ 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 adapter object buffers. For EISA systems
+ 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.
+
+--*/
+{
+
+ BOOLEAN masterDevice;
+ KIRQL Irql;
+
+ masterDevice = AdapterObject->MasterDevice;
+
+ KeAcquireSpinLock( &AdapterObject->MapAdapter->SpinLock, &Irql );
+
+ //
+ // If this is a slave device, then stop the DMA controller.
+ //
+
+ if (masterDevice == FALSE) {
+
+ //
+ // Mask the DMA request line so that DMA requests cannot occur.
+ //
+
+ if (AdapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber)
+ );
+
+ } else {
+
+ //
+ // This request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR(
+ &dmaControl->SingleMask,
+ (UCHAR) (DMA_SETMASK | AdapterObject->ChannelNumber)
+ );
+
+ }
+
+ }
+
+ KeReleaseSpinLock( &AdapterObject->MapAdapter->SpinLock, Irql );
+
+ return TRUE;
+
+}
+
+ULONG
+HalpReadEisaDmaCounter(
+ IN PADAPTER_OBJECT AdapterObject
+ )
+/*++
+
+Routine Description:
+
+ This function reads the DMA counter and returns the number of bytes left
+ to be transfered.
+
+Arguments:
+
+ AdapterObject - Supplies a pointer to the adapter object to be read.
+
+Return Value:
+
+ Returns the number of bytes still be be transfered.
+
+--*/
+
+{
+
+ ULONG count;
+ ULONG high;
+ KIRQL Irql;
+
+ //
+ // Grab the spinlock for the system DMA controller.
+ //
+
+ KeAcquireSpinLock( &AdapterObject->MapAdapter->SpinLock, &Irql );
+
+ //
+ // Determine the controller number based on the Adapter number.
+ //
+
+ if (AdapterObject->AdapterNumber == 1) {
+
+ //
+ // This request is for DMA controller 1
+ //
+
+ PDMA1_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+
+ //
+ // Initialize count to a value which will not match.
+ //
+
+ count = 0xFFFF00;
+
+ //
+ // Loop until the same high byte is read twice.
+ //
+
+ do {
+
+ high = count;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ //
+ // Read the current DMA count.
+ //
+
+ count = READ_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount
+ );
+
+ count |= READ_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount
+ ) << 8;
+
+ } while ((count & 0xFFFF00) != (high & 0xFFFF00));
+
+ } else {
+
+ //
+ // This request is for DMA controller 2
+ //
+
+ PDMA2_CONTROL dmaControl;
+
+ dmaControl = AdapterObject->AdapterBaseVa;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ //
+ // Initialize count to a value which will not match.
+ //
+
+ count = 0xFFFF00;
+
+ //
+ // Loop until the same high byte is read twice.
+ //
+
+ do {
+
+ high = count;
+
+ WRITE_PORT_UCHAR( &dmaControl->ClearBytePointer, 0 );
+
+ //
+ // Read the current DMA count.
+ //
+
+ count = READ_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount
+ );
+
+ count |= READ_PORT_UCHAR(
+ &dmaControl->DmaAddressCount[AdapterObject->ChannelNumber]
+ .DmaBaseCount
+ ) << 8;
+
+ } while ((count & 0xFFFF00) != (high & 0xFFFF00));
+
+
+ }
+
+ //
+ // Release the spinlock for the system DMA controller.
+ //
+
+ KeReleaseSpinLock( &AdapterObject->MapAdapter->SpinLock, Irql );
+
+ //
+ // The DMA counter has a bias of one and can only be 16 bit long.
+ //
+
+ count = (count + 1) & 0xFFFF;
+
+ //
+ // If this is a 16 bit dma the multiply the count by 2.
+ //
+
+ if (AdapterObject->Width16Bits) {
+
+ count *= 2;
+
+ }
+
+ return(count);
+
+}
+
+#if !defined(AXP_FIRMWARE)
+
+ULONG
+HalpGetEisaData (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ The function returns the Eisa bus data for a slot or address.
+
+Arguments:
+
+
+ BusHandler - Registered BUSHANDLER for the target configuration space
+
+ RootHandler - Registered BUSHANDLER for the orginating HalGetBusData
+ request.
+
+ Buffer - Supplies the space to store the data.
+
+ Offset - Supplies the offset into data to begin access.
+
+ Length - Supplies a count in bytes of the maximum amount to return.
+
+Return Value:
+
+ Returns the amount of data stored into the buffer.
+
+--*/
+{
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ OBJECT_ATTRIBUTES BusObjectAttributes;
+ PWSTR EisaPath = L"\\Registry\\Machine\\Hardware\\Description\\System\\EisaAdapter";
+ PWSTR ConfigData = L"Configuration Data";
+ ANSI_STRING TmpString;
+ ULONG BusNumber;
+ UCHAR BusString[] = "00";
+ UNICODE_STRING RootName, BusName;
+ UNICODE_STRING ConfigDataName;
+ NTSTATUS NtStatus;
+ PKEY_VALUE_FULL_INFORMATION ValueInformation;
+ PCM_FULL_RESOURCE_DESCRIPTOR Descriptor;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR PartialResource;
+ PCM_EISA_SLOT_INFORMATION SlotInformation;
+ ULONG PartialCount;
+ ULONG TotalDataSize, SlotDataSize;
+ HANDLE EisaHandle, BusHandle;
+ ULONG BytesWritten, BytesNeeded;
+ PUCHAR KeyValueBuffer;
+ ULONG i;
+ ULONG DataLength = 0;
+ PUCHAR DataBuffer = Buffer;
+ BOOLEAN Found = FALSE;
+
+ UNREFERENCED_PARAMETER( RootHandler );
+
+ RtlInitUnicodeString(
+ &RootName,
+ EisaPath
+ );
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &RootName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE)NULL,
+ NULL
+ );
+
+ //
+ // Open the EISA root
+ //
+
+ NtStatus = ZwOpenKey(
+ &EisaHandle,
+ KEY_READ,
+ &ObjectAttributes
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+#if DBG
+ DbgPrint("HAL: Open Status = %x\n",NtStatus);
+#endif
+ return(0);
+ }
+
+ //
+ // Init bus number path
+ //
+
+ BusNumber = BusHandler->BusNumber;
+
+ if (BusNumber > 99) {
+ return (0);
+ }
+
+ if (BusNumber > 9) {
+ BusString[0] += (UCHAR) (BusNumber/10);
+ BusString[1] += (UCHAR) (BusNumber % 10);
+ } else {
+ BusString[0] += (UCHAR) BusNumber;
+ BusString[1] = '\0';
+ }
+
+ RtlInitAnsiString(
+ &TmpString,
+ BusString
+ );
+
+ RtlAnsiStringToUnicodeString(
+ &BusName,
+ &TmpString,
+ TRUE
+ );
+
+
+ InitializeObjectAttributes(
+ &BusObjectAttributes,
+ &BusName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE)EisaHandle,
+ NULL
+ );
+
+ //
+ // Open the EISA root + Bus Number
+ //
+
+ NtStatus = ZwOpenKey(
+ &BusHandle,
+ KEY_READ,
+ &BusObjectAttributes
+ );
+
+ if (!NT_SUCCESS(NtStatus)) {
+#if DBG
+ DbgPrint("HAL: Opening Bus Number: Status = %x\n",NtStatus);
+#endif
+ return(0);
+ }
+
+ //
+ // opening the configuration data. This first call tells us how
+ // much memory we need to allocate
+ //
+
+ RtlInitUnicodeString(
+ &ConfigDataName,
+ ConfigData
+ );
+
+ //
+ // This should fail. We need to make this call so we can
+ // get the actual size of the buffer to allocate.
+ //
+
+ ValueInformation = (PKEY_VALUE_FULL_INFORMATION) &i;
+ NtStatus = ZwQueryValueKey(
+ BusHandle,
+ &ConfigDataName,
+ KeyValueFullInformation,
+ ValueInformation,
+ 0,
+ &BytesNeeded
+ );
+
+ KeyValueBuffer = ExAllocatePool(
+ NonPagedPool,
+ BytesNeeded
+ );
+
+ if (KeyValueBuffer == NULL) {
+#if DBG
+ DbgPrint("HAL: Cannot allocate Key Value Buffer\n");
+#endif
+ ZwClose(BusHandle);
+ return(0);
+ }
+
+ ValueInformation = (PKEY_VALUE_FULL_INFORMATION)KeyValueBuffer;
+
+ NtStatus = ZwQueryValueKey(
+ BusHandle,
+ &ConfigDataName,
+ KeyValueFullInformation,
+ ValueInformation,
+ BytesNeeded,
+ &BytesWritten
+ );
+
+
+ ZwClose(BusHandle);
+
+ if (!NT_SUCCESS(NtStatus) || ValueInformation->DataLength == 0) {
+#if DBG
+ DbgPrint("HAL: Query Config Data: Status = %x\n",NtStatus);
+#endif
+ ExFreePool(KeyValueBuffer);
+ return(0);
+ }
+
+
+ //
+ // We get back a Full Resource Descriptor List
+ //
+
+ Descriptor = (PCM_FULL_RESOURCE_DESCRIPTOR)((PUCHAR)ValueInformation +
+ ValueInformation->DataOffset);
+
+ PartialResource = (PCM_PARTIAL_RESOURCE_DESCRIPTOR)
+ &(Descriptor->PartialResourceList.PartialDescriptors);
+ PartialCount = Descriptor->PartialResourceList.Count;
+
+ for (i = 0; i < PartialCount; i++) {
+
+ //
+ // Do each partial Resource
+ //
+
+ switch (PartialResource->Type) {
+ case CmResourceTypeNull:
+ case CmResourceTypePort:
+ case CmResourceTypeInterrupt:
+ case CmResourceTypeMemory:
+ case CmResourceTypeDma:
+
+ //
+ // We dont care about these.
+ //
+
+ PartialResource++;
+
+ break;
+
+ case CmResourceTypeDeviceSpecific:
+
+ //
+ // Bingo!
+ //
+
+ TotalDataSize = PartialResource->u.DeviceSpecificData.DataSize;
+
+ SlotInformation = (PCM_EISA_SLOT_INFORMATION)
+ ((PUCHAR)PartialResource +
+ sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
+
+ while (((LONG)TotalDataSize) > 0) {
+
+ if (SlotInformation->ReturnCode == EISA_EMPTY_SLOT) {
+
+ SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION);
+
+ } else {
+
+ SlotDataSize = sizeof(CM_EISA_SLOT_INFORMATION) +
+ SlotInformation->NumberFunctions *
+ sizeof(CM_EISA_FUNCTION_INFORMATION);
+ }
+
+ if (SlotDataSize > TotalDataSize) {
+
+ //
+ // Something is wrong again
+ //
+
+ ExFreePool(KeyValueBuffer);
+ return(0);
+
+ }
+
+ if (SlotNumber != 0) {
+
+ SlotNumber--;
+
+ SlotInformation = (PCM_EISA_SLOT_INFORMATION)
+ ((PUCHAR)SlotInformation + SlotDataSize);
+
+ TotalDataSize -= SlotDataSize;
+
+ continue;
+
+ }
+
+ //
+ // This is our slot
+ //
+
+ Found = TRUE;
+ break;
+
+ }
+
+ //
+ // End loop
+ //
+
+ i = PartialCount;
+
+ break;
+
+ default:
+
+#if DBG
+ DbgPrint("Bad Data in registry!\n");
+#endif
+
+ ExFreePool(KeyValueBuffer);
+ return(0);
+
+ }
+
+ }
+
+ if (Found) {
+
+ i = Length + Offset;
+ if (i > SlotDataSize) {
+ i = SlotDataSize;
+ }
+
+ DataLength = i - Offset;
+ RtlMoveMemory (Buffer, ((PUCHAR)SlotInformation + Offset), DataLength);
+
+ }
+
+ ExFreePool(KeyValueBuffer);
+ return DataLength;
+}
+
+
+NTSTATUS
+HalpAdjustEisaResourceList (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+ )
+/*++
+
+Routine Description:
+
+ The function adjusts pResourceList to keep it in the bounds of the EISA bus
+ resources.
+
+Arguments:
+
+ BusHandler - Registered BUSHANDLER for the target configuration space
+
+ RootHandler - Register BUSHANDLER for the orginating HalAdjustResourceList request.
+
+ pResourceList - Supplies the PIO_RESOURCE_REQUIREMENTS_LIST to be checked.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+{
+ LARGE_INTEGER li64k, li4g;
+
+ li64k.QuadPart = 0xffff;
+ li4g.QuadPart = 0xffffffff;
+
+ HalpAdjustResourceListUpperLimits (
+ pResourceList,
+ li64k, // Bus supports up to I/O port 0xFFFF
+ li4g, // Bus supports up to memory 0xFFFFFFFF
+ 15, // Bus supports up to 15 IRQs
+ 7 // Bus supports up to Dma channel 7
+ );
+
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+HalpAdjustIsaResourceList (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+ )
+/*++
+
+Routine Description:
+
+ The function adjusts pResourceList to keep it in the bounds of ISA bus
+ resources.
+
+Arguments:
+
+ BusHandler - Registered BUSHANDLER for the target configuration space
+
+ RootHandler - Register BUSHANDLER for the orginating HalAdjustResourceList request.
+
+ pResourceList - Supplies the PIO_RESOURCE_REQUIREMENTS_LIST to be checked.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+{
+ LARGE_INTEGER li64k, limem;
+
+ li64k.QuadPart = 0xffff;
+ limem.QuadPart = 0xffffff;
+
+ HalpAdjustResourceListUpperLimits (
+ pResourceList,
+ li64k, // Bus supports up to I/O port 0xFFFF
+ limem, // Bus supports up to memory 0xFFFFFF
+ 15, // Bus supports up to 15 IRQs
+ 7 // Bus supports up to Dma channel 7
+ );
+
+ return STATUS_SUCCESS;
+}
+#endif // AXP_FIRMWARE
diff --git a/private/ntos/nthals/halalpha/environ.c b/private/ntos/nthals/halalpha/environ.c
new file mode 100644
index 000000000..3831214a5
--- /dev/null
+++ b/private/ntos/nthals/halalpha/environ.c
@@ -0,0 +1,952 @@
+//smjfix - This code needs to be made MP safe if it isn't being called
+// by MP safe code.
+//jwlfix - It's currently being called by the kernel (ex, actually) in
+// an MP-safe fashion, and by config during phase 1 (?) of
+// bootstrapping the system.
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ environ.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.
+
+Author:
+
+ David M. Robinson (davidro) 13-June-1991
+
+
+Revision History:
+
+ James Livingston 94.05.17
+
+ Fix a coding error that caused NVRAM to get trashed in the attempt
+ to update a nearly full environment variable space.
+
+ Steve Jenness 93.12.20
+
+ The firmware still requires the naked checksum set and check
+ routines. Add them back in under the AXP_FIRMWARE conditional
+ until the jxenvir.c in the firmware and the environ.c files
+ are rationalized.
+
+ Steve Jenness. 93.12.17
+
+ Reduce the reads and writes to the NVRAM part. Some parts are
+ slow to access (especially on writes). Do NVRAM access only when
+ really necessary. Remove use of HalpCopyNVRamBuffer because it is
+ too difficult to make generically fast (put more intelligence
+ in higher code instead).
+
+ Steve Brooks. 6-Oct 1993 remove all platform and device specific references
+
+ These routines have been restructured to be platform and device
+ independant. All calls access the NVRAM via the calls
+ HalpReadNVRamBuffer, HalpWriteNVRamBuffer, and HalpCopyNVRamBuffer
+
+ Jeff McLeman (DEC) 31-Jul-1992 modify for Jensen
+
+--*/
+
+#include "halp.h"
+#include "environ.h"
+
+#include "arccodes.h"
+
+//
+// Static data.
+//
+
+UCHAR Environment[LENGTH_OF_ENVIRONMENT];
+ULONG EnvironmentChecksum;
+BOOLEAN EnvironmentValid = FALSE;
+
+UCHAR OutputString[MAXIMUM_ENVIRONMENT_VALUE];
+PCONFIGURATION Configuration;
+
+//
+// Routine prototypes.
+//
+
+ARC_STATUS
+HalpReadAndChecksumEnvironment (
+ );
+
+ARC_STATUS
+HalpWriteAndChecksumEnvironment (
+ );
+
+ARC_STATUS
+HalGetEnvironmentVariable (
+ IN PCHAR Variable,
+ IN USHORT length,
+ OUT PCHAR Buffer
+ );
+
+ARC_STATUS
+HalSetEnvironmentVariable (
+ IN PCHAR Variable,
+ IN PCHAR Value
+ );
+
+ARC_STATUS
+HalpFindEnvironmentVariable (
+ IN PCHAR Variable,
+ OUT PULONG VariableIndex,
+ OUT PULONG ValueIndex
+ );
+
+#if defined(AXP_FIRMWARE)
+
+ARC_STATUS
+HalpEnvironmentCheckChecksum (
+ VOID
+ );
+
+ARC_STATUS
+HalpEnvironmentSetChecksum (
+ VOID
+ );
+
+#endif //AXP_FIRMWARE
+
+#ifdef AXP_FIRMWARE
+
+#pragma alloc_text(DISTEXT, HalpReadAndChecksumEnvironment )
+#pragma alloc_text(DISTEXT, HalpWriteAndChecksumEnvironment )
+#pragma alloc_text(DISTEXT, HalGetEnvironmentVariable )
+#pragma alloc_text(DISTEXT, HalSetEnvironmentVariable )
+#pragma alloc_text(DISTEXT, HalpFindEnvironmentVariable )
+#pragma alloc_text(DISTEXT, HalpEnvironmentCheckChecksum )
+#pragma alloc_text(DISTEXT, HalpEnvironmentSetChecksum )
+
+#endif // AXP_FIRMWARE
+
+
+ARC_STATUS
+HalpReadAndChecksumEnvironment(
+ )
+
+/*++
+
+Routine Description:
+
+ This routine reads the part of the NVRAM containing the environment
+ variables into a memory buffer. It checksums the data as read.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ESUCCESS - checksum is good.
+ EIO - checksum is bad.
+
+--*/
+
+{
+ PUCHAR BufChar;
+ ULONG Index;
+ ULONG Checksum1, Checksum2;
+
+#ifndef EISA_PLATFORM
+ UCHAR Nvram[LENGTH_OF_ENVIRONMENT+16];
+#endif // EISA_PLATFORM
+
+ //
+ // Read checksum of environment data from the NVRAM.
+ // For non eisa machines we have only one checksum for the whole nvram.
+ // And it is stored in Checksum
+ //
+
+ HalpReadNVRamBuffer(
+ (PUCHAR)&Checksum2,
+#ifdef EISA_PLATFORM
+ &((PNV_CONFIGURATION)NVRAM_CONFIGURATION)->Checksum2[0],
+#else // EISA_PLATFORM
+ &((PNV_CONFIGURATION)NVRAM_CONFIGURATION)->Checksum[0],
+#endif // EISA_PLATFORM
+ 4);
+
+ //
+ // If the environment data stored in the buffer is already valid,
+ // short-circuit the NVRAM read.
+ //
+
+ if (EnvironmentValid == TRUE) {
+ if (Checksum2 == EnvironmentChecksum) {
+ return ESUCCESS;
+ }
+ }
+
+#ifdef EISA_PLATFORM
+ //
+ // Read the NVRAM environment data into the buffer.
+ //
+
+ HalpReadNVRamBuffer(
+ &Environment[0],
+ &((PNV_CONFIGURATION)NVRAM_CONFIGURATION)->Environment[0],
+ LENGTH_OF_ENVIRONMENT);
+
+ //
+ // Form checksum of data read from NVRAM.
+ //
+
+ BufChar = &Environment[0];
+ Checksum1 = 0;
+ for ( Index = 0 ; Index < LENGTH_OF_ENVIRONMENT; Index++ ) {
+ Checksum1 += *BufChar++;
+ }
+
+ if (Checksum1 != Checksum2) {
+ return EIO;
+ } else {
+ EnvironmentValid = TRUE;
+ EnvironmentChecksum = Checksum1;
+ return ESUCCESS;
+ }
+#else // EISA_PLATFORM
+
+ //
+ // Read the NVRAM into Nvram.
+ //
+
+ HalpReadNVRamBuffer( &Nvram[0],
+ NVRAM_CONFIGURATION,
+ LENGTH_OF_ENVIRONMENT + 16 );
+
+ //
+ // Form checksum of data read from NVRAM.
+ //
+
+ BufChar = &Nvram[0];
+ Checksum1 = 0;
+ for ( Index = 0 ; Index < LENGTH_OF_ENVIRONMENT+16; Index++ ) {
+ Checksum1 += *BufChar++;
+ }
+
+ if (Checksum1 != Checksum2) {
+ return EIO;
+ } else {
+ EnvironmentValid = TRUE;
+ EnvironmentChecksum = Checksum1;
+
+ //
+ // Nvram checksum was ok. Save the read Environment part of NVRAM
+ // in global Environment[].
+ //
+ BufChar = &Environment[0];
+ for( Index = 16; Index < LENGTH_OF_ENVIRONMENT+16; Index++ ) {
+ *BufChar++ = Nvram[Index];
+ }
+
+ return ESUCCESS;
+ }
+#endif // EISA_PLATFORM
+}
+
+
+ARC_STATUS
+HalpWriteAndChecksumEnvironment (
+ )
+
+/*++
+
+Routine Description:
+
+ This routine writes the environment data back to the NVRAM, calculates
+ a new checksum, and stores the checksum.
+
+ N.B. - For this method of rewriting the environment variables to be
+ effective (minimal NVRAM access and quick overall), the
+ HalpWriteNVRamBuffer is assumed to do block access and to
+ suppress writes it doesn't need to do.
+
+ N.B. - To allow the HalpWriteNVRamBuffer to suppress writes, the new data
+ should have as many bytes in common with the current NVRAM
+ contents as possible. For example, the environment variables
+ should not be reordered unless needed.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ ESUCCESS - NVRAM write succeeded.
+ EIO - NVRAM write failed.
+
+--*/
+
+{
+ ULONG Index;
+ ULONG Checksum;
+ KIRQL OldIrql;
+ PUCHAR BufChar;
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+ //
+ // Form checksum from new NVRAM data.
+ //
+
+ Checksum = 0;
+
+ BufChar = &Environment[0];
+ for ( Index = 0 ; Index < LENGTH_OF_ENVIRONMENT; Index++ ) {
+ Checksum += *BufChar++;
+ }
+
+#ifndef EISA_PLATFORM
+ {
+ UCHAR TempBuffer[16];
+ HalpReadNVRamBuffer( TempBuffer, (PUCHAR)NVRAM_CONFIGURATION, 16 );
+ for ( Index = 0 ; Index < 16; Index++ ) {
+ Checksum += TempBuffer[ Index ];
+ }
+ }
+#endif // !EISA_PLATFORM
+
+ //
+ // Write environment variables to NVRAM.
+ //
+
+ HalpWriteNVRamBuffer(
+ &((PNV_CONFIGURATION)NVRAM_CONFIGURATION)->Environment[0],
+ &Environment[0],
+ LENGTH_OF_ENVIRONMENT);
+
+ //
+ // Write environment checksum.
+ //
+
+ HalpWriteNVRamBuffer(
+#ifdef EISA_PLATFORM
+ &((PNV_CONFIGURATION)NVRAM_CONFIGURATION)->Checksum2[0],
+#else // EISA_PLATFORM
+ &((PNV_CONFIGURATION)NVRAM_CONFIGURATION)->Checksum[0],
+#endif // EISA_PLATFORM
+ (PUCHAR)&Checksum,
+ 4);
+
+ EnvironmentChecksum = Checksum;
+ EnvironmentValid = TRUE;
+
+ KeLowerIrql(OldIrql);
+
+ return ESUCCESS;
+}
+
+
+ARC_STATUS
+HalGetEnvironmentVariable (
+ IN PCHAR Variable,
+ IN USHORT length,
+ OUT PCHAR Buffer
+ )
+
+/*++
+
+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.
+ Length - Supplies the length of the value buffer in bytes
+
+ Buffer - Supplies a pointer to a buffer that will recieve the
+ environment variable.
+
+Return Value:
+
+ ESUCCESS - Buffer contains the zero terminated string value of Variable.
+ ENOENT - The variable doesn't exist in the environment.
+ ENOMEM - The variable exists, but the value is longer than Length.
+
+--*/
+
+{
+ PUCHAR NvChars;
+ ULONG VariableIndex;
+ ULONG ValueIndex;
+ ULONG Index;
+ ARC_STATUS Status;
+ KIRQL OldIrql;
+
+ //
+ // Raise IRQL to synchronize
+ //
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+ //
+ // If checksum is wrong, or the variable can't be found, return NULL.
+ //
+
+ if ((HalpReadAndChecksumEnvironment() != ESUCCESS) ||
+ (HalpFindEnvironmentVariable(Variable,
+ &VariableIndex,
+ &ValueIndex) != ESUCCESS)) {
+ Status = ENOENT;
+ } else {
+
+ //
+ // Copy value to an output string, break on zero terminator
+ // or string max.
+ //
+
+ NvChars = &Environment[ValueIndex];
+ for ( Index = 0 ; Index < length ; Index += 1 ) {
+ if ( (*Buffer++ = *NvChars++) == 0 ) {
+ break;
+ }
+ }
+
+ if (Index == length) {
+ Status = ENOMEM;
+ } else {
+ Status = ESUCCESS;
+ }
+ }
+
+ //
+ // Lower IRQL back to where it was
+ //
+
+ KeLowerIrql(OldIrql);
+
+ return Status;
+}
+
+
+ARC_STATUS
+HalSetEnvironmentVariable (
+ 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:
+
+ ESUCCESS - The set completed successfully
+ ENOSPC - No space in NVRAM for set operation.
+ EIO - Invalid Checksum.
+
+--*/
+
+{
+ ULONG VariableIndex;
+ ULONG ValueIndex;
+ PUCHAR TopOfEnvironment;
+ PCHAR String;
+ PUCHAR NvChars;
+ LONG Count;
+ CHAR Char;
+ KIRQL OldIrql;
+
+ //
+ // Raise Irql to Synchronize
+ //
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+ //
+ // If checksum is wrong, return EIO;
+ //
+
+ if (HalpReadAndChecksumEnvironment() != ESUCCESS) {
+ KeLowerIrql(OldIrql);
+ return EIO;
+ }
+
+//
+//smjfix - examine the boundary condition where the environment space
+// is exactly filled.
+
+ //
+ // Determine the top of the environment space by looking for the first
+ // non-null character from the top.
+ //
+
+ TopOfEnvironment = &Environment[LENGTH_OF_ENVIRONMENT-1];
+
+ do {
+ Char = *TopOfEnvironment;
+
+ } while ( Char == 0 && (--TopOfEnvironment > Environment) );
+
+ //
+ // Adjust TopOfEnvironment to the first new character, unless environment
+ // space is empty, or the environment is exactly full. In the latter
+ // case, the new value MUST fit into the space taken by the old.
+ //
+
+ if (TopOfEnvironment != Environment
+ && TopOfEnvironment < &Environment[LENGTH_OF_ENVIRONMENT-2]) {
+ TopOfEnvironment += 2;
+ }
+
+ //
+ // Handle the case where the content of the NVRAM has been corrupted
+ // such that the last character in the environment is non-zero.
+ //
+
+ Count = &Environment[LENGTH_OF_ENVIRONMENT-1] - TopOfEnvironment;
+ if (Count < 0) {
+ KeLowerIrql(OldIrql);
+ return ENOSPC;
+ }
+
+
+ //
+ // Check to see if the variable already has a value.
+ //
+
+ if (HalpFindEnvironmentVariable(Variable, &VariableIndex, &ValueIndex)
+ == ESUCCESS) {
+ ULONG SizeOfValue = strlen(Value);
+
+ if (SizeOfValue == strlen(&Environment[ValueIndex])) {
+
+ //
+ // Overwrite the current variable in place.
+ //
+
+ RtlMoveMemory(&Environment[ValueIndex],
+ Value,
+ SizeOfValue);
+ //
+ // Suppress the append of the variable to the end of the
+ // environment variable data.
+ //
+
+ *Value = 0;
+
+ } else {
+
+ //
+ // Count free space, starting with the free area at the top and
+ // adding the old variable value.
+ //
+
+ for ( NvChars = &Environment[ValueIndex];
+ NvChars <= TopOfEnvironment;
+ NvChars++ ) {
+
+ Char = *NvChars;
+ if ( Char == 0 )
+ break;
+ 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) {
+ KeLowerIrql(OldIrql);
+ return ENOSPC;
+ }
+ }
+
+ //
+ // Move ValueIndex to the end of the value and compress strings.
+ //
+
+ do {
+ Char = Environment[ValueIndex++];
+ } while( Char != 0 );
+
+ Count = TopOfEnvironment - &Environment[ValueIndex];
+ RtlMoveMemory(&Environment[VariableIndex],
+ &Environment[ValueIndex],
+ Count);
+
+ //
+ // Adjust new top of environment.
+ //
+
+ TopOfEnvironment = &Environment[VariableIndex+Count];
+
+ //
+ // Zero to the end.
+ //
+
+ Count = &Environment[LENGTH_OF_ENVIRONMENT] - TopOfEnvironment;
+ Char = 0;
+ while ( Count -- ) {
+ TopOfEnvironment[Count] = Char;
+ }
+ }
+
+ } else {
+
+ //
+ // Variable is new.
+ //
+
+ //
+ // Determine if free area is large enough to handle new value, if not
+ // return error.
+ //
+
+ //
+ // From the length of free space subtract new variable's length,
+ // Value's length and 2 chars, one for the '=' sign and one of the
+ // null terminator.
+ //
+
+ Count -= ( strlen(Variable) + strlen(Value) + 2 );
+
+ //
+ // Check if there is space to fit the new variable.
+ //
+
+ if (Count < 0) {
+ KeLowerIrql(OldIrql);
+ return ENOSPC;
+ }
+
+ }
+
+ //
+ // If Value is not zero, append the new variable and value.
+ //
+
+ if (*Value != 0) {
+
+ //
+ // Write new variable, converting to upper case.
+ //
+ while ( *Variable != 0 ) {
+
+ Char = ((*Variable >= 'a') && (*Variable <= 'z') ?
+ (*Variable - 'a' + 'A') : *Variable);
+
+ *TopOfEnvironment = Char;
+
+ Variable ++;
+ TopOfEnvironment ++;
+ }
+
+ //
+ // Write equal sign.
+ //
+
+ Char = '=';
+ *TopOfEnvironment++ = Char;
+
+ //
+ // Write new value.
+ //
+
+ for ( Count = 0; Value[Count] != 0; Count ++ )
+ ;
+
+ RtlMoveMemory(&TopOfEnvironment[0], Value, Count);
+
+ }
+
+ //
+ // Write the environment variables out to NVRAM and checksum it.
+ //
+
+ if (HalpWriteAndChecksumEnvironment() != ESUCCESS) {
+ KeLowerIrql(OldIrql);
+ return EIO;
+ }
+
+ //
+ // Lower Irql back to where it was
+ //
+
+ KeLowerIrql(OldIrql);
+
+
+ return ESUCCESS;
+
+}
+
+ARC_STATUS
+HalpFindEnvironmentVariable (
+ IN PCHAR Variable,
+ OUT PULONG VariableIndex,
+ OUT PULONG ValueIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches (not case sensitive) the supplied NVRAM image
+ for the given Variable.
+
+Arguments:
+
+ Variable - Supplies a zero terminated string containing an environment
+ variable.
+ VariableIndex - Returned byte offset into Environment of the
+ Variable if found.
+ ValueIndex - Returned byte offset into Environment of the
+ value of the Variable if found.
+
+Return Value:
+
+ ESUCCESS - Variable found and indicies returned.
+ ENOENT - Variable not found.
+
+--*/
+
+{
+ PUCHAR String;
+ UCHAR Char;
+ ULONG Index;
+
+ //
+ // If Variable is null, return immediately.
+ //
+
+ if (*Variable == 0) {
+ return ENOENT;
+ }
+
+ 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.
+ //
+
+ Char = Environment[Index];
+
+ if ( Char != ((*String >= 'a') && (*String <= 'z') ?
+ (*String - 'a' + 'A') : *String) ) {
+ break;
+ }
+
+ String++;
+ Index++;
+ }
+
+ if ( Index == LENGTH_OF_ENVIRONMENT )
+ return ENOENT;
+
+ //
+ // Check to see if we're at the end of the string and the variable,
+ // which means a match.
+ //
+
+ Char = Environment[Index];
+ if ((*String == 0) && (Char == '=')) {
+ *ValueIndex = ++Index;
+ return ESUCCESS;
+ }
+
+ //
+ // Move index to the start of the next variable.
+ //
+
+ do {
+ Char = Environment[Index++];
+
+ if (Index >= LENGTH_OF_ENVIRONMENT) {
+ return ENOENT;
+ }
+
+ } while (Char != 0);
+
+ }
+}
+
+#if defined(AXP_FIRMWARE)
+
+ARC_STATUS
+HalpEnvironmentCheckChecksum (
+ 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;
+ UCHAR Char;
+ PNV_CONFIGURATION NvConfiguration;
+ ULONG Index;
+ ULONG Checksum1, Checksum2;
+ BOOLEAN AllZeroBytes;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // Form checksum from NVRAM data.
+ //
+
+ Checksum1 = 0;
+ AllZeroBytes = TRUE;
+ NvChars = (PUCHAR)&NvConfiguration->Environment[0];
+
+ for ( Index = 0 ; Index < LENGTH_OF_ENVIRONMENT; Index++ ) {
+
+ HalpReadNVRamBuffer(&Char,NvChars++,1);
+ Checksum1 += Char;
+ if (Char != 0) {
+ AllZeroBytes = FALSE;
+ }
+ }
+
+ //
+ // Reconstitute checksum and return error if no compare.
+ //
+
+#ifdef EISA_PLATFORM
+ HalpReadNVRamBuffer((PCHAR)&Checksum2,&NvConfiguration->Checksum2[0],4);
+#else // EISA_PLATFORM
+ HalpReadNVRamBuffer((PCHAR)&Checksum2,&NvConfiguration->Checksum[0],4);
+#endif // EISA_PLATFORM
+
+ //
+ // We return an error condition if the Checksum does not match the sum
+ // of all the protected bytes, *or* if all the protected bytes are zero.
+ // The latter check covers the condition of a completely zeroed NVRAM;
+ // such a condition would appear to have a valid checksum.
+ //
+ // We do not use a better checksum algorithm because the pain of
+ // orchestrating a change in the existing SRM consoles (which read our
+ // stored Nvram information for various purposes) has been deemed to be
+ // too high.
+ //
+
+ if ((Checksum1 != Checksum2) || (AllZeroBytes == TRUE)) {
+ return EIO;
+ } else {
+ return ESUCCESS;
+ }
+}
+
+
+ARC_STATUS
+HalpEnvironmentSetChecksum (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the environment area checksum.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PUCHAR NvChars;
+ UCHAR Char;
+ PNV_CONFIGURATION NvConfiguration;
+ ULONG Index;
+ ULONG Checksum;
+ KIRQL OldIrql;
+
+ NvConfiguration = (PNV_CONFIGURATION)NVRAM_CONFIGURATION;
+
+ //
+ // Form checksum from NVRAM data.
+ //
+
+ Checksum = 0;
+ NvChars = (PUCHAR)&NvConfiguration->Environment[0];
+
+ KeRaiseIrql(DEVICE_LEVEL, &OldIrql);
+
+ for ( Index = 0 ; Index < LENGTH_OF_ENVIRONMENT; Index++ ) {
+ HalpReadNVRamBuffer(&Char, NvChars ++, 1);
+ Checksum += Char;
+ }
+
+ KeLowerIrql(OldIrql);
+
+ //
+ // Write environment checksum.
+ //
+
+ if (
+#ifdef EISA_PLATFORM
+ HalpWriteNVRamBuffer((PCHAR)NvConfiguration->Checksum2, (PCHAR)&Checksum, 4)
+#else // EISA_PLATFORM
+ HalpWriteNVRamBuffer((PCHAR)NvConfiguration->Checksum, (PCHAR)&Checksum, 4)
+#endif // EISA_PLATFORM
+ != ESUCCESS ) {
+ return EIO;
+ } else {
+ return ESUCCESS;
+
+ }
+}
+
+#endif //AXP_FIRMWARE
diff --git a/private/ntos/nthals/halalpha/environ.h b/private/ntos/nthals/halalpha/environ.h
new file mode 100644
index 000000000..8a1abc91c
--- /dev/null
+++ b/private/ntos/nthals/halalpha/environ.h
@@ -0,0 +1,167 @@
+/*++
+
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ environ.h
+
+Abstract:
+
+ This module contains definitions for environment variable support
+ under the HAL. (Parts taken from J. Derosa's FWP.H)
+
+Author:
+
+ Jeff McLeman (DEC) 17-Sep-1992
+
+Revision History:
+
+--*/
+
+
+
+//
+// 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
+
+#ifdef EISA_PLATFORM
+//
+// Defines for the non-volatile configuration tables.
+//
+
+#define NV_NUMBER_OF_ENTRIES 40
+#define NV_LENGTH_OF_IDENTIFIER (1024 - (NV_NUMBER_OF_ENTRIES * 16) - 8)
+#define NV_LENGTH_OF_DATA (2048 -16)
+#define LENGTH_OF_ENVIRONMENT 1024
+#define LENGTH_OF_EISA_DATA 2044
+
+#define MAXIMUM_ENVIRONMENT_VALUE 256
+#define MAX_NUMBER_OF_ENVIRONMENT_VARIABLES 40
+
+//
+// The non-volatile configuration table structure.
+//
+
+typedef struct _NV_CONFIGURATION {
+ COMPRESSED_CONFIGURATION_PACKET Packet[NV_NUMBER_OF_ENTRIES]; // 0 to 640-4
+ UCHAR Identifier[NV_LENGTH_OF_IDENTIFIER]; // 640 to (1K - 8 - 4)
+ ULONG Monitor; // 1K-8
+ ULONG Floppy; // 1K-4
+ ULONG Floppy2; // 1K
+ ULONG KeyboardType; // 1K+4
+ UCHAR Data[NV_LENGTH_OF_DATA]; // Unused space 1K+8 to 3K-8-4
+ UCHAR Checksum1[4]; // Data checksum 3K-8
+ UCHAR Environment[LENGTH_OF_ENVIRONMENT]; // Env Variables 3K-4 to 4K-4-4
+ UCHAR Checksum2[4]; // Env checksum 4K-4
+ UCHAR EisaData[LENGTH_OF_EISA_DATA]; // Eisa Data (4K to 6K-4)
+ UCHAR Checksum3[4]; // EisaData checksum
+} NV_CONFIGURATION, *PNV_CONFIGURATION;
+
+//
+// Defines for the volatile configuration tables.
+// smd - Increased the number of entries, length of Identifier and length
+// of data.
+//
+
+#define NUMBER_OF_ENTRIES 200
+#define LENGTH_OF_IDENTIFIER (3*1024)
+#define LENGTH_OF_DATA 2048
+
+//
+// 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;
+
+#else // EISA_PLATFORM
+
+//
+// Defines for the Non-Volatile configuration tables.
+//
+// SMD - We have reduced the size of the NVRAM from 6K to 3K
+// If needed we could take a few bytes from ENVIRONMENT
+// since there is tons of empty space there.
+//
+
+#define LENGTH_OF_ENVIRONMENT ((3*1024) - 16 - 4)
+
+#define MAXIMUM_ENVIRONMENT_VALUE 256
+#define MAXIMUM_NUMBER_OF_ENVIRONMENT_VARIABLES 28
+#define MAX_NUMBER_OF_ENVIRONMENT_VARIABLES 28
+//
+// The non-volatile configuration table structure.
+//
+
+typedef struct _NV_CONFIGURATION {
+ ULONG Monitor; //0
+ ULONG Floppy; //4
+ ULONG Floppy2; //8
+ ULONG KeyboardType; //12
+ UCHAR Environment[LENGTH_OF_ENVIRONMENT]; //16 to (3K-4)
+ UCHAR Checksum[4];
+} NV_CONFIGURATION, *PNV_CONFIGURATION;
+
+//
+// Defines for the Volatile configuration tables.
+//
+
+#define NUMBER_OF_ENTRIES 40
+#define LENGTH_OF_IDENTIFIER (1024 - (NUMBER_OF_ENTRIES * 16))
+#define LENGTH_OF_DATA 2048
+
+//
+// The volatile configuration table structure.
+//
+
+typedef struct _CONFIGURATION {
+ CONFIGURATION_PACKET Packet[NUMBER_OF_ENTRIES];
+ UCHAR Identifier[LENGTH_OF_IDENTIFIER];
+ UCHAR Data[LENGTH_OF_DATA];
+} CONFIGURATION, *PCONFIGURATION;
+
+#endif // EISA_PLATFORM
+
+//
+// The value of HalpCMOSRamBase must be set at initialization:
+//
+#define NVRAM_CONFIGURATION HalpCMOSRamBase
diff --git a/private/ntos/nthals/halalpha/errframe.h b/private/ntos/nthals/halalpha/errframe.h
new file mode 100644
index 000000000..ced43eb08
--- /dev/null
+++ b/private/ntos/nthals/halalpha/errframe.h
@@ -0,0 +1,697 @@
+/*++
+
+Copyright (c) 1995,1996 Digital Equipment Corporation
+
+Module Name:
+
+ errframe.h
+
+Abstract:
+
+ Definitions for both the correctable and uncorrectable error
+ frames.
+
+Author:
+
+ Joe Notarangelo 10-Mar-1995
+ Chao Chen 24-Apr-1995
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+0.1 28-Feb-1995 Joe Notarangelo Initial version.
+
+0.2 10-Mar-1995 Joe Notarangelo Incorporate initial review comments from
+ 6-Mar-95 review with: C. Chen, S. Jenness,
+ Bala, E. Rehm.
+
+0.3 24-Apr-1995 Chao Chen Made into .h file for inclusion by other
+ modules.
+
+0.4 16-Apr-1996 Gene Morgan Add fields to SystemError struct for PSU,
+ Wachdog events.
+
+--*/
+
+#ifndef ERRFRAME_H
+#define ERRFRAME_H
+
+#include "errplat.h"
+
+/*
+ *
+ * Common defines.
+ *
+ */
+
+#define ERROR_FRAME_VERSION 0x1
+
+#define UNIDENTIFIED 0x0
+#define MEMORY_SPACE 0x1
+#define IO_SPACE 0x2
+#define PROCESSOR_CACHE 0x2
+#define SYSTEM_CACHE 0x3
+#define PROCESSOR_MEMORY 0x4
+#define SYSTEM_MEMORY 0x5
+
+#define CACHE_ERROR_MASK 0x2
+#define MEMORY_ERROR_MASK 0x4
+
+#define BUS_DMA_READ 0x1
+#define BUS_DMA_WRITE 0x2
+#define BUS_DMA_OP 0x3
+#define BUS_IO_READ 0x4
+#define BUS_IO_WRITE 0x5
+#define BUS_IO_OP 0x6
+#define TLB_MISS_READ 0x7
+#define TLB_MISS_WRITE 0x8
+#define VICTIM_WRITE 0x9
+
+#define MAX_UNCORRERR_STRLEN 128
+
+#define ERROR_FRAME_SIGNATURE 0xE22F2F2A // ERRORFRA R=2 (18%16)
+
+/*
+ *
+ * Definitions for the correctable error frame.
+ *
+ */
+
+//
+// Correctable Error Flags
+//
+
+typedef struct _CORRECTABLE_FLAGS{
+
+ //
+ // Address space
+ // Unidentified: 00
+ // Memory Space: 01
+ // I/O Space: 10
+ // Reserved: 11
+ //
+
+ ULONGLONG AddressSpace: 2;
+
+ //
+ // Error Interpretation Validity.
+ //
+
+ ULONGLONG ServerManagementInformationValid: 1;
+ ULONGLONG PhysicalAddressValid: 1;
+ ULONGLONG ErrorBitMasksValid: 1;
+ ULONGLONG ExtendedErrorValid: 1;
+ ULONGLONG ProcessorInformationValid: 1;
+ ULONGLONG SystemInformationValid: 1;
+
+ //
+ // Memory Space Error Source:
+ //
+ // Unidentified: 000
+ // ProcessorCache: 010
+ // SystemCache: 011
+ // ProcessorMemory: 100
+ // SystemMemory: 101
+ //
+
+ ULONGLONG MemoryErrorSource: 4;
+
+ //
+ // Driver Actions.
+ //
+
+ ULONGLONG ScrubError: 1;
+
+ //
+ // Lost errors.
+ //
+
+ ULONGLONG LostCorrectable: 1;
+ ULONGLONG LostAddressSpace: 2;
+ ULONGLONG LostMemoryErrorSource: 4;
+
+} CORRECTABLE_FLAGS, *PCORRECTABLE_FLAGS;
+
+ //
+ // Description of CORRECTABLE_FLAG structure:
+ //
+ // AddressSpace
+ //
+ // Identifies the system address space that was the source of the
+ // correctable error.
+ //
+ // PhysicalAddressValid
+ //
+ // Indicates if the physical address in the CORRECTABLE_ERROR
+ // structure is valid. A value of 1 indicates the physical address
+ // is valid, a value of 0 indicates the physical address is not
+ // valid.
+ //
+ // ErrorBitMasksValid
+ //
+ // Indicates if the error bit mask fields in the CORRECTABLE_ERROR
+ // structure are valid. A value of 1 indicates the DataBitErrorMask
+ // and the CheckBitErrorMask are valid, a value of 0 indicates they
+ // are not valid.
+ //
+ // ExtendedErrorValid
+ //
+ // Indicates if the extended error information structure in the
+ // CORRECTABLE_ERROR structure is valid. A value of 1 indicates the
+ // extended error information structure is valid, a value of 0
+ // indicates that it is not.
+ //
+ // ProcessorInformationValid
+ //
+ // Indicates if the raw processor information pointer in the
+ // CORRECTABLE_ERROR structure is valid. A value of 1 indicates the
+ // processor information is valid, a value of 0 indicates it is not.
+ //
+ // SystemInformationValid
+ //
+ // Indicates if the raw system information pointer in the
+ // CORRECTABLE_ERROR structure is valid. A value of 1 indicates the
+ // system information is valid, a value of 0 indicates it is not.
+ //
+ // ServerManagementInformationValid
+ //
+ // Indicates that the server management information in the extended
+ // error information structure is valid. The server management
+ // information relays information about failed fans or high
+ // temperature in the system.
+ //
+ //
+ // MemoryErrorSource
+ //
+ // Identifies the source of a memory error as either main error
+ // or cache for either a system or processor.
+ //
+ // ScrubError
+ //
+ // Instructs the driver to scrub the correctable error. If the
+ // value is 1 the driver should scrub the error, if the value is
+ // 0 the driver must not scrub the error.
+ //
+ // LostCorrectable
+ //
+ // Identifies if a lost correctable error has been reported. A
+ // lost error is an error that reported by the hardware while
+ // correctable error handling for a previous error was in progress.
+ // A value of 1 indicates that a correctable error report was lost.
+ //
+ // LostAddressSpace
+ //
+ // Identifies the system address space that was the source of the
+ // correctable error. Valid only if LostCorrectable == 1.
+ //
+ // LostMemoryErrorSource
+ //
+ // Identifies the source of a memory error as either main error
+ // or cache for either a system or processor. Valid only if
+ // LostCorrectable == 1.
+ //
+
+//
+// Processor information.
+//
+
+typedef struct _PROCESSOR_INFO{
+
+ ULONG ProcessorType;
+ ULONG ProcessorRevision;
+ ULONG PhysicalProcessorNumber;
+ ULONG LogicalProcessorNumber;
+
+} PROCESSOR_INFO, *PPROCESSOR_INFO;
+
+ //
+ // Description of PROCESSOR_INFO structure:
+ //
+ // ProcessorType
+ //
+ // Identifies the type of processor running on the system
+ // (eg. 21064, 21066, 21164). Note that the type of processor
+ // is expected to be consistent across the system for MP machines.
+ //
+ // ProcessorRevision
+ //
+ // Identifies the revision number of the processor running on
+ // the system. Note that the revision is expected to be consistent
+ // across the system for MP machines.
+ //
+ // PhysicalProcessorNumber
+ //
+ // The physical processor number as numbered in the hardware
+ // specifications.
+ //
+ // LogicalProcessorNumber
+ //
+ // The logical processor number assigned to the processor by NT.
+ //
+
+//
+// System Information.
+//
+
+typedef struct _SYSTEM_INFORMATION{
+
+ UCHAR SystemType[8];
+ ULONG ClockSpeed;
+ ULONG OsRevisionId;
+ ULONG PalMajorVersion;
+ ULONG PalMinorVersion;
+ UCHAR FirmwareRevisionId[16];
+ ULONG SystemVariant;
+ ULONG SystemRevision;
+ UCHAR SystemSerialNumber[16];
+ ULONG ModuleVariant;
+ ULONG ModuleRevision;
+ ULONG ModuleSerialNumber;
+} SYSTEM_INFORMATION, *PSYSTEM_INFORMATION;
+
+ //
+ // Description of SYSTEM_INFORMATION structure:
+ //
+ // SystemType
+ //
+ // Identifies the type of system that reported the error
+ // (eg. "Sable", "Gamma"). The actual format and value of the
+ // SystemType string is system-specific.
+ //
+ // OsRevisionId
+ //
+ // A numeric value that identifies the OS revision executing
+ // on the system that reported the fault.
+ //
+ // PalRevisionId
+ //
+ // A numeric value that identifies the pal revision executing
+ // on the system that reported the fault.
+ //
+ // FirmwareRevisionId
+ //
+ // A numeric value that identifies the firmware revision executing
+ // on the system that reported the fault.
+ //
+ // SystemVariant
+ //
+ // A numeric value used to distinguish variants of the same system
+ // type. The values and their interpretation are system_specific.
+ //
+ // SystemRevision
+ //
+ // A numeric value used to distinguish revisions of the same system
+ // type. The values and their interpretation are system_specific.
+ //
+ //
+
+//
+// Extended Error Information.
+//
+
+typedef union _EXTENDED_ERROR{
+
+ struct{
+ struct{
+ ULONG CacheLevelValid: 1;
+ ULONG CacheBoardValid: 1;
+ ULONG CacheSimmValid: 1;
+ } Flags;
+ PROCESSOR_INFO ProcessorInfo;
+ ULONG CacheLevel;
+ ULONG CacheBoardNumber;
+ ULONG CacheSimm;
+ ULONG TransferType;
+ ULONG Reserved;
+ } CacheError;
+
+ struct{
+ struct{
+ ULONG MemoryBoardValid: 1;
+ ULONG MemorySimmValid: 1;
+ } Flags;
+ PROCESSOR_INFO ProcessorInfo;
+ ULONG MemoryBoard;
+ ULONG MemorySimm;
+ ULONG TransferType;
+ ULONG Reserved[2];
+ } MemoryError;
+
+ struct{
+ INTERFACE_TYPE Interface;
+ ULONG BusNumber;
+ PHYSICAL_ADDRESS BusAddress;
+ ULONG TransferType;
+ ULONG Reserved[5];
+ } IoError;
+
+ struct{
+ struct{
+ ULONG FanNumberValid: 1;
+ ULONG TempSensorNumberValid: 1;
+ ULONG PowerSupplyNumberValid: 1;
+ ULONG WatchDogExpiredValid: 1;
+ } Flags;
+ ULONG FanNumber;
+ ULONG TempSensorNumber;
+ ULONG PowerSupplyNumber;
+ ULONG WatchdogExpiration;
+ ULONG Reserved[5];
+ } SystemError;
+
+} EXTENDED_ERROR, *PEXTENDED_ERROR;
+
+ //
+ // Description of EXTENDED_ERROR union:
+ //
+ // The EXTENDED_ERROR union has different interpretation depending
+ // upon the AddressSpace and MemoryErrorSource fields of the
+ // CORRECTABLE_FLAGS structure according to the following table:
+ //
+ // 1. AddressSpace=MemorySpace
+ // MemoryErrorSource = 01x use CacheError structure
+ //
+ // 2. AddressSpace=MemorySpace
+ // MemoryErrorSource = 10x use MemoryError structure
+ //
+ // 3. AddressSpace=IoSpace use IoError
+ //
+ // 4. AddressSpace=Unidentified use SystemError
+ // MemoryErrorSource = 0x0 (note: ServerManagementInformationValid
+ // should be set)
+ //
+ //
+ // CacheError.Flags
+ //
+ // Identifies which fields of the CacheError structure are valid.
+ // CacheLevelValid = 1 indicates CacheLevel is valid.
+ // CacheBoardValid = 1 indicates CacheBoardNumber is valid.
+ // CacheSimmValid = 1 indicates CacheSimm is valid.
+ //
+ // CacheError.ProcessorInfo
+ //
+ // Identifies the processor associated with the error. Most
+ // frequently will identify the processor that experienced and
+ // reported the error. However, it is possible that the processor
+ // that is reporting has experienced the error from another
+ // processor's cache. This field is valid only if the
+ // MemoryErrorSource = 010 .
+ //
+ // CacheError.CacheLevel
+ //
+ // Identifies the level of the cache that caused the error. Primary
+ // caches are Level 1, Secondary are Level 2, etc.. This field
+ // only valid if CacheError.Flags.CacheLevelValid == 1.
+ //
+ // CacheError.CacheBoardNumber
+ //
+ // Identifies the board number of the cache that caused the error.
+ // This field only valid if
+ // CacheError.Flags.CacheBoardNumberValid == 1.
+ //
+ // CacheError.CacheSimm
+ //
+ // Identifies the Cache Simm that caused the error.
+ // This field only valid if CacheError.Flags.CacheSimmValid == 1.
+ //
+ //
+ // MemoryError.Flags
+ //
+ // Identifies which fields of the CacheError structure are valid.
+ // CacheLevelValid = 1 indicates CacheLevel is valid.
+ // CacheBoardValid = 1 indicates CacheBoardNumber is valid.
+ // CacheSimmValid = 1 indicates CacheSimm is valid.
+ //
+ // MemoryError.ProcessorInfo
+ //
+ // Identifies the processor associated with the error. Most
+ // frequently will identify the processor that experienced and
+ // reported the error. However, it is possible that the processor
+ // that is reporting has experienced the error from another
+ // processor's cache. This field is valid only if the
+ // MemoryErrorSource = 010 .
+ //
+ // MemoryError.MemoryBoardNumber
+ //
+ // Identifies the board number of the cache that caused the error.
+ // This field only valid if MemoryError.Flags.MemoryBoardValid == 1.
+ //
+ // MemoryError.MemorySimm
+ //
+ // Identifies the memory SIMM that caused the error.
+ // This field only valid if MemoryError.Flags.MemorySimmValid == 1.
+ //
+ //
+ // IoError.Interface
+ //
+ // Identifies the bus interface type (eg. PCI) of the bus that caused
+ // the correctable error.
+ //
+ // IoError.BusNumber
+ //
+ // Identifies the bus number of the bus that caused the correctable
+ // error.
+ //
+ // IoError.BusAddress
+ //
+ // Identifies the bus address of the bus that caused the correctable
+ // error.
+ //
+
+//
+// Correctable Error Frame.
+//
+
+typedef struct _CORRECTABLE_ERROR{
+
+ CORRECTABLE_FLAGS Flags;
+ ULONGLONG PhysicalAddress;
+ ULONGLONG DataBitErrorMask;
+ ULONGLONG CheckBitErrorMask;
+ EXTENDED_ERROR ErrorInformation;
+ PROCESSOR_INFO ReportingProcessor;
+ SYSTEM_INFORMATION System;
+ ULONG RawProcessorInformationLength;
+ PVOID RawProcessorInformation;
+ ULONG RawSystemInformationLength;
+ PVOID RawSystemInformation;
+ ULONG Reserved;
+
+} CORRECTABLE_ERROR, *PCORRECTABLE_ERROR;
+
+ //
+ // Description of CORRECTABLE_ERROR structure:
+ //
+ // Flags
+ //
+ // The flags describe the various aspects of the error report. The
+ // CORRECTABLE_FLAGS structure is described below.
+ //
+ // PhysicalAddress
+ //
+ // The physical CPU address of the quadword that caused the correctable
+ // error report. This value is optional, its validiity is indicated
+ // in the Flags.
+ //
+ // DataBitErrorMask
+ //
+ // A mask that describes which data bits in the corrected word were
+ // in error. A value of one in the mask indicates that the
+ // corresponding bit in the data word were in error.
+ //
+ // CheckBitErrorMask
+ //
+ // A mask that describes which check bits in the corrected word were
+ // in error. A value of one in the mask indicates that the
+ // corresponding bit in the check bits were in error.
+ //
+ // ErrorInformation
+ //
+ // A structure that desribes interpretation of the error. The values
+ // in the structure are optional, the EXTENDED_ERROR structure is
+ // described below.
+ //
+ // ReportingProcessor
+ //
+ // A structure that describes the processor type on the system and
+ // the processor that reported the error. PROCESSOR_INFO structure
+ // is described below.
+ //
+ // RawProcessorInformationLength
+ //
+ // The length of the raw processor error information structure in
+ // bytes.
+ //
+ // RawProcessorInformation
+ //
+ // A pointer to the raw processor error information structure. The
+ // definition of the structure is processor-specific. The definitions
+ // for the known processors is defined in Appendix A below.
+ //
+ // System
+ //
+ // A structure that describes the type of system for which the
+ // error was reported. SYSTEM_INFORMATION structure is described below.
+ //
+ // RawSystemInformationLength
+ //
+ // The length of the raw processor error information structure in
+ // bytes.
+ //
+ // RawSystemInformation
+ //
+ // A pointer to the raw system error information structure. The
+ // definition of the structure is system/ASIC-specific. The
+ // definitions for the known systems/ASICs is defined in Appendix B.
+ //
+ //
+
+
+/*
+ *
+ * Definitions for the uncorrectable error frame.
+ *
+ */
+
+//
+// Uncorrectable Error Flags.
+//
+
+typedef struct _UNCORRECTABLE_FLAGS{
+
+ //
+ // Address space
+ // Unidentified: 00
+ // Memory Space: 01
+ // I/O Space: 10
+ // Reserved: 11
+ //
+
+ ULONGLONG AddressSpace: 2;
+
+ //
+ // Error Interpretation Validity.
+ //
+
+ ULONGLONG ErrorStringValid: 1;
+ ULONGLONG PhysicalAddressValid: 1;
+ ULONGLONG ErrorBitMasksValid: 1;
+ ULONGLONG ExtendedErrorValid: 1;
+ ULONGLONG ProcessorInformationValid: 1;
+ ULONGLONG SystemInformationValid: 1;
+
+ //
+ // Memory Space Error Source:
+ //
+ // Unidentified: 000
+ // ProcessorCache: 010
+ // SystemCache: 011
+ // ProcessorMemory: 100
+ // SystemMemory: 101
+ //
+
+ ULONGLONG MemoryErrorSource: 4;
+
+} UNCORRECTABLE_FLAGS, *PUNCORRECTABLE_FLAGS;
+
+ //
+ // The extended error information, processor information and system
+ // information structures are identical for correctable and uncorrectable
+ // errors. The rules for printing the failing FRU are also identical
+ // to the rules for the correctable errors.
+ //
+
+//
+// Uncorrectable Error Frame.
+//
+
+typedef struct _UNCORRECTABLE_ERROR{
+
+ UNCORRECTABLE_FLAGS Flags;
+ CHAR ErrorString[MAX_UNCORRERR_STRLEN];
+ ULONGLONG PhysicalAddress;
+ ULONGLONG DataBitErrorMask;
+ ULONGLONG CheckBitErrorMask;
+ EXTENDED_ERROR ErrorInformation;
+ PROCESSOR_INFO ReportingProcessor;
+ SYSTEM_INFORMATION System;
+ ULONG RawProcessorInformationLength;
+ PVOID RawProcessorInformation;
+ ULONG RawSystemInformationLength;
+ PVOID RawSystemInformation;
+ ULONG Reserved;
+
+} UNCORRECTABLE_ERROR, *PUNCORRECTABLE_ERROR;
+
+
+/*
+ *
+ * Generic definitions for the error frame.
+ *
+ */
+
+//
+// Generic error frame.
+//
+
+typedef enum _FRAME_TYPE{
+ CorrectableFrame,
+ UncorrectableFrame
+} FRAME_TYPE, *PFRAME_TYPE;
+
+typedef struct _ERROR_FRAME{
+
+ ULONG Signature; // Needed to make sure that the buffer is infact
+ // an error frame.
+ ULONG LengthOfEntireErrorFrame;
+ FRAME_TYPE FrameType;
+ ULONG VersionNumber;
+ ULONG SequenceNumber;
+ ULONGLONG PerformanceCounterValue;
+
+ union {
+ CORRECTABLE_ERROR CorrectableFrame;
+ UNCORRECTABLE_ERROR UncorrectableFrame;
+ };
+
+} ERROR_FRAME, *PERROR_FRAME;
+
+ //
+ // Description of the generic error frame structure:
+ //
+ // FrameType
+ //
+ // Specify which frame type we have. Either correctable or
+ // uncorrectable.
+ //
+ // VersionNumber
+ //
+ // Defines the version of the error structure. Current version
+ // number = 1.
+ //
+ // SequenceNumber
+ //
+ // A number that identifies a particular error frame.
+ //
+ // PerformanceCounterValue
+ //
+ // The value of the system performance counter when the error was
+ // reported. The value is determined during error processing by the
+ // HAL and so may be captured significantly after the hardware
+ // detected the error. The value cannot be used for fine grained
+ // timing of when errors occurred but can be used for coarse grained
+ // timing and approximate timing.
+ //
+ // CorrectableFrame
+ //
+ // Shared common area for a correctable frame.
+ //
+ // UncorrectableFrame
+ //
+ // Shared common area for an uncorrectable frame.
+ //
+
+#endif //ERRFRAME_H
diff --git a/private/ntos/nthals/halalpha/errplat.h b/private/ntos/nthals/halalpha/errplat.h
new file mode 100644
index 000000000..99133ed2c
--- /dev/null
+++ b/private/ntos/nthals/halalpha/errplat.h
@@ -0,0 +1,774 @@
+/*++
+
+Copyright (c) 1995 Digital Equipment Corporation
+
+Module Name:
+
+ errplat.h
+
+Abstract:
+
+ Definitions for the platform specific correctable and uncorrectable error
+ frames for processors and systems.
+
+Author:
+
+ Joe Notarangelo 10-Mar-1995
+ Chao Chen 24-Apr-1995
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+0.1 28-Feb-1995 Joe Notarangelo Initial version.
+
+0.2 10-Mar-1995 Joe Notarangelo Incorporate initial review comments from
+ 6-Mar-95 review with: C. Chen, S. Jenness,
+ Bala, E. Rehm.
+
+0.3 24-Apr-1995 Chao Chen Made into .h file for inclusion by other
+ modules.
+
+0.4 Jun-July-1995 Bala Nagarajan Added Uncorrectable Error frames for
+ APECS, SABLE, GAMMA etc.
+--*/
+#ifndef ERRPLAT_H
+#define ERRPLAT_H
+
+/*
+ *
+ * Processor specific definitions for error frame.
+ *
+ */
+
+//
+// EV5:
+//
+
+//
+// Processor information structure for processor detected correctable read
+// on the EV5.
+//
+
+typedef struct PROCESSOR_EV5_CORRECTABLE{
+ ULONGLONG EiAddr;
+ ULONGLONG FillSyn;
+ ULONGLONG EiStat;
+ ULONGLONG BcConfig;
+ ULONGLONG BcControl;
+} PROCESSOR_EV5_CORRECTABLE, *PPROCESSOR_EV5_CORRECTABLE;
+
+//
+// Processor information structure for processor-detected uncorrectable errors
+// on the EV5.
+//
+
+typedef struct PROCESSOR_EV5_UNCORRECTABLE{
+ ULONGLONG IcPerrStat;
+ ULONGLONG DcPerrStat;
+ ULONGLONG ScStat;
+ ULONGLONG ScAddr;
+ ULONGLONG EiStat;
+ ULONGLONG BcTagAddr;
+ ULONGLONG EiAddr;
+ ULONGLONG FillSyn;
+ ULONGLONG BcConfig;
+ ULONGLONG BcControl;
+} PROCESSOR_EV5_UNCORRECTABLE, *PPROCESSOR_EV5_UNCORRECTABLE;
+
+
+//
+// EV4(5):
+//
+
+//
+// Processor information structure for processor detected correctable read
+// on the EV4(5).
+//
+
+typedef struct PROCESSOR_EV4_CORRECTABLE{
+ ULONGLONG BiuStat;
+ ULONGLONG BiuAddr;
+ ULONGLONG AboxCtl;
+ ULONGLONG BiuCtl;
+ ULONGLONG CStat; // a.k.a. DcStat for EV4
+} PROCESSOR_EV4_CORRECTABLE, *PPROCESSOR_EV4_CORRECTABLE;
+
+//
+// Processor information structure for processor detected uncorrectable errors
+// on the EV4(5).
+//
+
+typedef struct PROCESSOR_EV4_UNCORRECTABLE{
+ ULONGLONG BiuStat;
+ ULONGLONG BiuAddr;
+ ULONGLONG AboxCtl;
+ ULONGLONG BiuCtl;
+ ULONGLONG CStat; // a.k.a. DcStat for EV4
+ ULONGLONG BcTag;
+ ULONGLONG FillAddr;
+ ULONGLONG FillSyndrome;
+} PROCESSOR_EV4_UNCORRECTABLE, *PPROCESSOR_EV4_UNCORRECTABLE;
+
+
+//
+// LCA:
+//
+
+//
+// Processor information structure for processor detected correctable read
+// on the LCA.
+//
+
+typedef struct PROCESSOR_LCA_CORRECTABLE{
+ ULONG VersionNumber; // Version Number of this structure not the LCA.
+ ULONGLONG Esr;
+ ULONGLONG Ear;
+ ULONGLONG AboxCtl;
+ ULONG BankConfig0;
+ ULONG BankConfig1;
+ ULONG BankConfig2;
+ ULONG BankConfig3;
+ ULONG BankMask0;
+ ULONG BankMask1;
+ ULONG BankMask2;
+ ULONG BankMask3;
+ ULONG Car;
+ ULONG Gtr;
+} PROCESSOR_LCA_CORRECTABLE, *PPROCESSOR_LCA_CORRECTABLE;
+
+//
+// Processor information structure for processor detected uncorrectable errors
+// on the LCA.
+//
+
+typedef struct PROCESSOR_LCA_UNCORRECTABLE{
+ ULONG VersionNumber; // Version Number of this structure not the LCA.
+ ULONGLONG CStat; // a.k.a. DcStat for LCA4
+ ULONGLONG Esr;
+ ULONGLONG Ear;
+ ULONGLONG IocStat0;
+ ULONGLONG IocStat1;
+ ULONGLONG AboxCtl;
+ ULONGLONG MmCsr;
+ ULONGLONG BankConfig0;
+ ULONGLONG BankConfig1;
+ ULONGLONG BankConfig2;
+ ULONGLONG BankConfig3;
+ ULONGLONG BankMask0;
+ ULONGLONG BankMask1;
+ ULONGLONG BankMask2;
+ ULONGLONG BankMask3;
+ ULONGLONG Car;
+ ULONGLONG Gtr;
+} PROCESSOR_LCA_UNCORRECTABLE, *PPROCESSOR_LCA_UNCORRECTABLE;
+
+//
+// The generic raw processor frame.
+//
+
+typedef union _RAW_PROCESSOR_FRAME{
+
+ PROCESSOR_EV5_CORRECTABLE Ev5Correctable;
+ PROCESSOR_EV5_UNCORRECTABLE Ev5Uncorrectable;
+ PROCESSOR_EV4_CORRECTABLE Ev4Correctable;
+ PROCESSOR_EV4_UNCORRECTABLE Ev4Uncorrectable;
+ PROCESSOR_LCA_CORRECTABLE LcaCorrectable;
+ PROCESSOR_LCA_UNCORRECTABLE LcaUncorrectable;
+
+} RAW_PROCESSOR_FRAME, *PRAW_PROCESSOR_FRAME;
+
+/*
+ *
+ * System specific definitions for error frame.
+ *
+ */
+
+//
+// Cia:
+//
+
+//
+// Cia configuration information
+//
+
+typedef struct _CIA_CONFIGURATION{
+
+ ULONG CiaRev;
+ ULONG CiaCtrl;
+ ULONG Mcr;
+ ULONG Mba0;
+ ULONG Mba2;
+ ULONG Mba4;
+ ULONG Mba6;
+ ULONG Mba8;
+ ULONG MbaA;
+ ULONG MbaC;
+ ULONG MbaE;
+ ULONG Tmg0;
+ ULONG Tmg1;
+ ULONG Tmg2;
+ ULONG CacheCnfg;
+ ULONG Scr;
+
+} CIA_CONFIGURATION, *PCIA_CONFIGURATION;
+
+//
+// Cia system detected correctable.
+//
+
+typedef struct _CIA_CORRECTABLE_FRAME{
+ ULONG VersionNumber; // Version Number of this structure.
+ ULONG CiaErr;
+ ULONG CiaStat;
+ ULONG CiaSyn;
+ ULONG MemErr0;
+ ULONG MemErr1;
+ ULONG PciErr0;
+ ULONG PciErr1;
+ ULONG PciErr2;
+ CIA_CONFIGURATION Configuration;
+
+} CIA_CORRECTABLE_FRAME, *PCIA_CORRECTABLE_FRAME;
+
+ //
+ // Note: it appears that the only correctable errors that are detected
+ // are:
+ //
+ // a. ECC on DMA Read (memory or cache)
+ // b. ECC on S/G TLB fill for DMA Read (memory or cache)
+ // c. ECC on DMA Write (probably CIA)
+ // d. ECC on S/G TLB fill for DMA write (memory or cache) (no PA?)
+ // e. I/O Write (ASIC problem) (no PA)
+ //
+
+//
+// Cia System-detected Uncorrectable Error
+//
+
+typedef struct _CIA_UNCORRECTABLE_FRAME{
+ ULONG VersionNumber; // Version Number of this structure.
+ ULONG CiaErr;
+ ULONG ErrMask;
+ ULONG CiaStat;
+ ULONG CiaSyn;
+ ULONG CpuErr0;
+ ULONG CpuErr1;
+ ULONG MemErr0;
+ ULONG MemErr1;
+ ULONG PciErr0;
+ ULONG PciErr1;
+ ULONG PciErr2;
+ CIA_CONFIGURATION Configuration;
+
+} CIA_UNCORRECTABLE_FRAME, *PCIA_UNCORRECTABLE_FRAME;
+
+//
+// Apecs:
+//
+
+//
+// Apecs Configuration Information
+//
+
+typedef struct _APECS_CONFIGURATION {
+ ULONG ApecsRev;
+ ULONG CGcr; // General Control register
+ ULONG CTer; // Tag Enable Register
+ ULONG CGtr; // Global Timer Register
+ ULONG CRtr; // refresh Timer register
+ ULONG CBank0; // Bank Configuration registers.
+ ULONG CBank1;
+ ULONG CBank2;
+ ULONG CBank3;
+ ULONG CBank4;
+ ULONG CBank5;
+ ULONG CBank6;
+ ULONG CBank7;
+ ULONG CBank8;
+
+} APECS_CONFIGURATION, *PAPECS_CONFIGURATION;
+
+//
+// Apecs based system-detected Correctable Error
+//
+
+typedef struct _APECS_CORRECTABLE_FRAME{
+ ULONG VersionNumber; // Version Number of this structure not the APECS.
+ ULONG EpicEcsr;
+ ULONG EpicSysErrAddr;
+ APECS_CONFIGURATION Configuration;
+
+} APECS_CORRECTABLE_FRAME, *PAPECS_CORRECTABLE_FRAME;
+
+ //
+ // Note: it appears that the only correctable errors that are detected
+ // are:
+ //
+ // a. ECC on DMA Read (memory)
+ // b. ECC on S/G TLB fill for DMA Read (memory)
+ //
+
+//
+// Apecs based system-detected Uncorrectable Error
+//
+
+typedef struct _APECS_UNCORRECTABLE_FRAME{
+ ULONG VersionNumber; // Version Number of this structure not the APECS.
+ ULONG EpicEcsr;
+ ULONG ComancheEdsr;
+ ULONG EpicPciErrAddr;
+ ULONG EpicSysErrAddr;
+ ULONG ComancheErrAddr;
+ APECS_CONFIGURATION Configuration;
+
+} APECS_UNCORRECTABLE_FRAME, *PAPECS_UNCORRECTABLE_FRAME;
+
+
+//
+// T2, T3, T4 Chipset error frame.
+//
+
+typedef struct _TX_ERROR_FRAME {
+ ULONGLONG Cerr1; // CBUS Error Register 1
+ ULONGLONG Cerr2; // CBUS Error Register 2
+ ULONGLONG Cerr3; // CBUS Error Register 3
+ ULONGLONG Perr1; // PCI Error Register 1
+ ULONGLONG Perr2; // PCI Error Register 2
+} TX_ERROR_FRAME, *PTX_ERROR_FRAME;
+
+
+//
+// Sable CPU Module configuration information.
+//
+
+typedef struct _SABLE_CPU_CONFIGURATION {
+ ULONGLONG Cbctl;
+ ULONGLONG Pmbx;
+ ULONGLONG C4rev;
+} SABLE_CPU_CONFIGURATION, *PSABLE_CPU_CONFIGURATION;
+
+//
+// Sable Memory Module configuration information.
+//
+
+typedef struct _SABLE_MEMORY_CONFIGURATION {
+ ULONGLONG Conifg; // CSR 3
+ ULONGLONG EdcCtl; // Error detection/correction control register
+ ULONGLONG StreamBfrCtl;
+ ULONGLONG RefreshCtl;
+ ULONGLONG CrdFilterCtl;
+} SABLE_MEMORY_CONFIGURATION, *PSABLE_MEMORY_CONFIGURATION;
+
+
+//
+// Sable System Configuration
+//
+
+typedef struct _SABLE_CONFIGURATION {
+ ULONG T2Revision; // Revision number of the T2 chipset.
+ ULONG NumberOfCpus; // Number of CPUs in the system.
+ ULONG NumberOfMemModules; // Number of memory modules in the system.
+ ULONGLONG T2IoCsr;
+ SABLE_CPU_CONFIGURATION CpuConfigs[4]; // 4 is the max CPU's
+ SABLE_MEMORY_CONFIGURATION MemConfigs[4]; // Maximum of 4 memory modules.
+} SABLE_CONFIGURATION, *PSABLE_CONFIGURATION;
+
+//
+// Sable CPU-module Error Information
+//
+
+typedef struct _SABLE_CPU_ERROR {
+
+ union {
+ struct {
+ ULONGLONG Bcue; // BCacheUncorrectableError
+ ULONGLONG Bcuea; // BCacheUncorrectableErrorAddress
+ } Uncorrectable;
+
+ struct {
+ ULONGLONG Bcce; // BCacheCorrectableError
+ ULONGLONG Bccea; // BCacheCorrectableErrorAddress
+ } Correctable;
+ };
+ ULONGLONG Dter; // Duplicate Tag Error Register
+ ULONGLONG Cberr; // CBUS2 Error (System Bus Error)
+ ULONGLONG Cbeal; // system bus error address register low.
+ ULONGLONG Cbeah; // system bus error address register high.
+} SABLE_CPU_ERROR, *PSABLE_CPU_ERROR;
+
+typedef struct _SABLE_MEMORY_ERROR {
+
+ ULONGLONG MemError; // CSR0 of memory module
+ ULONGLONG EdcStatus1;
+ ULONGLONG EdcStatus2;
+
+} SABLE_MEMORY_ERROR, *PSABLE_MEMORY_ERROR;
+
+//
+// Sable Correctable and Uncorrectable Error Frame.
+//
+
+typedef struct _SABLE_ERROR_FRAME {
+
+ SABLE_CPU_ERROR CpuError[4];
+ SABLE_MEMORY_ERROR MemError[4];
+ TX_ERROR_FRAME IoChipsetError;
+ SABLE_CONFIGURATION Configuration;
+} SABLE_UNCORRECTABLE_FRAME, *PSABLE_UNCORRECTABLE_FRAME,
+ SABLE_CORRECTABLE_FRAME, *PSABLE_CORRECTABLE_FRAME;
+
+
+
+//
+// Gamma CPU Module configuration information.
+//
+
+typedef struct _GAMMA_CPU_CONFIGURATION {
+ ULONGLONG Cbctl; // Cbus2 Control Register.
+ ULONGLONG Dtctr; // Duplicate Tag control register.
+ ULONGLONG Creg; // Rattler Control Register.
+} GAMMA_CPU_CONFIGURATION, *PGAMMA_CPU_CONFIGURATION;
+
+
+//
+// Gamma System Configuration
+//
+
+typedef struct _GAMMA_CONFIGURATION {
+ ULONG T2Revision; // Revision number of the T2 chipset.
+ ULONG NumberOfCpus; // Number of CPUs in the system.
+ ULONG NumberOfMemModules; // Number of memory modules in the system.
+ ULONGLONG T2IoCsr;
+ GAMMA_CPU_CONFIGURATION CpuConfigs[4]; // 4 is the max CPU's
+ SABLE_MEMORY_CONFIGURATION MemConfigs[4]; // Maximum of 4 memory modules.
+} GAMMA_CONFIGURATION, *PGAMMA_CONFIGURATION;
+
+//
+// Gamma CPU-module Error Information
+//
+
+typedef struct _GAMMA_CPU_ERROR {
+ ULONGLONG Esreg; // Error Summary
+ union {
+ struct {
+ ULONGLONG Evbuer; // EVB Uncorrectable Error
+ ULONGLONG Evbuear; // EVB Uncorrectable Error Address
+ } Uncorrectable;
+
+ struct {
+ ULONGLONG Evbcer; // EVB Correctable Error
+ ULONGLONG Evbcear; // EVB Correctable error address
+ } Correctable;
+ };
+ ULONGLONG Vear; // Victim Error Address
+ // valid only if bit 5 or bit 37
+ // of Evbuer is set.
+
+ ULONGLONG Dter; // Duplicate Tag Error Register
+ ULONGLONG Cberr; // CBUS2 Error (System Bus Error)
+ ULONGLONG Cbeal; // system bus error address register low.
+ ULONGLONG Cbeah; // system bus error address register high.
+} GAMMA_CPU_ERROR, *PGAMMA_CPU_ERROR;
+
+
+//
+// Gamma Correctable and Uncorrectable Error Frame.
+//
+
+typedef struct _GAMMA_ERROR_FRAME {
+
+ GAMMA_CPU_ERROR CpuError[4];
+ SABLE_MEMORY_ERROR MemError[4];
+ TX_ERROR_FRAME IoChipsetError;
+ GAMMA_CONFIGURATION Configuration;
+} GAMMA_UNCORRECTABLE_FRAME, *PGAMMA_UNCORRECTABLE_FRAME,
+ GAMMA_CORRECTABLE_FRAME, *PGAMMA_CORRECTABLE_FRAME;
+
+
+//
+// Rawhide Error Frame Definitions
+//
+
+//
+// CPU Daughter Card (CUD) Header
+//
+
+typedef struct _RAWHIDE_CUD_HEADER { // As Per Rawhide SPM
+ ULONG ActiveCpus; // (0x00)
+ ULONG HwRevision; // (0x04)
+ UCHAR SystemSN[10]; // (0x08-0x11) Same as FRU System Serial Number
+ UCHAR Reserved2[6]; // (0x12-0x17)
+ UCHAR ModuleSN[10]; // (0x18-0x21) Module (processor) S/N, if available
+ USHORT ModType; // (0x22)
+ ULONG Reserved3; // (0x24)
+ ULONG DisabledResources; // (0x28)
+ UCHAR SystemRev[4]; // (0x2c) Same as FRU System Revision Level?
+} RAWHIDE_CUD_HEADER, *PRAWHIDE_CUD_HEADER;
+
+
+
+//
+// IOD Error Frame Valid Bits
+//
+// Corresponds to bitfields of ValidBits in the Iod Error Frame
+//
+
+typedef union _IOD_ERROR_FRAME_VALID_BITS {
+ struct {
+ ULONG IodBaseAddrValid: 1; // <0>
+ ULONG WhoAmIValid: 1; // <1>
+ ULONG PciRevValid: 1; // <2>
+ ULONG CapCtrlValid: 1; // <3>
+ ULONG HaeMemValid: 1; // <4>
+ ULONG HaeIoValid: 1; // <5>
+ ULONG IntCtrlValid: 1; // <6>
+ ULONG IntReqValid: 1; // <7>
+ ULONG IntMask0Valid: 1; // <8>
+ ULONG IntMask1Valid: 1; // <9>
+ ULONG McErr0Valid: 1; // <10>
+ ULONG McErr1Valid: 1; // <11>
+ ULONG CapErrValid: 1; // <12>
+ ULONG PciErr1Valid: 1; // <13>
+ ULONG MdpaStatValid: 1; // <14>
+ ULONG MdpaSynValid: 1; // <15>
+ ULONG MdpbStatValid: 1; // <16>
+ ULONG MdpbSynValid: 1; // <17>
+ };
+ ULONG all;
+} IOD_ERROR_FRAME_VALID_BITS, *PIOD_ERROR_FRAME_VALID_BITS;
+
+//
+// IOD Error Frame
+//
+// N.B. Used in Uncorrectable *and* correctable error frames for
+// information on the IOD that recevied the machine check.
+// It is uses as well in MC Bus snapshot (for each IOD) and Iod Register
+// Subpacket.
+// As far as I'm concerned, they IOD information is the same in each case.
+// We can use the ValidBits field to optionally disable irrelevant
+// fields.
+//
+
+typedef struct _IOD_ERROR_FRAME {
+ ULONGLONG BaseAddress; // (0x00)
+ ULONG WhoAmI; // (0x08)
+ IOD_ERROR_FRAME_VALID_BITS ValidBits; // (0x0c)
+ ULONG PciRevision; // (0x10)
+ ULONG CapCtrl; // (0x14)
+ ULONG HaeMem; // (0x18)
+ ULONG HaeIo; // (0x1c)
+ ULONG IntCtrl; // (0x20)
+ ULONG IntReq; // (0x24)
+ ULONG IntMask0; // (0x28)
+ ULONG IntMask1; // (0x2c)
+ ULONG McErr0; // (0x30)
+ ULONG McErr1; // (0x34)
+ ULONG CapErr; // (0x38)
+ ULONG Reserved0; // (0x3c)
+ ULONG PciErr1; // (0x40)
+ ULONG MdpaStat; // (0x44)
+ ULONG MdpaSyn; // (0x48)
+ ULONG MdpbStat; // (0x4c)
+ ULONG MdpbSyn; // (0x50)
+ ULONG Reserved1[3]; // (0x54-0x5f)
+} IOD_ERROR_FRAME, *PIOD_ERROR_FRAME;
+
+
+//
+// Optional Snapshots for which headers or frames are defined below:
+// PCI Bus Snapshot
+// MC Bus Snapshot
+// Memory Size Frame
+// System Managment Frame
+// ESC Frame
+//
+
+//
+// Flags indicating which of the optional snapshots or frames are present
+// in a correctable or uncorrectable error frame
+//
+
+typedef union _RAWHIDE_ERROR_SUBPACKET_FLAGS {
+ struct {
+ ULONGLONG Reserved0: 10; // <0:9> Reserved
+ ULONGLONG SysEnvPresent : 1; // <10>
+ ULONGLONG MemSizePreset : 1; // <11>
+ ULONGLONG Reserved1: 8; // <12:19> Reserved
+ ULONGLONG McBusPresent: 1; // <20>
+ ULONGLONG GcdBusPresent: 1; // <21>
+ ULONGLONG Reserved2: 8; // <22:29> Reserved
+ ULONGLONG IodSubpacketPresent: 1; // <30>
+ ULONGLONG PciSnapshotPresent: 1; // <31>
+ ULONGLONG EscSubpacketPresent: 1; // <32>
+ ULONGLONG Reserved3: 7; // <33:39> Reserved
+ ULONGLONG Iod2SubpacketPresent: 1; // <40> ???
+ ULONGLONG Pci2SnapshotPresent: 1; // <41> ???
+ };
+ ULONGLONG all;
+} RAWHIDE_ERROR_SUBPACKET_FLAGS, *PRAWHIDE_ERROR_SUBPACKET_FLAGS;
+
+
+//
+// PCI Bus Snapshot Header
+//
+// Header is followed PCI_COMMON_CONFIG packets (256 bytes each) for each PCI
+// device present in the system. Therefore,
+// Length = sizeof (PCI_BUS_SNAPSHOT) + NumberOfNodes*sizeof(PCI_COMMON_CONFIG)
+//
+// N.B. PCI_COMMON_CONFIG is defined \nt\private\ntos\inc\pci.h
+//
+
+
+typedef struct _PCI_BUS_SNAPSHOT {
+ ULONG Length; // (0x00)
+ USHORT BusNumber; // (0x04)
+ USHORT NumberOfNodes; // (0x06)
+ //
+ // NumberOfNodes packets follow (0x08)
+ //
+} PCI_BUS_SNAPSHOT, *PPCI_BUS_SNAPSHOT;
+
+
+
+//
+// MC Bus Snapshot Header
+//
+// Header is followed a IOD_ERROR_FRAME for each IOD on the system;
+// Therefore,
+// Length = sizeof (MC_BUS_SNAPSHOT) + NumberOfIods*sizeof(IOD_ERROR_FRAME)
+//
+
+typedef struct _MC_BUS_SNAPSHOT {
+ ULONG Length; // (0x00)
+ ULONG NumberOfIods; // (0x04)
+ ULONGLONG ReportingCpuBaseAddr; // (0x08)
+
+ //
+ // NumberOfIods packets follow (0x10)
+ //
+
+} MC_BUS_SNAPSHOT, *PMC_BUS_SNAPSHOT;
+
+
+//
+// Memory Size Frame
+//
+
+typedef union _RAWHIDE_MEMORY_SIZE {
+ struct {
+ ULONGLONG MemorySize0: 8; // <0:7>
+ ULONGLONG MemorySize1: 8; // <8:15>
+ ULONGLONG MemorySize2: 8; // <16:23>
+ ULONGLONG MemorySize3: 8; // <24:31>
+ ULONGLONG Reserved: 24; // <32:55>
+ ULONGLONG MemorySize0Valid: 1; // <56>
+ ULONGLONG MemorySize1Valid: 1; // <57>
+ ULONGLONG MemorySize2Valid: 1; // <58>
+ ULONGLONG MemorySize3Valid: 1; // <59>
+ };
+ ULONGLONG all;
+} RAWHIDE_MEMORY_SIZE, *PRAWHIDE_MEMORY_SIZE;
+
+
+//
+// System Managment Frame
+//
+
+typedef struct _RAWHIDE_SYSTEM_MANAGEMENT_FRAME {
+ ULONGLONG SystemEnvironment; // (0x00)
+ ULONG Elcr2; // (0x08) (see IOD_ELCR2 in iod.h)
+ ULONG Reserved0; // (0x0c)
+} SYSTEM_MANAGEMENT_FRAME, *PSYSTEM_MANAGEMENT_FRAME;
+
+typedef union _RAWHIDE_SYSTEM_ENVIRONMENT {
+ struct {
+ ULONGLONG FanFailReg: 8; // <0:7> I2C Fain Fail Register
+ ULONGLONG SensorReg1: 8; // <8:15> I2C Sensor Register 1
+ ULONGLONG OpcControl: 8; // <16:23> I2C OPC Control
+ ULONGLONG SensorReg2: 8; // <24:31> I2C Sensor Register 2
+ ULONGLONG Reserved: 24; // <32:55> I2C Sensor Register 1
+ ULONGLONG FanFailValid: 1; // <56>
+ ULONGLONG SensorReg1Valid: 1; // <57>
+ ULONGLONG OpcControlValid: 1; // <58>
+ ULONGLONG SensorReg2Valid: 1; // <59>
+ };
+ ULONGLONG all;
+} RAWHIDE_SYSTEM_ENVIRONMENT, *PRAWHIDE_SYSTEM_ENVIRONMENT;
+
+
+//
+// ESC Frame
+//
+// This isn't just and ESC frame. EISA Id information is also contained herein.
+//
+// N.B. "index" refers to an indexed config ESC register accessed at index/data
+// ports 0x22/0x23.
+//
+
+
+typedef struct _ESC_FRAME {
+ UCHAR Id[4]; // (0x00) "ESC\0"
+ ULONG ByteCount; // (0x04) ???
+ UCHAR EscId; // (0x08) ESC ID Register (index 0x02)
+ UCHAR Filler0[7]; // (0x09-0x0f)
+ UCHAR Rid; // (0x0c) Revision Id (index 0x08)
+ UCHAR Filler1[3]; // (0x0d-0x0f)
+ UCHAR ModeSel; // (0x10) Mode Select Reg (index 0x40)
+ UCHAR Filler2[3]; // (0x11-0x13)
+ UCHAR EisaId[4]; // (0x14-0x17) EisaId of devices in EISA Slots
+ UCHAR SgRba; // (0x18) S-G Reloate Base Addr Reg (index 57)
+ UCHAR Filler3[3]; // (0x19-0x1b)
+ UCHAR Pirq[4]; // (0x1c-0x1f) PIRQ Route Ctrl (index 0x60-0x63)
+ UCHAR NmiSc; // (0x20) NMI Status & Ctrl (port 0x61)
+ UCHAR Filler4[3]; // (0x21-0x23)
+ UCHAR NmiEsc; // (0x24) NMI Ext. Status & Ctrl (port 0x461)
+ UCHAR Filler5[3]; // (0x25-0x27)
+ UCHAR LEisaMg; // (0x28) Last EISA Master Granted (port 0x464)
+ UCHAR Filler6[3]; // (0x29-0x2b)
+} ESC_FRAME, *PESC_FRAME;
+
+
+//
+// Rawhide Correctable (Soft) Error Frame
+// Rawhide Uncorrectable (Hard) Error Frame
+//
+
+#define RAWHIDE_UNCORRECTABLE_FRAME_REVISION 0x10 // V1.0
+#define RAWHIDE_CORRECTABLE_FRAME_REVISION 0x10 // V1.0
+
+typedef struct _RAWHIDE_UNCORRECTABLE_FRAME {
+ ULONG Revision; // (0x00)
+ ULONG WhoAmI; // (0x04)
+ RAWHIDE_ERROR_SUBPACKET_FLAGS ErrorSubpacketFlags; // (0x08)
+ RAWHIDE_CUD_HEADER CudHeader; // (0x10-0x4f)
+ MC_BUS_SNAPSHOT McBusSnapshot; // (0x50-0x5f)
+
+ //
+ // Uncorrectable Error Frame will have:
+ // a) two (Dodge) or four (Durango) IOD_ERROR_FRAMEs (0x60 - ???)
+ //
+ // b) Optional Error Subpackets as per ErrorSubpacketFlags
+ //
+
+} RAWHIDE_UNCORRECTABLE_FRAME, *PRAWHIDE_UNCORRECTABLE_FRAME;
+
+typedef struct _RAWHIDE_CORRECTABLE_FRAME {
+ ULONG Revision; // (0x00)
+ ULONG WhoAmI; // (0x04)
+ RAWHIDE_ERROR_SUBPACKET_FLAGS ErrorSubpacketFlags; // (0x08)
+ RAWHIDE_CUD_HEADER CudHeader; // (0x10-0x4f)
+ IOD_ERROR_FRAME IodErrorFrame; // (0x50-0xaf)
+
+ //
+ // Correctable Error will always have only
+ // one IOD in the McBusSnapshot, that of the IOD with
+ // the correctable error.
+ //
+
+} RAWHIDE_CORRECTABLE_FRAME, *PRAWHIDE_CORRECTABLE_FRAME;
+
+
+#endif //ERRPLAT_H
diff --git a/private/ntos/nthals/halalpha/ev4cache.c b/private/ntos/nthals/halalpha/ev4cache.c
new file mode 100644
index 000000000..506dd581f
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ev4cache.c
@@ -0,0 +1,488 @@
+/*++
+
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ ev4cache.c
+
+Abstract:
+
+ This file contains the routines for managing the caches on machines
+ based on the DECchip 21064 microprocessor.
+
+ EV4 has primary I and D caches of 8KB each, both write-through.
+ Any systems based on EV4 are expected to have an external backup cache
+ which is write-back, but it is also coherent with all DMA operations. The
+ primary caches are shadowed by the backup, and on a write hit, the
+ primary data (but not instruction) cache is invalidated.
+ Consequently, the routines to flush,sweep,purge,etc the data
+ stream are nops on EV4, but the corresponding routines for the
+ Istream must ensure that we cannot hit in the primary I cache
+ after a DMA operation.
+
+ EV4 has a write buffer which contains 4 32-byte entries, which
+ must be flushable before DMA operations. The MB instruction is
+ used to accomplish this.
+
+ There is no coloring support on EV4, so Color operations are
+ null. Zero page is unsupported because it has no users. Copy
+ page is not special because we lack coloring.
+
+ We had to make a philosophical decision about what interfaces to
+ support in this file. (Almost) none of the interfaces defined in
+ the HAL spec are actually supported in either the i386 or MIPS
+ code. The i386 stream has almost no cache support at all. The
+ Mips stream has cache support, but most routines also refer to
+ coloring. Should we use the Spec'ed interfaces, or the Mips
+ interfaces? I have elected the Mips interfaces because they are
+ in use, and we are stealing much of the Mips code which expects
+ these interfaces. Besides, the only change we might make is to
+ remove the coloring arguments, but they may be used on Alpha
+ machines at some future date.
+
+Author:
+
+ Miche Baker-Harvey (miche) 29-May-1992
+
+Revision History:
+
+
+ 13-Jul-1992 Jeff McLeman (mcleman)
+ use HalpMb to do a memory barrier. Also, alter code and use super
+ pages to pass to rtl memory routines.
+
+ 10-Jul-1992 Jeff McLeman (mcleman)
+ use HalpImb to call pal.
+
+ 06-Jul-1992 Jeff McLeman (mcleman)
+ Move routine KeFlushDcache into this module.
+ Use only one memory barrier in the KeFlushWriteBuffer
+ routine. This is because the PAL for the EVx will
+ make sure the proper write ordering is done in PAL mode.
+
+--*/
+ // Include files
+
+#include "halp.h"
+
+
+
+VOID
+HalFlushDcache (
+ IN BOOLEAN AllProcessors
+ );
+
+//
+// Cache and write buffer flush functions.
+//
+
+
+VOID
+HalChangeColorPage (
+ IN PVOID NewColor,
+ IN PVOID OldColor,
+ IN ULONG PageFrame
+ )
+/*++
+
+Routine Description:
+
+ This function changes the color of a page if the old and new colors
+ do not match. DECchip 21064-based machines do not have page coloring, and
+ therefore, this function performs no operation.
+
+Arguments:
+
+ NewColor - Supplies the page aligned virtual address of the
+ new color of the page to change.
+
+ OldColor - Supplies the page aligned virtual address of the
+ old color of the page to change.
+
+ pageFrame - Supplies the page frame number of the page that
+ is changed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+VOID
+HalFlushDcachePage (
+ IN PVOID Color,
+ IN ULONG PageFrame,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function flushes (invalidates) up to a page of data from the
+ data cache.
+
+Arguments:
+
+ Color - Supplies the starting virtual address and color of the
+ data that is flushed.
+ PageFrame - Supplies the page frame number of the page that
+ is flushed.
+
+ Length - Supplies the length of the region in the page that is
+ flushed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+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.
+
+--*/
+{
+ //
+ // The Dcache coherency is maintained in hardware. The Icache coherency
+ // is maintained by invalidating the istream on page read operations.
+ //
+ HalpMb(); // synchronize this processors view of memory
+ if (ReadOperation) {
+ HalpMb(); // not issued until previous mb completes
+ if (Mdl->MdlFlags & MDL_IO_PAGE_READ) {
+
+ //
+ // The operation is a page read, thus the istream must
+ // be flushed.
+ //
+ HalpImb();
+ }
+ }
+}
+
+VOID
+HalPurgeDcachePage (
+ IN PVOID Color,
+ IN ULONG PageFrame,
+ IN ULONG Length
+ )
+/*++
+Routine Description:
+
+ This function purges (invalidates) up to a page of data from the
+ data cache.
+
+Arguments:
+
+ Color - Supplies the starting virtual address and color of the
+ data that is purged.
+
+ PageFrame - Supplies the page frame number of the page that
+ is purged.
+
+ Length - Supplies the length of the region in the page that is
+ purged.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+
+VOID
+HalPurgeIcachePage (
+ IN PVOID Color,
+ IN ULONG PageFrame,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function purges (invalidates) up to a page fo data from the
+ instruction cache.
+
+Arguments:
+
+ Color - Supplies the starting virtual address and color of the
+ data that is purged.
+
+ PageFrame - Supplies the page frame number of the page that
+ is purged.
+
+ Length - Supplies the length of the region in the page that is
+ purged.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The call to HalpImb calls PAL to flush the Icache, which ensures that
+ // any stale hits will be invalidated
+ //
+ HalpImb;
+}
+
+VOID
+HalSweepDcache (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function sweeps (invalidates) the entire data cache.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+VOID
+HalSweepDcacheRange (
+ IN PVOID BaseAddress,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function flushes the specified range of addresses from the data
+ cache on the current processor.
+
+Arguments:
+
+ BaseAddress - Supplies the starting physical address of a range of
+ physical addresses that are to be flushed from the data cache.
+
+ Length - Supplies the length of the range of physical addresses
+ that are to be flushed from the data cache.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+VOID
+HalSweepIcache (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function sweeps (invalidates) the entire instruction cache.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The call to HalpImb calls PAL to flush the Icache, which ensures that
+ // any stale hits will be invalidated
+ //
+ HalpImb;
+ return;
+}
+
+VOID
+HalSweepIcacheRange (
+ IN PVOID BaseAddress,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function flushes the specified range of addresses from the
+ instruction cache on the current processor.
+
+Arguments:
+
+ BaseAddress - Supplies the starting physical address of a range of
+ physical addresses that are to be flushed from the instruction cache.
+
+ Length - Supplies the length of the range of physical addresses
+ that are to be flushed from the instruction cache.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The call to HalpImb calls PAL to flush the Icache, which ensures that
+ // any stale hits will be invalidated
+ //
+ HalpImb;
+
+}
+
+VOID
+KeFlushWriteBuffer (
+ VOID
+ )
+
+{
+ //
+ // We flush the write buffer by doing a series of memory
+ // barrier operations. It still isn't clear if we need
+ // to do two/four of them to flush the buffer, or if one
+ // to order the writes is suffcient
+ //
+
+ HalpMb;
+ return;
+}
+
+VOID
+KeFlushDcache (
+ IN BOOLEAN AllProcessors,
+ IN PVOID BaseAddress OPTIONAL,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This function flushes the data cache on all processors that are currently
+ running threads which are children of the current process or flushes the
+ data cache on all processors in the host configuration.
+
+Arguments:
+
+ AllProcessors - Supplies a boolean value that determines which data
+ caches are flushed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(BaseAddress);
+ UNREFERENCED_PARAMETER(Length);
+
+ HalFlushDcache(AllProcessors);
+ return;
+}
+
+VOID
+HalFlushDcache (
+ IN BOOLEAN AllProcessors
+ )
+
+/*++
+
+Routine Description:
+
+ This function flushes the data cache on all processors that are currently
+ running threads which are children of the current process or flushes the
+ data cache on all processors in the host configuration.
+
+Arguments:
+
+ AllProcessors - Supplies a boolean value that determines which data
+ caches are flushed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Sweep (index/writeback/invalidate) the data cache.
+ //
+
+ HalSweepDcache();
+ return;
+}
+
+ULONG
+HalGetDmaAlignmentRequirement (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the alignment requirements for DMA transfers on
+ host system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The DMA alignment requirement is returned as the fucntion value.
+
+--*/
+
+{
+
+ return 8;
+}
diff --git a/private/ntos/nthals/halalpha/ev4int.c b/private/ntos/nthals/halalpha/ev4int.c
new file mode 100644
index 000000000..71a4c9dd1
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ev4int.c
@@ -0,0 +1,1013 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ ev4int.c
+
+Abstract:
+
+ This module implements the support routines to enable/disable DECchip
+ 21064-specific interrupts.
+
+Author:
+
+ Joe Notarangelo 27-Sep-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "axp21064.h"
+
+VOID
+HalpUpdate21064PriorityTable(
+ VOID
+ );
+
+VOID
+HalpCachePcrValues(
+ VOID
+ );
+
+
+
+VOID
+HalpInitialize21064Interrupts(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the data structures for the 21064
+ interrupt enable/disable routines.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Index;
+ EV4Irq Irq;
+
+ //
+ // Initialize each entry in the Irq Status Table.
+ //
+
+ for( Irq=Irq0; Irq<MaximumIrq; Irq++ ){
+ HAL_PCR->IrqStatusTable[Irq].Enabled = FALSE;
+ HAL_PCR->IrqStatusTable[Irq].Irql = PASSIVE_LEVEL;
+ HAL_PCR->IrqStatusTable[Irq].Vector = PASSIVE_VECTOR;
+ HAL_PCR->IrqStatusTable[Irq].Priority = 0;
+ }
+
+ HalpUpdate21064PriorityTable();
+
+ //
+ // Write IrqlMask table entries for the Software Subtable.
+ //
+
+ Index = IRQLMASK_SFW_SUBTABLE_21064;
+
+ PCR->IrqlMask[Index].IrqlTableIndex = PASSIVE_LEVEL;
+ PCR->IrqlMask[Index].IDTIndex = PASSIVE_VECTOR;
+ Index += 1;
+
+ PCR->IrqlMask[Index].IrqlTableIndex = APC_LEVEL;
+ PCR->IrqlMask[Index].IDTIndex = APC_VECTOR;
+ Index += 1;
+
+ PCR->IrqlMask[Index].IrqlTableIndex = DISPATCH_LEVEL;
+ PCR->IrqlMask[Index].IDTIndex = DISPATCH_VECTOR;
+ Index += 1;
+
+ PCR->IrqlMask[Index].IrqlTableIndex = DISPATCH_LEVEL;
+ PCR->IrqlMask[Index].IDTIndex = DISPATCH_VECTOR;
+
+ //
+ // Write the IrqlMask table entries for the Performance Counter Subtable.
+ //
+
+ Index = IRQLMASK_PC_SUBTABLE_21064;
+
+ PCR->IrqlMask[Index].IrqlTableIndex = PASSIVE_LEVEL;
+ PCR->IrqlMask[Index].IDTIndex = PASSIVE_VECTOR;
+ Index += 1;
+
+ PCR->IrqlMask[Index].IrqlTableIndex = PROFILE_LEVEL;
+ PCR->IrqlMask[Index].IDTIndex = PC0_VECTOR;
+ Index += 1;
+
+ PCR->IrqlMask[Index].IrqlTableIndex = PROFILE_LEVEL;
+ PCR->IrqlMask[Index].IDTIndex = PC1_VECTOR;
+ Index += 1;
+
+ PCR->IrqlMask[Index].IrqlTableIndex = PROFILE_LEVEL;
+ PCR->IrqlMask[Index].IDTIndex = PC1_VECTOR;
+
+ return;
+
+}
+
+VOID
+HalpUpdate21064PriorityTable(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function updates the Irql Mask Table in the PCR of the current
+ processor. It is called whenever an interrupt is enabled or disabled.
+ The source of the data used to update the table is the global
+ IrqStatusTable.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG InterruptMask;
+ EV4Irq Irq;
+ KIRQL Irql;
+ ULONG IrqlMaskIndex;
+ UCHAR Priority;
+ ULONG Vector;
+
+ //
+ // Cycle through each entry of the interrupt mask table for the
+ // hardware entries. For each entry, compute the highest priority
+ // entry that could be asserted for the mask entry and is enabled.
+ // The priority is determined first by Irql level, higher Irql
+ // indicates higher priority, and then, if there are multiple
+ // enabled, asserted interrupts of the same Irql, by a relative
+ // priority that was assigned by the caller when the interrupt
+ // was enabled.
+ //
+
+ for( InterruptMask=0;
+ InterruptMask < IRQLMASK_HDW_SUBTABLE_21064_ENTRIES;
+ InterruptMask++ ){
+
+ Vector = PASSIVE_VECTOR;
+ Irql = PASSIVE_LEVEL;
+ Priority = 0;
+
+ //
+ // Check if each Irq is asserted and enabled for this interrupt
+ // mask.
+ //
+
+ for( Irq=Irq0; Irq<MaximumIrq; Irq++ ){
+ ULONG IrqMask = 1 << Irq;
+
+ if( (IrqMask & InterruptMask) &&
+ (HAL_PCR->IrqStatusTable[Irq].Enabled == TRUE) &&
+ (HAL_PCR->IrqStatusTable[Irq].Irql >= Irql) ){
+
+ //
+ // If the new Irq has a higher Irql than the highest
+ // currently selected or has a higher relative priority
+ // then this is the Irq to be selected if this mask
+ // pattern is selected.
+ //
+
+ if( (HAL_PCR->IrqStatusTable[Irq].Irql > Irql) ||
+ (HAL_PCR->IrqStatusTable[Irq].Priority > Priority) ){
+
+ Irql = HAL_PCR->IrqStatusTable[Irq].Irql;
+ Priority = HAL_PCR->IrqStatusTable[Irq].Priority;
+ Vector = HAL_PCR->IrqStatusTable[Irq].Vector;
+
+ }
+
+ }
+ }
+
+ IrqlMaskIndex = IRQLMASK_HDW_SUBTABLE_21064 + InterruptMask;
+ PCR->IrqlMask[IrqlMaskIndex].IrqlTableIndex = Irql;
+ PCR->IrqlMask[IrqlMaskIndex].IDTIndex = (USHORT)Vector;
+ }
+}
+
+VOID
+HalpDisable21064HardwareInterrupt(
+ IN ULONG Irq
+ )
+/*++
+
+Routine Description:
+
+ This routine disables the interrupt connected to the specified Irq
+ pin on the 21064.
+
+Arguments:
+
+ Irq - Supplies the number of the Irq pin for the interrupt that is disabled.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ KIRQL IrqlIndex;
+ PIETEntry_21064 IetEntry;
+ KIRQL OldIrql;
+
+ //
+ // Raise IRQL to the highest level.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+ IetEntry = (PIETEntry_21064)(&PCR->IrqlTable);
+ IrqlIndex = PASSIVE_LEVEL;
+
+ //
+ // Update the enable table for all the Irqls such that the interrupt
+ // is disabled.
+ //
+
+ while( IrqlIndex <= HIGH_LEVEL ){
+
+ switch( Irq ){
+
+ case Irq0:
+
+ IetEntry[IrqlIndex].Irq0Enable = 0;
+ break;
+
+ case Irq1:
+
+ IetEntry[IrqlIndex].Irq1Enable = 0;
+ break;
+
+ case Irq2:
+
+ IetEntry[IrqlIndex].Irq2Enable = 0;
+ break;
+
+ case Irq3:
+
+ IetEntry[IrqlIndex].Irq3Enable = 0;
+ break;
+
+ case Irq4:
+
+ IetEntry[IrqlIndex].Irq4Enable = 0;
+ break;
+
+ case Irq5:
+
+ IetEntry[IrqlIndex].Irq5Enable = 0;
+ break;
+
+
+ } //end switch( Irq )
+
+ IrqlIndex++;
+
+ } //end while IrqlIndex <= HIGH_LEVEL
+
+ //
+ // Update the Irq status table and reflect the changes in the
+ // PCR IrqlMask table.
+ //
+
+ HAL_PCR->IrqStatusTable[Irq].Enabled = FALSE;
+
+ //
+ // Alert the PAL that the enable table has changed so that it can
+ // reload the new values.
+ //
+
+ HalpCachePcrValues();
+
+ //
+ // Lower IRQL to the previous level.
+ //
+
+ KeLowerIrql(OldIrql);
+ return;
+
+}
+
+
+VOID
+HalpDisable21064SoftwareInterrupt(
+ IN KIRQL Irql
+ )
+/*++
+
+Routine Description:
+
+ This routine disables the indicated software interrupt level.
+
+Arguments:
+
+ Irql - Supplies the software interrupt level to disable (APC_LEVEL or
+ DISPATCH_LEVEL).
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PIETEntry_21064 IetEntry;
+ KIRQL OldIrql;
+
+ //
+ // Raise IRQL to the highest level.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+ IetEntry = (PIETEntry_21064)(&PCR->IrqlTable);
+
+ switch( Irql ){
+
+ //
+ // APC Interrupt level.
+ //
+
+ case APC_LEVEL:
+
+ IetEntry[PASSIVE_LEVEL].ApcEnable = 0;
+ break;
+
+ //
+ // DPC Interrupt level.
+ //
+
+ case DISPATCH_LEVEL:
+
+ IetEntry[PASSIVE_LEVEL].DispatchEnable = 0;
+ IetEntry[APC_LEVEL].DispatchEnable = 0;
+ break;
+
+ //
+ // Unrecognized software interrupt level.
+ //
+
+ default:
+
+ NOTHING;
+
+#if HALDBG
+
+ DbgPrint( "HalpDisable21064SoftwareInterrupt, Bad software level= %x\n",
+ Irql );
+
+#endif //HALDBG
+
+ }
+
+ //
+ // Alert the PAL that the enable table has changed so that it can
+ // reload the new values.
+ //
+
+ HalpCachePcrValues();
+
+ //
+ // Lower IRQL to the previous level.
+ //
+
+ KeLowerIrql(OldIrql);
+ return;
+}
+
+
+VOID
+HalpDisable21064PerformanceInterrupt(
+ IN ULONG Vector
+ )
+/*++
+
+Routine Description:
+
+ This routine disables the specified performance counter interrupt.
+
+Arguments:
+
+ Vector - Supplies the interrupt vector number of the performance counter
+ interrupt which is disabled.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ KIRQL IrqlIndex;
+ PIETEntry_21064 IetEntry;
+ KIRQL OldIrql;
+
+ //
+ // Raise IRQL to the highest level.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+ IetEntry = (PIETEntry_21064)(&PCR->IrqlTable);
+ IrqlIndex = PASSIVE_LEVEL;
+
+ //
+ // Update the enable table for all the Irqls such that the interrupt
+ // is disabled.
+ //
+
+ while( IrqlIndex <= HIGH_LEVEL ){
+
+ switch( Vector ){
+
+ case PC0_VECTOR:
+ case PC0_SECONDARY_VECTOR:
+
+ IetEntry[IrqlIndex].PerformanceCounter0Enable = 0;
+ break;
+
+ case PC1_VECTOR:
+ case PC1_SECONDARY_VECTOR:
+
+ IetEntry[IrqlIndex].PerformanceCounter1Enable = 0;
+ break;
+
+
+ } //end switch( Vector )
+
+ IrqlIndex++;
+
+ } //end while IrqlIndex <= HIGH_LEVEL
+
+ //
+ // Alert the PAL that the enable table has changed so that it can
+ // reload the new values.
+ //
+
+ HalpCachePcrValues();
+
+ //
+ // Lower IRQL to the previous level.
+ //
+
+ KeLowerIrql(OldIrql);
+ return;
+}
+
+VOID
+HalpDisable21064CorrectableInterrupt(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine disables the correctable read error interrupt.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ KIRQL IrqlIndex;
+ PIETEntry_21064 IetEntry;
+ KIRQL OldIrql;
+
+ //
+ // Raise IRQL to the highest level.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+ IetEntry = (PIETEntry_21064)(&PCR->IrqlTable);
+ IrqlIndex = PASSIVE_LEVEL;
+
+ //
+ // Update the enable table for all the Irqls such that the interrupt
+ // is disabled.
+ //
+
+ while( IrqlIndex <= HIGH_LEVEL ){
+
+ IetEntry[IrqlIndex].CorrectableReadEnable = 0;
+
+ IrqlIndex++;
+
+ } //end while IrqlIndex <= HIGH_LEVEL
+
+ //
+ // Alert the PAL that the enable table has changed so that it can
+ // reload the new values.
+ //
+
+ HalpCachePcrValues();
+
+ //
+ // Lower IRQL to the previous level.
+ //
+
+ KeLowerIrql(OldIrql);
+ return;
+}
+
+VOID
+HalpEnable21064HardwareInterrupt (
+ IN ULONG Irq,
+ IN KIRQL Irql,
+ IN ULONG Vector,
+ IN UCHAR Priority
+ )
+
+/*++
+
+Routine Description:
+
+ This routine enables the specified system interrupt.
+
+Arguments:
+
+ Irq - Supplies the IRQ pin number of the interrupt that is enabled.
+
+ Irql - Supplies the Irql of the interrupting source.
+
+ Vector - Supplies the interrupt vector for the enabled interrupt.
+
+ Priority - Supplies the relative priority of the interrupt in comparison
+ with other Irqs of the same Irql.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ KIRQL IrqlIndex;
+ PIETEntry_21064 IetEntry;
+ KIRQL OldIrql;
+
+ //
+ // Raise IRQL to the highest level.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+
+ IetEntry = (PIETEntry_21064)(&PCR->IrqlTable);
+ IrqlIndex = PASSIVE_LEVEL;
+
+ //
+ // Update the enable table for each Irql that the interrupt should
+ // be enabled.
+ //
+
+ while( IrqlIndex < Irql ){
+
+ switch( Irq ){
+
+ case Irq0:
+
+ IetEntry[IrqlIndex].Irq0Enable = 1;
+ break;
+
+ case Irq1:
+
+ IetEntry[IrqlIndex].Irq1Enable = 1;
+ break;
+
+ case Irq2:
+
+ IetEntry[IrqlIndex].Irq2Enable = 1;
+ break;
+
+ case Irq3:
+
+ IetEntry[IrqlIndex].Irq3Enable = 1;
+ break;
+
+ case Irq4:
+
+ IetEntry[IrqlIndex].Irq4Enable = 1;
+ break;
+
+ case Irq5:
+
+ IetEntry[IrqlIndex].Irq5Enable = 1;
+ break;
+
+ } // end switch( Vector )
+
+ IrqlIndex++;
+
+ } //end while IrqlIndex < Irql
+
+ //
+ // Populate the interrupt status table and then update the Irql Mask
+ // table.
+ //
+
+ HAL_PCR->IrqStatusTable[Irq].Enabled = TRUE;
+ HAL_PCR->IrqStatusTable[Irq].Vector = Vector;
+ HAL_PCR->IrqStatusTable[Irq].Irql = Irql;
+ HAL_PCR->IrqStatusTable[Irq].Priority = Priority;
+
+ HalpUpdate21064PriorityTable();
+
+ //
+ // Alert the PAL that the enable table has changed so that it can
+ // reload the new values.
+ //
+
+ HalpCachePcrValues();
+
+ //
+ // Lower IRQL to the previous level.
+ //
+
+ KeLowerIrql(OldIrql);
+ return;
+}
+
+
+VOID
+HalpEnable21064SoftwareInterrupt(
+ IN KIRQL Irql
+ )
+/*++
+
+Routine Description:
+
+ This routine enables the indicated software interrupt level.
+
+Arguments:
+
+ Irql - Supplies the software interrupt level to enable (APC_LEVEL or
+ DISPATCH_LEVEL).
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PIETEntry_21064 IetEntry;
+ KIRQL OldIrql;
+
+ //
+ // Raise IRQL to the highest level.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+ IetEntry = (PIETEntry_21064)(&PCR->IrqlTable);
+
+ switch( Irql ){
+
+ //
+ // APC Interrupt level.
+ //
+
+ case APC_LEVEL:
+
+ IetEntry[PASSIVE_LEVEL].ApcEnable = 1;
+ break;
+
+ //
+ // DPC Interrupt level.
+ //
+
+ case DISPATCH_LEVEL:
+
+ IetEntry[PASSIVE_LEVEL].DispatchEnable = 1;
+ IetEntry[APC_LEVEL].DispatchEnable = 1;
+ break;
+
+ //
+ // Unrecognized software interrupt level.
+ //
+
+ default:
+
+ NOTHING;
+
+#if HALDBG
+
+ DbgPrint( "HalpEnable21064SoftwareInterrupt, Bad software level= %x\n",
+ Irql );
+
+#endif //HALDBG
+
+ }
+
+ //
+ // Alert the PAL that the enable table has changed so that it can
+ // reload the new values.
+ //
+
+ HalpCachePcrValues();
+
+ //
+ // Lower IRQL to the previous level.
+ //
+
+ KeLowerIrql(OldIrql);
+ return;
+
+}
+
+
+VOID
+HalpEnable21064PerformanceInterrupt (
+ IN ULONG Vector,
+ IN KIRQL Irql
+ )
+
+/*++
+
+Routine Description:
+
+ This routine enables the specified performance counter interrupt.
+
+Arguments:
+
+ Vector - Supplies the vector of the performance counter interrupt that is
+ enabled.
+
+ Irql - Supplies the Irql of the performance counter interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ KIRQL IrqlIndex;
+ PIETEntry_21064 IetEntry;
+ KIRQL OldIrql;
+
+ //
+ // Raise IRQL to the highest level.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+
+ IetEntry = (PIETEntry_21064)(&PCR->IrqlTable);
+ IrqlIndex = PASSIVE_LEVEL;
+
+ //
+ // Update the enable table for each Irql that the interrupt should
+ // be enabled.
+ //
+
+ while( IrqlIndex < Irql ){
+
+ switch( Vector ){
+
+ case PC0_VECTOR:
+ case PC0_SECONDARY_VECTOR:
+
+ IetEntry[IrqlIndex].PerformanceCounter0Enable = 1;
+ break;
+
+ case PC1_VECTOR:
+ case PC1_SECONDARY_VECTOR:
+
+ IetEntry[IrqlIndex].PerformanceCounter1Enable = 1;
+ break;
+
+ } // end switch( Vector )
+
+ IrqlIndex++;
+
+ } //end while IrqlIndex < Irql
+
+ //
+ // Alert the PAL that the enable table has changed so that it can
+ // reload the new values.
+ //
+
+ HalpCachePcrValues();
+
+ //
+ // Lower IRQL to the previous level.
+ //
+
+ KeLowerIrql(OldIrql);
+ return;
+}
+
+VOID
+HalpEnable21064CorrectableInterrupt (
+ IN KIRQL Irql
+ )
+
+/*++
+
+Routine Description:
+
+ This routine enables the correctable read error interrupt.
+
+Arguments:
+
+ Irql - Supplies the Irql of the correctable read error interrupt.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ KIRQL IrqlIndex;
+ PIETEntry_21064 IetEntry;
+ KIRQL OldIrql;
+
+ //
+ // Raise IRQL to the highest level.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+
+ IetEntry = (PIETEntry_21064)(&PCR->IrqlTable);
+ IrqlIndex = PASSIVE_LEVEL;
+
+ //
+ // Update the enable table for each Irql that the interrupt should
+ // be enabled.
+ //
+
+ while( IrqlIndex < Irql ){
+
+ IetEntry[IrqlIndex].CorrectableReadEnable = 1;
+
+ IrqlIndex++;
+
+ } //end while IrqlIndex < Irql
+
+ //
+ // Alert the PAL that the enable table has changed so that it can
+ // reload the new values.
+ //
+
+ HalpCachePcrValues();
+
+ //
+ // Lower IRQL to the previous level.
+ //
+
+ KeLowerIrql(OldIrql);
+ return;
+}
+
+
+ULONG
+HalpGet21064PerformanceVector(
+ IN ULONG BusInterruptLevel,
+ OUT PKIRQL Irql
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the system interrupt vector and IRQL level
+ corresponding to the specified performance counter interrupt.
+
+Arguments:
+
+ BusInterruptLevel - Supplies the performance counter number.
+
+ Irql - Returns the system request priority.
+
+Return Value:
+
+ Returns the system interrupt vector corresponding to the specified device.
+
+--*/
+
+{
+
+ //
+ // Handle the special internal bus defined for the processor itself
+ // and used to control the performance counters in the 21064.
+ //
+
+ *Irql = PROFILE_LEVEL;
+
+ switch( BusInterruptLevel ){
+
+ //
+ // Performance Counter 0
+ //
+
+ case 0:
+
+ return PC0_SECONDARY_VECTOR;
+
+ //
+ // Performance Counter 1
+ //
+
+ case 1:
+
+ return PC1_SECONDARY_VECTOR;
+
+ } //end switch( BusInterruptLevel )
+
+ //
+ // Unrecognized.
+ //
+
+ *Irql = 0;
+ return 0;
+
+}
+
+
+ULONG
+HalpGet21064CorrectableVector(
+ IN ULONG BusInterruptLevel,
+ OUT PKIRQL Irql
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the system interrupt vector and IRQL level
+ corresponding to the specified correctable interrupt.
+
+Arguments:
+
+ BusInterruptLevel - Supplies the performance counter number.
+
+ Irql - Returns the system request priority.
+
+Return Value:
+
+ Returns the system interrupt vector corresponding to the specified device.
+
+--*/
+
+{
+ //
+ // Get the correctable interrupt vector.
+ //
+
+ if (BusInterruptLevel == 5) {
+
+ //
+ // Correctable error interrupt was sucessfully recognized.
+ //
+
+ *Irql = DEVICE_LEVEL;
+ return CORRECTABLE_VECTOR;
+
+
+ } else {
+
+ //
+ // Unrecognized.
+ //
+
+ *Irql = 0;
+ return 0;
+ }
+}
+
diff --git a/private/ntos/nthals/halalpha/ev4ints.s b/private/ntos/nthals/halalpha/ev4ints.s
new file mode 100644
index 000000000..aaa06db87
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ev4ints.s
@@ -0,0 +1,272 @@
+//++
+//
+// Copyright (c) 1994 Microsoft Corporation
+//
+// Module Name:
+//
+// ev4ints.s
+//
+// Abstract:
+//
+// This module implements EV4-specific interrupt handlers.
+// (the performance counters)
+//
+// Author:
+//
+// John Vert (jvert) 15-Nov-1994
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+#include "halalpha.h"
+
+#define PC0_SECONDARY_VECTOR 11
+#define PC1_SECONDARY_VECTOR 13
+#define PcProfileCount0 PcHalReserved+8
+#define PcProfileCount1 PcProfileCount0+4
+#define PcProfileCountReload0 PcProfileCount1+4
+#define PcProfileCountReload1 PcProfileCountReload0+4
+
+ .struct 0
+ .space 8 // reserved for alignment
+PrRa: .space 8 // space for return address
+PrFrameLength: //
+
+ SBTTL("Performance Counter 0 Interrupt")
+//++
+//
+// VOID
+// HalpPerformanceCounter0Interrupt
+// )
+//
+// Routine Description:
+//
+// This function is executed as the result of an interrupt from the
+// internal microprocessor performance counter 0. The interrupt
+// may be used to signal the completion of a profile event.
+// If profiling is current active, the function determines if the
+// profile interval has expired and if so dispatches to the standard
+// system routine to update the system profile time. If profiling
+// is not active then the function performs a secondary dispatch for
+// performance counter 0.
+//
+// Arguments:
+//
+// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for
+// the interrupt.
+//
+// Return Value:
+//
+// TRUE is returned.
+//
+//--
+
+ NESTED_ENTRY(HalpPerformanceCounter0Interrupt, PrFrameLength, zero )
+
+ lda sp, -PrFrameLength(sp) // allocate a stack frame
+ stq ra, PrRa(sp) // save the return address
+
+ PROLOGUE_END //
+
+ call_pal rdpcr // v0 = pcr base address
+
+ ldl t0, PcProfileCount0(v0) // capture the current profile count
+ beq t0, 20f // if eq, profiling not active
+
+//
+// Profiling is active. Decrement the interval count and if it has
+// reached zero then call the kernel profile routine.
+//
+
+ subl t0, 1, t0 // decrement the interval count
+ bne t0, 10f // if ne, interval has not expired
+
+//
+// The profile interval has expired. Reset the profile interval count
+// and process the profile interrupt.
+//
+
+ ldl t0, PcProfileCountReload0(v0) // get the new tick count
+ stl t0, PcProfileCount0(v0) // reset the profile interval count
+
+ ldl a1, HalpProfileSource0
+ bis fp, zero, a0 // pass trap frame pointer
+ ldl t1, __imp_KeProfileInterruptWithSource
+ jsr ra, (t1) // process the profile interrupt
+
+ br zero, 40f // common return
+
+//
+// The profile interval has not expired. Update the decremented count.
+//
+
+10:
+ stl t0, PcProfileCount0(v0) // update profile interval count
+ br zero, 40f // common return
+
+//
+// Profiling is not active. Therefore, this interrupt was caused by
+// a performance counter driver. Deliver a secondary dispatch.
+//
+
+20:
+
+ ldil a0, PC0_SECONDARY_VECTOR // get IDT vector for secondary
+ s4addl a0, v0, a0 // a0 = PCR + IDT index
+ ldl a0, PcInterruptRoutine(a0) // get service routine address
+ jsr ra, (a0) // call interrupt service routine
+
+//
+// Setup for return.
+//
+
+40:
+ ldil v0, TRUE // set return value = TRUE
+ ldq ra, PrRa(sp) // restore return address
+ lda sp, PrFrameLength(sp) // deallocate the stack frame
+ ret zero, (ra) // return
+
+ .end HalpPerformanceCounter0Interrupt
+
+
+ SBTTL("Performance Counter 1 Interrupt")
+//++
+//
+// VOID
+// HalpPerformanceCounter1Interrupt
+// )
+//
+// Routine Description:
+//
+// This function is executed as the result of an interrupt from the
+// internal microprocessor performance counter 1. The interrupt
+// may be used to signal the completion of a profile event.
+// If profiling is current active, the function determines if the
+// profile interval has expired and if so dispatches to the standard
+// system routine to update the system profile time. If profiling
+// is not active then the function performs a secondary dispatch for
+// performance counter 1.
+//
+// Arguments:
+//
+// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for
+// the interrupt.
+//
+// Return Value:
+//
+// TRUE is returned.
+//
+//--
+
+ NESTED_ENTRY(HalpPerformanceCounter1Interrupt, PrFrameLength, zero )
+
+ lda sp, -PrFrameLength(sp) // allocate a stack frame
+ stq ra, PrRa(sp) // save the return address
+
+ PROLOGUE_END //
+
+ call_pal rdpcr // v0 = pcr base address
+
+ ldl t0, PcProfileCount1(v0) // capture the current profile count
+ beq t0, 20f // if eq, profiling not active
+
+//
+// Profiling is active. Decrement the interval count and if it has
+// reached zero then call the kernel profile routine.
+//
+
+ subl t0, 1, t0 // decrement the interval count
+ bne t0, 10f // if ne, interval has not expired
+
+//
+// The profile interval has expired. Reset the profile interval count
+// and process the profile interrupt.
+//
+
+ ldl t0, PcProfileCountReload1(v0) // get the new tick count
+ stl t0, PcProfileCount1(v0) // reset the profile interval count
+
+ ldl a1, HalpProfileSource1
+ bis fp, zero, a0 // pass trap frame pointer
+ ldl t1, __imp_KeProfileInterruptWithSource
+ jsr ra, (t1) // process the profile interrupt
+
+ br zero, 40f // common return
+
+//
+// The profile interval has not expired. Update the decremented count.
+//
+
+10:
+ stl t0, PcProfileCount1(v0) // update profile interval count
+ br zero, 40f // common return
+
+//
+// Profiling is not active. Therefore, this interrupt was caused by
+// a performance counter driver. Deliver a secondary dispatch.
+//
+
+20:
+
+ ldil a0, PC1_SECONDARY_VECTOR // get IDT vector for secondary
+ s4addl a0, v0, a0 // a0 = PCR + IDT index
+ ldl a0, PcInterruptRoutine(a0) // get service routine address
+ jsr ra, (a0) // call interrupt service routine
+
+//
+// Setup for return.
+//
+
+40:
+ ldil v0, TRUE // set return value = TRUE
+ ldq ra, PrRa(sp) // restore return address
+ lda sp, PrFrameLength(sp) // deallocate the stack frame
+ ret zero, (ra) // return
+
+ .end HalpPerformanceCounter1Interrupt
+
+//++
+//
+// VOID
+// HalpWritePerformanceCounter(
+// IN ULONG PerformanceCounter,
+// IN BOOLEAN Enable,
+// IN ULONG MuxControl OPTIONAL,
+// IN ULONG EventCount OPTIONAL
+// )
+//
+// Routine Description:
+//
+// Write the specified microprocessor internal performance counter.
+//
+// Arguments:
+//
+// PerformanceCounter(a0) - Supplies the number of the performance counter
+// to write.
+//
+// Enable(a1) - Supplies a boolean that indicates if the performance
+// counter should be enabled or disabled.
+//
+// MuxControl(a2) - Supplies the mux control value which selects which
+// type of event to count when the counter is enabled.
+//
+// EventCount(a3) - Supplies the event interval when the counter is
+// enabled.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpWritePerformanceCounter)
+
+ call_pal wrperfmon // write the counter
+
+ ret zero, (ra) // return
+
+ .end HalpWritePerformanceCounter
diff --git a/private/ntos/nthals/halalpha/ev4mchk.c b/private/ntos/nthals/halalpha/ev4mchk.c
new file mode 100644
index 000000000..57fe29312
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ev4mchk.c
@@ -0,0 +1,709 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ ev4mchk.c
+
+Abstract:
+
+ This module implements generalized machine check handling for
+ platforms based on the DECchip 21064 (EV4) microprocessor.
+
+Author:
+
+ Joe Notarangelo 14-Feb-1994
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "axp21064.h"
+#include "stdio.h"
+
+
+//
+// Declare the extern variable UncorrectableError declared in
+// inithal.c.
+//
+extern PERROR_FRAME PUncorrectableError;
+
+VOID
+HalpDisplayLogout21064(
+ IN PLOGOUT_FRAME_21064 LogoutFrame );
+
+BOOLEAN
+HalpPlatformMachineCheck(
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PKEXCEPTION_FRAME ExceptionFrame,
+ IN PKTRAP_FRAME TrapFrame
+ );
+
+VOID
+HalpUpdateMces(
+ IN BOOLEAN ClearMachineCheck,
+ IN BOOLEAN ClearCorrectableError
+ );
+
+//
+// MAX_RETRYABLE_ERRORS is the number of times to retry machine checks before
+// just giving up.
+//
+
+#define MAX_RETRYABLE_ERRORS 32
+
+//
+// System-wide controls for machine check reporting.
+//
+
+ProcessorCorrectableDisable = FALSE;
+SystemCorrectableDisable = FALSE;
+MachineCheckDisable = FALSE;
+
+//
+//jnfix - temporary counts
+//
+
+ULONG CorrectableErrors = 0;
+ULONG RetryableErrors = 0;
+
+VOID
+HalpSetMachineCheckEnables(
+ IN BOOLEAN DisableMachineChecks,
+ IN BOOLEAN DisableProcessorCorrectables,
+ IN BOOLEAN DisableSystemCorrectables
+ )
+/*++
+
+Routine Description:
+
+ This function sets the enables that define which machine check
+ errors will be signaled by the processor.
+
+ N.B. - The system has the capability to ignore all machine checks
+ by indicating DisableMachineChecks = TRUE. This is intended
+ for debugging purposes on broken hardware. If you disable
+ this you will get no machine check no matter what error the
+ system/processor detects. Consider the consequences.
+
+Arguments:
+
+ DisableMachineChecks - Supplies a boolean which indicates if all
+ machine checks should be disabled and not
+ reported. (see note above).
+
+ DisableProcessorCorrectables - Supplies a boolean which indicates if
+ processor correctable error reporting
+ should be disabled.
+ DisableSystemCorrectables - Supplies a boolean which indicates if
+ system correctable error reporting
+ should be disabled.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+
+ ProcessorCorrectableDisable = DisableProcessorCorrectables;
+ SystemCorrectableDisable = DisableSystemCorrectables;
+ MachineCheckDisable = DisableMachineChecks;
+
+ HalpUpdateMces( FALSE, FALSE );
+
+ return;
+}
+
+VOID
+HalpUpdateMces(
+ IN BOOLEAN ClearMachineCheck,
+ IN BOOLEAN ClearCorrectableError
+ )
+/*++
+
+Routine Description:
+
+ This function updates the state of the MCES internal processor
+ register.
+
+Arguments:
+
+ ClearMachineCheck - Supplies a boolean that indicates if the machine
+ check indicator in the MCES should be cleared.
+
+ ClearCorrectableError - Supplies a boolean that indicates if the
+ correctable error indicators in the MCES should
+ be cleared.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ MCES Mces;
+
+ Mces.MachineCheck = ClearMachineCheck;
+ Mces.SystemCorrectable = ClearCorrectableError;
+ Mces.ProcessorCorrectable = ClearCorrectableError;
+ Mces.DisableProcessorCorrectable = ProcessorCorrectableDisable;
+ Mces.DisableSystemCorrectable = SystemCorrectableDisable;
+ Mces.DisableMachineChecks = MachineCheckDisable;
+
+ HalpWriteMces( Mces );
+
+}
+
+
+BOOLEAN
+HalMachineCheck (
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PKEXCEPTION_FRAME ExceptionFrame,
+ IN PKTRAP_FRAME TrapFrame
+ )
+/*++
+
+Routine Description:
+
+ This function fields machine check for 21064-based machines with
+ parity memory protection.
+
+Arguments:
+
+ ExceptionRecord - Supplies a pointer to the exception record for the
+ machine check. Included in the exception information
+ is the pointer to the logout frame.
+
+ ExceptionFrame - Supplies a pointer to the kernel exception frame.
+
+ TrapFrame - Supplies a pointer to the kernel trap frame.
+
+Return Value:
+
+ A value of TRUE is returned if the machine check has been
+ handled by the HAL. If it has been handled then execution may
+ resume at the faulting address. Otherwise, a value of FALSE
+ is returned.
+
+ N.B. - under some circumstances this routine may not return at
+ all.
+
+--*/
+
+{
+
+ PBIU_STAT_21064 BiuStat;
+ BOOLEAN Handled;
+ PLOGOUT_FRAME_21064 LogoutFrame;
+ PMCHK_STATUS MachineCheckStatus;
+ MCES Mces;
+ BOOLEAN UnhandledPlatformError = FALSE;
+
+ PUNCORRECTABLE_ERROR uncorrerr = NULL;
+ PPROCESSOR_EV4_UNCORRECTABLE ev4uncorr = NULL;
+
+
+ //
+ // This is a parity machine. If we receive a machine check it
+ // is uncorrectable. We will print the logout frame and then we
+ // will bugcheck.
+ //
+ // However, we will first check that the machine check is not
+ // marked as correctable. If the machine check is correctable it uses
+ // a differently formatted logout frame. We will ignore the frame
+ // for any machine check marked as correctable since it is an impossible
+ // condition on a parity machine.
+ //
+
+ MachineCheckStatus =
+ (PMCHK_STATUS)&ExceptionRecord->ExceptionInformation[0];
+
+ //
+ // Handle any processor correctable errors.
+ //
+
+ if( MachineCheckStatus->Correctable == 1 ){
+
+ //
+ // Log the error.
+ //
+ //jnfix - temporary code
+ // simply assume this was a fill ecc correctable for now, print
+ // a debug message periodically
+
+ CORRECTABLE_FRAME_21064 *CorrectableFrame;
+
+ CorrectableFrame =
+ (CORRECTABLE_FRAME_21064 *)ExceptionRecord->ExceptionInformation[1];
+
+ CorrectableErrors += 1;
+
+#if (DBG) || (HALDBG)
+
+ if( (CorrectableErrors % 32) == 0 ){
+ DbgPrint( "Correctable errors = %d, Error Address = 0x%016Lx\n",
+ CorrectableFrame->FillAddr );
+ }
+
+#endif //DBG || HALDBG
+
+ //
+ // Acknowledge receipt of the correctable error by clearing
+ // the error in the MCES register.
+ //
+
+ HalpUpdateMces( FALSE, TRUE );
+
+ return TRUE;
+ }
+
+ //
+ // Handle any retryable errors.
+ //
+
+ if( MachineCheckStatus->Retryable == 1 ){
+
+ //
+ // Increment the number of retryable machine checks.
+ //
+
+ RetryableErrors += 1;
+
+#if (DBG) || (HALDBG)
+
+ DbgPrint( "HAL Retryable Errors = %d\n", RetryableErrors );
+
+#endif //DBG || HALDBG
+
+ //
+ // We'll retry MAX_RETRYABLE_ERRORS times and then give up. We
+ // do this to avoid infinite retry loops.
+ //
+
+ if( RetryableErrors <= MAX_RETRYABLE_ERRORS ){
+
+ //
+ // Acknowledge receipt of the retryable machine check.
+ //
+
+ HalpUpdateMces( TRUE, TRUE );
+
+ return TRUE;
+ }
+ }
+
+ //
+ // Capture the logout frame pointer.
+ //
+
+ LogoutFrame =
+ (PLOGOUT_FRAME_21064)ExceptionRecord->ExceptionInformation[1];
+
+ if(PUncorrectableError) {
+
+ //
+ // Fill in the processor specific uncorrectable error frame
+ //
+ uncorrerr = (PUNCORRECTABLE_ERROR)
+ &PUncorrectableError->UncorrectableFrame;
+
+ //
+ // first fill in some generic processor Information.
+ // For the Current (Reporting) Processor.
+ //
+ HalpGetProcessorInfo(&uncorrerr->ReportingProcessor);
+ uncorrerr->Flags.ProcessorInformationValid = 1;
+
+ ev4uncorr = (PPROCESSOR_EV4_UNCORRECTABLE)
+ uncorrerr->RawProcessorInformation;
+ }
+ if(ev4uncorr) {
+
+ ev4uncorr->BiuStat = ((ULONGLONG)LogoutFrame->BiuStat.all.HighPart <<
+ 32) | LogoutFrame->BiuStat.all.LowPart;
+
+ ev4uncorr->BiuAddr = ((ULONGLONG)LogoutFrame->BiuAddr.HighPart << 32) |
+ LogoutFrame->BiuAddr.LowPart;
+
+ ev4uncorr->AboxCtl = ((ULONGLONG)LogoutFrame->AboxCtl.all.HighPart <<
+ 32) | LogoutFrame->AboxCtl.all.LowPart;
+
+ ev4uncorr->BiuCtl = ((ULONGLONG)LogoutFrame->BiuCtl.HighPart << 32) |
+ LogoutFrame->BiuCtl.LowPart;
+
+ ev4uncorr->CStat = ((ULONGLONG)LogoutFrame->DcStat.all.HighPart <<
+ 32) | LogoutFrame->DcStat.all.LowPart;
+
+ ev4uncorr->BcTag = ((ULONGLONG)LogoutFrame->BcTag.all.HighPart <<
+ 32 ) | LogoutFrame->BcTag.all.LowPart;
+
+ ev4uncorr->FillAddr = ((ULONGLONG)LogoutFrame->FillAddr.HighPart <<
+ 32) | LogoutFrame->FillAddr.LowPart;
+
+ ev4uncorr->FillSyndrome =
+ ((ULONGLONG)LogoutFrame->FillSyndrome.all.HighPart << 32) |
+ LogoutFrame->FillSyndrome.all.LowPart;
+ }
+
+ //
+ // Check for any hard errors that cannot be dismissed.
+ // They are:
+ // Tag parity error
+ // Tag control parity error
+ // Multiple external errors
+ // Fill ECC error
+ // Fill parity error
+ // Multiple fill errors
+ //
+
+ BiuStat = (PBIU_STAT_21064)&LogoutFrame->BiuStat;
+
+ if( (BiuStat->bits.BcTperr == 1) ||
+ (BiuStat->bits.BcTcperr == 1) ||
+ (BiuStat->bits.Fatal1 == 1) ||
+ (BiuStat->bits.FillEcc == 1) ||
+ (BiuStat->bits.FillDperr == 1) ||
+ (BiuStat->bits.Fatal2 == 1) ) {
+
+ //
+ // set the flag to indicate that the processor information is valid.
+ //
+ uncorrerr->Flags.ProcessorInformationValid = 1;
+ uncorrerr->Flags.ErrorStringValid = 1;
+ sprintf(uncorrerr->ErrorString,"Uncorrectable Error From "
+ "Processor Detected");
+
+ //
+ // A serious, uncorrectable error has occured, under no circumstances
+ // can it be simply dismissed.
+ //
+
+ goto FatalError;
+
+ }
+
+//jnfix - dcache parity error checking for EV45?
+
+ //
+ // It is possible that the system has experienced a hard error and
+ // that nonetheless the error is recoverable. This is a system-specific
+ // decision - allow it to be handled as such.
+ //
+
+ UnhandledPlatformError = TRUE;
+ if( (Handled = HalpPlatformMachineCheck(
+ ExceptionRecord,
+ ExceptionFrame,
+ TrapFrame )) == TRUE ){
+
+ //
+ // The system-specific code has handled the error. Dismiss
+ // the error and continue execution.
+ //
+
+ HalpUpdateMces( TRUE, TRUE );
+
+ return TRUE;
+
+ }
+
+//
+// The system has experienced a fatal error that cannot be corrected.
+// Print any possible relevant information and crash the system.
+//
+// N.B. - In the future some of these fatal errors could be potential
+// recovered. Example, a user process gets a fatal error on one
+// of its pages - we kill the user process, mark the page as bad
+// and continue executing.
+//
+
+FatalError:
+
+ //
+ // Begin the error output if this is a processor error. If this is
+ // an unhandled platform error than that code is responsible for
+ // beginning the error output.
+ //
+
+ if( UnhandledPlatformError == FALSE ){
+
+ //
+ // Acquire ownership of the display. This is done here in case we take
+ // a machine check before the display has been taken away from the HAL.
+ // When the HAL begins displaying strings after it has lost the
+ // display ownership then the HAL will be careful not to scroll
+ // information off of the screen.
+ //
+
+ HalAcquireDisplayOwnership(NULL);
+
+ //
+ // Display the dreaded banner.
+ //
+
+ HalDisplayString( "\nFatal system hardware error.\n\n" );
+
+ }
+
+ //
+ // Display the EV4 logout frame.
+ //
+
+ HalpDisplayLogout21064( LogoutFrame );
+
+ //
+ // Bugcheck to dump the rest of the machine state, this will help
+ // if the machine check is software-related.
+ //
+
+ KeBugCheckEx( DATA_BUS_ERROR,
+ (ULONG)MachineCheckStatus->Correctable,
+ (ULONG)MachineCheckStatus->Retryable,
+ (ULONG)0,
+ (ULONG)PUncorrectableError );
+
+}
+
+#define MAX_ERROR_STRING 100
+
+VOID
+HalpDisplayLogout21064 (
+ IN PLOGOUT_FRAME_21064 LogoutFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This function displays the logout frame for a 21064.
+
+Arguments:
+
+ LogoutFrame - Supplies a pointer to the logout frame generated
+ by the 21064.
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR OutBuffer[ MAX_ERROR_STRING ];
+ ULONG Index;
+ PKPRCB Prcb;
+ extern HalpLogicalToPhysicalProcessor[HAL_MAXIMUM_PROCESSOR+1];
+
+ sprintf( OutBuffer, "BIU_STAT : %016Lx BIU_ADDR: %016Lx\n",
+ BIUSTAT_ALL_21064( LogoutFrame->BiuStat ),
+ LogoutFrame->BiuAddr.QuadPart );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "FILL_ADDR: %016Lx FILL_SYN: %016Lx\n",
+ LogoutFrame->FillAddr.QuadPart,
+ FILLSYNDROME_ALL_21064(LogoutFrame->FillSyndrome) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "DC_STAT : %016Lx BC_TAG : %016Lx\n",
+ DCSTAT_ALL_21064(LogoutFrame->DcStat),
+ BCTAG_ALL_21064(LogoutFrame->BcTag) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "ICCSR : %016Lx ABOX_CTL: %016Lx EXC_SUM: %016Lx\n",
+ ICCSR_ALL_21064(LogoutFrame->Iccsr),
+ ABOXCTL_ALL_21064(LogoutFrame->AboxCtl),
+ EXCSUM_ALL_21064(LogoutFrame->ExcSum) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "EXC_ADDR : %016Lx VA : %016Lx MM_CSR : %016Lx\n",
+ LogoutFrame->ExcAddr.QuadPart,
+ LogoutFrame->Va.QuadPart,
+ MMCSR_ALL_21064(LogoutFrame->MmCsr) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "HIRR : %016Lx HIER : %016Lx PS : %016Lx\n",
+ IRR_ALL_21064(LogoutFrame->Hirr),
+ IER_ALL_21064(LogoutFrame->Hier),
+ PS_ALL_21064(LogoutFrame->Ps) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "Waiting 15 seconds...\n");
+ HalDisplayString( OutBuffer );
+
+ for( Index=0; Index<1500; Index++)
+ KeStallExecutionProcessor( 10000 ); // ~15 second delay
+
+ sprintf( OutBuffer, "PAL_BASE : %016Lx \n",
+ LogoutFrame->PalBase.QuadPart );
+ HalDisplayString( OutBuffer );
+
+ //
+ // Print out interpretation of the error.
+ //
+
+ //
+ // First print the processor on which we saw the error
+ //
+
+ Prcb = PCR->Prcb;
+ sprintf( OutBuffer, "Error on processor number: %d\n",
+ HalpLogicalToPhysicalProcessor[Prcb->Number] );
+ HalDisplayString( OutBuffer );
+
+ //
+ // If we got a Data Cache Parity Error print a message on screen.
+ //
+
+ if( DCSTAT_DCPARITY_ERROR_21064(LogoutFrame->DcStat) ){
+ sprintf( OutBuffer, "Data Cache Parity Error.\n" );
+ HalDisplayString( OutBuffer );
+ }
+
+ //
+ // Check for tag control parity error.
+ //
+
+ if( BIUSTAT_TCPERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer,
+ "Tag control parity error, Tag control: P: %1x D: %1x S: %1x V: %1x\n",
+ BCTAG_TAGCTLP_21064( LogoutFrame->BcTag ),
+ BCTAG_TAGCTLD_21064( LogoutFrame->BcTag ),
+ BCTAG_TAGCTLS_21064( LogoutFrame->BcTag ),
+ BCTAG_TAGCTLV_21064( LogoutFrame->BcTag ) );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for tag parity error.
+ //
+
+ if( BIUSTAT_TPERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer,
+ "Tag parity error, Tag: %x Parity: %1x\n",
+ BCTAG_TAG_21064(LogoutFrame->BcTag),
+ BCTAG_TAGP_21064(LogoutFrame->BcTag) );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for hard error.
+ //
+
+ if( BIUSTAT_HERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer, "Hard error acknowledge: BIU CMD: %x PA: %16Lx\n",
+ BIUSTAT_CMD_21064(LogoutFrame->BiuStat),
+ LogoutFrame->BiuAddr.QuadPart );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for soft error.
+ //
+
+ if( BIUSTAT_SERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer, "Soft error acknowledge: BIU CMD: %x PA: %16Lx\n",
+ BIUSTAT_CMD_21064(LogoutFrame->BiuStat),
+ LogoutFrame->BiuAddr.QuadPart );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+
+ //
+ // Check for fill ECC errors.
+ //
+
+ if( BIUSTAT_FILLECC_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer, "ECC error: %s\n",
+ (BIUSTAT_FILLIRD_21064(LogoutFrame->BiuStat) ?
+ "Icache Fill" : "Dcache Fill") );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer,
+ "PA: %16Lx Quadword: %x Longword0: %x Longword1: %x\n",
+ LogoutFrame->FillAddr.QuadPart,
+ BIUSTAT_FILLQW_21064(LogoutFrame->BiuStat),
+ FILLSYNDROME_LO_21064(LogoutFrame->FillSyndrome),
+ FILLSYNDROME_HI_21064(LogoutFrame->FillSyndrome) );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for fill Parity errors.
+ //
+
+ if( BIUSTAT_FILLDPERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer, "Parity error: %s\n",
+ (BIUSTAT_FILLIRD_21064(LogoutFrame->BiuStat) ?
+ "Icache Fill" : "Dcache Fill") );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer,
+ "PA: %16Lx Quadword: %x Longword0: %x Longword1: %x\n",
+ LogoutFrame->FillAddr.QuadPart,
+ BIUSTAT_FILLQW_21064(LogoutFrame->BiuStat),
+ FILLSYNDROME_LO_21064(LogoutFrame->FillSyndrome),
+ FILLSYNDROME_HI_21064(LogoutFrame->FillSyndrome) );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for multiple hard errors.
+ //
+
+ if( BIUSTAT_FATAL1_21064(LogoutFrame->BiuStat) == 1 ){
+
+ HalDisplayString( "Multiple external/tag errors detected.\n" );
+
+ }
+
+ //
+ // Check for multiple fill errors.
+ //
+
+ if( BIUSTAT_FATAL2_21064(LogoutFrame->BiuStat) == 1 ){
+
+ HalDisplayString( "Multiple fill errors detected.\n" );
+
+ }
+
+
+ //
+ // return to caller
+ //
+
+ return;
+}
+
diff --git a/private/ntos/nthals/halalpha/ev4mem.s b/private/ntos/nthals/halalpha/ev4mem.s
new file mode 100644
index 000000000..ab6815a91
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ev4mem.s
@@ -0,0 +1,146 @@
+// TITLE("EV4 Memory Operations")
+//++
+//
+// Copyright (c) 1994 Digital Equipment Corporation
+//
+// Module Name:
+//
+// ev4mem.s
+//
+// Abstract:
+//
+// This module implements EV4 memory operations that require assembly
+// language.
+//
+// Author:
+//
+// Joe Notarangelo 1-Jun-1994
+//
+// Environment:
+//
+// HAL, Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+#include "ksalpha.h"
+
+
+//++
+//
+// VOID
+// HalZeroPage (
+// IN PVOID NewColor,
+// IN PVOID OldColor,
+// IN ULONG PageFrame
+// )
+//
+// Routine Description:
+//
+// This function zeros a page of memory.
+//
+// Arguments:
+//
+// NewColor (a0) - Supplies the page aligned virtual address of the
+// new color of the page that is zeroed.
+//
+// OldColor (a1) - Supplies the page aligned virtual address of the
+// old color of the page that is zeroed.
+//
+// PageFrame (a2) - Supplies the page frame number of the page that
+// is zeroed.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalZeroPage)
+
+ .set noreorder // hand scheduled
+
+#define ZERO_BLOCK_SIZE (256)
+#define ZERO_LOOPS (PAGE_SIZE/ZERO_BLOCK_SIZE)
+
+//
+// Map the page via the 43-bit super-page on EV4.
+//
+
+ ldiq t0, -0x4000 // 0xffff ffff ffff c000
+ sll a2, PAGE_SHIFT, t1 // physical address of page
+
+ sll t0, 28, t0 // 0xffff fc00 0000 0000
+ ldil t2, ZERO_LOOPS // set count of loops to run
+
+ bis t0, t1, t0 // set super-page enable + physical
+ bis zero, zero, zero // for branch alignment
+
+//
+// Zero the page in a loop, zeroing 256 bytes per iteration. This number
+// was chosen to tradeoff loop overhead versus the overhead of fetching
+// Icache blocks.
+//
+
+10:
+ stq zero, 0x00(t0) //
+ subl t2, 1, t2 // decrement the loop count
+
+ stq zero, 0x08(t0) //
+ stt f31, 0x10(t0) //
+
+ stq zero, 0x18(t0) //
+ stt f31, 0x20(t0) //
+
+ stq zero, 0x28(t0) //
+ stt f31, 0x30(t0) //
+
+ stq zero, 0x38(t0) //
+ stt f31, 0x40(t0) //
+
+ stq zero, 0x48(t0) //
+ stt f31, 0x50(t0) //
+
+ stq zero, 0x58(t0) //
+ stt f31, 0x60(t0) //
+
+ stq zero, 0x68(t0) //
+ stt f31, 0x70(t0) //
+
+ stq zero, 0x78(t0) //
+ stt f31, 0x80(t0) //
+
+ stq zero, 0x88(t0) //
+ stt f31, 0x90(t0) //
+
+ stq zero, 0x98(t0) //
+ stt f31, 0xa0(t0) //
+
+ stq zero, 0xa8(t0) //
+ stt f31, 0xb0(t0) //
+
+ bis t0, zero, t1 // copy base register
+ stq zero, 0xb8(t0) //
+
+ stq zero, 0xc0(t0) //
+ stt f31, 0xc8(t0) //
+
+ stq zero, 0xd0(t0) //
+ stt f31, 0xd8(t0) //
+
+ stq zero, 0xe0(t0) //
+ lda t0, 0x100(t0) // increment to next block
+
+ stq zero, 0xe8(t1) //
+ stt f31, 0xf0(t1) //
+
+ stt f31, 0xf8(t1) // use stt for dual issue with bne
+ bne t2, 10b // while count > 0
+
+ ret zero, (ra) // return
+
+
+ .set reorder //
+
+ .end HalZeroPage
diff --git a/private/ntos/nthals/halalpha/ev4parit.c b/private/ntos/nthals/halalpha/ev4parit.c
new file mode 100644
index 000000000..bd9527680
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ev4parit.c
@@ -0,0 +1,336 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ ev4parit.c
+
+Abstract:
+
+ This module implements machine check handling for machines with
+ parity memory protection that are based on the DECchip 21064
+ microprocessor.
+
+Author:
+
+ Joe Notarangelo 11-Feb-1993
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "axp21064.h"
+
+VOID
+HalpDisplayLogout21064( PLOGOUT_FRAME_21064 LogoutFrame );
+
+
+BOOLEAN
+HalMachineCheck (
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PKEXCEPTION_FRAME ExceptionFrame,
+ IN PKTRAP_FRAME TrapFrame
+ )
+/*++
+
+Routine Description:
+
+ This function fields machine check for 21064-based machines with
+ parity memory protection.
+
+Arguments:
+
+ ExceptionRecord - Supplies a pointer to the exception record for the
+ machine check. Included in the exception information
+ is the pointer to the logout frame.
+
+ ExceptionFrame - Supplies a pointer to the kernel exception frame.
+
+ TrapFrame - Supplies a pointer to the kernel trap frame.
+
+Return Value:
+
+ A value of TRUE is returned if the machine check has been
+ handled by the HAL. If it has been handled then execution may
+ resume at the faulting address. Otherwise, a value of FALSE
+ is returned.
+
+ N.B. - under some circumstances this routine may not return at
+ all.
+
+--*/
+
+{
+
+ PMCHK_STATUS MachineCheckStatus;
+
+ //
+ // This is a parity machine. If we receive a machine check it
+ // is uncorrectable. We will print the logout frame and then we
+ // will bugcheck.
+ //
+ // However, we will first check that the machine check is not
+ // marked as correctable. If the machine check is correctable it uses
+ // a differently formatted logout frame. We will ignore the frame
+ // for any machine check marked as correctable since it is an impossible
+ // condition on a parity machine.
+ //
+
+ MachineCheckStatus =
+ (PMCHK_STATUS)&ExceptionRecord->ExceptionInformation[0];
+
+ if( MachineCheckStatus->Correctable == 0 ){
+
+ HalpDisplayLogout21064(
+ (PLOGOUT_FRAME_21064)(ExceptionRecord->ExceptionInformation[1])
+ );
+
+ }
+
+ //
+ // Bugcheck to dump the rest of the machine state, this will help
+ // if the machine check is software-related.
+ //
+
+ KeBugCheckEx( DATA_BUS_ERROR,
+ (ULONG)MachineCheckStatus->Correctable,
+ (ULONG)MachineCheckStatus->Retryable,
+ 0,
+ 0 );
+
+}
+
+
+#define MAX_ERROR_STRING 100
+
+VOID
+HalpDisplayLogout21064 (
+ IN PLOGOUT_FRAME_21064 LogoutFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This function displays the logout frame for a 21064.
+
+Arguments:
+
+ LogoutFrame - Supplies a pointer to the logout frame generated
+ by the 21064.
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR OutBuffer[ MAX_ERROR_STRING ];
+
+ //
+ // Acquire ownership of the display. This is done here in case we take
+ // a machine check before the display has been taken away from the HAL.
+ // When the HAL begins displaying strings after it has lost the
+ // display ownership then the HAL will be careful not to scroll information
+ // off of the screen.
+ //
+
+ HalAcquireDisplayOwnership(NULL);
+
+ //
+ // Display the machine state via the logout frame.
+ //
+
+ HalDisplayString( "\nFatal system hardware error.\n\n" );
+
+
+ sprintf( OutBuffer, "BIU_STAT : %016Lx BIU_ADDR: %016Lx\n",
+ BIUSTAT_ALL_21064( LogoutFrame->BiuStat ),
+ LogoutFrame->BiuAddr.QuadPart );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "FILL_ADDR: %016Lx FILL_SYN: %016Lx\n",
+ LogoutFrame->FillAddr.QuadPart,
+ FILLSYNDROME_ALL_21064(LogoutFrame->FillSyndrome) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "DC_STAT : %016Lx BC_TAG : %016Lx\n",
+ DCSTAT_ALL_21064(LogoutFrame->DcStat),
+ BCTAG_ALL_21064(LogoutFrame->BcTag) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "ICCSR : %016Lx ABOX_CTL: %016Lx EXC_SUM: %016Lx\n",
+ ICCSR_ALL_21064(LogoutFrame->Iccsr),
+ ABOXCTL_ALL_21064(LogoutFrame->AboxCtl),
+ EXCSUM_ALL_21064(LogoutFrame->ExcSum) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "EXC_ADDR : %016Lx VA : %016Lx MM_CSR : %016Lx\n",
+ LogoutFrame->ExcAddr.QuadPart,
+ LogoutFrame->Va.QuadPart,
+ MMCSR_ALL_21064(LogoutFrame->MmCsr) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "HIRR : %016Lx HIER : %016Lx PS : %016Lx\n",
+ IRR_ALL_21064(LogoutFrame->Hirr),
+ IER_ALL_21064(LogoutFrame->Hier),
+ PS_ALL_21064(LogoutFrame->Ps) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "PAL_BASE : %016Lx \n",
+ LogoutFrame->PalBase.QuadPart );
+ HalDisplayString( OutBuffer );
+
+ //
+ // Print out interpretation of the error.
+ //
+
+
+ HalDisplayString( "\n" );
+
+ //
+ // Check for tag control parity error.
+ //
+
+ if( BIUSTAT_TCPERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer,
+ "Tag control parity error, Tag control: P: %1x D: %1x S: %1x V: %1x\n",
+ BCTAG_TAGCTLP_21064( LogoutFrame->BcTag ),
+ BCTAG_TAGCTLD_21064( LogoutFrame->BcTag ),
+ BCTAG_TAGCTLS_21064( LogoutFrame->BcTag ),
+ BCTAG_TAGCTLV_21064( LogoutFrame->BcTag ) );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for tag parity error.
+ //
+
+ if( BIUSTAT_TPERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer,
+ "Tag parity error, Tag: 0b%17b Parity: %1x\n",
+ BCTAG_TAG_21064(LogoutFrame->BcTag),
+ BCTAG_TAGP_21064(LogoutFrame->BcTag) );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for hard error.
+ //
+
+ if( BIUSTAT_HERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer, "Hard error acknowledge: BIU CMD: %x PA: %16Lx\n",
+ BIUSTAT_CMD_21064(LogoutFrame->BiuStat),
+ LogoutFrame->BiuAddr.QuadPart );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for soft error.
+ //
+
+ if( BIUSTAT_SERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer, "Soft error acknowledge: BIU CMD: %x PA: %16Lx\n",
+ BIUSTAT_CMD_21064(LogoutFrame->BiuStat),
+ LogoutFrame->BiuAddr.QuadPart );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+
+ //
+ // Check for fill ECC errors.
+ //
+
+ if( BIUSTAT_FILLECC_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer, "ECC error: %s\n",
+ (BIUSTAT_FILLIRD_21064(LogoutFrame->BiuStat) ?
+ "Icache Fill" : "Dcache Fill") );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer,
+ "PA: %16Lx Quadword: %x Longword0: %x Longword1: %x\n",
+ LogoutFrame->FillAddr.QuadPart,
+ BIUSTAT_FILLQW_21064(LogoutFrame->BiuStat),
+ FILLSYNDROME_LO_21064(LogoutFrame->FillSyndrome),
+ FILLSYNDROME_HI_21064(LogoutFrame->FillSyndrome) );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for fill Parity errors.
+ //
+
+ if( BIUSTAT_FILLDPERR_21064(LogoutFrame->BiuStat) == 1 ){
+
+ sprintf( OutBuffer, "Parity error: %s\n",
+ (BIUSTAT_FILLIRD_21064(LogoutFrame->BiuStat) ?
+ "Icache Fill" : "Dcache Fill") );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer,
+ "PA: %16Lx Quadword: %x Longword0: %x Longword1: %x\n",
+ LogoutFrame->FillAddr.QuadPart,
+ BIUSTAT_FILLQW_21064(LogoutFrame->BiuStat),
+ FILLSYNDROME_LO_21064(LogoutFrame->FillSyndrome),
+ FILLSYNDROME_HI_21064(LogoutFrame->FillSyndrome) );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for multiple hard errors.
+ //
+
+ if( BIUSTAT_FATAL1_21064(LogoutFrame->BiuStat) == 1 ){
+
+ HalDisplayString( "Multiple external/tag errors detected.\n" );
+
+ }
+
+ //
+ // Check for multiple fill errors.
+ //
+
+ if( BIUSTAT_FATAL2_21064(LogoutFrame->BiuStat) == 1 ){
+
+ HalDisplayString( "Multiple fill errors detected.\n" );
+
+ }
+
+
+ //
+ // return to caller
+ //
+
+ return;
+}
diff --git a/private/ntos/nthals/halalpha/ev4prof.c b/private/ntos/nthals/halalpha/ev4prof.c
new file mode 100644
index 000000000..513187b0d
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ev4prof.c
@@ -0,0 +1,591 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ ev4prof.c
+
+Abstract:
+
+ This module implements the Profile Counter using the performance
+ counters within the EV4 core. This module is appropriate for all
+ machines based on microprocessors using the EV4 core.
+
+ N.B. - This module assumes that all processors in a multiprocessor
+ system are running the microprocessor at the same clock speed.
+
+Author:
+
+ Joe Notarangelo 22-Feb-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "axp21064.h"
+
+
+//
+// Define space in the HAL-reserved part of the PCR structure for each
+// performance counter's interval count
+//
+// Note that ev4ints.s depends on these positions in the PCR.
+//
+#define PCRProfileCount ((PULONG)(HAL_PCR->ProfileCount.ProfileCount))
+#define PCRProfileCountReload ((PULONG)(&HAL_PCR->ProfileCount.ProfileCountReload))
+
+
+//
+// Define the currently selected profile source for each counter
+//
+KPROFILE_SOURCE HalpProfileSource0;
+KPROFILE_SOURCE HalpProfileSource1;
+
+#define INTERVAL_DELTA (10)
+
+//
+// Define the mapping between possible profile sources and the
+// CPU-specific settings.
+//
+typedef struct _HALP_PROFILE_MAPPING {
+ BOOLEAN Supported;
+ ULONG MuxControl;
+ ULONG Counter;
+ ULONG EventCount;
+ ULONG NumberOfTicks;
+} HALP_PROFILE_MAPPING, *PHALP_PROFILE_MAPPING;
+
+HALP_PROFILE_MAPPING HalpProfileMapping[ProfileMaximum] =
+ {
+ {TRUE, Ev4TotalCycles, Ev4PerformanceCounter0, Ev4CountEvents2xx12, 10},
+ {FALSE, 0, 0, 0, 0},
+ {TRUE, Ev4TotalIssues, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10},
+ {TRUE, Ev4PipelineDry, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10},
+ {TRUE, Ev4LoadInstruction, Ev4PerformanceCounter0, Ev4CountEvents2xx12, 10},
+ {TRUE, Ev4PipelineFrozen, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10},
+ {TRUE, Ev4BranchInstructions, Ev4PerformanceCounter0, Ev4CountEvents2xx12, 10},
+ {TRUE, Ev4TotalNonIssues, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10},
+ {TRUE, Ev4DcacheMiss, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10},
+ {TRUE, Ev4IcacheMiss, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10},
+ {FALSE, 0, 0, 0, 0},
+ {TRUE, Ev4BranchMispredicts, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10},
+ {TRUE, Ev4StoreInstructions, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10},
+ {TRUE, Ev4FPInstructions, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10},
+ {TRUE, Ev4IntegerOperate, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10},
+ {TRUE, Ev4DualIssues, Ev4PerformanceCounter1, Ev4CountEvents2xx12, 10},
+ {FALSE, 0, 0, 0, 0},
+ {FALSE, 0, 0, 0, 0},
+ {TRUE, Ev4PalMode, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10},
+ {TRUE, Ev4TotalCycles, Ev4PerformanceCounter0, Ev4CountEvents2xx16, 10},
+ {FALSE, 0, 0, 0, 0},
+ {FALSE, 0, 0, 0, 0}
+ };
+
+BOOLEAN
+HalQueryProfileInterval(
+ IN KPROFILE_SOURCE Source
+ );
+
+NTSTATUS
+HalSetProfileSourceInterval(
+ IN KPROFILE_SOURCE ProfileSource,
+ IN OUT ULONG *Interval
+ );
+
+
+
+NTSTATUS
+HalpProfileSourceInformation (
+ OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG ReturnedLength
+ )
+/*++
+
+Routine Description:
+
+ Returns the HAL_PROFILE_SOURCE_INFORMATION for this processor.
+
+Arguments:
+
+ Buffer - output buffer
+ BufferLength - length of buffer on input
+ ReturnedLength - The length of data returned
+
+Return Value:
+
+ STATUS_SUCCESS
+ STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
+ currently needed.
+
+--*/
+{
+ PHAL_PROFILE_SOURCE_INFORMATION SourceInfo;
+ NTSTATUS Status;
+
+
+ if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INFORMATION)) {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ return Status;
+ }
+
+ SourceInfo = (PHAL_PROFILE_SOURCE_INFORMATION)Buffer;
+ SourceInfo->Supported = HalQueryProfileInterval(SourceInfo->Source);
+
+ if (SourceInfo->Supported) {
+ SourceInfo->Interval =
+ HalpProfileMapping[SourceInfo->Source].EventCount *
+ HalpProfileMapping[SourceInfo->Source].NumberOfTicks;
+ if (SourceInfo->Source == ProfileTotalIssues) {
+ //
+ // Convert total issues/2 back into total issues
+ //
+ SourceInfo->Interval = SourceInfo->Interval * 2;
+ }
+ }
+
+ Status = STATUS_SUCCESS;
+ return Status;
+}
+
+NTSTATUS
+HalpProfileSourceInterval (
+ OUT PVOID Buffer,
+ IN ULONG BufferLength
+ )
+/*++
+
+Routine Description:
+
+ Returns the HAL_PROFILE_SOURCE_INTERVAL for this processor.
+
+Arguments:
+
+ Buffer - output buffer
+ BufferLength - length of buffer on input
+
+Return Value:
+
+ STATUS_SUCCESS
+ STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
+ currently needed.
+
+--*/
+{
+ PHAL_PROFILE_SOURCE_INTERVAL Interval;
+ NTSTATUS Status;
+
+
+ if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INTERVAL)) {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ return Status;
+ }
+
+ Interval = (PHAL_PROFILE_SOURCE_INTERVAL)Buffer;
+ Status = HalSetProfileSourceInterval(Interval->Source,
+ &Interval->Interval);
+ return Status;
+}
+
+VOID
+HalpInitializeProfiler(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine is called during initialization to initialize profiling
+ for each processor in the system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PKINTERRUPT InterruptObject;
+ KIRQL Irql;
+ PKPRCB Prcb = PCR->Prcb;
+ ULONG Vector;
+
+ //
+ // Establish the profile interrupt as the interrupt handler for
+ // all performance counter interrupts.
+ //
+
+ PCR->InterruptRoutine[PC0_VECTOR] = HalpPerformanceCounter0Interrupt;
+ PCR->InterruptRoutine[PC1_VECTOR] = HalpPerformanceCounter1Interrupt;
+
+ return;
+
+}
+
+
+BOOLEAN
+HalQueryProfileInterval(
+ IN KPROFILE_SOURCE Source
+ )
+
+/*++
+
+Routine Description:
+
+ Given a profile source, returns whether or not that source is
+ supported.
+
+Arguments:
+
+ Source - Supplies the profile source
+
+Return Value:
+
+ TRUE - Profile source is supported
+
+ FALSE - Profile source is not supported
+
+--*/
+
+{
+ if (Source > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) {
+ return(FALSE);
+ }
+
+ return(HalpProfileMapping[Source].Supported);
+}
+
+
+NTSTATUS
+HalSetProfileSourceInterval(
+ IN KPROFILE_SOURCE ProfileSource,
+ IN OUT ULONG *Interval
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the profile interval for a specified profile source
+
+Arguments:
+
+ ProfileSource - Supplies the profile source
+
+ Interval - Supplies the specified profile interval
+ Returns the actual profile interval
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+{
+ ULONG FastTickPeriod;
+ ULONG SlowTickPeriod;
+ ULONG TickPeriod;
+ ULONGLONG CountEvents;
+ ULONG FastCountEvents;
+ ULONG SlowCountEvents;
+ ULONGLONG TempInterval;
+
+ if (!HalQueryProfileInterval(ProfileSource)) {
+ return(STATUS_NOT_IMPLEMENTED);
+ }
+
+ if (ProfileSource == ProfileTime) {
+
+ //
+ // Convert the clock tick period (in 100ns units ) into
+ // a cycle count period
+ //
+
+ CountEvents = ((ULONGLONG)(*Interval) * 100000) / PCR->CycleClockPeriod;
+ } else if (ProfileSource == ProfileTotalIssues) {
+
+ //
+ // Convert the total issue events into the wonky
+ // total issues/2 form implemented by EV4.
+ //
+
+ CountEvents = (ULONGLONG)(*Interval / 2);
+ } else {
+ CountEvents = (ULONGLONG)*Interval;
+ }
+
+ if (HalpProfileMapping[ProfileSource].Counter == Ev4PerformanceCounter1) {
+ FastCountEvents = Ev4CountEvents2xx8;
+ SlowCountEvents = Ev4CountEvents2xx12;
+ } else {
+ FastCountEvents = Ev4CountEvents2xx12;
+ SlowCountEvents = Ev4CountEvents2xx16;
+ }
+
+ //
+ // Limit the interval to the smallest interval we can time.
+ //
+ if (CountEvents < FastCountEvents) {
+ CountEvents = (ULONGLONG)FastCountEvents;
+ }
+
+ //
+ // Assume we will use the fast event count
+ //
+ HalpProfileMapping[ProfileSource].EventCount = FastCountEvents;
+ HalpProfileMapping[ProfileSource].NumberOfTicks =
+ (ULONG)((CountEvents + FastCountEvents - 1) / FastCountEvents);
+
+ //
+ // See if we can successfully use the slower period. If the requested
+ // interval is greater than the slower tick period and the difference
+ // between the requested interval and the interval that we can deliver
+ // with the slower clock is acceptable, then use the slower clock.
+ // We define an acceptable difference as a difference of less than
+ // INTERVAL_DELTA of the requested interval.
+ //
+ if (CountEvents > SlowCountEvents) {
+ ULONG NewInterval;
+
+ NewInterval = (ULONG)(((CountEvents + SlowCountEvents-1) /
+ SlowCountEvents) * SlowCountEvents);
+ if (((NewInterval - CountEvents) * 100 / CountEvents) < INTERVAL_DELTA) {
+ HalpProfileMapping[ProfileSource].EventCount = SlowCountEvents;
+ HalpProfileMapping[ProfileSource].NumberOfTicks = NewInterval / SlowCountEvents;
+ }
+ }
+
+ *Interval = HalpProfileMapping[ProfileSource].EventCount *
+ HalpProfileMapping[ProfileSource].NumberOfTicks;
+
+ if (ProfileSource == ProfileTime) {
+ //
+ // Convert cycle count back into 100ns clock ticks
+ //
+ // Use 64-bit integer to prevent overflow.
+ //
+ TempInterval = (ULONGLONG)(*Interval) * (ULONGLONG)(PCR->CycleClockPeriod);
+ *Interval = (ULONG)(TempInterval / 100000);
+ } else if (ProfileSource == ProfileTotalIssues) {
+ //
+ // Convert issues/2 count back into issues
+ //
+ TempInterval = (ULONGLONG)(*Interval) * 2;
+ *Interval = (ULONG)TempInterval;
+ }
+ return(STATUS_SUCCESS);
+}
+
+
+ULONG
+HalSetProfileInterval (
+ IN ULONG Interval
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the profile interrupt interval.
+
+Arguments:
+
+ Interval - Supplies the desired profile interval in 100ns units.
+
+Return Value:
+
+ The actual profile interval.
+
+--*/
+
+{
+ ULONG NewInterval;
+
+ NewInterval = Interval;
+ HalSetProfileSourceInterval(ProfileTime, &NewInterval);
+ return(NewInterval);
+}
+
+
+
+VOID
+HalStartProfileInterrupt (
+ KPROFILE_SOURCE ProfileSource
+ )
+
+/*++
+
+Routine Description:
+
+ This routine turns on the profile interrupt.
+
+ N.B. This routine must be called at PROCLK_LEVEL while holding the
+ profile lock.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG PerformanceCounter;
+ ULONG MuxControl;
+ ULONG EventCount;
+
+ //
+ // Check input to see if we are turning on a source that is
+ // supported. If it is unsupported, just return.
+ //
+
+ if ((ProfileSource > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) ||
+ (!HalpProfileMapping[ProfileSource].Supported)) {
+ return;
+ }
+
+ //
+ // Set the performance counter within the processor to begin
+ // counting total cycles.
+ //
+ PerformanceCounter = HalpProfileMapping[ProfileSource].Counter;
+ MuxControl = HalpProfileMapping[ProfileSource].MuxControl;
+
+ if (PerformanceCounter == Ev4PerformanceCounter0) {
+
+ HalpProfileSource0 = ProfileSource;
+ EventCount = (HalpProfileMapping[ProfileSource].EventCount == Ev4CountEvents2xx12) ?
+ Ev4EventCountHigh :
+ Ev4EventCountLow;
+ HalpWritePerformanceCounter( PerformanceCounter,
+ TRUE,
+ MuxControl,
+ EventCount );
+
+ PCRProfileCountReload[0] = HalpProfileMapping[ProfileSource].NumberOfTicks;
+ PCRProfileCount[0] = HalpProfileMapping[ProfileSource].NumberOfTicks;
+
+ //
+ // Enable the performance counter interrupt.
+ //
+
+ HalEnableSystemInterrupt ( PC0_VECTOR,
+ PROFILE_LEVEL,
+ LevelSensitive );
+
+
+ } else {
+
+ HalpProfileSource1 = ProfileSource;
+ EventCount = (HalpProfileMapping[ProfileSource].EventCount == Ev4CountEvents2xx12) ?
+ Ev4EventCountLow :
+ Ev4EventCountHigh;
+ HalpWritePerformanceCounter( PerformanceCounter,
+ TRUE,
+ MuxControl,
+ EventCount );
+
+ PCRProfileCountReload[1] = HalpProfileMapping[ProfileSource].NumberOfTicks;
+ PCRProfileCount[1] = HalpProfileMapping[ProfileSource].NumberOfTicks;
+
+ //
+ // Enable the performance counter interrupt.
+ //
+
+ HalEnableSystemInterrupt ( PC1_VECTOR,
+ PROFILE_LEVEL,
+ LevelSensitive );
+ }
+
+ return;
+}
+
+
+VOID
+HalStopProfileInterrupt (
+ KPROFILE_SOURCE ProfileSource
+ )
+
+/*++
+
+Routine Description:
+
+ This routine turns off the profile interrupt.
+
+ N.B. This routine must be called at PROCLK_LEVEL while holding the
+ profile lock.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG PerformanceCounter;
+ ULONG Vector;
+
+ //
+ // Check input to see if we are turning off a source that is
+ // supported. If it is unsupported, just return.
+ //
+
+ if ((ProfileSource > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) ||
+ (!HalpProfileMapping[ProfileSource].Supported)) {
+ return;
+ }
+
+ //
+ // Stop the performance counter from interrupting.
+ //
+
+ PerformanceCounter = HalpProfileMapping[ProfileSource].Counter;
+ HalpWritePerformanceCounter( PerformanceCounter,
+ FALSE,
+ 0,
+ 0 );
+
+ //
+ // Disable the performance counter interrupt.
+ //
+ if (PerformanceCounter == Ev4PerformanceCounter0) {
+ HalDisableSystemInterrupt( PC0_VECTOR, PROFILE_LEVEL );
+
+ //
+ // Clear the current profile count. Can't clear value in PCR
+ // since a profile interrupt could be pending or in progress
+ // so clear the reload counter.
+ //
+
+ PCRProfileCountReload[0] = 0;
+ } else {
+ HalDisableSystemInterrupt( PC1_VECTOR, PROFILE_LEVEL );
+
+ //
+ // Clear the current profile count. Can't clear value in PCR
+ // since a profile interrupt could be pending or in progress
+ // so clear the reload counter.
+ //
+
+ PCRProfileCountReload[0] = 0;
+ }
+
+ return;
+}
+
diff --git a/private/ntos/nthals/halalpha/ev5cache.c b/private/ntos/nthals/halalpha/ev5cache.c
new file mode 100644
index 000000000..2ab2e09bf
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ev5cache.c
@@ -0,0 +1,475 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ ev5cache.c
+
+Abstract:
+
+ This file contains the routines for managing the caches on machines
+ based on the DECchip 21164 microprocessor (aka EV5).
+
+ EV5 has primary I and D caches of 8KB each, Dcache is write-through.
+ EV5 also contains a 96K, 3-way set associative, write-back secondary cache.
+ Many EV5 systems will also have an external 3rd level backup cache.
+ The data caches (internal and external) must be kept coherent by the
+ hardware. Instruction cache coherency is maintained by software.
+
+ EV5 has a write buffer which contains 6 32-byte entries, which
+ must be flushable before DMA operations. The MB instruction is
+ used to accomplish this.
+
+ There is no coloring support on EV5, so Color operations are
+ null. Zero page is implemented in ev5mem.s Copy page is not
+ special because we lack coloring.
+
+Author:
+
+ Miche Baker-Harvey (miche) 29-May-1992 (EV4 version)
+ Steve Brooks 30-Jun-1994 (EV5 version)
+ Joe Notarangelo 30-Jun-1994 (EV5 version)
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+
+
+VOID
+HalFlushDcache (
+ IN BOOLEAN AllProcessors
+ );
+
+
+//
+// Cache and write buffer flush functions.
+//
+
+
+VOID
+HalChangeColorPage (
+ IN PVOID NewColor,
+ IN PVOID OldColor,
+ IN ULONG PageFrame
+ )
+/*++
+
+Routine Description:
+
+ This function changes the color of a page if the old and new colors
+ do not match. DECchip 21064-based machines do not have page coloring, and
+ therefore, this function performs no operation.
+
+Arguments:
+
+ NewColor - Supplies the page aligned virtual address of the
+ new color of the page to change.
+
+ OldColor - Supplies the page aligned virtual address of the
+ old color of the page to change.
+
+ pageFrame - Supplies the page frame number of the page that
+ is changed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+
+VOID
+HalFlushDcachePage (
+ IN PVOID Color,
+ IN ULONG PageFrame,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function flushes (invalidates) up to a page of data from the
+ data cache.
+
+Arguments:
+
+ Color - Supplies the starting virtual address and color of the
+ data that is flushed.
+ PageFrame - Supplies the page frame number of the page that
+ is flushed.
+
+ Length - Supplies the length of the region in the page that is
+ flushed.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+
+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.
+
+--*/
+{
+ //
+ // The Dcache coherency is maintained in hardware. The Icache coherency
+ // is maintained by invalidating the istream on page read operations.
+ //
+ HalpMb(); // synchronize this processors view of memory
+ if (ReadOperation) {
+ HalpMb(); // not issued until previous mb completes
+ if (Mdl->MdlFlags & MDL_IO_PAGE_READ) {
+
+ //
+ // The operation is a page read, thus the istream must
+ // be flushed.
+ //
+ HalpImb();
+ }
+ }
+}
+
+VOID
+HalPurgeDcachePage (
+ IN PVOID Color,
+ IN ULONG PageFrame,
+ IN ULONG Length
+ )
+/*++
+Routine Description:
+
+ This function purges (invalidates) up to a page of data from the
+ data cache.
+
+Arguments:
+
+ Color - Supplies the starting virtual address and color of the
+ data that is purged.
+
+ PageFrame - Supplies the page frame number of the page that
+ is purged.
+
+ Length - Supplies the length of the region in the page that is
+ purged.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+
+VOID
+HalPurgeIcachePage (
+ IN PVOID Color,
+ IN ULONG PageFrame,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function purges (invalidates) up to a page fo data from the
+ instruction cache.
+
+Arguments:
+
+ Color - Supplies the starting virtual address and color of the
+ data that is purged.
+
+ PageFrame - Supplies the page frame number of the page that
+ is purged.
+
+ Length - Supplies the length of the region in the page that is
+ purged.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The call to HalpImb calls PAL to flush the Icache, which ensures that
+ // any stale hits will be invalidated
+ //
+
+ HalpImb();
+}
+
+
+VOID
+HalSweepDcache (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function sweeps (invalidates) the entire data cache.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+
+VOID
+HalSweepDcacheRange (
+ IN PVOID BaseAddress,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function flushes the specified range of addresses from the data
+ cache on the current processor.
+
+Arguments:
+
+ BaseAddress - Supplies the starting physical address of a range of
+ physical addresses that are to be flushed from the data cache.
+
+ Length - Supplies the length of the range of physical addresses
+ that are to be flushed from the data cache.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ return;
+}
+
+
+VOID
+HalSweepIcache (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function sweeps (invalidates) the entire instruction cache.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // The call to HalpImb calls PAL to flush the Icache, which ensures that
+ // any stale hits will be invalidated
+ //
+
+ HalpImb();
+ return;
+}
+
+
+VOID
+HalSweepIcacheRange (
+ IN PVOID BaseAddress,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function flushes the specified range of addresses from the
+ instruction cache on the current processor.
+
+Arguments:
+
+ BaseAddress - Supplies the starting physical address of a range of
+ physical addresses that are to be flushed from the instruction cache.
+
+ Length - Supplies the length of the range of physical addresses
+ that are to be flushed from the instruction cache.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // The call to HalpImb calls PAL to flush the Icache, which ensures that
+ // any stale hits will be invalidated
+ //
+
+ HalpImb;
+
+}
+
+
+VOID
+KeFlushWriteBuffer (
+ VOID
+ )
+
+{
+ //
+ // We flush the write buffer by doing a series of memory
+ // barrier operations, the flush method is specific to the 21164.
+ //
+
+ HalpMb();
+ HalpMb();
+
+ return;
+}
+
+
+VOID
+KeFlushDcache (
+ IN BOOLEAN AllProcessors,
+ IN PVOID BaseAddress OPTIONAL,
+ IN ULONG Length
+ )
+
+/*++
+
+Routine Description:
+
+ This function flushes the data cache on all processors that are currently
+ running threads which are children of the current process or flushes the
+ data cache on all processors in the host configuration.
+
+Arguments:
+
+ AllProcessors - Supplies a boolean value that determines which data
+ caches are flushed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER(BaseAddress);
+ UNREFERENCED_PARAMETER(Length);
+
+ HalFlushDcache(AllProcessors);
+ return;
+}
+
+
+VOID
+HalFlushDcache (
+ IN BOOLEAN AllProcessors
+ )
+
+/*++
+
+Routine Description:
+
+ This function flushes the data cache on all processors that are currently
+ running threads which are children of the current process or flushes the
+ data cache on all processors in the host configuration.
+
+Arguments:
+
+ AllProcessors - Supplies a boolean value that determines which data
+ caches are flushed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Sweep (index/writeback/invalidate) the data cache.
+ //
+
+ HalSweepDcache();
+ return;
+}
+
+
+ULONG
+HalGetDmaAlignmentRequirement (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the alignment requirements for DMA transfers on
+ host system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The DMA alignment requirement is returned as the fucntion value.
+
+--*/
+
+{
+
+ return 8;
+}
diff --git a/private/ntos/nthals/halalpha/ev5int.c b/private/ntos/nthals/halalpha/ev5int.c
new file mode 100644
index 000000000..3fa1eec25
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ev5int.c
@@ -0,0 +1,440 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ ev5int.c
+
+Abstract:
+
+ This module implements the support routines to control DECchip 21164
+ interrupts.
+
+Author:
+
+ Joe Notarangelo 20-Jul-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "axp21164.h"
+
+//
+// Function prototype.
+//
+
+VOID
+HalpCachePcrValues(
+ ULONG InterruptMask
+ );
+
+
+VOID
+HalpInitialize21164Interrupts(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine initializes the data structures for the 21164
+ interrupt routines.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PIMSK_21164 InterruptMask;
+ PBOOLEAN InterruptsStarted;
+
+ //
+ // Set up the standard correspondence of NT IRQLs to EV5 IPLs.
+ // It is possible that some machines may need a different correspondence
+ // then the one below - HALs that change this table do so at their
+ // own risk.
+ //
+ // NT IRQL EV5 IPL
+ // ------- -------
+ // PASSIVE_LEVEL 0
+ // APC_LEVEL 1
+ // DISPATCH_LEVEL 2
+ // DEVICE_LEVEL 20
+ // DEVICE_HIGH_LEVEL 21
+ // CLOCK_LEVEL 22
+ // IPI_LEVEL 23
+ // HIGH_LEVEL 31
+ //
+
+ PCR->IrqlTable[PASSIVE_LEVEL] = EV5_IPL0;
+ PCR->IrqlTable[APC_LEVEL] = EV5_IPL1;
+ PCR->IrqlTable[DISPATCH_LEVEL] = EV5_IPL2;
+ PCR->IrqlTable[DEVICE_LEVEL] = EV5_IPL20;
+ PCR->IrqlTable[DEVICE_HIGH_LEVEL] = EV5_IPL21;
+ PCR->IrqlTable[CLOCK_LEVEL] = EV5_IPL22;
+ PCR->IrqlTable[IPI_LEVEL] = EV5_IPL23;
+ PCR->IrqlTable[HIGH_LEVEL] = EV5_IPL31;
+
+ //
+ // Define the default set of disables (masks) for the EV5 interrupt
+ // pins INT0 - INT3. All interrupts are enabled by default and may
+ // be disabled by the interface: HalpDisable21164HardwareInterrupt().
+ //
+
+ InterruptMask = (PIMSK_21164)(&PCR->IrqlMask[0]);
+
+ InterruptMask->all = 0;
+
+ //
+ // Indicate that interrupts have not been started yet.
+ //
+
+ InterruptsStarted = (PBOOLEAN)(&PCR->IrqlMask[1]);
+ *InterruptsStarted = FALSE;
+
+ return;
+
+}
+
+
+VOID
+HalpStart21164Interrupts(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function starts interrupt dispatching on the current 21164.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PIMSK_21164 InterruptMask;
+ PBOOLEAN InterruptsStarted;
+
+ //
+ // Issue the initpcr call pal to alert the PALcode that it can
+ // begin taking interrupts, pass the disable mask for the hardware
+ // interrupts.
+ //
+
+ InterruptMask = (PIMSK_21164)(&PCR->IrqlMask);
+ HalpCachePcrValues( InterruptMask->all );
+
+ //
+ // Indicate that interrupts have been started yet.
+ //
+
+ InterruptsStarted = (PBOOLEAN)(&PCR->IrqlMask[1]);
+ *InterruptsStarted = TRUE;
+
+ return;
+}
+
+
+#if 0 // used ??
+
+VOID
+HalpEnable21164HardwareInterrupt(
+ IN ULONG Irq
+ )
+/*++
+
+Routine Description:
+
+ Clear the mask value for the desired Irq pin so that interrupts
+ are enabled from that pin.
+
+Arguments:
+
+ Irq - Supplies the interrupt pin number to be enabled.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PIMSK_21164 InterruptMask;
+ PBOOLEAN InterruptsStarted;
+ KIRQL OldIrql;
+
+ //
+ // Raise Irql to HIGH_LEVEL to prevent any interrupts.
+ //
+
+ KeRaiseIrql( HIGH_LEVEL, &OldIrql );
+
+ //
+ // Clear the mask value for the desired Irq pin.
+ //
+
+ InterruptMask = (PIMSK_21164)(&PCR->IrqlMask);
+
+ switch( Irq ){
+
+ case Irq0:
+
+ InterruptMask->Irq0Mask = 0;
+ break;
+
+ case Irq1:
+
+ InterruptMask->Irq1Mask = 0;
+ break;
+
+ case Irq2:
+
+ InterruptMask->Irq2Mask = 0;
+ break;
+
+ case Irq3:
+
+ InterruptMask->Irq3Mask = 0;
+ break;
+
+ } //end switch (Irq)
+
+ //
+ // Set the new masks in the PALcode.
+ //
+
+ InterruptsStarted = (PBOOLEAN)(&PCR->IrqlMask[1]);
+ if( *InterruptsStarted == TRUE ){
+ HalpCachePcrValues( InterruptMask->all );
+ }
+
+ //
+ // Lower Irql to the previous level and return.
+ //
+
+ KeLowerIrql( OldIrql );
+ return;
+
+}
+
+
+VOID
+HalpDisable21164HardwareInterrupt(
+ IN ULONG Irq
+ )
+/*++
+
+Routine Description:
+
+ Set the mask value for the desired Irq pin so that interrupts
+ are disabled from that pin.
+
+Arguments:
+
+ Irq - Supplies the interrupt pin number to be disabled.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PIMSK_21164 InterruptMask;
+ PBOOLEAN InterruptsStarted;
+ KIRQL OldIrql;
+
+ //
+ // Raise Irql to HIGH_LEVEL to prevent any interrupts.
+ //
+
+ KeRaiseIrql( HIGH_LEVEL, &OldIrql );
+
+ //
+ // Set the mask value for the desired Irq pin.
+ //
+
+ InterruptMask = (PIMSK_21164)(&PCR->IrqlMask);
+
+ switch( Irq ){
+
+ case Irq0:
+
+ InterruptMask->Irq0Mask = 1;
+ break;
+
+ case Irq1:
+
+ InterruptMask->Irq1Mask = 1;
+ break;
+
+ case Irq2:
+
+ InterruptMask->Irq2Mask = 1;
+ break;
+
+ case Irq3:
+
+ InterruptMask->Irq3Mask = 1;
+ break;
+
+ } //end switch (Irq)
+
+ //
+ // Set the new masks in the PALcode, if interrupts have been started.
+ //
+
+ InterruptsStarted = (PBOOLEAN)(&PCR->IrqlMask[1]);
+ if( *InterruptsStarted == TRUE ){
+ HalpCachePcrValues( InterruptMask->all );
+ }
+
+ //
+ // Lower Irql to the previous level and return.
+ //
+
+ KeLowerIrql( OldIrql );
+ return;
+
+}
+
+#endif // Used ??
+
+
+ULONG
+HalpGet21164PerformanceVector(
+ IN ULONG BusInterruptLevel,
+ OUT PKIRQL Irql
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the system interrupt vector and IRQL level
+ corresponding to the specified performance counter interrupt.
+
+Arguments:
+
+ BusInterruptLevel - Supplies the performance counter number.
+
+ Irql - Returns the system request priority.
+
+Return Value:
+
+ Returns the system interrupt vector corresponding to the specified device.
+
+--*/
+
+{
+
+ //
+ // Handle the special internal bus defined for the processor itself
+ // and used to control the performance counters in the 21164.
+ //
+
+ *Irql = PROFILE_LEVEL;
+
+ switch( BusInterruptLevel ){
+
+ //
+ // Performance Counter 0
+ //
+
+ case 0:
+
+ return PC0_SECONDARY_VECTOR;
+
+ //
+ // Performance Counter 1
+ //
+
+ case 1:
+
+ return PC1_SECONDARY_VECTOR;
+
+ //
+ // Performance Counter 2
+ //
+
+ case 2:
+
+ return PC2_SECONDARY_VECTOR;
+
+ } //end switch( BusInterruptLevel )
+
+ //
+ // Unrecognized.
+ //
+
+ *Irql = 0;
+ return 0;
+
+}
+
+ULONG
+HalpGet21164CorrectableVector(
+ IN ULONG BusInterruptLevel,
+ OUT PKIRQL Irql
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the system interrupt vector and IRQL level
+ corresponding to the specified correctable interrupt.
+
+Arguments:
+
+ BusInterruptLevel - Supplies the performance counter number.
+
+ Irql - Returns the system request priority.
+
+Return Value:
+
+ Returns the system interrupt vector corresponding to the specified device.
+
+--*/
+
+{
+ //
+ // Get the correctable interrupt vector.
+ //
+
+ if (BusInterruptLevel == 5) {
+
+ //
+ // Correctable error interrupt was sucessfully recognized.
+ //
+
+ *Irql = DEVICE_HIGH_LEVEL;
+ return CORRECTABLE_VECTOR;
+
+
+ } else {
+
+ //
+ // Unrecognized.
+ //
+
+ *Irql = 0;
+ return 0;
+ }
+}
+
diff --git a/private/ntos/nthals/halalpha/ev5ints.s b/private/ntos/nthals/halalpha/ev5ints.s
new file mode 100644
index 000000000..1970c83fe
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ev5ints.s
@@ -0,0 +1,397 @@
+//++
+//
+// Copyright (c) 1994 Microsoft Corporation
+//
+// Module Name:
+//
+// ev5ints.s
+//
+// Abstract:
+//
+// This module implements EV5-specific interrupt handlers.
+// (the performance counters)
+//
+// Author:
+//
+// John Vert (jvert) 15-Nov-1994
+// Steve Brooks 14-Feb-1994 (modified from ev4ints.s)
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+//--
+#include "halalpha.h"
+
+#define PC0_SECONDARY_VECTOR 11
+#define PC1_SECONDARY_VECTOR 13
+#define PC2_SECONDARY_VECTOR 16 // SjBfix. This is actually PC3_VECTOR
+#define PcProfileCount0 PcHalReserved+20
+#define PcProfileCount1 PcProfileCount0+4
+#define PcProfileCount2 PcProfileCount1+4
+#define PcProfileCountReload0 PcProfileCount2+4
+#define PcProfileCountReload1 PcProfileCountReload0+4
+#define PcProfileCountReload2 PcProfileCountReload1+4
+
+ .struct 0
+ .space 8 // reserved for alignment
+PrRa: .space 8 // space for return address
+PrFrameLength: //
+
+ SBTTL("Performance Counter 0 Interrupt")
+//++
+//
+// VOID
+// HalpPerformanceCounter0Interrupt
+// )
+//
+// Routine Description:
+//
+// This function is executed as the result of an interrupt from the
+// internal microprocessor performance counter 0. The interrupt
+// may be used to signal the completion of a profile event.
+// If profiling is current active, the function determines if the
+// profile interval has expired and if so dispatches to the standard
+// system routine to update the system profile time. If profiling
+// is not active then the function performs a secondary dispatch for
+// performance counter 0.
+//
+// Arguments:
+//
+// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for
+// the interrupt.
+//
+// Return Value:
+//
+// TRUE is returned.
+//
+//--
+
+ NESTED_ENTRY(HalpPerformanceCounter0Interrupt, PrFrameLength, zero )
+
+ lda sp, -PrFrameLength(sp) // allocate a stack frame
+ stq ra, PrRa(sp) // save the return address
+
+ PROLOGUE_END //
+
+ call_pal rdpcr // v0 = pcr base address
+
+ ldl t0, PcProfileCount0(v0) // capture the current profile count
+ beq t0, 20f // if eq, profiling not active
+
+//
+// Profiling is active. Decrement the interval count and if it has
+// reached zero then call the kernel profile routine.
+//
+
+ subl t0, 1, t0 // decrement the interval count
+ bne t0, 10f // if ne, interval has not expired
+
+//
+// The profile interval has expired. Reset the profile interval count
+// and process the profile interrupt.
+//
+
+ ldl t0, PcProfileCountReload0(v0) // get the new tick count
+ stl t0, PcProfileCount0(v0) // reset the profile interval count
+
+ ldl a1, HalpProfileSource0
+ bis fp, zero, a0 // pass trap frame pointer
+ ldl t1, __imp_KeProfileInterruptWithSource
+ jsr ra, (t1) // process the profile interrupt
+
+ br zero, 40f // common return
+
+//
+// The profile interval has not expired. Update the decremented count.
+//
+
+10:
+ stl t0, PcProfileCount0(v0) // update profile interval count
+ br zero, 40f // common return
+
+//
+// Profiling is not active. Therefore, this interrupt was caused by
+// a performance counter driver. Deliver a secondary dispatch.
+//
+
+20:
+
+ ldil a0, PC0_SECONDARY_VECTOR // get IDT vector for secondary
+ s4addl a0, v0, a0 // a0 = PCR + IDT index
+ ldl a0, PcInterruptRoutine(a0) // get service routine address
+ jsr ra, (a0) // call interrupt service routine
+
+//
+// Setup for return.
+//
+
+40:
+ ldil v0, TRUE // set return value = TRUE
+ ldq ra, PrRa(sp) // restore return address
+ lda sp, PrFrameLength(sp) // deallocate the stack frame
+ ret zero, (ra) // return
+
+ .end HalpPerformanceCounter0Interrupt
+
+
+ SBTTL("Performance Counter 1 Interrupt")
+//++
+//
+// VOID
+// HalpPerformanceCounter1Interrupt
+// )
+//
+// Routine Description:
+//
+// This function is executed as the result of an interrupt from the
+// internal microprocessor performance counter 1. The interrupt
+// may be used to signal the completion of a profile event.
+// If profiling is current active, the function determines if the
+// profile interval has expired and if so dispatches to the standard
+// system routine to update the system profile time. If profiling
+// is not active then the function performs a secondary dispatch for
+// performance counter 1.
+//
+// Arguments:
+//
+// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for
+// the interrupt.
+//
+// Return Value:
+//
+// TRUE is returned.
+//
+//--
+
+ NESTED_ENTRY(HalpPerformanceCounter1Interrupt, PrFrameLength, zero )
+
+ lda sp, -PrFrameLength(sp) // allocate a stack frame
+ stq ra, PrRa(sp) // save the return address
+
+ PROLOGUE_END //
+
+ call_pal rdpcr // v0 = pcr base address
+
+ ldl t0, PcProfileCount1(v0) // capture the current profile count
+ beq t0, 20f // if eq, profiling not active
+
+//
+// Profiling is active. Decrement the interval count and if it has
+// reached zero then call the kernel profile routine.
+//
+
+ subl t0, 1, t0 // decrement the interval count
+ bne t0, 10f // if ne, interval has not expired
+
+//
+// The profile interval has expired. Reset the profile interval count
+// and process the profile interrupt.
+//
+
+ ldl t0, PcProfileCountReload1(v0) // get the new tick count
+ stl t0, PcProfileCount1(v0) // reset the profile interval count
+
+ ldl a1, HalpProfileSource1
+ bis fp, zero, a0 // pass trap frame pointer
+ ldl t1, __imp_KeProfileInterruptWithSource
+ jsr ra, (t1) // process the profile interrupt
+
+ br zero, 40f // common return
+
+//
+// The profile interval has not expired. Update the decremented count.
+//
+
+10:
+ stl t0, PcProfileCount1(v0) // update profile interval count
+ br zero, 40f // common return
+
+//
+// Profiling is not active. Therefore, this interrupt was caused by
+// a performance counter driver. Deliver a secondary dispatch.
+//
+
+20:
+
+ ldil a0, PC1_SECONDARY_VECTOR // get IDT vector for secondary
+ s4addl a0, v0, a0 // a0 = PCR + IDT index
+ ldl a0, PcInterruptRoutine(a0) // get service routine address
+ jsr ra, (a0) // call interrupt service routine
+
+//
+// Setup for return.
+//
+
+40:
+ ldil v0, TRUE // set return value = TRUE
+ ldq ra, PrRa(sp) // restore return address
+ lda sp, PrFrameLength(sp) // deallocate the stack frame
+ ret zero, (ra) // return
+
+ .end HalpPerformanceCounter1Interrupt
+
+ SBTTL("Performance Counter 2 Interrupt")
+//++
+//
+// VOID
+// HalpPerformanceCounter2Interrupt
+// )
+//
+// Routine Description:
+//
+// This function is executed as the result of an interrupt from the
+// internal microprocessor performance counter 2. The interrupt
+// may be used to signal the completion of a profile event.
+// If profiling is current active, the function determines if the
+// profile interval has expired and if so dispatches to the standard
+// system routine to update the system profile time. If profiling
+// is not active then the function performs a secondary dispatch for
+// performance counter 2.
+//
+// Arguments:
+//
+// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for
+// the interrupt.
+//
+// Return Value:
+//
+// TRUE is returned.
+//
+//--
+
+ NESTED_ENTRY(HalpPerformanceCounter2Interrupt, PrFrameLength, zero )
+
+ lda sp, -PrFrameLength(sp) // allocate a stack frame
+ stq ra, PrRa(sp) // save the return address
+
+ PROLOGUE_END //
+
+ call_pal rdpcr // v0 = pcr base address
+
+ ldl t0, PcProfileCount2(v0) // capture the current profile count
+ beq t0, 20f // if eq, profiling not active
+
+//
+// Profiling is active. Decrement the interval count and if it has
+// reached zero then call the kernel profile routine.
+//
+
+ subl t0, 1, t0 // decrement the interval count
+ bne t0, 10f // if ne, interval has not expired
+
+//
+// The profile interval has expired. Reset the profile interval count
+// and process the profile interrupt.
+//
+
+ ldl t0, PcProfileCountReload2(v0) // get the new tick count
+ stl t0, PcProfileCount2(v0) // reset the profile interval count
+
+ ldl a1, HalpProfileSource2
+ bis fp, zero, a0 // pass trap frame pointer
+ ldl t1, __imp_KeProfileInterruptWithSource
+ jsr ra, (t1) // process the profile interrupt
+
+ br zero, 40f // common return
+
+//
+// The profile interval has not expired. Update the decremented count.
+//
+
+10:
+ stl t0, PcProfileCount2(v0) // update profile interval count
+ br zero, 40f // common return
+
+//
+// Profiling is not active. Therefore, this interrupt was caused by
+// a performance counter driver. Deliver a secondary dispatch.
+//
+
+20:
+
+ ldil a0, PC2_SECONDARY_VECTOR // get IDT vector for secondary
+ s4addl a0, v0, a0 // a0 = PCR + IDT index
+ ldl a0, PcInterruptRoutine(a0) // get service routine address
+ jsr ra, (a0) // call interrupt service routine
+
+//
+// Setup for return.
+//
+
+40:
+ ldil v0, TRUE // set return value = TRUE
+ ldq ra, PrRa(sp) // restore return address
+ lda sp, PrFrameLength(sp) // deallocate the stack frame
+ ret zero, (ra) // return
+
+ .end HalpPerformanceCounter2Interrupt
+
+//++
+//
+// ULONGLONG
+// HalpRead21164PerformanceCounter(
+// VOID
+// )
+//
+// Routine Description:
+//
+// Read the processor performance counter register
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// The current value of the performance counter register.
+//
+//--
+
+ LEAF_ENTRY(HalpRead21164PerformanceCounter)
+
+ bis zero, 1, a1 // indicate read operation
+ call_pal wrperfmon // read the performance counter
+
+ ret zero, (ra) // return to caller
+
+ .end HalpRead21164PerformanceCounter
+
+
+//++
+//
+// VOID
+// HalpWrite21164PerformanceCounter(
+// ULONGLONG PmCtr
+// ULONG CboxMux1
+// ULONG CboxMux2
+// )
+//
+// Routine Description:
+//
+// Write the processor performance counter register
+//
+// Arguments:
+//
+// PmCtr(a0) - value to be written to the performance counter
+// CboxMux1(a1) - value to be written to Cbox mux 1 select (optional)
+// CboxMux2(a2) - value to be written to Cbox mux 2 select (optional)
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpWrite21164PerformanceCounter)
+
+ bis zero, a2, a3 // move arguments up
+ bis zero, a1, a2 //
+ bis zero, zero, a1 // indicate write operation
+ call_pal wrperfmon // write the performance counter
+
+ ret zero, (ra)
+
+ .end HalpWrite21164PerformanceCounter
diff --git a/private/ntos/nthals/halalpha/ev5mchk.c b/private/ntos/nthals/halalpha/ev5mchk.c
new file mode 100644
index 000000000..400c2a95c
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ev5mchk.c
@@ -0,0 +1,677 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ ev5mchk.c
+
+Abstract:
+
+ This module implements generalized machine check handling for
+ platforms based on the DECchip 21164 (EV5) microprocessor.
+
+Author:
+
+ Joe Notarangelo 30-Jun-1994
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "axp21164.h"
+#include "stdio.h"
+
+
+//
+// Declare the extern variable UncorrectableError declared in
+// inithal.c.
+//
+extern PERROR_FRAME PUncorrectableError;
+
+
+VOID
+HalpDisplayLogout21164(
+ IN PLOGOUT_FRAME_21164 LogoutFrame );
+
+BOOLEAN
+HalpPlatformMachineCheck(
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PKEXCEPTION_FRAME ExceptionFrame,
+ IN PKTRAP_FRAME TrapFrame
+ );
+
+VOID
+HalpUpdateMces(
+ IN BOOLEAN ClearMachineCheck,
+ IN BOOLEAN ClearCorrectableError
+ );
+
+//
+// System-wide controls for machine check reporting.
+//
+
+ProcessorCorrectableDisable = FALSE;
+SystemCorrectableDisable = FALSE;
+MachineCheckDisable = FALSE;
+
+//
+// Error counts.
+//
+
+ULONG CorrectableErrors = 0;
+ULONG RetryableErrors = 0;
+
+VOID
+HalpSetMachineCheckEnables(
+ IN BOOLEAN DisableMachineChecks,
+ IN BOOLEAN DisableProcessorCorrectables,
+ IN BOOLEAN DisableSystemCorrectables
+ )
+/*++
+
+Routine Description:
+
+ This function sets the enables that define which machine check
+ errors will be signaled by the processor.
+
+ N.B. - The system has the capability to ignore all machine checks
+ by indicating DisableMachineChecks = TRUE. This is intended
+ for debugging purposes on broken hardware. If you disable
+ this you will get no machine check no matter what error the
+ system/processor detects. Consider the consequences.
+
+Arguments:
+
+ DisableMachineChecks - Supplies a boolean which indicates if all
+ machine checks should be disabled and not
+ reported. (see note above).
+
+ DisableProcessorCorrectables - Supplies a boolean which indicates if
+ processor correctable error reporting
+ should be disabled.
+ DisableSystemCorrectables - Supplies a boolean which indicates if
+ system correctable error reporting
+ should be disabled.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+
+ ProcessorCorrectableDisable = DisableProcessorCorrectables;
+ SystemCorrectableDisable = DisableSystemCorrectables;
+ MachineCheckDisable = DisableMachineChecks;
+
+ HalpUpdateMces( FALSE, FALSE );
+
+ return;
+}
+
+VOID
+HalpUpdateMces(
+ IN BOOLEAN ClearMachineCheck,
+ IN BOOLEAN ClearCorrectableError
+ )
+/*++
+
+Routine Description:
+
+ This function updates the state of the MCES internal processor
+ register.
+
+Arguments:
+
+ ClearMachineCheck - Supplies a boolean that indicates if the machine
+ check indicator in the MCES should be cleared.
+
+ ClearCorrectableError - Supplies a boolean that indicates if the
+ correctable error indicators in the MCES should
+ be cleared.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ MCES Mces;
+
+ Mces.MachineCheck = ClearMachineCheck;
+ Mces.SystemCorrectable = ClearCorrectableError;
+ Mces.ProcessorCorrectable = ClearCorrectableError;
+ Mces.DisableProcessorCorrectable = ProcessorCorrectableDisable;
+ Mces.DisableSystemCorrectable = SystemCorrectableDisable;
+ Mces.DisableMachineChecks = MachineCheckDisable;
+
+ HalpWriteMces( Mces );
+
+}
+
+
+BOOLEAN
+HalMachineCheck (
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PKEXCEPTION_FRAME ExceptionFrame,
+ IN PKTRAP_FRAME TrapFrame
+ )
+/*++
+
+Routine Description:
+
+ This function fields machine check for 21164-based machines.
+
+Arguments:
+
+ ExceptionRecord - Supplies a pointer to the exception record for the
+ machine check. Included in the exception information
+ is the pointer to the logout frame.
+
+ ExceptionFrame - Supplies a pointer to the kernel exception frame.
+
+ TrapFrame - Supplies a pointer to the kernel trap frame.
+
+Return Value:
+
+ A value of TRUE is returned if the machine check has been
+ handled by the HAL. If it has been handled then execution may
+ resume at the faulting address. Otherwise, a value of FALSE
+ is returned.
+
+ N.B. - Under some circumstances this routine may not return at
+ all.
+
+--*/
+
+{
+
+ BOOLEAN Handled;
+ PLOGOUT_FRAME_21164 LogoutFrame;
+ PMCHK_STATUS MachineCheckStatus;
+ MCES Mces;
+ PICPERR_STAT_21164 icPerrStat;
+ PDC_PERR_STAT_21164 dcPerrStat;
+ PSC_STAT_21164 scStat;
+ PEI_STAT_21164 eiStat;
+ BOOLEAN UnhandledPlatformError = FALSE;
+
+ PUNCORRECTABLE_ERROR uncorrerr = NULL;
+ PPROCESSOR_EV5_UNCORRECTABLE ev5uncorr = NULL;
+
+ //
+ // Check for retryable errors. These are usually I-stream parity
+ // errors, which may be retried following a cache flush (the cache
+ // flush is handled by the PAL).
+ //
+
+ MachineCheckStatus =
+ (PMCHK_STATUS)&ExceptionRecord->ExceptionInformation[0];
+
+ //
+ // Handle any retryable errors.
+ //
+
+ if( MachineCheckStatus->Retryable == 1 ){
+
+ //
+ // Log the error.
+ //
+
+ RetryableErrors += 1;
+
+#if (DBG) || (HALDBG)
+
+ if( (RetryableErrors % 32) == 0 ){
+ DbgPrint( "HAL Retryable Errors = %d\n", RetryableErrors );
+ }
+
+#endif //DBG || HALDBG
+
+ //
+ // Acknowledge receipt of the retryable machine check.
+ //
+
+ HalpUpdateMces( TRUE, TRUE );
+
+ return TRUE;
+
+ }
+
+ //
+ // Capture the logout frame pointer.
+ //
+
+ LogoutFrame =
+ (PLOGOUT_FRAME_21164)ExceptionRecord->ExceptionInformation[1];
+
+ //
+ // Check for any hard errors that cannot be dismissed.
+ // They are:
+ // Tag parity error
+ // Tag control parity error
+ // Multiple external errors
+ // Fill ECC error
+ // Fill parity error
+ // Multiple fill errors
+ //
+
+ icPerrStat = (PICPERR_STAT_21164)&LogoutFrame->IcPerrStat;
+ dcPerrStat = (PDC_PERR_STAT_21164)&LogoutFrame->DcPerrStat;
+ scStat = (PSC_STAT_21164)&LogoutFrame->ScStat;
+ eiStat = (PEI_STAT_21164)&LogoutFrame->EiStat;
+
+ if(PUncorrectableError) {
+ //
+ // Fill in the processor specific uncorrectable error frame
+ //
+ uncorrerr = (PUNCORRECTABLE_ERROR)
+ &PUncorrectableError->UncorrectableFrame;
+
+ //
+ // first fill in some generic processor Information.
+ // For the Current (Reporting) Processor.
+ //
+ HalpGetProcessorInfo(&uncorrerr->ReportingProcessor);
+ uncorrerr->Flags.ProcessorInformationValid = 1;
+
+ ev5uncorr = (PPROCESSOR_EV5_UNCORRECTABLE)
+ uncorrerr->RawProcessorInformation;
+ }
+ if(ev5uncorr){
+ ev5uncorr->IcPerrStat = LogoutFrame->IcPerrStat.all;
+ ev5uncorr->DcPerrStat = LogoutFrame->DcPerrStat.all;
+ ev5uncorr->ScStat = LogoutFrame->ScStat.all;
+ ev5uncorr->ScAddr = LogoutFrame->ScAddr.all;
+ ev5uncorr->EiStat = LogoutFrame->EiStat.all;
+ ev5uncorr->BcTagAddr = LogoutFrame->BcTagAddr.all;
+ ev5uncorr->EiAddr = LogoutFrame->EiAddr.all;
+ ev5uncorr->FillSyn = LogoutFrame->FillSyn.all;
+ ev5uncorr->BcConfig = LogoutFrame->BcConfig.all;
+ ev5uncorr->BcControl = LogoutFrame->BcControl.all;
+ }
+
+//
+// SjBfix. The External parity error checking is disabled due to bug
+// Rattler chipset on Gamma which causes the parity error on
+// machine checks due to reads to PCI config space. (fixed in pass 2)
+//
+
+ if ( icPerrStat->Dpe == 1 || icPerrStat->Tpe == 1 ||
+ icPerrStat->Tmr == 1 || dcPerrStat->Lock == 1 ||
+ scStat->ScTperr == 1 || scStat->ScDperr == 1 ||
+ eiStat->BcTperr == 1 || eiStat->BcTcperr == 1 ||
+// eiStat->UncEccErr == 1 || eiStat->EiParErr == 1 ||
+ eiStat->SeoHrdErr == 1 || scStat->ScScndErr == 1 ){
+
+ //
+ // A serious, uncorrectable error has occured, under no circumstances
+ // can it be simply dismissed.
+ //
+
+ goto FatalError;
+
+ }
+
+ //
+ // It is possible that the system has experienced a hard error and
+ // that nonetheless the error is recoverable. This is a system-specific
+ // decision - allow it to be handled as such.
+ //
+
+ UnhandledPlatformError = TRUE;
+ if( (Handled = HalpPlatformMachineCheck(
+ ExceptionRecord,
+ ExceptionFrame,
+ TrapFrame )) == TRUE ){
+
+ //
+ // The system-specific code has handled the error. Dismiss
+ // the error and continue execution.
+ //
+
+ HalpUpdateMces( TRUE, TRUE );
+
+ return TRUE;
+
+ }
+
+//
+// The system has experienced a fatal error that cannot be corrected.
+// Print any possible relevant information and crash the system.
+//
+// N.B. - In the future some of these fatal errors could be potential
+// recovered. Example, a user process gets a fatal error on one
+// of its pages - we kill the user process, mark the page as bad
+// and continue executing.
+//
+
+FatalError:
+
+ uncorrerr->Flags.ErrorStringValid = 1;
+ sprintf(uncorrerr->ErrorString,"Uncorrectable Error From "
+ "Processor Detected");
+ //
+ // Begin the error output if this is a processor error. If this is
+ // an unhandled platform error than that code is responsible for
+ // beginning the error output.
+ //
+
+ if( UnhandledPlatformError == FALSE ){
+
+ //
+ // Acquire ownership of the display. This is done here in case we take
+ // a machine check before the display has been taken away from the HAL.
+ // When the HAL begins displaying strings after it has lost the
+ // display ownership then the HAL will be careful not to scroll
+ // information off of the screen.
+ //
+
+ HalAcquireDisplayOwnership(NULL);
+
+ //
+ // Display the dreaded banner.
+ //
+
+ HalDisplayString( "\nFatal system hardware error.\n\n" );
+
+ }
+
+ //
+ // Display the EV5 logout frame.
+ //
+
+ HalpDisplayLogout21164( LogoutFrame );
+
+ //
+ // Bugcheck to dump the rest of the machine state, this will help
+ // if the machine check is software-related.
+ //
+
+ KeBugCheckEx( DATA_BUS_ERROR,
+ (ULONG)MachineCheckStatus->Correctable,
+ (ULONG)MachineCheckStatus->Retryable,
+ 0,
+ (ULONG)PUncorrectableError );
+
+}
+
+#define MAX_ERROR_STRING 100
+
+VOID
+HalpDisplayLogout21164 (
+ IN PLOGOUT_FRAME_21164 LogoutFrame
+ )
+
+/*++
+
+Routine Description:
+
+ This function displays the logout frame for a 21164.
+
+Arguments:
+
+ LogoutFrame - Supplies a pointer to the logout frame generated
+ by the 21164.
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR OutBuffer[ MAX_ERROR_STRING ];
+
+ sprintf( OutBuffer, "ICSR : %016Lx ICPERR_STAT : %016Lx\n",
+ LogoutFrame->Icsr.all, LogoutFrame->IcPerrStat.all );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "MM_STAT : %016Lx DC_PERR_STAT : %016Lx\n",
+ LogoutFrame->MmStat.all,
+ LogoutFrame->DcPerrStat.all );
+
+ HalDisplayString( OutBuffer );
+
+
+ sprintf( OutBuffer, "PS : %016Lx VA : %016Lx VA_FORM : %016Lx\n",
+ LogoutFrame->Ps,
+ LogoutFrame->Va,
+ LogoutFrame->VaForm );
+
+ HalDisplayString( OutBuffer );
+
+
+ sprintf( OutBuffer, "ISR : %016Lx IPL : %016Lx INTID : %016Lx\n",
+ LogoutFrame->Isr.all,
+ LogoutFrame->Ipl,
+ LogoutFrame->IntId );
+
+ HalDisplayString( OutBuffer );
+
+
+ sprintf( OutBuffer, "SC_STAT : %016Lx SC_CTL : %016Lx SC_ADDR : %016Lx\n",
+ LogoutFrame->ScStat.all,
+ LogoutFrame->ScCtl.all,
+ LogoutFrame->ScAddr.all );
+
+ HalDisplayString( OutBuffer );
+
+
+ sprintf( OutBuffer, "EI_STAT : %016Lx EI_ADDR : %016Lx\n",
+ LogoutFrame->EiStat.all, LogoutFrame->EiAddr.all );
+
+ HalDisplayString( OutBuffer );
+
+
+ sprintf( OutBuffer, "BC_TAG_ADDR : %016Lx FILL_SYN : %016Lx\n",
+ LogoutFrame->BcTagAddr.all, LogoutFrame->FillSyn.all );
+
+
+ HalDisplayString( OutBuffer );
+
+
+ sprintf( OutBuffer, "BC_CONTROL : %016Lx BC_CONFIG : %016Lx\n",
+ LogoutFrame->BcControl.all, LogoutFrame->BcConfig.all );
+
+ HalDisplayString( OutBuffer );
+
+
+ sprintf( OutBuffer, "EXC_ADDR : %016Lx PAL_BASE : %016Lx\n",
+ LogoutFrame->ExcAddr, LogoutFrame->PalBase );
+
+ HalDisplayString( OutBuffer );
+
+ //
+ // Print out interpretation of the error.
+ //
+
+ HalDisplayString( "\n" );
+
+ //
+ // Check for tag parity error.
+ //
+
+ if ( LogoutFrame->IcPerrStat.Dpe == 1 ||
+ LogoutFrame->IcPerrStat.Tpe == 1 ){
+
+ //
+ // Note: The excAddr may contain the address of the instruction
+ // the caused the parity error but it is not guaranteed:
+ //
+ sprintf( OutBuffer, "Icache %s parity error, Addr: %x\n",
+ LogoutFrame->IcPerrStat.Dpe ? "Data" : "Tag",
+ LogoutFrame->ExcAddr );
+
+ HalDisplayString( OutBuffer );
+
+ } else if ( LogoutFrame->DcPerrStat.Lock == 1 ){
+
+ sprintf( OutBuffer, "Dcache %s parity error, Addr: %x\n",
+ LogoutFrame->DcPerrStat.Dp0 || LogoutFrame->DcPerrStat.Dp1 ?
+ "Data" : "Tag",
+ LogoutFrame->Va );
+
+ HalDisplayString( OutBuffer );
+
+ } else if ( LogoutFrame->ScStat.ScTperr != 0 ) {
+
+ sprintf( OutBuffer,
+ "Scache Tag parity error, Addr: %x Tag: %x Cmd: %x\n",
+ LogoutFrame->ScAddr.ScAddr,
+ LogoutFrame->ScStat.ScTperr,
+ LogoutFrame->ScStat.CboxCmd);
+
+ HalDisplayString( OutBuffer );
+
+
+ } else if ( LogoutFrame->ScStat.ScDperr != 0 ) {
+
+ sprintf( OutBuffer,
+ "Scache Data parity error, Addr: %x Tag: %x Cmd: %x\n",
+ LogoutFrame->ScAddr.ScAddr,
+ LogoutFrame->ScStat.ScDperr,
+ LogoutFrame->ScStat.CboxCmd);
+
+ HalDisplayString( OutBuffer );
+
+
+ } else if ( LogoutFrame->EiStat.BcTperr == 1 ||
+ LogoutFrame->EiStat.BcTcperr == 1 ){
+
+ sprintf( OutBuffer,
+ "Bcache Tag Parity error, Addr: %x Tag: %x\n",
+ LogoutFrame->EiAddr.EiAddr,
+ LogoutFrame->BcTagAddr.Tag1);
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for timeout reset error:
+ //
+
+ if ( LogoutFrame->IcPerrStat.Tmr == 1 ){
+
+ sprintf( OutBuffer, "Timeout Reset Error\n" );
+
+ HalDisplayString( OutBuffer );
+ }
+
+ //
+ // Check for fill ECC errors.
+ //
+
+ if( LogoutFrame->EiStat.UncEccErr == 1 ){
+
+ sprintf( OutBuffer, "Uncorrectable ECC error: %s\n",
+ LogoutFrame->EiStat.FilIrd ? "Icache Fill" : "Dcache Fill" );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer,
+ "PA: %16Lx Longword0: %x Longword1: %x\n",
+ LogoutFrame->EiAddr.EiAddr,
+ LogoutFrame->FillSyn.Lo,
+ LogoutFrame->FillSyn.Hi );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for address/command parity error
+ //
+
+ if( LogoutFrame->EiStat.EiParErr == 1 ){
+
+ sprintf( OutBuffer, "Address/Command parity error, Addr=%x\n",
+ LogoutFrame->EiAddr.EiAddr );
+
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for multiple hard errors.
+ //
+
+ if ( LogoutFrame->ScStat.ScScndErr == 1 ){
+
+ HalDisplayString( "Multiple Scache parity errors detected.\n" );
+ }
+
+ if( LogoutFrame->EiStat.SeoHrdErr == 1 ){
+
+ HalDisplayString( "Multiple external/tag errors detected.\n" );
+
+ }
+
+ return;
+}
+
+
+BOOLEAN
+Halp21164CorrectedErrorInterrupt (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This is the interrupt handler for the 21164 processor corrected error
+ interrupt.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Handle any processor correctable errors.
+ //
+
+
+ //
+ // Log the error.
+ //
+ // simply assume this was a fill ecc correctable for now, print
+ // a debug message periodically
+
+ CorrectableErrors += 1;
+
+#if 0 //jnfix
+#if (DBG) || (HALDBG)
+
+ if( (CorrectableErrors % 32) == 0 ){
+ DbgPrint( "Correctable errors = %d\n", CorrectableErrors );
+ }
+
+#endif //DBG || HALDBG
+#endif //0 jnfix
+
+ //
+ // Acknowledge receipt of the correctable error by clearing
+ // the error in the MCES register.
+ //
+
+ HalpUpdateMces( FALSE, TRUE );
+
+ return TRUE;
+
+}
diff --git a/private/ntos/nthals/halalpha/ev5mem.s b/private/ntos/nthals/halalpha/ev5mem.s
new file mode 100644
index 000000000..bd82d7f52
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ev5mem.s
@@ -0,0 +1,231 @@
+// TITLE("EV5 Memory Operations")
+//++
+//
+// Copyright (c) 1994 Digital Equipment Corporation
+//
+// Module Name:
+//
+// ev5mem.s
+//
+// Abstract:
+//
+// This module implements EV5 memory operations that require assembly
+// language.
+//
+// Author:
+//
+// Joe Notarangelo 30-Jun-1994
+//
+// Environment:
+//
+// HAL, Kernel mode only.
+//
+// Revision History:
+//
+//--
+
+#include "ksalpha.h"
+
+
+//++
+//
+// VOID
+// HalZeroPage (
+// IN PVOID NewColor,
+// IN PVOID OldColor,
+// IN ULONG PageFrame
+// )
+//
+// Routine Description:
+//
+// This function zeros a page of memory.
+//
+// Arguments:
+//
+// NewColor (a0) - Supplies the page aligned virtual address of the
+// new color of the page that is zeroed.
+//
+// OldColor (a1) - Supplies the page aligned virtual address of the
+// old color of the page that is zeroed.
+//
+// PageFrame (a2) - Supplies the page frame number of the page that
+// is zeroed.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalZeroPage)
+
+ .set noreorder // hand scheduled
+
+#define ZERO_BLOCK_SIZE (256)
+#define ZERO_LOOPS (PAGE_SIZE/ZERO_BLOCK_SIZE)
+
+//
+// Map the page via the 43-bit super-page on EV5.
+//
+
+ ldiq t0, -0x4000 // 0xffff ffff ffff c000
+ sll a2, PAGE_SHIFT, t1 // physical address of page
+
+ sll t0, 28, t0 // 0xffff fc00 0000 0000
+ ldil t2, ZERO_LOOPS // set count of loops to run
+
+ bis t0, t1, t0 // set super-page enable + physical
+ br zero, 10f // start the zeroing
+
+//
+// Zero the page in a loop, zeroing 256 bytes per iteration. This number
+// was chosen to tradeoff loop overhead versus the overhead of fetching
+// Icache blocks.
+//
+
+ .align 4 // align as branch target
+10:
+ stq zero, 0x00(t0) //
+ subl t2, 1, t2 // decrement the loop count
+
+ stq zero, 0x08(t0) //
+ stq zero, 0x10(t0) //
+
+ stq zero, 0x18(t0) //
+ stq zero, 0x20(t0) //
+
+ stq zero, 0x28(t0) //
+ stq zero, 0x30(t0) //
+
+ stq zero, 0x38(t0) //
+ stq zero, 0x40(t0) //
+
+ stq zero, 0x48(t0) //
+ stq zero, 0x50(t0) //
+
+ stq zero, 0x58(t0) //
+ stq zero, 0x60(t0) //
+
+ stq zero, 0x68(t0) //
+ stq zero, 0x70(t0) //
+
+ stq zero, 0x78(t0) //
+ stq zero, 0x80(t0) //
+
+ stq zero, 0x88(t0) //
+ stq zero, 0x90(t0) //
+
+ stq zero, 0x98(t0) //
+ stq zero, 0xa0(t0) //
+
+ stq zero, 0xa8(t0) //
+ stq zero, 0xb0(t0) //
+
+ stq zero, 0xb8(t0) //
+ bis t0, zero, t1 // copy base register
+
+ stq zero, 0xc0(t0) //
+ stq zero, 0xc8(t0) //
+
+ stq zero, 0xd0(t0) //
+ stq zero, 0xd8(t0) //
+
+ stq zero, 0xe0(t0) //
+ lda t0, 0x100(t0) // increment to next block
+
+ stq zero, 0xe8(t1) //
+ stq zero, 0xf0(t1) //
+
+ stq zero, 0xf8(t1) // use stt for dual issue with bne
+ bne t2, 10b // while count > 0
+
+ ret zero, (ra) // return
+
+
+ .set reorder //
+
+ .end HalZeroPage
+
+//++
+//
+// ULONGLONG
+// EV5_READ_PHYSICAL (
+// IN ULONGLONG Physical
+// )
+//
+// Routine Description:
+//
+// This function reads a 64 bit value from the specified physical address
+// The intended use of this function is to read the EV-5 C-Box registers,
+// which reside in uncached memory space.
+//
+// Arguments:
+//
+// Physical (a0) - Supplies the physical address from which to read
+//
+// Return Value:
+//
+// v0 - 64 bit value read from the specified physical address
+//
+//--
+
+ LEAF_ENTRY(READ_EV5_PHYSICAL)
+
+//
+// Create superpage address:
+//
+ ldiq t0, -0x4000 // 0xffff ffff ffff c000
+ sll t0, 28, t0 // 0xffff fc00 0000 0000
+
+ bis a0, t0, t0
+ ldq v0, 0(t0) // get the quadword
+
+ ret zero, (ra)
+
+ .end READ_EV5_PHYSICAL
+
+
+//++
+//
+// VOID
+// WRITE_EV5_PHYSICAL (
+// IN ULONGLONG Physical,
+// IN ULONGLONG Value
+// )
+//
+// Routine Description:
+//
+// This function writes a 64 bit value to the specified physical address.
+// The intended use of this function is to write the EV-5 C-Box registers,
+// which reside in uncached memory space.
+//
+// Arguments:
+//
+// Physical (a0) - Supplies the physical address to write
+//
+// Value (a1) - Supplies the value to write
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_EV5_PHYSICAL)
+
+//
+// Create superpage address:
+//
+ ldiq t0, -0x4000 // 0xffff ffff ffff c000
+ sll t0, 28, t0 // 0xffff fc00 0000 0000
+
+ bis a0, t0, t0
+ stq a1, 0(t0) // write the value
+ mb // order the write
+ mb // for sure, for sure
+
+ ret zero, (ra)
+
+ .end WRITE_EV5_PHYSICAL
+
+
diff --git a/private/ntos/nthals/halalpha/ev5prof.c b/private/ntos/nthals/halalpha/ev5prof.c
new file mode 100644
index 000000000..d5bab69aa
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ev5prof.c
@@ -0,0 +1,741 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ ev5prof.c
+
+Abstract:
+
+ This module implements the Profile Counter using the performance
+ counters within the EV5 core. This module is appropriate for all
+ machines based on microprocessors using the EV5 core.
+
+ N.B. - This module assumes that all processors in a multiprocessor
+ system are running the microprocessor at the same clock speed.
+
+Author:
+
+ Steve Brooks 14-Feb-1995 (adapted from ev4prof.c)
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "axp21164.h"
+
+
+//
+// Define space in the HAL-reserved part of the PCR structure for each
+// performance counter's interval count
+//
+// Note that ev5ints.s depends on these positions in the PCR.
+//
+#define PCRProfileCount ((PULONG)(HAL_PCR->ProfileCount.ProfileCount))
+#define PCRProfileCountReload ((PULONG)(&HAL_PCR->ProfileCount.ProfileCountReload))
+
+
+//
+// Define the currently selected profile source for each counter
+//
+KPROFILE_SOURCE HalpProfileSource0;
+KPROFILE_SOURCE HalpProfileSource1;
+KPROFILE_SOURCE HalpProfileSource2;
+
+#define INTERVAL_DELTA (10)
+
+//
+// Define the mapping between possible profile sources and the
+// CPU-specific settings.
+//
+typedef struct _HALP_PROFILE_MAPPING {
+ BOOLEAN Supported;
+ ULONG MuxControl;
+ ULONG Counter;
+ ULONG EventCount;
+ ULONG NumberOfTicks;
+} HALP_PROFILE_MAPPING, *PHALP_PROFILE_MAPPING;
+
+HALP_PROFILE_MAPPING HalpProfileMapping[ProfileMaximum] =
+{
+ {TRUE, Ev5Cycles, Ev5PerformanceCounter0, Ev5CountEvents2xx16, 10},
+ {FALSE, 0,0,0,0},
+ {TRUE, Ev5Instructions, Ev5PerformanceCounter0, Ev5CountEvents2xx16, 10},
+ {TRUE, Ev5PipeDry, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
+ {TRUE, Ev5LoadsIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
+ {FALSE, 0,0,0,0},
+ {TRUE, Ev5AllFlowIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
+ {TRUE, Ev5NonIssue, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
+ {TRUE, Ev5DcacheLDMisses, Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10},
+ {TRUE, Ev5IcacheRFBMisses, Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10},
+ {FALSE, 0,0,0,0},
+ {TRUE, Ev5BRMispredicts, Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10},
+ {TRUE, Ev5StoresIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
+ {TRUE, Ev5FPOpsIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
+ {TRUE, Ev5IntOpsIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
+ {TRUE, Ev5DualIssue, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
+ {TRUE, Ev5TripleIssue, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
+ {TRUE, Ev5QuadIssue, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
+ {FALSE, 0,0,0,0},
+ {TRUE, Ev5Cycles, Ev5PerformanceCounter0, Ev5CountEvents2xx16, 10},
+ {TRUE, Ev5IcacheIssued, Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
+ {TRUE, Ev5DcacheAccesses,Ev5PerformanceCounter1, Ev5CountEvents2xx16, 10},
+ {TRUE, Ev5MBStallCycles, Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10},
+ {TRUE, Ev5LDxLInstIssued,Ev5PerformanceCounter2, Ev5CountEvents2xx14, 10}
+};
+
+BOOLEAN
+HalQueryProfileInterval(
+ IN KPROFILE_SOURCE Source
+ );
+
+NTSTATUS
+HalSetProfileSourceInterval(
+ IN KPROFILE_SOURCE ProfileSource,
+ IN OUT ULONG *Interval
+ );
+
+VOID
+HalpUpdatePerformanceCounter(
+ IN ULONG PerformanceCounter,
+ IN ULONG MuxControl,
+ IN ULONG EventCount
+ );
+
+
+NTSTATUS
+HalpProfileSourceInformation (
+ OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG ReturnedLength
+ )
+/*++
+
+Routine Description:
+
+ Returns the HAL_PROFILE_SOURCE_INFORMATION for this processor.
+
+Arguments:
+
+ Buffer - output buffer
+ BufferLength - length of buffer on input
+ ReturnedLength - The length of data returned
+
+Return Value:
+
+ STATUS_SUCCESS
+ STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
+ currently needed.
+
+--*/
+{
+ PHAL_PROFILE_SOURCE_INFORMATION SourceInfo;
+ NTSTATUS Status;
+
+
+ if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INFORMATION)) {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ return Status;
+ }
+
+ SourceInfo = (PHAL_PROFILE_SOURCE_INFORMATION)Buffer;
+ SourceInfo->Supported = HalQueryProfileInterval(SourceInfo->Source);
+
+ if (SourceInfo->Supported) {
+ SourceInfo->Interval =
+ HalpProfileMapping[SourceInfo->Source].EventCount *
+ HalpProfileMapping[SourceInfo->Source].NumberOfTicks;
+ }
+
+ Status = STATUS_SUCCESS;
+ return Status;
+}
+
+NTSTATUS
+HalpProfileSourceInterval (
+ OUT PVOID Buffer,
+ IN ULONG BufferLength
+ )
+/*++
+
+Routine Description:
+
+ Returns the HAL_PROFILE_SOURCE_INTERVAL for this processor.
+
+Arguments:
+
+ Buffer - output buffer
+ BufferLength - length of buffer on input
+
+Return Value:
+
+ STATUS_SUCCESS
+ STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
+ currently needed.
+
+--*/
+{
+ PHAL_PROFILE_SOURCE_INTERVAL Interval;
+ NTSTATUS Status;
+
+
+ if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INTERVAL)) {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ return Status;
+ }
+
+ Interval = (PHAL_PROFILE_SOURCE_INTERVAL)Buffer;
+ Status = HalSetProfileSourceInterval(Interval->Source,
+ &Interval->Interval);
+ return Status;
+}
+
+VOID
+HalpInitializeProfiler(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine is called during initialization to initialize profiling
+ for each processor in the system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ //
+ // Establish the profile interrupt as the interrupt handler for
+ // all performance counter interrupts.
+ //
+
+ PCR->InterruptRoutine[PC0_VECTOR] = HalpPerformanceCounter0Interrupt;
+ PCR->InterruptRoutine[PC1_VECTOR] = HalpPerformanceCounter1Interrupt;
+ PCR->InterruptRoutine[PC2_VECTOR] = HalpPerformanceCounter2Interrupt;
+
+ return;
+
+}
+
+
+BOOLEAN
+HalQueryProfileInterval(
+ IN KPROFILE_SOURCE Source
+ )
+
+/*++
+
+Routine Description:
+
+ Given a profile source, returns whether or not that source is
+ supported.
+
+Arguments:
+
+ Source - Supplies the profile source
+
+Return Value:
+
+ TRUE - Profile source is supported
+
+ FALSE - Profile source is not supported
+
+--*/
+
+{
+ if (Source > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) {
+ return(FALSE);
+ }
+
+ return(HalpProfileMapping[Source].Supported);
+}
+
+
+NTSTATUS
+HalSetProfileSourceInterval(
+ IN KPROFILE_SOURCE ProfileSource,
+ IN OUT ULONG *Interval
+ )
+
+/*++
+
+Routine Description:
+
+ Sets the profile interval for a specified profile source
+
+Arguments:
+
+ ProfileSource - Supplies the profile source
+
+ Interval - Supplies the specified profile interval
+ Returns the actual profile interval
+
+Return Value:
+
+ NTSTATUS
+
+--*/
+
+{
+ ULONG FastTickPeriod;
+ ULONG SlowTickPeriod;
+ ULONG TickPeriod;
+ ULONG FastCountEvents;
+ ULONG SlowCountEvents;
+ ULONGLONG CountEvents;
+ ULONGLONG TempInterval;
+
+ if (!HalQueryProfileInterval(ProfileSource)) {
+ return(STATUS_NOT_IMPLEMENTED);
+ }
+
+ if (ProfileSource == ProfileTime) {
+
+ //
+ // Convert the clock tick period (in 100ns units ) into
+ // a cycle count period
+ //
+
+ CountEvents = ((ULONGLONG)(*Interval) * 100000) / PCR->CycleClockPeriod;
+ } else {
+ CountEvents = (ULONGLONG)*Interval;
+ }
+
+ FastCountEvents = Ev5CountEvents2xx8;
+ SlowCountEvents = Ev5CountEvents2xx16;
+
+ if (HalpProfileMapping[ProfileSource].Counter == Ev5PerformanceCounter0) {
+ FastCountEvents = Ev5CountEvents2xx16;
+ }
+ else if (HalpProfileMapping[ProfileSource].Counter == Ev5PerformanceCounter2) {
+ SlowCountEvents = Ev5CountEvents2xx14;
+ }
+
+ //
+ // Limit the interval to the smallest interval we can time.
+ //
+ if (CountEvents < FastCountEvents) {
+ CountEvents = (ULONGLONG)FastCountEvents;
+ }
+
+ //
+ // Assume we will use the fast event count
+ //
+ HalpProfileMapping[ProfileSource].EventCount = FastCountEvents;
+ HalpProfileMapping[ProfileSource].NumberOfTicks =
+ (ULONG)((CountEvents + FastCountEvents - 1) / FastCountEvents);
+
+ //
+ // See if we can successfully use the slower period. If the requested
+ // interval is greater than the slower tick period and the difference
+ // between the requested interval and the interval that we can deliver
+ // with the slower clock is acceptable, then use the slower clock.
+ // We define an acceptable difference as a difference of less than
+ // INTERVAL_DELTA of the requested interval.
+ //
+ if (CountEvents > SlowCountEvents) {
+ ULONG NewInterval;
+
+ NewInterval = (ULONG)(((CountEvents + SlowCountEvents-1) /
+ SlowCountEvents) * SlowCountEvents);
+ if (((NewInterval - CountEvents) * 100 / CountEvents) < INTERVAL_DELTA) {
+ HalpProfileMapping[ProfileSource].EventCount = SlowCountEvents;
+ HalpProfileMapping[ProfileSource].NumberOfTicks = NewInterval / SlowCountEvents;
+ }
+ }
+
+ *Interval = HalpProfileMapping[ProfileSource].EventCount *
+ HalpProfileMapping[ProfileSource].NumberOfTicks;
+
+ if (ProfileSource == ProfileTime) {
+ //
+ // Convert cycle count back into 100ns clock ticks
+ //
+ // Use 64-bit integer to prevent overflow.
+ //
+ TempInterval = (ULONGLONG)(*Interval) * (ULONGLONG)(PCR->CycleClockPeriod);
+ *Interval = (ULONG)(TempInterval / 100000);
+ }
+ return(STATUS_SUCCESS);
+}
+
+
+ULONG
+HalSetProfileInterval (
+ IN ULONG Interval
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the profile interrupt interval.
+
+Arguments:
+
+ Interval - Supplies the desired profile interval in 100ns units.
+
+Return Value:
+
+ The actual profile interval.
+
+--*/
+
+{
+ ULONG NewInterval;
+
+ NewInterval = Interval;
+ HalSetProfileSourceInterval(ProfileTime, &NewInterval);
+ return(NewInterval);
+}
+
+
+
+VOID
+HalStartProfileInterrupt (
+ KPROFILE_SOURCE ProfileSource
+ )
+
+/*++
+
+Routine Description:
+
+ This routine turns on the profile interrupt.
+
+ N.B. This routine must be called at PROCLK_LEVEL while holding the
+ profile lock.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG PerformanceCounter;
+ ULONG MuxControl;
+ ULONG EventCount;
+
+ //
+ // Check input to see if we are turning on a source that is
+ // supported. If it is unsupported, just return.
+ //
+
+ if ((ProfileSource > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) ||
+ (!HalpProfileMapping[ProfileSource].Supported)) {
+ return;
+ }
+
+ //
+ // Set the performance counter within the processor to begin
+ // counting total cycles.
+ //
+ PerformanceCounter = HalpProfileMapping[ProfileSource].Counter;
+ MuxControl = HalpProfileMapping[ProfileSource].MuxControl;
+
+ if (PerformanceCounter == Ev5PerformanceCounter0) {
+
+ EventCount = (HalpProfileMapping[ProfileSource].EventCount ==
+ Ev5CountEvents2xx16) ? Ev5EventCountLow
+ : Ev5EventCountHigh;
+
+ HalpProfileSource0 = ProfileSource;
+ HalpUpdatePerformanceCounter( PerformanceCounter,
+ MuxControl,
+ EventCount );
+
+ PCRProfileCountReload[0] = HalpProfileMapping[ProfileSource].NumberOfTicks;
+ PCRProfileCount[0] = HalpProfileMapping[ProfileSource].NumberOfTicks;
+
+ //
+ // Enable the performance counter interrupt.
+ //
+
+ HalEnableSystemInterrupt ( PC0_VECTOR,
+ PROFILE_LEVEL,
+ LevelSensitive );
+
+
+ } else if (PerformanceCounter == Ev5PerformanceCounter1) {
+
+ EventCount = (HalpProfileMapping[ProfileSource].EventCount ==
+ Ev5CountEvents2xx16) ? Ev5EventCountLow
+ : Ev5EventCountHigh;
+
+ HalpProfileSource1 = ProfileSource;
+ HalpUpdatePerformanceCounter( PerformanceCounter,
+ MuxControl,
+ EventCount );
+
+ PCRProfileCountReload[1] = HalpProfileMapping[ProfileSource].NumberOfTicks;
+ PCRProfileCount[1] = HalpProfileMapping[ProfileSource].NumberOfTicks;
+
+ //
+ // Enable the performance counter interrupt.
+ //
+
+ HalEnableSystemInterrupt ( PC1_VECTOR,
+ PROFILE_LEVEL,
+ LevelSensitive );
+
+ } else if (PerformanceCounter == Ev5PerformanceCounter2) {
+
+ EventCount = (HalpProfileMapping[ProfileSource].EventCount ==
+ Ev5CountEvents2xx14) ? Ev5EventCountLow
+ : Ev5EventCountHigh;
+
+ HalpProfileSource2 = ProfileSource;
+ HalpUpdatePerformanceCounter( PerformanceCounter,
+ MuxControl,
+ EventCount );
+
+ PCRProfileCountReload[2] = HalpProfileMapping[ProfileSource].NumberOfTicks;
+ PCRProfileCount[2] = HalpProfileMapping[ProfileSource].NumberOfTicks;
+
+ //
+ // Enable the performance counter interrupt.
+ //
+
+ HalEnableSystemInterrupt ( PC2_VECTOR,
+ PROFILE_LEVEL,
+ LevelSensitive );
+ }
+
+ return;
+}
+
+
+VOID
+HalStopProfileInterrupt (
+ KPROFILE_SOURCE ProfileSource
+ )
+
+/*++
+
+Routine Description:
+
+ This routine turns off the profile interrupt.
+
+ N.B. This routine must be called at PROCLK_LEVEL while holding the
+ profile lock.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG PerformanceCounter;
+ ULONG Vector;
+
+ //
+ // Check input to see if we are turning off a source that is
+ // supported. If it is unsupported, just return.
+ //
+
+ if ((ProfileSource > (sizeof(HalpProfileMapping)/sizeof(HALP_PROFILE_MAPPING))) ||
+ (!HalpProfileMapping[ProfileSource].Supported)) {
+ return;
+ }
+
+ //
+ // Stop the performance counter from interrupting.
+ //
+
+ PerformanceCounter = HalpProfileMapping[ProfileSource].Counter;
+ HalpUpdatePerformanceCounter( PerformanceCounter,
+ 0,
+ Ev5CounterDisable );
+
+ //
+ // Disable the performance counter interrupt.
+ //
+ if (PerformanceCounter == Ev5PerformanceCounter0) {
+
+ HalDisableSystemInterrupt( PC0_VECTOR, PROFILE_LEVEL );
+
+ //
+ // Clear the current profile count. Can't clear value in PCR
+ // since a profile interrupt could be pending or in progress
+ // so clear the reload counter.
+ //
+
+ PCRProfileCountReload[0] = 0;
+
+ } else if (PerformanceCounter == Ev5PerformanceCounter1) {
+
+ HalDisableSystemInterrupt( PC1_VECTOR, PROFILE_LEVEL );
+
+ //
+ // Clear the current profile count. Can't clear value in PCR
+ // since a profile interrupt could be pending or in progress
+ // so clear the reload counter.
+ //
+
+ PCRProfileCountReload[1] = 0;
+
+ } else if (PerformanceCounter == Ev5PerformanceCounter2) {
+
+ HalDisableSystemInterrupt( PC2_VECTOR, PROFILE_LEVEL );
+
+ //
+ // Clear the current profile count. Can't clear value in PCR
+ // since a profile interrupt could be pending or in progress
+ // so clear the reload counter.
+ //
+
+ PCRProfileCountReload[2] = 0;
+ }
+
+ return;
+}
+
+
+VOID
+HalpUpdatePerformanceCounter(
+ IN ULONG PerformanceCounter,
+ IN ULONG MuxControl,
+ IN ULONG EventCount
+ )
+//++
+//
+// Routine Description:
+//
+// Write the specified microprocessor internal performance counter.
+//
+// Arguments:
+//
+// PerformanceCounter(a0) - Supplies the number of the performance counter
+// to write.
+//
+// MuxControl(a2) - Supplies the mux control value which selects which
+// type of event to count when the counter is enabled.
+//
+// EventCount(a3) - Supplies the event interval when the counter is
+// enabled.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+{
+ PMCTR_21164 PmCtr; // the performance counter register
+ ULONG CboxMux1 = 0; // CBOX select 1 mux value
+ ULONG CboxMux2 = 0; // CBOX select 2 mux value
+
+ PmCtr.all = HalpRead21164PerformanceCounter();
+
+ //
+ // Check for special values first:
+ //
+
+ if ( MuxControl >= Ev5PcSpecial ) {
+
+ switch( MuxControl ) {
+
+ //
+ // Count JsrRet Issued
+ //
+
+ case Ev5JsrRetIssued:
+
+ PmCtr.Ctl1 = EventCount;
+ PmCtr.Sel1 = Ev5FlowChangeInst;
+ PmCtr.Sel2 = Ev5PCMispredicts;
+ break;
+
+ //
+ // Count CondBr Issued
+ //
+
+ case Ev5CondBrIssued:
+
+ PmCtr.Ctl1 = EventCount;
+ PmCtr.Sel1 = Ev5FlowChangeInst;
+ PmCtr.Sel2 = Ev5BRMispredicts;
+ break;
+
+ //
+ // Count all flow change inst Issued
+ //
+
+ case Ev5AllFlowIssued:
+
+ PmCtr.Ctl1 = EventCount;
+ PmCtr.Sel1 = Ev5FlowChangeInst;
+
+ if ( (PmCtr.Sel2 == Ev5PCMispredicts) ||
+ (PmCtr.Sel2 == Ev5BRMispredicts)) {
+
+ PmCtr.Sel2 = Ev5LongStalls;
+
+ }
+ break;
+
+ //
+ // Must be an Scache counter. Select the appropriate counter
+ // in Sel1 or Sel2, and pass the CBOX mux value to WritePerfCounter
+ //
+
+ default:
+
+ if ( MuxControl <= Ev5ScSystemCmdReq ) {
+
+ PmCtr.Ctl1 = EventCount;
+ PmCtr.Sel1 = Ev5CBOXInput1;
+ CboxMux1 = MuxControl - Ev5ScMux1;
+
+ } else if ( MuxControl <= Ev5ScSysReadReq ) {
+
+ PmCtr.Ctl2 = EventCount;
+ PmCtr.Sel2 = Ev5CBOXInput2;
+ CboxMux2 = MuxControl - Ev5ScMux2;
+
+ }
+
+ } // switch
+
+ } else if ( PerformanceCounter == Ev5PerformanceCounter0 ) {
+
+ PmCtr.Ctl0 = EventCount;
+ PmCtr.Sel0 = MuxControl;
+
+ } else if ( PerformanceCounter == Ev5PerformanceCounter1 ) {
+
+ PmCtr.Ctl1 = EventCount;
+ PmCtr.Sel1 = MuxControl;
+
+ } else if ( PerformanceCounter == Ev5PerformanceCounter2 ) {
+
+ PmCtr.Ctl2 = EventCount;
+ PmCtr.Sel2 = MuxControl;
+
+ }
+
+ HalpWrite21164PerformanceCounter(PmCtr.all, CboxMux1, CboxMux2);
+}
diff --git a/private/ntos/nthals/halalpha/flash8k.c b/private/ntos/nthals/halalpha/flash8k.c
new file mode 100644
index 000000000..96d198845
--- /dev/null
+++ b/private/ntos/nthals/halalpha/flash8k.c
@@ -0,0 +1,323 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ flash8k.c
+
+Abstract:
+
+ This module implements the flash-specific, device-independent routines
+ necessary to Read and Write the flash ROM containing the system environment
+ variables. The routines implemented here are:
+
+ HalpReadNVRamBuffer() - copy data from Flash into memory
+ HalpWriteNVRamBuffer() - write memory data to Flash
+ HalpCopyNVRamBuffer() - stubbed for compatibility with NVRAM
+
+Author:
+
+ Steve Brooks 5-Oct 93
+
+
+Revision History:
+
+
+--*/
+
+
+#include "halp.h"
+#include "flash8k.h"
+
+#include "arccodes.h"
+
+//
+// Variables:
+//
+// PFLASH_DRIVER HalpFlashDriver
+// Pointer to the device-specific flash driver.
+//
+PFLASH_DRIVER HalpFlashDriver = NULL;
+
+//
+// Flash Drivers
+//
+// Each platform which uses this module must define FlashDriverList as an
+// array of pointers to the initialize functions of any flash drivers for
+// which the flash device might be used for the environment in the system.
+//
+extern PFLASH_DRIVER (*FlashDriverList[])(PUCHAR);
+
+
+#ifdef AXP_FIRMWARE
+
+#pragma alloc_text(DISTEXT, HalpReadNVRamBuffer )
+#pragma alloc_text(DISTEXT, HalpWriteNVRamBuffer )
+#pragma alloc_text(DISTEXT, HalpCopyNVRamBuffer )
+#pragma alloc_text(DISTEXT, HalpInitializeFlashDriver )
+
+#endif
+
+ARC_STATUS HalpReadNVRamBuffer (
+ OUT PCHAR DataPtr,
+ IN PCHAR NvRamPtr,
+ IN ULONG Length )
+
+/*++
+
+Routine Description:
+
+ This routine Reads data from the NVRam into main memory
+
+Arguments:
+
+ DataPtr - Pointer to memory location to receive data
+ NvRamPtr - Pointer (qva) to NVRam location to read data from
+ Length - Number of bytes of data to transfer
+
+Return Value:
+
+ ESUCCESS if the operation succeeds.
+ ENODEV if no flash driver is loaded
+
+--*/
+{
+ //
+ // If there is no flash driver, return an error.
+ //
+ if ((HalpFlashDriver == NULL) &&
+ ((HalpFlashDriver = HalpInitializeFlashDriver(NvRamPtr)) == NULL)) {
+
+ return ENODEV;
+ }
+
+ //
+ // Read from the flash.
+ //
+ while(Length--) {
+ *DataPtr = HalpFlash8kReadByte(NvRamPtr);
+ DataPtr++;
+ NvRamPtr++;
+ }
+
+ return ESUCCESS;
+}
+
+//
+//
+//
+ARC_STATUS
+HalpWriteNVRamBuffer (
+ IN PCHAR NvRamPtr,
+ IN PCHAR DataPtr,
+ IN ULONG Length )
+
+/*++
+
+Routine Description:
+
+ This routine Writes data from memory into the NVRam
+
+Arguments:
+
+ NvRamPtr - Pointer (qva) to NVRam location to write data into
+ DataPtr - Pointer to memory location of data to be written
+ Length - Number of bytes of data to transfer
+
+Return Value:
+
+ ESUCCESS if the operation succeeds.
+ ENODEV if no flash driver is loaded
+ EIO if a device error was detected
+
+--*/
+{
+ ARC_STATUS ReturnStatus = ESUCCESS;
+ UCHAR NeedToErase = FALSE;
+ UCHAR Byte;
+ ULONG Index;
+ ULONG Address;
+
+ //
+ // If there is no flash driver, return an error.
+ //
+ if ((HalpFlashDriver == NULL) &&
+ ((HalpFlashDriver = HalpInitializeFlashDriver(NvRamPtr)) == NULL)) {
+
+ return ENODEV;
+ }
+
+ //
+ // Try to do the udate without erasing the flash block if possible.
+ // We don't write bytes which agree with the current contents of the
+ // flash. If the byte to be written is not the same as what is already
+ // in the flash, write it if the new byte can overwrite the old byte.
+ // On the first byte that cannot be overwritten, abort this loop with
+ // NeedToErase == TRUE and fall through to the failsafe case below.
+ //
+ NeedToErase = FALSE;
+ for(Index = Length;
+ !NeedToErase && (ReturnStatus == ESUCCESS) && Index--;) {
+
+ Address = (ULONG)NvRamPtr + Index;
+ if (((Byte = HalpFlash8kReadByte((PUCHAR)Address)) !=
+ (UCHAR)DataPtr[Index])) {
+
+ if (HalpFlash8kOverwriteCheck(Byte, (UCHAR)DataPtr[Index])) {
+ ReturnStatus = HalpFlash8kWriteByte(Address, DataPtr[Index]);
+ } else {
+#if defined(ALPHA_FW_KDHOOKS) || defined(HALDBG)
+ DbgPrint("Need to erase flash because byte at %08x (%02x) ",
+ Address, Byte);
+ DbgPrint("Cannot be written with %02x\r\n",
+ (UCHAR)DataPtr[Index]);
+#endif
+
+ NeedToErase = TRUE;
+ }
+ }
+ }
+
+ if (NeedToErase) {
+ ULONG BlockSize;
+ ULONG BlockBase;
+ ULONG DataBase;
+ PUCHAR pShadow = NULL;
+
+ //
+ // We need to erase the flash block in order to write some of the
+ // requested data. We take the safe approach of copy the entire
+ // flash block into memory (we don't know what else is there), modify
+ // the copy in memory, erase the flash block, and write the entire
+ // block.
+ //
+
+ DataBase = (ULONG)NvRamPtr & ~(ULONG)HalpCMOSRamBase;
+ BlockBase = (ULONG)HalpFlash8kBlockAlign(NvRamPtr);
+ BlockSize = HalpFlash8kBlockSize(BlockBase);
+
+ pShadow = ExAllocatePool(NonPagedPool, BlockSize);
+
+ if (pShadow != NULL) {
+ for(Index = 0; Index < BlockSize; Index++) {
+ pShadow[Index] = HalpFlash8kReadByte(BlockBase + Index);
+ }
+
+ for(Index = 0; Index < Length; Index++) {
+ pShadow[DataBase + Index] = DataPtr[Index];
+ }
+
+ ReturnStatus = HalpFlash8kEraseBlock(BlockBase);
+
+ for(Index = 0;
+ (Index < BlockSize) && (ReturnStatus == ESUCCESS);
+ Index++) {
+
+ if (pShadow[Index] != HalpFlashDriver->ErasedData) {
+ ReturnStatus = HalpFlash8kWriteByte(BlockBase + Index,
+ pShadow[Index]);
+ }
+ }
+
+ ExFreePool(pShadow);
+ } else {
+#if defined(ALPHA_KDHOOKS) || defined(HALDBG)
+ DbgPrint("HalpWriteNVRamBuffer: Could not allocate shadow...\r\n");
+#endif
+ ReturnStatus = ENOMEM;
+ }
+ }
+
+ HalpFlash8kSetReadMode(NvRamPtr);
+ return ReturnStatus;
+}
+
+//
+//
+//
+ARC_STATUS HalpCopyNVRamBuffer (
+ IN PCHAR NvDestPtr,
+ IN PCHAR NvSrcPtr,
+ IN ULONG Length )
+/*++
+
+Routine Description:
+
+ This routine is not supported.
+
+Arguments:
+
+ NvDestPtr - Pointer (qva) to NVRam location to write data into
+ NvSrcPtr - Pointer (qva) to NVRam location of data to copy
+ Length - Number of bytes of data to transfer
+
+Return Value:
+
+ ENODEV if no flash driver is loaded
+ EIO if a flash driver is loaded
+
+--*/
+
+{
+ //
+ // If there is no flash driver, return an error.
+ //
+ if (HalpFlashDriver == NULL) {
+ return ENODEV;
+ }
+
+ return EIO;
+}
+
+PFLASH_DRIVER
+HalpInitializeFlashDriver(
+ IN PCHAR NvRamPtr
+ )
+/*++
+
+Routine Description:
+
+ This routine attempts to recognize the flash device present in the
+ system by calling each known flash driver's Initialize() function
+ with the address passed in. The Initialize() functions will each
+ return NULL if they do not recognize the flash device at the specified
+ address and a pointer to a FLASH_DRIVER structure if the device is
+ recognized. This routine looks until it either recognizes a flash device
+ or runs out of known flash devices.
+
+Arguments:
+
+ NvRamPtr - a pointer to an address within the flash device
+
+Return Value:
+
+ A pointer to the FLASH_DRIVER structure of the driver which corresponds
+ to the flash device in the system. NULL if no known flash device was
+ recognized.
+
+--*/
+{
+ PFLASH_DRIVER FlashDriver = NULL;
+ ULONG DriverNumber;
+
+ for(DriverNumber=0; FlashDriverList[DriverNumber] != NULL; DriverNumber++) {
+ FlashDriver = FlashDriverList[DriverNumber](NvRamPtr);
+ if (FlashDriver != NULL) {
+ break;
+ }
+ }
+
+#ifdef ALPHA_FW_SERDEB
+ if (FlashDriver != NULL) {
+ SerFwPrint("Flash device found at %08x: %s\r\n",
+ NvRamPtr,
+ FlashDriver->DeviceName);
+ } else {
+ SerFwPrint("ERROR: No flash device found at %08x\r\n", NvRamPtr);
+ }
+#endif
+
+ return FlashDriver;
+}
+
diff --git a/private/ntos/nthals/halalpha/flash8k.h b/private/ntos/nthals/halalpha/flash8k.h
new file mode 100644
index 000000000..32a5f18f2
--- /dev/null
+++ b/private/ntos/nthals/halalpha/flash8k.h
@@ -0,0 +1,130 @@
+// flash8k.h
+
+#ifndef _FLASH8K_H_
+#define _FLASH8K_H_
+
+#ifdef FLASH8K_INCLUDE_FILES
+#include "halp.h"
+#include "arccodes.h"
+#endif //FLASH8K_DONT_INCLUDE_FILES
+
+//
+// The value of HalpCMOSRamBase must be set at initialization
+//
+
+typedef enum _FLASH_OPERATIONS {
+ FlashByteWrite,
+ FlashEraseBlock
+} FLASH_OPERATIONS, *PFLASH_OPERATIONS;
+
+typedef struct _FLASH_DRIVER {
+ PCHAR DeviceName;
+ ARC_STATUS (*SetReadModeFunction)(PUCHAR address);
+ ARC_STATUS (*WriteByteFunction)(PUCHAR address, UCHAR data);
+ ARC_STATUS (*EraseBlockFunction)(PUCHAR address);
+ PUCHAR (*BlockAlignFunction)(PUCHAR address);
+ UCHAR (*ReadByteFunction)(PUCHAR address);
+ BOOLEAN (*OverwriteCheckFunction)(UCHAR olddata, UCHAR newdata);
+ ULONG (*BlockSizeFunction)(PUCHAR address);
+ ULONG (*GetLastErrorFunction)(VOID);
+ ULONG DeviceSize;
+ UCHAR ErasedData;
+} FLASH_DRIVER, *PFLASH_DRIVER;
+
+extern PFLASH_DRIVER HalpFlashDriver;
+
+#define WRITE_CONFIG_RAM_DATA(boffset,data) \
+ WRITE_REGISTER_UCHAR((PUCHAR)(boffset),((data) & 0xff))
+
+#define READ_CONFIG_RAM_DATA(boffset) \
+ READ_REGISTER_UCHAR((PUCHAR)(boffset))
+
+
+PFLASH_DRIVER
+HalpInitializeFlashDriver(
+ IN PCHAR NvRamPtr
+ );
+
+ARC_STATUS
+HalpReadNVRamBuffer (
+ OUT PCHAR DataPtr,
+ IN PCHAR NvRamPtr,
+ IN ULONG Length
+ );
+
+ARC_STATUS
+HalpWriteNVRamBuffer (
+ IN PCHAR NvRamPtr,
+ IN PCHAR DataPtr,
+ IN ULONG Length
+ );
+
+ARC_STATUS
+HalpCopyNVRamBuffer (
+ IN PCHAR NvDestPtr,
+ IN PCHAR NvSrcPtr,
+ IN ULONG Length
+ );
+
+
+//
+// The following macros define the HalpFlash8k*() functions in terms
+// of the FlashDriver variable. FlashDriver points to a structure
+// containing information about the currently active flash driver.
+// Information in the structure pointed to by FlashDriver includes
+// functions within the driver to perform all device-dependent operations.
+//
+
+#define HalpFlash8kSetReadMode(boffset) \
+ HalpFlashDriver->SetReadModeFunction( \
+ (PUCHAR)((ULONG)(HalpCMOSRamBase) | \
+ (ULONG)(boffset)))
+
+#define HalpFlash8kReadByte(boffset) \
+ HalpFlashDriver->ReadByteFunction( \
+ (PUCHAR)((ULONG)(HalpCMOSRamBase) | \
+ (ULONG)(boffset)))
+
+#define HalpFlash8kWriteByte(boffset, data) \
+ HalpFlashDriver->WriteByteFunction( \
+ (PUCHAR)((ULONG)(HalpCMOSRamBase) | \
+ (ULONG)(boffset)), ((data) & 0xff))
+
+#define HalpFlash8kOverwriteCheck(olddata, newdata) \
+ HalpFlashDriver->OverwriteCheckFunction( \
+ (olddata) & 0xff, (newdata) & 0xff)
+
+#define HalpFlash8kEraseBlock(boffset) \
+ HalpFlashDriver->EraseBlockFunction( \
+ (PUCHAR)((ULONG)(HalpCMOSRamBase) | \
+ (ULONG)(boffset)))
+
+#define HalpFlash8kBlockAlign(boffset) \
+ HalpFlashDriver->BlockAlignFunction( \
+ (PUCHAR)((ULONG)(HalpCMOSRamBase) | \
+ (ULONG)(boffset)))
+
+#define HalpFlash8kBlockSize(boffset) \
+ HalpFlashDriver->BlockSizeFunction( \
+ (PUCHAR)((ULONG)(HalpCMOSRamBase) | \
+ (ULONG)(boffset)))
+
+#define HalpFlash8kCheckStatus(boffset, operation) \
+ HalpFlashDriver->CheckStatusFunction( \
+ (PUCHAR)((ULONG)(HalpCMOSRamBase) | \
+ (ULONG)(boffset)), (operation))
+
+#define HalpFlash8kGetLastError() \
+ HalpFlashDriver->GetLastErrorFunction()
+
+
+//
+// Error codes for GetLastError()
+//
+#define ERROR_VPP_LOW 1L
+#define ERROR_ERASE_ERROR 2L
+#define ERROR_WRITE_ERROR 3L
+#define ERROR_TIMEOUT 4L
+#define ERROR_UNKNOWN 127L
+
+#endif // _FLASH8K_H_
diff --git a/private/ntos/nthals/halalpha/flashdrv.c b/private/ntos/nthals/halalpha/flashdrv.c
new file mode 100644
index 000000000..6c87efecd
--- /dev/null
+++ b/private/ntos/nthals/halalpha/flashdrv.c
@@ -0,0 +1,23 @@
+//
+// Flash Drivers
+//
+// extern declarations of each known flash driver's Initialize() funcion
+// are needed here for addition into the list of known drivers.
+//
+// FlashDriverList is an array of driver Initialize() functions used to
+// identify the flash device present in the system. The last entry
+// in FlashDriverList must be NULL.
+//
+#include "halp.h"
+#include "flash8k.h"
+
+extern PFLASH_DRIVER I28F008SA_Initialize(PUCHAR);
+extern PFLASH_DRIVER Am29F080_Initialize(PUCHAR);
+extern PFLASH_DRIVER Am29F040_Initialize(PUCHAR);
+
+PFLASH_DRIVER (*FlashDriverList[])(PUCHAR) = {
+ I28F008SA_Initialize,
+ Am29F080_Initialize,
+ Am29F040_Initialize,
+ NULL};
+
diff --git a/private/ntos/nthals/halalpha/fwreturn.c b/private/ntos/nthals/halalpha/fwreturn.c
new file mode 100644
index 000000000..bf11d8c27
--- /dev/null
+++ b/private/ntos/nthals/halalpha/fwreturn.c
@@ -0,0 +1,255 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ fwreturn.c
+
+Abstract:
+
+ This module implements the HAL return to firmware function.
+
+ Stolen wholesale from s3return.c in ../mips.
+ Assumes that the firmware entry vector defined in the HAL spec has
+ been set up and is reachable through the System Parameter Block.
+
+Author:
+
+ David N. Cutler (davec) 21-Aug-1991
+ Miche Baker-Harvey (miche) 4-Jun-1992
+
+Revision History:
+
+ 14-Dec-1993 Joe Notarangelo
+ Add MP support, use reboot encoding to return to firmware
+
+--*/
+
+#include "halp.h"
+
+#if !defined(NT_UP)
+
+
+VOID // #definition of KiIpiSendPacket
+KiIpiSendPacket( // not in ntmp.h. Define here
+ IN KAFFINITY TargetProcessors,
+ IN PKIPI_WORKER WorkerFunction,
+ IN PVOID Parameter1,
+ IN PVOID Parameter2,
+ IN PVOID Parameter3
+ );
+#endif
+
+VOID
+HalpResetHAERegisters(
+ VOID
+ );
+
+VOID
+HalpShutdownSystem(
+ ULONG HaltReasonCode
+ );
+
+
+VOID
+HalReturnToFirmware(
+ IN FIRMWARE_REENTRY Routine
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns control to the specified firmware routine.
+
+Arguments:
+
+ Routine - Supplies a value indicating which firmware routine to invoke.
+
+Return Value:
+
+ Does not return.
+
+Revision History:
+
+ 09-Jul-1992 Jeff McLeman (mcleman)
+ In all cases, except for ArcEnterInteractiveMode, invoke a
+ halt to restart the firmware. (Enter PAL)
+ 04-Mar-1993 Joe Mitchell (DEC)
+ Invoke a routine to call halt in ALL cases. Before calling this routine,
+ pass a value to the firmware indicating the desired function via
+ the Restart Block save area.
+
+--*/
+
+{
+
+ //
+ // Case on the type of return.
+ //
+
+ switch (Routine)
+ {
+ case HalHaltRoutine:
+ HalpShutdownSystem( AXP_HALT_REASON_POWEROFF );
+ break;
+ case HalPowerDownRoutine:
+ HalpShutdownSystem( AXP_HALT_REASON_POWERFAIL );
+ break;
+ case HalRestartRoutine:
+ HalpShutdownSystem( AXP_HALT_REASON_RESTART );
+ break;
+ case HalRebootRoutine:
+ HalpShutdownSystem( AXP_HALT_REASON_REBOOT );
+ break;
+ case HalInteractiveModeRoutine:
+ HalpShutdownSystem( AXP_HALT_REASON_HALT );
+ break;
+ default:
+ HalDisplayString("Unknown ARCS restart function.\n");
+ DbgBreakPoint();
+ }
+
+ /* NOTREACHED */
+ HalDisplayString("Illegal return from ARCS restart function.\n");
+ DbgBreakPoint();
+}
+
+VOID
+HalpShutdownSystem(
+ ULONG HaltReasonCode
+ )
+/*++
+
+Routine Description:
+
+ This function causes a system shutdown so that each processor in
+ the system will return to the firmware. A processor returns to
+ the firmware by executing the reboot call pal function.
+
+Arguments:
+
+ HaltReasonCode - Supplies the reason code for the halt.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PRESTART_BLOCK RestartBlock; // Boot Master Restart Block
+#if !defined(NT_UP)
+ KAFFINITY TargetProcessors;
+ KIRQL OldIrql;
+ PKPRCB Prcb = PCR->Prcb;
+ ULONG Wait;
+#endif
+
+ //
+ // Reset video using NT driver's HwResetHw routine
+ //
+
+ HalpVideoReboot();
+
+ //
+ // Reset the HAE Registers to 0
+ //
+
+ HalpResetHAERegisters();
+
+ //
+ // Write the halt reason code into the restart block of the
+ // boot master processor.
+ //
+
+ RestartBlock = SYSTEM_BLOCK->RestartBlock;
+ if( RestartBlock != NULL ){
+ RestartBlock->u.Alpha.HaltReason = HaltReasonCode;
+ }
+
+#if !defined(NT_UP)
+
+#define REBOOT_WAIT_LIMIT (5 * 1000) // loop count for 5 second wait
+
+ //
+ // Raise Irql to block all interrupts except errors and IPIs.
+ //
+
+ KeRaiseIrql( CLOCK_LEVEL, &OldIrql );
+
+ //
+ // Send an IPI to each processor.
+ //
+ TargetProcessors = HalpActiveProcessors;
+ TargetProcessors &= ~Prcb->SetMember;
+
+#if HALDBG
+
+ DbgPrint( "HalpShutdown: TargetProcessors = %x, Active = %x\n",
+ TargetProcessors, HalpActiveProcessors );
+
+#endif //HALDBG
+
+
+ KiIpiSendPacket( TargetProcessors,
+ (PKIPI_WORKER) HalpReboot,
+ NULL,
+ NULL,
+ NULL );
+
+
+ //
+ // If the current processor is the primary, it must reboot and handle
+ // the firmware restart. If a secondary processor is executing this
+ // shutdown, then it waits to verify that the primary has shutdown so
+ // that the restart can be performed. If the primary doesn't reach the
+ // firmware, the system is toasted and a message is printed.
+ //
+ if ( Prcb->Number == HAL_PRIMARY_PROCESSOR )
+ {
+ HalpReboot; // Never to return
+ }
+
+ //
+ // Wait until the primary processor has rebooted and signalled that
+ // it has returned to the firmware by indicating that the processor
+ // is not started in the BootStatus of its restart block. (ProcessorStart=0)
+ // However, put a timeout on the check in case the primary processor
+ // is currently wedged (it may not be able to receive the IPI).
+ //
+
+ Wait = 0;
+ while( RestartBlock->BootStatus.ProcessorStart == 0 &&
+ Wait < REBOOT_WAIT_LIMIT ) {
+ //
+ // The Primary processor is still running. Stall for a while
+ // and increment the wait count.
+ //
+
+ KeStallExecutionProcessor( 1000 ); // 1000000 );
+ Wait ++;
+
+ } //end while( Wait < REBOOT_WAIT_LIMIT )
+
+
+ //
+ // if the wait timed out print messages to alert the user.
+ //
+ if ( Wait >= REBOOT_WAIT_LIMIT )
+ {
+ HalDisplayString( "The Primary Processor was not shutdown.\n" );
+ HalDisplayString( "Power off your system before restarting.\n" );
+ }
+
+#endif //!NT_UP
+
+ //
+ // Reboot this processor.
+ //
+
+ HalpReboot();
+
+}
+
diff --git a/private/ntos/nthals/halalpha/gru.h b/private/ntos/nthals/halalpha/gru.h
new file mode 100644
index 000000000..f1cbe1067
--- /dev/null
+++ b/private/ntos/nthals/halalpha/gru.h
@@ -0,0 +1,84 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ gru.h
+
+Abstract:
+
+ This file defines the structures and definitions for the GRU ASIC.
+
+Author:
+
+ Steve Brooks 7-July-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#ifndef _GRUH_
+#define _GRUH_
+
+//
+// Define locations of the GRU ASIC registers
+//
+
+#define GRU_CSRS_PHYSICAL ((ULONGLONG)0x8780000000)
+#define GRU_CSRS_QVA HAL_MAKE_QVA(GRU_CSRS_PHYSICAL)
+
+#define GRU_CACHECNFG_CSRS_PHYSICAL ((ULONGLONG)0x8780000200)
+#define GRU_CACHECNFG_CSRS_QVA HAL_MAKE_QVA(GRU_CSRS_PHYSICAL)
+
+//
+// Define various masks for the GRU registers
+//
+
+#define GRU_ENABLE_EISA_INT 0x80000000
+#define GRU_SET_LEVEL_INT 0x00000000
+#define GRU_SET_LOW_INT 0x8F000000
+#define GRU_PCI_MASK_INT 0x000FFFFF
+#define GRU_EISA_MASK_INT 0x80000000
+
+//
+// Define GRU Interrupt register access structure:
+//
+
+typedef struct _GRU_INTERRUPT_CSRS{
+ UCHAR IntReq; // (00) Interrupt Request Register
+ UCHAR Filler1; // (20)
+ UCHAR IntMask; // (40) Interrupt Mask Register
+ UCHAR Filler2; // (60)
+ UCHAR IntEdge; // (80) Edge/Level Interrupt Select
+ UCHAR Filler3; // (a0)
+ UCHAR IntHiLo; // (c0) Active High/Low select register
+ UCHAR Filler4; // (e0)
+ UCHAR IntClear; // (100) Interrupt Clear register
+} GRU_INTERRUPT_CSRS, *PGRU_INTERRUPT_CSRS;
+
+//
+// Define GRU cache register structure.
+//
+
+typedef union _GRU_CACHECNFG{
+ struct{
+ ULONG Reserved0 : 4; //
+ ULONG ClockDivisor: 4; // Clock divisor for EV5.
+ ULONG Reserved1 : 3; //
+ ULONG CacheSpeed : 2; // SRAM cache access time.
+ ULONG CacheSize : 3; // SRAM cache size.
+ ULONG Mmb0Config : 4; // Presence and type of MMB0.
+ ULONG Reserved2 : 4; //
+ ULONG Mmb1Config : 4; // Presence and type of MMB1.
+ ULONG Reserved3 : 4; //
+ };
+ ULONG all;
+} GRU_CACHECNFG, *PGRU_CACHECNFG;
+
+#endif // _GRUH_
diff --git a/private/ntos/nthals/halalpha/haldebug.c b/private/ntos/nthals/halalpha/haldebug.c
new file mode 100644
index 000000000..543354e72
--- /dev/null
+++ b/private/ntos/nthals/halalpha/haldebug.c
@@ -0,0 +1,58 @@
+#if HALDBG
+
+/*++
+
+Copyright (c) 1993-1994 Digital Equipment Corporation
+
+Module Name:
+
+ haldebug.c
+
+Abstract:
+
+ This module contains debugging code for the HAL.
+
+Author:
+
+ Steve Jenness 09-Nov-1993
+ Joe Notarangelo 28-Jan-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+
+
+#include <stdarg.h>
+#include <stdio.h>
+
+ULONG HalDebugMask = 0;
+UCHAR HalDebugBuffer[512];
+
+VOID
+HalDebugPrint(
+ ULONG DebugPrintMask,
+ PCCHAR DebugMessage,
+ ...
+ )
+{
+ va_list ap;
+ va_start(ap, DebugMessage);
+
+ if( (DebugPrintMask & HalDebugMask) != 0 )
+ {
+ vsprintf(HalDebugBuffer, DebugMessage, ap);
+ DbgPrint(HalDebugBuffer);
+ }
+
+ va_end(ap);
+}
+
+#endif // HALDBG
+
diff --git a/private/ntos/nthals/halalpha/haldump.c b/private/ntos/nthals/halalpha/haldump.c
new file mode 100644
index 000000000..2b95e24d8
--- /dev/null
+++ b/private/ntos/nthals/halalpha/haldump.c
@@ -0,0 +1,83 @@
+#ifdef HAL_DBG
+
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ haldump.c
+
+Abstract:
+
+ This module is used to dump blocks of data during debugging and unit
+ testing.
+
+Author:
+
+ Steve Jenness 93.12.17
+
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+VOID
+HalpDumpBlock (
+ IN PUCHAR Buffer,
+ IN LONG BufferLength
+ )
+
+/*++
+
+Routine Description:
+
+ This routine dumps a block of data to the debugger.
+
+Arguments:
+
+ Buffer - Pointer to data to be dumped.
+ BufferLength - Number of bytes to be dumped.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Offset = 0;
+ ULONG ByteCount = 0;
+ UCHAR CharBuffer[17];
+ PUCHAR CharPtr;
+
+ CharBuffer[16] = 0;
+ while (BufferLength > 0) {
+ DbgPrint(" %08x: ", Offset);
+ CharPtr = &CharBuffer[0];
+
+ DbgPrint(" %02x %02x %02x %02x %02x %02x %02x %02x",
+ Buffer[0], Buffer[1], Buffer[2], Buffer[3],
+ Buffer[4], Buffer[5], Buffer[6], Buffer[7]);
+ DbgPrint(" %02x %02x %02x %02x %02x %02x %02x %02x",
+ Buffer[8], Buffer[9], Buffer[10], Buffer[11],
+ Buffer[11], Buffer[13], Buffer[14], Buffer[15]);
+ do {
+ if ((*Buffer >= 0x20) && (*Buffer <= 0x7e)) {
+ *CharPtr++ = *Buffer++;
+ } else {
+ *CharPtr++ = '.';
+ Buffer++;
+ }
+ Offset++;
+ } while ((Offset & 0xf) != 0);
+
+ DbgPrint(" %s\n", &CharBuffer[0]);
+ Offset += 16;
+ BufferLength -= 16;
+ }
+}
+
+#endif //HAL_DBG
diff --git a/private/ntos/nthals/halalpha/halisa.h b/private/ntos/nthals/halalpha/halisa.h
new file mode 100644
index 000000000..2ebe313ae
--- /dev/null
+++ b/private/ntos/nthals/halalpha/halisa.h
@@ -0,0 +1,89 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ halisa.h
+
+Abstract:
+
+ This header file defines the private Hardware Architecture Layer (HAL)
+ EISA/ISA specific interfaces, defines and structures.
+
+Author:
+
+ Jeff Havens (jhavens) 20-Jun-91
+ Jeff McLeman (mcleman) 01-Jun-1992
+
+Revision History:
+
+ 17-Jul-1992 Jeff McLeman (mcleman)
+ Remove adapter object structure from here.
+
+ 01-Jun-1992 Jeff McLeman
+ modify for Jensen EISA/ISA
+
+--*/
+
+#ifndef _HALISA_
+#define _HALISA_
+
+
+//
+// The MAXIMUM_MAP_BUFFER_SIZE defines the maximum map buffers which the system
+// will allocate for devices which require phyically contigous buffers.
+//
+
+#define MAXIMUM_MAP_BUFFER_SIZE 0x40000
+
+//
+// Define the initial buffer allocation size for a map buffers for systems with
+// no memory which has a physical address greater than MAXIMUM_PHYSICAL_ADDRESS.
+//
+
+#define INITIAL_MAP_BUFFER_SMALL_SIZE 0x10000
+
+//
+// Define the initial buffer allocation size for a map buffers for systems with
+// no memory which has a physical address greater than MAXIMUM_PHYSICAL_ADDRESS.
+//
+
+#define INITIAL_MAP_BUFFER_LARGE_SIZE 0x30000
+
+//
+// Define the incremental buffer allocation for a map buffers.
+//
+
+#define INCREMENT_MAP_BUFFER_SIZE 0x10000
+
+//
+// Define the maximum number of map registers that can be requested at one time
+// if actual map registers are required for the transfer.
+//
+
+#define __64K (0x10000)
+#define MAXIMUM_ISA_MAP_REGISTER (__64K >> PAGE_SHIFT)
+
+//
+// Define the maximum physical address which can be handled by an Isa card.
+//
+
+#define __16MB (0x1000000)
+#define MAXIMUM_ISA_PHYSICAL_ADDRESS (__16MB)
+
+//
+// Define the scatter/gather flag for the Map Register Base.
+//
+
+#define NO_SCATTER_GATHER 0x00000001
+
+//
+// Define the copy buffer flag for the index.
+//
+
+#define COPY_BUFFER 0XFFFFFFFF
+
+
+#endif // _HALISA_
diff --git a/private/ntos/nthals/halalpha/halp.h b/private/ntos/nthals/halalpha/halp.h
new file mode 100644
index 000000000..c36428a82
--- /dev/null
+++ b/private/ntos/nthals/halalpha/halp.h
@@ -0,0 +1,1095 @@
+/*++ BUILD Version: 0003 // Increment this if a change has global effects
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992,1993 Digital Equipment Corporation
+
+Module Name:
+
+ halp.h
+
+Abstract:
+
+ This header file defines the private Hardware Architecture Layer (HAL)
+ interfaces.
+
+Author:
+
+ David N. Cutler (davec) 25-Apr-1991
+ Miche Baker-Harvey (miche) 22-Apr-1992
+
+
+Revision History:
+
+ 09-Jul-1992 Jeff McLeman (mcleman)
+ If processor is an Alpha, include XXHALP.C for Alpha.
+
+ 24-Sep-1993 Joe Notarangelo
+ Incorporate definitions from xxhalp.h and jxhalp.h.
+ Restructure so that related modules are together.
+
+ 5-Jan-1994 Eric Rehm
+ Incorport support for PCI and IoAssignResources.
+
+--*/
+
+#ifndef _HALP_
+#define _HALP_
+
+#include "nthal.h"
+#include "hal.h"
+#include "pci.h"
+#include "errframe.h"
+
+
+//
+// Declare HAL spinlocks.
+//
+
+extern KSPIN_LOCK HalpBeepLock;
+extern KSPIN_LOCK HalpDisplayAdapterLock;
+extern KSPIN_LOCK HalpSystemInterruptLock;
+
+//
+// Define external references.
+//
+
+extern ULONG HalpClockFrequency;
+extern ULONG HalpClockMegaHertz;
+
+extern ULONG HalpProfileCountRate;
+
+extern PADAPTER_OBJECT MasterAdapterObject;
+
+extern BOOLEAN LessThan16Mb;
+
+extern KAFFINITY HalpActiveProcessors;
+
+//
+// Map buffer prameters. These are initialized in HalInitSystem
+//
+
+extern PHYSICAL_ADDRESS HalpMapBufferPhysicalAddress;
+extern ULONG HalpMapBufferSize;
+
+extern ULONG HalpBusType;
+
+//
+// Define global data used to relate PCI devices to their interrupt
+// vector.
+//
+
+extern ULONG *HalpPCIPinToLineTable;
+
+//
+// Define global data used to locate the EISA control space and the realtime
+// clock registers.
+//
+
+extern PVOID HalpEisaControlBase;
+extern PVOID HalpEisaIntAckBase;
+extern PVOID HalpCMOSRamBase;
+extern PVOID HalpRtcAddressPort;
+extern PVOID HalpRtcDataPort;
+
+extern POBJECT_TYPE *IoAdapterObjectType;
+
+//
+// Determine if a virtual address is really a physical address.
+//
+
+#define HALP_IS_PHYSICAL_ADDRESS(Va) \
+ ((((ULONG)Va >= KSEG0_BASE) && ((ULONG)Va < KSEG2_BASE)) ? TRUE : FALSE)
+
+//
+// Define the different address spaces.
+//
+
+typedef enum _ADDRESS_SPACE_TYPE{
+ BusMemory=0,
+ BusIo = 1,
+ UserBusMemory = 2,
+ UserBusIo = 3,
+ KernelPciDenseMemory = 4,
+ UserPciDenseMemory = 6,
+} ADDRESS_SPACE_TYPE, *PADDRESS_SPACE_TYPE;
+
+//
+// Prototype for Memory Size determination routine
+//
+ULONGLONG
+HalpGetMemorySize(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+ULONGLONG
+HalpGetContiguousMemorySize(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+//
+// Prototype for BCache Size determination routine
+//
+ULONG
+HalpGetBCacheSize(
+ ULONGLONG ContiguousMemorySize
+ );
+
+//
+// Define initialization routine prototypes.
+//
+
+BOOLEAN
+HalpCreateDmaStructures (
+ PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+VOID
+HalpEstablishErrorHandler(
+ VOID
+ );
+
+VOID
+HalpInitializeClockInterrupts(
+ VOID
+ );
+
+VOID
+HalpInitializeProfiler(
+ VOID
+ );
+
+BOOLEAN
+HalpInitializeDisplay (
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+BOOLEAN
+HalpInitializeInterrupts (
+ VOID
+ );
+
+VOID
+HalpInitializeMachineDependent(
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+BOOLEAN
+HalpMapIoSpace (
+ VOID
+ );
+
+ULONG
+HalpMapDebugPort (
+ IN ULONG ComPort,
+ OUT PULONG ReadQva,
+ OUT PULONG WriteQva
+ );
+
+VOID
+HalpSetTimeIncrement(
+ VOID
+ );
+
+VOID
+HalpParseLoaderBlock(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+VOID
+HalpInitializeProcessorParameters(
+ VOID
+ );
+
+//
+// Error Frame Initialization and Support Routines
+//
+VOID
+HalpAllocateUncorrectableFrame(
+ VOID
+ );
+
+VOID
+HalpGetMachineDependentErrorFrameSizes(
+ PULONG RawProcessorSize,
+ PULONG RawSystemInfoSize
+ );
+
+VOID
+HalpInitializeUncorrectableErrorFrame (
+ VOID
+ );
+
+VOID
+HalpGetProcessorInfo(
+ PPROCESSOR_INFO pProcessorInfo
+ );
+
+VOID
+HalpGetSystemInfo(
+ SYSTEM_INFORMATION *SystemInfo
+ );
+
+//
+// Define profiler function prototypes.
+//
+
+NTSTATUS
+HalpProfileSourceInformation (
+ OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG ReturnedLength
+ );
+
+NTSTATUS
+HalpProfileSourceInterval (
+ OUT PVOID Buffer,
+ IN ULONG BufferLength
+ );
+
+
+//
+// Define interrupt function prototypes.
+//
+
+VOID
+HalpProgramIntervalTimer(
+ IN ULONG RateSelect
+ );
+
+VOID
+HalpClockInterrupt (
+ VOID
+ );
+
+VOID
+HalpSecondaryClockInterrupt (
+ VOID
+ );
+
+VOID
+HalpIpiInterruptHandler (
+ VOID
+ );
+
+BOOLEAN
+HalpDmaDispatch(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ );
+
+VOID
+HalpPerformanceCounter0Interrupt (
+ VOID
+ );
+
+VOID
+HalpPerformanceCounter1Interrupt (
+ VOID
+ );
+
+VOID
+HalpPerformanceCounter2Interrupt (
+ VOID
+ );
+
+VOID
+HalpStallInterrupt (
+ VOID
+ );
+
+VOID
+HalpVideoReboot(
+ VOID
+ );
+
+//
+// Define microprocessor-specific function prototypes and structures.
+//
+
+//
+// 21064 (EV4) processor family.
+//
+
+typedef enum _EV4Irq{
+ Irq0 = 0,
+ Irq1 = 1,
+ Irq2 = 2,
+ Irq3 = 3,
+ Irq4 = 4,
+ Irq5 = 5,
+ MaximumIrq
+} EV4Irq, *PEV4Irq;
+
+typedef struct _EV4IrqStatus{
+ ULONG Vector;
+ BOOLEAN Enabled;
+ KIRQL Irql;
+ UCHAR Priority;
+} EV4IrqStatus, *PEV4IrqStatus;
+
+typedef struct _EV4ProfileCount {
+ ULONG ProfileCount[2];
+ ULONG ProfileCountReload[2];
+} EV4ProfileCount, *PEV4ProfileCount;
+
+VOID
+HalpInitialize21064Interrupts(
+ VOID
+ );
+
+VOID
+HalpDisable21064HardwareInterrupt(
+ IN ULONG Irq
+ );
+
+VOID
+HalpDisable21064SoftwareInterrupt(
+ IN KIRQL Irql
+ );
+
+VOID
+HalpDisable21064PerformanceInterrupt(
+ IN ULONG Vector
+ );
+
+VOID
+HalpEnable21064HardwareInterrupt(
+ IN ULONG Irq,
+ IN KIRQL Irql,
+ IN ULONG Vector,
+ IN UCHAR Priority
+ );
+
+VOID
+HalpEnable21064SoftwareInterrupt(
+ IN KIRQL Irql
+ );
+
+VOID
+HalpInitialize21064Interrupts(
+ VOID
+ );
+
+VOID
+HalpEnable21064PerformanceInterrupt(
+ IN ULONG Vector,
+ IN KIRQL Irql
+ );
+
+ULONG
+HalpGet21064PerformanceVector(
+ IN ULONG BusInterruptLevel,
+ OUT PKIRQL Irql
+ );
+
+ULONG
+HalpGet21064CorrectableVector(
+ IN ULONG BusInterruptLevel,
+ OUT PKIRQL Irql
+ );
+
+//
+// 21164 processor family.
+//
+
+#ifdef EV5
+
+typedef struct _EV5ProfileCount {
+ ULONG ProfileCount[3];
+ ULONG ProfileCountReload[3];
+} EV5ProfileCount, *PEV5ProfileCount;
+
+VOID
+HalpInitialize21164Interrupts(
+ VOID
+ );
+
+VOID
+HalpStart21164Interrupts(
+ VOID
+ );
+
+ULONG
+HalpGet21164PerformanceVector(
+ IN ULONG BusInterruptLevel,
+ OUT PKIRQL Irql
+ );
+
+ULONGLONG
+HalpRead21164PerformanceCounter(
+ VOID
+ );
+
+VOID
+HalpWrite21164PerformanceCounter(
+ ULONGLONG PmCtr,
+ ULONG CBOXMux1,
+ ULONG CBOXMux2
+ );
+
+ULONG
+HalpGet21164CorrectableVector(
+ IN ULONG BusInterruptLevel,
+ OUT PKIRQL Irql
+ );
+
+#endif // EV5 specific definitions
+
+//
+// Define the context structure for use by interrupt service routines.
+//
+
+typedef BOOLEAN (*PSECONDARY_DISPATCH)(
+ PVOID InterruptRoutine,
+ PKTRAP_FRAME TrapFrame
+ );
+
+//
+// Define memory utility function prototypes.
+//
+
+ULONG
+HalpAllocPhysicalMemory(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN ULONG MaxPhysicalAddress,
+ IN ULONG NumberOfPages,
+ IN BOOLEAN bAlignOn64k
+ );
+
+PVOID
+HalpMapPhysicalMemory(
+ IN PVOID PhysicalAddress,
+ IN ULONG NumberOfPages
+ );
+
+PVOID
+HalpRemapVirtualAddress(
+ IN PVOID VirtualAddress,
+ IN PVOID PhysicalAddress
+ );
+
+#if HALDBG
+
+VOID
+HalpDumpMemoryDescriptors(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+#endif
+
+//
+// Low-level routine interfaces.
+//
+
+VOID
+HalpReboot(
+ VOID
+ );
+
+VOID
+HalpImb(
+ VOID
+ );
+
+VOID
+HalpMb(
+ VOID
+ );
+
+ULONG
+HalpRpcc(
+ VOID
+ );
+
+MCES
+HalpReadMces(
+ VOID
+ );
+
+MCES
+HalpWriteMces(
+ IN MCES Mces
+ );
+
+VOID
+HalpWritePerformanceCounter(
+ IN ULONG PerformanceCounter,
+ IN BOOLEAN Enable,
+ IN ULONG MuxControl OPTIONAL,
+ IN ULONG EventCount OPTIONAL
+ );
+
+//
+// Define synonym for KeStallExecutionProcessor.
+//
+
+#define HalpStallExecution KeStallExecutionProcessor
+
+//
+// Define Bus Handler support function prototypes.
+//
+
+
+VOID
+HalpRegisterInternalBusHandlers (
+ VOID
+ );
+
+ULONG
+HalpGetSystemInterruptVector(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ );
+
+BOOLEAN
+HalpTranslateSystemBusAddress(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ );
+
+
+VOID
+HalpAdjustResourceListUpperLimits (
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList,
+ IN LARGE_INTEGER MaximumPortAddress,
+ IN LARGE_INTEGER MaximumMemoryAddress,
+ IN ULONG MaximumInterruptVector,
+ IN ULONG MaximumDmaChannel
+ );
+
+//
+// Define SIO support function prototypes.
+//
+
+VOID
+HalpInitializeSioInterrupts(
+ VOID
+ );
+
+VOID
+HalpEnableSioInterrupt(
+ IN ULONG Vector,
+ IN KINTERRUPT_MODE InterruptMode
+ );
+
+VOID
+HalpDisableSioInterrupt(
+ IN ULONG Vector
+ );
+
+BOOLEAN
+HalpSioDispatch(
+ VOID
+ );
+
+//
+// Define EISA support function prototypes.
+//
+
+BOOLEAN
+HalpInitializeEisaInterrupts(
+ VOID
+ );
+
+VOID
+HalpEnableEisaInterrupt(
+ IN ULONG Vector,
+ IN KINTERRUPT_MODE InterruptMode
+ );
+
+VOID
+HalpDisableEisaInterrupt(
+ IN ULONG Vector
+ );
+
+BOOLEAN
+HalpEisaDispatch(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext,
+ IN PKTRAP_FRAME TrapFrame
+ );
+
+BOOLEAN
+HalpEisaInterruptHandler(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ );
+
+VOID
+HalpEisaInitializeDma(
+ VOID
+ );
+
+PADAPTER_OBJECT
+HalpAllocateAdapter(
+ VOID
+ );
+
+PADAPTER_OBJECT
+HalpAllocateEisaAdapter(
+ IN PDEVICE_DESCRIPTION DeviceDescription,
+ OUT PULONG NumberOfMapRegisters
+ );
+
+BOOLEAN
+HalpMapEisaTransfer(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN ULONG LogicalAddress,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+BOOLEAN
+HalpFlushEisaAdapter(
+ IN PADAPTER_OBJECT AdapterObject,
+ IN PMDL Mdl,
+ IN PVOID MapRegisterBase,
+ IN PVOID CurrentVa,
+ IN ULONG Length,
+ IN BOOLEAN WriteToDevice
+ );
+
+ULONG
+HalpReadEisaDmaCounter(
+ IN PADAPTER_OBJECT AdapterObject
+ );
+
+
+ULONG
+HalpGetEisaData(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+NTSTATUS
+HalpAdjustEisaResourceList (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+ );
+
+NTSTATUS
+HalpAdjustIsaResourceList (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+ );
+
+//
+// Define PCI support function prototypes.
+//
+
+VOID
+HalpInitializePCIBus (
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+PBUS_HANDLER
+HalpAllocateAndInitPCIBusHandler (
+ IN ULONG BusNo,
+ IN ULONG HwBusNo,
+ IN BOOLEAN BusIsAcrossPPB,
+ IN ULONG PPBBusNumber,
+ IN PCI_SLOT_NUMBER PPBSlotNumber
+ );
+
+VOID
+HalpRegisterPCIInstallHandler(
+ IN PINSTALL_BUS_HANDLER MachineSpecificPCIInstallHandler
+);
+
+NTSTATUS
+HalpDefaultPCIInstallHandler(
+ IN PBUS_HANDLER Bus
+ );
+
+VOID
+HalpDeterminePCIDevicesPresent(
+ IN PBUS_HANDLER Bus
+);
+
+BOOLEAN
+HalpInitializePCIInterrupts(
+ VOID
+ );
+
+VOID
+HalpEnablePCIInterrupt(
+ IN ULONG Vector
+ );
+
+VOID
+HalpDisablePCIInterrupt(
+ IN ULONG Vector
+ );
+
+BOOLEAN
+HalpPCIInterruptHandler(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext
+ );
+
+
+//
+// Environment variable support
+//
+
+ARC_STATUS
+HalpReadNVRamBuffer(
+ OUT PCHAR DataPtr,
+ IN PCHAR NvRamPtr,
+ IN ULONG Length
+ );
+
+ARC_STATUS
+HalpWriteNVRamBuffer(
+ IN PCHAR NvRamPtr,
+ IN PCHAR DataPtr,
+ IN ULONG Length
+ );
+
+ARC_STATUS
+HalpCopyNVRamBuffer(
+ IN PCHAR NvDestPtr,
+ IN PCHAR NvSrcPtr,
+ IN ULONG Length
+ );
+
+#if defined(TAGGED_NVRAM)
+
+//
+// NVRAM API
+//
+
+UCHAR
+HalpGetNVRamUchar(
+ IN ULONG Offset
+ );
+
+VOID
+HalpSetNVRamUchar(
+ IN ULONG Offset,
+ IN UCHAR Data
+ );
+
+USHORT
+HalpGetNVRamUshort(
+ IN ULONG Offset
+ );
+
+VOID
+HalpSetNVRamUshort(
+ IN ULONG Offset,
+ IN USHORT Data
+ );
+
+ULONG
+HalpGetNVRamUlong(
+ IN ULONG Offset
+ );
+
+VOID
+HalpSetNVRamUlong(
+ IN ULONG Offset,
+ IN ULONG Data
+ );
+
+VOID
+HalpMoveMemoryToNVRam(
+ IN ULONG Offset,
+ IN PVOID Data,
+ IN ULONG Length
+ );
+
+VOID
+HalpMoveNVRamToMemory(
+ IN PVOID Data,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+VOID
+HalpMoveNVRamToNVRam(
+ IN ULONG Destination,
+ IN ULONG Source,
+ IN ULONG Length
+ );
+
+ULONG
+HalpGetNVRamStringLength(
+ IN ULONG Offset
+ );
+
+VOID
+HalpMoveMemoryStringToNVRam(
+ IN ULONG Offset,
+ IN PCHAR Data
+ );
+
+VOID
+HalpMoveNVRamStringToMemory(
+ IN PUCHAR Data,
+ IN ULONG Offset
+ );
+
+VOID
+HalpZeroNVRam(
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+ULONG
+HalpComputeNVRamChecksum(
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+BOOLEAN
+HalpIsNVRamRegion0Valid(
+ VOID
+ );
+
+BOOLEAN
+HalpSynchronizeNVRamRegion0(
+ IN BOOLEAN RecomputeChecksum
+ );
+
+BOOLEAN
+HalpInitializeNVRamRegion0(
+ IN BOOLEAN Synchronize
+ );
+
+ULONG
+HalpGetNVRamFwConfigOffset(
+ VOID
+ );
+
+ULONG
+HalpGetNVRamFwConfigLength(
+ VOID
+ );
+
+ULONG
+HalpGetNVRamLanguageOffset(
+ VOID
+ );
+
+ULONG
+HalpGetNVRamLanguageLength(
+ VOID
+ );
+
+ULONG
+HalpGetNVRamEnvironmentOffset(
+ VOID
+ );
+
+ULONG
+HalpGetNVRamEnvironmentLength(
+ VOID
+ );
+
+#if defined(EISA_PLATFORM)
+
+BOOLEAN
+HalpIsNVRamRegion1Valid(
+ VOID
+ );
+
+BOOLEAN
+HalpSynchronizeNVRamRegion1(
+ IN BOOLEAN RecomputeChecksum
+ );
+
+BOOLEAN
+HalpInitializeNVRamRegion1(
+ IN BOOLEAN Synchronize
+ );
+
+#endif // EISA_PLATFORM
+
+#endif // TAGGED_NVRAM
+
+//
+// Error handling function prototype.
+//
+
+typedef
+BOOLEAN
+KBUS_ERROR_ROUTINE(
+ IN struct _EXCEPTION_RECORD *ExceptionRecord,
+ IN struct _KEXCEPTION_FRAME *ExceptionFrame,
+ IN struct _KTRAP_FRAME *TrapFrame
+ );
+
+KBUS_ERROR_ROUTINE HalMachineCheck;
+
+VOID
+HalpInitializeMachineChecks(
+ IN BOOLEAN ReportCorrectableErrors
+ );
+
+//
+// Low-level I/O function prototypes.
+//
+
+VOID
+HalpAcknowledgeClockInterrupt(
+ VOID
+ );
+
+UCHAR
+HalpAcknowledgeEisaInterrupt(
+ IN PVOID ServiceContext
+ );
+
+UCHAR
+HalpReadClockRegister(
+ IN UCHAR Register
+ );
+
+VOID
+HalpWriteClockRegister(
+ IN UCHAR Register,
+ IN UCHAR Value
+ );
+
+UCHAR
+READ_CONFIG_UCHAR(
+ IN PVOID ConfigurationAddress,
+ IN ULONG ConfigurationType
+ );
+
+USHORT
+READ_CONFIG_USHORT(
+ IN PVOID ConfigurationAddress,
+ IN ULONG ConfigurationType
+ );
+
+ULONG
+READ_CONFIG_ULONG(
+ IN PVOID ConfigurationAddress,
+ IN ULONG ConfigurationType
+ );
+
+VOID
+WRITE_CONFIG_UCHAR(
+ IN PVOID ConfigurationAddress,
+ IN UCHAR ConfigurationData,
+ IN ULONG ConfigurationType
+ );
+
+VOID
+WRITE_CONFIG_USHORT(
+ IN PVOID ConfigurationAddress,
+ IN USHORT ConfigurationData,
+ IN ULONG ConfigurationType
+ );
+
+VOID
+WRITE_CONFIG_ULONG(
+ IN PVOID ConfigurationAddress,
+ IN ULONG ConfigurationData,
+ IN ULONG ConfigurationType
+ );
+
+//
+// Define the I/O superpage enable VA base.
+//
+
+#define SUPERPAGE_ENABLE ((ULONGLONG)0xfffffc0000000000)
+
+//
+// Numeric constants used in the HAL.
+//
+
+#define __1K (0x400)
+#define __2K (0x800)
+#define __4K (0x1000)
+#define __8K (0x2000)
+#define __16K (0x4000)
+#define __32K (0x8000)
+#define __64K (0x10000)
+#define __128K (0x20000)
+#define __256K (0x40000)
+#define __512K (0x80000)
+#define __1MB (0x100000)
+#define __2MB (0x200000)
+#define __4MB (0x400000)
+#define __8MB (0x800000)
+#define __16MB (0x1000000)
+#define __32MB (0x2000000)
+#define __64MB (0x4000000)
+#define __128MB (0x8000000)
+#define __256MB (0x10000000)
+#define __512MB (0x20000000)
+#define __1GB (0x40000000)
+#define __2GB (0x80000000)
+
+//
+// CPU mask values. Used to interpret cpu bitmap values.
+//
+#define HAL_CPU0_MASK ((ULONG)0x1)
+#define HAL_CPU1_MASK ((ULONG)0x2)
+#define HAL_CPU2_MASK ((ULONG)0x4)
+#define HAL_CPU3_MASK ((ULONG)0x8)
+
+//
+// HAL Debugging Support.
+//
+
+#if HALDBG
+
+#define DebugPrint(x) HalDebugPrint x
+
+VOID
+HalDebugPrint(
+ ULONG DebugPrintLevel,
+ PCCHAR DebugMessage,
+ ...
+ );
+
+#else //HALDBG
+
+#define DebugPrint(x)
+
+#endif //HALDBG
+
+//
+// Define HAL debugging masks.
+//
+
+//
+// Trace IoMapTransfer, IoFlushAdapterBuffers
+//
+
+#define HALDBG_IOMT (0x1)
+
+//
+// Trace Map Register allocations and frees
+//
+
+#define HALDBG_MAPREG (0x2)
+
+//
+// Include machine-dependent definitions.
+//
+// N.B. - Each platform that includes this file must have a machdep.h
+// include file in its private directory.
+//
+
+#include <machdep.h>
+
+#endif // _HALP_
diff --git a/private/ntos/nthals/halalpha/halpal.s b/private/ntos/nthals/halalpha/halpal.s
new file mode 100644
index 000000000..d34a29084
--- /dev/null
+++ b/private/ntos/nthals/halalpha/halpal.s
@@ -0,0 +1,276 @@
+// TITLE("Alpha PAL funtions for HAL")
+//++
+//
+// Copyright (c) 1992 Digital Equipment Corporation
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// halpal.s
+//
+// Abstract:
+//
+// This module implements routines to call PAL functions
+// from the Hal.
+//
+//
+// Author:
+//
+// Jeff McLeman (mcleman) 09-Jul-1992
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+// 13-Jul-1992 Jeff McLeman (mcleman)
+// add HalpMb to functions.
+//
+// 14-Dec-1993 Joe Notarangelo
+// use new encoding to return to firmware: HalpReboot instead of
+// HalpHalt
+//--
+
+#include "halalpha.h"
+
+//++
+//
+// VOID
+// HalpReboot(
+// )
+//
+// Routine Description:
+//
+// This function merely calls the PAL to reboot the Alpha processor.
+// This is used to restart the console firmware. (Note, MIPS does
+// not have a HALT instruction, so there had to be a mechanism to
+// restart the firware. Alpha merely reboots, which causes a jump
+// to firmware PAL, which restarts the firmware.)
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpReboot)
+
+ REBOOT // call the PAL to reboot
+
+ .end HalpReboot
+
+//++
+//
+// VOID
+// HalpSwppal(
+// )
+//
+// Routine Description:
+//
+// This function merely calls the PAL to issue a SWPPAL
+// on the Alpha processor...
+//
+// Arguments:
+//
+// a0 The physical address to do the Swappal to.
+// a1 -- a5 Any other arguments to the PALcode.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpSwppal)
+
+ SWPPAL // call the PAL to do a swap_pal
+
+ ret zero,(ra)
+
+ .end HalpSwppal
+
+
+//++
+//
+// VOID
+// HalpImb(
+// )
+//
+// Routine Description:
+//
+// This function merely calls the PAL to issue an Instruction
+// Memory Barrier on the Alpha processor..
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpImb)
+
+ IMB // call the PAL to do an IMB
+
+ ret zero,(ra)
+
+ .end HalpImb
+
+
+//++
+//
+// VOID
+// HalpMb(
+// )
+//
+// Routine Description:
+//
+// This function merely calls the PAL to issue a general
+// Memory Barrier on the Alpha processor..
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpMb)
+
+ mb // memory barrier
+
+ ret zero, (ra)
+
+ .end HalpMb
+
+//++
+//
+// VOID
+// HalpCachePcrValues(
+// )
+//
+// Routine Description:
+//
+// This function merely calls the PAL to cache values in the
+// PCR for faster access.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalpCachePcrValues)
+
+ CACHE_PCR_VALUES // call the palcode
+
+ ret zero,(ra)
+
+ .end HalpCachePcrValues
+//++
+//
+// ULONG
+// HalpRpcc(
+// )
+//
+// Routine Description:
+//
+// This function executes the RPCC (read processor cycle counter)
+// instruction.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// The low-order 32 bits of the processor cycle counter is returned
+// as the function value.
+// N.B. At 125 MHz this counter wraps about every 30 seconds. It is
+// the caller's responsibility to deal with overflow or wraparound.
+//
+//--
+
+ LEAF_ENTRY(HalpRpcc)
+
+ rpcc v0 // get rpcc value
+ addl v0, zero, v0 // extend
+
+ ret zero, (ra) // return
+
+ .end HalpRpcc
+
+
+//++
+//
+// MCES
+// HalpReadMces(
+// VOID
+// )
+//
+// Routine Description:
+//
+// Read the state of the MCES (Machine Check Error Summary)
+// internal processor register.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// v0 - Current MCES value.
+//--
+
+ LEAF_ENTRY(HalpReadMces)
+
+ GET_MACHINE_CHECK_ERROR_SUMMARY // v0 = current value
+
+ ret zero, (ra) // return
+
+ .end HalpReadMces
+
+
+//++
+//
+// MCES
+// HalpWriteMces(
+// IN MCES Mces
+// )
+//
+// Routine Description:
+//
+// Update the current value of the MCES internal processor register.
+//
+// Arguments:
+//
+// Mces(a0) - Supplies the new value for the MCES register.
+//
+// Return Value:
+//
+// v0 - Previous MCES value.
+//
+//--
+
+ LEAF_ENTRY(HalpWriteMces)
+
+ WRITE_MACHINE_CHECK_ERROR_SUMMARY // v0 = previous value
+
+ ret zero, (ra) // return
+
+ .end HalpWriteMces
diff --git a/private/ntos/nthals/halalpha/halpcsl.h b/private/ntos/nthals/halalpha/halpcsl.h
new file mode 100644
index 000000000..21b7d49df
--- /dev/null
+++ b/private/ntos/nthals/halalpha/halpcsl.h
@@ -0,0 +1,187 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ halpcsl.h
+
+Abstract:
+
+ This header file includes the definitions for standard PC serial
+ port UARTs.
+
+ Stolen from jazzserp.h, which is a slightly different chip-
+ it has a 16 byte fifo - we are just double buffered.
+
+Author:
+
+ David N. Cutler (davec) 28-Apr-1991
+ Miche Baker-Harvey (miche) 01-June-1992
+
+
+Revision History:
+
+--*/
+
+#ifndef _HALPCSL_
+#define _HALPCSL_
+
+
+//
+// Define base port numbers for serial lines inside the combo chip
+//
+
+#define COMA_PORT_BASE 0x3f8
+#define COMB_PORT_BASE 0x2f8
+
+
+//
+// Define serial port read registers structure.
+//
+
+typedef struct _SP_READ_REGISTERS {
+ UCHAR ReceiveBuffer;
+ UCHAR InterruptEnable;
+ UCHAR InterruptId;
+ UCHAR LineControl;
+ UCHAR ModemControl;
+ UCHAR LineStatus;
+ UCHAR ModemStatus;
+ UCHAR ScratchPad;
+} SP_READ_REGISTERS, *PSP_READ_REGISTERS;
+
+//
+// Define define serial port write registers structure.
+//
+
+typedef struct _SP_WRITE_REGISTERS {
+ UCHAR TransmitBuffer;
+ UCHAR InterruptEnable;
+ UCHAR FifoControl;
+ UCHAR LineControl;
+ UCHAR ModemControl;
+ UCHAR Reserved1;
+ UCHAR ModemStatus;
+ UCHAR ScratchPad;
+} SP_WRITE_REGISTERS, *PSP_WRITE_REGISTERS;
+
+//
+// Define serial port interrupt enable register structure.
+//
+
+typedef struct _SP_INTERRUPT_ENABLE {
+ UCHAR ReceiveEnable : 1;
+ UCHAR TransmitEnable : 1;
+ UCHAR LineStatusEnable : 1;
+ UCHAR ModemStatusEnable : 1;
+ UCHAR Reserved1 : 4;
+} SP_INTERRUPT_ENABLE, *PSP_INTERRUPT_ENABLE;
+
+//
+// Define serial port interrupt id register structure.
+//
+
+typedef struct _SP_INTERRUPT_ID {
+ UCHAR InterruptPending : 1;
+ UCHAR Identification : 3;
+ UCHAR Reserved1 : 2;
+ UCHAR FifoEnabled : 2; // always read as 0
+} SP_INTERRUPT_ID, *PSP_INTERRUPT_ID;
+
+//
+// Define serial port fifo control register structure.
+// This register is here for software compatibility, but there is
+// no FIFO on the 16C452
+//
+
+typedef struct _SP_FIFO_CONTROL {
+ UCHAR FifoEnable : 1;
+ UCHAR ReceiveFifoReset : 1;
+ UCHAR TransmitFifoReset : 1;
+ UCHAR DmaModeSelect : 1;
+ UCHAR Reserved1 : 2;
+ UCHAR ReceiveFifoLevel : 2;
+} SP_FIFO_CONTROL, *PSP_FIFO_CONTROL;
+
+//
+// Define serial port line control register structure.
+//
+
+typedef struct _SP_LINE_CONTROL {
+ UCHAR CharacterSize : 2;
+ UCHAR StopBits : 1;
+ UCHAR ParityEnable : 1;
+ UCHAR EvenParity : 1;
+ UCHAR StickParity : 1;
+ UCHAR SetBreak : 1;
+ UCHAR DivisorLatch : 1;
+} SP_LINE_CONTROL, *PSP_LINE_CONTROL;
+
+//
+// Line status register character size definitions.
+//
+
+#define FIVE_BITS 0x0 // five bits per character
+#define SIX_BITS 0x1 // six bits per character
+#define SEVEN_BITS 0x2 // seven bits per character
+#define EIGHT_BITS 0x3 // eight bits per character
+
+//
+// Line speed divisor definition. We get our baud rate clock
+// from the 82C106.
+//
+
+#define BAUD_RATE_2400 48 // divisor for 2400 baud
+#define BAUD_RATE_4800 24 // divisor for 4800 baud
+#define BAUD_RATE_9600 12 // divisor for 9600 baud
+#define BAUD_RATE_19200 6 // divisor for 19200 baud
+#define BAUD_RATE_38400 3 // divisor for 38400 baud
+#define BAUD_RATE_57600 2 // divisor for 57600 baud
+#define BAUD_RATE_115200 1 // divisor for 115200 baud
+
+//
+// Define serial port modem control register structure.
+//
+
+typedef struct _SP_MODEM_CONTROL {
+ UCHAR DataTerminalReady : 1;
+ UCHAR RequestToSend : 1;
+ UCHAR Reserved1 : 1;
+ UCHAR Interrupt : 1;
+ UCHAR loopBack : 1;
+ UCHAR Reserved2 : 3;
+} SP_MODEM_CONTROL, *PSP_MODEM_CONTROL;
+
+//
+// Define serial port line status register structure.
+//
+
+typedef struct _SP_LINE_STATUS {
+ UCHAR DataReady : 1;
+ UCHAR OverrunError : 1;
+ UCHAR ParityError : 1;
+ UCHAR FramingError : 1;
+ UCHAR BreakIndicator : 1;
+ UCHAR TransmitHoldingEmpty : 1;
+ UCHAR TransmitEmpty : 1;
+ UCHAR ReceiveFifoError : 1;
+} SP_LINE_STATUS, *PSP_LINE_STATUS;
+
+//
+// Define serial port modem status register structure.
+//
+
+typedef struct _SP_MODEM_STATUS {
+ UCHAR DeltaClearToSend : 1;
+ UCHAR DeltaDataSetReady : 1;
+ UCHAR TrailingRingIndicator : 1;
+ UCHAR DeltaReceiveDetect : 1;
+ UCHAR ClearToSend : 1;
+ UCHAR DataSetReady : 1;
+ UCHAR RingIndicator : 1;
+ UCHAR ReceiveDetect : 1;
+} SP_MODEM_STATUS, *PSP_MODEM_STATUS;
+
+#endif // _HALPCSL_
diff --git a/private/ntos/nthals/halalpha/halprof.c b/private/ntos/nthals/halalpha/halprof.c
new file mode 100644
index 000000000..62235fc7c
--- /dev/null
+++ b/private/ntos/nthals/halalpha/halprof.c
@@ -0,0 +1,179 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ halprof.c
+
+Abstract:
+
+ This module implements the high level Profile Counter interface.
+
+ N.B. - This module assumes that all processors in a multiprocessor
+ system are running the microprocessor at the same clock speed.
+
+Author:
+
+ Steve Brooks 14-Feb-1995
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+
+NTSTATUS
+HalpProfileSourceInformation (
+ OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG ReturnedLength
+ )
+/*++
+
+Routine Description:
+
+ Returns the HAL_PROFILE_SOURCE_INFORMATION for this processor.
+
+Arguments:
+
+ Buffer - output buffer
+ BufferLength - length of buffer on input
+ ReturnedLength - The length of data returned
+
+Return Value:
+
+ STATUS_SUCCESS
+ STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
+ currently needed.
+
+--*/
+{
+ PHAL_PROFILE_SOURCE_INFORMATION SourceInfo;
+ NTSTATUS Status;
+
+
+ if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INFORMATION)) {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ return Status;
+ }
+
+ SourceInfo = (PHAL_PROFILE_SOURCE_INFORMATION)Buffer;
+ SourceInfo->Supported = HalQueryProfileInterval(SourceInfo->Source);
+
+ if (SourceInfo->Supported) {
+ SourceInfo->Interval =
+ HalpProfileMapping[SourceInfo->Source].EventCount *
+ HalpProfileMapping[SourceInfo->Source].NumberOfTicks;
+ }
+
+ Status = STATUS_SUCCESS;
+ return Status;
+}
+
+NTSTATUS
+HalpProfileSourceInterval (
+ OUT PVOID Buffer,
+ IN ULONG BufferLength
+ )
+/*++
+
+Routine Description:
+
+ Returns the HAL_PROFILE_SOURCE_INTERVAL for this processor.
+
+Arguments:
+
+ Buffer - output buffer
+ BufferLength - length of buffer on input
+
+Return Value:
+
+ STATUS_SUCCESS
+ STATUS_BUFFER_TOO_SMALL - The ReturnedLength contains the buffersize
+ currently needed.
+
+--*/
+{
+ PHAL_PROFILE_SOURCE_INTERVAL Interval;
+ NTSTATUS Status;
+
+
+ if (BufferLength != sizeof(HAL_PROFILE_SOURCE_INTERVAL)) {
+ Status = STATUS_INFO_LENGTH_MISMATCH;
+ return Status;
+ }
+
+ Interval = (PHAL_PROFILE_SOURCE_INTERVAL)Buffer;
+ Status = HalSetProfileSourceInterval(Interval->Source,
+ &Interval->Interval);
+ return Status;
+}
+
+BOOLEAN
+HalQueryProfileInterval(
+ IN KPROFILE_SOURCE Source
+ )
+
+/*++
+
+Routine Description:
+
+ Given a profile source, returns whether or not that source is
+ supported.
+
+Arguments:
+
+ Source - Supplies the profile source
+
+Return Value:
+
+ TRUE - Profile source is supported
+
+ FALSE - Profile source is not supported
+
+--*/
+
+{
+ if (Source >= ProfileMaximum) {
+ return(FALSE);
+ }
+
+ return(HalpProfileMapping[Source].Supported);
+}
+
+ULONG
+HalSetProfileInterval (
+ IN ULONG Interval
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the profile interrupt interval.
+
+Arguments:
+
+ Interval - Supplies the desired profile interval in 100ns units.
+
+Return Value:
+
+ The actual profile interval.
+
+--*/
+
+{
+ ULONG NewInterval;
+
+ NewInterval = Interval;
+ HalSetProfileSourceInterval(ProfileTime, &NewInterval);
+ return(NewInterval);
+}
+
+
diff --git a/private/ntos/nthals/halalpha/halprof.h b/private/ntos/nthals/halalpha/halprof.h
new file mode 100644
index 000000000..bb02e1ff0
--- /dev/null
+++ b/private/ntos/nthals/halalpha/halprof.h
@@ -0,0 +1,77 @@
+/*++
+
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ halprof.h
+
+Abstract:
+
+ This header file defines profile counter hardware in the
+ 82357 PIC chip.
+
+Author:
+
+ Jeff McLeman (mcleman) 5-June-1992
+
+Revision History:
+
+--*/
+
+#ifndef _HALPROF_
+#define _HALPROF_
+
+
+//
+// Define the timer values for the Profiler
+//
+
+#define PIC_BINARY 0
+#define PIC_BCD 1
+
+#define PIC_MODE0 0x00 // xxxx000x
+#define PIC_MODE1 0x02 // xxxx001x
+#define PIC_MODE2 0x04 // xxxx010x
+#define PIC_MODE3 0x06 // xxxx011x
+#define PIC_MODE4 0x08 // xxxx100x
+#define PIC_MODE5 0x0A // xxxx101x
+
+#define PIC_CLC 0x00 // xx00xxxx
+#define PIC_RWLSBO 0x10 // xx01xxxx
+#define PIC_RWMSBO 0x20 // xx10xxxx
+#define PIC_RWLSBMSB 0x30 // xx11xxxx
+
+#define PIC_SC0 0x00 // 00xxxxxx
+#define PIC_SC1 0x40 // 01xxxxxx
+#define PIC_SC2 0x80 // 10xxxxxx
+#define PIC_RBC 0xC0 // 11xxxxxx
+
+
+#define PIC_SCALE_FACTOR 10 * 1000 // # of microsecond units times 10.
+
+//
+// Define a macro to set and enable the system profiler timer.
+// Note that the interval 'c' is in 100nS units.
+// Note that also the interval is incremented AFTER it is scaled.
+// This is due to the fact that the timer counts down to 1 in mode 2
+//
+
+#define PIC_PROFILER_ON(c)\
+ WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->CommandMode1,\
+ (UCHAR)(PIC_BINARY | PIC_MODE2 | PIC_RWLSBMSB | PIC_SC0));\
+ WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->Timer1,\
+ (UCHAR)((c) & 0xff) );\
+ WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->Timer1,\
+ (UCHAR)(((c)>> 8) & 0xff) )
+
+//
+// Define a macro to shut down the profiler
+//
+
+#define PIC_PROFILER_OFF()\
+ WRITE_PORT_UCHAR(&((PEISA_CONTROL) HalpEisaControlBase)->CommandMode1,\
+ (ULONG)(PIC_BINARY | PIC_MODE4 | PIC_RWLSBMSB | PIC_SC0))
+
+
+#endif // _HALPROF_
diff --git a/private/ntos/nthals/halalpha/haltsup.s b/private/ntos/nthals/halalpha/haltsup.s
new file mode 100644
index 000000000..0fa6c8d0e
--- /dev/null
+++ b/private/ntos/nthals/halalpha/haltsup.s
@@ -0,0 +1,110 @@
+// TITLE("Halt Interrupt Support")
+//++
+//
+// Copyright (c) 1992 Digital Equipment Corporation
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// haltsup.s
+//
+// Abstract:
+//
+// This module implements the code necessary to field halt button
+// interrupts.
+//
+// Author:
+//
+// Joe Notarangelo 18-Dec-1992
+//
+// Environment:
+//
+// Kernel mode only, IRQL halt synchronization level.
+//
+// Revision History:
+//
+//--
+
+#if !(DBG)
+
+//
+// Boolean value that controls whether to break or not for a halt button
+// interrupt on a free build. The default value is zero and must be set
+// in the debugger to a non-zero value to trigger the breakpoint action
+// when the halt button is pressed.
+//
+
+ .data
+
+ .globl HalpHaltButtonBreak
+HalpHaltButtonBreak:
+ .long 0 : 1
+
+#endif //!DBG
+
+
+#include "halalpha.h"
+
+ SBTTL("Halt Interrupt Support")
+//++
+//
+// Routine Description:
+//
+// This routine is entered as the result of a halt interrupt caused by
+// a human pushing the halt switch on the system box. This routine is
+// connected directly into the IDT. The halt interrupt is mechanical and
+// does not require an interrupt acknowledge.
+//
+// Arguments:
+//
+// s6/fp - Supplies a pointer to a trap frame.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ .struct 0
+HaltRa: .space 8 // saved return address
+ .space 8 // fill for alignment
+HaltFrameLength:
+
+ NESTED_ENTRY(HalpHaltInterrupt, ExceptionFrameLength, zero)
+
+ lda sp, -HaltFrameLength(sp) // allocate stack frame
+ stq ra, HaltRa(sp) // save ra
+
+ PROLOGUE_END
+
+
+#if DBG
+
+//
+// Always stop in the debugger if this is a checked build.
+//
+
+ BREAK_DEBUG_STOP // stop in the debugger
+
+#else
+
+//
+// If this is a free build then check the variable HalpHaltButtonBreak,
+// if it is non-zero then take the breakpoint, otherwise ignore it.
+//
+
+ lda t0, HalpHaltButtonBreak // get the address of the boolean
+ ldl t0, 0(t0) // read the boolean
+ beq t0, 10f // if eq, don't stop
+
+ BREAK_DEBUG_STOP // stop in the debugger
+
+10:
+
+#endif //DBG
+
+ ldq ra, HaltRa(sp) // save ra
+ lda sp, HaltFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // interrupt is dismissed
+
+ .end HalpHaltInterrupt
diff --git a/private/ntos/nthals/halalpha/halvfont.h b/private/ntos/nthals/halalpha/halvfont.h
new file mode 100644
index 000000000..df634a336
--- /dev/null
+++ b/private/ntos/nthals/halalpha/halvfont.h
@@ -0,0 +1,233 @@
+/*
+
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ halvfont.h
+
+Abstract:
+
+ 8x16 pixel fonts for the VGA video boot driver. Stolen from
+ David Conroy's Beta-machine fonts.
+
+
+
+Author:
+
+ John DeRosa 5/7/1992
+
+
+
+Revision History:
+
+ Jeff McLeman (DEC) 28-Jul-1992
+ Stole from FW to use with HAL and renamed to header file
+
+*/
+
+
+/*
+ * ASCII characters 0x20 -- 0x7f (space -- del). Each byte is one
+ * scan line, and each character is 2 rows.
+ */
+
+unsigned char vga8x16undef[] = {
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+ };
+
+unsigned char vga8x16chars[] = {
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0xFF, 0xFF, 0x66, 0x66,
+ 0xFF, 0xFF, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x18, 0x18, 0x3E, 0x7E, 0x60, 0x60, 0x7C, 0x3E,
+ 0x06, 0x06, 0x7E, 0x7C, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x6C, 0x0C, 0x18, 0x18,
+ 0x30, 0x36, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x38, 0x7C, 0x6C, 0x6C, 0x38, 0x38, 0x70, 0x70,
+ 0xDE, 0xDE, 0xCC, 0xCC, 0xFE, 0x76, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x0C, 0x1C, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x1C, 0x0C, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x30, 0x38, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x38, 0x30, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x3C, 0x3C, 0xFF, 0xFF,
+ 0x3C, 0x3C, 0x66, 0x66, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x7E, 0x7E,
+ 0x18, 0x18, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x30, 0x20,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x06, 0x0C, 0x0C, 0x18,
+ 0x18, 0x30, 0x30, 0x60, 0x60, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x6E,
+ 0x76, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x38, 0x38, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x0C, 0x0C,
+ 0x18, 0x18, 0x30, 0x30, 0x7E, 0x7E, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x0C, 0x0C, 0x18, 0x18,
+ 0x0C, 0x0C, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x0C, 0x0C, 0x1C, 0x1C, 0x3C, 0x3C,
+ 0x6C, 0x6C, 0x7E, 0x7E, 0x0C, 0x0C, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x60, 0x60, 0x7C, 0x7E,
+ 0x06, 0x06, 0x06, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x1C, 0x3C, 0x70, 0x60, 0x60, 0x7C,
+ 0x7E, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x06, 0x06, 0x0C, 0x0C,
+ 0x18, 0x18, 0x30, 0x30, 0x30, 0x30, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x3C, 0x3C,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x7E, 0x3E,
+ 0x06, 0x06, 0x06, 0x0E, 0x3C, 0x38, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18,
+ 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0x30, 0x20,
+ 0x00, 0x00, 0x00, 0x0E, 0x1C, 0x38, 0x70, 0xE0,
+ 0x70, 0x38, 0x1C, 0x0E, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x00, 0x00,
+ 0x7E, 0x7E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0xE0, 0x70, 0x38, 0x1C, 0x0E,
+ 0x1C, 0x38, 0x70, 0xE0, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x0C, 0x0C,
+ 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x7C, 0xE6, 0xC2, 0xDA, 0xD6,
+ 0xD6, 0xDC, 0xC0, 0xE2, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x3C, 0x7E, 0x66, 0x66, 0x66,
+ 0x7E, 0x7E, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x7E, 0x66, 0x66, 0x7E, 0x7C,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x60, 0x60,
+ 0x60, 0x60, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x7C, 0x6E, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x6E, 0x7C, 0x78, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x60, 0x60, 0x7C, 0x7C,
+ 0x60, 0x60, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x60, 0x60, 0x7C, 0x7C,
+ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x3E, 0x7E, 0x60, 0x60, 0x6E, 0x6E,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7E,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x7E, 0x7E, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06,
+ 0x06, 0x06, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0xCC, 0xCC, 0xD8, 0xD8, 0xF0, 0xF0,
+ 0xD8, 0xD8, 0xCC, 0xCC, 0xC6, 0xC6, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x60, 0x60, 0x60, 0x60, 0x60,
+ 0x60, 0x60, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00,
+ 0x00, 0x00, 0xC6, 0xC6, 0xEE, 0xEE, 0xFE, 0xD6,
+ 0xD6, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x76, 0x76, 0x7E,
+ 0x7E, 0x6E, 0x6E, 0x66, 0x66, 0x66, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x7C, 0x7E, 0x66, 0x66, 0x66, 0x66,
+ 0x7E, 0x7C, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x3C, 0x7E, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x6A, 0x7C, 0x36, 0x00, 0x00,
+ 0x00, 0x00, 0xF8, 0xFC, 0xCC, 0xCC, 0xCC, 0xFC,
+ 0xF8, 0xD8, 0xCC, 0xCC, 0xC6, 0xC6, 0x00, 0x00,
+ 0x00, 0x00, 0x3E, 0x7E, 0x60, 0x60, 0x70, 0x38,
+ 0x1C, 0x0E, 0x06, 0x06, 0x7E, 0x7C, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0xC6, 0xC6, 0xC6, 0xC6, 0xC6, 0xD6,
+ 0xD6, 0xFE, 0xFE, 0xEE, 0xC6, 0x82, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x3C, 0x3C, 0x18,
+ 0x18, 0x3C, 0x3C, 0x66, 0x66, 0x66, 0x00, 0x00,
+ 0x00, 0x00, 0x66, 0x66, 0x66, 0x66, 0x3C, 0x3C,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x7E, 0x7E, 0x0C, 0x0C, 0x18, 0x18,
+ 0x30, 0x30, 0x60, 0x60, 0x7E, 0x7E, 0x00, 0x00,
+ 0x00, 0x00, 0x1E, 0x1E, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1E, 0x1E, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x60, 0x60, 0x30, 0x30, 0x18,
+ 0x18, 0x0C, 0x0C, 0x06, 0x06, 0x06, 0x00, 0x00,
+ 0x00, 0x00, 0x78, 0x78, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x78, 0x78, 0x00, 0x00,
+ 0x00, 0x10, 0x10, 0x38, 0x38, 0x6C, 0x6C, 0xC6,
+ 0xC6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFE, 0x00, 0x00,
+ 0x40, 0x60, 0x70, 0x38, 0x1C, 0x0C, 0x04, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x3E, 0x06,
+ 0x3E, 0x7E, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x60, 0x60, 0x60, 0x7C, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x60,
+ 0x60, 0x60, 0x60, 0x60, 0x7E, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x06, 0x06, 0x06, 0x3E, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66,
+ 0x66, 0x7E, 0x60, 0x60, 0x7E, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x0E, 0x1E, 0x18, 0x18, 0x7E, 0x7E,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x7E, 0x7C,
+ 0x00, 0x00, 0x60, 0x60, 0x60, 0x7C, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+ 0x00, 0x00, 0x18, 0x18, 0x00, 0x38, 0x38, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x0C, 0x0C, 0x00, 0x0C, 0x0C, 0x0C,
+ 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x7C, 0x78,
+ 0x00, 0x00, 0xC0, 0xC0, 0xC0, 0xCC, 0xDC, 0xF8,
+ 0xF0, 0xF8, 0xD8, 0xCC, 0xCE, 0xC6, 0x00, 0x00,
+ 0x00, 0x00, 0x38, 0x38, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x3C, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x6C, 0xFE, 0xFE,
+ 0xD6, 0xD6, 0xD6, 0xC6, 0xC6, 0xC6, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3C, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x7C, 0x60, 0x60,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x06,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7C, 0x7E, 0x66,
+ 0x60, 0x60, 0x60, 0x60, 0x60, 0x60, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x3E, 0x7E, 0x60,
+ 0x70, 0x3C, 0x0E, 0x06, 0x7E, 0x7C, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x18, 0x18, 0x7E, 0x7E, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x1E, 0x0E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x3C, 0x3C, 0x18, 0x18, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0xC6, 0xC6, 0xD6,
+ 0xD6, 0xFE, 0xFE, 0xEE, 0xC6, 0x82, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x3C,
+ 0x3C, 0x18, 0x3C, 0x3C, 0x66, 0x66, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x7E, 0x3E, 0x06, 0x7E, 0x7C,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x7E, 0x7E, 0x0C,
+ 0x18, 0x18, 0x30, 0x30, 0x7E, 0x7E, 0x00, 0x00,
+ 0x00, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x38, 0xF0,
+ 0xF0, 0x38, 0x18, 0x18, 0x18, 0x18, 0x0E, 0x00,
+ 0x00, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
+ 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x00,
+ 0x00, 0xE0, 0x30, 0x30, 0x30, 0x30, 0x38, 0x1E,
+ 0x1E, 0x38, 0x30, 0x30, 0x30, 0x30, 0xE0, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x62, 0xF2, 0xBE,
+ 0x9C, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
diff --git a/private/ntos/nthals/halalpha/halvga.h b/private/ntos/nthals/halalpha/halvga.h
new file mode 100644
index 000000000..c393d49c7
--- /dev/null
+++ b/private/ntos/nthals/halalpha/halvga.h
@@ -0,0 +1,72 @@
+/*
+
+Copyright (c) 1992, 1993, 1994 Digital Equipment Corporation
+
+Module Name:
+
+ halvga.h
+
+
+Abstract:
+
+ Defines registers for standard VGA alphanumeric color mode video.
+ (graphics, bw mode are not defined.)
+
+ Addresses are based on the VGA video ISA base address.
+
+
+Author:
+
+ John DeRosa 4/30/92
+
+
+Revision History:
+
+ 17-Feb-1994 Eric Rehm
+ Remove all references to VGA. HAL display routines are
+ now device-independent.
+
+*/
+
+#ifndef _HALVGA_
+#define _HALVGA_
+
+//
+// Define special character values for device-indpendent control functions.
+//
+
+#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 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 // _HALVGA_
diff --git a/private/ntos/nthals/halalpha/idle.s b/private/ntos/nthals/halalpha/idle.s
new file mode 100644
index 000000000..0d53d7aed
--- /dev/null
+++ b/private/ntos/nthals/halalpha/idle.s
@@ -0,0 +1,62 @@
+// TITLE("Processor Idle Support")
+//++
+//
+// Copyright (c) 1992 Digital Equipment Corporation
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// idle.s
+//
+// Abstract:
+//
+// This module implements the HalProcessorIdle interface
+//
+// Author:
+//
+// John Vert (jvert) 11-May-1994
+//
+// Environment:
+//
+// Revision History:
+//
+//--
+#include "halalpha.h"
+
+
+ SBTTL("Processor Idle")
+//++
+//
+// VOID
+// HalProcessorIdle(
+// VOID
+// )
+//
+// Routine Description:
+//
+// This function is called when the current processor is idle with
+// interrupts disabled. There is no thread active and there are no
+// DPCs to process. Therefore, power can be switched to a standby
+// mode until the the next interrupt occurs on the current processor.
+//
+// N.B. This routine is entered with interrupts disabled. This routine
+// must do any power management enabling necessary, enable interrupts,
+// then either return or wait for an interrupt.
+//
+// Arguments:
+//
+// None.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(HalProcessorIdle)
+
+ ENABLE_INTERRUPTS // no power management, just
+ // enable interrupts and return
+ ret zero, (ra)
+
+ .end HalProcessorIdle
diff --git a/private/ntos/nthals/halalpha/info.c b/private/ntos/nthals/halalpha/info.c
new file mode 100644
index 000000000..141ceff53
--- /dev/null
+++ b/private/ntos/nthals/halalpha/info.c
@@ -0,0 +1,180 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ info.c
+
+Abstract:
+
+Author:
+
+ Ken Reneris (kenr) 08-Aug-1994
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+
+#include "halp.h"
+
+#ifdef _PNP_POWER_
+HAL_CALLBACKS HalCallback;
+#endif // _PNP_POWER_
+
+//
+// External references
+//
+
+extern WINDOW_CONTROL_REGISTERS HalpIsaWindowControl;
+extern WINDOW_CONTROL_REGISTERS HalpMasterWindowControl;
+
+
+
+NTSTATUS
+HalpQueryInstalledBusInformation (
+ OUT PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG ReturnedLength
+ );
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE,HaliQuerySystemInformation)
+#pragma alloc_text(PAGE,HaliSetSystemInformation)
+#endif
+
+
+NTSTATUS
+HaliQuerySystemInformation(
+ IN HAL_QUERY_INFORMATION_CLASS InformationClass,
+ IN ULONG BufferSize,
+ IN OUT PVOID Buffer,
+ OUT PULONG ReturnedLength
+ )
+/*++
+
+Routine Description:
+
+ The function returns system-wide information controlled by the HAL for a
+ variety of classes.
+
+Arguments:
+
+ InformationClass - Information class of the request.
+
+ BufferSize - Size of buffer supplied by the caller.
+
+ Buffer - Supplies the space to store the data and pass additional info.
+
+ ReturnedLength - Supplies a count in bytes of the amount of data returned.
+
+Return Value:
+
+ STATUS_SUCCESS or error.
+
+--*/
+{
+ NTSTATUS Status;
+ PULONG mapRegisters;
+
+ switch (InformationClass) {
+ case HalInstalledBusInformation:
+ Status = HalpQueryInstalledBusInformation (
+ Buffer,
+ BufferSize,
+ ReturnedLength
+ );
+ break;
+
+ case HalProfileSourceInformation:
+ Status = HalpProfileSourceInformation (
+ Buffer,
+ BufferSize,
+ ReturnedLength);
+ break;
+
+ case HalMapRegisterInformation:
+ mapRegisters = (PULONG)Buffer;
+ if ( BufferSize < 4 ) {
+ Status = STATUS_BUFFER_TOO_SMALL;
+ } else {
+ switch ( *(PULONG)Buffer ) {
+ case Isa:
+ *mapRegisters = HalpIsaWindowControl.WindowSize / PAGE_SIZE;
+ *ReturnedLength = 4;
+ Status = STATUS_SUCCESS;
+ break;
+
+ case Eisa:
+ case PCIBus:
+ *mapRegisters = HalpMasterWindowControl.WindowSize / PAGE_SIZE;
+ *ReturnedLength = 4;
+ Status = STATUS_SUCCESS;
+ break;
+
+ default:
+ Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ }
+ break;
+
+ default:
+ Status = STATUS_INVALID_LEVEL;
+ break;
+ }
+
+ return(Status);
+}
+
+NTSTATUS
+HaliSetSystemInformation (
+ IN HAL_SET_INFORMATION_CLASS InformationClass,
+ IN ULONG BufferSize,
+ IN PVOID Buffer
+ )
+/*++
+
+Routine Description:
+
+ The function allows setting of various fields return by
+ HalQuerySystemInformation.
+
+Arguments:
+
+ InformationClass - Information class of the request.
+
+ BufferSize - Size of buffer supplied by the caller.
+
+ Buffer - Supplies the data to be set.
+
+Return Value:
+
+ STATUS_SUCCESS or error.
+
+--*/
+{
+ NTSTATUS Status;
+
+ switch (InformationClass) {
+
+ case HalProfileSourceInterval:
+ Status = HalpProfileSourceInterval (
+ Buffer,
+ BufferSize);
+ break;
+
+ default:
+ Status = STATUS_INVALID_LEVEL;
+ break;
+ }
+
+ return Status;
+}
diff --git a/private/ntos/nthals/halalpha/inithal.c b/private/ntos/nthals/halalpha/inithal.c
new file mode 100644
index 000000000..a3bc08c7a
--- /dev/null
+++ b/private/ntos/nthals/halalpha/inithal.c
@@ -0,0 +1,1052 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ inithal.c
+
+Abstract:
+
+
+ This module implements the initialization of the system dependent
+ functions that define the Hardware Architecture Layer (HAL) for an
+ Alpha machine
+
+Author:
+
+ David N. Cutler (davec) 25-Apr-1991
+ Miche Baker-Harvey (miche) 18-May-1992
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+ 28-Jul-1992 Jeff McLeman (mcleman)
+ Add code to allocate a mapping buffer for buffered DMA
+
+ 14-Jul-1992 Jeff McLeman (mcleman)
+ Add call to HalpCachePcrValues, which will call the PALcode to
+ cache values of the PCR that need fast access.
+
+ 10-Jul-1992 Jeff McLeman (mcleman)
+ Remove reference to initializing the fixed TB entries, since Alpha
+ does not have fixed TB entries.
+
+ 24-Sep-1993 Joe Notarangelo
+ Restructured to make this module platform-independent.
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+
+
+//
+// Declare the extern variable UncorrectableError declared in
+// inithal.c.
+//
+PERROR_FRAME PUncorrectableError;
+
+//
+// external
+//
+
+ULONG HalDisablePCIParityChecking = 0xffffffff;
+
+//
+// Define HAL spinlocks.
+//
+
+KSPIN_LOCK HalpBeepLock;
+KSPIN_LOCK HalpDisplayAdapterLock;
+KSPIN_LOCK HalpSystemInterruptLock;
+
+//
+// Mask of all of the processors that are currently active.
+//
+
+KAFFINITY HalpActiveProcessors;
+
+//
+// Mapping of the logical processor numbers to the physical processors.
+//
+
+ULONG HalpLogicalToPhysicalProcessor[HAL_MAXIMUM_PROCESSOR+1];
+
+ULONG AlreadySet = 0;
+
+//
+// HalpClockFrequency is the processor cycle counter frequency in units
+// of cycles per second (Hertz). It is a large number (e.g., 125,000,000)
+// but will still fit in a ULONG.
+//
+// HalpClockMegaHertz is the processor cycle counter frequency in units
+// of megahertz. It is a small number (e.g., 125) and is also the number
+// of cycles per microsecond. The assumption here is that clock rates will
+// always be an integral number of megahertz.
+//
+// Having the frequency available in both units avoids multiplications, or
+// especially divisions in time critical code.
+//
+
+ULONG HalpClockFrequency;
+ULONG HalpClockMegaHertz = DEFAULT_PROCESSOR_FREQUENCY_MHZ;
+
+ULONGLONG HalpContiguousPhysicalMemorySize;
+//
+// Use the square wave mode of the PIT to measure the processor
+// speed. The timer has a frequency of 1.193MHz. We want a
+// square wave with a period of 50ms so we must initialize the
+// pit with a count of:
+// 50ms*1.193MHz = 59650 cycles
+//
+
+#define TIMER_REF_VALUE 59650
+
+VOID
+HalpVerifyPrcbVersion(
+ VOID
+ );
+
+VOID
+HalpRecurseLoaderBlock(
+ IN PCONFIGURATION_COMPONENT_DATA CurrentEntry
+ );
+
+ULONG
+HalpQuerySystemFrequency(
+ ULONG SampleTime
+ );
+
+VOID
+HalpAllocateUncorrectableFrame(
+ VOID
+ );
+
+
+BOOLEAN
+HalInitSystem (
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes the Hardware Architecture Layer (HAL) for an
+ Alpha system.
+
+Arguments:
+
+ Phase - Supplies the initialization phase (zero or one).
+
+ LoaderBlock - Supplies a pointer to a loader parameter block.
+
+Return Value:
+
+ A value of TRUE is returned is the initialization was successfully
+ complete. Otherwise a value of FALSE is returend.
+
+--*/
+
+{
+ PKPRCB Prcb;
+ ULONG BuildType = 0;
+
+ Prcb = PCR->Prcb;
+
+ //
+ // Perform initialization for the primary processor.
+ //
+
+ if( Prcb->Number == HAL_PRIMARY_PROCESSOR ){
+
+ if (Phase == 0) {
+
+#if HALDBG
+
+ DbgPrint( "HAL/HalInitSystem: Phase = %d\n", Phase );
+ DbgBreakPoint();
+ HalpDumpMemoryDescriptors( LoaderBlock );
+
+#endif //HALDBG
+ //
+ // Get the memory Size.
+ //
+ HalpContiguousPhysicalMemorySize =
+ HalpGetContiguousMemorySize( LoaderBlock );
+
+ //
+ // Set second level cache size
+ // NOTE: Although we set the PCR with the right cache size this
+ // could be overridden by setting the Registry key
+ // HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet
+ // \Control\Session Manager
+ // \Memory Management\SecondLevelDataCache.
+ //
+ // If the secondlevel cache size is 0 or 512KB then it is
+ // possible that the firmware is an old one. In which case
+ // we determine the cache size here. If the value is anything
+ // other than these then it is a new firmware and probably
+ // reporting the correct cache size hence use this value.
+ //
+
+ if(LoaderBlock->u.Alpha.SecondLevelDcacheSize == 0 ||
+ LoaderBlock->u.Alpha.SecondLevelDcacheSize == 512*__1K){
+ PCR->SecondLevelCacheSize = HalpGetBCacheSize(
+ HalpContiguousPhysicalMemorySize
+ );
+ } else {
+ PCR->SecondLevelCacheSize =
+ LoaderBlock->u.Alpha.SecondLevelDcacheSize;
+ }
+
+ //
+ // Initialize HAL spinlocks.
+ //
+
+ KeInitializeSpinLock(&HalpBeepLock);
+ KeInitializeSpinLock(&HalpDisplayAdapterLock);
+ KeInitializeSpinLock(&HalpSystemInterruptLock);
+
+ //
+ // Fill in handlers for APIs which this HAL supports
+ //
+
+ HalQuerySystemInformation = HaliQuerySystemInformation;
+ HalSetSystemInformation = HaliSetSystemInformation;
+
+ //
+ // Phase 0 initialization.
+ //
+
+ HalpSetTimeIncrement();
+ HalpMapIoSpace();
+ HalpEstablishErrorHandler();
+ HalpInitializeDisplay(LoaderBlock);
+ HalpInitializeMachineDependent( Phase, LoaderBlock );
+ HalpCreateDmaStructures(LoaderBlock);
+ HalpInitializeInterrupts();
+ HalpVerifyPrcbVersion();
+
+ //
+ // Set the processor active in the HAL active processor mask.
+ //
+
+ HalpActiveProcessors = 1 << Prcb->Number;
+
+ //
+ // Initialize the logical to physical processor mapping
+ // for the primary processor.
+ //
+ HalpLogicalToPhysicalProcessor[0] = HAL_PRIMARY_PROCESSOR;
+
+ return TRUE;
+
+ } else {
+
+#if HALDBG
+
+ DbgPrint( "HAL/HalInitSystem: Phase = %d\n", Phase );
+ DbgBreakPoint();
+
+#endif //HALDBG
+
+ //
+ // Phase 1 initialization.
+ //
+
+ HalpInitializeClockInterrupts();
+ HalpInitializeMachineDependent( Phase, LoaderBlock );
+
+ //
+ // Allocate memory for the uncorrectable frame
+ //
+
+ HalpAllocateUncorrectableFrame();
+
+ //
+ // Initialize the Buffer for Uncorrectable Error.
+ //
+
+ HalpInitializeUncorrectableErrorFrame();
+
+ return TRUE;
+
+ }
+ }
+
+ //
+ // Perform necessary processor-specific initialization for
+ // secondary processors. Phase is ignored as this will be called
+ // only once on each secondary processor.
+ //
+
+ HalpMapIoSpace();
+ HalpInitializeInterrupts();
+ HalpInitializeMachineDependent( Phase, LoaderBlock );
+
+ //
+ // Set the processor active in the HAL active processor mask.
+ //
+
+ HalpActiveProcessors |= 1 << Prcb->Number;
+
+#if HALDBG
+
+ DbgPrint( "Secondary %d is alive\n", Prcb->Number );
+
+#endif //HALDBG
+
+ return TRUE;
+}
+
+VOID
+HalpAllocateUncorrectableFrame(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function is called after the Phase1 Machine Dependent initialization.
+ It must be called only after Phase1 machine-dependent initialization.
+ This function allocates the necessary amountof memory for storing the
+ uncorrectable error frame. This function makes a call to a machine-
+ dependent function 'HalpGetMachineDependentErrorFrameSizes' for
+ getting the size of the Processor Specific and System Specific error
+ frame size. The machine-dependent code will know the size of these
+ frames after the machine-dependent Phase1 initialization.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG RawProcessorFrameSize;
+ ULONG RawSystemFrameSize;
+ ULONG EntireErrorFrameSize;
+
+ //
+ // First get the machine-dependent error frame sizes.
+ //
+ HalpGetMachineDependentErrorFrameSizes(
+ &RawProcessorFrameSize,
+ &RawSystemFrameSize);
+
+ //
+ // Compute the total size of the error frame
+ //
+ EntireErrorFrameSize = sizeof(ERROR_FRAME) + RawProcessorFrameSize +
+ RawSystemFrameSize;
+
+ //
+ // Allocate space to store the error frame.
+ // Not sure if it is OK to use ExAllocatePool at this instant.
+ // We will give this a try if it doesn't work What do we do??!!
+ //
+
+ PUncorrectableError = ExAllocatePool(NonPagedPool,
+ EntireErrorFrameSize);
+ if(PUncorrectableError == NULL) {
+ return;
+ }
+
+ PUncorrectableError->LengthOfEntireErrorFrame = EntireErrorFrameSize;
+
+ //
+ // if the size is not equal to zero then set the RawInformation pointers
+ // to point to the right place. If not set the pointer to NULL and set
+ // size to 0.
+ //
+
+ //
+ // make Raw processor info to point right after the error frame.
+ //
+ if(RawProcessorFrameSize) {
+ PUncorrectableError->UncorrectableFrame.RawProcessorInformation =
+ (PVOID)((PUCHAR)PUncorrectableError + sizeof(ERROR_FRAME) );
+ PUncorrectableError->UncorrectableFrame.RawProcessorInformationLength =
+ RawProcessorFrameSize;
+ }
+ else{
+ PUncorrectableError->UncorrectableFrame.RawProcessorInformation =
+ NULL;
+ PUncorrectableError->UncorrectableFrame.RawProcessorInformationLength =
+ 0;
+ }
+ if(RawSystemFrameSize){
+ PUncorrectableError->UncorrectableFrame.RawSystemInformation =
+ (PVOID)((PUCHAR)PUncorrectableError->UncorrectableFrame.
+ RawProcessorInformation + RawProcessorFrameSize);
+ PUncorrectableError->UncorrectableFrame.RawSystemInformationLength =
+ RawSystemFrameSize;
+ }
+ else{
+ PUncorrectableError->UncorrectableFrame.RawSystemInformation =
+ NULL;
+ PUncorrectableError->UncorrectableFrame.RawSystemInformationLength =
+ 0;
+ }
+}
+
+VOID
+HalpGetProcessorInfo(
+ PPROCESSOR_INFO pProcessorInfo
+)
+/*++
+
+Routine Description:
+
+ Collects the Processor Information and fills in the buffer.
+
+Arguments:
+
+ pProcessorInfo - Pointer to the PROCESSOR_INFO structure into which
+ the processor information will be filled in.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PKPRCB Prcb;
+
+ pProcessorInfo->ProcessorType = PCR->ProcessorType;
+ pProcessorInfo->ProcessorRevision = PCR->ProcessorRevision;
+
+ Prcb = PCR->Prcb;
+ pProcessorInfo->LogicalProcessorNumber = Prcb->Number;
+ pProcessorInfo->PhysicalProcessorNumber =
+ HalpLogicalToPhysicalProcessor[Prcb->Number];
+ return;
+}
+
+
+
+VOID
+HalInitializeProcessor (
+ IN ULONG Number
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called early in the initialization of the kernel
+ to perform platform dependent initialization for each processor
+ before the HAL Is fully functional.
+
+ N.B. When this routine is called, the PCR is present but is not
+ fully initialized.
+
+Arguments:
+
+ Number - Supplies the number of the processor to initialize.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+//jnfix - for mp systems if processor != 0 then init PALcode?
+//either here or in next module?
+ return;
+}
+
+BOOLEAN
+HalStartNextProcessor (
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN PKPROCESSOR_STATE ProcessorState
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called to start the next processor.
+
+Arguments:
+
+ LoaderBlock - Supplies a pointer to the loader parameter block.
+
+ ProcessorState - Supplies a pointer to the processor state to be
+ used to start the processor.
+
+Return Value:
+
+ If a processor is successfully started, then a value of TRUE is
+ returned. Otherwise a value of FALSE is returned. If a value of
+ TRUE is returned, then the logical processor number is stored
+ in the processor control block specified by the loader block.
+
+--*/
+
+{
+ ULONG LogicalNumber;
+ PRESTART_BLOCK NextRestartBlock;
+ ULONG PhysicalNumber;
+ PKPRCB Prcb;
+
+#if !defined(NT_UP)
+
+ //
+ // If the address of the first restart parameter block is NULL, then
+ // the host system is a uniprocessor system running with old firmware.
+ // Otherwise, the host system may be a multiprocessor system if more
+ // than one restart block is present.
+ //
+ // N.B. The first restart parameter block must be for the boot master
+ // and must represent logical processor 0.
+ //
+
+ NextRestartBlock = SYSTEM_BLOCK->RestartBlock;
+ if (NextRestartBlock == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Scan the restart parameter blocks for a processor that is ready,
+ // but not running. If a processor is found, then fill in the restart
+ // processor state, set the logical processor number, and set start
+ // in the boot status.
+ //
+
+ LogicalNumber = 0;
+ PhysicalNumber = 0;
+ do {
+
+ //
+ // If the processor is not ready then we assume that it is not
+ // present. We must increment the physical processor number but
+ // the logical processor number does not changed.
+ //
+
+ if( NextRestartBlock->BootStatus.ProcessorReady == FALSE ){
+
+ PhysicalNumber += 1;
+
+ } else {
+
+ //
+ // Check if this processor has already been started.
+ // If it has not then start it now.
+ //
+
+ if( NextRestartBlock->BootStatus.ProcessorStart == FALSE ){
+
+ RtlZeroMemory( &NextRestartBlock->u.Alpha,
+ sizeof(ALPHA_RESTART_STATE));
+ NextRestartBlock->u.Alpha.IntA0 =
+ ProcessorState->ContextFrame.IntA0;
+ NextRestartBlock->u.Alpha.IntSp =
+ ProcessorState->ContextFrame.IntSp;
+ NextRestartBlock->u.Alpha.ReiRestartAddress =
+ (ULONG)ProcessorState->ContextFrame.Fir;
+ Prcb = (PKPRCB)(LoaderBlock->Prcb);
+ Prcb->Number = (CCHAR)LogicalNumber;
+ Prcb->RestartBlock = NextRestartBlock;
+ NextRestartBlock->BootStatus.ProcessorStart = 1;
+
+ HalpLogicalToPhysicalProcessor[LogicalNumber] = PhysicalNumber;
+
+ return TRUE;
+
+ } else {
+
+ //
+ // Ensure that the logical to physical mapping has been
+ // established for this processor.
+ //
+
+ HalpLogicalToPhysicalProcessor[LogicalNumber] = PhysicalNumber;
+
+ }
+
+ LogicalNumber += 1;
+ PhysicalNumber += 1;
+ }
+
+ NextRestartBlock = NextRestartBlock->NextRestartBlock;
+
+ } while (NextRestartBlock != NULL);
+
+#endif // !defined(NT_UP)
+
+ return FALSE;
+}
+
+VOID
+HalpVerifyPrcbVersion(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function verifies that the HAL matches the kernel. If there
+ is a mismatch the HAL bugchecks the system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PKPRCB Prcb;
+
+ //
+ // Verify Prcb major version number, and build options are
+ // all conforming to this binary image
+ //
+
+ Prcb = KeGetCurrentPrcb();
+
+#if DBG
+ if (!(Prcb->BuildType & PRCB_BUILD_DEBUG)) {
+ // This checked hal requires a checked kernel
+ KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, PRCB_BUILD_DEBUG, 0);
+ }
+#else
+ if (Prcb->BuildType & PRCB_BUILD_DEBUG) {
+ // This free hal requires a free kernel
+ KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0);
+ }
+#endif
+#ifndef NT_UP
+ if (Prcb->BuildType & PRCB_BUILD_UNIPROCESSOR) {
+ // This MP hal requires an MP kernel
+ KeBugCheckEx (MISMATCHED_HAL, 2, Prcb->BuildType, 0, 0);
+ }
+#endif
+ if (Prcb->MajorVersion != PRCB_MAJOR_VERSION) {
+ KeBugCheckEx (MISMATCHED_HAL,
+ 1, Prcb->MajorVersion, PRCB_MAJOR_VERSION, 0);
+ }
+
+
+}
+
+
+VOID
+HalpParseLoaderBlock(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+{
+
+ if (LoaderBlock == NULL) {
+ return;
+ }
+
+ HalpRecurseLoaderBlock( (PCONFIGURATION_COMPONENT_DATA)
+ LoaderBlock->ConfigurationRoot);
+}
+
+
+
+VOID
+HalpRecurseLoaderBlock(
+ IN PCONFIGURATION_COMPONENT_DATA CurrentEntry
+ )
+/*++
+
+Routine Description:
+
+ This routine parses the loader parameter block looking for the PCI
+ node. Once found, used to determine if PCI parity checking should be
+ enabled or disabled. Set the default to not disable checking.
+
+Arguments:
+
+ CurrentEntry - Supplies a pointer to a loader configuration
+ tree or subtree.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ PCONFIGURATION_COMPONENT Component;
+ PWSTR NameString;
+
+ //
+ // Quick out
+ //
+
+ if (AlreadySet) {
+ return;
+ }
+
+ if (CurrentEntry) {
+ Component = &CurrentEntry->ComponentEntry;
+
+ if (Component->Class == AdapterClass &&
+ Component->Type == MultiFunctionAdapter) {
+
+ if (strcmp(Component->Identifier, "PCI") == 0) {
+ HalDisablePCIParityChecking = Component->Flags.ConsoleOut;
+ AlreadySet = TRUE;
+#if HALDBG
+ DbgPrint("ARC tree sets PCI parity checking to %s\n",
+ HalDisablePCIParityChecking ? "OFF" : "ON");
+#endif
+ return;
+ }
+ }
+
+ //
+ // Process all the Siblings of current entry
+ //
+
+ HalpRecurseLoaderBlock(CurrentEntry->Sibling);
+
+ //
+ // Process all the Childeren of current entry
+ //
+
+ HalpRecurseLoaderBlock(CurrentEntry->Child);
+
+ }
+}
+
+
+ULONG
+HalpQuerySystemFrequency(
+ ULONG SampleTime
+ )
+/*++
+
+Routine Description:
+
+ This routine returns the speed at which the system is running in hertz.
+ The system frequency is calculated by counting the number of processor
+ cycles that occur during 500ms, using the Programmable Interval Timer
+ (PIT) as the reference time. The PIT is used to generate a square
+ wave with a 50ms Period. We use the Speaker counter since we can
+ enable and disable the count from software. The output of the
+ speaker is obtained from the SIO NmiStatus register.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The system frequency in Hertz.
+
+--*/
+{
+ TIMER_CONTROL TimerControlSetup;
+ TIMER_CONTROL TimerControlReadStatus;
+ TIMER_STATUS TimerStatus;
+ NMI_STATUS NmiStatus;
+ PEISA_CONTROL controlBase;
+ ULONGLONG Count1;
+ ULONGLONG Count2;
+ ULONG NumberOfIntervals;
+ ULONG SquareWaveState = 0;
+
+// mdbfix - move this into eisa.h one day
+#define SB_READ_STATUS_ONLY 2
+
+ controlBase = HalpEisaControlBase;
+
+ //
+ // Disable the speaker counter.
+ //
+
+ *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
+
+ NmiStatus.SpeakerGate = 0;
+ NmiStatus.SpeakerData = 0;
+
+ // these are MBZ when writing to NMIMISC
+ NmiStatus.RefreshToggle = 0;
+ NmiStatus.SpeakerTimer = 0;
+ NmiStatus.IochkNmi = 0;
+
+ WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
+
+ //
+ // Number of Square Wave transitions to count.
+ // at 50ms period, count the number of 25ms
+ // square wave transitions for a sample reference
+ // time to against which we measure processor cycle count.
+ //
+
+ NumberOfIntervals = (SampleTime/50) * 2;
+
+ //
+ // Set the timer for counter 0 in binary mode, square wave output
+ //
+
+ TimerControlSetup.BcdMode = 0;
+ TimerControlSetup.Mode = TM_SQUARE_WAVE;
+ TimerControlSetup.SelectByte = SB_LSB_THEN_MSB;
+ TimerControlSetup.SelectCounter = SELECT_COUNTER_2;
+
+ //
+ // Set the counter for a latched read of the status.
+ // We will poll the PIT for the state of the square
+ // wave output.
+ //
+
+ TimerControlReadStatus.BcdMode = 0;
+ TimerControlReadStatus.Mode = (1 << SELECT_COUNTER_2);
+ TimerControlReadStatus.SelectByte = SB_READ_STATUS_ONLY;
+ TimerControlReadStatus.SelectCounter = SELECT_READ_BACK;
+
+
+ //
+ // Write the count value LSB and MSB for a 50ms clock period
+ //
+
+ WRITE_PORT_UCHAR( &controlBase->CommandMode1,
+ *(PUCHAR)&TimerControlSetup );
+
+ WRITE_PORT_UCHAR( &controlBase->SpeakerTone,
+ TIMER_REF_VALUE & 0xff );
+
+ WRITE_PORT_UCHAR( &controlBase->SpeakerTone,
+ (TIMER_REF_VALUE >> 8) & 0xff );
+
+ //
+ // Enable the speaker counter but disable the SPKR output signal.
+ //
+
+ *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
+
+ NmiStatus.SpeakerGate = 1;
+ NmiStatus.SpeakerData = 0;
+
+ // these are MBZ when writing to NMIMISC
+ NmiStatus.RefreshToggle = 0;
+ NmiStatus.SpeakerTimer = 0;
+ NmiStatus.IochkNmi = 0;
+
+ WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
+
+ //
+ // Synchronize with the counter before taking the first
+ // sample of the Processor Cycle Count (PCC). Since we
+ // are using the Square Wave Mode, wait until the next
+ // state change and then observe half a cycle before
+ // sampling.
+ //
+
+ //
+ // observe the low transition of the square wave output.
+ //
+ do {
+
+ *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
+
+ } while (NmiStatus.SpeakerTimer != SquareWaveState);
+
+ SquareWaveState ^= 1;
+
+ //
+ // observe the next transition of the square wave output and then
+ // take the first cycle counter sample.
+ //
+ do {
+
+ *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
+
+ } while (NmiStatus.SpeakerTimer != SquareWaveState);
+
+ Count1 = __RCC();
+
+ //
+ // Wait for the 500ms time period to pass and then take the
+ // second sample of the PCC. For a 50ms period, we have to
+ // observe eight wave transitions (25ms each).
+ //
+
+ do {
+
+ SquareWaveState ^= 1;
+
+ //
+ // wait for wave transition
+ //
+ do {
+
+ *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
+
+ } while (NmiStatus.SpeakerTimer != SquareWaveState);
+
+ } while (--NumberOfIntervals);
+
+ Count2 = __RCC();
+
+ //
+ // Disable the speaker counter.
+ //
+
+ *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
+
+ NmiStatus.SpeakerGate = 0;
+ NmiStatus.SpeakerData = 0;
+
+ WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
+
+ //
+ // Calculate the Hz by the number of processor cycles
+ // elapsed during 1s.
+ //
+ // Hz = PCC/SampleTime * 1000ms/s
+ // = PCC * (1000/SampleTime)
+ //
+
+ // did the counter wrap? if so add 2^32
+ if (Count1 > Count2) {
+
+ Count2 += (ULONGLONG)(1 << 32);
+
+ }
+
+ return (ULONG) ((Count2 - Count1)*(((ULONG)1000)/SampleTime));
+}
+
+
+VOID
+HalpInitializeProcessorParameters(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine initalize the processor counter parameters
+ HalpClockFrequency and HalpClockMegaHertz based on the
+ estimated CPU speed. A 1s reference time is used for
+ the estimation.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ HalpClockFrequency = HalpQuerySystemFrequency(1000);
+ HalpClockMegaHertz = (HalpClockFrequency + 500000)/ 1000000;
+
+#if DBG
+ DbgPrint(
+ "Frequency = %d\nMegaHertz = %d\n",
+ HalpClockFrequency,
+ HalpClockMegaHertz
+ );
+#endif
+
+
+}
+
+
+
+
+#if 0
+VOID
+HalpGatherPerformanceParameterStats(
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine gathers statistics on the method for
+ estimating the system frequency.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ ULONG Index;
+ ULONG Hertz[32];
+ ULONGLONG Mean = 0;
+ ULONGLONG Variance = 0;
+ ULONGLONG TempHertz;
+
+ //
+ // take 32 samples of estimated CPU speed,
+ // calculating the mean in the process.
+ //
+ DbgPrint("Sample\tFrequency\tMegaHertz\n\n");
+
+ for (Index = 0; Index < 32; Index++) {
+ Hertz[Index] = HalpQuerySystemFrequency(500);
+ Mean += Hertz[Index];
+
+ DbgPrint(
+ "%d\t%d\t%d\n",
+ Index,
+ Hertz[Index],
+ (ULONG)((Hertz[Index] + 500000)/1000000)
+ );
+
+ }
+
+ //
+ // calculate the mean
+ //
+
+ Mean /= 32;
+
+ //
+ // calculate the variance
+ //
+ for (Index = 0; Index < 32; Index++) {
+ TempHertz = (Mean > Hertz[Index])?
+ (Mean - Hertz[Index]) : (Hertz[Index] - Mean);
+ TempHertz = TempHertz*TempHertz;
+ Variance += TempHertz;
+ }
+
+ Variance /= 32;
+
+ DbgPrint("\nResults\n\n");
+ DbgPrint(
+ "Mean = %d\nVariance = %d\nMegaHertz (derived) = %d\n",
+ Mean,
+ Variance,
+ (Mean + 500000)/ 1000000
+ );
+
+}
+#endif
+
+
diff --git a/private/ntos/nthals/halalpha/intsup.s b/private/ntos/nthals/halalpha/intsup.s
new file mode 100644
index 000000000..40d484db4
--- /dev/null
+++ b/private/ntos/nthals/halalpha/intsup.s
@@ -0,0 +1,256 @@
+//++
+//
+// Copyright (c) 1993 Digital Equipment Corporation
+//
+// Module Name:
+//
+// intsup.s
+//
+// Abstract:
+//
+// This module implements first level interrupt handlers.
+//
+// Author:
+//
+// Joe Notarangelo 08-Jul-1993
+//
+// Environment:
+//
+// Kernel mode only.
+//
+// Revision History:
+//
+// 24-Sep-93 Joe Notarangelo
+// Make this module platform-independent.
+//--
+
+#include "halalpha.h"
+
+ SBTTL("System Clock Interrupt")
+//++
+//
+// VOID
+// HalpClockInterrupt(
+// )
+//
+// Routine Description:
+//
+// This function is executed for each interval timer interrupt on
+// the primary processor. The routine is responsible for acknowledging the
+// interrupt and calling the kernel to update the system time.
+// In addition, this routine checks for breakins from the kernel debugger
+// and maintains the 64 bit performance counter based upon the
+// processor cycle counter.
+//
+// Arguments:
+//
+// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for
+// the interrupt.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ .struct 0
+ .space 8 // filler for octaword alignment
+CiRa: .space 8 // space for return address
+CiFrameLength: //
+
+ NESTED_ENTRY(HalpClockInterrupt, CiFrameLength, zero )
+
+ lda sp, -CiFrameLength(sp) // allocate stack frame
+ stq ra, CiRa(sp) // save return address
+
+ PROLOGUE_END
+
+//
+// Acknowledge the clock interrupt.
+//
+
+ bsr ra, HalpAcknowledgeClockInterrupt // ack the interrupt
+
+//
+// Call the kernel to update the system time.
+//
+ ldl a1, HalpCurrentTimeIncrement // Get current time increment
+ bis fp, zero, a0 // a0 = pointer to trap frame
+ ldl t0, __imp_KeUpdateSystemTime
+ jsr ra, (t0) // call kernel
+
+ ldl t0, HalpNextTimeIncrement // Get next time increment
+ stl t0, HalpCurrentTimeIncrement // Set CurrentTimeIncrement to NextTimeIncrement
+
+ ldl a0, HalpNextRateSelect // Get NextIntervalCount. If 0, no change required
+ beq a0, 10f
+
+ stl zero, HalpNextRateSelect // Set NextRateSelect to 0
+ bsr ra, HalpProgramIntervalTimer // Program timer with new rate select
+
+ ldl t0, HalpNewTimeIncrement
+ stl t0, HalpNextTimeIncrement // Set HalpNextTimeIncrement to HalpNewTimeIncrement
+
+//
+// Call to handle performance counter wrap.
+//
+10:
+ bsr ra, HalpCheckPerformanceCounter // check for perf. counter wrap
+
+#if DEVL
+
+//
+// Check for a breakin request from the kernel debugger.
+//
+
+ ldl t0, __imp_KdPollBreakIn
+ jsr ra, (t0) // check for breakin requested
+ beq v0, 30f // if eq[false], no breakin
+ ldl t0, __imp_DbgBreakPointWithStatus
+ lda a0, DBG_STATUS_CONTROL_C
+ jsr ra, (t0) // send status to debugger
+
+ BREAK_BREAKIN // execute breakin breakpoint
+
+30:
+
+#endif //DEVL
+
+//
+// Return to the caller.
+//
+
+ ldq ra, CiRa(sp) // restore return address
+ lda sp, CiFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return to caller
+
+ .end HalpClockInterrupt
+
+
+#ifndef NT_UP
+
+ SBTTL("Secondary Processor Clock Interrupt")
+//++
+//
+// VOID
+// HalpSecondaryClockInterrupt(
+// )
+//
+// Routine Description:
+//
+// This function is executed for each interval timer interrupt on
+// the current secondary processor. The routine is responsible for
+// acknowledging the interrupt and calling the kernel to update the
+// run time for the current processor.
+// In addition, this routine checks for breakins from the kernel debugger
+// and maintains the 64 bit performance counter based upon the
+// processor cycle counter.
+//
+// Arguments:
+//
+// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for
+// the interrupt.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+
+ NESTED_ENTRY(HalpSecondaryClockInterrupt, CiFrameLength, zero )
+
+ lda sp, -CiFrameLength(sp) // allocate stack frame
+ stq ra, CiRa(sp) // save return address
+
+ PROLOGUE_END
+
+//
+// Acknowledge the clock interrupt.
+//
+
+ bsr ra, HalpAcknowledgeClockInterrupt // ack the interrupt
+
+//
+// Call the kernel to update the run time.
+//
+
+ bis fp, zero, a0 // a0 = pointer to trap frame
+ ldl t0, __imp_KeUpdateRunTime
+ jsr ra, (t0) // call kernel
+
+#if DEVL
+
+//
+// Check for a breakin request from the kernel debugger.
+//
+
+ ldl t0, __imp_KdPollBreakIn
+ jsr ra, (t0) // check for breakin requested
+ beq v0, 30f // if eq[false], no breakin
+ BREAK_BREAKIN // execute breakin breakpoint
+
+30:
+
+#endif //DEVL
+
+//
+// Return to the caller.
+//
+
+ ldq ra, CiRa(sp) // restore return address
+ lda sp, CiFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return to caller
+
+ .end HalpSecondaryClockInterrupt
+
+ SBTTL("Interprocessor Interrupt")
+//++
+//
+// VOID
+// HalpIpiInterruptHandler
+// )
+//
+// Routine Description:
+//
+// This function is executed as the result of an interprocessor
+// interrupt asserted on the current processor. This function is
+// responsible for acknowledging the interrupt and dispatching to
+// the kernel for processing.
+//
+// Arguments:
+//
+// TrapFrame (fp/s6) - Supplies a pointer to the trap frame for
+// the interrupt.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ .struct 0
+ .space 8 // filler for octaword alignment
+IpiRa: .space 8 // space for return address
+IpiFrameLength: //
+
+ NESTED_ENTRY(HalpIpiInterruptHandler, IpiFrameLength, zero )
+
+ lda sp, -IpiFrameLength(sp) // allocate stack frame
+ stq ra, IpiRa(sp) // save return address
+
+ PROLOGUE_END
+
+ bsr ra, HalpAcknowledgeIpiInterrupt // acknowledge interrupt
+
+ ldl t0, __imp_KeIpiInterrupt
+ jsr ra, (t0) // call kernel to process
+
+ ldq ra, IpiRa(sp) // restore return address
+ ret zero, (ra) // return
+
+ .end HalpIpiInterruptHandler
+
+
+#endif //NT_UP
+
diff --git a/private/ntos/nthals/halalpha/ioproc.c b/private/ntos/nthals/halalpha/ioproc.c
new file mode 100644
index 000000000..ec0ee051d
--- /dev/null
+++ b/private/ntos/nthals/halalpha/ioproc.c
@@ -0,0 +1,104 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ioproc.c
+
+Abstract:
+
+ Stub functions for UP hals.
+
+Author:
+
+ Ken Reneris (kenr) 22-Jan-1991
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+ Added to Avanti Hals (Sameer Dekate) 04-May-1994
+
+--*/
+
+#include "halp.h"
+#include "iousage.h"
+
+UCHAR HalName[] = "Alpha Compatible PCI/Eisa/Isa HAL";
+
+BOOLEAN
+HalpInitMP (
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+VOID HalpInitializePciBuses (VOID);
+VOID HalpInitOtherBuses (VOID);
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,HalpInitMP)
+#pragma alloc_text(INIT,HalReportResourceUsage)
+#pragma alloc_text(INIT,HalpInitOtherBuses)
+#endif
+
+
+
+BOOLEAN
+HalpInitMP (
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+{
+ return TRUE;
+ // do nothing
+}
+
+
+VOID
+HalpResetAllProcessors (
+ VOID
+ )
+{
+ // Just return, that will invoke the standard PC reboot code
+}
+
+
+VOID
+HalReportResourceUsage (
+ VOID
+ )
+{
+ INTERFACE_TYPE interfacetype;
+ ANSI_STRING AHalName;
+ UNICODE_STRING UHalName;
+
+ switch (HalpBusType) {
+ case MACHINE_TYPE_ISA: interfacetype = Isa; break;
+ case MACHINE_TYPE_EISA: interfacetype = Eisa; break;
+#if 0
+ case MACHINE_TYPE_MCA: interfacetype = MicroChannel; break;
+#endif // 0
+ default: interfacetype = Internal; break;
+ }
+
+ RtlInitAnsiString (&AHalName, HalName);
+ RtlAnsiStringToUnicodeString (&UHalName, &AHalName, TRUE);
+ HalpReportResourceUsage (
+ &UHalName, // descriptive name
+ interfacetype // device space interface type
+ );
+
+ RtlFreeUnicodeString (&UHalName);
+}
+
+
+VOID
+HalpInitOtherBuses (
+ VOID
+ )
+{
+ // no other internal buses supported
+}
diff --git a/private/ntos/nthals/halalpha/iousage.c b/private/ntos/nthals/halalpha/iousage.c
new file mode 100644
index 000000000..b1f9ce006
--- /dev/null
+++ b/private/ntos/nthals/halalpha/iousage.c
@@ -0,0 +1,527 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ iousage.c
+
+Abstract:
+
+Author:
+
+ Ken Reneris (kenr)
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+ Added to Alpha (Avanti Hals) (Sameer Dekate) 5-4-94
+
+--*/
+
+#include "halp.h"
+#include "iousage.h"
+
+//
+// Define constants for system IDTs
+//
+
+#define MAXIMUM_IDTVECTOR 0xff
+#define MAXIMUM_PRIMARY_VECTOR 0xff
+#define PRIMARY_VECTOR_BASE 0x30 // 0-2f are x86 trap vectors
+
+//
+// Array to remember hal's IDT usage
+//
+
+KAFFINITY HalpActiveProcessors;
+
+//
+// From usage.c
+//
+
+ADDRESS_USAGE *HalpAddressUsageList;
+
+//
+// IDT vector usage info
+//
+
+IDTUsage HalpIDTUsage[MAXIMUM_IDTVECTOR];
+
+VOID
+HalpGetResourceSortValue (
+ IN PCM_PARTIAL_RESOURCE_DESCRIPTOR pRCurLoc,
+ OUT PULONG sortscale,
+ OUT PLARGE_INTEGER sortvalue
+ );
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,HalpEnableInterruptHandler)
+#pragma alloc_text(INIT,HalpRegisterVector)
+#pragma alloc_text(INIT,HalpGetResourceSortValue)
+#pragma alloc_text(INIT,HalpReportResourceUsage)
+#endif
+
+
+VOID
+HalpEnableInterruptHandler (
+ IN UCHAR ReportFlags,
+ IN ULONG BusInterruptVector,
+ IN ULONG SystemInterruptVector,
+ IN KIRQL SystemIrql,
+ IN VOID (*HalInterruptServiceRoutine)(VOID),
+ IN KINTERRUPT_MODE InterruptMode
+ )
+/*++
+
+Routine Description:
+
+ This function connects & registers an IDT vectors usage by the HAL.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ //
+ // Remember which vector the hal is connecting so it can be reported
+ // later on
+ //
+ HalpRegisterVector (ReportFlags, BusInterruptVector, SystemInterruptVector, SystemIrql);
+
+
+ //
+ // Connect the IDT and enable the vector now
+ //
+
+#if 0
+ KiSetHandlerAddressToIDT(SystemInterruptVector, HalInterruptServiceRoutine);
+#endif //0
+ HalEnableSystemInterrupt(SystemInterruptVector, SystemIrql, InterruptMode);
+}
+
+
+VOID
+HalpRegisterVector (
+ IN UCHAR ReportFlags,
+ IN ULONG BusInterruptVector,
+ IN ULONG SystemInterruptVector,
+ IN KIRQL SystemIrql
+ )
+/*++
+
+Routine Description:
+
+ This registers an IDT vectors usage by the HAL.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+#if DBG
+ // There are only 0ff IDT entries...
+ ASSERT (SystemInterruptVector <= MAXIMUM_IDTVECTOR &&
+ BusInterruptVector <= MAXIMUM_IDTVECTOR);
+#endif
+
+ //
+ // Remember which vector the hal is connecting so it can be reported
+ // later on
+ //
+
+ HalpIDTUsage[SystemInterruptVector].Flags = ReportFlags;
+ HalpIDTUsage[SystemInterruptVector].Irql = SystemIrql;
+ HalpIDTUsage[SystemInterruptVector].BusReleativeVector = (UCHAR) BusInterruptVector;
+}
+
+
+VOID
+HalpGetResourceSortValue (
+ IN PCM_PARTIAL_RESOURCE_DESCRIPTOR pRCurLoc,
+ OUT PULONG sortscale,
+ OUT PLARGE_INTEGER sortvalue
+ )
+/*++
+
+Routine Description:
+
+ Used by HalpReportResourceUsage in order to properly sort
+ partial_resource_descriptors.
+
+Arguments:
+
+ pRCurLoc - resource descriptor
+
+Return Value:
+
+ sortscale - scaling of resource descriptor for sorting
+ sortvalue - value to sort on
+
+
+--*/
+{
+ switch (pRCurLoc->Type) {
+ case CmResourceTypeInterrupt:
+ *sortscale = 0;
+ sortvalue->QuadPart = pRCurLoc->u.Interrupt.Level;
+ break;
+
+ case CmResourceTypePort:
+ *sortscale = 1;
+ *sortvalue = pRCurLoc->u.Port.Start;
+ break;
+
+ case CmResourceTypeMemory:
+ *sortscale = 2;
+ *sortvalue = pRCurLoc->u.Memory.Start;
+ break;
+
+ default:
+ *sortscale = 4;
+ sortvalue->QuadPart = 0;
+ break;
+ }
+}
+
+
+VOID
+HalpReportResourceUsage (
+ IN PUNICODE_STRING HalName,
+ IN INTERFACE_TYPE DeviceInterfaceToUse
+ )
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ PCM_RESOURCE_LIST RawResourceList, TranslatedResourceList;
+ PCM_FULL_RESOURCE_DESCRIPTOR pRFullDesc, pTFullDesc;
+ PCM_PARTIAL_RESOURCE_LIST pRPartList, pTPartList;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR pRCurLoc, pTCurLoc;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR pRSortLoc, pTSortLoc;
+ CM_PARTIAL_RESOURCE_DESCRIPTOR RPartialDesc, TPartialDesc;
+ ULONG i, j, k, ListSize, Count;
+ ULONG curscale, sortscale;
+ UCHAR pass, reporton;
+ INTERFACE_TYPE interfacetype;
+ ULONG CurrentIDT, CurrentElement;
+ ADDRESS_USAGE *CurrentAddress;
+ LARGE_INTEGER curvalue, sortvalue;
+ PHYSICAL_ADDRESS TempAddress;
+
+ //
+ // Allocate some space to build the resource structure
+ //
+
+ RawResourceList = (PCM_RESOURCE_LIST) ExAllocatePool (NonPagedPool, PAGE_SIZE*2);
+ TranslatedResourceList = (PCM_RESOURCE_LIST) ExAllocatePool (NonPagedPool, PAGE_SIZE*2);
+
+ // This functions assumes unset fields are zero
+ RtlZeroMemory (RawResourceList, PAGE_SIZE*2);
+ RtlZeroMemory (TranslatedResourceList, PAGE_SIZE*2);
+
+ //
+ // Initialize the lists
+ //
+
+ RawResourceList->List[0].InterfaceType = (INTERFACE_TYPE) -1;
+
+ pRFullDesc = RawResourceList->List;
+ pRCurLoc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) RawResourceList->List;
+ pTCurLoc = (PCM_PARTIAL_RESOURCE_DESCRIPTOR) TranslatedResourceList->List;
+
+ //
+ // Make sure all vectors 00-2f are reserved
+ // 00-1E reserved by Intel
+ // 1F reserved by Intel for APIC (apc priority level)
+ // 20-2e reserved by Microsoft
+ // 2f reserved by Microsoft for APIC (dpc priority level)
+ //
+
+ for(i=0; i < PRIMARY_VECTOR_BASE; i++) {
+ if (!(HalpIDTUsage[i].Flags & IDTOwned)) {
+ HalpIDTUsage[i].Flags = InternalUsage;
+ HalpIDTUsage[i].BusReleativeVector = (UCHAR) i;
+ }
+ }
+
+ for(pass=0; pass < 3; pass++) {
+
+ switch(pass) {
+
+ case 0: {
+#if DBG
+DbgPrint("Device LIST...\n");
+#endif // DBG
+ //
+ // First pass - build resource lists for resources reported
+ // reported against device usage.
+ //
+
+ reporton = DeviceUsage & ~IDTOwned;
+ interfacetype = DeviceInterfaceToUse;
+ break;
+ }
+
+ case 1: {
+#if DBG
+DbgPrint("Internal LIST...\n");
+#endif // DBG
+ //
+ // Second pass = build reousce lists for resources reported
+ // as internal usage.
+ //
+
+ reporton = InternalUsage & ~IDTOwned;
+ interfacetype = Internal;
+ break;
+ }
+
+ case 2: {
+#if DBG
+DbgPrint("PCI LIST...\n");
+#endif // DBG
+ //
+ // Third pass = build reousce lists for resources reported
+ // as PCI usage.
+ //
+
+ reporton = PCIUsage & ~IDTOwned;
+ interfacetype = PCIBus;
+ break;
+ }
+ }
+
+ CurrentIDT = 0;
+ CurrentElement = 0;
+ CurrentAddress = HalpAddressUsageList;
+
+ for (; ;) {
+ if (CurrentIDT <= MAXIMUM_IDTVECTOR) {
+ //
+ // Check to see if CurrentIDT needs to be reported
+ //
+
+ if (!(HalpIDTUsage[CurrentIDT].Flags & reporton)) {
+ // Don't report on this one
+ CurrentIDT++;
+ continue;
+ }
+
+ //
+ // Report CurrentIDT resource
+ //
+
+ RPartialDesc.Type = CmResourceTypeInterrupt;
+ RPartialDesc.ShareDisposition = CmResourceShareDriverExclusive;
+ RPartialDesc.Flags =
+ HalpIDTUsage[CurrentIDT].Flags & InterruptLatched ?
+ CM_RESOURCE_INTERRUPT_LATCHED :
+ CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+ RPartialDesc.u.Interrupt.Vector = HalpIDTUsage[CurrentIDT].BusReleativeVector;
+ RPartialDesc.u.Interrupt.Level = HalpIDTUsage[CurrentIDT].BusReleativeVector;
+ RPartialDesc.u.Interrupt.Affinity = HalpActiveProcessors;
+
+ RtlCopyMemory (&TPartialDesc, &RPartialDesc, sizeof TPartialDesc);
+ TPartialDesc.u.Interrupt.Vector = CurrentIDT;
+ TPartialDesc.u.Interrupt.Level = HalpIDTUsage[CurrentIDT].Irql;
+
+ CurrentIDT++;
+
+ } else {
+
+ //
+ // Check to see if CurrentAddress needs to be reported
+ //
+
+ if (!CurrentAddress) {
+ break; // No addresses left
+ }
+
+ if (!(CurrentAddress->Flags & reporton)) {
+ // Don't report on this list
+ CurrentElement = 0;
+ CurrentAddress = CurrentAddress->Next;
+ continue;
+ }
+
+ if (!CurrentAddress->Element[CurrentElement].Length) {
+ // End of current list, go to next list
+ CurrentElement = 0;
+ CurrentAddress = CurrentAddress->Next;
+ continue;
+ }
+
+ //
+ // Report CurrentAddress
+ //
+
+ RPartialDesc.Type = (UCHAR) CurrentAddress->Type;
+ RPartialDesc.ShareDisposition = CmResourceShareDriverExclusive;
+
+ if (RPartialDesc.Type == CmResourceTypePort) {
+ i = 1; // address space port
+ RPartialDesc.Flags = CM_RESOURCE_PORT_IO;
+ } else {
+ i = 0; // address space memory
+ RPartialDesc.Flags = CM_RESOURCE_MEMORY_READ_WRITE;
+ }
+
+ // Notice: assuming u.Memory and u.Port have the same layout
+ RPartialDesc.u.Memory.Start.HighPart = 0;
+ RPartialDesc.u.Memory.Start.LowPart =
+ CurrentAddress->Element[CurrentElement].Start;
+
+ RPartialDesc.u.Memory.Length =
+ CurrentAddress->Element[CurrentElement].Length;
+
+#if DBG
+DbgPrint("Start=0x%x Lenght=0x%x\n", RPartialDesc.u.Memory.Start.LowPart, RPartialDesc.u.Memory.Length);
+#endif // DBG
+
+ // translated address = Raw address
+ RtlCopyMemory (&TPartialDesc, &RPartialDesc, sizeof TPartialDesc);
+ HalTranslateBusAddress (
+ interfacetype, // device bus or internal
+ 0, // bus number
+ RPartialDesc.u.Memory.Start, // source address
+ &i, // address space
+ &TempAddress ); // aligned translated address
+
+ TPartialDesc.u.Memory.Start = TempAddress; // TPartialDesc is pack(4)
+
+#if DBG
+DbgPrint("TRANSLATED ADDRESS Start=0x%x Lenght=0x%x\n", TPartialDesc.u.Memory.Start.LowPart, TPartialDesc.u.Memory.Length);
+#endif // DBG
+
+ if (RPartialDesc.Type == CmResourceTypePort && i == 0) {
+ TPartialDesc.Flags = CM_RESOURCE_PORT_MEMORY;
+ }
+
+ CurrentElement++;
+ }
+
+ //
+ // Include the current resource in the HALs list
+ //
+
+ if (pRFullDesc->InterfaceType != interfacetype) {
+ //
+ // Interface type changed, add another full section
+ //
+
+ RawResourceList->Count++;
+ TranslatedResourceList->Count++;
+
+ pRFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) pRCurLoc;
+ pTFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) pTCurLoc;
+
+ pRFullDesc->InterfaceType = interfacetype;
+ pTFullDesc->InterfaceType = interfacetype;
+
+ pRPartList = &pRFullDesc->PartialResourceList;
+ pTPartList = &pTFullDesc->PartialResourceList;
+
+ //
+ // Bump current location pointers up
+ //
+ pRCurLoc = pRFullDesc->PartialResourceList.PartialDescriptors;
+ pTCurLoc = pTFullDesc->PartialResourceList.PartialDescriptors;
+ }
+
+
+ pRPartList->Count++;
+ pTPartList->Count++;
+ RtlCopyMemory (pRCurLoc, &RPartialDesc, sizeof RPartialDesc);
+ RtlCopyMemory (pTCurLoc, &TPartialDesc, sizeof TPartialDesc);
+
+ pRCurLoc++;
+ pTCurLoc++;
+ }
+ }
+
+ ListSize = (ULONG) ( ((PUCHAR) pRCurLoc) - ((PUCHAR) RawResourceList) );
+
+ //
+ // The HAL's resource usage structures have been built
+ // Sort the partial lists based on the Raw resource values
+ //
+
+ pRFullDesc = RawResourceList->List;
+ pTFullDesc = TranslatedResourceList->List;
+
+ for (i=0; i < RawResourceList->Count; i++) {
+
+ pRCurLoc = pRFullDesc->PartialResourceList.PartialDescriptors;
+ pTCurLoc = pTFullDesc->PartialResourceList.PartialDescriptors;
+ Count = pRFullDesc->PartialResourceList.Count;
+
+ for (j=0; j < Count; j++) {
+ HalpGetResourceSortValue (pRCurLoc, &curscale, &curvalue);
+
+ pRSortLoc = pRCurLoc;
+ pTSortLoc = pTCurLoc;
+
+ for (k=j; k < Count; k++) {
+ HalpGetResourceSortValue (pRSortLoc, &sortscale, &sortvalue);
+
+ if (sortscale < curscale ||
+ (sortscale == curscale &&
+ (sortvalue.QuadPart < curvalue.QuadPart)) ) {
+
+ //
+ // Swap the elements..
+ //
+
+ RtlCopyMemory (&RPartialDesc, pRCurLoc, sizeof RPartialDesc);
+ RtlCopyMemory (pRCurLoc, pRSortLoc, sizeof RPartialDesc);
+ RtlCopyMemory (pRSortLoc, &RPartialDesc, sizeof RPartialDesc);
+
+ // swap translated descriptor as well
+ RtlCopyMemory (&TPartialDesc, pTCurLoc, sizeof TPartialDesc);
+ RtlCopyMemory (pTCurLoc, pTSortLoc, sizeof TPartialDesc);
+ RtlCopyMemory (pTSortLoc, &TPartialDesc, sizeof TPartialDesc);
+
+ // get new curscale & curvalue
+ HalpGetResourceSortValue (pRCurLoc, &curscale, &curvalue);
+ }
+
+ pRSortLoc++;
+ pTSortLoc++;
+ }
+
+ pRCurLoc++;
+ pTCurLoc++;
+ }
+
+ pRFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) pRCurLoc;
+ pTFullDesc = (PCM_FULL_RESOURCE_DESCRIPTOR) pTCurLoc;
+ }
+
+
+ //
+ // Inform the IO system of our resources..
+ //
+
+ IoReportHalResourceUsage (
+ HalName,
+ RawResourceList,
+ TranslatedResourceList,
+ ListSize
+ );
+
+ ExFreePool (RawResourceList);
+ ExFreePool (TranslatedResourceList);
+}
diff --git a/private/ntos/nthals/halalpha/iousage.h b/private/ntos/nthals/halalpha/iousage.h
new file mode 100644
index 000000000..8a128d56e
--- /dev/null
+++ b/private/ntos/nthals/halalpha/iousage.h
@@ -0,0 +1,85 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992,1993 Digital Equipment Corporation
+
+Module Name:
+
+ iousage.h
+
+Abstract:
+
+ This header file defines the iousage definitions
+
+Author:
+
+ Sameer Dekate 5-3-1994
+
+
+Revision History:
+
+ Most pieces have be stolen from Microsofts halp.h
+
+--*/
+
+//
+// External Function Prototypes
+//
+
+VOID
+HalpEnableInterruptHandler (
+ IN UCHAR ReportFlags,
+ IN ULONG BusInterruptVector,
+ IN ULONG SystemInterruptVector,
+ IN KIRQL SystemIrql,
+ IN VOID (*HalInterruptServiceRoutine)(VOID),
+ IN KINTERRUPT_MODE InterruptMode
+ );
+
+VOID
+HalpRegisterVector (
+ IN UCHAR ReportFlags,
+ IN ULONG BusInterruptVector,
+ IN ULONG SystemInterruptVector,
+ IN KIRQL SystemIrql
+ );
+
+VOID
+HalpReportResourceUsage (
+ IN PUNICODE_STRING HalName,
+ IN INTERFACE_TYPE DeviceInterfaceToUse
+ );
+//
+// Resource usage information
+//
+
+#pragma pack(1)
+typedef struct {
+ UCHAR Flags;
+ KIRQL Irql;
+ UCHAR BusReleativeVector;
+} IDTUsage;
+
+typedef struct _HalAddressUsage{
+ struct _HalAddressUsage *Next;
+ CM_RESOURCE_TYPE Type; // Port or Memory
+ UCHAR Flags; // same as IDTUsage.Flags
+ struct {
+ ULONG Start;
+ ULONG Length;
+ } Element[];
+} ADDRESS_USAGE;
+#pragma pack()
+
+#define IDTOwned 0x01 // IDT is not available for others
+#define InterruptLatched 0x02 // Level or Latched
+#define InternalUsage 0x11 // Report usage on internal bus
+#define DeviceUsage 0x21 // Report usage on device bus
+#define PCIUsage 0x41 // Report usage on PCI bus
+
+extern IDTUsage HalpIDTUsage[];
+extern ADDRESS_USAGE *HalpAddressUsageList;
+
+#define HalpRegisterAddressUsage(a) \
+ (a)->Next = HalpAddressUsageList, HalpAddressUsageList = (a);
+
diff --git a/private/ntos/nthals/halalpha/isaaddr.h b/private/ntos/nthals/halalpha/isaaddr.h
new file mode 100644
index 000000000..832a48d49
--- /dev/null
+++ b/private/ntos/nthals/halalpha/isaaddr.h
@@ -0,0 +1,75 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ isaaddr.h
+
+Abstract:
+
+ This module defines the standard device addresses on the ISA/EISA bus.
+
+Author:
+
+ Joe Notarangelo 22-Oct-1993
+
+Revision History:
+
+
+--*/
+
+#ifndef _ISAADDR_
+#define _ISAADDR_
+
+//
+// Standard VGA video adapter offsets
+//
+
+#define VIDEO_MEMORY_OFFSET 0xb8000
+#define VIDEO_FONT_MEMORY_OFFSET 0xa0000
+
+//
+// Define the base port address for the PC standard floppy.
+//
+
+#define FLOPPY_ISA_PORT_ADDRESS 0x3f0
+
+//
+// Define the base port address for the PC standard keyboard and mouse.
+//
+
+#define KEYBOARD_ISA_PORT_ADDRESS 0x060
+#define MOUSE_ISA_PORT_ADDRESS 0x060
+#define KBD_ISA_OUTPUT_BUFFER_PORT 0x060
+#define KBD_ISA_STATUS_PORT 0x064
+
+//
+// Define the base port address for the PC standard parallel port.
+//
+
+#define PARALLEL_ISA_PORT_ADDRESS 0x3bc
+
+//
+// Define the base port addresses for the PC standard serial lines.
+//
+
+#define COM1_ISA_PORT_ADDRESS 0x3f8
+#define COM2_ISA_PORT_ADDRESS 0x2f8
+
+//
+// Define the port addresses for the PC standard real time clock.
+//
+
+#define RTC_ISA_ADDRESS_PORT 0x070
+#define RTC_ISA_DATA_PORT 0x071
+#define RTC_ALT_ISA_ADDRESS_PORT 0x170
+#define RTC_ALT_ISA_DATA_PORT 0x171
+
+//
+// Define the base port address for the PC standard 8K CMOS RAM.
+//
+
+#define CMOS_ISA_PORT_ADDRESS 0x800
+
+#endif // _ISAADDR_
diff --git a/private/ntos/nthals/halalpha/lca4.c b/private/ntos/nthals/halalpha/lca4.c
new file mode 100644
index 000000000..64e28dba4
--- /dev/null
+++ b/private/ntos/nthals/halalpha/lca4.c
@@ -0,0 +1,657 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ lca4.c
+
+Abstract:
+
+ This module implements functions that are specific to the LCA4
+ microprocessor.
+
+Author:
+
+ Joe Notarangelo 20-Oct-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#include "lca4.h"
+#include "axp21066.h"
+
+#ifndef AXP_FIRMWARE
+VOID
+DumpIoc(
+ VOID
+ );
+#endif
+
+//
+// Globals
+//
+
+//
+// Parity checking is a tri-state variable, unknown == all f's. Which means
+// Keep checking disabled until we can determine what we want to set it to,
+// which then means 1 or 0.
+//
+
+extern ULONG HalDisablePCIParityChecking;
+
+#ifdef AXP_FIRMWARE
+
+//
+// Put these functions in the discardable text section.
+//
+
+//
+// Local function prototypes
+//
+
+ULONG
+HalpDetermineLca4Revision(
+ VOID
+ );
+
+VOID
+HalpLca4MapAddressSpaces(
+ VOID
+ );
+
+ULONG
+HalpLca4Revision(
+ VOID
+ );
+
+ULONGLONG
+HalpLca4IocTbTagPhysical(
+ VOID
+ );
+
+ULONGLONG
+HalpLca4PciIntAckPhysical(
+ VOID
+ );
+
+ULONGLONG
+HalpLca4PciIoPhysical(
+ VOID
+ );
+
+ULONGLONG
+HalpLca4PciDensePhysical(
+ VOID
+ );
+
+#pragma alloc_text(DISTEXT, HalpDetermineLca4Revision)
+#pragma alloc_text(DISTEXT, HalpLca4MapAddressSpaces)
+#pragma alloc_text(DISTEXT, HalpLca4Revision)
+#pragma alloc_text(DISTEXT, HalpLca4IocTbTagPhysical)
+#pragma alloc_text(DISTEXT, HalpLca4PciIntAckPhysical)
+#pragma alloc_text(DISTEXT, HalpLca4PciIoPhysical)
+#pragma alloc_text(DISTEXT, HalpLca4PciDensePhysical)
+
+#endif // AXP_FIRMWARE
+
+
+ULONG
+HalpDetermineLca4Revision(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Determine the revision of the LCA4 processor we are currently executing.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Return the recognized revision of the LCA4 processor executing.
+
+--*/
+{
+ CAR_21066 Car;
+ ULONG Revision;
+
+ //
+ // Pass 1 and Pass 2 LCA processors can be distinguished by the
+ // PWR bit of the Cache Register (CAR). For Pass 1 the bit is RAZ
+ // while for Pass 2 the bit is read/write.
+ //
+ // Read the current value of the CAR. If it is 1, then we know that
+ // it is Pass 2. Else, set the PWR bit and write it back.
+ // Then read CAR again. If PWR is still set then we are executing on
+ // Pass 2. Don't forget to reset the PWR bit before finishing.
+ //
+
+ Car.all.QuadPart = READ_MEMC_REGISTER(
+ &((PLCA4_MEMC_CSRS)(0))->CacheControl );
+
+ if( Car.Pwr == 1 ) {
+
+ Revision = Lca4Pass2;
+
+ } else {
+
+ Car.Pwr = 1;
+
+ WRITE_MEMC_REGISTER( &((PLCA4_MEMC_CSRS)(0))->CacheControl,
+ Car.all.QuadPart );
+
+ Car.all.QuadPart = READ_MEMC_REGISTER(
+ &((PLCA4_MEMC_CSRS)(0))->CacheControl );
+
+ if( Car.Pwr == 1 ){
+ Revision = Lca4Pass2;
+ } else {
+ Revision = Lca4Pass1;
+ }
+
+ Car.Pwr = 0;
+
+ WRITE_MEMC_REGISTER( &((PLCA4_MEMC_CSRS)(0))->CacheControl,
+ Car.all.QuadPart );
+
+ }
+
+
+ return Revision;
+
+}
+
+//
+// Define the Revision variable for LCA4.
+//
+
+ULONG Lca4Revision;
+
+//
+// Define the Physical Address space variables for LCA4.
+//
+
+ULONGLONG Lca4IocTbTagPhysical;
+ULONGLONG Lca4PciIntAckPhysical;
+ULONGLONG Lca4PciIoPhysical;
+ULONGLONG Lca4PciDensePhysical;
+
+
+VOID
+HalpLca4MapAddressSpaces(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Map the address spaces of the LCA4 dependent upon which revision
+ of the chip is executing.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ Lca4Revision = HalpDetermineLca4Revision();
+
+ switch (Lca4Revision){
+
+ //
+ // Pass 1 LCA4
+ //
+
+ case Lca4Pass1:
+
+ Lca4IocTbTagPhysical = LCA4_PASS1_IOC_TBTAG_PHYSICAL;
+ Lca4PciIntAckPhysical = LCA4_PASS1_PCI_INTACK_BASE_PHYSICAL;
+ Lca4PciIoPhysical = LCA4_PASS1_PCI_IO_BASE_PHYSICAL;
+ Lca4PciDensePhysical = 0;
+
+ break;
+
+ //
+ // Pass 2 LCA4
+ //
+
+ case Lca4Pass2:
+
+ Lca4IocTbTagPhysical = LCA4_PASS2_IOC_TBTAG_PHYSICAL;
+ Lca4PciIntAckPhysical = LCA4_PASS2_PCI_INTACK_BASE_PHYSICAL;
+ Lca4PciIoPhysical = LCA4_PASS2_PCI_IO_BASE_PHYSICAL;
+ Lca4PciDensePhysical = LCA4_PASS2_PCI_DENSE_BASE_PHYSICAL;
+
+ break;
+
+#if (DBG) || (HALDBG)
+
+ default:
+
+ DbgPrint( "Unrecognized LCA4 Revision = %x (execution is hopeless)\n",
+ Lca4Revision );
+ DbgBreakPoint();
+
+#endif //DBG || HALDBG
+
+ }
+
+ return;
+
+}
+
+//
+// The following routines could be in-lined (it that were supported) or
+// made into macros to save space (time isn't any issue with these values).
+// To do so the variables above would have to be exported.
+//
+
+ULONG
+HalpLca4Revision(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Return the version of the LCA4 processor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The version of the LCA4 processor.
+
+--*/
+{
+
+ return Lca4Revision;
+
+}
+
+ULONGLONG
+HalpLca4IocTbTagPhysical(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Return the base address of the IOC TB Tag registers on the currently
+ executing LCA4 processor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The base physical address of the IOC TB Tag registers.
+
+--*/
+{
+
+ return Lca4IocTbTagPhysical;
+
+}
+
+
+ULONGLONG
+HalpLca4PciIntAckPhysical(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Return the base physical address of PCI Interrupt Acknowledge space
+ on the currently executing LCA4 processor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The base physical address of PCI Interrupt Acknowledge.
+
+--*/
+{
+
+ return Lca4PciIntAckPhysical;
+
+}
+
+ULONGLONG
+HalpLca4PciIoPhysical(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Return the base physical address of PCI I/O space on the currently
+ executing LCA4 processor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The base physical address of PCI I/O space.
+
+--*/
+{
+
+ return Lca4PciIoPhysical;
+
+}
+
+ULONGLONG
+HalpLca4PciDensePhysical(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Return the base physical address of PCI Dense Memory space on the
+ currently executing LCA4 processor.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The base physical address of PCI Dense Memory space.
+
+--*/
+{
+
+ return Lca4PciDensePhysical;
+
+}
+
+#if !defined(AXP_FIRMWARE)
+
+
+VOID
+HalpLca4InitializeSfwWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ LCA4_WINDOW_NUMBER WindowNumber
+ )
+/*++
+
+Routine Description:
+
+ Initialize the DMA Control software window registers for the specified
+ DMA Window.
+
+Arguments:
+
+ WindowRegisters - Supplies a pointer to the software window control.
+
+ WindowNumber - Supplies the window number initialized. (0 = Isa Dma
+ Window, 1 = Master Dma Window).
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ switch( WindowNumber ){
+
+ //
+ // The ISA DMA Window.
+ //
+
+ case Lca4IsaWindow:
+
+ WindowRegisters->WindowBase = (PVOID)ISA_DMA_WINDOW_BASE;
+ WindowRegisters->WindowSize = ISA_DMA_WINDOW_SIZE;
+ WindowRegisters->TranslatedBaseRegister =
+ &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->TranslatedBase0;
+ WindowRegisters->WindowBaseRegister =
+ &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->WindowBase0;
+ WindowRegisters->WindowMaskRegister =
+ &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->WindowMask0;
+ WindowRegisters->WindowTbiaRegister =
+ &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->Tbia;
+
+ break;
+
+ //
+ // The Master DMA Window.
+ //
+
+ case Lca4MasterWindow:
+
+ WindowRegisters->WindowBase = (PVOID)MASTER_DMA_WINDOW_BASE;
+ WindowRegisters->WindowSize = MASTER_DMA_WINDOW_SIZE;
+ WindowRegisters->TranslatedBaseRegister =
+ &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->TranslatedBase1;
+ WindowRegisters->WindowBaseRegister =
+ &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->WindowBase1;
+ WindowRegisters->WindowMaskRegister =
+ &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->WindowMask1;
+ WindowRegisters->WindowTbiaRegister =
+ &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->Tbia;
+
+ break;
+
+ default:
+
+#if DBG
+
+ DbgPrint( "Lca4InitializeSfwWindow: Bad Window Number = %x\n",
+ WindowNumber );
+
+#endif //DBG
+
+ break;
+
+ }
+
+ return;
+}
+
+
+VOID
+HalpLca4ProgramDmaWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ PVOID MapRegisterBase
+ )
+/*++
+
+Routine Description:
+
+ Program the control windows in the hardware so that DMA can be started
+ to the DMA window.
+
+Arguments:
+
+ WindowRegisters - Supplies a pointer to the software window register
+ control structure.
+
+ MapRegisterBase - Supplies the logical address of the scatter/gather
+ array in system memory.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ LCA4_IOC_WMASK WindowMask;
+ LCA4_IOC_WBASE WindowBase;
+ LCA4_IOC_TBEN TbEnable;
+ LCA4_IOC_PCIPD PciPD;
+ LCA4_IOC_TBASE TranslatedBase;
+
+ PVOID RegisterQva;
+
+ WindowBase.Reserved1 = 0;
+ WindowBase.Reserved2 = 0;
+ WindowBase.Sg = 1;
+ WindowBase.Wen = 1;
+ WindowBase.BaseValue = (ULONG)(WindowRegisters->WindowBase) >> 20;
+
+ WindowMask.Reserved1 = 0;
+ WindowMask.Reserved = 0;
+ WindowMask.MaskValue = (WindowRegisters->WindowSize >> 20) - 1;
+
+ TranslatedBase.Reserved1 = 0;
+ TranslatedBase.Reserved = 0;
+ TranslatedBase.TBase = (ULONG)(MapRegisterBase) >> 10;
+
+#if DBG
+
+ //
+ // Dump the EPIC registers.
+ //
+
+ DumpIoc();
+
+#endif //DBG
+
+ //
+ // Clear the window base, temporarily disabling transactions to this
+ // DMA window.
+ //
+
+ WRITE_IOC_REGISTER( WindowRegisters->WindowBaseRegister, (ULONGLONG)0 );
+
+ //
+ // Now program the window by writing the translated base, then the size
+ // of the window in the mask register and finally the window base,
+ // enabling both the window and scatter gather.
+ //
+
+ WRITE_IOC_REGISTER( WindowRegisters->TranslatedBaseRegister,
+ *(PULONGLONG)&TranslatedBase );
+
+ WRITE_IOC_REGISTER( WindowRegisters->WindowMaskRegister,
+ *(PULONGLONG)&WindowMask );
+
+ WRITE_IOC_REGISTER( WindowRegisters->WindowBaseRegister,
+ *(PULONGLONG)&WindowBase );
+
+ //
+ // Invalidate any translations that might have existed for this window.
+ //
+
+ WRITE_IOC_REGISTER( WindowRegisters->WindowTbiaRegister, (ULONGLONG)0 );
+
+ //
+ // Enable the translation buffer inside of the IOC.
+ //
+
+ RtlZeroMemory( &TbEnable, sizeof(LCA4_IOC_TBEN) );
+ TbEnable.Ten = 1;
+
+ WRITE_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->TbEnable,
+ *(PULONGLONG)&TbEnable );
+
+ //
+ // Tri state parity checking - keep disabled if not determined
+ // yet. otherwise, Whack the PCI parity disable bit with the stored
+ // value
+ //
+
+ RtlZeroMemory( &PciPD, sizeof(LCA4_IOC_PCIPD) );
+
+ if (HalDisablePCIParityChecking == 0xffffffff) {
+ PciPD.Par = 1;
+ } else {
+ PciPD.Par = HalDisablePCIParityChecking;
+ }
+
+ WRITE_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->PciParityDisable,
+ *(PULONGLONG)&PciPD );
+
+#if DBG
+
+ //
+ // Dump the IOC registers.
+ //
+
+ DumpIoc();
+
+#endif //DBG
+
+ return;
+}
+
+ULONGLONG
+READ_IOC_REGISTER(
+ PVOID
+ );
+
+#if DBG
+
+VOID
+DumpIoc(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Read the interesting IOC registers and print them to the debug port.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PVOID RegisterQva;
+ ULONGLONG Value;
+
+ DbgPrint( "Dumping the IOC registers\n" );
+
+ RegisterQva =
+ &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0;
+ Value = READ_IOC_REGISTER( RegisterQva );
+ DbgPrint( "IOSTAT[0] = %Lx\n", Value );
+
+ RegisterQva =
+ &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat1;
+ Value = READ_IOC_REGISTER( RegisterQva );
+ DbgPrint( "IOSTAT[1] = %Lx\n", Value );
+
+ DbgPrint( "--end IOC dump\n\n" );
+
+ return;
+
+}
+
+#endif //DBG
+
+#endif //!AXP_FIRMWARE
diff --git a/private/ntos/nthals/halalpha/lca4.h b/private/ntos/nthals/halalpha/lca4.h
new file mode 100644
index 000000000..0fd7ab02f
--- /dev/null
+++ b/private/ntos/nthals/halalpha/lca4.h
@@ -0,0 +1,669 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ lca4.h
+
+Abstract:
+
+ This file defines the structures and definitions common to all
+ LCA4-based platforms (Low Cost Alpha in Hudson CMOS 4).
+
+Author:
+
+ Joe Notarangelo 20-Oct-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#ifndef _LCA4H_
+#define _LCA4H_
+
+
+//
+// Define QVA constants for LCA4.
+//
+
+#if !defined(QVA_ENABLE)
+
+#define QVA_ENABLE (0xa0000000) // Identify VA as QVA
+
+#endif //QVA_ENABLE
+
+#define QVA_SELECTORS (0xE0000000) // Identify QVA bits
+
+#define IO_BIT_SHIFT 0x05 // Bits to shift QVA
+
+#define IO_BYTE_OFFSET 0x20 // Offset to next byte
+#define IO_SHORT_OFFSET 0x40 // Offset to next short
+#define IO_LONG_OFFSET 0x80 // Offset to next long
+
+#define IO_BYTE_LEN 0x00 // Byte length
+#define IO_WORD_LEN 0x08 // Word length
+#define IO_TRIBYTE_LEN 0x10 // TriByte length
+#define IO_LONG_LEN 0x18 // Longword length
+
+//
+// Define size of I/O and memory space for LCA4
+//
+
+#define PCI_MAX_IO_ADDRESS 0xFFFFFF // 16 Mb of IO Space
+
+//
+// Due we have 128MB total sparse space, of which some of it are holes
+//
+
+#define PCI_MAX_SPARSE_MEMORY_ADDRESS ((128*1024*1024) - 1)
+#define PCI_MIN_DENSE_MEMORY_ADDRESS PCI_MAX_SPARSE_MEMORY_ADDRESS + 1 // 128 Mb
+#define PCI_MAX_DENSE_MEMORY_ADDRESS (0xa0000000 -1) // 2.5 Gb
+
+//
+// Constant used by dense space I/O routines
+//
+
+#define PCI_DENSE_BASE_PHYSICAL_SUPERPAGE 0xfffffc0300000000
+
+
+//
+// Protect the assembly language code from C definitions.
+//
+
+#if !defined(_LANGUAGE_ASSEMBLY)
+
+//
+// QVA
+// HAL_MAKE_QVA(
+// ULONGLONG PhysicalAddress
+// )
+//
+// Routine Description:
+//
+// This macro returns the Qva for a physical address in system space.
+//
+// Arguments:
+//
+// PhysicalAddress - Supplies a 64-bit physical address.
+//
+// Return Value:
+//
+// The Qva associated with the physical address.
+//
+
+#define HAL_MAKE_QVA(PA) \
+ ( (PVOID)( QVA_ENABLE | (ULONG)(PA >> IO_BIT_SHIFT) ) )
+
+
+//
+// Define the different supported passes of the LCA4 processor.
+//
+
+typedef enum _LCA4_REVISIONS{
+ Lca4Pass1 = 1,
+ Lca4Pass2 = 2
+}LCA4_REVISIONS, *PLCA4_REVISIONS;
+
+//
+// Define physical address spaces for LCA4.
+//
+
+#define LCA4_MEMC_BASE_PHYSICAL ((ULONGLONG)0x120000000)
+#define LCA4_IOC_BASE_PHYSICAL ((ULONGLONG)0x180000000)
+#define LCA4_PCI_MEMORY_BASE_PHYSICAL ((ULONGLONG)0x200000000)
+#define LCA4_PCI_CONFIG_BASE_PHYSICAL ((ULONGLONG)0x1E0000000)
+
+#define LCA4_PASS1_IOC_TBTAG_PHYSICAL ((ULONGLONG)0x181000000)
+#define LCA4_PASS1_PCI_INTACK_BASE_PHYSICAL ((ULONGLONG)0x1C0000000)
+#define LCA4_PASS1_PCI_IO_BASE_PHYSICAL ((ULONGLONG)0x300000000)
+
+#define LCA4_PASS2_IOC_TBTAG_PHYSICAL ((ULONGLONG)0x181000000)
+#define LCA4_PASS2_PCI_INTACK_BASE_PHYSICAL ((ULONGLONG)0x1A0000000)
+#define LCA4_PASS2_PCI_IO_BASE_PHYSICAL ((ULONGLONG)0x1C0000000)
+#define LCA4_PASS2_PCI_DENSE_BASE_PHYSICAL ((ULONGLONG)0x300000000)
+
+
+//
+// Define the Memory Controller CSRs.
+//
+
+
+#define LCA4_MEMC_BASE_QVA (HAL_MAKE_QVA(LCA4_MEMC_BASE_PHYSICAL))
+
+//
+// N.B. The structure below defines the offsets of the registers within
+// the memory controller. These are "real" address offsets, not
+// QVA offsets. Unfortunately, since these offsets represent "real"
+// quadword addresses, they cannot be used as QVAs. Therefore,
+// the routines to read and write the memory controller will take
+// the base QVA and an offset as 2 address parameters, rather than
+// using a single address parameter. This is inconvenient but
+// manageable.
+//
+
+typedef struct _LCA4_MEMC_CSRS{
+ ULONGLONG BankConfiguration0;
+ ULONGLONG BankConfiguration1;
+ ULONGLONG BankConfiguration2;
+ ULONGLONG BankConfiguration3;
+ ULONGLONG BankMask0;
+ ULONGLONG BankMask1;
+ ULONGLONG BankMask2;
+ ULONGLONG BankMask3;
+ ULONGLONG BankTiming0;
+ ULONGLONG BankTiming1;
+ ULONGLONG BankTiming2;
+ ULONGLONG BankTiming3;
+ ULONGLONG GlobalTiming;
+ ULONGLONG ErrorStatus;
+ ULONGLONG ErrorAddress;
+ ULONGLONG CacheControl;
+ ULONGLONG VideoGraphicsControl;
+ ULONGLONG PlaneMask;
+ ULONGLONG Foreground;
+} LCA4_MEMC_CSRS, *PLCA4_MEMC_CSRS;
+
+
+//
+// Define IO Controller CSRs.
+//
+
+#define LCA4_IOC_BASE_QVA (HAL_MAKE_QVA(LCA4_IOC_BASE_PHYSICAL))
+#define LCA4_IOC_TBTAG_QVA (HAL_MAKE_QVA(LCA4_IOC_TBTAG_PHYSICAL))
+
+//
+// N.B. The structures below defines the address offsets of the control
+// registers when used with the base QVA. It does NOT define the
+// size or structure of the individual registers.
+//
+
+typedef struct _LCA4_IOC_CSRS{
+ UCHAR HostAddressExtension;
+ UCHAR ConfigurationCycleType;
+ UCHAR IocStat0;
+ UCHAR IocStat1;
+ UCHAR Tbia;
+ UCHAR TbEnable;
+ UCHAR PciSoftReset;
+ UCHAR PciParityDisable;
+ UCHAR WindowBase0;
+ UCHAR WindowBase1;
+ UCHAR WindowMask0;
+ UCHAR WindowMask1;
+ UCHAR TranslatedBase0;
+ UCHAR TranslatedBase1;
+} LCA4_IOC_CSRS, *PLCA4_IOC_CSRS;
+
+#define LCA4_IOC_TB_ENTRIES (8)
+
+typedef struct _LCA4_IOC_TBTAGS{
+ UCHAR IocTbTag[LCA4_IOC_TB_ENTRIES];
+} LCA4_IOC_TBTAGS, *PLCA4_IOC_TBTAGS;
+
+//
+// Define formats of useful IOC registers.
+//
+
+typedef struct _LCA4_IOC_HAE{
+ ULONG Reserved1: 27;
+ ULONG Hae: 5;
+ ULONG Reserved;
+} LCA4_IOC_HAE, *PLCA4_IOC_HAE;
+
+typedef struct _LCA4_IOC_CCT{
+ ULONG CfgAd: 2;
+ ULONG Reserved1: 30;
+ ULONG Reserved;
+} LCA4_IOC_CCT, *PLCA4_IOC_CCT;
+
+typedef struct _LCA4_IOC_TBEN{
+ ULONG Reserved1: 7;
+ ULONG Ten: 1;
+ ULONG Reserved2: 24;
+ ULONG Reserved;
+} LCA4_IOC_TBEN, *PLCA4_IOC_TBEN;
+
+typedef struct _LCA4_IOC_PCISR{
+ ULONG Reserved1: 6;
+ ULONG Rst: 1;
+ ULONG Reserved2: 25;
+ ULONG Reserved;
+} LCA4_IOC_PCISR, *PLCA4_IOC_PCISR;
+
+typedef struct _LCA4_IOC_PCIPD{
+ ULONG Reserved1: 5;
+ ULONG Par: 1;
+ ULONG Reserved2: 26;
+ ULONG Reserved;
+} LCA4_IOC_PCIPD, *PLCA4_IOC_PCIPD;
+
+typedef struct _LCA4_IOC_STAT0{
+ ULONG Cmd: 4;
+ ULONG Err: 1;
+ ULONG Lost: 1;
+ ULONG THit: 1;
+ ULONG TRef: 1;
+ ULONG Code: 3;
+ ULONG Reserved1: 2;
+ ULONG Pnbr: 19;
+ ULONG Reserved;
+} LCA4_IOC_STAT0, *PLCA4_IOC_STAT0;
+
+typedef enum _LCA4_IOC_STAT0_CODE{
+ IocErrorRetryLimit = 0x0,
+ IocErrorNoDevice = 0x1,
+ IocErrorBadDataParity = 0x2,
+ IocErrorTargetAbort = 0x3,
+ IocErrorBadAddressParity = 0x4,
+ IocErrorPageTableReadError = 0x5,
+ IocErrorInvalidPage = 0x6,
+ IocErrorDataError = 0x7,
+ MaximumIocError
+} LCA4_IOC_STAT0_CODE, *PLCA4_IOC_STAT0_CODE;
+
+typedef struct _LCA4_IOC_STAT1{
+ ULONG Addr;
+ ULONG Reserved;
+} LCA4_IO_STAT1, *PLCA4_IO_STAT1;
+
+typedef struct _LCA4_IOC_WMASK{
+ ULONG Reserved1: 20;
+ ULONG MaskValue: 12;
+ ULONG Reserved;
+} LCA4_IOC_WMASK, *PLCA4_IOC_WMASK;
+
+typedef struct _LCA4_IOC_WBASE{
+ ULONG Reserved1: 20;
+ ULONG BaseValue: 12;
+ ULONG Sg: 1;
+ ULONG Wen: 1;
+ ULONG Reserved2: 30;
+} LCA4_IOC_WBASE, *PLCA4_IOC_WBASE;
+
+typedef struct _LCA4_IOC_TBASE{
+ ULONG Reserved1: 10;
+ ULONG TBase: 22;
+ ULONG Reserved;
+} LCA4_IOC_TBASE, *PLCA4_IOC_TBASE;
+
+typedef struct _LCA4_IOC_TBTAG{
+ ULONG Reserved1: 13;
+ ULONG TbTag: 19;
+ ULONG Reserved;
+} LCA4_IOC_TBTAG, *PLCA4_IOC_TBTAG;
+
+typedef struct _LCA4_IOC_CTRL{
+ ULONG CfgAd: 2;
+ ULONG Reserved1: 2;
+ ULONG Cerr: 1;
+ ULONG Clost: 1;
+ ULONG Rst: 1;
+ ULONG Ten: 1;
+ ULONG Reserved2: 19;
+ ULONG Hae: 5;
+ ULONG Reserved;
+} LCA4_IOC_CTRL, *PLCA4_IOC_CTRL;
+
+//
+// Define formats of useful Memory Controller registers.
+//
+
+typedef struct _LCA4_MEMC_ESR{
+ ULONG Eav: 1;
+ ULONG Cee: 1;
+ ULONG Uee: 1;
+ ULONG Wre: 1;
+ ULONG Sor: 1;
+ ULONG Reserved1: 2;
+ ULONG Cte: 1;
+ ULONG Reserved2: 1;
+ ULONG Mse: 1;
+ ULONG Mhe: 1;
+ ULONG Ice: 1;
+ ULONG Nxm: 1;
+ ULONG Reserved3: 19;
+ ULONG Reserved;
+} LCA4_MEMC_ESR, *PLCA4_MEMC_ESR;
+
+
+//
+// Define PCI Config Space QVA
+//
+
+#define LCA4_PCI_CONFIG_BASE_QVA (HAL_MAKE_QVA(LCA4_PCI_CONFIG_BASE_PHYSICAL))
+
+#if !defined(AXP_FIRMWARE)
+
+
+//
+// DMA Window Values.
+//
+// The LCA4 will be initialized to allow 2 DMA windows.
+// The first window will be for the use of of ISA devices and DMA slaves
+// and therefore must have logical addresses below 16MB.
+// The second window will be for bus masters (non-ISA) and so may be
+// above 16MB.
+//
+// The arrangement of the windows will be as follows:
+//
+// Window Logical Start Address Window Size
+// ------ --------------------- -----------
+// Isa 8MB 8MB
+// Master 16MB 16MB
+//
+
+#define ISA_DMA_WINDOW_BASE (__8MB)
+#define ISA_DMA_WINDOW_SIZE (__8MB)
+
+#define MASTER_DMA_WINDOW_BASE (__16MB)
+#define MASTER_DMA_WINDOW_SIZE (__16MB)
+
+
+//
+// Define the software control registers for a DMA window.
+//
+
+typedef struct _WINDOW_CONTROL_REGISTERS{
+ PVOID WindowBase;
+ ULONG WindowSize;
+ PVOID TranslatedBaseRegister;
+ PVOID WindowBaseRegister;
+ PVOID WindowMaskRegister;
+ PVOID WindowTbiaRegister;
+} WINDOW_CONTROL_REGISTERS, *PWINDOW_CONTROL_REGISTERS;
+
+//
+// Define types of windows.
+//
+
+typedef enum _LCA4_WINDOW_NUMBER{
+ Lca4IsaWindow,
+ Lca4MasterWindow
+} LCA4_WINDOW_NUMBER, *PLCA4_WINDOW_NUMBER;
+
+//
+// Define LCA4 Window Control routines.
+//
+
+VOID
+HalpLca4InitializeSfwWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ LCA4_WINDOW_NUMBER WindowNumber
+ );
+
+VOID
+HalpLca4ProgramDmaWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ PVOID MapRegisterBase
+ );
+
+
+//
+// VOID
+// INITIALIZE_ISA_DMA_CONTROL(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters
+// )
+//
+// Routine Description:
+//
+// Initialize the DMA Control software window registers for the ISA
+// DMA window.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window control.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INITIALIZE_ISA_DMA_CONTROL( WR ) \
+ HalpLca4InitializeSfwWindow( (WR), Lca4IsaWindow );
+
+
+//
+// VOID
+// INITIALIZE_MASTER_DMA_CONTROL(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters
+// )
+//
+// Routine Description:
+//
+// Initialize the DMA Control software window registers for the Master
+// DMA window.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window control.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INITIALIZE_MASTER_DMA_CONTROL( WR ) \
+ HalpLca4InitializeSfwWindow( (WR), Lca4MasterWindow );
+
+
+//
+// VOID
+// INITIALIZE_DMA_WINDOW(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters,
+// PTRANSLATION_ENTRY MapRegisterBase
+// )
+//
+// Routine Description:
+//
+// Program the control windows so that DMA can be started to the
+// DMA window.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window register
+// control structure.
+//
+// MapRegisterBase - Supplies the logical address of the scatter/gather
+// array in system memory.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INITIALIZE_DMA_WINDOW( WR, MRB ) \
+ HalpLca4ProgramDmaWindow( (WR), (MRB) );
+
+
+//
+// VOID
+// INVALIDATE_DMA_TRANSLATIONS(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters
+// )
+//
+// Routine Description:
+//
+// Invalidate all of the cached translations for a DMA window.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window control
+// registers.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INVALIDATE_DMA_TRANSLATIONS( WR ) \
+ WRITE_IOC_REGISTER( \
+ ((PWINDOW_CONTROL_REGISTERS)WR)->WindowTbiaRegister, 0 );
+
+
+//
+// Define the format of a translation entry aka a scatter/gather entry
+// or map register.
+//
+
+typedef struct _TRANSLATION_ENTRY{
+ ULONG Valid: 1;
+ ULONG Pfn: 31;
+ ULONG Reserved;
+} TRANSLATION_ENTRY, *PTRANSLATION_ENTRY;
+
+
+
+//
+// VOID
+// HAL_MAKE_VALID_TRANSLATION(
+// PTRANSLATION_ENTRY Entry,
+// ULONG PageFrameNumber
+// )
+//
+// Routine Description:
+//
+// Make the scatter/gather entry pointed to by Entry valid with
+// a translation to the page indicated by PageFrameNumber.
+//
+// Arguments:
+//
+// Entry - Supplies a pointer to the translation entry to make valid.
+//
+// PageFrameNumber - Supplies the page frame of the valid translation.
+//
+// Return Value:
+//
+// None.
+//
+
+#define HAL_MAKE_VALID_TRANSLATION( ENTRY, PFN ) \
+ { \
+ (ENTRY)->Valid = 1; \
+ (ENTRY)->Pfn = PFN; \
+ (ENTRY)->Reserved = 0; \
+ }
+
+
+//
+// VOID
+// HAL_INVALIDATE_TRANSLATION(
+// PTRANSLATION_ENTRY Entry
+// )
+//
+// Routine Description:
+//
+// Invalidate the translation indicated by Entry.
+//
+// Arguments:
+//
+// Entry - Supplies a pointer to the translation to be invalidated.
+//
+// Return Value:
+//
+// None.
+//
+
+#define HAL_INVALIDATE_TRANSLATION( ENTRY ) \
+ (ENTRY)->Valid = 0;
+
+//
+// Define the per-processor data structures allocated in the PCR
+// for each LCA4 processor.
+//
+
+typedef struct _LCA4_PCR{
+ ULONGLONG HalpCycleCount; // 64-bit per-processor cycle count
+ EV4ProfileCount ProfileCount; // Profile counter state, do not move
+ EV4IrqStatus IrqStatusTable[MaximumIrq]; // Irq status table
+} LCA4_PCR, *PLCA4_PCR;
+
+#define HAL_PCR ( (PLCA4_PCR)(&(PCR->HalReserved)) )
+
+#endif //!AXP_FIRMWARE
+
+
+//
+// Define LCA4-specific function prototypes.
+//
+
+ULONG
+HalpDetermineLca4Revision(
+ VOID
+ );
+
+VOID
+HalpLca4MapAddressSpaces(
+ VOID
+ );
+
+ULONGLONG
+HalpLca4IocTbTagPhysical(
+ VOID
+ );
+
+ULONGLONG
+HalpLca4PciIntAckPhysical(
+ VOID
+ );
+
+ULONGLONG
+HalpLca4PciIoPhysical(
+ VOID
+ );
+
+ULONGLONG
+HalpLca4PciDensePhysical(
+ VOID
+ );
+
+ULONG
+HalpLca4Revision(
+ VOID
+ );
+
+VOID
+WRITE_MEMC_REGISTER(
+ IN PVOID RegisterOffset,
+ IN ULONGLONG Value
+ );
+
+ULONGLONG
+READ_MEMC_REGISTER(
+ IN PVOID RegisterOffset
+ );
+
+VOID
+WRITE_IOC_REGISTER(
+ IN PVOID RegisterQva,
+ IN ULONGLONG Value
+ );
+
+ULONGLONG
+READ_IOC_REGISTER(
+ IN PVOID RegisterQva
+ );
+
+VOID
+HalpClearAllErrors(
+ IN BOOLEAN EnableCorrectableErrors
+ );
+
+
+
+//
+// Define primary (and only) CPU for an LCA system
+//
+
+#define HAL_PRIMARY_PROCESSOR (0)
+#define HAL_MAXIMUM_PROCESSOR (0)
+
+#endif //!_LANGUAGE_ASSEMBLY
+
+#endif //_LCA4H_
+
diff --git a/private/ntos/nthals/halalpha/lca4err.c b/private/ntos/nthals/halalpha/lca4err.c
new file mode 100644
index 000000000..edf050f1e
--- /dev/null
+++ b/private/ntos/nthals/halalpha/lca4err.c
@@ -0,0 +1,1153 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ lca4err.c
+
+Abstract:
+
+ This module implements error handling (machine checks and error
+ interrupts) for machines based on the DECchip 21066
+ microprocessor.
+
+Author:
+
+ Joe Notarangelo 8-Feb-1994
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "axp21066.h"
+#include "lca4.h"
+#include "stdio.h"
+
+//
+// Declare the extern variable UncorrectableError declared in
+// inithal.c.
+//
+extern PERROR_FRAME PUncorrectableError;
+
+//
+// MAX_RETRYABLE_ERRORS is the number of times to retry machine checks before
+// just giving up.
+//
+
+#define MAX_RETRYABLE_ERRORS 32
+
+//
+//jnfix - temporary counts
+//
+
+ULONG CorrectableErrors = 0;
+ULONG RetryableErrors = 0;
+
+
+VOID
+HalpDisplayLogout21066 (
+ IN ESR_21066 Esr,
+ IN IOC_STAT0_21066 IoStat0,
+ IN PLOGOUT_FRAME_21066 LogoutFrame
+ );
+
+VOID
+HalpClearMachineCheck(
+ VOID
+ );
+
+ULONG
+HalpBankError(
+ ULONG PhysicalAddress,
+ PLOGOUT_FRAME_21066 LogoutFrame
+ );
+
+//jnfix - should be exported from platform-specific
+ULONG
+HalpSimmError(
+ ULONG PhysicalAddress,
+ PLOGOUT_FRAME_21066 LogoutFrame
+ );
+
+
+VOID
+HalpClearAllErrors(
+ IN BOOLEAN SignalMemoryCorrectables
+ )
+/*++
+
+Routine Description:
+
+ This routine clears all of the error bits in the LCA4 memory
+ controller and I/O controller.
+
+Arguments:
+
+ SignalMemoryCorrectables - Supplies a boolean value which specifies
+ if correctable error reporting should be
+ enabled in the memory controller.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ ESR_21066 ErrorStatus;
+ IOC_STAT0_21066 IoStat0;
+
+ //
+ // The error status bits of the ESR are all write one to clear.
+ // Clear the value and then set all of the error bits. Then set
+ // correctable enable according to specified input.
+ //
+
+ ErrorStatus.all.QuadPart = (ULONGLONG)0;
+
+ ErrorStatus.Eav = 1;
+ ErrorStatus.Cee = 1;
+ ErrorStatus.Uee = 1;
+ ErrorStatus.Cte = 1;
+ ErrorStatus.Mse = 1;
+ ErrorStatus.Mhe = 1;
+ ErrorStatus.Nxm = 1;
+
+ if( SignalMemoryCorrectables == TRUE ){
+ ErrorStatus.Ice = 0;
+ } else {
+ ErrorStatus.Ice = 1;
+ }
+
+ WRITE_MEMC_REGISTER( &((PLCA4_MEMC_CSRS)(0))->ErrorStatus,
+ ErrorStatus.all.QuadPart );
+
+ //
+ // The ERR and LOST bits of the IO_STAT0 are write one to clear.
+ //
+
+ IoStat0.all.QuadPart = (ULONGLONG)0;
+
+ IoStat0.Err = 1;
+ IoStat0.Lost = 1;
+
+ WRITE_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0,
+ IoStat0.all.QuadPart );
+
+ return;
+
+}
+
+VOID
+HalpBuildLCAUncorrectableErrorFrame(
+ VOID
+ )
+{
+ PPROCESSOR_LCA_UNCORRECTABLE LcaUncorrerr = NULL;
+ PEXTENDED_ERROR PExtErr;
+ EAR_21066 Ear;
+
+ if(PUncorrectableError){
+ LcaUncorrerr = (PPROCESSOR_LCA_UNCORRECTABLE)
+ PUncorrectableError->UncorrectableFrame.RawProcessorInformation;
+
+ //
+ // first fill in some generic processor Information.
+ // For the Current (Reporting) Processor.
+ //
+ HalpGetProcessorInfo(
+ &PUncorrectableError->UncorrectableFrame.ReportingProcessor);
+ PUncorrectableError->
+ UncorrectableFrame.Flags.ProcessorInformationValid = 1;
+
+
+ PExtErr = &PUncorrectableError->UncorrectableFrame.ErrorInformation;
+ }
+
+ if(LcaUncorrerr) {
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+ sprintf(PUncorrectableError->UncorrectableFrame.ErrorString,
+ "Uncorrectable Error From "
+ "LCA4 Detected");
+ LcaUncorrerr->IocStat0 = (ULONGLONG)
+ READ_IOC_REGISTER(&((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0);
+
+ LcaUncorrerr->IocStat1 = (ULONGLONG)
+ READ_IOC_REGISTER(&((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat1);
+
+ LcaUncorrerr->Esr = (ULONGLONG)
+ READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->ErrorStatus);
+
+ Ear.all.QuadPart = LcaUncorrerr->Ear = (ULONGLONG)
+ READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->ErrorAddress);
+
+ PUncorrectableError->UncorrectableFrame.Flags.PhysicalAddressValid = 1;
+ PUncorrectableError->UncorrectableFrame.PhysicalAddress =
+ Ear.ErrorAddress;
+
+ LcaUncorrerr->BankConfig0 =
+ READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration0);
+
+ LcaUncorrerr->BankConfig1 =
+ READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration1);
+
+ LcaUncorrerr->BankConfig2 =
+ READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration2);
+
+ LcaUncorrerr->BankConfig3 =
+ READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankConfiguration3);
+
+ LcaUncorrerr->BankMask0 =
+ READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask0);
+
+ LcaUncorrerr->BankMask1 =
+ READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask1);
+
+ LcaUncorrerr->BankMask2 =
+ READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask2);
+
+ LcaUncorrerr->BankMask3 =
+ READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->BankMask3);
+
+ LcaUncorrerr->Car =
+ READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->CacheControl);
+
+ LcaUncorrerr->Gtr =
+ READ_MEMC_REGISTER(&((PLCA4_MEMC_CSRS)(0))->GlobalTiming);
+ }
+}
+
+
+BOOLEAN
+HalMachineCheck (
+ IN PEXCEPTION_RECORD ExceptionRecord,
+ IN PKEXCEPTION_FRAME ExceptionFrame,
+ IN PKTRAP_FRAME TrapFrame
+ )
+/*++
+
+Routine Description:
+
+ This function fields machine checks for 21066-based machines.
+
+ The following errors may be the cause of the machine check:
+
+ (a) Uncorrectable Dcache error
+ (b) Uncorrectable Load from Memory Controller
+ (c) Uncorrectable Load from I/O Controller
+ (d) Non-existent device in PCI Configuration Space (I/O Controller)
+ (e) Retryable Icache parity error
+
+Arguments:
+
+ ExceptionRecord - Supplies a pointer to the exception record for the
+ machine check. Included in the exception information
+ is the pointer to the logout frame.
+
+ ExceptionFrame - Supplies a pointer to the kernel exception frame.
+
+ TrapFrame - Supplies a pointer to the kernel trap frame.
+
+Return Value:
+
+ A value of TRUE is returned if the machine check has been
+ handled by the HAL. If it has been handled then execution may
+ resume at the faulting address. Otherwise, a value of FALSE
+ is returned.
+
+ N.B. - When a fatal error is recognized this routine does not
+ return at all.
+
+--*/
+
+{
+
+ PMCHK_STATUS MachineCheckStatus;
+ ESR_21066 ErrorStatus;
+ IOC_STAT0_21066 IoStat0;
+ PPROCESSOR_LCA_UNCORRECTABLE LcaUncorrerr = NULL;
+
+ MachineCheckStatus =
+ (PMCHK_STATUS)&ExceptionRecord->ExceptionInformation[0];
+
+ //
+ // Print an error message if a correctable machine check is signalled.
+ // Correctable machine checks are not possible on the 21066.
+ //
+
+ if( MachineCheckStatus->Correctable == 1 ){
+
+#if DBG
+
+ DbgPrint( "Illegal correctable error for LCA4\n" );
+
+#endif //DBG
+
+ }
+
+ //
+ // If the machine check is retryable then log the error and
+ // and restart the operation.
+ //
+
+ if( MachineCheckStatus->Retryable == 1 ){
+
+ //
+ // jnfix Log the error, interface undefined.
+ //
+
+ //
+ // Increment the number of retryable machine checks.
+ //
+
+ RetryableErrors += 1;
+
+
+#if (DBG) || (HALDBG)
+
+ DbgPrint( "HAL Retryable Errors = %d\n", RetryableErrors );
+ // if( (RetryableErrors % 32) == 0 ){
+ // DbgPrint( "HAL Retryable Errors = %d\n", RetryableErrors );
+ // }
+
+#endif //DBG || HALDBG
+
+
+ //
+ // We'll retry MAX_RETRYABLE_ERRORS times and then give up. We
+ // do this to avoid infinite retry loops.
+ //
+
+ if( RetryableErrors > MAX_RETRYABLE_ERRORS ){
+
+ //
+ // Acknowledge receipt of the retryable machine check.
+ //
+ DbgPrint("Got too many Retryable Errors errors\n");
+ }
+
+ //
+ // Clear the machine check in the MCES register.
+ //
+
+ HalpClearMachineCheck();
+
+ //
+ // Attempt to retry the operation.
+ //
+
+ return TRUE;
+
+ }
+
+ //
+ // The machine check is uncorrectable according to the processor.
+ // Read the error registers in the Memory and I/O Controller.
+ // If the operation was a read to PCI configuration space and no
+ // device is the error then we will fix up the operation and continue,
+ // otherwise the machine has taken a fatal error.
+ //
+
+//jnfix - code here to check for dcache parity error?
+
+
+ ErrorStatus.all.QuadPart =
+ READ_MEMC_REGISTER(
+ &((PLCA4_MEMC_CSRS)(0))->ErrorStatus );
+
+ IoStat0.all.QuadPart =
+ READ_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0 );
+
+ //
+ // If any of the following errors are indicated in the memory controller
+ // then process a fatal error:
+ // Uncorrectable Error
+ // Cache Tag Error
+ // Multiple Hard Errors
+ // Non-existent Memory
+ //
+
+ if( (ErrorStatus.Uee == 1) ||
+ (ErrorStatus.Cte == 1) ||
+ (ErrorStatus.Mhe == 1) ||
+ (ErrorStatus.Nxm == 1) ){
+
+ goto FatalError;
+
+ }
+
+ //
+ // Check for a PCI configuration read error. An error is a
+ // candidate if the I/O controller has signalled an error, there
+ // are no lost errors and the error was a no device error on the PCI.
+ //
+
+ if( (IoStat0.Err == 1) && (IoStat0.Code == IocErrorNoDevice) &&
+ (IoStat0.Lost == 0) ){
+
+ //
+ // So far, the error looks like a PCI configuration space read
+ // that accessed a device that does not exist. In order to fix
+ // this up we expect that the faulting instruction or the instruction
+ // previous to the faulting instruction must be a load with v0 as
+ // the destination register. If this condition is met then simply
+ // update v0 in the register set and return. However, be careful
+ // not to re-execute the load.
+ //
+ // jnfix - add condition to check if Rb contains the superpage
+ // address for config space?
+
+ ALPHA_INSTRUCTION FaultingInstruction;
+ BOOLEAN PreviousInstruction = FALSE;
+
+ FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir);
+ if( (FaultingInstruction.Memory.Ra != V0_REG) ||
+ (FaultingInstruction.Memory.Opcode != LDL_OP) ){
+
+ //
+ // Faulting instruction did not match, try the previous
+ // instruction.
+ //
+
+ PreviousInstruction = TRUE;
+
+ FaultingInstruction.Long = *(PULONG)((ULONG)TrapFrame->Fir - 4);
+ if( (FaultingInstruction.Memory.Ra != V0_REG) ||
+ (FaultingInstruction.Memory.Opcode != LDL_OP) ){
+
+ //
+ // No match, we can't fix this up.
+ //
+
+ goto FatalError;
+ }
+ }
+
+ //
+ // The error has matched all of our conditions. Fix it up by
+ // writing the value 0xffffffff into the destination of the load.
+ //
+
+ TrapFrame->IntV0 = (ULONGLONG)0xffffffffffffffff;
+
+ //
+ // Clear the machine check condition in the processor.
+ //
+
+ HalpClearMachineCheck();
+
+ //
+ // Clear the error condition in the io controller.
+ // The Err bit is write one to clear.
+ //
+
+ IoStat0.all.QuadPart = (ULONGLONG)0;
+ IoStat0.Err = 1;
+ WRITE_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat0,
+ IoStat0.all.QuadPart );
+
+ //
+ // If the faulting instruction was the load the restart execution
+ // at the instruction after the load.
+ //
+
+ if( PreviousInstruction == FALSE ){
+ TrapFrame->Fir += 4;
+ }
+
+ return TRUE;
+
+ } //end if (IoStat0.Err == 1) && (IoStat0.Code == IocErrorNoDevice) ){
+
+
+//
+// The system is not well and cannot continue reliable execution.
+// Print some useful messages and shutdown the machine.
+//
+
+FatalError:
+
+ HalpBuildLCAUncorrectableErrorFrame();
+
+ if(PUncorrectableError){
+ LcaUncorrerr = (PPROCESSOR_LCA_UNCORRECTABLE)
+ PUncorrectableError->UncorrectableFrame.RawProcessorInformation;
+
+ LcaUncorrerr->AboxCtl = (ULONGLONG)
+ ((PLOGOUT_FRAME_21066)
+ (ExceptionRecord->ExceptionInformation[1] ))->AboxCtl.all.QuadPart;
+
+ LcaUncorrerr->CStat = (ULONGLONG)
+ ((PLOGOUT_FRAME_21066)
+ (ExceptionRecord->ExceptionInformation[1] ))->DcStat.all.QuadPart;
+
+ LcaUncorrerr->MmCsr = (ULONGLONG)
+ ((PLOGOUT_FRAME_21066)
+ (ExceptionRecord->ExceptionInformation[1] ))->MmCsr.all.QuadPart;
+ }
+
+ //
+ // Display the logout frame.
+ //
+
+ HalpDisplayLogout21066(
+ ErrorStatus,
+ IoStat0,
+ (PLOGOUT_FRAME_21066)(ExceptionRecord->ExceptionInformation[1]) );
+
+ //
+ //
+ // Bugcheck to dump the rest of the machine state, this will help
+ // if the machine check is software-related.
+ //
+
+ KeBugCheckEx( DATA_BUS_ERROR,
+ (ULONG)MachineCheckStatus->Correctable,
+ (ULONG)MachineCheckStatus->Retryable,
+ 0,
+ (ULONG)PUncorrectableError );
+
+}
+
+VOID
+HalpClearMachineCheck(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Clear the machine check which is currently pending. Clearing the
+ pending machine check bit will allow us to take machine checks in
+ the future without detecting a double machine check condition.
+ The machine check pending bit must be cleared in the MCES register
+ within the PALcode.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ MCES MachineCheckSummary;
+
+ MachineCheckSummary.MachineCheck = 1;
+ MachineCheckSummary.SystemCorrectable = 0;
+ MachineCheckSummary.ProcessorCorrectable = 0;
+ MachineCheckSummary.DisableProcessorCorrectable = 0;
+ MachineCheckSummary.DisableSystemCorrectable = 0;
+ MachineCheckSummary.DisableMachineChecks = 0;
+
+ HalpWriteMces( MachineCheckSummary );
+
+ return;
+
+}
+
+#define MAX_ERROR_STRING 100
+
+VOID
+HalpDisplayLogout21066 (
+ IN ESR_21066 Esr,
+ IN IOC_STAT0_21066 IoStat0,
+ IN PLOGOUT_FRAME_21066 LogoutFrame
+ )
+/*++
+
+Routine Description:
+
+ This function displays the logout frame for a 21066.
+
+Arguments:
+
+ Esr - Supplies the value of the memory controller error status register.
+
+ IoStat0 - Supplies the value of the i/o controller status register 0.
+
+ LogoutFrame - Supplies a pointer to the logout frame generated
+ by the 21066.
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR OutBuffer[ MAX_ERROR_STRING ];
+ EAR_21066 Ear;
+ CAR_21066 Car;
+ IOC_STAT1_21066 IoStat1;
+ ULONG Index;
+ PKPRCB Prcb;
+ extern HalpLogicalToPhysicalProcessor[HAL_MAXIMUM_PROCESSOR+1];
+ PCHAR parityErrString = NULL;
+ PEXTENDED_ERROR exterr;
+
+
+ if(PUncorrectableError) {
+ exterr = &PUncorrectableError->UncorrectableFrame.ErrorInformation;
+ parityErrString = PUncorrectableError->UncorrectableFrame.ErrorString;
+ }
+
+
+ //
+ // Capture other useful registers, EAR, CAR, and IO_STAT1.
+ //
+
+ Ear.all.QuadPart =
+ READ_MEMC_REGISTER(
+ &((PLCA4_MEMC_CSRS)(0))->ErrorAddress );
+
+ Car.all.QuadPart =
+ READ_MEMC_REGISTER(
+ &((PLCA4_MEMC_CSRS)(0))->CacheControl );
+
+ IoStat1.all.QuadPart =
+ READ_IOC_REGISTER( &((PLCA4_IOC_CSRS)(LCA4_IOC_BASE_QVA))->IocStat1);
+
+ //
+ // Acquire ownership of the display. This is done here in case we take
+ // a machine check before the display has been taken away from the HAL.
+ // When the HAL begins displaying strings after it has lost the
+ // display ownership then the HAL will be careful not to scroll information
+ // off of the screen.
+ //
+
+ HalAcquireDisplayOwnership(NULL);
+
+ //
+ // Display the machine state via the logout frame.
+ //
+
+ HalDisplayString( "\nFatal system hardware error.\n\n" );
+
+
+ sprintf( OutBuffer, "MEMC_ESR: %16Lx MEMC_EAR: %16Lx CAR: %16Lx\n",
+ Esr.all.QuadPart,
+ Ear.all.QuadPart,
+ Car.all.QuadPart );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "IO_STAT0: %16Lx IO_STAT1: %16Lx\n",
+ IoStat0.all.QuadPart,
+ IoStat1.all.QuadPart );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "ICCSR : %016Lx ABOX_CTL: %016Lx DC_STAT: %016Lx\n",
+ ICCSR_ALL_21064(LogoutFrame->Iccsr),
+ ABOXCTL_ALL_21064(LogoutFrame->AboxCtl),
+ DCSTAT_ALL_21064(LogoutFrame->DcStat) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "EXC_ADDR : %016Lx VA : %016Lx MM_CSR : %016Lx\n",
+ LogoutFrame->ExcAddr.QuadPart,
+ LogoutFrame->Va.QuadPart,
+ MMCSR_ALL_21064(LogoutFrame->MmCsr) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "HIRR : %016Lx HIER : %016Lx PS : %016Lx\n",
+ IRR_ALL_21064(LogoutFrame->Hirr),
+ IER_ALL_21064(LogoutFrame->Hier),
+ PS_ALL_21064(LogoutFrame->Ps) );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "PAL_BASE : %016Lx \n",
+ LogoutFrame->PalBase.QuadPart );
+
+ HalDisplayString( OutBuffer );
+
+ sprintf( OutBuffer, "Waiting 15 seconds...\n");
+ HalDisplayString( OutBuffer );
+
+ for( Index=0; Index<1500; Index++)
+ KeStallExecutionProcessor( 10000 ); // ~15 second delay
+
+ //
+ // Print out interpretation of the error.
+ //
+
+ //
+ // First print the processor on which we saw the error
+ //
+
+ Prcb = PCR->Prcb;
+ sprintf( OutBuffer, "Error on processor number: %d\n",
+ HalpLogicalToPhysicalProcessor[Prcb->Number] );
+ HalDisplayString( OutBuffer );
+
+ //
+ // If we got a Data Cache Parity Error print a message on screen.
+ //
+
+ if( DCSTAT_DCPARITY_ERROR_21064(LogoutFrame->DcStat) ){
+
+ PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
+ MEMORY_SPACE;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ MemoryErrorSource = PROCESSOR_CACHE;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ ExtendedErrorValid = 1;
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+ sprintf( parityErrString,
+ "Data Cache Parity Error.\n");
+ HalpGetProcessorInfo(&exterr->CacheError.ProcessorInfo);
+
+ sprintf( OutBuffer, "Data Cache Parity Error.\n" );
+ HalDisplayString( OutBuffer );
+ }
+
+ //
+ // Check for uncorrectable error.
+ //
+
+ if( Esr.Uee == 1 ){
+
+ if( Esr.Sor == 0 ){
+
+ //
+ // Uncorrectable error from cache.
+ //
+ PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
+ MEMORY_SPACE;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ MemoryErrorSource = PROCESSOR_CACHE;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ ExtendedErrorValid = 1;
+ HalpGetProcessorInfo(&exterr->CacheError.ProcessorInfo);
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+
+ sprintf( parityErrString,
+ "Uncorrectable error from cache on %s, Tag: 0x%x\n",
+ Esr.Wre ? "write" : "read",
+ Car.Tag );
+ HalDisplayString( parityErrString );
+
+ } else {
+
+ //
+ // Uncorrectable error from memory.
+ //
+ PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
+ MEMORY_SPACE;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ MemoryErrorSource = SYSTEM_MEMORY;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ ExtendedErrorValid = 1;
+ HalpGetProcessorInfo(&exterr->MemoryError.ProcessorInfo);
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+
+ sprintf( parityErrString,
+ "Uncorrectable error from memory on %s\n",
+ Esr.Wre ? "write" : "read" );
+ HalDisplayString( parityErrString );
+
+ PUncorrectableError->UncorrectableFrame.Flags.
+ PhysicalAddressValid = 1;
+ PUncorrectableError->UncorrectableFrame.PhysicalAddress =
+ Ear.ErrorAddress;
+
+ exterr->MemoryError.Flags.MemorySimmValid = 1;
+ exterr->MemoryError.MemorySimm =
+ HalpSimmError( Ear.ErrorAddress, LogoutFrame );
+
+ sprintf( OutBuffer,
+ "Physical Address: 0x%x, Bank: %d, SIMM: %d\n",
+ Ear.ErrorAddress,
+ HalpBankError( Ear.ErrorAddress, LogoutFrame ),
+ HalpSimmError( Ear.ErrorAddress, LogoutFrame ) );
+ HalDisplayString( OutBuffer );
+
+ } //end if( Esr.Sor == 0 )
+
+ } //end if( Esr.Uee == 1 )
+
+ //
+ // Check for cache tag errors.
+ //
+
+ if( Esr.Cte == 1 ){
+ PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
+ MEMORY_SPACE;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ MemoryErrorSource = PROCESSOR_CACHE;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ ExtendedErrorValid = 1;
+ HalpGetProcessorInfo(&exterr->CacheError.ProcessorInfo);
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+
+
+ sprintf( parityErrString,
+ "Cache Tag Error, Tag: 0x%x, Hit: %d\n",
+ Car.Tag, Car.Hit );
+ HalDisplayString( parityErrString );
+
+ }
+
+ //
+ // Check for non-existent memory error.
+ //
+
+ if( Esr.Nxm == 1 ){
+
+ PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
+ MEMORY_SPACE;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ MemoryErrorSource = SYSTEM_MEMORY;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ ExtendedErrorValid = 1;
+ HalpGetProcessorInfo(&exterr->MemoryError.ProcessorInfo);
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+
+ sprintf( parityErrString,
+ "Non-existent memory accessed\n" );
+ sprintf( OutBuffer,
+ "Non-existent memory accessed, Physical Address: 0x%x.\n",
+ Ear.ErrorAddress );
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // Check for multiple hard errors.
+ //
+
+ if( Esr.Mhe == 1 ){
+ PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
+ MEMORY_SPACE;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ MemoryErrorSource = SYSTEM_MEMORY;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ ExtendedErrorValid = 1;
+ HalpGetProcessorInfo(&exterr->MemoryError.ProcessorInfo);
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+
+ sprintf( parityErrString,
+ "Multiple hard errors detected\n" );
+
+ sprintf( OutBuffer,
+ "Multiple hard errors detected.\n" );
+ HalDisplayString( OutBuffer );
+
+ }
+
+ //
+ // If an I/O Error was pending print the interpretation.
+ //
+
+ if( IoStat0.Err == 1 ){
+ PUncorrectableError->UncorrectableFrame.Flags.AddressSpace =
+ IO_SPACE;
+ PUncorrectableError->UncorrectableFrame.Flags.
+ ExtendedErrorValid = 1;
+ exterr->IoError.Interface = PCIBus;
+ exterr->IoError.BusNumber = 0;
+ exterr->IoError.BusAddress.QuadPart = IoStat1.Address;
+ PUncorrectableError->UncorrectableFrame.Flags.PhysicalAddressValid =
+ 1;
+ PUncorrectableError->UncorrectableFrame.PhysicalAddress =
+ IoStat1.Address;
+ PUncorrectableError->UncorrectableFrame.Flags.ErrorStringValid = 1;
+
+
+ switch( IoStat0.Code ){
+
+ //
+ // Retry Limit.
+ //
+
+ case IocErrorRetryLimit:
+ sprintf(parityErrString,
+ "Retry Limit Error, PCI Cmd 0x%x\n",
+ IoStat0.Cmd );
+
+ sprintf( OutBuffer,
+ "Retry Limit Error, PCI Address 0x%x PCI Cmd 0x%x\n",
+ IoStat1.Address,
+ IoStat0.Cmd );
+ break;
+
+ //
+ // No device error.
+ //
+
+ case IocErrorNoDevice:
+ sprintf(parityErrString,
+ "No Device Error, PCI Cmd 0x%x\n",
+ IoStat0.Cmd );
+
+
+ sprintf( OutBuffer,
+ "No Device Error, PCI Address 0x%x PCI Cmd 0x%x\n",
+ IoStat1.Address,
+ IoStat0.Cmd );
+ break;
+
+ //
+ // Bad data parity.
+ //
+
+ case IocErrorBadDataParity:
+ sprintf(parityErrString,
+ "Bad Data Parity Error, PCI Cmd 0x%x\n",
+ IoStat0.Cmd );
+
+
+ sprintf( OutBuffer,
+ "Bad Data Parity Error, PCI Address 0x%x PCI Cmd 0x%x\n",
+ IoStat1.Address,
+ IoStat0.Cmd );
+ break;
+
+ //
+ // Target abort.
+ //
+
+ case IocErrorTargetAbort:
+ sprintf(parityErrString,
+ "Target Abort, PCI Cmd 0x%x\n",
+ IoStat0.Cmd );
+
+
+ sprintf( OutBuffer,
+ "Target Abort, PCI Address 0x%x PCI Cmd 0x%x\n",
+ IoStat1.Address,
+ IoStat0.Cmd );
+ break;
+
+ //
+ // Bad address parity.
+ //
+
+ case IocErrorBadAddressParity:
+ sprintf(parityErrString,
+ "Bad Address Parity, PCI Cmd 0x%x\n",
+ IoStat0.Cmd );
+
+
+ sprintf( OutBuffer,
+ "Bad Address Parity, PCI Address 0x%x PCI Cmd 0x%x\n",
+ IoStat1.Address,
+ IoStat0.Cmd );
+ break;
+
+ //
+ // Page Table Read Error.
+ //
+
+ case IocErrorPageTableReadError:
+ sprintf(parityErrString,
+ "Page Table Read Error, PCI Cmd 0x%x\n",
+ IoStat0.Cmd );
+
+
+ sprintf( OutBuffer,
+ "Page Table Read Error, PCI Pfn 0x%x PCI Cmd 0x%x\n",
+ IoStat0.PageNumber,
+ IoStat0.Cmd );
+ break;
+
+ //
+ // Invalid page.
+ //
+
+ case IocErrorInvalidPage:
+ sprintf(parityErrString,
+ "Invalid Page Error, PCI Cmd 0x%x\n",
+ IoStat0.Cmd );
+
+
+ sprintf( OutBuffer,
+ "Invalid Page Error, PCI Pfn 0x%x PCI Cmd 0x%x\n",
+ IoStat0.PageNumber,
+ IoStat0.Cmd );
+ break;
+
+ //
+ // Data error.
+ //
+
+ case IocErrorDataError:
+
+ sprintf(parityErrString,
+ "Data Error, PCI Cmd 0x%x\n",
+ IoStat0.Cmd );
+
+ sprintf( OutBuffer,
+ "Data Error, PCI Address 0x%x PCI Cmd 0x%x\n",
+ IoStat1.Address,
+ IoStat0.Cmd );
+ break;
+
+ //
+ // Unrecognized error code.
+ //
+
+ default:
+
+ sprintf(parityErrString,
+ "Unrecognized I/O Error.\n" );
+
+ sprintf( OutBuffer, "Unrecognized I/O Error.\n" );
+ break;
+
+ } //end switch (IoStat0.Code)
+
+ HalDisplayString( OutBuffer );
+
+ if( IoStat0.Lost == 1 ){
+ sprintf(parityErrString,
+ "Additional I/O errors were lost.\n" );
+
+ HalDisplayString( "Additional I/O errors were lost.\n" );
+ }
+
+ } //end if( IoStat0.Err == 1 )
+
+ //
+ // return to caller
+ //
+
+ return;
+
+}
+
+
+ULONG
+HalpBankError(
+ ULONG PhysicalAddress,
+ PLOGOUT_FRAME_21066 LogoutFrame
+ )
+/*++
+
+Routine Description:
+
+ Return the bank of memory that the physical address fails within.
+
+Arguments:
+
+ PhysicalAddress - Supplies the physical address to locate.
+
+ LogoutFrame - Supplies a pointer to the logout frame that contains the
+ bank configuration information.
+
+Return Value:
+
+ Returns the number of the bank that contains the physical address.
+ Returns 0xffffffff if the physical address is not contained within any of
+ the banks.
+
+--*/
+{
+
+ ULONG Bank;
+
+ for( Bank=0; Bank < MEMORY_BANKS_21066; Bank++ ){
+
+ //
+ // If the bank is valid and the physical address is within the
+ // bank then we have found the correct bank.
+ //
+
+ if( (LogoutFrame->BankConfig[Bank].Bav == 1) &&
+ ((PhysicalAddress >> 20) &
+ (~LogoutFrame->BankMask[Bank].BankAddressMask)) ==
+ LogoutFrame->BankConfig[Bank].BankBase ){
+
+ return Bank;
+
+ }
+
+ }
+
+ //
+ // Did not find a bank which contains physical address.
+ //
+
+ return (0xffffffff);
+
+}
+
+//jnfix - this should be move to platform-specific
+//jnfix - and made real depending upon how memory is configured
+//jnfix - this current code is a simple guess which provides a model
+
+ULONG
+HalpSimmError(
+ ULONG PhysicalAddress,
+ PLOGOUT_FRAME_21066 LogoutFrame
+ )
+/*++
+
+Routine Description:
+
+ Return the SIMM number that the physical address fails within.
+
+Arguments:
+
+ PhysicalAddress - Supplies the physical address to locate.
+
+ LogoutFrame - Supplies a pointer to the logout frame that contains the
+ bank configuration information.
+
+Return Value:
+
+ Returns the number of the SIMM that contains the physical address.
+ Returns 0xffffffffif the physical address is not contained within any of
+ the SIMMs.
+
+--*/
+{
+ ULONG Bank;
+ ULONG Simm;
+
+ for( Bank=0; Bank < MEMORY_BANKS_21066; Bank++ ){
+
+ //
+ // If the bank is valid and the physical address is within the
+ // bank then we have found the correct bank.
+ //
+
+ if( (LogoutFrame->BankConfig[Bank].Bav == 1) &&
+ ((PhysicalAddress >> 20) &
+ (~LogoutFrame->BankMask[Bank].BankAddressMask)) ==
+ LogoutFrame->BankConfig[Bank].BankBase ){
+
+ //
+ // Assume that each bank contains 2 SIMMs and that they are
+ // numbered 0..N. We need to determine which SIMM within the
+ // bank. We will guess that the SIMMs are 32-bits wide and
+ // that the low 32-bits are in the low SIMM while the high
+ // 32-bits are in the high SIMM. So addresses 0..3 are low
+ // and 4..7 are high.
+ //
+
+ Simm = Bank * 2;
+ if( PhysicalAddress & 4 ) Simm += 1;
+ return Simm;
+
+ }
+
+ }
+
+ //
+ // Did not find a bank which contains physical address.
+ //
+
+ return (0xffffffff);
+
+}
diff --git a/private/ntos/nthals/halalpha/lcaioacc.s b/private/ntos/nthals/halalpha/lcaioacc.s
new file mode 100644
index 000000000..8d6f98760
--- /dev/null
+++ b/private/ntos/nthals/halalpha/lcaioacc.s
@@ -0,0 +1,746 @@
+
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ lcaioacc.s
+
+
+Abstract:
+
+ This module implements the low-level I/O access routines for the
+ DECchip 21066 microprocessor (a.k.a. Low Cost Alpha or LCA).
+
+ The module contains the functions to turn quasi virtual
+ addresses into an Alpha superpage virtual address
+ and then read or write based on the request.
+ (We are using the 43-bit superpage mode.)
+
+
+Author:
+
+ Jeff Mcleman (mcleman) 13-Jan-1993
+
+
+Environment:
+
+ Executes in kernel mode.
+
+Revision History:
+
+ 9-Mar-1993 - Bruce Butts - replaced hardcoded constants with
+ IO_BIT_SHIFT, IO_xxxx_LEN, and IO_xxxx_OFFSET
+ values defined in mrgndef.h. Commented out several
+ unused defines.
+
+ 3-Mar-1993 - Jeff McLeman - Bring up to rev.
+
+ 28-July-1994 - Sameer Dekate -
+
+ Made a common file alphaio.s for machine independent IO routines.
+
+
+--*/
+
+
+#include "lca4.h"
+#include "halalpha.h"
+
+
+
+ SBTTL( "Write I/O control register" )
+//++
+//
+// VOID
+// WRITE_IOC_REGISTER(
+// QVA RegisterQva,
+// ULONGLONG Value
+// )
+//
+// Routine Description:
+//
+// Writes a quadword location to LCA IOC register space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of register to be written.
+// Value(a1) - Supplies the quadword to be written.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_IOC_REGISTER)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ or t0, t4, t0 // superpage mode
+ stq a1, (t0) // write the longword
+ mb // order the write
+ ret zero, (ra) // return
+
+2:
+ stq a1, (a0) // store the longword
+ ret zero, (ra) // return
+
+ .end WRITE_IOC_REGISTER
+
+
+
+#define LCA4_MEMC_BASE_PHYSICAL 0x120000000
+
+ SBTTL( "Write memory control register" )
+//++
+//
+// VOID
+// WRITE_MEMC_REGISTER(
+// ULONG RegisterOffset,
+// ULONGLONG Value
+// )
+//
+// Routine Description:
+//
+// Writes a quadword location to LCA MEMC register space.
+//
+// Arguments:
+//
+// RegisterOffset(a0) - Supplies the offset of the memory controller
+// register within memory controller physical space.
+// Value(a1) - Supplies the quadword to be written.
+//
+// Return Value:
+//
+// None.
+//
+//--
+
+ LEAF_ENTRY(WRITE_MEMC_REGISTER)
+
+ ldiq t0, LCA4_MEMC_BASE_PHYSICAL // get memory cntlr physical address
+
+ ldiq t4, -0x4000 // create superpage mask
+ sll t4, 28, t4 // 0xffff fc00 0000 0000
+
+ bis t0, t4, t0 // get superpage address of mem ctlr
+ bis t0, a0, t0 // add offset of specified register
+
+ stq a1, (t0) // write the longword
+ mb // order the write
+ ret zero, (ra) // return
+
+ .end WRITE_MEMC_REGISTER
+
+
+
+ SBTTL( "Read I/O control register" )
+//++
+//
+// ULONGLONG
+// READ_IOC_REGISTER(
+// QVA RegisterQva
+// )
+//
+// Routine Description:
+//
+// Read a quadword location from LCA IOC register space.
+//
+// Arguments:
+//
+// RegisterQva(a0) - Supplies the QVA of register to be read.
+//
+// Return Value:
+//
+// v0 - Return the value read from the controller register.
+//
+//--
+
+ LEAF_ENTRY(READ_IOC_REGISTER)
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ or t0, t4, t0 // superpage mode
+ ldq v0, (t0) // read the quadword
+
+ ret zero, (ra) // return
+
+2:
+ ldq v0, (a0) // read the quadword
+ ret zero, (ra) // return
+
+ .end READ_IOC_REGISTER
+
+
+
+ SBTTL( "Read memory control register" )
+//++
+//
+// ULONGLONG
+// READ_MEMC_REGISTER(
+// ULONG RegisterOffset,
+// )
+//
+// Routine Description:
+//
+// Read a quadword location from LCA MEMC register space.
+//
+// Arguments:
+//
+// RegisterOffset(a0) - Supplies the offset of the memory controller
+// register within memory controller physical space.
+//
+// Return Value:
+//
+// v0 - Return the value read from the controller register.
+//
+//--
+
+ LEAF_ENTRY(READ_MEMC_REGISTER)
+
+ ldiq t0, LCA4_MEMC_BASE_PHYSICAL // get memory cntlr physical address
+
+ ldiq t4, -0x4000 // create superpage mask
+ sll t4, 28, t4 // 0xffff fc00 0000 0000
+
+ bis t0, t4, t0 // get superpage address of mem ctlr
+ bis t0, a0, t0 // add offset of specified register
+
+ ldq v0, (t0) // read the quadword
+ ret zero, (ra) // return
+
+ .end READ_MEMC_REGISTER
+
+
+//
+// Values and structures used to access configuration space.
+//
+
+//
+// Define the QVA for the Configuration Cycle Type register within the
+// IOC.
+//
+
+#define IOC_CONFIG_CYCLE_TYPE_QVA (0xac000001)
+
+//
+// Define the configuration routines stack frame.
+//
+
+ .struct 0
+CfgRa: .space 8 // return address
+CfgA0: .space 8 // saved ConfigurationAddress
+CfgA1: .space 8 // saved ConfigurationData
+ .space 8 // padding for 16 byte alignment
+CfgFrameLength:
+
+
+//++
+//
+// ULONG
+// READ_CONFIG_UCHAR(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read an unsigned byte from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of configuration to be read.
+//
+// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - This routine follows a protocol for reading from PCI configuration
+// space that allows the HAL or firmware to fixup and continue
+// execution if no device exists at the configuration target address.
+// The protocol requires 2 rules:
+// (1) The configuration space load must use a destination register
+// of v0
+// (2) The instruction immediately following the configuration space
+// load must use v0 as an operand (it must consume the value
+// returned by the load)
+//
+//--
+
+ NESTED_ENTRY( READ_CONFIG_UCHAR, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Write the cycle type into the ConfigurationCycleType register in
+// the IOC.
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+
+ ldil a0, IOC_CONFIG_CYCLE_TYPE_QVA // address of cycle type register
+ bsr ra, WRITE_IOC_REGISTER // update the configuration cycle type
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 0x3, t3 // capture byte lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_BYTE_LEN, t0 // or in the byte enables
+
+ ldl v0, (t0) // read the longword
+ extbl v0, t3, v0 // return the byte from the right lane
+ // also, consume loaded value to cause
+ // a pipeline stall
+2: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end READ_CONFIG_UCHAR
+
+//++
+//
+// VOID
+// WRITE_CONFIG_UCHAR(
+// ULONG ConfigurationAddress,
+// UCHAR ConfigurationData,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Write an unsigned byte to PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA to write.
+//
+// ConfigurationData(a1) - Supplies the data to be written.
+//
+// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// None.
+//
+// N.B. - The configuration address must exist within the address space
+// allocated to an existing PCI device. Otherwise, the access
+// below will initiate an unrecoverable machine check.
+//
+//--
+
+ NESTED_ENTRY( WRITE_CONFIG_UCHAR, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Write the cycle type into the ConfigurationCycleType register in
+// the IOC.
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+ stq a1, CfgA1(sp) // save configuration data
+
+ ldil a0, IOC_CONFIG_CYCLE_TYPE_QVA // address of cycle type register
+ bis a2, zero, a1 // set cycle type
+
+ bsr ra, WRITE_IOC_REGISTER // update the configuration cycle type
+
+//
+// Perform the write to configuration space after restoring the
+// configuration space address and data.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+ ldq a1, CfgA1(sp) // restore configuration data
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 0x3, t3 // capture byte lane
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_BYTE_LEN, t0 // or in the byte length indicator
+
+ insbl a1, t3, t4 // put byte in the appropriate lane
+ stl t4, (t0) // write the configuration byte
+ mb // synchronize
+
+2: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end WRITE_CONFIG_UCHAR
+
+//++
+//
+// ULONG
+// READ_CONFIG_USHORT(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read a short from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of quadword to be read.
+//
+// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - This routine follows a protocol for reading from PCI configuration
+// space that allows the HAL or firmware to fixup and continue
+// execution if no device exists at the configuration target address.
+// The protocol requires 2 rules:
+// (1) The configuration space load must use a destination register
+// of v0
+// (2) The instruction immediately following the configuration space
+// load must use v0 as an operand (it must consume the value
+// returned by the load)
+//--
+
+ NESTED_ENTRY( READ_CONFIG_USHORT, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Write the cycle type into the ConfigurationCycleType register in
+// the IOC.
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+
+ ldil a0, IOC_CONFIG_CYCLE_TYPE_QVA // address of cycle type register
+ bsr ra, WRITE_IOC_REGISTER // update the configuration cycle type
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 0x3, t3 // capture word offset
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_WORD_LEN, t0 // or in the byte enables
+
+ ldl v0, (t0) // read the longword
+ extwl v0, t3, v0 // return word from requested lanes
+ // also, consume loaded value to cause
+ // a pipeline stall
+2: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end READ_CONFIG_USHORT
+
+//++
+//
+// VOID
+// WRITE_CONFIG_USHORT(
+// ULONG ConfigurationAddress,
+// USHORT ConfigurationData,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Write a short to PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA to write.
+//
+// ConfigurationData(a1) - Supplies the data to be written.
+//
+// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - The configuration address must exist within the address space
+// allocated to an existing PCI device. Otherwise, the access
+// below will initiate an unrecoverable machine check.
+//
+//--
+
+ NESTED_ENTRY( WRITE_CONFIG_USHORT, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Write the cycle type into the ConfigurationCycleType register in
+// the IOC.
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+ stq a1, CfgA1(sp) // save configuration data
+
+ ldil a0, IOC_CONFIG_CYCLE_TYPE_QVA // address of cycle type register
+ bis a2, zero, a1 // set configuration cycle type
+
+ bsr ra, WRITE_IOC_REGISTER // update the configuration cycle type
+
+//
+// Perform the write to configuration space after restoring the
+// configuration space address and data.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+ ldq a1, CfgA1(sp) // restore configuration data
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ and a0, 0x3, t3 // capture word offset
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_WORD_LEN, t0 // or in the byte enables
+
+ inswl a1, t3, t4 // put data to appropriate lane
+ stl t4, (t0) // write the longword
+ mb // synchronize
+2: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end WRITE_CONFIG_USHORT
+
+//++
+//
+// ULONG
+// READ_CONFIG_ULONG(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Read a longword from PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA of quadword to be read.
+//
+// ConfigurationCycleType(a1) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - This routine follows a protocol for reading from PCI configuration
+// space that allows the HAL or firmware to fixup and continue
+// execution if no device exists at the configuration target address.
+// The protocol requires 2 rules:
+// (1) The configuration space load must use a destination register
+// of v0
+// (2) The instruction immediately following the configuration space
+// load must use v0 as an operand (it must consume the value
+// returned by the load)
+//--
+
+ NESTED_ENTRY( READ_CONFIG_ULONG, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Write the cycle type into the ConfigurationCycleType register in
+// the IOC.
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+
+ ldil a0, IOC_CONFIG_CYCLE_TYPE_QVA // address of cycle type register
+ bsr ra, WRITE_IOC_REGISTER // update the configuration cycle type
+
+//
+// Perform the read from configuration space after restoring the
+// configuration space address.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE,a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ or t0, t4, t0 // superpage mode
+
+ or t0, IO_LONG_LEN, t0 // or in the byte enables
+
+ ldl v0, (t0) // read the longword
+ bis v0, zero, t1 // consume loaded value to cause
+ // a pipeline stall
+2: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end READ_CONFIG_ULONG
+
+
+//++
+//
+// VOID
+// WRITE_CONFIG_ULONG(
+// ULONG ConfigurationAddress,
+// ULONG ConfigurationData,
+// ULONG ConfigurationCycleType
+// )
+//
+// Routine Description:
+//
+// Write a longword to PCI configuration space.
+//
+// Arguments:
+//
+// ConfigurationAddress(a0) - Supplies the QVA to write.
+//
+// ConfigurationData(a1) - Supplies the data to be written.
+//
+// ConfigurationCycleType(a2) - Supplies the type of the configuration cycle.
+//
+// Return Value:
+//
+// (v0) Returns the value of configuration space at the specified location.
+//
+// N.B. - The configuration address must exist within the address space
+// allocated to an existing PCI device. Otherwise, the access
+// below will initiate an unrecoverable machine check.
+//
+//--
+
+ NESTED_ENTRY( WRITE_CONFIG_ULONG, CfgFrameLength, zero )
+
+ lda sp, -CfgFrameLength(sp) // allocate stack frame
+ stq ra, CfgRa(sp) // save return address
+
+ PROLOGUE_END // end prologue
+
+//
+// Write the cycle type into the ConfigurationCycleType register in
+// the IOC.
+//
+
+ stq a0, CfgA0(sp) // save configuration space address
+ stq a1, CfgA1(sp) // save configuration data
+
+ ldil a0, IOC_CONFIG_CYCLE_TYPE_QVA // address of cycle type register
+ bis a2, zero, a1 // set configuration cycle type
+
+ bsr ra, WRITE_IOC_REGISTER // update the configuration cycle type
+
+//
+// Perform the write to configuration space after restoring the
+// configuration space address and data.
+//
+
+ ldq a0, CfgA0(sp) // restore configuration space address
+ ldq a1, CfgA1(sp) // restore configuration data
+
+ and a0, QVA_SELECTORS, t1 // get qva selector bits
+ xor t1, QVA_ENABLE, t1 // ok iff QVA_ENABLE set in selectors
+ bne t1, 2f // if ne, iff failed
+
+ zap a0, 0xf0, a0 // clear <63:32>
+ bic a0, QVA_ENABLE, a0 // clear QVA fields so shift is correct
+ sll a0, IO_BIT_SHIFT, t0 //
+ ldiq t4, -0x4000 //
+ sll t4, 28, t4 //
+ bis t0, t4, t0 // superpage mode
+
+ bis t0, IO_LONG_LEN, t0 // or in the byte enables
+
+ stl a1, (t0) // write the longword
+ mb // synchronize
+2: //
+ ldq ra, CfgRa(sp) // restore return address
+ lda sp, CfgFrameLength(sp) // deallocate stack frame
+ ret zero, (ra) // return
+
+ .end WRITE_CONFIG_ULONG
diff --git a/private/ntos/nthals/halalpha/memory.c b/private/ntos/nthals/halalpha/memory.c
new file mode 100644
index 000000000..306b9be61
--- /dev/null
+++ b/private/ntos/nthals/halalpha/memory.c
@@ -0,0 +1,575 @@
+/*++
+
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ memory.c
+
+Abstract:
+
+ Provides routines to allow tha HAL to map physical memory
+
+Author:
+
+ Jeff McLeman (DEC) 11-June-1992
+
+Revision History:
+
+ Joe Notarangelo 20-Oct-1993
+ - Fix bug where physical address was rounded up without referencing
+ AlignmentOffset, resulting in an incorrect physical address
+ - Remove magic numbers
+ - Create a routine to dump all of the descriptors to the debugger
+
+Environment:
+
+ Phase 0 initialization only
+
+--*/
+
+#include "halp.h"
+
+#define __1KB (1024)
+
+MEMORY_ALLOCATION_DESCRIPTOR HalpExtraAllocationDescriptor;
+
+
+
+ULONG
+HalpAllocPhysicalMemory(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN ULONG MaxPhysicalAddress,
+ IN ULONG NoPages,
+ IN BOOLEAN AlignOn64k
+ )
+/*++
+
+Routine Description:
+
+ Carves out N pages of physical memory from the memory descriptor
+ list in the desired location. This function is to be called only
+ during phase zero initialization. (ie, before the kernel's memory
+ management system is running)
+
+Arguments:
+
+ LoaderBlock - Supplies a pointer to the loader parameter block which
+ contains the system memory descriptors.
+
+ MaxPhysicalAddress - Supplies the maximum address below which the memory
+ must be allocated.
+
+ NoPages - Supplies the number of pages to allocate.
+
+ AlignOn64k - Supplies a boolean that specifies if the requested memory
+ allocation must start on a 64K boundary.
+
+Return Value:
+
+ The pyhsical address or NULL if the memory could not be obtained.
+
+--*/
+{
+ ULONG AlignmentMask;
+ ULONG AlignmentOffset;
+ PMEMORY_ALLOCATION_DESCRIPTOR BestFitDescriptor;
+ ULONG BestFitAlignmentOffset;
+ PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+ PLIST_ENTRY NextMd;
+ ULONG MaxPageAddress;
+ ULONG PhysicalAddress;
+
+ MaxPageAddress = MaxPhysicalAddress >> PAGE_SHIFT;
+
+ AlignmentMask = (__64K >> PAGE_SHIFT) - 1;
+
+ BestFitDescriptor = NULL;
+ BestFitAlignmentOffset = AlignmentMask + 1;
+
+ //
+ // Scan the memory allocation descriptors for an eligible descriptor from
+ // which we can allocate the requested block of memory.
+ //
+
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
+ Descriptor = CONTAINING_RECORD(NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ if( AlignOn64k ){
+
+ AlignmentOffset =
+ ((Descriptor->BasePage + AlignmentMask) & ~AlignmentMask) -
+ Descriptor->BasePage;
+
+ } else {
+
+ AlignmentOffset = 0;
+
+ }
+
+ //
+ // Search for a block of memory which is contains a memory chunk
+ // that is greater than size pages, and has a physical address less
+ // than MAXIMUM_PHYSICAL_ADDRESS.
+ //
+
+ if ((Descriptor->MemoryType == LoaderFree ||
+ Descriptor->MemoryType == MemoryFirmwareTemporary) &&
+ (Descriptor->PageCount >= NoPages + AlignmentOffset) &&
+ (Descriptor->BasePage + NoPages + AlignmentOffset <
+ MaxPageAddress) )
+ {
+
+ //
+ // Check for a perfect fit where we need not split the descriptor
+ // because AlignmentOffset == 0. No need to search further if
+ // there is a perfect fit.
+ //
+
+ if( AlignmentOffset == 0 ){
+ BestFitDescriptor = Descriptor;
+ BestFitAlignmentOffset = AlignmentOffset;
+ break;
+ }
+
+ //
+ // If not a perfect fit check for the best fit so far.
+ //
+
+ if( AlignmentOffset < BestFitAlignmentOffset ){
+ BestFitDescriptor = Descriptor;
+ BestFitAlignmentOffset = AlignmentOffset;
+ }
+
+ }
+
+ NextMd = NextMd->Flink;
+ }
+
+ //
+ // Verify that we have found an eligible descriptor.
+ //
+
+ ASSERT( BestFitDescriptor != NULL );
+
+ if( BestFitDescriptor == NULL ){
+ return (ULONG)NULL;
+ }
+
+ //
+ // Compute the physical address of the memory block we have found.
+ //
+
+ PhysicalAddress = (BestFitDescriptor->BasePage + BestFitAlignmentOffset)
+ << PAGE_SHIFT;
+ //
+ // Adjust the memory descriptors to account for the memory we have
+ // allocated.
+ //
+
+ if (BestFitAlignmentOffset == 0) {
+
+ BestFitDescriptor->BasePage += NoPages;
+ BestFitDescriptor->PageCount -= NoPages;
+
+ if (BestFitDescriptor->PageCount == 0) {
+
+ //
+ // The whole block was allocated,
+ // Remove the entry from the list completely.
+ //
+
+ RemoveEntryList(&BestFitDescriptor->ListEntry);
+
+ }
+
+ } else {
+
+ //
+ // The descriptor will be split into 3 pieces, the beginning
+ // segment up to our allocation, our allocation, and the trailing
+ // segment. We have one spare memory descriptor to handle this
+ // case, use it if it is not already used otherwise preserve as
+ // much memory as possible.
+ //
+
+ if( (BestFitDescriptor->PageCount - NoPages - BestFitAlignmentOffset)
+ == 0 ){
+
+ //
+ // The third segment is empty, use the original descriptor to
+ // map the first segment.
+ //
+
+ BestFitDescriptor->PageCount -= NoPages;
+
+ } else {
+
+ if( HalpExtraAllocationDescriptor.PageCount == 0 ){
+
+ //
+ // The extra descriptor can be used to map the third segment.
+ //
+
+ HalpExtraAllocationDescriptor.PageCount =
+ BestFitDescriptor->PageCount - NoPages -
+ BestFitAlignmentOffset;
+
+ HalpExtraAllocationDescriptor.BasePage =
+ BestFitDescriptor->BasePage + NoPages +
+ BestFitAlignmentOffset;
+
+ HalpExtraAllocationDescriptor.MemoryType = MemoryFree;
+
+ InsertTailList(
+ &BestFitDescriptor->ListEntry,
+ &HalpExtraAllocationDescriptor.ListEntry );
+
+ //
+ // Use the original descriptor to map the first segment.
+ //
+
+ BestFitDescriptor->PageCount = BestFitAlignmentOffset;
+
+ } else {
+
+ //
+ // We need to split the original descriptor into 3 segments
+ // but we've already used the spare descriptor. Use the
+ // original descriptor to map the largest segment.
+ //
+
+ ULONG WastedPages;
+
+ if( (BestFitDescriptor->PageCount - BestFitAlignmentOffset -
+ NoPages) > BestFitAlignmentOffset ){
+
+ WastedPages = BestFitAlignmentOffset;
+
+ //
+ // Map the third segment using the original descriptor.
+ //
+
+ BestFitDescriptor->BasePage += BestFitAlignmentOffset +
+ NoPages;
+ BestFitDescriptor->PageCount -= BestFitAlignmentOffset +
+ NoPages;
+
+ } else {
+
+ WastedPages = BestFitDescriptor->PageCount -
+ BestFitAlignmentOffset - NoPages;
+
+ //
+ // Map the first segment using the original descriptor.
+ //
+
+ BestFitDescriptor->PageCount = BestFitAlignmentOffset;
+
+ } //end if( (BestFitDescriptor->PageCount - BestFitAlignm ...
+
+ //
+ // Report that we have had to waste pages.
+ //
+
+ DbgPrint( "HalpAllocPhysicalMemory: wasting %d pages\n",
+ WastedPages );
+
+ } //end if( HalpExtraAllocationDescriptor.PageCount == 0 )
+
+ } //end if( (BestFitDescriptor->PageCount - NoPages - BestFitAlign ...
+
+ } //end if (BestFitAlignmentOffset == 0)
+
+
+ return PhysicalAddress;
+}
+
+ULONGLONG
+HalpGetMemorySize(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+/*++
+
+Routine Description:
+
+ Computes the size of the memory from the descriptor list.
+
+Arguments:
+
+ LoaderBlock - Supplies a pointer to the loader parameter block.
+
+
+Return Value:
+
+ Size of Memory in Bytes.
+
+--*/
+{
+ PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+ PLIST_ENTRY NextMd;
+ ULONG PageCounts = 0;
+
+ //
+ // Scan the memory allocation descriptors and
+ // compute the Total pagecount
+ //
+
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
+
+ Descriptor = CONTAINING_RECORD(NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ //
+ // ignore bad memory descriptors.
+ //
+ if(Descriptor->MemoryType != LoaderBad){
+ PageCounts += Descriptor->PageCount;
+ }
+
+
+ NextMd = NextMd->Flink;
+ }
+
+ return (PageCounts << PAGE_SHIFT) ;
+
+}
+
+TYPE_OF_MEMORY
+HalpGetMemoryType (
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock,
+ IN ULONG PageAddress,
+ OUT PULONG EndPageAddressInDesc
+ )
+
+/*++
+
+Routine Description:
+
+ This routine checks to see how the specified address is mapped.
+
+Arguments:
+
+ LoaderBlock - Supplies a pointer to the loader parameter block.
+
+ PageAddress - The page address of memory to probe.
+
+Return Value:
+
+ The memory type of the specified address, if it is mapped. If the
+ address is not mapped, then LoaderMaximum is returned.
+
+--*/
+
+{
+ PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+ PLIST_ENTRY NextMd;
+ ULONG PageCounts = 0;
+ TYPE_OF_MEMORY MemoryType = LoaderMaximum;
+
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
+
+ Descriptor = CONTAINING_RECORD(NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ if ((PageAddress >= Descriptor->BasePage) &&
+ (PageAddress <
+ Descriptor->BasePage + Descriptor->PageCount)) {
+
+ MemoryType = Descriptor->MemoryType;
+ *EndPageAddressInDesc = Descriptor->BasePage +
+ Descriptor->PageCount - 1;
+ break; // we found the descriptor.
+ }
+
+ NextMd = NextMd->Flink;
+ }
+ return MemoryType;
+}
+
+
+ULONGLONG
+HalpGetContiguousMemorySize(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+/*++
+
+Routine Description:
+
+ Computes the size of initial contiguous memory from the
+ descriptor list. Contiguous memory means, that there is
+ no hole or Bad memory in this range.
+
+Arguments:
+
+ LoaderBlock - Supplies a pointer to the loader parameter block.
+
+
+Return Value:
+
+ Size of Memory in Bytes.
+
+--*/
+{
+ PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+ PLIST_ENTRY NextMd;
+ ULONG PageCounts = 0;
+ TYPE_OF_MEMORY MemoryType;
+ ULONG EndPageAddressInDesc = 0;
+
+ //
+ // Start from Page Address 0 and go until we hit a page
+ // with no descriptor or Bad Descriptor.
+ //
+
+ MemoryType = HalpGetMemoryType(LoaderBlock,
+ PageCounts,
+ &EndPageAddressInDesc
+ );
+ while(MemoryType != LoaderMaximum && MemoryType != LoaderBad){
+ PageCounts = EndPageAddressInDesc + 1;
+ MemoryType = HalpGetMemoryType(LoaderBlock,
+ PageCounts,
+ &EndPageAddressInDesc
+ );
+ }
+
+ return (PageCounts << PAGE_SHIFT) ;
+
+}
+
+
+#if HALDBG
+
+
+VOID
+HalpDumpMemoryDescriptors(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+/*++
+
+Routine Description:
+
+ Print the contents of the memory descriptors built by the
+ firmware and OS loader and passed through to the kernel.
+ This routine is intended as a sanity check that the descriptors
+ have been prepared properly and that no memory has been wasted.
+
+Arguments:
+
+ LoaderBlock - Supplies a pointer to the loader parameter block.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+ PLIST_ENTRY NextMd;
+ ULONG PageCounts[LoaderMaximum];
+ PCHAR MemoryTypeStrings[] = {
+ "ExceptionBlock",
+ "SystemBlock",
+ "Free",
+ "Bad",
+ "LoadedProgram",
+ "FirmwareTemporary",
+ "FirmwarePermanent",
+ "OsloaderHeap",
+ "OsloaderStack",
+ "SystemCode",
+ "HalCode",
+ "BootDriver",
+ "ConsoleInDriver",
+ "ConsoleOutDriver",
+ "StartupDpcStack",
+ "StartupKernelStack",
+ "StartupPanicStack",
+ "StartupPcrPage",
+ "StartupPdrPage",
+ "RegistryData",
+ "MemoryData",
+ "NlsData",
+ "SpecialMemory"
+ };
+ ULONG i;
+
+ //
+ // Clear the summary information structure.
+ //
+
+ RtlZeroMemory( PageCounts, sizeof(ULONG) * LoaderMaximum );
+
+ //
+ // Scan the memory allocation descriptors print each descriptor and
+ // collect summary information.
+ //
+
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+ while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
+
+ Descriptor = CONTAINING_RECORD(NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ if( (Descriptor->MemoryType >= LoaderExceptionBlock) &&
+ (Descriptor->MemoryType < LoaderMaximum) )
+ {
+
+ PageCounts[Descriptor->MemoryType] += Descriptor->PageCount;
+ DbgPrint( "%08x: %08x Type = %s\n",
+ (Descriptor->BasePage << PAGE_SHIFT) | KSEG0_BASE,
+ ( ( (Descriptor->BasePage + Descriptor->PageCount)
+ << PAGE_SHIFT) - 1) | KSEG0_BASE,
+ MemoryTypeStrings[Descriptor->MemoryType] );
+
+
+ } else {
+
+ DbgPrint( "%08x: %08x Unrecognized Memory Type = %x\n",
+ (Descriptor->BasePage << PAGE_SHIFT) | KSEG0_BASE,
+ ( ( (Descriptor->BasePage + Descriptor->PageCount)
+ << PAGE_SHIFT) - 1) | KSEG0_BASE,
+ Descriptor->MemoryType );
+
+ DbgPrint( "Unrecognized memory type\n" );
+
+ }
+
+ NextMd = NextMd->Flink;
+ }
+
+
+ //
+ // Print the summary information.
+ //
+
+ for( i=LoaderExceptionBlock; i<LoaderMaximum; i++ ){
+
+ //
+ // Only print those memory types that have non-zero allocations.
+ //
+
+ if( PageCounts[i] != 0 ){
+
+ DbgPrint( "%8dK %s\n",
+ (PageCounts[i] << PAGE_SHIFT) / __1K,
+ MemoryTypeStrings[i] );
+
+ }
+
+ }
+
+ return;
+}
+
+#endif //HALDBG
diff --git a/private/ntos/nthals/halalpha/nvenv.c b/private/ntos/nthals/halalpha/nvenv.c
new file mode 100644
index 000000000..45c4a6f70
--- /dev/null
+++ b/private/ntos/nthals/halalpha/nvenv.c
@@ -0,0 +1,533 @@
+#if defined(TAGGED_NVRAM)
+
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992, 1993, 1994 Digital Equipment Corporation
+
+Module Name:
+
+ nvenv.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.
+
+Author:
+
+ David M. Robinson (davidro) 13-June-1991
+
+
+Revision History:
+
+ Dave Richards 94.11.03
+
+ Added support for the tagged NVRAM layout/API.
+
+ James Livingston 94.05.17
+
+ Fix a coding error that caused NVRAM to get trashed in the attempt
+ to update a nearly full environment variable space.
+
+ Steve Jenness 93.12.20
+
+ The firmware still requires the naked checksum set and check
+ routines. Add them back in under the AXP_FIRMWARE conditional
+ until the jxenvir.c in the firmware and the environ.c files
+ are rationalized.
+
+ Steve Jenness. 93.12.17
+
+ Reduce the reads and writes to the NVRAM part. Some parts are
+ slow to access (especially on writes). Do NVRAM access only when
+ really necessary. Remove use of HalpCopyNVRamBuffer because it is
+ too difficult to make generically fast (put more intelligence
+ in higher code instead).
+
+ Steve Brooks. 6-Oct 1993 remove all platform and device specific references
+
+ These routines have been restructured to be platform and device
+ independant. All calls access the NVRAM via the calls
+ HalpReadNVRamBuffer, HalpWriteNVRamBuffer, and HalpCopyNVRamBuffer
+
+ Jeff McLeman (DEC) 31-Jul-1992 modify for Jensen
+
+--*/
+
+#include "arccodes.h"
+#include "halp.h"
+#include "nvram.h"
+
+//
+// Routine prototypes.
+//
+
+ARC_STATUS
+HalpFindEnvironmentVariable (
+ IN PCHAR Variable,
+ OUT PULONG VariableIndex,
+ OUT PULONG ValueIndex
+ );
+
+ARC_STATUS
+HalGetEnvironmentVariable (
+ IN PCHAR Variable,
+ IN USHORT length,
+ OUT PCHAR Buffer
+ );
+
+ARC_STATUS
+HalSetEnvironmentVariable (
+ IN PCHAR Variable,
+ IN PCHAR Value
+ );
+
+#ifdef AXP_FIRMWARE
+
+#pragma alloc_text(DISTEXT, HalpFindEnvironmentVariable )
+#pragma alloc_text(DISTEXT, HalGetEnvironmentVariable )
+#pragma alloc_text(DISTEXT, HalSetEnvironmentVariable )
+
+#endif // AXP_FIRMWARE
+
+ARC_STATUS
+HalpFindEnvironmentVariable (
+ IN PCHAR Variable,
+ OUT PULONG VariableIndex,
+ OUT PULONG ValueIndex
+ )
+
+/*++
+
+Routine Description:
+
+ This routine searches (not case sensitive) the supplied NVRAM image
+ for the given Variable.
+
+Arguments:
+
+ Variable - Supplies a zero terminated string containing an environment
+ variable.
+ VariableIndex - Returned byte offset into Environment of the
+ Variable if found.
+ ValueIndex - Returned byte offset into Environment of the
+ value of the Variable if found.
+
+Return Value:
+
+ ESUCCESS - Variable found and indicies returned.
+ ENOENT - Variable not found.
+
+--*/
+
+{
+ ULONG EnvironmentOffset;
+ ULONG EnvironmentLength;
+ PUCHAR String;
+ UCHAR Char;
+ ULONG Index;
+
+ //
+ // If Variable is null, return immediately.
+ //
+
+ if (*Variable == 0) {
+ return ENOENT;
+ }
+
+ //
+ // Get the offset and length of the environment in NVRAM.
+ //
+
+ EnvironmentOffset = HalpGetNVRamEnvironmentOffset();
+ EnvironmentLength = HalpGetNVRamEnvironmentLength();
+
+ Index = 0;
+
+ while (TRUE) {
+
+ //
+ // Set string to beginning of Variable.
+ //
+
+ String = Variable;
+ *VariableIndex = EnvironmentOffset + Index;
+
+ //
+ // Search until the end of NVRAM.
+ //
+
+ while ( Index < EnvironmentLength ) {
+
+ //
+ // Convert to uppercase and break if mismatch.
+ //
+
+ Char = HalpGetNVRamUchar(EnvironmentOffset + Index);
+
+ if ( Char != ((*String >= 'a') && (*String <= 'z') ?
+ (*String - 'a' + 'A') : *String) ) {
+ break;
+ }
+
+ String++;
+ Index++;
+ }
+
+ if ( Index == EnvironmentLength )
+ return ENOENT;
+
+ //
+ // Check to see if we're at the end of the string and the variable,
+ // which means a match.
+ //
+
+ Char = HalpGetNVRamUchar(EnvironmentOffset + Index);
+ if ((*String == 0) && (Char == '=')) {
+ *ValueIndex = EnvironmentOffset + ++Index;
+ return ESUCCESS;
+ }
+
+ //
+ // Move index to the start of the next variable.
+ //
+
+ do {
+ Char = HalpGetNVRamUchar(EnvironmentOffset + Index++);
+
+ if (Index >= EnvironmentLength) {
+ return ENOENT;
+ }
+
+ } while (Char != 0);
+
+ }
+}
+
+ARC_STATUS
+HalGetEnvironmentVariable (
+ IN PCHAR Variable,
+ IN USHORT length,
+ OUT PCHAR Buffer
+ )
+
+/*++
+
+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.
+ Length - Supplies the length of the value buffer in bytes
+
+ Buffer - Supplies a pointer to a buffer that will recieve the
+ environment variable.
+
+Return Value:
+
+ ESUCCESS - Buffer contains the zero terminated string value of Variable.
+ ENOENT - The variable doesn't exist in the environment.
+ ENOMEM - The variable exists, but the value is longer than Length.
+
+--*/
+
+{
+ ULONG NvChars;
+ ULONG VariableIndex;
+ ULONG ValueIndex;
+ ULONG Index;
+ ARC_STATUS Status;
+
+ //
+ // If checksum is wrong, or the variable can't be found, return NULL.
+ //
+
+ if ((!HalpIsNVRamRegion0Valid()) ||
+ (HalpFindEnvironmentVariable(Variable,
+ &VariableIndex,
+ &ValueIndex) != ESUCCESS)) {
+ Status = ENOENT;
+ } else {
+
+ //
+ // Copy value to an output string, break on zero terminator
+ // or string max.
+ //
+
+ NvChars = ValueIndex;
+ for ( Index = 0 ; Index < length ; Index += 1 ) {
+ if ( (*Buffer++ = HalpGetNVRamUchar(NvChars++)) == 0 ) {
+ break;
+ }
+ }
+
+ if (Index == length) {
+ Status = ENOMEM;
+ } else {
+ Status = ESUCCESS;
+ }
+ }
+
+ return Status;
+}
+
+
+ARC_STATUS
+HalSetEnvironmentVariable (
+ 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:
+
+ ESUCCESS - The set completed successfully
+ ENOSPC - No space in NVRAM for set operation.
+ EIO - Invalid Checksum.
+
+--*/
+
+{
+ ULONG EnvironmentOffset;
+ ULONG EnvironmentLength;
+ ULONG VariableIndex;
+ ULONG ValueIndex;
+ ULONG TopOfEnvironment;
+ PCHAR String;
+ ULONG NvChars;
+ LONG Count;
+ CHAR Char;
+
+ //
+ // If checksum is wrong, return EIO;
+ //
+
+ if (!HalpIsNVRamRegion0Valid()) {
+ return EIO;
+ }
+
+ //
+ // Get the offset and length of the environment in NVRAM.
+ //
+
+ EnvironmentOffset = HalpGetNVRamEnvironmentOffset();
+ EnvironmentLength = HalpGetNVRamEnvironmentLength();
+
+//
+//smjfix - examine the boundary condition where the environment space
+// is exactly filled.
+
+ //
+ // Determine the top of the environment space by looking for the first
+ // non-null character from the top.
+ //
+
+ TopOfEnvironment = EnvironmentOffset + EnvironmentLength - 1;
+
+ do {
+ Char = HalpGetNVRamUchar(TopOfEnvironment);
+
+ } while ( Char == 0 && (--TopOfEnvironment > EnvironmentOffset) );
+
+ //
+ // Adjust TopOfEnvironment to the first new character, unless environment
+ // space is empty, or the environment is exactly full. In the latter
+ // case, the new value MUST fit into the space taken by the old.
+ //
+
+ if (TopOfEnvironment != EnvironmentOffset &&
+ TopOfEnvironment < EnvironmentOffset + EnvironmentLength - 2) {
+ TopOfEnvironment += 2;
+ }
+
+ //
+ // Handle the case where the content of the NVRAM has been corrupted
+ // such that the last character in the environment is non-zero.
+ //
+
+ Count = (EnvironmentOffset + EnvironmentLength - 1) - TopOfEnvironment;
+ if (Count < 0) {
+ return ENOSPC;
+ }
+
+
+ //
+ // Check to see if the variable already has a value.
+ //
+
+ if (HalpFindEnvironmentVariable(Variable, &VariableIndex, &ValueIndex)
+ == ESUCCESS) {
+ ULONG SizeOfValue = strlen(Value);
+
+ if (SizeOfValue == HalpGetNVRamStringLength(ValueIndex)) {
+
+ //
+ // Overwrite the current variable in place.
+ //
+
+ HalpMoveMemoryToNVRam(ValueIndex, Value, SizeOfValue);
+
+ //
+ // Suppress the append of the variable to the end of the
+ // environment variable data.
+ //
+
+ *Value = 0;
+
+ } else {
+
+ //
+ // Count free space, starting with the free area at the top and
+ // adding the old variable value.
+ //
+
+ for ( NvChars = ValueIndex;
+ NvChars <= TopOfEnvironment;
+ NvChars++ ) {
+
+ Char = HalpGetNVRamUchar(NvChars);
+ if ( Char == 0 )
+ break;
+ 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.
+ //
+
+ do {
+ Char = HalpGetNVRamUchar(ValueIndex++);
+ } while( Char != 0 );
+
+ Count = TopOfEnvironment - ValueIndex;
+
+ HalpMoveNVRamToNVRam(VariableIndex, ValueIndex, Count);
+
+ //
+ // Adjust new top of environment.
+ //
+
+ TopOfEnvironment = VariableIndex+Count;
+
+ //
+ // Zero to the end.
+ //
+
+ Count = EnvironmentOffset + EnvironmentLength - TopOfEnvironment;
+ Char = 0;
+ while ( Count -- ) {
+ HalpSetNVRamUchar(TopOfEnvironment + Count, Char);
+ }
+ }
+
+ } else {
+
+ //
+ // Variable is new.
+ //
+
+ //
+ // Determine if free area is large enough to handle new value, if not
+ // return error.
+ //
+
+ //
+ // From the length of free space subtract new variable's length,
+ // Value's length and 2 chars, one for the '=' sign and one of the
+ // null terminator.
+ //
+
+ Count -= ( strlen(Variable) + strlen(Value) + 2 );
+
+ //
+ // Check if there is space to fit the new variable.
+ //
+
+ if (Count < 0) {
+ return ENOSPC;
+ }
+
+ }
+
+ //
+ // If Value is not zero, append the new variable and value.
+ //
+
+ if (*Value != 0) {
+
+ //
+ // Write new variable, converting to upper case.
+ //
+ while ( *Variable != 0 ) {
+
+ Char = ((*Variable >= 'a') && (*Variable <= 'z') ?
+ (*Variable - 'a' + 'A') : *Variable);
+
+ HalpSetNVRamUchar(TopOfEnvironment, Char);
+
+ Variable ++;
+ TopOfEnvironment ++;
+ }
+
+ //
+ // Write equal sign.
+ //
+
+ Char = '=';
+ HalpSetNVRamUchar(TopOfEnvironment++, Char);
+
+ //
+ // Write new value.
+ //
+
+ for ( Count = 0; Value[Count] != 0; Count ++ )
+ ;
+
+ HalpMoveMemoryToNVRam(TopOfEnvironment, Value, Count);
+
+ }
+
+ //
+ // Write the environment variables out to NVRAM and checksum it.
+ //
+
+ if (HalpSynchronizeNVRamRegion0(TRUE)) {
+ return ESUCCESS;
+ } else {
+ return EIO;
+ }
+}
+
+#endif // TAGGED_NVRAM
diff --git a/private/ntos/nthals/halalpha/nvram.c b/private/ntos/nthals/halalpha/nvram.c
new file mode 100644
index 000000000..7bb392148
--- /dev/null
+++ b/private/ntos/nthals/halalpha/nvram.c
@@ -0,0 +1,1452 @@
+/*++
+
+Copyright (c) 1994, 1995 Digital Equipment Corporation
+
+Module Name:
+
+ nvram.c
+
+Abstract:
+
+ This module implements the new non-volatile RAM API. The new API
+ supports a cache interface and is layered on top of the old
+ Halp*NVRamBuffer() abstraction.
+
+Author:
+
+ Dave Richards 12-Jan-1995
+
+Environment:
+
+ Executes in kernel mode.
+
+Revision History:
+
+--*/
+
+#include "arccodes.h"
+#include "halp.h"
+#include "nvram.h"
+
+//
+// Global data structures.
+//
+
+BOOLEAN HalpNVRamCacheIsValid = FALSE;
+BOOLEAN HalpNVRamRegion0IsValid;
+BOOLEAN HalpNVRamRegion1IsValid;
+UCHAR HalpNVRamCache[NVR_LENGTH];
+BOOLEAN HalpNVRamCacheIsDirty;
+ULONG HalpNVRamCacheDirtyLo = NVR_LENGTH - 1;
+ULONG HalpNVRamCacheDirtyHi = 0;
+
+BOOLEAN
+HalpIsNVRamCacheValid(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function fills the NVRAM cache (if the current contents are
+ not valid).
+
+ This function should not be called outside this module.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A boolean value indicating whether the cache represents the contents
+ of NVRAM.
+
+--*/
+{
+ ARC_STATUS Status;
+
+ //
+ // If the NVRAM cache is valid, return success.
+ //
+
+ if (HalpNVRamCacheIsValid) {
+ return TRUE;
+ }
+
+ //
+ // Read the NVRAM contents into the cache.
+ //
+
+ Status = HalpReadNVRamBuffer(
+ HalpNVRamCache,
+ HalpCMOSRamBase,
+ NVR_LENGTH
+ );
+
+ //
+ // If we were unable to fill the cache, return failure.
+ //
+
+ if (Status != ESUCCESS) {
+ return FALSE;
+ }
+
+ //
+ // The cache is valid.
+ //
+
+ HalpNVRamCacheIsValid = TRUE;
+
+ //
+ // The cache is clean.
+ //
+
+ HalpNVRamCacheIsDirty = FALSE;
+ HalpNVRamCacheDirtyLo = NVR_LENGTH - 1;
+ HalpNVRamCacheDirtyHi = 0;
+
+ //
+ // The validity of regions 0 and 1 is not known.
+ //
+
+ HalpNVRamRegion0IsValid = FALSE;
+ HalpNVRamRegion1IsValid = FALSE;
+
+ //
+ // Return success.
+ //
+
+ return TRUE;
+}
+
+BOOLEAN
+HalpSynchronizeNVRamCache(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function flushes the cache to NVRAM.
+
+ This function should not be called outside this module.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A boolean value indicating whether the contents of the NVRAM cache
+ were written to NVRAM.
+
+--*/
+{
+ ULONG Lo;
+ ULONG Hi;
+ ARC_STATUS Status;
+
+ //
+ // If the cache is clean, return success.
+ //
+
+ if (!HalpNVRamCacheIsDirty) {
+ return TRUE;
+ }
+
+ //
+ // Write the dirty portion of the cache back to NVRAM.
+ //
+
+ Lo = HalpNVRamCacheDirtyLo;
+ Hi = HalpNVRamCacheDirtyHi;
+
+ Status = HalpWriteNVRamBuffer(
+ (UCHAR *)HalpCMOSRamBase + Lo,
+ &HalpNVRamCache[Lo],
+ Hi - Lo + 1
+ );
+
+ //
+ // If we were unable to flush the cache, return failure.
+ //
+
+ if (Status != ESUCCESS) {
+
+ //
+ // The cache and NVRAM are no longer synchronized!
+ //
+
+ HalpNVRamCacheIsValid = FALSE;
+
+ return FALSE;
+ }
+
+ //
+ // The cache is valid.
+ //
+
+ HalpNVRamCacheIsValid = TRUE;
+
+ //
+ // The cache is clean.
+ //
+
+ HalpNVRamCacheIsDirty = FALSE;
+ HalpNVRamCacheDirtyLo = NVR_LENGTH - 1;
+ HalpNVRamCacheDirtyHi = 0;
+
+ //
+ // Return success.
+ //
+
+ return TRUE;
+}
+
+VOID
+HalpMarkNVRamCacheDirty(
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function marks the NVRAM cache region between Offset and
+ Offset + Length - 1 as dirty.
+
+ This function should not be called outside this module.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Lo;
+ ULONG Hi;
+
+ //
+ // Compute the new lower and upper bounds.
+ //
+
+ Lo = Offset;
+ Hi = Offset + Length - 1;
+
+ if (Lo < HalpNVRamCacheDirtyLo) {
+ HalpNVRamCacheDirtyLo = Lo;
+ }
+
+ if (Hi > HalpNVRamCacheDirtyHi) {
+ HalpNVRamCacheDirtyHi = Hi;
+ }
+
+ //
+ // The cache is dirty.
+ //
+
+ HalpNVRamCacheIsDirty = TRUE;
+}
+
+UCHAR
+HalpGetNVRamUchar(
+ IN ULONG Offset
+ )
+/*++
+
+Routine Description:
+
+ This function reads a byte from the NVRAM cache.
+
+Arguments:
+
+ The offset in NVRAM.
+
+Return Value:
+
+ The byte read from the NVRAM cache.
+
+--*/
+{
+ //
+ // Read a byte.
+ //
+
+ return HalpNVRamCache[Offset];
+}
+
+VOID
+HalpSetNVRamUchar(
+ IN ULONG Offset,
+ IN UCHAR Data
+ )
+/*++
+
+Routine Description:
+
+ This function writes a byte to the NVRAM cache.
+
+Arguments:
+
+ Offset - The offset in NVRAM.
+
+ Data - The byte written.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Write a byte.
+ //
+
+ HalpNVRamCache[Offset] = Data;
+
+ //
+ // Mark the cache as dirty.
+ //
+
+ HalpMarkNVRamCacheDirty(Offset, sizeof (UCHAR));
+}
+
+USHORT
+HalpGetNVRamUshort(
+ IN ULONG Offset
+ )
+/*++
+
+Routine Description:
+
+ This function reads a word from the NVRAM cache.
+
+Arguments:
+
+ The offset in NVRAM.
+
+Return Value:
+
+ The word read from the NVRAM cache.
+
+--*/
+{
+ USHORT Data;
+
+ //
+ // Read a short.
+ //
+
+ RtlMoveMemory(&Data, &HalpNVRamCache[Offset], sizeof (USHORT));
+
+ return Data;
+}
+
+VOID
+HalpSetNVRamUshort(
+ IN ULONG Offset,
+ IN USHORT Data
+ )
+/*++
+
+Routine Description:
+
+ This function writes a word to the NVRAM cache.
+
+Arguments:
+
+ Offset - The offset in NVRAM.
+
+ Data - The word written.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Write a short.
+ //
+
+ RtlMoveMemory(&HalpNVRamCache[Offset], &Data, sizeof (USHORT));
+
+ //
+ // Mark the cache as dirty.
+ //
+
+ HalpMarkNVRamCacheDirty(Offset, sizeof (USHORT));
+}
+
+ULONG
+HalpGetNVRamUlong(
+ IN ULONG Offset
+ )
+/*++
+
+Routine Description:
+
+ This function reads a longword from the NVRAM cache.
+
+Arguments:
+
+ The offset in NVRAM.
+
+Return Value:
+
+ The longword read from the NVRAM cache.
+
+--*/
+{
+ ULONG Data;
+
+ //
+ // Read a long.
+ //
+
+ RtlMoveMemory(&Data, &HalpNVRamCache[Offset], sizeof (ULONG));
+
+ return Data;
+}
+
+VOID
+HalpSetNVRamUlong(
+ IN ULONG Offset,
+ IN ULONG Data
+ )
+/*++
+
+Routine Description:
+
+ This function writes a longword to the NVRAM cache.
+
+Arguments:
+
+ Offset - The offset in NVRAM.
+
+ Data - The longword written.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Write a long.
+ //
+
+ RtlMoveMemory(&HalpNVRamCache[Offset], &Data, sizeof (ULONG));
+
+ //
+ // Mark the cache as dirty.
+ //
+
+ HalpMarkNVRamCacheDirty(Offset, sizeof (ULONG));
+}
+
+VOID
+HalpMoveMemoryToNVRam(
+ IN ULONG Offset,
+ IN PVOID Data,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function copies a region of memory to the NVRAM cache.
+
+Arguments:
+
+ Offset - The offset in NVRAM (destination).
+
+ Data - A memory pointer (source).
+
+ Length - The length of the region to copy.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Move memory to the NVRAM cache.
+ //
+
+ RtlMoveMemory(&HalpNVRamCache[Offset], Data, Length);
+
+ //
+ // Mark the cache as dirty.
+ //
+
+ HalpMarkNVRamCacheDirty(Offset, Length);
+}
+
+VOID
+HalpMoveNVRamToMemory(
+ IN PVOID Data,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function copies a portion of the NVRAM cache to memory.
+
+Arguments:
+
+ Data - A memory pointer (destination).
+
+ Offset - The offset in NVRAM (source).
+
+ Length - The length of the region to copy.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Move memory from the NVRAM cache.
+ //
+
+ RtlMoveMemory(Data, &HalpNVRamCache[Offset], Length);
+}
+
+VOID
+HalpMoveNVRamToNVRam(
+ IN ULONG Destination,
+ IN ULONG Source,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function copies a one region of the NVRAM cache to another.
+
+Arguments:
+
+ Destination - An offset in NVRAM.
+
+ Source - An offset in NVRAM.
+
+ Length - The length of the region to copy.
+
+Return Value:
+
+--*/
+{
+ //
+ // Move memory within the NVRAM cache.
+ //
+
+ RtlMoveMemory(
+ &HalpNVRamCache[Destination],
+ &HalpNVRamCache[Source],
+ Length
+ );
+
+ //
+ // Mark the cache as dirty.
+ //
+
+ HalpMarkNVRamCacheDirty(Destination, Length);
+}
+
+ULONG
+HalpGetNVRamStringLength(
+ IN ULONG Offset
+ )
+/*++
+
+Routine Description:
+
+ This function returns the length of a '\0'-terminated string in
+ the NVRAM cache.
+
+Arguments:
+
+ Offset - A pointer to the beginning of the string in NVRAM.
+
+Return Value:
+
+ An integer value representing the length of the string.
+
+--*/
+{
+ //
+ // Return the length of a string in the NVRAM cache.
+ //
+
+ return strlen(&HalpNVRamCache[Offset]);
+}
+
+VOID
+HalpMoveMemoryStringToNVRam(
+ IN ULONG Offset,
+ IN PCHAR Data
+ )
+/*++
+
+Routine Description:
+
+ This function copies a string to the NVRAM cache.
+
+Arguments:
+
+ Offset - The offset in NVRAM.
+
+ Data - A pointer to the beginning of the string in memory.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Length;
+
+ //
+ // Compute the length of the string.
+ //
+
+ Length = strlen(Data);
+
+ //
+ // Move string to NVRAM.
+ //
+
+ HalpMoveMemoryToNVRam(Offset, Data, Length + 1);
+}
+
+VOID
+HalpMoveNVRamStringToMemory(
+ IN PUCHAR Data,
+ IN ULONG Offset
+ )
+/*++
+
+Routine Description:
+
+ This function copies a string from the NVRAM cache to memory.
+
+Arguments:
+
+ Data - A pointer in memory.
+
+ Offset - An offset in NVRAM to the string to copy.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Length;
+
+ //
+ // Compute the length of the string.
+ //
+
+ Length = HalpGetNVRamStringLength(Offset);
+
+ //
+ // Move string to memory.
+ //
+
+ HalpMoveNVRamToMemory(Data, Offset, Length + 1);
+}
+
+VOID
+HalpZeroNVRam(
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function zeroes the contents of a region in the NVRAM cache.
+
+Arguments:
+
+ Offset - The offset in NVRAM of the region to zero.
+
+ Length - The length of the region to zero.
+
+Return Value:
+
+--*/
+{
+ //
+ // Zero the NVRAM cache.
+ //
+
+ RtlZeroMemory(&HalpNVRamCache[Offset], Length);
+
+ //
+ // Mark the cache as dirty.
+ //
+
+ HalpMarkNVRamCacheDirty(Offset, Length);
+}
+
+ULONG
+HalpComputeNVRamChecksum(
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ This function computes the checksum for a region in the NVRAM cache.
+
+Arguments:
+
+ Offset - An offset in NVRAM.
+
+ Length - The length of the region to checksum.
+
+Return Value:
+
+ The 32-bit checksum of the region.
+
+--*/
+{
+ ULONG Checksum;
+ ULONG Index;
+
+ //
+ // Compute the checksum.
+ //
+
+ Checksum = 0;
+
+ for (Index = 0; Index < Length; Index++) {
+ Checksum = (Checksum << 1) + HalpGetNVRamUchar(Offset++) +
+ (Checksum >> 31 & 0x1);
+ }
+
+ return ~Checksum;
+}
+
+BOOLEAN
+HalpIsNVRamRegion0Valid(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function fills the NVRAM cache (if necessary) and ascertains
+ whether the contents of region 0 of the NVRAM are valid. It verifies
+ that the signature, version and checksum are valid.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A boolean value indicating whether the contents of the region are valid.
+
+--*/
+{
+ ULONG Signature;
+ UCHAR Version;
+ ULONG Checksum1;
+ ULONG Checksum2;
+
+ //
+ // If the contents of the NVRAM cache are invalid, return failure.
+ //
+
+ if (!HalpIsNVRamCacheValid()) {
+ return FALSE;
+ }
+
+ //
+ // If region 0 is valid, return success.
+ //
+
+ if (HalpNVRamRegion0IsValid) {
+ return TRUE;
+ }
+
+ //
+ // If the signature is invalid, return failure.
+ //
+
+ Signature = HalpGetNVRamUlong(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0, Signature)
+ );
+
+ if (Signature != NVR_REGION0_SIGNATURE) {
+ return FALSE;
+ }
+
+ //
+ // If the version is invalid, return failure.
+ //
+
+ Version = HalpGetNVRamUchar(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0, Version)
+ );
+
+ if (Version == 0) {
+ return FALSE;
+ }
+
+ //
+ // If the checksum is invalid, return failure.
+ //
+
+ Checksum1 = HalpComputeNVRamChecksum(
+ NVR_REGION0_OFFSET,
+ FIELD_OFFSET(NVR_REGION0, Checksum)
+ );
+
+ Checksum2 = HalpGetNVRamUlong(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0, Checksum)
+ );
+
+ if (Checksum1 != Checksum2) {
+ return FALSE;
+ }
+
+ //
+ // Region 0 is valid.
+ //
+
+ HalpNVRamRegion0IsValid = TRUE;
+
+ //
+ // Return success.
+ //
+
+ return TRUE;
+}
+
+BOOLEAN
+HalpSynchronizeNVRamRegion0(
+ IN BOOLEAN RecomputeChecksum
+ )
+/*++
+
+Routine Description:
+
+ This function writes the contents of the NVRAM cache region 0
+ back to NVRAM and optionally updates the checksum field.
+
+Arguments:
+
+ RecomputeChecksum - Update the checksum?
+
+Return Value:
+
+ A boolean value indicating whether the NVRAM was correctly updated.
+
+--*/
+{
+ ULONG Checksum;
+
+ //
+ // If we are unable to synchronize the NVRAM cache, return failure.
+ //
+
+ if (!HalpSynchronizeNVRamCache()) {
+ return FALSE;
+ }
+
+ //
+ // If we do not need to re-compute the checksum, return success.
+ //
+
+ if (!RecomputeChecksum) {
+ return TRUE;
+ }
+
+ //
+ // Re-compute the checksum and store it in NVRAM.
+ //
+
+ Checksum = HalpComputeNVRamChecksum(
+ NVR_REGION0_OFFSET,
+ FIELD_OFFSET(NVR_REGION0, Checksum)
+ );
+
+ HalpSetNVRamUlong(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0, Checksum),
+ Checksum
+ );
+
+ //
+ // Synchronize the NVRAM cache.
+ //
+
+ return HalpSynchronizeNVRamCache();
+}
+
+BOOLEAN
+HalpInitializeNVRamRegion0(
+ BOOLEAN Synchronize
+ )
+/*++
+
+Routine Description:
+
+ This function initializes the contents of region 0.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A boolean value indicating whether the NVRAM was properly initialized.
+
+--*/
+{
+ ULONG Checksum;
+
+ //
+ // Zero the contents of region 0.
+ //
+
+ HalpZeroNVRam(NVR_REGION0_OFFSET, NVR_REGION0_LENGTH);
+
+ //
+ // Initialize the signature.
+ //
+
+ HalpSetNVRamUlong(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0, Signature),
+ NVR_REGION0_SIGNATURE
+ );
+
+ //
+ // Initialize the version.
+ //
+
+ HalpSetNVRamUchar(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0, Version),
+ NVR_REGION0_VERSION
+ );
+
+ //
+ // Initialize the directory.
+ //
+
+ HalpSetNVRamUchar(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0, DirectoryEntries),
+ NVR_REGION0_DIR_SIZE
+ );
+
+ HalpSetNVRamUshort(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0, Directory[NVR_REGION0_DIR_FW_CONFIG]),
+ (USHORT)FIELD_OFFSET(NVR_REGION0, Opaque[0])
+ );
+
+ HalpSetNVRamUshort(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0, Directory[NVR_REGION0_DIR_LANGUAGE]),
+ FIELD_OFFSET(NVR_REGION0, Opaque[0]) +
+ NVR_FW_CONFIG_LENGTH
+ );
+
+ HalpSetNVRamUshort(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0, Directory[NVR_REGION0_DIR_ENVIRONMENT]),
+ FIELD_OFFSET(NVR_REGION0, Opaque[0]) +
+ NVR_FW_CONFIG_LENGTH +
+ NVR_LANGUAGE_LENGTH
+ );
+
+ HalpSetNVRamUshort(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0, Directory[NVR_REGION0_DIR_END]),
+ FIELD_OFFSET(NVR_REGION0, Checksum)
+ );
+
+ //
+ // Re-compute the checksum and store it in NVRAM.
+ //
+
+ Checksum = HalpComputeNVRamChecksum(
+ NVR_REGION0_OFFSET,
+ FIELD_OFFSET(NVR_REGION0, Checksum)
+ );
+
+ HalpSetNVRamUlong(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0, Checksum),
+ Checksum
+ );
+
+ //
+ // Synchronize the cache and NVRAM.
+ //
+
+ if (Synchronize) {
+ return HalpSynchronizeNVRamRegion0(TRUE);
+ }
+}
+
+ULONG
+HalpGetNVRamFwConfigOffset(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function returns the NVRAM offset of the firmware configuration
+ section in NVRAM.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The offset in NVRAM of the firmware configuration section.
+
+--*/
+{
+ //
+ // Return the firmware configuration offset.
+ //
+
+ return HalpGetNVRamUshort(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0,
+ Directory[NVR_REGION0_DIR_FW_CONFIG])
+ );
+}
+
+ULONG
+HalpGetNVRamFwConfigLength(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function returns the length of the firmware configuration
+ section of NVRAM.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The length of the firmware configuration section.
+
+--*/
+{
+ //
+ // Return the firmware configuration length.
+ //
+
+ return HalpGetNVRamUshort(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0,
+ Directory[NVR_REGION0_DIR_FW_CONFIG + 1])
+ ) -
+ HalpGetNVRamUshort(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0,
+ Directory[NVR_REGION0_DIR_FW_CONFIG])
+ );
+}
+
+ULONG
+HalpGetNVRamLanguageOffset(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function returns the NVRAM offset of the language section.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The NVRAM offset of the language section.
+
+--*/
+{
+ //
+ // Return the language offset.
+ //
+
+ return HalpGetNVRamUshort(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0,
+ Directory[NVR_REGION0_DIR_LANGUAGE])
+ );
+}
+
+ULONG
+HalpGetNVRamLanguageLength(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function returns the length of the language section in NVRAM.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The length of the language section.
+
+--*/
+{
+ //
+ // Return the language length.
+ //
+
+ return HalpGetNVRamUshort(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0,
+ Directory[NVR_REGION0_DIR_LANGUAGE + 1])
+ ) -
+ HalpGetNVRamUshort(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0,
+ Directory[NVR_REGION0_DIR_LANGUAGE])
+ );
+}
+
+ULONG
+HalpGetNVRamEnvironmentOffset(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function returns the NVRAM offset of the environment section.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The NVRAM offset of the environment section.
+
+--*/
+{
+ //
+ // Return the environment offset;
+ //
+
+ return HalpGetNVRamUshort(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0,
+ Directory[NVR_REGION0_DIR_ENVIRONMENT])
+ );
+}
+
+ULONG
+HalpGetNVRamEnvironmentLength(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function returns the length of the environment section.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The length of the environment section in NVRAM.
+
+--*/
+{
+ //
+ // Return the environment length.
+ //
+
+ return HalpGetNVRamUshort(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0,
+ Directory[NVR_REGION0_DIR_ENVIRONMENT + 1])
+ ) -
+ HalpGetNVRamUshort(
+ NVR_REGION0_OFFSET +
+ FIELD_OFFSET(NVR_REGION0,
+ Directory[NVR_REGION0_DIR_ENVIRONMENT])
+ );
+}
+
+#if defined(EISA_PLATFORM)
+
+BOOLEAN
+HalpIsNVRamRegion1Valid(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function fills the NVRAM cache (if necessary) and ascertains
+ whether the contents of region 1 of the NVRAM are valid. It verifies
+ that the signature, version and checksum are valid.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A boolean value indicating whether the contents of the region are valid.
+
+--*/
+{
+ ULONG Signature;
+ UCHAR Version;
+ ULONG Checksum1;
+ ULONG Checksum2;
+
+ //
+ // If the contents of the NVRAM cache are invalid, return failure.
+ //
+
+ if (!HalpIsNVRamCacheValid()) {
+ return FALSE;
+ }
+
+ //
+ // If region 1 is valid, return success.
+ //
+
+ if (HalpNVRamRegion1IsValid) {
+ return TRUE;
+ }
+
+ //
+ // If the signature is invalid, return failure.
+ //
+
+ Signature = HalpGetNVRamUlong(
+ NVR_REGION1_OFFSET +
+ FIELD_OFFSET(NVR_REGION1, Signature)
+ );
+
+ if (Signature != NVR_REGION1_SIGNATURE) {
+ return FALSE;
+ }
+
+ //
+ // If the version is invalid, return failure.
+ //
+
+ Version = HalpGetNVRamUchar(
+ NVR_REGION1_OFFSET +
+ FIELD_OFFSET(NVR_REGION1, Version)
+ );
+
+ if (Version == 0) {
+ return FALSE;
+ }
+
+ //
+ // If the checksum is invalid, return failure.
+ //
+
+ Checksum1 = HalpComputeNVRamChecksum(
+ NVR_REGION1_OFFSET,
+ FIELD_OFFSET(NVR_REGION1, Checksum)
+ );
+
+ Checksum2 = HalpGetNVRamUlong(
+ NVR_REGION1_OFFSET +
+ FIELD_OFFSET(NVR_REGION1, Checksum)
+ );
+
+ if (Checksum1 != Checksum2) {
+ return FALSE;
+ }
+
+ //
+ // Region 1 is valid.
+ //
+
+ HalpNVRamRegion1IsValid = TRUE;
+
+ //
+ // Return success.
+ //
+
+ return TRUE;
+}
+
+BOOLEAN
+HalpSynchronizeNVRamRegion1(
+ IN BOOLEAN RecomputeChecksum
+ )
+/*++
+
+Routine Description:
+
+ This function writes the contents of the NVRAM cache region 1
+ back to NVRAM and optionally updates the checksum field.
+
+Arguments:
+
+ RecomputeChecksum - Update the checksum?
+
+Return Value:
+
+ A boolean value indicating whether the NVRAM was correctly updated.
+
+--*/
+{
+ ULONG Checksum;
+
+ //
+ // If we are unable to synchronize the NVRAM cache, return failure.
+ //
+
+ if (!HalpSynchronizeNVRamCache()) {
+ return FALSE;
+ }
+
+ //
+ // If we do not need to re-compute the checksum, return success.
+ //
+
+ if (!RecomputeChecksum) {
+ return TRUE;
+ }
+
+ //
+ // Re-compute the checksum and store it in NVRAM.
+ //
+
+ Checksum = HalpComputeNVRamChecksum(
+ NVR_REGION1_OFFSET,
+ FIELD_OFFSET(NVR_REGION1, Checksum)
+ );
+
+ HalpSetNVRamUlong(
+ NVR_REGION1_OFFSET +
+ FIELD_OFFSET(NVR_REGION1, Checksum),
+ Checksum
+ );
+
+ //
+ // Synchronize the NVRAM cache.
+ //
+
+ return HalpSynchronizeNVRamCache();
+}
+
+BOOLEAN
+HalpInitializeNVRamRegion1(
+ BOOLEAN Synchronize
+ )
+/*++
+
+Routine Description:
+
+ This function initializes the contents of region 1.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A boolean value indicating whether the NVRAM was properly initialized.
+
+--*/
+{
+ ULONG Checksum;
+
+ //
+ // Zero the contents of region 1.
+ //
+
+ HalpZeroNVRam(NVR_REGION1_OFFSET, NVR_REGION1_LENGTH);
+
+ //
+ // Initialize the signature.
+ //
+
+ HalpSetNVRamUlong(
+ NVR_REGION1_OFFSET +
+ FIELD_OFFSET(NVR_REGION1, Signature),
+ NVR_REGION1_SIGNATURE
+ );
+
+ //
+ // Initialize the version.
+ //
+
+ HalpSetNVRamUchar(
+ NVR_REGION1_OFFSET +
+ FIELD_OFFSET(NVR_REGION1, Version),
+ NVR_REGION1_VERSION
+ );
+
+ //
+ // Re-compute the checksum and store it in NVRAM.
+ //
+
+ Checksum = HalpComputeNVRamChecksum(
+ NVR_REGION1_OFFSET,
+ FIELD_OFFSET(NVR_REGION1, Checksum)
+ );
+
+ HalpSetNVRamUlong(
+ NVR_REGION1_OFFSET +
+ FIELD_OFFSET(NVR_REGION1, Checksum),
+ Checksum
+ );
+
+ //
+ // Synchronize the cache and NVRAM.
+ //
+
+ if (Synchronize) {
+ return HalpSynchronizeNVRamRegion1(TRUE);
+ }
+}
+
+#endif // EISA_PLATFORM
diff --git a/private/ntos/nthals/halalpha/nvram.h b/private/ntos/nthals/halalpha/nvram.h
new file mode 100644
index 000000000..6126a4b38
--- /dev/null
+++ b/private/ntos/nthals/halalpha/nvram.h
@@ -0,0 +1,215 @@
+/*++
+
+Copyright (c) 1994, 1995 Digital Equipment Corporation
+
+Module Name:
+
+ nvram.h
+
+Abstract:
+
+ This module declares the NVRAM data structures.
+
+Author:
+
+ Dave Richards 12-Jan-1995
+
+Revision History:
+
+--*/
+
+#ifndef _NVRAM_H_
+#define _NVRAM_H_
+
+//
+// NVRAM Region 0 definitions.
+//
+
+#define NVR_REGION0_OFFSET FIELD_OFFSET(NVRAM, Region0)
+#define NVR_REGION0_LENGTH (3 * 1024)
+#define NVR_REGION0_SIGNATURE 0x06201993
+#define NVR_REGION0_VERSION 1
+
+//
+// NVRAM Region 0 Directory definitions.
+//
+
+#define NVR_REGION0_DIR_FW_CONFIG 0
+#define NVR_REGION0_DIR_LANGUAGE 1
+#define NVR_REGION0_DIR_ENVIRONMENT 2
+#define NVR_REGION0_DIR_END 3
+#define NVR_REGION0_DIR_SIZE 4
+
+//
+// NVRAM Region 0 structure.
+//
+
+#define NVR_REGION0_OPAQUE_LENGTH \
+ NVR_REGION0_LENGTH - \
+ (sizeof (ULONG) /* Signature */ + \
+ sizeof (UCHAR) /* Version */ + \
+ sizeof (UCHAR) /* DirectoryEntries */ + \
+ sizeof (USHORT) * NVR_REGION0_DIR_SIZE /* Directory */ + \
+ sizeof (ULONG)) /* Checksum */
+
+typedef struct {
+ ULONG Signature;
+ UCHAR Version;
+ UCHAR DirectoryEntries;
+ USHORT Directory[NVR_REGION0_DIR_SIZE];
+ UCHAR Opaque[NVR_REGION0_OPAQUE_LENGTH];
+ ULONG Checksum;
+} NVR_REGION0, *PNVR_REGION0;
+
+//
+// NVRAM Region 0 Section 0 structure. (Firmware configuration)
+//
+
+#define NVR_FW_CONFIG_LENGTH sizeof (NVR_FW_CONFIG)
+
+typedef struct {
+ ULONG Monitor;
+ ULONG Floppy;
+ ULONG Floppy2;
+ ULONG KeyboardType;
+} NVR_FW_CONFIG, *PNVR_FW_CONFIG;
+
+//
+// NVRAM Region 0 Section 1 structure. (Language configuration)
+//
+
+#define MAXIMUM_LANGUAGE_PATH 128
+#define NVR_LANGUAGE_LENGTH sizeof (NVR_LANGUAGE)
+
+typedef struct {
+ CHAR Path[MAXIMUM_LANGUAGE_PATH];
+ LONG Id;
+ LONG Source;
+ LONG Spare1;
+ LONG Spare2;
+} NVR_LANGUAGE, *PNVR_LANGUAGE;
+
+//
+// NVRAM Region 0 Section 2 definitions. (Environment)
+//
+
+#define MAXIMUM_ENVIRONMENT_VALUE 256
+#define MAX_NUMBER_OF_ENVIRONMENT_VARIABLES 28
+
+//
+// NVRAM Region 1 definitions.
+//
+
+#define NVR_REGION1_OFFSET FIELD_OFFSET(NVRAM, Region1)
+#define NVR_REGION1_LENGTH (3 * 1024)
+#define NVR_REGION1_SIGNATURE 0x865D8546
+#define NVR_REGION1_VERSION 1
+
+//
+// EISA NVRAM Definitions
+//
+
+#if defined(EISA_PLATFORM)
+
+//
+// Defines for Identifier index.
+//
+
+#define NO_CONFIGURATION_IDENTIFIER 0xFFFF
+
+//
+// Defines for the region 1 table sizes.
+//
+
+#define NV_NUMBER_OF_ENTRIES 33
+#define NV_LENGTH_OF_IDENTIFIER 496
+#define LENGTH_OF_EISA_DATA 2032
+
+//
+// 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;
+
+#endif // EISA_PLATFORM
+
+//
+// Region 1 structure.
+//
+
+typedef struct {
+
+#if defined(EISA_PLATFORM)
+
+ //
+ // EISA configuration information.
+ //
+
+ ULONG Signature;
+ UCHAR Version;
+ UCHAR CompressedPacketSize;
+ UCHAR IdentifierSize;
+ UCHAR EisaDataSize;
+ COMPRESSED_CONFIGURATION_PACKET
+ Packet[NV_NUMBER_OF_ENTRIES];
+ UCHAR Identifier[NV_LENGTH_OF_IDENTIFIER];
+ UCHAR EisaData[LENGTH_OF_EISA_DATA];
+ ULONG Spare;
+ ULONG Checksum;
+
+#else
+
+ //
+ // Reserved for the SRM Console.
+ //
+
+ UCHAR Opaque[NVR_REGION1_LENGTH];
+
+#endif
+
+} NVR_REGION1, *PNVR_REGION1;
+
+//
+// NVRAM Region 2 definitions.
+//
+
+#define NVR_REGION2_OFFSET FIELD_OFFSET(NVRAM, Region2)
+#define NVR_REGION2_LENGTH (2 * 1024)
+
+//
+// NVRAM Region 2 structure.
+//
+
+typedef struct {
+ UCHAR Opaque[NVR_REGION2_LENGTH];
+} NVR_REGION2, *PNVR_REGION2;
+
+//
+// NVRAM definitions.
+//
+
+#define NVR_LENGTH sizeof (NVRAM)
+
+//
+// NVRAM structure.
+//
+
+typedef struct {
+ NVR_REGION0 Region0;
+ NVR_REGION1 Region1;
+ NVR_REGION2 Region2;
+} NVRAM, *PNVRAM;
+
+#endif
diff --git a/private/ntos/nthals/halalpha/pciesc.c b/private/ntos/nthals/halalpha/pciesc.c
new file mode 100644
index 000000000..9a54e38ec
--- /dev/null
+++ b/private/ntos/nthals/halalpha/pciesc.c
@@ -0,0 +1,477 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+Copyright (c) 1992, 1993, 1994 Digital Equipment Corporation
+
+Module Name:
+
+ pciesc.c
+
+Abstract:
+
+ The module provides the interrupt support for the PCI ESC's
+ cascaded 82c59 programmable interrupt controllers.
+
+Author:
+
+ Eric Rehm (DEC) 4-Feburary-1994
+
+Revision History:
+
+ James Livingston 29-Apr-1994
+ Adapted from pcisio.c module for Intel 82374EB (ESC).
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+
+//
+// Import save area for ESC interrupt mask registers.
+//
+
+UCHAR HalpEisaInterrupt1Mask;
+UCHAR HalpEisaInterrupt2Mask;
+UCHAR HalpEisaInterrupt1Level;
+UCHAR HalpEisaInterrupt2Level;
+
+
+BOOLEAN
+HalpInitializeEisaInterrupts (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the standard dual 82c59 programmable interrupt
+ controller.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UCHAR DataByte;
+
+ //
+ // Initialize the ESC interrupt controller. There are two cascaded
+ // interrupt controllers, each of which must be initialized with 4
+ // control words.
+ //
+
+ DataByte = 0;
+ ((PINITIALIZATION_COMMAND_1) &DataByte)->Icw4Needed = 1;
+ ((PINITIALIZATION_COMMAND_1) &DataByte)->InitializationFlag = 1;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ DataByte
+ );
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ DataByte
+ );
+
+ //
+ // The second intitialization control word sets the interrupt vector to
+ // 0-15.
+ //
+
+ DataByte = 0;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ DataByte = 0x08;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ DataByte
+ );
+
+ //
+ // The third initialization control word sets the controls for slave mode.
+ // The master ICW3 uses bit position and the slave ICW3 uses a numeric.
+ //
+
+ DataByte = 1 << SLAVE_IRQL_LEVEL;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ DataByte = SLAVE_IRQL_LEVEL;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->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_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ DataByte
+ );
+
+
+ //
+ // Disable all of the interrupts except the slave.
+ //
+
+ HalpEisaInterrupt1Mask = (UCHAR)(~(1 << SLAVE_IRQL_LEVEL));
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpEisaInterrupt1Mask
+ );
+
+ HalpEisaInterrupt2Mask = 0xFF;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ HalpEisaInterrupt2Mask
+ );
+
+
+ //
+ // Initialize the edge/level register masks to 0, which is the default
+ // edge-sensitive value.
+ //
+
+ HalpEisaInterrupt1Level = 0;
+ HalpEisaInterrupt2Level = 0;
+
+ return (TRUE);
+}
+
+VOID
+HalpDisableEisaInterrupt(
+ IN ULONG Vector
+ )
+
+/*++
+
+Routine Description:
+
+ This function Disables the EISA interrupt specified by Vector.
+
+Arguments:
+
+ Vector - Supplies the vector of the ESIA interrupt that is Disabled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Calculate the EISA interrupt vector.
+ //
+
+ Vector -= EISA_VECTORS;
+
+ //
+ // Determine if this vector is for interrupt controller 1 or 2.
+ //
+
+ if (Vector & 0x08) {
+
+ //
+ // The interrupt is for controller 2.
+ //
+
+ Vector &= 0x7;
+
+ HalpEisaInterrupt2Mask |= (UCHAR) 1 << Vector;
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ HalpEisaInterrupt2Mask
+ );
+
+ } else {
+
+ //
+ // The interrupt is in controller 1.
+ //
+
+ Vector &= 0x7;
+
+ //
+ // never disable IRQL2; it is the slave interrupt
+ //
+
+ if (Vector != SLAVE_IRQL_LEVEL) {
+ HalpEisaInterrupt1Mask |= (ULONG) 1 << Vector;
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpEisaInterrupt1Mask
+ );
+ }
+ }
+}
+
+VOID
+HalpEnableEisaInterrupt(
+ IN ULONG Vector,
+ IN KINTERRUPT_MODE InterruptMode
+ )
+
+/*++
+
+Routine Description:
+
+ This function enables the EISA interrupt specified by Vector.
+Arguments:
+
+ Vector - Supplies the vector of the EISA interrupt that is enabled.
+
+ InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
+ Latched.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ //
+ // Calculate the EISA interrupt vector.
+ //
+
+ Vector -= EISA_VECTORS;
+
+ //
+ // Determine if this vector is for interrupt controller 1 or 2.
+ //
+
+ if (Vector & 0x08) {
+
+ //
+ // The interrupt is in controller 2.
+ //
+
+ Vector &= 0x7;
+
+ HalpEisaInterrupt2Mask &= (UCHAR) ~(1 << Vector);
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ HalpEisaInterrupt2Mask
+ );
+
+ //
+ // Set the level/edge control register.
+ //
+
+ if (InterruptMode == LevelSensitive) {
+
+ HalpEisaInterrupt2Level |= (UCHAR) (1 << Vector);
+
+ } else {
+
+ HalpEisaInterrupt2Level &= (UCHAR) ~(1 << Vector);
+
+ }
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2EdgeLevel,
+ HalpEisaInterrupt2Level
+ );
+
+ } else {
+
+ //
+ // The interrupt is in controller 1.
+ //
+
+ Vector &= 0x7;
+
+ HalpEisaInterrupt1Mask &= (UCHAR) ~(1 << Vector);
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpEisaInterrupt1Mask
+ );
+
+ //
+ // Set the level/edge control register.
+ //
+
+ if (InterruptMode == LevelSensitive) {
+
+ HalpEisaInterrupt1Level |= (UCHAR) (1 << Vector);
+
+ } else {
+
+ HalpEisaInterrupt1Level &= (UCHAR) ~(1 << Vector);
+
+ }
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1EdgeLevel,
+ HalpEisaInterrupt1Level
+ );
+ }
+}
+
+BOOLEAN
+HalpEisaDispatch(
+ IN PKINTERRUPT Interrupt,
+ IN PVOID ServiceContext,
+ IN PKTRAP_FRAME TrapFrame
+ )
+/*++
+
+Routine Description:
+
+ This routine is entered as the result of an interrupt being generated
+ via the vector that is connected to an interrupt object that describes
+ the EISA device interrupts. Its function is to call the second-level
+ interrupt dispatch routine and acknowledge the interrupt at the ESC
+ controller.
+
+ This service routine could be connected as follows:
+
+ KeInitializeInterrupt(&Interrupt, HalpDispatch,
+ EISA_VIRTUAL_BASE,
+ (PKSPIN_LOCK)NULL, ISA_LEVEL, ISA_LEVEL, ISA_LEVEL,
+ LevelSensitive, TRUE, 0, FALSE);
+ KeConnectInterrupt(&Interrupt);
+
+Arguments:
+
+ Interrupt - Supplies a pointer to the interrupt object.
+
+ ServiceContext - Supplies a pointer to the EISA interrupt acknowledge
+ register.
+
+ TrapFrame - Supplies a pointer to the trap frame for this interrupt.
+
+Return Value:
+
+ Returns the value returned from the second level routine.
+
+--*/
+{
+ UCHAR EISAVector;
+ PKPRCB Prcb;
+ BOOLEAN returnValue;
+ USHORT PCRInOffset;
+ UCHAR Int1Isr;
+ UCHAR Int2Isr;
+
+ //
+ // Acknowledge the Interrupt controller and receive the returned
+ // interrupt vector.
+ //
+
+ EISAVector = HalpAcknowledgeEisaInterrupt(ServiceContext);
+
+
+ if ((EISAVector & 0x07) == 0x07) {
+
+ //
+ // Check for a passive release by looking at the inservice register.
+ // If there is a real IRQL7 interrupt, just go along normally. If there
+ // is not, then it is a passive release. So just dismiss it.
+ //
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ 0x0B
+ );
+
+ Int1Isr = READ_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0);
+
+ //
+ // do second controller
+ //
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ 0x0B
+ );
+
+ Int2Isr = READ_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0);
+
+
+ if (!(Int2Isr & 0x80) && !(Int1Isr & 0x80)) {
+
+ //
+ // Clear the master controller to clear situation
+ //
+
+ if (!(Int2Isr & 0x80)) {
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ }
+
+ return FALSE; // ecrfix - now returns a value
+
+ }
+ }
+
+ //
+ // Dispatch to the secondary interrupt service routine.
+ //
+
+ PCRInOffset = EISAVector + EISA_VECTORS;
+
+ returnValue = ((PSECONDARY_DISPATCH) PCR->InterruptRoutine[PCRInOffset])(
+ PCR->InterruptRoutine[PCRInOffset],
+ TrapFrame
+ );
+
+ //
+ // Dismiss the interrupt in the ESC interrupt controllers.
+ //
+
+ //
+ // If this is a cascaded interrupt then the interrupt must be dismissed in
+ // both controlles.
+ //
+
+ if (EISAVector & 0x08) {
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+ }
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ return(returnValue);
+}
diff --git a/private/ntos/nthals/halalpha/pcip.h b/private/ntos/nthals/halalpha/pcip.h
new file mode 100644
index 000000000..8cd3f6cc4
--- /dev/null
+++ b/private/ntos/nthals/halalpha/pcip.h
@@ -0,0 +1,178 @@
+/*++ BUILD Version: 0000 Increment this if a change has global effects
+
+Copyright (c) 1994 Microsoft Corporation
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ pcip.h
+
+Abstract:
+
+ This header file defines the private PCI bus HAL interfaces and
+ data types.
+
+Author:
+
+ Eric Rehm (rehm) 14-August-1994
+
+Revision History:
+
+ 14-Jul-1994 (rehm)
+ Original
+
+ 5-Dec-1994 (rehm)
+ Added DevicePresent bitmap and PlatformSpecificData pointer to PCIBUSDATA
+ data type.
+
+--*/
+
+#ifndef _PCIPH_
+#define _PCIPH_
+
+//
+// Hal specific PCI bus structures
+//
+
+#define PCI_CONFIG_TYPE(PciData) ((PciData)->HeaderType & ~PCI_MULTIFUNCTION)
+
+#define PCI_MAX_BUSSES 256
+
+#define PciBitIndex(Dev,Fnc) (Fnc*32 + Dev)
+
+//
+// Define PCI configuration cycle types.
+//
+typedef enum _PCI_CONFIGURATION_TYPES {
+ PciConfigTypeInvalid = -1,
+ PciConfigType0 = 0,
+ PciConfigType1 = 1
+} PCI_CONFIGURATION_TYPES, *PPCI_CONFIGURATION_TYPES;
+
+typedef struct _PCI_CFG_CYCLE_BITS {
+ union {
+ struct {
+ ULONG Reserved1:2;
+ ULONG Reserved2:30;
+ } bits; // Generic Config Cycle
+
+ struct {
+ ULONG Reserved1:2;
+ ULONG RegisterNumber:6;
+ ULONG FunctionNumber:3;
+ ULONG Idsel:21;
+ } bits0; // Type0 Config Cycle
+
+ struct {
+ ULONG Reserved1:2;
+ ULONG RegisterNumber:6;
+ ULONG FunctionNumber:3;
+ ULONG DeviceNumber:5;
+ ULONG BusNumber:8;
+ ULONG Reserved2:7;
+ ULONG Enable:1;
+ } bits1; // Type 1 Config Cycle
+
+ ULONG AsULONG;
+ } u;
+} PCI_CFG_CYCLE_BITS, *PPCI_CFG_CYCLE_BITS;
+
+//
+// Define PCI cycle/command types.
+//
+
+typedef enum _PCI_COMMAND_TYPES{
+ PciCommandInterruptAcknowledge = 0x0,
+ PciCommandSpecialCycle = 0x1,
+ PciCommandIoRead = 0x2,
+ PciCommandIoWrite = 0x3,
+ PciCommandMemoryRead = 0x6,
+ PciCommandMemoryWrite = 0x7,
+ PciCommandConfigurationRead = 0xa,
+ PciCommandConfigurationWrite = 0xb,
+ PciCommandMemoryReadMultiple = 0xc,
+ PciCommandDualAddressCycle = 0xd,
+ PciCommandMemoryReadLine = 0xe,
+ PciCommandMemoryWriteAndInvalidate = 0xf,
+ MaximumPciCommand
+} PCI_COMMAND_TYPES, *PPCI_COMMAND_TYPES;
+
+//
+// PCI platform-specific functions
+//
+
+
+PCI_CONFIGURATION_TYPES
+HalpPCIConfigCycleType (
+ IN PBUS_HANDLER BusHandler
+ );
+
+VOID
+HalpPCIConfigAddr (
+ IN PBUS_HANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ PPCI_CFG_CYCLE_BITS pPciAddr
+ );
+
+
+//
+// Define PCI configuration cycle types.
+//
+
+typedef enum _PCI_TYPE0_CONFIG_TYPE {
+ PciConfigType0AsIdsel,
+ PciConfigType0AsDeviceNumber
+} PCI_TYPE0_CONFIG_TYPE, *PPCI_TYPE0_CONFIG_TYPE;
+
+
+typedef struct tagPCIPBUSDATA {
+
+ //
+ // NT Defined PCI data
+ //
+
+ PCIBUSDATA CommonData;
+
+ //
+ // Common alpha hal specific data
+ //
+
+ PVOID ConfigBaseQva;
+ PCI_TYPE0_CONFIG_TYPE PciType0ConfigType;
+ ULONG HwBusNumber;
+ BOOLEAN BusIsAcrossPPB;
+
+ RTL_BITMAP DevicePresent;
+ ULONG DevicePresentBits[PCI_MAX_DEVICES * PCI_MAX_FUNCTION / 32];
+
+ ULONG MaxDevice;
+
+ ULONG PPBBusNumber;
+ PCI_SLOT_NUMBER PPBSlotNumber;
+
+ //
+ // Platform-specific storage
+ //
+
+ PVOID PlatformSpecificData;
+
+} PCIPBUSDATA, *PPCIPBUSDATA;
+
+//
+// The following structure is used to communicate PCI bus information
+// between the ARC firmware and HAL. This structure is passed as
+// configuration information on the PCI multifunction adapter nodes of the
+// ARC configuration tree.
+//
+
+typedef struct _ARC_PCI_CONFIGURATION {
+ ULONG Version;
+ ULONG BusNumber;
+ ULONG HwBusNumber;
+ BOOLEAN BusIsAcrossPPB;
+ ULONG DevicePresentBits[PCI_MAX_DEVICES * PCI_MAX_FUNCTION / 32];
+} ARC_PCI_CONFIGURATION, *PARC_PCI_CONFIGURATION;
+
+#define ARC_PCI_CONFIGURATION_VERSION 1
+
+#endif // _PCIPH_
diff --git a/private/ntos/nthals/halalpha/pcisio.c b/private/ntos/nthals/halalpha/pcisio.c
new file mode 100644
index 000000000..76021c879
--- /dev/null
+++ b/private/ntos/nthals/halalpha/pcisio.c
@@ -0,0 +1,483 @@
+/*++
+
+Copyright (c) 1990 Microsoft Corporation
+Copyright (c) 1992, 1993, 1994 Digital Equipment Corporation
+
+Module Name:
+
+ pic8259.c
+
+Abstract:
+
+ The module provides the interrupt support for the PCI SIO
+ programmable interrupt controller.
+
+
+Author:
+
+ Eric Rehm (DEC) 4-Feburary-1994
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+
+//
+// Import save area for SIO interrupt mask registers.
+//
+
+UCHAR HalpSioInterrupt1Mask;
+UCHAR HalpSioInterrupt2Mask;
+UCHAR HalpSioInterrupt1Level;
+UCHAR HalpSioInterrupt2Level;
+
+//
+// Define the context structure for use by interrupt service routines.
+//
+
+typedef BOOLEAN (*PSECOND_LEVEL_DISPATCH)(
+ PKINTERRUPT InterruptObject
+ );
+
+
+VOID
+HalpInitializeSioInterrupts (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes the standard dual 8259 programmable interrupt
+ controller.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ UCHAR DataByte;
+
+ //
+ // Initialize the SIO 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_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ DataByte
+ );
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ DataByte
+ );
+
+ //
+ // The second intitialization control word sets the iterrupt vector to
+ // 0-15.
+ //
+
+ DataByte = 0;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ DataByte = 0x08;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->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_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ DataByte = SLAVE_IRQL_LEVEL;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->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_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ DataByte
+ );
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ DataByte
+ );
+
+
+ //
+ // Disable all of the interrupts except the slave.
+ //
+
+ HalpSioInterrupt1Mask = (UCHAR)(~(1 << SLAVE_IRQL_LEVEL));
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpSioInterrupt1Mask
+ );
+
+ HalpSioInterrupt2Mask = 0xFF;
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ HalpSioInterrupt2Mask
+ );
+
+
+ //
+ // Initialize the edge/level register masks to 0 which is the default
+ // edge sensitive value.
+ //
+
+ HalpSioInterrupt1Level = 0;
+ HalpSioInterrupt2Level = 0;
+
+ return;
+
+}
+
+VOID
+HalpDisableSioInterrupt(
+ IN ULONG Vector
+ )
+
+/*++
+
+Routine Description:
+
+ This function Disables the SIO bus specified SIO bus interrupt.
+
+Arguments:
+
+ Vector - Supplies the vector of the ESIA interrupt that is Disabled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Calculate the SIO interrupt vector.
+ //
+
+ Vector -= ISA_VECTORS;
+
+ //
+ // Determine if this vector is for interrupt controller 1 or 2.
+ //
+
+ if (Vector & 0x08) {
+
+ //
+ // The interrupt is in controller 2.
+ //
+
+ Vector &= 0x7;
+
+ HalpSioInterrupt2Mask |= (UCHAR) 1 << Vector;
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ HalpSioInterrupt2Mask
+ );
+
+ } else {
+
+ //
+ // The interrupt is in controller 1.
+ //
+
+ Vector &= 0x7;
+
+ //
+ // never disable IRQL2, it is the slave interrupt
+ //
+
+ if (Vector != SLAVE_IRQL_LEVEL) {
+ HalpSioInterrupt1Mask |= (ULONG) 1 << Vector;
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpSioInterrupt1Mask
+ );
+ }
+
+ }
+
+}
+
+VOID
+HalpEnableSioInterrupt(
+ IN ULONG Vector,
+ IN KINTERRUPT_MODE InterruptMode
+ )
+
+/*++
+
+Routine Description:
+
+ This function enables the SIO bus specified SIO bus interrupt.
+Arguments:
+
+ Vector - Supplies the vector of the SIO interrupt that is enabled.
+
+ InterruptMode - Supplies the mode of the interrupt; LevelSensitive or
+ Latched.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Calculate the SIO interrupt vector.
+ //
+
+ Vector -= ISA_VECTORS;
+
+ //
+ // Determine if this vector is for interrupt controller 1 or 2.
+ //
+
+ if (Vector & 0x08) {
+
+ //
+ // The interrupt is in controller 2.
+ //
+
+ Vector &= 0x7;
+
+ HalpSioInterrupt2Mask &= (UCHAR) ~(1 << Vector);
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort1,
+ HalpSioInterrupt2Mask
+ );
+
+ //
+ // Set the level/edge control register.
+ //
+
+ if (InterruptMode == LevelSensitive) {
+
+ HalpSioInterrupt2Level |= (UCHAR) (1 << Vector);
+
+ } else {
+
+ HalpSioInterrupt2Level &= (UCHAR) ~(1 << Vector);
+
+ }
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2EdgeLevel,
+ HalpSioInterrupt2Level
+ );
+
+ } else {
+
+ //
+ // The interrupt is in controller 1.
+ //
+
+ Vector &= 0x7;
+
+ HalpSioInterrupt1Mask &= (UCHAR) ~(1 << Vector);
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort1,
+ HalpSioInterrupt1Mask
+ );
+
+ //
+ // Set the level/edge control register.
+ //
+
+ if (InterruptMode == LevelSensitive) {
+
+ HalpSioInterrupt1Level |= (UCHAR) (1 << Vector);
+
+ } else {
+
+ HalpSioInterrupt1Level &= (UCHAR) ~(1 << Vector);
+
+ }
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1EdgeLevel,
+ HalpSioInterrupt1Level
+ );
+ }
+
+}
+
+BOOLEAN
+HalpSioDispatch(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine is entered as the result of an interrupt being generated
+ via the vector that is directly connected to an interrupt object that
+ describes the SIO device interrupts. Its function is to call the second
+ level interrupt dispatch routine and acknowledge the interrupt at the SIO
+ controller.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ Returns the value returned from the second level routine.
+
+--*/
+{
+ UCHAR ISAVector;
+ PKPRCB Prcb;
+ BOOLEAN returnValue;
+ USHORT PCRInOffset;
+ UCHAR Int1Isr;
+ UCHAR Int2Isr;
+ PULONG DispatchCode;
+ PKINTERRUPT InterruptObject;
+
+ //
+ // Acknowledge the Interrupt controller and receive the returned
+ // interrupt vector.
+ //
+
+ ISAVector = READ_PORT_UCHAR(HalpEisaIntAckBase);
+
+
+ if ((ISAVector & 0x07) == 0x07) {
+
+ //
+ // Check for a passive release by looking at the inservice register.
+ // If there is a real IRQL7 interrupt, just go along normally. If there
+ // is not, then it is a passive release. So just dismiss it.
+ //
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ 0x0B
+ );
+
+ Int1Isr = READ_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0);
+
+ //
+ // do second controller
+ //
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ 0x0B
+ );
+
+ Int2Isr = READ_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0);
+
+
+ if (!(Int2Isr & 0x80) && !(Int1Isr & 0x80)) {
+
+ //
+ // Clear the master controller to clear situation
+ //
+
+ if (!(Int2Isr & 0x80)) {
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ }
+
+ return FALSE; // ecrfix - now returns a value
+
+ }
+
+
+ }
+
+ //
+ // Dispatch to the secondary interrupt service routine.
+ //
+
+ PCRInOffset = ISAVector + ISA_VECTORS;
+ DispatchCode = (PULONG)PCR->InterruptRoutine[PCRInOffset];
+ InterruptObject = CONTAINING_RECORD(DispatchCode,
+ KINTERRUPT,
+ DispatchCode);
+
+ returnValue = ((PSECOND_LEVEL_DISPATCH)InterruptObject->DispatchAddress)(InterruptObject);
+
+ //
+ // Dismiss the interrupt in the SIO interrupt controllers.
+ //
+
+ //
+ // If this is a cascaded interrupt then the interrupt must be dismissed in
+ // both controlles.
+ //
+
+ if (ISAVector & 0x08) {
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt2ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ }
+
+ WRITE_PORT_UCHAR(
+ &((PEISA_CONTROL) HalpEisaControlBase)->Interrupt1ControlPort0,
+ NONSPECIFIC_END_OF_INTERRUPT
+ );
+
+ return(returnValue);
+}
+
+
diff --git a/private/ntos/nthals/halalpha/pcisup.c b/private/ntos/nthals/halalpha/pcisup.c
new file mode 100644
index 000000000..34147cc91
--- /dev/null
+++ b/private/ntos/nthals/halalpha/pcisup.c
@@ -0,0 +1,2453 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ pcisup.c
+
+Abstract:
+
+ Platform-independent PCI bus routines
+
+Author:
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+#include "pci.h"
+#include "pcip.h"
+
+typedef ULONG (*FncConfigIO) (
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+typedef struct {
+ FncConfigIO ConfigRead[3];
+ FncConfigIO ConfigWrite[3];
+} CONFIG_HANDLER, *PCONFIG_HANDLER;
+
+
+//
+// Define PCI slot validity
+//
+typedef enum _VALID_SLOT {
+ InvalidBus = 0,
+ InvalidSlot,
+ ValidSlot
+} VALID_SLOT;
+
+//
+// Local prototypes for routines supporting PCI bus handler routines
+//
+
+ULONG
+HalpGetPCIData (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG Slot,
+ IN PUCHAR Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+ULONG
+HalpSetPCIData (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG Slot,
+ IN PUCHAR Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+
+NTSTATUS
+HalpAdjustPCIResourceList (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+ );
+
+
+NTSTATUS
+HalpAssignPCISlotResources (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN PUNICODE_STRING RegistryPath,
+ IN PUNICODE_STRING DriverClassName OPTIONAL,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject OPTIONAL,
+ IN ULONG Slot,
+ IN OUT PCM_RESOURCE_LIST *pAllocatedResources
+ );
+
+VOID
+HalpReadPCIConfig (
+ IN PBUS_HANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+VOID
+HalpWritePCIConfig (
+ IN PBUS_HANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+VALID_SLOT
+HalpValidPCISlot (
+ IN PBUS_HANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot
+ );
+
+VOID
+HalpPCIConfig (
+ IN PBUS_HANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PUCHAR Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN FncConfigIO *ConfigIO
+ );
+
+ULONG HalpPCIReadUlong (
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIReadUchar (
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIReadUshort (
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIWriteUlong (
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIWriteUchar (
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+ULONG HalpPCIWriteUshort (
+ IN PVOID State,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ );
+
+VOID
+HalpPCILine2PinNop (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN PCI_SLOT_NUMBER SlotNumber,
+ IN PPCI_COMMON_CONFIG PciNewData,
+ IN PPCI_COMMON_CONFIG PciOldData
+ );
+
+VOID
+HalpPCIPin2LineNop (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN PCI_SLOT_NUMBER SlotNumber,
+ IN PPCI_COMMON_CONFIG PciData
+ );
+
+#if DBG
+BOOLEAN
+HalpValidPCIAddr(
+ IN PBUS_HANDLER BusHandler,
+ IN PHYSICAL_ADDRESS BAddr,
+ IN ULONG Length,
+ IN ULONG AddressSpace
+ );
+#endif
+
+//
+// Local prototypes of functions that are not built for Alpha AXP firmware
+//
+
+NTSTATUS
+HalpAssignPCISlotResources (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN PUNICODE_STRING RegistryPath,
+ IN PUNICODE_STRING DriverClassName OPTIONAL,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject OPTIONAL,
+ IN ULONG Slot,
+ IN OUT PCM_RESOURCE_LIST *pAllocatedResources
+ );
+
+#if DBG
+VOID
+HalpTestPci (
+ ULONG
+ );
+#endif
+
+//
+// Pragmas to assign functions to different kinds of pages.
+//
+
+#if !defined(AXP_FIRMWARE)
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,HalpInitializePCIBus)
+#pragma alloc_text(INIT,HalpAllocateAndInitPCIBusHandler)
+#pragma alloc_text(INIT,HalpRegisterPCIInstallHandler )
+#pragma alloc_text(INIT,HalpDefaultPCIInstallHandler )
+#pragma alloc_text(INIT,HalpDeterminePCIDevicesPresent )
+#pragma alloc_text(PAGE,HalpAssignPCISlotResources)
+#pragma alloc_text(PAGE,HalpAdjustPCIResourceList)
+#endif // ALLOC_PRAGMA
+#endif // !defined(AXP_FIRMWARE)
+
+#ifdef AXP_FIRMWARE
+
+#define ExFreePool(PoolData)
+
+#pragma alloc_text(DISTEXT, HalpInitializePCIBus )
+#pragma alloc_text(DISTEXT, HalpAllocateAndInitPCIBusHandler)
+#pragma alloc_text(DISTEXT, HalpRegisterPCIInstallHandler )
+#pragma alloc_text(DISTEXT, HalpDefaultPCIInstallHandler )
+#pragma alloc_text(DISTEXT, HalpDeterminePCIDevicesPresent )
+#pragma alloc_text(DISTEXT, HalpGetPCIData )
+#pragma alloc_text(DISTEXT, HalpSetPCIData )
+#pragma alloc_text(DISTEXT, HalpReadPCIConfig )
+#pragma alloc_text(DISTEXT, HalpWritePCIConfig )
+#pragma alloc_text(DISTEXT, HalpValidPCISlot )
+#if DBG
+#pragma alloc_text(DISTEXT, HalpValidPCIAddr )
+#endif
+#pragma alloc_text(DISTEXT, HalpPCIConfig )
+#pragma alloc_text(DISTEXT, HalpPCIReadUchar )
+#pragma alloc_text(DISTEXT, HalpPCIReadUshort )
+#pragma alloc_text(DISTEXT, HalpPCIReadUlong )
+#pragma alloc_text(DISTEXT, HalpPCIWriteUchar )
+#pragma alloc_text(DISTEXT, HalpPCIWriteUshort )
+#pragma alloc_text(DISTEXT, HalpPCIWriteUlong )
+#pragma alloc_text(DISTEXT, HalpAssignPCISlotResources)
+#pragma alloc_text(DISTEXT, HalpAdjustPCIResourceList)
+
+#endif // AXP_FIRMWARE
+
+
+//
+// Globals
+//
+
+KSPIN_LOCK HalpPCIConfigLock;
+BOOLEAN PCIInitialized = FALSE;
+ULONG PCIMaxLocalDevice;
+ULONG PCIMaxDevice;
+ULONG PCIMaxBus;
+PINSTALL_BUS_HANDLER PCIInstallHandler = HalpDefaultPCIInstallHandler;
+
+CONFIG_HANDLER PCIConfigHandlers = {
+ {
+ HalpPCIReadUlong, // 0
+ HalpPCIReadUchar, // 1
+ HalpPCIReadUshort // 2
+ },
+ {
+ HalpPCIWriteUlong, // 0
+ HalpPCIWriteUchar, // 1
+ HalpPCIWriteUshort // 2
+ }
+};
+UCHAR PCIDeref[4][4] = { {0,1,2,2},{1,1,1,1},{2,1,2,2},{1,1,1,1} };
+
+WCHAR rgzMultiFunctionAdapter[] = L"\\Registry\\Machine\\Hardware\\Description\\System\\MultifunctionAdapter";
+WCHAR rgzConfigurationData[] = L"Configuration Data";
+WCHAR rgzIdentifier[] = L"Identifier";
+WCHAR rgzPCIIndetifier[] = L"PCI";
+
+#define Is64BitBaseAddress(a) \
+ (((a & PCI_ADDRESS_IO_SPACE) == 0) && \
+ ((a & PCI_ADDRESS_MEMORY_TYPE_MASK) == PCI_TYPE_64BIT))
+
+#if !defined(AXP_FIRMWARE)
+
+VOID
+HalpRegisterPciBus(
+ IN PCONFIGURATION_COMPONENT Component,
+ IN PVOID ConfigurationData
+ )
+/*++
+
+Routine Description:
+
+ This function uses information obtained from the ARC configuration
+ tree to create PCI bus handlers. If configuration data was passed
+ with the PCI component, then that information is used to create the
+ bus handler. Otherwise, we use a priori knowledge (and bus scanning)
+ to generate the bus handler data. This function supports firmware
+ that both provide and do not provide configuration data payloads.
+
+Arguments:
+
+ Component - The ARC configuration component for this bus.
+
+ ConfigurationData - The configuration data payload (or NULL).
+
+Return Value:
+
+ None.
+
+--*/
+{
+ BOOLEAN ConfigurationDataPresent;
+ ARC_PCI_CONFIGURATION ArcPciConfiguration;
+ ULONG BusNumber;
+ ULONG HwBusNumber;
+ BOOLEAN BusIsAcrossPPB;
+ PBUS_HANDLER BusHandler;
+ PPCIPBUSDATA BusData;
+ RTL_BITMAP DevicePresent;
+ PCI_SLOT_NUMBER SlotNumber;
+ ULONG DeviceNumber;
+ ULONG FunctionNumber;
+ PCI_COMMON_CONFIG CommonConfig;
+ PCI_SLOT_NUMBER Dummy;
+
+ memset(&Dummy, 0, sizeof(PCI_SLOT_NUMBER) );
+
+ //
+ // Ascertain whether the ARC firmware provided configuration data as part
+ // of the multi-function adapter component.
+ //
+
+ ConfigurationDataPresent = Component->ConfigurationDataLength != 0;
+
+ //
+ // If configuration data was provided use it to allocate and initialize
+ // the handler for this bus. Otherwise, use a priori knowledge to
+ // generate reasonable values.
+ //
+
+ if (ConfigurationDataPresent) {
+
+ //
+ // Copy the configuration data from the component.
+ //
+
+ RtlCopyMemory(
+ &ArcPciConfiguration,
+ ConfigurationData,
+ sizeof (ARC_PCI_CONFIGURATION)
+ );
+
+ //
+ // Use the values provided.
+ //
+
+ BusNumber = ArcPciConfiguration.BusNumber;
+ HwBusNumber = ArcPciConfiguration.HwBusNumber;
+ BusIsAcrossPPB = ArcPciConfiguration.BusIsAcrossPPB;
+
+ //
+ // Despite its name, PCIMaxBus is really the number of busses present
+ // in the system.
+ //
+
+ if (PCIMaxBus < BusNumber + 1) {
+ PCIMaxBus = BusNumber + 1;
+ }
+
+ } else {
+
+ //
+ // PCIMaxBus keeps a running count of the number of busses seen up
+ // to this point. Use the current value as the bus number and advance
+ // the counter. Set HwBusNumber and BusIsAcrossPPB to reasonable
+ // values.
+ //
+
+ BusNumber = PCIMaxBus++;
+ HwBusNumber = 0;
+ BusIsAcrossPPB = BusNumber != 0;
+
+ }
+
+ //
+ // Allocate and initialize the handler for this bus. N.B. device-present
+ // checking is disabled at this point. We will enable it below.
+ //
+
+ BusHandler = HalpAllocateAndInitPCIBusHandler(
+ BusNumber,
+ HwBusNumber,
+ BusIsAcrossPPB,
+ 0, // MS here
+ Dummy // MS here
+ );
+
+ //
+ // Get a pointer to the bus-specific data.
+ //
+
+ BusData = (PPCIPBUSDATA)BusHandler->BusData;
+
+ //
+ // Compute the device-present bitmap for this bus. If configuration
+ // data is present then the bitmap has been pre-computed for us by the
+ // firmware. In this case, use the bitmap provided. otherwise, we
+ // have to do the work now of generating the bitmap.
+ //
+
+ if (ConfigurationDataPresent) {
+
+ //
+ // Initialize the device-present bitmap for this bus.
+ //
+
+ RtlInitializeBitMap(
+ &BusData->DevicePresent,
+ BusData->DevicePresentBits,
+ PCI_MAX_DEVICES * PCI_MAX_FUNCTION
+ );
+
+ //
+ // The firmware has already computed the device-present bitmap for
+ // us. Copy the bitmap from the configuration data.
+ //
+
+ RtlCopyMemory(
+ BusData->DevicePresentBits,
+ ArcPciConfiguration.DevicePresentBits,
+ sizeof (BusData->DevicePresentBits)
+ );
+
+
+ } else {
+
+ //
+ // Initialize a bitmap which we will use to accumulate the results
+ // of the device-present scan. N.B. Device-present checking is
+ // currently disabled.
+ //
+
+ RtlInitializeBitMap(
+ &DevicePresent,
+ BusData->DevicePresentBits,
+ PCI_MAX_DEVICES * PCI_MAX_FUNCTION
+ );
+
+ RtlClearBits(
+ &DevicePresent,
+ 0,
+ PCI_MAX_DEVICES * PCI_MAX_FUNCTION
+ );
+
+ //
+ // Initialize the slot number.
+ //
+
+ SlotNumber.u.AsULONG = 0;
+
+ //
+ // Loop through each device number.
+ //
+
+ for (DeviceNumber = 0;
+ DeviceNumber < PCI_MAX_DEVICES;
+ DeviceNumber++) {
+
+ SlotNumber.u.bits.DeviceNumber = DeviceNumber;
+
+ //
+ // Loop through each function number.
+ //
+
+ for (FunctionNumber = 0;
+ FunctionNumber < PCI_MAX_FUNCTION;
+ FunctionNumber++) {
+
+ SlotNumber.u.bits.FunctionNumber = FunctionNumber;
+
+ //
+ // Read the common configuration header.
+ //
+
+ HalpReadPCIConfig(
+ BusHandler,
+ SlotNumber,
+ &CommonConfig,
+ 0,
+ PCI_COMMON_HDR_LENGTH
+ );
+
+ //
+ // If the Vendor ID is invalid, then no device is present
+ // at this device/function number.
+ //
+
+ if (CommonConfig.VendorID == PCI_INVALID_VENDORID) {
+ if (FunctionNumber == 0) {
+ break;
+ }
+ continue;
+ }
+
+ //
+ // Set a bit indicating a device is present.
+ //
+
+ RtlSetBits(
+ &DevicePresent,
+ PciBitIndex(DeviceNumber, FunctionNumber),
+ 1
+ );
+
+ //
+ // If this is not a multi-function device, then terminate
+ // the function number loop.
+ //
+
+ if ((CommonConfig.HeaderType & PCI_MULTIFUNCTION) == 0) {
+ break;
+ }
+ }
+ }
+
+ //
+ // Enable device-present checking.
+ //
+
+ BusData->DevicePresent = DevicePresent;
+ }
+}
+
+#endif
+
+#if !defined(AXP_FIRMWARE)
+
+VOID
+HalpQueryPciBusConfiguration(
+ IN PCONFIGURATION_COMPONENT_DATA Root
+ )
+/*++
+
+Routine Description:
+
+ This function loops through each multi-function adapter component
+ in the ARC configuration tree and calls HalpRegisterPciBus() to create
+ a bus handler for it.
+
+Arguments:
+
+ Root - The root of the ARC configuration tree.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONG Key;
+ PCONFIGURATION_COMPONENT_DATA Adapter;
+
+ //
+ // Loop through each multi-function adapter component in the ARC
+ // configuration tree.
+ //
+
+ for (Key = 0; TRUE; Key++) {
+
+ //
+ // Get a pointer to the component data.
+ //
+
+ Adapter = KeFindConfigurationEntry(
+ Root,
+ AdapterClass,
+ MultiFunctionAdapter,
+ &Key
+ );
+
+ //
+ // If there are no more multi-function adapters in the ARC
+ // configuration tree, then we're done.
+ //
+
+ if (Adapter == NULL) {
+ break;
+ }
+
+ //
+ // Ascertain whether this is a PCI multi-function adapter component.
+ // If so, register a bus handler for it.
+ //
+
+ if (_stricmp(Adapter->ComponentEntry.Identifier, "PCI") == 0) {
+ HalpRegisterPciBus(
+ &Adapter->ComponentEntry,
+ Adapter->ConfigurationData
+ );
+ }
+ }
+}
+
+#endif
+
+VOID
+HalpInitializePCIBus(
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+/*++
+
+Routine Description:
+
+ The function intializes global PCI bus state from the registry.
+
+ The Arc firmware is responsible for building configuration information
+ about the number of PCI buses on the system and nature (local vs. secondary
+ - across a PCI-PCI bridge) of the each bus.
+
+ The maximum virtual slot number on the local (type 0 config cycle)
+ PCI bus is registered here, based on the machine dependent define
+ PCI_MAX_LOCAL_DEVICE. This state is carried in PCIMaxLocalDevice.
+
+ The maximum number of virtual slots on a secondary bus is fixed by the
+ PCI Specification and is represented by PCI_MAX_DEVICES. This
+ state is held in PCIMaxDevice.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ //
+ // Only initialize the PCI subsystem once.
+ //
+
+ if (PCIInitialized) {
+ return;
+ }
+
+ //
+ // Initialize PCI subsystem variables.
+ //
+
+#ifdef AXP_FIRMWARE
+ PCIMaxBus = PCI_MAX_BUSSES;
+#else
+ PCIMaxBus = 0;
+#endif
+ PCIMaxLocalDevice = PCI_MAX_LOCAL_DEVICE;
+ PCIMaxDevice = PCI_MAX_DEVICES - 1;
+
+ //
+ // Initialize the PCI configuration spinlock.
+ //
+
+ KeInitializeSpinLock(&HalpPCIConfigLock);
+
+#if !AXP_FIRMWARE
+
+ //
+ // Consult the ARC configuration tree and register bus handlers for
+ // all PCI multi-function adapter nodes.
+ //
+
+ HalpQueryPciBusConfiguration(LoaderBlock->ConfigurationRoot);
+
+#endif
+
+ //
+ // The PCI subsystem has been initialized.
+ //
+
+ PCIInitialized = TRUE;
+}
+
+PBUS_HANDLER
+HalpAllocateAndInitPCIBusHandler (
+ IN ULONG BusNo,
+ IN ULONG HwBusNo,
+ IN BOOLEAN BusIsAcrossPPB,
+ IN ULONG PPBBusNumber,
+ IN PCI_SLOT_NUMBER PPBSlotNumber
+ )
+{
+ PBUS_HANDLER Bus;
+ PPCIPBUSDATA BusData;
+
+ HaliRegisterBusHandler (
+ PCIBus, // Interface type
+ PCIConfiguration, // Has this configuration space
+ BusNo, // Bus Number
+ Internal, // child of this bus
+ 0, // and number
+ sizeof (PCIPBUSDATA), // sizeof bus specific buffer
+ PCIInstallHandler, // PCI install handler
+ &Bus); // Bushandler return
+
+ BusData = (PPCIPBUSDATA) Bus->BusData;
+ BusData->HwBusNumber = HwBusNo;
+ BusData->BusIsAcrossPPB = BusIsAcrossPPB;
+ BusData->PPBBusNumber = PPBBusNumber;
+ BusData->PPBSlotNumber = PPBSlotNumber;
+
+ return Bus;
+}
+
+NTSTATUS
+HalpDefaultPCIInstallHandler(
+ IN PBUS_HANDLER Bus
+ )
+{
+ PPCIPBUSDATA BusData;
+
+
+ //
+ // Fill in PCI handlers
+ //
+
+ Bus->GetBusData = (PGETSETBUSDATA) HalpGetPCIData;
+ Bus->SetBusData = (PGETSETBUSDATA) HalpSetPCIData;
+ Bus->AdjustResourceList = (PADJUSTRESOURCELIST) HalpAdjustPCIResourceList;
+ Bus->AssignSlotResources = (PASSIGNSLOTRESOURCES) HalpAssignPCISlotResources;
+
+ BusData = (PPCIPBUSDATA) Bus->BusData;
+
+ //
+ // Fill in common PCI data
+ //
+
+ BusData->CommonData.Tag = PCI_DATA_TAG;
+ BusData->CommonData.Version = PCI_DATA_VERSION;
+ BusData->CommonData.ReadConfig = (PciReadWriteConfig)HalpReadPCIConfig;
+ BusData->CommonData.WriteConfig = (PciReadWriteConfig)HalpWritePCIConfig;
+ BusData->CommonData.Pin2Line = (PciPin2Line)HalpPCIPin2LineNop;
+ BusData->CommonData.Line2Pin = (PciLine2Pin)HalpPCILine2PinNop;
+
+
+ // set defaults
+ //
+ // ecrfix - if we knew more about the PCI bus at this
+ // point (e.g., local vs. across bridge, PCI config
+ // space base QVA, APECS vs. Sable T2/T4 vs. LCA4 vs. ??? config
+ // cycle type 0 mechanism), we could put this info into
+ // the "BusData" structure. The nice thing about this is
+ // that we could eliminate the platform-dependent module
+ // PCIBUS.C.
+ //
+
+ BusData->MaxDevice = PCI_MAX_DEVICES - 1; // not currently used anywhere
+
+ return STATUS_SUCCESS;
+}
+
+VOID
+HalpRegisterPCIInstallHandler(
+ IN PINSTALL_BUS_HANDLER MachineSpecificPCIInstallHandler
+)
+/*++
+
+Routine Description:
+
+ The function register's a machine-specific PCI Install Handler.
+ This allows a specific platform to override the default PCI install
+ handler, DefaultPCIInstallHandler().
+
+Arguments:
+
+ MachineSpecificPCIInstallHandler - Function that provides machine
+ specific PCI Bus Handler setup.
+
+Return Value:
+
+ None.
+
+
+--*/
+{
+ PCIInstallHandler = MachineSpecificPCIInstallHandler;
+
+ return;
+}
+
+ULONG
+HalpGetPCIData (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG Slot,
+ IN PUCHAR Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ The function returns the PCI bus data for a device.
+
+Arguments:
+
+ BusHandler - Registered BUS_HANDLER for the target configuration space
+
+ RootHandler - Register BUS_HANDLER for the orginating HalGetBusData request.
+
+ VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word)
+
+ 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.
+
+ If this PCI slot has never been set, then the configuration information
+ returned is zeroed.
+
+
+--*/
+{
+ PPCI_COMMON_CONFIG PciData;
+ UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
+ ULONG Len;
+ PCI_SLOT_NUMBER PciSlot;
+
+
+ if (Length > sizeof (PCI_COMMON_CONFIG)) {
+ Length = sizeof (PCI_COMMON_CONFIG);
+ }
+
+ Len = 0;
+ PciData = (PPCI_COMMON_CONFIG) iBuffer;
+ PciSlot = *((PPCI_SLOT_NUMBER) &Slot);
+
+ if (Offset >= PCI_COMMON_HDR_LENGTH) {
+ //
+ // The user did not request any data from the common
+ // header. Verify the PCI device exists, then continue
+ // in the device specific area.
+ //
+
+ HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, sizeof(ULONG));
+
+ //
+ // Check for invalid slot
+ //
+
+ if (PciData->VendorID == PCI_INVALID_VENDORID) {
+ return 0;
+ }
+
+ } else {
+
+ //
+ // Caller requested at least some data within the
+ // common header. Read the whole header, effect the
+ // fields we need to and then copy the user's requested
+ // bytes from the header
+ //
+
+ //
+ // Read this PCI devices slot data
+ //
+
+ Len = PCI_COMMON_HDR_LENGTH;
+ HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, Len);
+
+ //
+ // Check for invalid slot
+ //
+
+ if (PciData->VendorID == PCI_INVALID_VENDORID) {
+ PciData->VendorID = PCI_INVALID_VENDORID;
+ Len = 2; // only return invalid id
+ }
+
+ //
+ // Copy whatever data overlaps into the callers buffer
+ //
+
+ if (Len < Offset) {
+ // no data at caller's buffer
+ return 0;
+ }
+
+ Len -= Offset;
+ if (Len > Length) {
+ Len = Length;
+ }
+
+ RtlMoveMemory(Buffer, iBuffer + Offset, Len);
+
+ Offset += Len;
+ Buffer += Len;
+ Length -= Len;
+ }
+
+ if (Length) {
+ if (Offset >= PCI_COMMON_HDR_LENGTH) {
+ //
+ // The remaining Buffer comes from the Device Specific
+ // area - put on the kitten gloves and read from it.
+ //
+ // Specific read/writes to the PCI device specific area
+ // are guarenteed:
+ //
+ // Not to read/write any byte outside the area specified
+ // by the caller. (this may cause WORD or BYTE references
+ // to the area in order to read the non-dword aligned
+ // ends of the request)
+ //
+ // To use a WORD access if the requested length is exactly
+ // a WORD long.
+ //
+ // To use a BYTE access if the requested length is exactly
+ // a BYTE long.
+ //
+
+ HalpReadPCIConfig (BusHandler, PciSlot, Buffer, Offset, Length);
+ Len += Length;
+ }
+ }
+
+ return Len;
+}
+
+ULONG
+HalpSetPCIData (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG Slot,
+ IN PUCHAR Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+
+ The function returns the Pci bus data for a device.
+
+Arguments:
+
+ BusHandler - Registered BUS_HANDLER for the target configuration space
+
+ RootHandler - Register BUS_HANDLER for the orginating HalSetBusData request.
+
+ VendorSpecificDevice - The VendorID (low Word) and DeviceID (High Word)
+
+ 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.
+
+--*/
+{
+ PPCI_COMMON_CONFIG PciData, PciData2;
+ UCHAR iBuffer[PCI_COMMON_HDR_LENGTH];
+ UCHAR iBuffer2[PCI_COMMON_HDR_LENGTH];
+ ULONG Len;
+ PCI_SLOT_NUMBER PciSlot;
+
+
+ if (Length > sizeof (PCI_COMMON_CONFIG)) {
+ Length = sizeof (PCI_COMMON_CONFIG);
+ }
+
+
+ Len = 0;
+ PciData = (PPCI_COMMON_CONFIG) iBuffer;
+ PciData2 = (PPCI_COMMON_CONFIG) iBuffer2;
+ PciSlot = *((PPCI_SLOT_NUMBER) &Slot);
+
+
+ if (Offset >= PCI_COMMON_HDR_LENGTH) {
+ //
+ // The user did not request any data from the common
+ // header. Verify the PCI device exists, then continue in
+ // the device specific area.
+ //
+
+ HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, sizeof(ULONG));
+
+ if (PciData->VendorID == PCI_INVALID_VENDORID ||
+ PciData->VendorID == 0x00) {
+ return 0;
+ }
+
+ } else {
+
+ //
+ // Caller requested to set at least some data within the
+ // common header.
+ //
+
+ Len = PCI_COMMON_HDR_LENGTH;
+ HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, Len);
+ if (PciData->VendorID == PCI_INVALID_VENDORID ||
+ PciData->VendorID == 0x00) {
+
+ // no device
+ return 0;
+ }
+
+ //
+ // Copy COMMON_HDR values to buffer2, then overlay callers changes.
+ //
+
+ RtlMoveMemory (iBuffer2, iBuffer, Len);
+
+ Len -= Offset;
+ if (Len > Length) {
+ Len = Length;
+ }
+
+ RtlMoveMemory (iBuffer2+Offset, Buffer, Len);
+
+#if DBG
+ //
+ // Verify R/O fields haven't changed
+ //
+ if (PciData2->VendorID != PciData->VendorID ||
+ PciData2->DeviceID != PciData->DeviceID ||
+ PciData2->RevisionID != PciData->RevisionID ||
+ PciData2->ProgIf != PciData->ProgIf ||
+ PciData2->SubClass != PciData->SubClass ||
+ PciData2->BaseClass != PciData->BaseClass ||
+ PciData2->HeaderType != PciData->HeaderType ||
+ PciData2->BaseClass != PciData->BaseClass ||
+ PciData2->u.type0.MinimumGrant != PciData->u.type0.MinimumGrant ||
+ PciData2->u.type0.MaximumLatency != PciData->u.type0.MaximumLatency) {
+ DbgPrint ("PCI SetBusData: Read-Only configation value changed\n");
+ DbgBreakPoint ();
+ }
+#endif // DBG
+ //
+ // Set new PCI configuration
+ //
+
+ HalpWritePCIConfig (BusHandler, PciSlot, iBuffer2+Offset, Offset, Len);
+
+ Offset += Len;
+ Buffer += Len;
+ Length -= Len;
+ }
+
+ if (Length) {
+
+ if (Offset >= PCI_COMMON_HDR_LENGTH) {
+ //
+ // The remaining Buffer comes from the Device Specific
+ // area - put on the kitten gloves and write it
+ //
+ // Specific read/writes to the PCI device specific area
+ // are guarenteed:
+ //
+ // Not to read/write any byte outside the area specified
+ // by the caller. (this may cause WORD or BYTE references
+ // to the area in order to read the non-dword aligned
+ // ends of the request)
+ //
+ // To use a WORD access if the requested length is exactly
+ // a WORD long.
+ //
+ // To use a BYTE access if the requested length is exactly
+ // a BYTE long.
+ //
+
+ HalpWritePCIConfig (BusHandler, PciSlot, Buffer, Offset, Length);
+ Len += Length;
+ }
+ }
+
+ return Len;
+}
+
+VOID
+HalpPCILine2PinNop (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN PCI_SLOT_NUMBER SlotNumber,
+ IN PPCI_COMMON_CONFIG PciNewData,
+ IN PPCI_COMMON_CONFIG PciOldData
+ )
+{
+ // line-pin mappings not needed on alpha machines
+ return ;
+}
+
+VOID
+HalpPCIPin2LineNop (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN PCI_SLOT_NUMBER SlotNumber,
+ IN PPCI_COMMON_CONFIG PciData
+ )
+{
+ // line-pin mappings not needed on alpha machines
+ return ;
+}
+
+VOID
+HalpReadPCIConfig (
+ IN PBUS_HANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+{
+#if 0
+ if (!HalpValidPCISlot (BusHandler, Slot)) {
+ //
+ // Invalid SlotID return no data
+ //
+
+ RtlFillMemory (Buffer, Length, (UCHAR) -1);
+ return ;
+ }
+
+ HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
+ PCIConfigHandlers.ConfigRead);
+#endif // 0
+
+ //
+ // Read the slot, if it's valid.
+ // Otherwise, return an Invalid VendorId for a invalid slot on an existing bus
+ // or a null (zero) buffer if we have a non-existant bus.
+ //
+
+ switch (HalpValidPCISlot (BusHandler, Slot))
+ {
+
+ case ValidSlot:
+
+ HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
+ PCIConfigHandlers.ConfigRead);
+ break;
+
+ case InvalidSlot:
+
+ //
+ // Invalid SlotID return no data (Invalid Slot ID = 0xFFFF)
+ //
+
+ RtlFillMemory (Buffer, Length, (UCHAR) -1);
+ break ;
+
+ case InvalidBus:
+
+ //
+ // Invalid Bus, return return no data
+ //
+
+ RtlFillMemory (Buffer, Length, (UCHAR) 0);
+ break ;
+ }
+
+ return;
+
+}
+
+VOID
+HalpWritePCIConfig (
+ IN PBUS_HANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ )
+{
+
+ if (HalpValidPCISlot (BusHandler, Slot) != ValidSlot) {
+ //
+ // Invalid SlotID do nothing
+ //
+ return ;
+ }
+
+ HalpPCIConfig (BusHandler, Slot, (PUCHAR) Buffer, Offset, Length,
+ PCIConfigHandlers.ConfigWrite);
+}
+
+VALID_SLOT
+HalpValidPCISlot (
+ IN PBUS_HANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot
+ )
+{
+ ULONG BusNumber;
+ PPCIPBUSDATA BusData;
+ PCI_SLOT_NUMBER Slot2;
+ PCI_CONFIGURATION_TYPES PciConfigType;
+ UCHAR HeaderType;
+ ULONG i, bit;
+
+ BusNumber = BusHandler->BusNumber;
+ BusData = (PPCIPBUSDATA) BusHandler->BusData;
+
+ if (Slot.u.bits.Reserved != 0) {
+ return FALSE;
+ }
+
+ //
+ // If the initial device probe has been completed and no device
+ // is present for this slot then simply return invalid slot.
+ //
+
+ bit = PciBitIndex(Slot.u.bits.DeviceNumber, Slot.u.bits.FunctionNumber);
+
+ if( ( (BusData->DevicePresent).Buffer != NULL) &&
+ !RtlCheckBit(&BusData->DevicePresent, bit) ) {
+
+ return InvalidSlot;
+ }
+
+
+ //
+ // Get the config cycle type for the proposed bus.
+ // (PciConfigTypeInvalid indicates a non-existent bus.)
+ //
+
+ PciConfigType = HalpPCIConfigCycleType(BusHandler);
+
+ //
+ // The number of devices allowed on a local PCI bus may be different
+ // than that across a PCI-PCI bridge.
+ //
+
+ switch(PciConfigType) {
+ case PciConfigType0:
+
+ if (Slot.u.bits.DeviceNumber > PCIMaxLocalDevice) {
+#if HALDBG
+ DbgPrint("Invalid local PCI Slot %x\n", Slot.u.bits.DeviceNumber);
+#endif
+ return InvalidSlot;
+ }
+ break;
+
+ case PciConfigType1:
+
+ if (Slot.u.bits.DeviceNumber > PCIMaxDevice) {
+#if HALDBG
+ DbgPrint("Invalid remote PCI Slot %x\n", Slot.u.bits.DeviceNumber);
+#endif
+ return InvalidSlot;
+ }
+ break;
+
+ case PciConfigTypeInvalid:
+
+#if HALDBG
+ DbgPrint("Invalid PCI Bus %x\n", BusNumber);
+#endif
+ return InvalidBus;
+ break;
+
+ }
+
+ //
+ // Check function number
+ //
+
+ if (Slot.u.bits.FunctionNumber == 0) {
+ return ValidSlot;
+ }
+
+ //
+ // Non zero function numbers are only supported if the
+ // device has the PCI_MULTIFUNCTION bit set in it's header
+ //
+
+ i = Slot.u.bits.DeviceNumber;
+
+ //
+ // Read DeviceNumber, Function zero, to determine if the
+ // PCI supports multifunction devices
+ //
+
+ Slot2 = Slot;
+ Slot2.u.bits.FunctionNumber = 0;
+
+ HalpReadPCIConfig (
+ BusHandler,
+ Slot2,
+ &HeaderType,
+ FIELD_OFFSET (PCI_COMMON_CONFIG, HeaderType),
+ sizeof (UCHAR)
+ );
+
+ if (!(HeaderType & PCI_MULTIFUNCTION) || (HeaderType == 0xFF)) {
+ // this device doesn't exists or doesn't support MULTIFUNCTION types
+ return InvalidSlot;
+ }
+
+ return ValidSlot;
+}
+
+VOID
+HalpPCIConfig (
+ IN PBUS_HANDLER BusHandler,
+ IN PCI_SLOT_NUMBER Slot,
+ IN PUCHAR Buffer,
+ IN ULONG Offset,
+ IN ULONG Length,
+ IN FncConfigIO *ConfigIO
+ )
+{
+ KIRQL OldIrql;
+ ULONG i;
+ PCI_CFG_CYCLE_BITS PciAddr;
+ ULONG BusNumber;
+
+ //
+ // Setup platform-dependent state for configuration space access
+ //
+
+ HalpPCIConfigAddr(BusHandler, Slot, &PciAddr);
+
+ //
+ // Synchronize with PCI config space
+ //
+
+ KeAcquireSpinLock (&HalpPCIConfigLock, &OldIrql);
+
+ //
+ // Do the I/O to PCI configuration space
+ //
+
+ while (Length) {
+ i = PCIDeref[Offset % sizeof(ULONG)][Length % sizeof(ULONG)];
+ i = ConfigIO[i] (&PciAddr, Buffer, Offset);
+
+ Offset += i;
+ Buffer += i;
+ Length -= i;
+ }
+
+ //
+ // Release spinlock
+ //
+
+ KeReleaseSpinLock (&HalpPCIConfigLock, OldIrql);
+
+ return;
+}
+
+ULONG
+HalpPCIReadUchar (
+ IN PPCI_CFG_CYCLE_BITS PciCfg,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ ULONG ConfigurationCycleType;
+
+ //
+ // The configuration cycle type is extracted from bits[1:0] of PciCfg.
+ //
+ // Since an LCA4 register generates the configuration cycle type
+ // on the PCI bus, and because Offset bits[1:0] are used to
+ // generate the PCI byte enables (C/BE[3:0]), clear PciCfg bits [1:0]
+ // out before adding in Offset.
+ //
+
+ ConfigurationCycleType = PciCfg->u.bits.Reserved1;
+ PciCfg->u.bits.Reserved1 = 0;
+
+ *Buffer = READ_CONFIG_UCHAR ((PUCHAR) (PciCfg->u.AsULONG + Offset),
+ ConfigurationCycleType);
+
+ //
+ // Reset state to preserve config cycle type across calls
+ //
+
+ PciCfg->u.bits.Reserved1 = ConfigurationCycleType;
+
+ return sizeof (UCHAR);
+}
+
+ULONG
+HalpPCIReadUshort (
+ IN PPCI_CFG_CYCLE_BITS PciCfg,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ ULONG ConfigurationCycleType;
+
+ ConfigurationCycleType = PciCfg->u.bits.Reserved1;
+ PciCfg->u.bits.Reserved1 = 0;
+
+ *((PUSHORT) Buffer) = READ_CONFIG_USHORT ((PUSHORT) (PciCfg->u.AsULONG + Offset),
+ ConfigurationCycleType);
+ //
+ // Reset state to preserve config cycle type across calls
+ //
+
+ PciCfg->u.bits.Reserved1 = ConfigurationCycleType;
+
+ return sizeof (USHORT);
+}
+
+ULONG
+HalpPCIReadUlong (
+ IN PPCI_CFG_CYCLE_BITS PciCfg,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ ULONG ConfigurationCycleType;
+
+ ConfigurationCycleType = PciCfg->u.bits.Reserved1;
+ PciCfg->u.bits.Reserved1 = 0;
+
+ *((PULONG) Buffer) = READ_CONFIG_ULONG ((PULONG) (PciCfg->u.AsULONG + Offset),
+ ConfigurationCycleType);
+ //
+ // Reset state to preserve config cycle type across calls
+ //
+
+ PciCfg->u.bits.Reserved1 = ConfigurationCycleType;
+
+ return sizeof (ULONG);
+}
+
+
+ULONG
+HalpPCIWriteUchar (
+ IN PPCI_CFG_CYCLE_BITS PciCfg,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ ULONG ConfigurationCycleType;
+
+ ConfigurationCycleType = PciCfg->u.bits.Reserved1;
+ PciCfg->u.bits.Reserved1 = 0;
+
+ WRITE_CONFIG_UCHAR ((PUCHAR) (PciCfg->u.AsULONG + Offset), *Buffer,
+ ConfigurationCycleType);
+ //
+ // Reset state to preserve config cycle type across calls
+ //
+
+ PciCfg->u.bits.Reserved1 = ConfigurationCycleType;
+
+ return sizeof (UCHAR);
+}
+
+ULONG
+HalpPCIWriteUshort (
+ IN PPCI_CFG_CYCLE_BITS PciCfg,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ ULONG ConfigurationCycleType;
+
+ ConfigurationCycleType = PciCfg->u.bits.Reserved1;
+ PciCfg->u.bits.Reserved1 = 0;
+
+ WRITE_CONFIG_USHORT ((PUSHORT) (PciCfg->u.AsULONG + Offset), *((PUSHORT) Buffer),
+ ConfigurationCycleType);
+ //
+ // Reset state to preserve config cycle type across calls
+ //
+
+ PciCfg->u.bits.Reserved1 = ConfigurationCycleType;
+
+ return sizeof (USHORT);
+}
+
+ULONG
+HalpPCIWriteUlong (
+ IN PPCI_CFG_CYCLE_BITS PciCfg,
+ IN PUCHAR Buffer,
+ IN ULONG Offset
+ )
+{
+ ULONG ConfigurationCycleType;
+
+ ConfigurationCycleType = PciCfg->u.bits.Reserved1;
+ PciCfg->u.bits.Reserved1 = 0;
+
+ WRITE_CONFIG_ULONG ((PULONG) (PciCfg->u.AsULONG + Offset), *((PULONG) Buffer),
+ ConfigurationCycleType);
+ //
+ // Reset state to preserve config cycle type across calls
+ //
+
+ PciCfg->u.bits.Reserved1 = ConfigurationCycleType;
+
+ return sizeof (ULONG);
+}
+
+#if DBG
+
+BOOLEAN
+HalpValidPCIAddr(
+ IN PBUS_HANDLER BusHandler,
+ IN PHYSICAL_ADDRESS BAddr,
+ IN ULONG Length,
+ IN ULONG AddressSpace)
+/*++
+
+Routine Description:
+
+ Checks to see that the begining and ending 64 bit PCI bus addresses
+ of the 32 bit range of length Length are supported on the system.
+
+Arguments:
+
+ BAddr - the 64 bit starting address
+
+ Length - a 32 bit length
+
+ AddressSpace - is this I/O (1) or memory space (0)
+
+Return Value:
+
+ TRUE or FALSE
+
+--*/
+{
+ PHYSICAL_ADDRESS EAddr, TBAddr, TEAddr;
+ LARGE_INTEGER LiILen;
+ ULONG inIoSpace, inIoSpace2;
+ BOOLEAN flag, flag2;
+ ULONG BusNumber;
+
+ BusNumber = BusHandler->BusNumber;
+
+ //
+ // Translated address to system global setting and verify
+ // resource is available.
+ //
+ // Note that this code will need to be changed to support
+ // 64 bit PCI bus addresses.
+ //
+
+ LiILen.QuadPart = (ULONG)(Length - 1); // Inclusive length
+ EAddr.QuadPart = BAddr.QuadPart + LiILen.QuadPart;
+
+ inIoSpace = inIoSpace2 = AddressSpace;
+
+ flag = HalTranslateBusAddress ( PCIBus,
+ BusNumber,
+ BAddr,
+ &inIoSpace,
+ &TBAddr
+ );
+
+ flag2 = HalTranslateBusAddress (PCIBus,
+ BusNumber,
+ EAddr,
+ &inIoSpace2,
+ &TEAddr
+ );
+
+ if (flag == FALSE || flag2 == FALSE || inIoSpace != inIoSpace2) {
+
+ //
+ // HalAdjustResourceList should ensure that the returned range
+ // for the bus is within the bus limits and no translation
+ // within those limits should ever fail
+ //
+
+ DbgPrint ("HalpValidPCIAddr: Error return for HalTranslateBusAddress %x.%x:%x %x.%x:%x\n",
+ BAddr.HighPart, BAddr.LowPart, flag,
+ EAddr.HighPart, EAddr.LowPart, flag2);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+#endif
+
+
+NTSTATUS
+HalpAssignPCISlotResources (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN PUNICODE_STRING RegistryPath,
+ IN PUNICODE_STRING DriverClassName OPTIONAL,
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT DeviceObject OPTIONAL,
+ IN ULONG Slot,
+ IN OUT PCM_RESOURCE_LIST *pAllocatedResources
+ )
+/*++
+
+Routine Description:
+
+ Reads the targeted device to determine the firmwaire-assigned resources.
+ Calls IoReportResources to report/confirm them.
+ Returns the assignments to the caller.
+
+Arguments:
+
+Return Value:
+
+ STATUS_SUCCESS or error
+
+--*/
+{
+ NTSTATUS status;
+ PUCHAR WorkingPool;
+ PPCI_COMMON_CONFIG PciData, PciOrigData;
+ PCI_SLOT_NUMBER PciSlot;
+
+ PCM_RESOURCE_LIST CmRes;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDesc;
+ PHYSICAL_ADDRESS BAddr;
+ ULONG addr;
+ ULONG Command;
+ ULONG cnt, len;
+ BOOLEAN conflict;
+
+ ULONG i, j, m, length, holdvalue;
+ ULONG BusNumber;
+
+ BusNumber = BusHandler->BusNumber;
+
+ *pAllocatedResources = NULL;
+ PciSlot = *((PPCI_SLOT_NUMBER) &Slot);
+
+ //
+ // Allocate some pool for working space
+ //
+
+ i = sizeof (CM_RESOURCE_LIST) +
+ sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) +
+ PCI_COMMON_HDR_LENGTH * 2;
+
+ WorkingPool = (PUCHAR) ExAllocatePool (PagedPool, i);
+ if (!WorkingPool) {
+ return STATUS_NO_MEMORY;
+ }
+
+ //
+ // Zero initialize pool, and get pointers into memory - here we allocate
+ // a single chunk of memory and partition it into three pieces, pointed
+ // to by three separate pointers.
+ //
+
+ RtlZeroMemory (WorkingPool, i);
+ CmRes = (PCM_RESOURCE_LIST) WorkingPool;
+ PciData = (PPCI_COMMON_CONFIG)(WorkingPool + i - PCI_COMMON_HDR_LENGTH * 2);
+ PciOrigData = (PPCI_COMMON_CONFIG)(WorkingPool + i - PCI_COMMON_HDR_LENGTH);
+
+ //
+ // Read the PCI device configuration
+ //
+
+ HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
+ if (PciData->VendorID == PCI_INVALID_VENDORID || // empty slot
+ PciData->VendorID == 0x00) { // non-existant bus
+ ExFreePool (WorkingPool);
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ //
+ // Make a copy of the devices current settings
+ //
+
+ RtlMoveMemory (PciOrigData, PciData, PCI_COMMON_HDR_LENGTH);
+
+ //
+ // Set resources to all bits on to see what type of resources
+ // are required.
+ //
+
+ for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
+ PciData->u.type0.BaseAddresses[j] = 0xFFFFFFFF;
+ }
+
+ PciData->u.type0.ROMBaseAddress = 0xFFFFFFFF;
+
+ PciData->Command &= ~(PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE);
+ PciData->u.type0.ROMBaseAddress &= ~PCI_ROMADDRESS_ENABLED;
+ HalpWritePCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
+ HalpReadPCIConfig (BusHandler, PciSlot, PciData, 0, PCI_COMMON_HDR_LENGTH);
+
+ //
+ // Build an CM_RESOURCE_LIST for the PCI device to report resources
+ // to IoReportResourceUsage.
+ //
+ // This code does *not* use IoAssignoResources, as the PCI
+ // address space resources have been previously assigned by the ARC firmware
+ //
+
+ CmRes->Count = 1;
+ CmRes->List[0].InterfaceType = PCIBus;
+ CmRes->List[0].BusNumber = BusNumber;
+
+ CmRes->List[0].PartialResourceList.Count = 0;
+
+ //
+ // Set current CM_RESOURCE_LIST version and revision
+ //
+
+ CmRes->List[0].PartialResourceList.Version = 0;
+ CmRes->List[0].PartialResourceList.Revision = 0;
+
+ CmDesc = CmRes->List[0].PartialResourceList.PartialDescriptors;
+
+#if DBG
+ DbgPrint ("HalAssignSlotResources: Resource List V%d.%d for slot %x:\n",
+ CmRes->List[0].PartialResourceList.Version,
+ CmRes->List[0].PartialResourceList.Revision,
+ Slot);
+
+#endif
+
+ //
+ // Interrupt resource
+ //
+
+ if (PciData->u.type0.InterruptPin) {
+
+ CmDesc->Type = CmResourceTypeInterrupt;
+ CmDesc->ShareDisposition = CmResourceShareShared;
+ CmDesc->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
+
+ CmDesc->u.Interrupt.Level = PciData->u.type0.InterruptLine;
+ CmDesc->u.Interrupt.Vector = PciData->u.type0.InterruptLine;
+
+#if DBG
+ DbgPrint (" INT Level %x, Vector %x\n",
+ CmDesc->u.Interrupt.Level, CmDesc->u.Interrupt.Vector );
+#endif
+
+ CmRes->List[0].PartialResourceList.Count++;
+ CmDesc++;
+ }
+
+ //
+ // Add a memory or port resoruce for each PCI resource
+ // (Compute the ROM address as well. Just append it to the Base
+ // Address table.)
+ //
+
+ holdvalue = PciData->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES];
+ PciData->u.type0.BaseAddresses[PCI_TYPE0_ADDRESSES] =
+ PciData->u.type0.ROMBaseAddress & ~PCI_ADDRESS_IO_SPACE;
+
+ Command = PciOrigData->Command;
+ for (j=0; j < PCI_TYPE0_ADDRESSES + 1; j++) {
+ if (PciData->u.type0.BaseAddresses[j]) {
+ addr = i = PciData->u.type0.BaseAddresses[j];
+
+ //
+ // calculate the length necessary - note there is more complicated
+ // code in the x86 HAL that probably isn't necessary
+ //
+
+ length = ~(i & ~((i & 1) ? 3 : 15)) + 1;
+
+ //
+ // I/O space resource
+ //
+
+ if (addr & PCI_ADDRESS_IO_SPACE) {
+
+ CmDesc->Type = CmResourceTypePort;
+ CmDesc->ShareDisposition = CmResourceShareDeviceExclusive;
+ CmDesc->Flags = CM_RESOURCE_PORT_IO;
+
+ BAddr.LowPart = PciOrigData->u.type0.BaseAddresses[j] & ~3;
+ BAddr.HighPart = 0;
+
+#if DBG
+ HalpValidPCIAddr(BusHandler, BAddr, length, 1); // I/O space
+#endif
+
+ CmDesc->u.Port.Start = BAddr;
+ CmDesc->u.Port.Length = length;
+ Command |= PCI_ENABLE_IO_SPACE;
+#if DBG
+ DbgPrint (" IO Start %x:%08x, Len %x\n",
+ CmDesc->u.Port.Start.HighPart, CmDesc->u.Port.Start.LowPart,
+ CmDesc->u.Port.Length );
+#endif
+ //
+ // Memory space resource
+ //
+
+ } else {
+
+ CmDesc->Type = CmResourceTypeMemory;
+ CmDesc->ShareDisposition = CmResourceShareDeviceExclusive;
+
+ if (j == PCI_TYPE0_ADDRESSES) {
+ // this is a ROM address
+ if ((PciOrigData->u.type0.ROMBaseAddress & PCI_ROMADDRESS_ENABLED) == 0) {
+ //
+ // Ignore expansion ROMs which are not enabled by
+ // the firmware/ROM BIOS.
+ //
+
+ continue;
+ }
+ CmDesc->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
+ BAddr.LowPart = PciOrigData->u.type0.ROMBaseAddress &
+ ~PCI_ROMADDRESS_ENABLED;
+ BAddr.HighPart = 0;
+ } else {
+ // this is a memory space base address
+ CmDesc->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
+ BAddr.LowPart = PciOrigData->u.type0.BaseAddresses[j] & ~15;
+ BAddr.HighPart = 0;
+ }
+
+#if DBG
+ HalpValidPCIAddr(BusHandler, BAddr, length, 0); // Memory space
+#endif
+
+ CmDesc->u.Memory.Start = BAddr;
+ CmDesc->u.Memory.Length = length;
+#if DBG
+ DbgPrint (" MEM Start %x:%08x, Len %x\n",
+ CmDesc->u.Memory.Start.HighPart, CmDesc->u.Memory.Start.LowPart,
+ CmDesc->u.Memory.Length );
+#endif
+ }
+
+ CmRes->List[0].PartialResourceList.Count++;
+ CmDesc++;
+
+ if (Is64BitBaseAddress(addr)) {
+ // skip upper half of 64 bit address since we
+ // only supports 32 bits PCI addresses for now.
+ j++;
+ }
+ }
+ }
+
+ //
+ // Setup the resource list.
+ // Count only the acquired resources.
+ //
+
+ *pAllocatedResources = CmRes;
+ cnt = CmRes->List[0].PartialResourceList.Count;
+ len = sizeof (CM_RESOURCE_LIST) +
+ cnt * sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR);
+
+#if DBG
+ DbgPrint("HalAssignSlotResources: Acq. Resourses = %d (len %x list %x\n)",
+ cnt, len, *pAllocatedResources);
+#endif
+
+ //
+ // Report the IO resource assignments
+ //
+
+ if (!DeviceObject) {
+ status = IoReportResourceUsage (
+ DriverClassName,
+ DriverObject, // DriverObject
+ *pAllocatedResources, // DriverList
+ len, // DriverListSize
+ DeviceObject, // DeviceObject
+ NULL, // DeviceList
+ 0, // DeviceListSize
+ FALSE, // override conflict
+ &conflict // conflicted detected
+ );
+ } else {
+ status = IoReportResourceUsage (
+ DriverClassName,
+ DriverObject, // DriverObject
+ NULL, // DriverList
+ 0, // DriverListSize
+ DeviceObject,
+ *pAllocatedResources, // DeviceList
+ len, // DeviceListSize
+ FALSE, // override conflict
+ &conflict // conflicted detected
+ );
+ }
+
+ if (NT_SUCCESS(status) && conflict) {
+
+ //
+ // IopReportResourceUsage saw a conflict?
+ //
+
+#if DBG
+ DbgPrint("HalAssignSlotResources: IoAssignResources detected a conflict: %x\n",
+ status);
+#endif
+ status = STATUS_CONFLICTING_ADDRESSES;
+ goto CleanUp;
+ }
+
+ if (!NT_SUCCESS(status)) {
+#if DBG
+ DbgPrint("HalAssignSlotResources: IoAssignResources failed: %x\n", status);
+#endif
+ goto CleanUp;
+ }
+
+ //
+ // Restore orginial data, turning on the appropiate decodes
+ //
+
+#if DBG
+ DbgPrint ("HalAssignSlotResources: IoReportResourseUsage succeeded\n");
+#endif
+
+ // enable IO & Memory decodes
+
+ PciOrigData->Command |= (USHORT) Command;
+
+ HalpWritePCIConfig (
+ BusHandler,
+ PciSlot,
+ PciOrigData,
+ 0,
+ PCI_COMMON_HDR_LENGTH
+ );
+
+#if DBG
+ DbgPrint ("HalAssignSlotResources: PCI Config Space updated with Command = %x\n",
+ Command);
+#endif
+
+CleanUp:
+ if (!NT_SUCCESS(status)) {
+
+ //
+ // Failure, if there are any allocated resources free them
+ //
+
+ i = 0;
+ if (*pAllocatedResources) {
+
+ if (!DeviceObject) {
+ status = IoReportResourceUsage (
+ DriverClassName,
+ DriverObject, // DriverObject
+ (PCM_RESOURCE_LIST) &i, // DriverList
+ sizeof (i), // DriverListSize
+ DeviceObject,
+ NULL, // DeviceList
+ 0, // DeviceListSize
+ FALSE, // override conflict
+ &conflict // conflicted detected
+ );
+ } else {
+ status = IoReportResourceUsage (
+ DriverClassName,
+ DriverObject, // DriverObject
+ NULL, // DriverList
+ 0, // DriverListSize
+ DeviceObject,
+ (PCM_RESOURCE_LIST) &i, // DeviceList
+ sizeof (i), // DeviceListSize
+ FALSE, // override conflict
+ &conflict // conflicted detected
+ );
+ }
+
+ ExFreePool (*pAllocatedResources);
+ *pAllocatedResources = NULL;
+ }
+
+ //
+ // Restore the device settings as we found them, enable memory
+ // and io decode after setting base addresses
+ //
+
+ HalpWritePCIConfig (
+ BusHandler,
+ PciSlot,
+ PciOrigData,
+ FIELD_OFFSET (PCI_COMMON_CONFIG, Status),
+ PCI_COMMON_HDR_LENGTH - FIELD_OFFSET (PCI_COMMON_CONFIG, Status)
+ );
+
+ HalpWritePCIConfig (
+ BusHandler,
+ PciSlot,
+ PciOrigData,
+ 0,
+ FIELD_OFFSET (PCI_COMMON_CONFIG, Status)
+ );
+ }
+
+ return status;
+}
+
+
+NTSTATUS
+HalpAdjustPCIResourceList (
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+ )
+/*++
+
+Routine Description:
+
+ The function adjusts a PCI pResourceList and forces it to match the
+ pre-configured values in PCI configuration space for this device.
+
+Arguments:
+
+ BusHandler - Registered BUS_HANDLER for the target configuration space
+
+ RootHandler - Register BUS_HANDLER for the orginating HalAdjustResourceList request.
+
+ pResourceList - Supplies the PIO_RESOURCE_REQUIREMENTS_LIST to be checked.
+
+Return Value:
+
+ STATUS_SUCCESS
+
+--*/
+{
+ UCHAR buffer[PCI_COMMON_HDR_LENGTH];
+ PCI_SLOT_NUMBER PciSlot;
+ PPCI_COMMON_CONFIG PciData;
+ PIO_RESOURCE_REQUIREMENTS_LIST CompleteList;
+ PIO_RESOURCE_LIST ResourceList;
+ PIO_RESOURCE_DESCRIPTOR Descriptor;
+ ULONG alt, cnt, bcnt;
+ ULONG MemoryBaseAddress, RomIndex;
+ PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1];
+
+ //
+ // Fix any requested resources for this device to be the
+ // value set in PCI configuration space for this device.
+ //
+
+ //
+ // Get PCI common configuration space for this slot
+ //
+
+ PciSlot = *((PPCI_SLOT_NUMBER) &(*pResourceList)->SlotNumber),
+ PciData = (PPCI_COMMON_CONFIG) buffer;
+
+ HalGetBusData (
+ PCIConfiguration,
+ BusHandler->BusNumber,
+ PciSlot.u.AsULONG,
+ PciData,
+ PCI_COMMON_HDR_LENGTH
+ );
+
+ if (PciData->VendorID == PCI_INVALID_VENDORID) {
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ //
+ // Copy base addresses based on configuration data type
+ //
+
+ switch (PCI_CONFIG_TYPE(PciData)) {
+ case 0 :
+ for (bcnt=0; bcnt < PCI_TYPE0_ADDRESSES; bcnt++) {
+ BaseAddress[bcnt] = &PciData->u.type0.BaseAddresses[bcnt];
+ }
+ BaseAddress[bcnt] = &PciData->u.type0.ROMBaseAddress;
+ RomIndex = bcnt;
+ break;
+ case 1:
+ for (bcnt=0; bcnt < PCI_TYPE1_ADDRESSES; bcnt++) {
+ BaseAddress[bcnt] = &PciData->u.type1.BaseAddresses[bcnt];
+ }
+ BaseAddress[bcnt] = &PciData->u.type0.ROMBaseAddress;
+ RomIndex = bcnt;
+ break;
+
+ default:
+ return STATUS_NO_SUCH_DEVICE;
+ }
+
+ //
+ // Walk each ResourceList and confine resources
+ // to preconfigured settings.
+ //
+
+ CompleteList = *pResourceList;
+ ResourceList = CompleteList->List;
+ ResourceList->Version = 1;
+ ResourceList->Revision = 1;
+
+ for (alt=0; alt < CompleteList->AlternativeLists; alt++) {
+ Descriptor = ResourceList->Descriptors;
+
+ //
+ // For each alternative list, reset to review entire
+ // set of Base Address registers
+ //
+ // We assume that the order of resource descriptors for
+ // each alternative list matches the order of the
+ // PCI configuration space base address registers
+ //
+
+ bcnt = 0;
+
+ for (cnt = ResourceList->Count; cnt; cnt--) {
+
+ //
+ // Limit desctiptor to to preconfigured setting
+ // held in the InterruptLine register.
+ //
+
+ switch (Descriptor->Type) {
+ case CmResourceTypeInterrupt:
+
+ //
+ // Confine interrupt vector to preconfigured setting.
+ //
+
+ Descriptor->u.Interrupt.MinimumVector = PciData->u.type0.InterruptLine;
+ Descriptor->u.Interrupt.MaximumVector = PciData->u.type0.InterruptLine;
+ break;
+
+ case CmResourceTypePort:
+
+ //
+ // Assure that requested descriptor is valid
+ //
+
+ if (bcnt > RomIndex) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Confine to preconfigured setting.
+ //
+
+ Descriptor->u.Port.MinimumAddress.QuadPart =
+ *BaseAddress[bcnt++] & ~0x3;
+
+ Descriptor->u.Port.MaximumAddress.QuadPart =
+ Descriptor->u.Port.MinimumAddress.QuadPart +
+ Descriptor->u.Port.Length - 1;
+
+#if HALDBG
+ DbgPrint("AdjustPCIResourceList\nPort: MinimumAddress set to %x\n",
+ Descriptor->u.Port.MinimumAddress.QuadPart);
+
+ DbgPrint(" MaximumAddress set to %x\n",
+ Descriptor->u.Port.MaximumAddress.QuadPart);
+#endif
+
+ break;
+
+ case CmResourceTypeMemory:
+
+ //
+ // Assure that requested descriptor is valid
+ //
+
+ if (bcnt > RomIndex) {
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Confine to preconfigured setting.
+ //
+
+ MemoryBaseAddress = *BaseAddress[bcnt];
+
+ if (bcnt == RomIndex) {
+ Descriptor->u.Memory.MinimumAddress.QuadPart =
+ *BaseAddress[bcnt++] & ~PCI_ROMADDRESS_ENABLED;
+ } else {
+ Descriptor->u.Memory.MinimumAddress.QuadPart =
+ *BaseAddress[bcnt++] & ~0xF;
+ }
+
+ Descriptor->u.Memory.MaximumAddress.QuadPart =
+ Descriptor->u.Memory.MinimumAddress.QuadPart +
+ Descriptor->u.Memory.Length - 1;
+
+ if (Is64BitBaseAddress(MemoryBaseAddress)) {
+ // skip upper half of 64 bit address since we
+ // only supports 32 bits PCI addresses for now.
+ bcnt++;
+ }
+
+
+#if HALDBG
+ DbgPrint("AdjustPCIResourceList\nMemory: MinimumAddress set to %x\n",
+ Descriptor->u.Memory.MinimumAddress.QuadPart);
+
+ DbgPrint(" MaximumAddress set to %x\n",
+ Descriptor->u.Memory.MaximumAddress.QuadPart);
+#endif
+ break;
+
+ case CmResourceTypeDma:
+ break;
+
+ default:
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ //
+ // Next descriptor
+ //
+ Descriptor++;
+ }
+
+ //
+ // Next Resource List
+ //
+ ResourceList = (PIO_RESOURCE_LIST) Descriptor;
+ }
+ return STATUS_SUCCESS;
+}
+
+
+#define TEST_PCI 1
+
+#if DBG && TEST_PCI
+
+VOID HalpTestPci (ULONG flag2)
+{
+ PCI_SLOT_NUMBER SlotNumber;
+ PCI_COMMON_CONFIG PciData, OrigData;
+ ULONG i, f, j, k, bus;
+ BOOLEAN flag;
+
+ if (!flag2) {
+ return ;
+ }
+
+ DbgBreakPoint ();
+ SlotNumber.u.bits.Reserved = 0;
+
+ //
+ // Read every possible PCI Device/Function and display it's
+ // default info.
+ //
+ // (note this destories it's current settings)
+ //
+
+ flag = TRUE;
+ for (bus = 0; flag; bus++) {
+
+ for (i = 0; i < 32; i++) {
+ SlotNumber.u.bits.DeviceNumber = i;
+
+ for (f = 0; f < 8; f++) {
+ SlotNumber.u.bits.FunctionNumber = f;
+
+
+ j = HalGetBusData (
+ PCIConfiguration,
+ bus,
+ SlotNumber.u.AsULONG,
+ &PciData,
+ sizeof (PciData)
+ );
+
+ if (j == 0) {
+ // out of buses
+ flag = FALSE;
+ break;
+ }
+
+ if (j < PCI_COMMON_HDR_LENGTH) {
+ continue;
+ }
+
+ HalSetBusData (
+ PCIConfiguration,
+ bus,
+ SlotNumber.u.AsULONG,
+ &PciData,
+ 1
+ );
+
+ HalGetBusData (
+ PCIConfiguration,
+ bus,
+ SlotNumber.u.AsULONG,
+ &PciData,
+ sizeof (PciData)
+ );
+
+ memcpy (&OrigData, &PciData, sizeof PciData);
+
+ for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
+ PciData.u.type0.BaseAddresses[j] = 0xFFFFFFFF;
+ }
+
+ PciData.u.type0.ROMBaseAddress = 0xFFFFFFFF;
+
+ HalSetBusData (
+ PCIConfiguration,
+ bus,
+ SlotNumber.u.AsULONG,
+ &PciData,
+ sizeof (PciData)
+ );
+
+ HalGetBusData (
+ PCIConfiguration,
+ bus,
+ SlotNumber.u.AsULONG,
+ &PciData,
+ sizeof (PciData)
+ );
+
+ DbgPrint ("PCI Bus %d Slot %2d %2d ID:%04lx-%04lx Rev:%04lx",
+ bus, i, f, PciData.VendorID, PciData.DeviceID,
+ PciData.RevisionID);
+
+ if (PciData.u.type0.InterruptPin) {
+ DbgPrint (" IntPin:%x", PciData.u.type0.InterruptPin);
+ }
+
+ if (PciData.u.type0.InterruptLine) {
+ DbgPrint (" IntLine:%x", PciData.u.type0.InterruptLine);
+ }
+
+ if (PciData.u.type0.ROMBaseAddress) {
+ DbgPrint (" ROM:%08lx", PciData.u.type0.ROMBaseAddress);
+ }
+
+ DbgPrint ("\n ProgIf:%04x SubClass:%04x BaseClass:%04lx\n",
+ PciData.ProgIf, PciData.SubClass, PciData.BaseClass);
+
+ k = 0;
+ for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
+ if (PciData.u.type0.BaseAddresses[j]) {
+ DbgPrint (" Ad%d:%08lx", j, PciData.u.type0.BaseAddresses[j]);
+ k = 1;
+ }
+ }
+
+ if (PciData.u.type0.ROMBaseAddress == 0xC08001) {
+
+ PciData.u.type0.ROMBaseAddress = 0xC00001;
+ HalSetBusData (
+ PCIConfiguration,
+ bus,
+ SlotNumber.u.AsULONG,
+ &PciData,
+ sizeof (PciData)
+ );
+
+ HalGetBusData (
+ PCIConfiguration,
+ bus,
+ SlotNumber.u.AsULONG,
+ &PciData,
+ sizeof (PciData)
+ );
+
+ DbgPrint ("\n Bogus rom address, edit yields:%08lx",
+ PciData.u.type0.ROMBaseAddress);
+ }
+ if (k) {
+ DbgPrint ("\n");
+ }
+
+ if (PciData.VendorID == 0x8086) {
+ // dump complete buffer
+ DbgPrint ("Command %x, Status %x, BIST %x\n",
+ PciData.Command, PciData.Status,
+ PciData.BIST
+ );
+
+ DbgPrint ("CacheLineSz %x, LatencyTimer %x",
+ PciData.CacheLineSize, PciData.LatencyTimer
+ );
+
+ for (j=0; j < 192; j++) {
+ if ((j & 0xf) == 0) {
+ DbgPrint ("\n%02x: ", j + 0x40);
+ }
+ DbgPrint ("%02x ", PciData.DeviceSpecific[j]);
+ }
+ DbgPrint ("\n");
+ }
+
+ //
+ // now print original data
+ //
+
+ if (OrigData.u.type0.ROMBaseAddress) {
+ DbgPrint (" oROM:%08lx", OrigData.u.type0.ROMBaseAddress);
+ }
+
+ DbgPrint ("\n");
+ k = 0;
+ for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
+ if (OrigData.u.type0.BaseAddresses[j]) {
+ DbgPrint (" oAd%d:%08lx", j, OrigData.u.type0.BaseAddresses[j]);
+ k = 1;
+ }
+ }
+
+ //
+ // Restore original settings
+ //
+
+ HalSetBusData (
+ PCIConfiguration,
+ bus,
+ SlotNumber.u.AsULONG,
+ &OrigData,
+ sizeof (PciData)
+ );
+
+ //
+ // Next
+ //
+
+ if (k) {
+ DbgPrint ("\n\n");
+ }
+ }
+ }
+
+ }
+ DbgBreakPoint();
+}
+
+#endif // DBG && TEST_PCI
diff --git a/private/ntos/nthals/halalpha/pcrtc.c b/private/ntos/nthals/halalpha/pcrtc.c
new file mode 100644
index 000000000..6e8bd954a
--- /dev/null
+++ b/private/ntos/nthals/halalpha/pcrtc.c
@@ -0,0 +1,381 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ pcrtc.c
+
+Abstract:
+
+ This module implements the HAL set/query realtime clock routines for
+ the standard pc-compatible real time clock use on Alpha AXP systems.
+
+Author:
+
+ David N. Cutler (davec) 5-May-1991
+ Jeff McLeman (mcleman) 3-Jun-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ 13-Jul-1992 Jeff McLeman
+ use VTI access routines to access clock
+
+ 3-June-1992 Jeff McLeman
+ Adapt this module into a Jensen specific module
+
+--*/
+
+#include "halp.h"
+#include "pcrtc.h"
+
+//
+// Local function prototypes.
+//
+
+BOOLEAN
+HalQueryRealTimeClock (
+ OUT PTIME_FIELDS TimeFields
+ );
+
+BOOLEAN
+HalSetRealTimeClock (
+ IN PTIME_FIELDS TimeFields
+ );
+
+UCHAR
+HalpReadClockRegister (
+ UCHAR Register
+ );
+
+VOID
+HalpWriteClockRegister (
+ UCHAR Register,
+ UCHAR Value
+ );
+
+#ifdef AXP_FIRMWARE
+
+//
+// Put these functions in the discardable text section.
+//
+
+#pragma alloc_text(DISTEXT, HalQueryRealTimeClock )
+#pragma alloc_text(DISTEXT, HalSetRealTimeClock )
+#pragma alloc_text(DISTEXT, HalpReadClockRegister )
+#pragma alloc_text(DISTEXT, HalpWriteClockRegister )
+
+#endif // AXP_FIRMWARE
+
+//
+// Define globals used to map the realtime clock address and data ports.
+//
+
+PVOID HalpRtcAddressPort = NULL;
+PVOID HalpRtcDataPort = NULL;
+
+
+BOOLEAN
+HalQueryRealTimeClock (
+ OUT PTIME_FIELDS TimeFields
+ )
+
+/*++
+
+Routine Description:
+
+ This routine queries the realtime clock.
+
+ N.B. This routine assumes that the caller has provided any required
+ synchronization to query the realtime clock information.
+
+Arguments:
+
+ TimeFields - Supplies a pointer to a time structure that receives
+ the realtime clock information.
+
+Return Value:
+
+ If the power to the realtime clock has not failed, then the time
+ values are read from the realtime clock and a value of TRUE is
+ returned. Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+
+ UCHAR DataByte;
+ BOOLEAN Status;
+ KIRQL OldIrql;
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+
+ //
+ // If the realtime clock battery is still functioning, then read
+ // the realtime clock values, and return a function value of TRUE.
+ // Otherwise, return a function value of FALSE.
+ //
+
+ DataByte = HalpReadClockRegister(RTC_CONTROL_REGISTERD);
+ if (((PRTC_CONTROL_REGISTER_D)(&DataByte))->ValidTime == 1) {
+
+ //
+ // Wait until the realtime clock is not being updated.
+ //
+
+ do {
+ DataByte = HalpReadClockRegister(RTC_CONTROL_REGISTERA);
+ } while (((PRTC_CONTROL_REGISTER_A)(&DataByte))->UpdateInProgress == 1);
+
+ //
+ // Read the realtime clock values.
+ //
+
+ TimeFields->Year = 1980 + (CSHORT)HalpReadClockRegister(RTC_YEAR);
+ TimeFields->Month = (CSHORT)HalpReadClockRegister(RTC_MONTH);
+ TimeFields->Day = (CSHORT)HalpReadClockRegister(RTC_DAY_OF_MONTH);
+ TimeFields->Weekday = (CSHORT)HalpReadClockRegister(RTC_DAY_OF_WEEK) - 1;
+ TimeFields->Hour = (CSHORT)HalpReadClockRegister(RTC_HOUR);
+ TimeFields->Minute = (CSHORT)HalpReadClockRegister(RTC_MINUTE);
+ TimeFields->Second = (CSHORT)HalpReadClockRegister(RTC_SECOND);
+ TimeFields->Milliseconds = 0;
+ Status = TRUE;
+
+ } else {
+ Status = FALSE;
+ }
+
+ KeLowerIrql(OldIrql);
+ return(Status);
+}
+
+BOOLEAN
+HalSetRealTimeClock (
+ IN PTIME_FIELDS TimeFields
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets the realtime clock.
+
+ N.B. This routine is required to provide any synchronization necessary
+ 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.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ 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.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+ DataByte = HalpReadClockRegister(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;
+
+#ifdef RTC_SQE
+
+ //
+ // If the platform requires it, make sure that the Square
+ // Wave output of the RTC is turned on.
+ //
+
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SquareWaveEnable = 1;
+
+#endif //RTC_SQE
+
+ HalpWriteClockRegister(RTC_CONTROL_REGISTERB, DataByte);
+
+ //
+ // Write the realtime clock values.
+ //
+
+ HalpWriteClockRegister(RTC_YEAR, (UCHAR)(TimeFields->Year - 1980));
+ HalpWriteClockRegister(RTC_MONTH, (UCHAR)TimeFields->Month);
+ HalpWriteClockRegister(RTC_DAY_OF_MONTH, (UCHAR)TimeFields->Day);
+ HalpWriteClockRegister(RTC_DAY_OF_WEEK, (UCHAR)(TimeFields->Weekday + 1));
+ HalpWriteClockRegister(RTC_HOUR, (UCHAR)TimeFields->Hour);
+ HalpWriteClockRegister(RTC_MINUTE, (UCHAR)TimeFields->Minute);
+ HalpWriteClockRegister(RTC_SECOND, (UCHAR)TimeFields->Second);
+
+ //
+ // Set the realtime clock control to update the time.
+ // (Make sure periodic interrupt is enabled)
+ //
+
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SetTime = 0;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->TimerInterruptEnable = 1;
+ HalpWriteClockRegister(RTC_CONTROL_REGISTERB, DataByte);
+ KeLowerIrql(OldIrql);
+ return TRUE;
+
+ } else {
+ KeLowerIrql(OldIrql);
+ return FALSE;
+ }
+}
+
+
+UCHAR
+HalpReadClockRegister (
+ 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.
+
+--*/
+
+{
+ //
+ // Read the realtime clock register value.
+ //
+
+ WRITE_PORT_UCHAR( HalpRtcAddressPort, Register );
+
+ return READ_PORT_UCHAR( HalpRtcDataPort );
+}
+
+VOID
+HalpWriteClockRegister (
+ 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:
+
+ None
+
+--*/
+
+{
+ //
+ // Write the realtime clock register value.
+ //
+
+ WRITE_PORT_UCHAR( HalpRtcAddressPort, Register );
+
+ WRITE_PORT_UCHAR( HalpRtcDataPort, Value );
+
+ return;
+}
+
+
+VOID
+HalpProgramIntervalTimer(
+ IN ULONG RateSelect
+ )
+
+/*++
+
+Routine Description:
+
+ This function is called to program the interval timer. It is used during
+ Phase 1 initialization to start the heartbeat timer. It also used by
+ the clock interrupt interrupt routine to change the hearbeat timer rate
+ when a call to HalSetTimeIncrement has been made in the previous time slice.
+
+ On Sable the periodic interrupt comes from the square ware output of
+ the Dallas 1489A RTC on the Standard I/O board. Each processor
+ receives this clock phase shifted by at least 90 degrees from all
+ other processors. The periodic interrupt from the RTC is not used and
+ thus doesn't need to be enabled or acknowledged. Each processor has
+ its own clock interrupt latch that is cleared locally. This routine is
+ not used for Sable platforms.
+
+ Because of the phase shifting among the processors, the clock is
+ half the rate given to the RTC. So, the RTC is programmed twice
+ as fast as on a system that takes the RTC periodic interrupt in
+ directly.
+
+Arguments:
+
+ RateSelect - Supplies rate select to be placed in the clock.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR DataByte;
+
+ //
+ // Set the new rate
+ //
+ DataByte = 0;
+ ((PRTC_CONTROL_REGISTER_A)(&DataByte))->RateSelect = (UCHAR)RateSelect;
+ ((PRTC_CONTROL_REGISTER_A)(&DataByte))->TimebaseDivisor = RTC_TIMEBASE_DIVISOR;
+ HalpWriteClockRegister( RTC_CONTROL_REGISTERA, DataByte );
+
+ //
+ // Set the correct mode
+ //
+ DataByte = 0;
+#if defined(RTC_SQE)
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->SquareWaveEnable = 1;
+#else
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->TimerInterruptEnable = 1;
+#endif
+
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->HoursFormat = 1;
+ ((PRTC_CONTROL_REGISTER_B)(&DataByte))->DataMode = 1;
+ HalpWriteClockRegister( RTC_CONTROL_REGISTERB, DataByte );
+}
diff --git a/private/ntos/nthals/halalpha/pcrtc.h b/private/ntos/nthals/halalpha/pcrtc.h
new file mode 100644
index 000000000..bff457f05
--- /dev/null
+++ b/private/ntos/nthals/halalpha/pcrtc.h
@@ -0,0 +1,166 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ pcrtc.h
+
+Abstract:
+
+ This module is the header file that describes hardware structure
+ for the standard compatible PC Toy clock.
+
+Author:
+
+ David N. Cutler (davec) 3-May-1991
+ Jeff McLeman (mcleman) 4-Jun-1992
+
+Revision History:
+
+ 13-Jul-1992 Jeff McLeman
+ Add port offsets for use with VTI access routines.
+
+ 4-Jun-1992 Jeff McLeman
+ Adapt module to Jensen specific
+
+--*/
+
+#ifndef _PCRTC_
+#define _PCRTC_
+
+//
+// Define Realtime Clock register numbers.
+//
+
+#define RTC_SECOND 0 // second of minute [0..59]
+#define RTC_SECOND_ALARM 1 // seconds to alarm
+#define RTC_MINUTE 2 // minute of hour [0..59]
+#define RTC_MINUTE_ALARM 3 // minutes to alarm
+#define RTC_HOUR 4 // hour of day [0..23]
+#define RTC_HOUR_ALARM 5 // hours to alarm
+#define RTC_DAY_OF_WEEK 6 // day of week [1..7]
+#define RTC_DAY_OF_MONTH 7 // day of month [1..31]
+#define RTC_MONTH 8 // month of year [1..12]
+#define RTC_YEAR 9 // year [00..99]
+#define RTC_CONTROL_REGISTERA 10 // control register A
+#define RTC_CONTROL_REGISTERB 11 // control register B
+#define RTC_CONTROL_REGISTERC 12 // control register C
+#define RTC_CONTROL_REGISTERD 13 // control register D
+#define RTC_REGNUMBER_RTC_CR1 0x6A // control register 1
+
+#ifndef _LANGUAGE_ASSEMBLY
+
+//
+// Definitions for NT area of NVRAM
+//
+typedef struct _RTC_RAM_NT_FLAGS_0 {
+ UCHAR ConfigurationBit : 1; // Serial line console only
+ UCHAR Fill : 6;
+ UCHAR AutoRunECU : 1; // Go directly to ECU
+} RTC_RAM_NT_FLAGS_0, *PRTC_RAM_NT_FLAGS_0;
+
+#define RTC_RAM_NT_FLAGS_0_RUNARCAPP (0x80)
+#define RTC_RAM_NT_FLAGS_0_RESERVED (0x7E)
+#define RTC_RAM_NT_FLAGS_0_USECOM1FORIO (0x01)
+
+//
+// Values for RTC_RAM_CONSOLE_SELECTION
+//
+
+#define RTC_RAM_CONSOLE_SELECTION_NT 1
+#define RTC_RAM_CONSOLE_SELECTION_VMS 2
+#define RTC_RAM_CONSOLE_SELECTION_OSF 3
+
+//
+// Define Control Register A structure.
+//
+
+typedef struct _RTC_CONTROL_REGISTER_A {
+ UCHAR RateSelect : 4;
+ UCHAR TimebaseDivisor : 3;
+ UCHAR UpdateInProgress : 1;
+} RTC_CONTROL_REGISTER_A, *PRTC_CONTROL_REGISTER_A;
+
+//
+// Define Control Register B structure.
+//
+
+typedef struct _RTC_CONTROL_REGISTER_B {
+ UCHAR DayLightSavingsEnable : 1;
+ UCHAR HoursFormat : 1;
+ UCHAR DataMode : 1;
+ UCHAR SquareWaveEnable : 1;
+ UCHAR UpdateInterruptEnable : 1;
+ UCHAR AlarmInterruptEnable : 1;
+ UCHAR TimerInterruptEnable : 1;
+ UCHAR SetTime : 1;
+} RTC_CONTROL_REGISTER_B, *PRTC_CONTROL_REGISTER_B;
+
+//
+// Define Control Register C structure.
+//
+
+typedef struct _RTC_CONTROL_REGISTER_C {
+ UCHAR Fill : 4;
+ UCHAR UpdateInterruptFlag : 1;
+ UCHAR AlarmInterruptFlag : 1;
+ UCHAR TimeInterruptFlag : 1;
+ UCHAR InterruptRequest : 1;
+} RTC_CONTROL_REGISTER_C, *PRTC_CONTROL_REGISTER_C;
+
+//
+// Define Control Register D structure.
+//
+
+typedef struct _RTC_CONTROL_REGISTER_D {
+ UCHAR Fill : 7;
+ UCHAR ValidTime : 1;
+} RTC_CONTROL_REGISTER_D, *PRTC_CONTROL_REGISTER_D;
+
+//
+// Common routine for programming the interval timer
+//
+VOID
+HalpProgramIntervalTimer(
+ IN ULONG RateSelect
+ );
+
+#endif // _LANGUAGE_ASSEMBLY
+
+//
+// Define initialization values for Jensen interval timer
+// There are four different rates that are used under NT
+// (see page 9-8 of KN121 System Module Programmer's Reference)
+//
+// .976562 ms
+// 1.953125 ms
+// 3.90625 ms
+// 7.8125 ms
+//
+#define RTC_TIMEBASE_DIVISOR 0x02
+
+#define RTC_RATE_SELECT1 6
+#define RTC_RATE_SELECT2 7
+#define RTC_RATE_SELECT3 8
+#define RTC_RATE_SELECT4 9
+
+//
+// note that rates 1-3 have some rounding error,
+// since they are not expressible in even 100ns units
+//
+
+#define RTC_PERIOD_IN_CLUNKS1 9766
+#define RTC_PERIOD_IN_CLUNKS2 19531
+#define RTC_PERIOD_IN_CLUNKS3 39063
+#define RTC_PERIOD_IN_CLUNKS4 78125
+
+//
+// Defaults
+//
+#define MINIMUM_INCREMENT RTC_PERIOD_IN_CLUNKS1
+#define MAXIMUM_INCREMENT RTC_PERIOD_IN_CLUNKS4
+#define MAXIMUM_RATE_SELECT RTC_RATE_SELECT4
+
+#endif // _PCRTC_
diff --git a/private/ntos/nthals/halalpha/pcserial.c b/private/ntos/nthals/halalpha/pcserial.c
new file mode 100644
index 000000000..6d22448a6
--- /dev/null
+++ b/private/ntos/nthals/halalpha/pcserial.c
@@ -0,0 +1,596 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ pcserial.c
+
+Abstract:
+
+ This module implements the code that provides communication between
+ the kernel debugger stub and the kernel debugger via a standard
+ PC serial UART.
+
+ Stolen from ../mips/jxport.c
+
+Author:
+
+ Miche Baker-Harvey (miche) 01-June-1992
+ Jeff McLeman [DEC] 02-Feb-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Joe Notarangelo 21-Jun-1992
+ update to use super-page access to serial port so we aren't depend
+ on translation code, this will allow us to debug the translation
+ code, use serial line 2
+
+
+--*/
+
+
+#include "halp.h"
+#include "halpcsl.h"
+
+
+//
+// BUGBUG Temporarily, we use counter to do the timeout
+//
+
+#define TIMEOUT_COUNT 1024*512
+
+//
+// BUGBUG Temp until we have a configuration manager.
+//
+PUCHAR KdComPortInUse = NULL;
+BOOLEAN KdUseModemControl = FALSE;
+//
+// Define serial port read and write addresses.
+//
+PSP_READ_REGISTERS SP_READ;
+PSP_WRITE_REGISTERS SP_WRITE;
+
+//
+// Define forward referenced prototypes.
+//
+
+SP_LINE_STATUS
+KdReadLsr (
+ IN BOOLEAN WaitReason
+ );
+
+//
+// Define baud rate divisor to be used on the debugger port.
+//
+
+UCHAR HalpBaudRateDivisor = 0;
+
+
+ULONG
+HalpGetByte (
+ IN PUCHAR Input,
+ IN BOOLEAN Wait
+ )
+
+/*++
+
+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.
+
+--*/
+{
+ SP_LINE_STATUS LsrByte;
+ UCHAR DataByte;
+ ULONG TimeoutCount;
+
+ //
+ // Attempt to read a byte from the debugger port until a byte is
+ // available or until a timeout occurs.
+ //
+
+ TimeoutCount = Wait ? TIMEOUT_COUNT : 1;
+ do {
+ TimeoutCount -= 1;
+
+ //
+ // Wait until data is available in the receive buffer.
+ //
+
+ KeStallExecutionProcessor(1);
+ LsrByte = KdReadLsr(TRUE);
+ if (LsrByte.DataReady == 0) {
+ continue;
+ }
+
+ //
+ // Read input byte and store in callers buffer.
+ //
+
+ *Input = READ_PORT_UCHAR(&SP_READ->ReceiveBuffer);
+
+ //
+ // If using modem controls, then skip any incoming data while
+ // ReceiveData not set.
+ //
+
+ if (KdUseModemControl) {
+ DataByte = READ_PORT_UCHAR(&SP_READ->ModemStatus);
+ if ( ((PSP_MODEM_STATUS)&DataByte)->ReceiveDetect == 0) {
+ continue;
+ }
+ }
+
+ //
+ // Return function value as the not of the error indicators.
+ //
+
+ if (LsrByte.ParityError ||
+ LsrByte.FramingError ||
+ LsrByte.OverrunError ||
+ LsrByte.BreakIndicator) {
+ return CP_GET_ERROR;
+ }
+
+ return CP_GET_SUCCESS;
+ } while(TimeoutCount != 0);
+
+ return CP_GET_NODATA;
+
+}
+
+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:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ PCONFIGURATION_COMPONENT_DATA ConfigurationEntry;
+ UCHAR DataByte;
+ PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
+ PCM_SERIAL_DEVICE_DATA DeviceData;
+ PCM_PARTIAL_RESOURCE_LIST List;
+ ULONG MatchKey;
+ ULONG BaudClock;
+ ULONG BaudRate;
+ ULONG Remainder;
+
+
+ //
+ // Find the configuration information for the first serial port.
+ //
+
+ if (LoaderBlock != NULL) {
+ MatchKey = 0;
+ ConfigurationEntry = KeFindConfigurationEntry(LoaderBlock->ConfigurationRoot,
+ ControllerClass,
+ SerialController,
+ &MatchKey);
+
+ } else {
+ ConfigurationEntry = NULL;
+ }
+
+ if (DebugParameters->BaudRate != 0) {
+ BaudRate = DebugParameters->BaudRate;
+ } else {
+ BaudRate = 19200;
+ }
+ //
+ // If the serial configuration entry was not found or the frequency
+ // specified is not supported, then default the baud rate divisor to
+ // six, which is 19.2Kbps. Otherwise, set the baud rate divisor
+ // to the correct value for 19.2 baud communication.
+ //
+
+ BaudClock = 1843200;
+
+ if (ConfigurationEntry != NULL) {
+ List = (PCM_PARTIAL_RESOURCE_LIST)ConfigurationEntry->ConfigurationData;
+ Descriptor = &List->PartialDescriptors[List->Count];
+ DeviceData = (PCM_SERIAL_DEVICE_DATA)Descriptor;
+ if ((DeviceData->BaudClock == 1843200) ||
+ (DeviceData->BaudClock == 4233600) ||
+ (DeviceData->BaudClock == 8000000)) {
+ BaudClock = DeviceData->BaudClock;
+ }
+ }
+
+ HalpBaudRateDivisor = (UCHAR)(BaudClock / (BaudRate*16));
+
+ //
+ // round up
+ //
+ Remainder = BaudClock % (BaudRate*16);
+ if ((Remainder*2) > BaudClock) {
+ HalpBaudRateDivisor++;
+ }
+
+ //
+ // If the debugger is not being enabled, then return.
+ //
+
+ if (Initialize == FALSE) {
+ return TRUE;
+ }
+
+ //
+ // Establish pointers to serial line register structures
+ //
+
+ KdComPortInUse = (PUCHAR)HalpMapDebugPort(
+ DebugParameters->CommunicationPort,
+ (PULONG)&SP_READ,
+ (PULONG)&SP_WRITE );
+
+ //
+ // Clear the divisor latch, clear all interrupt enables, and reset and
+ // disable the FIFO's.
+ //
+
+ WRITE_PORT_UCHAR( &SP_WRITE->LineControl, 0x0 );
+ WRITE_PORT_UCHAR( &SP_WRITE->InterruptEnable, 0x0 );
+
+
+ // We shouldn't have to do anything with the FIFO here -
+
+ //
+ // Set the divisor latch and set the baud rate to 19200 baud.
+ //
+ // Note: the references to TransmitBuffer and InterruptEnable are
+ // actually the Divisor Latch LSB and MSB registers respectively
+ DataByte = 0;
+ ((PSP_LINE_CONTROL)(&DataByte))->DivisorLatch = 1;
+ WRITE_PORT_UCHAR(&SP_WRITE->LineControl, DataByte);
+ WRITE_PORT_UCHAR(&SP_WRITE->TransmitBuffer, HalpBaudRateDivisor);
+ WRITE_PORT_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_PORT_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_PORT_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 an error is encountered during reading.
+
+ CP_GET_NODATA is returned if timeout occurs.
+
+--*/
+
+{
+
+ return HalpGetByte(Input, TRUE);
+}
+
+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.
+
+--*/
+
+{
+
+ ULONG Status;
+
+ //
+ // Save port status, map the serial controller, get byte from the
+ // debugger port is one is avaliable, restore port status, unmap
+ // the serial controller, and return the operation status.
+ //
+
+ KdPortSave();
+ Status = HalpGetByte(Input, FALSE);
+ KdPortRestore();
+ return Status;
+}
+
+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;
+
+ if (KdUseModemControl) {
+ //
+ // Modem control, make sure DSR, CTS and CD are all set before
+ // sending any data.
+ //
+
+ for (; ;) {
+ DataByte = READ_PORT_UCHAR(&SP_READ->ModemStatus);
+ if ( ((PSP_MODEM_STATUS)&DataByte)->ClearToSend &&
+ ((PSP_MODEM_STATUS)&DataByte)->DataSetReady &&
+ ((PSP_MODEM_STATUS)&DataByte)->ReceiveDetect ) {
+ break;
+ }
+
+ KdReadLsr(FALSE);
+ }
+ }
+
+ //
+ // Wait for transmit ready.
+ //
+
+ while (KdReadLsr(FALSE).TransmitHoldingEmpty == 0 );
+
+ //
+ // Wait for data set ready.
+ //
+
+// do {
+// LsrByte = READ_PORT_UCHAR(&SP_READ->ModemStatus);
+// } while (((PSP_MODEM_STATUS)(&LsrByte))->DataSetReady == 0);
+
+ //
+ // Transmit data.
+ //
+
+ WRITE_PORT_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;
+}
+
+
+SP_LINE_STATUS
+KdReadLsr (
+ IN BOOLEAN WaitReason
+ )
+
+/*++
+
+Routine Description:
+
+ Returns current line status.
+
+ If status which is being waited for is ready, then the function
+ checks the current modem status and causes a possible display update
+ of the current statuses.
+
+Arguments:
+
+ WaitReason - Suuplies a boolean value that determines whether the line
+ status is required for a receive or transmit.
+
+Return Value:
+
+ The current line status is returned as the function value.
+
+--*/
+
+{
+
+ static UCHAR RingFlag = 0;
+ UCHAR DataLsr, DataMsr;
+
+ //
+ // Get the line status for a receive or a transmit.
+ //
+
+ DataLsr = READ_PORT_UCHAR(&SP_READ->LineStatus);
+ if (WaitReason) {
+
+ //
+ // Get line status for receive data.
+ //
+
+ if (((PSP_LINE_STATUS)&DataLsr)->DataReady) {
+ return *((PSP_LINE_STATUS)&DataLsr);
+ }
+
+ } else {
+
+ //
+ // Get line status for transmit empty.
+ //
+
+ if (((PSP_LINE_STATUS)&DataLsr)->TransmitEmpty) {
+ return *((PSP_LINE_STATUS)&DataLsr);
+ }
+ }
+
+ DataMsr = READ_PORT_UCHAR(&SP_READ->ModemStatus);
+ RingFlag |= ((PSP_MODEM_STATUS)&DataMsr)->RingIndicator ? 1 : 2;
+ if (RingFlag == 3) {
+
+ //
+ // The ring indicate line has toggled, use modem control from
+ // now on.
+ //
+
+ KdUseModemControl = TRUE;
+ }
+
+ return *((PSP_LINE_STATUS) &DataLsr);
+}
diff --git a/private/ntos/nthals/halalpha/pcspeakr.c b/private/ntos/nthals/halalpha/pcspeakr.c
new file mode 100644
index 000000000..912a87b2a
--- /dev/null
+++ b/private/ntos/nthals/halalpha/pcspeakr.c
@@ -0,0 +1,136 @@
+/*++
+
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ pcspeakr.c
+
+Abstract:
+
+ This module implements the HAL speaker "beep" routines for the
+ Alpha system that use the standard PC speaker driven by an interval
+ timer.
+
+Author:
+
+ Jeff McLeman (mcleman) 23-Jun-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+
+
+BOOLEAN
+HalMakeBeep(
+ IN ULONG Frequency
+ )
+
+/*++
+
+Routine Description:
+
+ This function sets the frequency of the speaker, causing it to sound a
+ tone. The tone will sound until the speaker is explicitly turned off,
+ so the driver is responsible for controlling the duration of the tone.
+
+Arguments:
+
+ Frequency - Supplies the frequency of the desired tone. A frequency of
+ 0 means the speaker should be shut off.
+
+Return Value:
+
+ TRUE - Operation was successful (frequency within range or zero).
+ FALSE - Operation was unsuccessful (frequency was out of range).
+ Current tone (if any) is unchanged.
+
+--*/
+
+{
+ KIRQL oldIrql;
+ NMI_STATUS NmiStatus;
+ PEISA_CONTROL controlBase;
+ TIMER_CONTROL timerControl;
+ ULONG newCount;
+
+ controlBase = HalpEisaControlBase;
+
+ //
+ // Raise the IRQL to dispatch level and acquire the beep spinlock.
+ //
+
+ KeAcquireSpinLock(&HalpBeepLock, &oldIrql);
+
+ //
+ // Stop the speaker.
+ //
+
+ *((PUCHAR) &NmiStatus) = READ_PORT_UCHAR(&controlBase->NmiStatus);
+
+ NmiStatus.SpeakerGate = 0;
+ NmiStatus.SpeakerData = 0;
+
+ WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
+
+ if (Frequency == 0) {
+ KeReleaseSpinLock(&HalpBeepLock, oldIrql);
+ return(TRUE);
+ }
+
+ //
+ // Calculate the new counter value.
+ //
+
+ newCount = TIMER_CLOCK_IN / Frequency;
+
+ //
+ // The new count must be less than 16 bits in value.
+ //
+
+ if (newCount >= 0x10000) {
+ KeReleaseSpinLock(&HalpBeepLock, oldIrql);
+ return(FALSE);
+ }
+
+ //
+ // Set the speaker timer to the correct mode.
+ //
+
+ timerControl.BcdMode = 0;
+ timerControl.Mode = TM_SQUARE_WAVE;
+ timerControl.SelectByte = SB_LSB_THEN_MSB;
+ timerControl.SelectCounter = SELECT_COUNTER_2;
+
+ WRITE_PORT_UCHAR(&controlBase->CommandMode1, *((PUCHAR) &timerControl));
+
+ //
+ // Set the speaker timer to the correct mode.
+ //
+
+ WRITE_PORT_UCHAR(&controlBase->SpeakerTone, (UCHAR)newCount);
+ WRITE_PORT_UCHAR(&controlBase->SpeakerTone, (UCHAR)(newCount >> 8));
+
+ //
+ // Start the speaker.
+ //
+
+ NmiStatus.SpeakerGate = 1;
+ NmiStatus.SpeakerData = 1;
+
+ WRITE_PORT_UCHAR(&controlBase->NmiStatus, *((PUCHAR) &NmiStatus));
+
+ //
+ // Release the beep spinlock and restore the IRQL.
+ //
+
+ KeReleaseSpinLock(&HalpBeepLock, oldIrql);
+ return(TRUE);
+}
diff --git a/private/ntos/nthals/halalpha/perf8254.c b/private/ntos/nthals/halalpha/perf8254.c
new file mode 100644
index 000000000..7a2160408
--- /dev/null
+++ b/private/ntos/nthals/halalpha/perf8254.c
@@ -0,0 +1,457 @@
+/*++
+
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ perf82454.c
+
+Abstract:
+
+ This module implements the interfaces that access the system
+ performance counter and the calibrated stall for systems that
+ use an external 8254 timer chip to implement the performance counter.
+ This module is suitable for use in multiprocessor systems.
+
+Author:
+
+ Joe Notarangelo 14-Mar-1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+
+//
+// Declare the global that contains the current value of the performance
+// counter.
+//
+
+ULONG HalpLastTimer;
+ULONGLONG HalpTimerWrapCount;
+
+//
+// Declare globals used to control the access to and initialization of
+// the performance counter.
+//
+
+BOOLEAN HalpPerformanceCounterInitialized = FALSE;
+ULONG HalpPerformanceCounterFrequency;
+KSPIN_LOCK HalpPerformanceCounterSpinLock;
+
+#define TIMER_START_VALUE (0xffff)
+
+//
+// Define local routine prototypes.
+//
+
+VOID
+HalpStartTimer(
+ VOID
+ );
+
+ULONG
+HalpReadTimerValue(
+ VOID
+ );
+
+VOID
+HalCalibratePerformanceCounter (
+ IN volatile PLONG Number
+ )
+
+/*++
+
+Routine Description:
+
+ This routine is responsible for synchronizing the performance
+ counter across all processors in the system configuration.
+ For an 8254-based performance counter all that is necessary is that
+ the counter be initialized.
+
+Arguments:
+
+ Number - Supplies a pointer to count of the number of processors in
+ the configuration.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ PKPRCB Prcb = PCR->Prcb;
+
+ //
+ // If this isn't the primary processor, then return.
+ //
+
+ if( Prcb->Number != HAL_PRIMARY_PROCESSOR ){
+ return;
+ }
+
+ //
+ // If the counter has already been initialized then simply return.
+ //
+
+ if( HalpPerformanceCounterInitialized == TRUE ){
+ return;
+ }
+
+ //
+ // Initialize the spinlock for controlling access to the counter.
+ //
+
+ KeInitializeSpinLock( &HalpPerformanceCounterSpinLock );
+
+ //
+ // Set the frequency of the counter.
+ //
+
+ HalpPerformanceCounterFrequency = TIMER_CLOCK_IN;
+
+ //
+ // Initialize the wrap count.
+ //
+
+ HalpTimerWrapCount = 0;
+
+ //
+ // Initialize the counter and start it.
+ //
+
+ HalpStartTimer();
+
+ HalpLastTimer = HalpReadTimerValue();
+
+ //
+ // Mark the counter as initialized.
+ //
+
+ HalpPerformanceCounterInitialized = TRUE;
+
+}
+
+
+LARGE_INTEGER
+KeQueryPerformanceCounter (
+ OUT PLARGE_INTEGER Frequency OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the current performance counter value and the
+ performance counter frequency.
+
+Arguments:
+
+ Frequency - Supplies an optional pointer to a variable which receives
+ the performance counter frequency in Hertz.
+
+Return Value:
+
+ The current performance counter value is returned as the function
+ value.
+
+--*/
+
+{
+
+ LARGE_INTEGER LocalPerformanceCount;
+ KIRQL OldIrql;
+ ULONG TimerValue;
+
+ //
+ // Return 0 if the performance counter has not been initialized yet.
+ //
+
+ if( HalpPerformanceCounterInitialized == FALSE ){
+ LocalPerformanceCount.QuadPart = 0;
+ return LocalPerformanceCount;
+ }
+
+ //
+ // Synchronize the calculation of the performance counter with the
+ // clock routine executing on the boot processor.
+ //
+
+ KeRaiseIrql( CLOCK_LEVEL, &OldIrql );
+ KiAcquireSpinLock( &HalpPerformanceCounterSpinLock );
+
+ //
+ // Read the current value of the timer count.
+ //
+
+ TimerValue = HalpReadTimerValue();
+
+ //
+ // If the timer is greater than the last timer value then the timer
+ // has wrapped since the last time we have read it.
+ //
+
+ if( TimerValue > HalpLastTimer ){
+
+ HalpTimerWrapCount += (1 << 15);
+ }
+
+ HalpLastTimer = TimerValue;
+
+ LocalPerformanceCount.QuadPart = HalpTimerWrapCount +
+ (TIMER_START_VALUE - TimerValue)/2;
+
+ //
+ // Once the value is calculated synchronization is no longer
+ // required.
+ //
+
+ KiReleaseSpinLock( &HalpPerformanceCounterSpinLock );
+ KeLowerIrql( OldIrql );
+
+ //
+ // If the frequency parameter is specified, then return the frequency
+ // of the 8254 counter.
+ //
+
+ if (ARGUMENT_PRESENT(Frequency) != FALSE) {
+ Frequency->LowPart = HalpPerformanceCounterFrequency;
+ Frequency->HighPart = 0;
+ }
+
+ //
+ // Return the calculated performance count.
+ //
+
+ return LocalPerformanceCount;
+
+}
+
+
+VOID
+HalpCheckPerformanceCounter(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function is called every system clock interrupt in order to
+ check for wrap of the performance counter. The function must handle
+ a wrap if it is detected.
+
+ N.B. - This function must be called at CLOCK_LEVEL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ ULONG TimerValue;
+
+ //
+ // Synchronize the performance counter check with any possible
+ // readers.
+ //
+
+ KiAcquireSpinLock( &HalpPerformanceCounterSpinLock );
+
+ //
+ // Read the current value of the timer count.
+ //
+
+ TimerValue = HalpReadTimerValue();
+
+ //
+ // If the timer is greater than the last timer value then the timer
+ // has wrapped since the last time we have read it.
+ //
+
+ if( TimerValue > HalpLastTimer ){
+
+ HalpTimerWrapCount += (1 << 15);
+ }
+
+ HalpLastTimer = TimerValue;
+
+ KiReleaseSpinLock( &HalpPerformanceCounterSpinLock );
+
+ return;
+
+}
+
+
+VOID
+KeStallExecutionProcessor (
+ IN ULONG MicroSeconds
+ )
+
+/*++
+
+Routine Description:
+
+ This function stalll execution of the current processor for the specified
+ number of microseconds.
+
+Arguments:
+
+ MicroSeconds - Supplies the number of microseconds that execution is to
+ be stalled.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ LONG StallCyclesRemaining; // signed value
+ ULONG PreviousRpcc, CurrentRpcc;
+
+ //
+ // Get the value of the RPCC as soon as we enter
+ //
+
+ PreviousRpcc = HalpRpcc();
+
+ //
+ // Compute the number of cycles to stall
+ //
+
+ StallCyclesRemaining = MicroSeconds * HalpClockMegaHertz;
+
+ //
+ // Wait while there are stall cycles remaining.
+ // The accuracy of this routine is limited by the
+ // length of this while loop.
+ //
+
+ while (StallCyclesRemaining > 0) {
+
+ CurrentRpcc = HalpRpcc();
+
+ //
+ // The subtraction always works because the Rpcc
+ // is a wrapping long-word. If it wraps, we still
+ // get the positive number we want.
+ //
+
+ StallCyclesRemaining -= (CurrentRpcc - PreviousRpcc);
+
+ //
+ // remember this RPCC value
+ //
+
+ PreviousRpcc = CurrentRpcc;
+ }
+
+}
+
+
+VOID
+HalpStartTimer(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Start the timer used to maintain the performance count. The timer used
+ is counter 0 in timer 1 - it is an 8254-compatible timer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ TIMER_CONTROL TimerControl;
+
+ //
+ // Set the timer for counter 0 in binary mode. Write the counter
+ // with the LSB then MSB of the TIMER_START_VALUE.
+ //
+
+ TimerControl.BcdMode = 0;
+ TimerControl.Mode = TM_SQUARE_WAVE;
+ TimerControl.SelectByte = SB_LSB_THEN_MSB;
+ TimerControl.SelectCounter = SELECT_COUNTER_0;
+
+ WRITE_PORT_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->CommandMode1,
+ *(PUCHAR)&TimerControl );
+
+ WRITE_PORT_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Timer1,
+ TIMER_START_VALUE & 0xff );
+
+ WRITE_PORT_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Timer1,
+ (TIMER_START_VALUE >> 8) & 0xff );
+
+
+ return;
+
+}
+
+
+ULONG
+HalpReadTimerValue(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Read the current value from the timer used to maintain the performance
+ count. The timer used is counter 0 in timer - it is an 8254-compatible
+ timer.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ The current count value of the timer is returned.
+
+--*/
+{
+ UCHAR Lsb;
+ UCHAR Msb;
+ TIMER_CONTROL TimerControl;
+
+ //
+ // Set the counter for a latched read, read it Lsb then Msb.
+ //
+
+ TimerControl.BcdMode = 0;
+ TimerControl.Mode = 0;
+ TimerControl.SelectByte = SB_COUNTER_LATCH;
+ TimerControl.SelectCounter = SELECT_COUNTER_0;
+
+ WRITE_PORT_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->CommandMode1,
+ *(PUCHAR)&TimerControl );
+
+ Lsb = READ_PORT_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Timer1 );
+
+ Msb = READ_PORT_UCHAR( &((PEISA_CONTROL)HalpEisaControlBase)->Timer1 );
+
+ return (ULONG)( (Msb << 8) | Lsb );
+
+}
diff --git a/private/ntos/nthals/halalpha/perfcntr.c b/private/ntos/nthals/halalpha/perfcntr.c
new file mode 100644
index 000000000..6e1791443
--- /dev/null
+++ b/private/ntos/nthals/halalpha/perfcntr.c
@@ -0,0 +1,260 @@
+/*++
+
+Copyright (c) 1992, 1993 Digital Equipment Corporation
+
+Module Name:
+
+ perfcntr.c
+
+Abstract:
+
+ This module implements the interfaces that access the system
+ performance counter and the calibrated stall. The functions implemented
+ in this module are suitable for uniprocessor systems only.
+
+Author:
+
+ Jeff McLeman (mcleman) 05-June-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+
+ Rod Gamache [DEC] 9-Mar-1993
+ Fix profile clock.
+
+
+--*/
+
+#include "halp.h"
+#include "eisa.h"
+
+//
+// Define and initialize the 64-bit count of total system cycles used
+// as the performance counter.
+//
+
+ULONGLONG HalpCycleCount = 0;
+
+
+LARGE_INTEGER
+KeQueryPerformanceCounter (
+ OUT PLARGE_INTEGER Frequency OPTIONAL
+ )
+
+/*++
+
+Routine Description:
+
+ This routine returns the current performance counter value and the
+ performance counter frequency.
+
+Arguments:
+
+ Frequency - Supplies an optional pointer to a variable which receives
+ the performance counter frequency in Hertz.
+
+Return Value:
+
+ The current performance counter value is returned as the function
+ value.
+
+--*/
+
+{
+
+ LARGE_INTEGER LocalRpccTime;
+ ULONG RpccValue;
+
+ //
+ // Obtain the current value of the processor cycle counter and adjust
+ // the upper 32 bits if a roll-over occurred since the last time the
+ // Rpcc value was checked (at least oncce per clock interrupt). This
+ // code may be interrupted so we must fetch HalpRpccTimec atomically.
+ //
+
+ *(PULONGLONG)&LocalRpccTime = HalpCycleCount;
+ RpccValue = HalpRpcc();
+ if (RpccValue < LocalRpccTime.LowPart) {
+ LocalRpccTime.HighPart += 1;
+ }
+ LocalRpccTime.LowPart = RpccValue;
+
+
+ //
+ // If the frequency parameter is specified, then return the performance
+ // counter frequency as the current system time frequency.
+ //
+
+ if (ARGUMENT_PRESENT(Frequency) != FALSE) {
+ Frequency->LowPart = HalpClockFrequency;
+ Frequency->HighPart = 0;
+ }
+
+ //
+ // Return the current processor cycle counter as the function value.
+ //
+
+ return LocalRpccTime;
+}
+
+
+VOID
+HalCalibratePerformanceCounter (
+ IN volatile PLONG Number
+ )
+
+/*++
+
+Routine Description:
+
+ This routine resets the performance counter value for the current
+ processor to zero. The reset is done such that the resulting value
+ is closely synchronized with other processors in the configuration.
+
+Arguments:
+
+ Number - Supplies a pointer to count of the number of processors in
+ the configuration.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // ****** Warning ******
+ //
+ // This is a stub routine. It should clear the current value of the
+ // performance counter. It is really only needed in an MP system where,
+ // close, but not exact synchronization of the performance counters
+ // are needed. See MIPS code in halfxs\mips\j4prof.c for a method of
+ // synchronizing.
+ //
+
+ return;
+}
+
+
+VOID
+HalpCheckPerformanceCounter(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This function is called every system clock interrupt in order to
+ check for wrap of the performance counter. The function must handle
+ a wrap if it is detected.
+
+ N.B. - This function must be called at CLOCK_LEVEL.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ LARGE_INTEGER LocalRpccTime;
+ ULONG RpccValue;
+
+ //
+ // Update the low part of the performance counter directly from the
+ // rpcc count. Check for wrap of the rpcc count, if wrap has occurred
+ // then increment the high part of the performance counter.
+ //
+
+ LocalRpccTime.QuadPart = HalpCycleCount;
+ RpccValue = HalpRpcc();
+
+ if (RpccValue < LocalRpccTime.LowPart) {
+ LocalRpccTime.HighPart += 1;
+ }
+
+ LocalRpccTime.LowPart = RpccValue;
+
+ HalpCycleCount = LocalRpccTime.QuadPart;
+
+ return;
+
+}
+
+
+VOID
+KeStallExecutionProcessor (
+ IN ULONG Microseconds
+ )
+
+/*++
+
+Routine Description:
+
+ This function stalll execution of the current processor for the specified
+ number of microseconds.
+
+Arguments:
+
+ Microseconds - Supplies the number of microseconds to stall.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ LONG StallCyclesRemaining; // signed value
+ ULONG PreviousRpcc, CurrentRpcc;
+
+ //
+ // Get the value of the RPCC as soon as we enter
+ //
+
+ PreviousRpcc = HalpRpcc();
+
+ //
+ // Compute the number of cycles to stall
+ //
+
+ StallCyclesRemaining = Microseconds * HalpClockMegaHertz;
+
+ //
+ // Wait while there are stall cycles remaining.
+ // The accuracy of this routine is limited by the
+ // length of this while loop.
+ //
+
+ while (StallCyclesRemaining > 0) {
+
+ CurrentRpcc = HalpRpcc();
+
+ //
+ // The subtraction always works because the Rpcc
+ // is a wrapping long-word. If it wraps, we still
+ // get the positive number we want.
+ //
+
+ StallCyclesRemaining -= (CurrentRpcc - PreviousRpcc);
+
+ //
+ // remember this RPCC value
+ //
+
+ PreviousRpcc = CurrentRpcc;
+ }
+
+}
+
diff --git a/private/ntos/nthals/halalpha/t2.c b/private/ntos/nthals/halalpha/t2.c
new file mode 100644
index 000000000..19ada2b78
--- /dev/null
+++ b/private/ntos/nthals/halalpha/t2.c
@@ -0,0 +1,760 @@
+/*++
+
+Copyright (c) 1993 Digital Equipment Corporation
+
+Module Name:
+
+ t2.c
+
+Abstract:
+
+ This module implements functions that are specific to the T2 chip.
+ The T2 chip is a system support chip that bridges between the
+ CBUS2 and the PCI bus.
+
+Author:
+
+ Joe Notarangelo 18-Oct-1993
+ Steve Jenness 18-Oct-1993
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Steve Brooks 30-Dec-1994
+
+ Remove sable specific references and move to common halalpha directory
+
+--*/
+
+#include "halp.h"
+
+extern ULONG HalDisablePCIParityChecking;
+
+#ifdef HALDBG
+
+ULONG T2Debug;
+
+VOID
+DumpT2(
+ VOID
+ );
+
+VOID
+DumpT4(
+ VOID
+ );
+
+#define DebugDumpT2(DebugPrintLevel) \
+ if (DebugPrintLevel <= T2Debug) \
+ DumpT2()
+
+#else //HALDBG
+
+#define DebugDumpT2(a)
+
+#endif //HALDBG
+
+VOID
+HalpT2InitializeSfwWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ T2_WINDOW_NUMBER WindowNumber
+ )
+/*++
+
+Routine Description:
+
+ Initialize the DMA Control software window registers for the specified
+ DMA Window.
+
+Arguments:
+
+ WindowRegisters - Supplies a pointer to the software window control.
+
+ WindowNumber - Supplies the window number initialized. (0 = Isa Dma
+ Window, 1 = Master Dma Window).
+
+Return Value:
+
+ None.
+
+--*/
+{
+
+ switch( WindowNumber ){
+
+ //
+ // The ISA DMA Window.
+ //
+
+ case T2IsaWindow:
+
+ WindowRegisters->WindowBase = (PVOID)ISA_DMA_WINDOW_BASE;
+ WindowRegisters->WindowSize = ISA_DMA_WINDOW_SIZE;
+
+ WindowRegisters->TranslatedBaseRegister[0] =
+ &((PT2_CSRS)(T2_CSRS_QVA))->Tbase1;
+ WindowRegisters->WindowBaseRegister[0] =
+ &((PT2_CSRS)(T2_CSRS_QVA))->Wbase1;
+ WindowRegisters->WindowMaskRegister[0] =
+ &((PT2_CSRS)(T2_CSRS_QVA))->Wmask1;
+ WindowRegisters->WindowTbiaRegister[0] =
+ &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr;
+
+ WindowRegisters->TranslatedBaseRegister[1] = NULL;
+ WindowRegisters->WindowBaseRegister[1] = NULL;
+ WindowRegisters->WindowMaskRegister[1] = NULL;
+ WindowRegisters->WindowTbiaRegister[1] = NULL;
+
+ break;
+
+ case T2MasterWindow:
+
+ WindowRegisters->WindowBase = (PVOID)MASTER_DMA_WINDOW_BASE;
+ WindowRegisters->WindowSize = MASTER_DMA_WINDOW_SIZE;
+
+ WindowRegisters->TranslatedBaseRegister[0] =
+ &((PT2_CSRS)(T2_CSRS_QVA))->Tbase2;
+ WindowRegisters->WindowBaseRegister[0] =
+ &((PT2_CSRS)(T2_CSRS_QVA))->Wbase2;
+ WindowRegisters->WindowMaskRegister[0] =
+ &((PT2_CSRS)(T2_CSRS_QVA))->Wmask2;
+ WindowRegisters->WindowTbiaRegister[0] =
+ &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr;
+
+ WindowRegisters->TranslatedBaseRegister[1] =
+ &((PT2_CSRS)(T4_CSRS_QVA))->Tbase2;
+ WindowRegisters->WindowBaseRegister[1] =
+ &((PT2_CSRS)(T4_CSRS_QVA))->Wbase2;
+ WindowRegisters->WindowMaskRegister[1] =
+ &((PT2_CSRS)(T4_CSRS_QVA))->Wmask2;
+ WindowRegisters->WindowTbiaRegister[1] =
+ &((PT2_CSRS)(T4_CSRS_QVA))->Iocsr;
+
+
+ break;
+
+ default:
+
+#if HALDBG
+
+ DbgPrint( "T2InitializeSfwWindow: Bad Window Number = %x\n",
+ WindowNumber );
+
+#endif //HALDBG
+
+ break;
+
+ }
+
+ return;
+}
+
+
+VOID
+HalpT2ProgramDmaWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ PVOID MapRegisterBase
+ )
+/*++
+
+Routine Description:
+
+ Program the control windows in the hardware so that DMA can be started
+ to the DMA window.
+
+Arguments:
+
+ WindowRegisters - Supplies a pointer to the software window register
+ control structure.
+
+ MapRegisterBase - Supplies the logical address of the scatter/gather
+ array in system memory.
+
+
+Return Value:
+
+ None.
+
+--*/
+{
+ T2_WBASE PciBase;
+ T2_WMASK PciMask;
+ T2_TBASE Tbase;
+
+ PciBase.all = 0;
+ PciBase.EnablePciWindow = 1;
+ PciBase.EnableScatterGather = 1;
+ PciBase.PciWindowStartAddress = (ULONG)(WindowRegisters->WindowBase) >> 20;
+ PciBase.PciWindowEndAddress =
+ ((ULONG)(WindowRegisters->WindowBase) +
+ WindowRegisters->WindowSize - 1) >> 20;
+
+ PciMask.all = 0;
+ PciMask.PciWindowMask = (WindowRegisters->WindowSize >> 20) - 1;
+
+ Tbase.all = 0;
+ Tbase.TranslatedBaseAddress = (ULONG)(MapRegisterBase) >> 10;
+
+ //
+ // Dump the T2 registers.
+ //
+
+ DebugDumpT2(5);
+
+ //
+ // Clear the window base, temporarily disabling transactions to this
+ // DMA window.
+ //
+
+ WRITE_T2_REGISTER( WindowRegisters->WindowBaseRegister[0], (ULONGLONG)0 );
+
+ //
+ // Now program the window by writing the translated base, then the size
+ // of the window in the mask register and finally the window base,
+ // enabling both the window and scatter gather.
+ //
+
+ WRITE_T2_REGISTER( WindowRegisters->TranslatedBaseRegister[0],
+ *(PULONGLONG)&Tbase );
+
+ WRITE_T2_REGISTER( WindowRegisters->WindowMaskRegister[0],
+ *(PULONGLONG)&PciMask );
+
+ WRITE_T2_REGISTER( WindowRegisters->WindowBaseRegister[0],
+ *(PULONGLONG)&PciBase );
+
+// smjfix - Turn on Hole 1 and 2 to make access to
+// Eisa memory space work. This is currently used to
+// to allow access to the Qvision frame buffer at 4Mbytes.
+// Note that the StartAddress and EndAddress need to be
+// shifted by 1 bit (in contrast to the T2 spec).
+// Currently memory devices on Sable have to be 0-16Mbytes or
+// above 2Gbytes.
+
+ {
+ T2_HBASE Hbase;
+
+ Hbase.all = 0;
+ Hbase.HoleStartAddress = 0x40 << 1; // 4 Mbytes
+ Hbase.HoleEndAddress = 0x4f << 1; // 5 Mbytes - 1
+ Hbase.Hole1Enable = 1;
+ Hbase.Hole2Enable = 1;
+
+ WRITE_T2_REGISTER( &((PT2_CSRS)(T2_CSRS_QVA))->Hbase,
+ *(PULONGLONG)&Hbase );
+ }
+
+#if defined(XIO_PASS1) || defined(XIO_PASS2)
+
+ //
+ // If the external I/O module is present and this is *not* the ISA
+ // DMA window, initialize the T4 similarly.
+ //
+
+ if( HalpXioPresent && WindowRegisters->WindowBaseRegister[1] != NULL ) {
+
+#if HALDBG
+ DumpT4();
+#endif
+
+ //
+ // Clear the window base, temporarily disabling transactions to this
+ // DMA window.
+ //
+
+ WRITE_T2_REGISTER( WindowRegisters->WindowBaseRegister[1],
+ (ULONGLONG)0 );
+
+ //
+ // Now program the window by writing the translated base, then the size
+ // of the window in the mask register and finally the window base,
+ // enabling both the window and scatter gather.
+ //
+
+ WRITE_T2_REGISTER( WindowRegisters->TranslatedBaseRegister[1],
+ *(PULONGLONG)&Tbase );
+
+ WRITE_T2_REGISTER( WindowRegisters->WindowMaskRegister[1],
+ *(PULONGLONG)&PciMask );
+
+ WRITE_T2_REGISTER( WindowRegisters->WindowBaseRegister[1],
+ *(PULONGLONG)&PciBase );
+
+ //
+ // The external I/O module does not have a co-resident EISA/ISA
+ // bus, therefore, no holes are necessary.
+ //
+
+ WRITE_T2_REGISTER( &((PT2_CSRS)(T4_CSRS_QVA))->Hbase,
+ (ULONGLONG)0 );
+
+#if HALDBG
+ DumpT4();
+#endif
+ }
+
+#endif
+
+ //
+ // Flush and enable the translation buffer inside of the T2.
+ // Since the TLB is maintained by bus snooping, this should be the
+ // only time a flush is needed.
+ //
+
+
+ {
+ ULONGLONG Value;
+ T2_IOCSR Iocsr;
+
+ Value = READ_T2_REGISTER(&((PT2_CSRS)(T2_CSRS_QVA))->Iocsr);
+ Iocsr = *(PT2_IOCSR)&Value;
+ Iocsr.EnableTlb = 0;
+ Iocsr.FlushTlb = 1;
+
+ WRITE_T2_REGISTER( &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr,
+ *(PULONGLONG)&Iocsr );
+
+ Iocsr.EnableTlb = 1;
+ Iocsr.FlushTlb = 0;
+
+ WRITE_T2_REGISTER( &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr,
+ *(PULONGLONG)&Iocsr );
+
+#if defined(XIO_PASS1) || defined(XIO_PASS2)
+
+ if( HalpXioPresent ) {
+
+ Value = READ_T2_REGISTER(&((PT2_CSRS)(T4_CSRS_QVA))->Iocsr);
+ Iocsr = *(PT2_IOCSR)&Value;
+ Iocsr.EnableTlb = 0;
+ Iocsr.FlushTlb = 1;
+
+ WRITE_T2_REGISTER( &((PT2_CSRS)(T4_CSRS_QVA))->Iocsr,
+ *(PULONGLONG)&Iocsr );
+
+ Iocsr.EnableTlb = 0;
+ Iocsr.FlushTlb = 0;
+
+ WRITE_T2_REGISTER( &((PT2_CSRS)(T4_CSRS_QVA))->Iocsr,
+ *(PULONGLONG)&Iocsr );
+
+#if HALDBG
+ DumpT4();
+#endif
+ }
+
+#endif
+
+ }
+
+ //
+ // Dump the T2 registers.
+ //
+
+ DebugDumpT2(5);
+
+ return;
+}
+
+VOID
+HalpT2InvalidateTLB(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters
+ )
+/*++
+
+Routine Description:
+
+ Invalidate the DMA Scatter/Gather TLB in the T2. This routine
+ is called when initializing the window registers. It is *not*
+ called by HAL_INVALIDATE_TRANSLATIONS because invalidating the
+ TLB when DMAs are in progress doesn't work on the T2.
+
+ There is a single TLB in the T2; the WindowRegisters argument is
+ ignored.
+
+Arguments:
+
+ WindowRegisters - Supplies a pointer to the software window register
+ control structure.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ ULONGLONG Value;
+ T2_IOCSR Iocsr;
+
+#if 0
+
+ // Pass2 appears to be broken also.
+
+#ifndef T2PASS1ONLY
+
+ //
+ // If the T2 is a Pass2 or later, flush and enable the TLB.
+ //
+
+ Value = READ_T2_REGISTER(&((PT2_CSRS)(T2_CSRS_QVA))->Iocsr);
+ Iocsr = *(PT2_IOCSR)&Value;
+
+ if (Iocsr.T2RevisionNumber != 0) {
+
+ Iocsr.FlushTlb = 1;
+ WRITE_T2_REGISTER( &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr,
+ *(PULONGLONG)&Iocsr );
+
+ Iocsr.EnableTlb = 1;
+ Iocsr.FlushTlb = 0;
+ WRITE_T2_REGISTER( &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr,
+ *(PULONGLONG)&Iocsr );
+ }
+
+#if defined(XIO_PASS1) || defined(XIO_PASS2)
+
+ //
+ // Invalidate the T4's TLB...
+ //
+
+ if( HalpXioPresent ){
+
+ Value = READ_T2_REGISTER(&((PT2_CSRS)(T4_CSRS_QVA))->Iocsr);
+ Iocsr = *(PT2_IOCSR)&Value;
+
+ Iocsr.FlushTlb = 1;
+ WRITE_T2_REGISTER( &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr,
+ *(PULONGLONG)&Iocsr );
+
+ Iocsr.EnableTlb = 0;
+ Iocsr.FlushTlb = 0;
+ WRITE_T2_REGISTER( &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr,
+ *(PULONGLONG)&Iocsr );
+
+ }
+
+#endif
+
+#endif //T2PASS1ONLY
+#endif //0
+}
+
+#if HALDBG
+
+VOID
+DumpT2(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Read the interesting T2 registers and print them to the debug port.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PVOID RegisterQva;
+ PVOID TestQva;
+ ULONGLONG Value;
+ ULONG LongValue;
+ T2_TDR Tdr;
+
+// DbgPrint( "Dumping the T2 registers, " );
+
+#if 0
+//
+// This code tests whether the windows and holes allow access to
+// the address in I/O memory space set in PhysicalAddress.
+// See also the companion code at the end of this routine.
+//
+ {
+ ULONG AddressSpace;
+ PHYSICAL_ADDRESS PhysicalAddress;
+
+ AddressSpace = 0;
+ PhysicalAddress.LowPart = 0xD0000; // DE422
+// PhysicalAddress.LowPart = 0x2200000; // 34Mbytes
+// PhysicalAddress.LowPart = 0x0400000; // 4Mbytes
+ PhysicalAddress.HighPart = 0;
+ HalTranslateBusAddress( Isa, 0, PhysicalAddress, &AddressSpace, &TestQva );
+
+ LongValue = READ_REGISTER_ULONG( TestQva );
+ DbgPrint( "TestQva = %lx, Value = %x, writing 0xa5a5a5a5..\n",
+ TestQva, LongValue );
+ LongValue = 0xa5a5a5a5;
+ WRITE_REGISTER_ULONG( TestQva, LongValue );
+ LongValue = READ_REGISTER_ULONG( TestQva );
+ DbgPrint( "TestQva = %lx, Value = %x\n", TestQva, LongValue );
+ }
+#endif // 0
+
+#if 0
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Iocsr;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Iocsr = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Ivrpr;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Ivrpr = %Lx\n", Value );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Hae0_1;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Hae0_1 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Hae0_2;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Hae0_2 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Hbase;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Hbase = %Lx\n", Value );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Wbase1;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Wbase1 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Wmask1;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Wmask1 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tbase1;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Tbase1 = %Lx\n", Value );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Wbase2;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Wbase2 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Wmask2;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Wmask2 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tbase2;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Tbase2 = %Lx\n", Value );
+
+#endif // 0
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr0;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr0 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr1;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr1 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr2;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr2 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr3;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr3 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr4;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr4 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr5;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr5 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr6;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr6 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ RegisterQva = &((PT2_CSRS)(T2_CSRS_QVA))->Tdr7;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr7 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+#if 0
+ LongValue = READ_REGISTER_ULONG( TestQva );
+ DbgPrint( "TestQva = %lx, Value = %x, writing 0xc3c3c3c3..\n",
+ TestQva, LongValue );
+ LongValue = 0xc3c3c3c3;
+ WRITE_REGISTER_ULONG( TestQva, LongValue );
+ LongValue = READ_REGISTER_ULONG( TestQva );
+ DbgPrint( "TestQva = %lx, Value = %x\n", TestQva, LongValue );
+#endif // 0
+
+// DbgPrint( "--end T2 dump\n\n" );
+
+ return;
+
+}
+
+#endif //HALDBG
+
+#if HALDBG && defined(XIO_PASS1) || defined(XIO_PASS2)
+
+VOID
+DumpT4(
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ Read the interesting T2 registers and print them to the debug port.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+{
+ PVOID RegisterQva;
+ ULONGLONG Value;
+ ULONG LongValue;
+ T2_TDR Tdr;
+
+ if( !HalpXioPresent ){
+ DbgPrint( "XIO module not present.\n" );
+ return;
+ }
+
+ DbgPrint( "Dumping the T4 registers:\n" );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Iocsr;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Iocsr = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Ivrpr;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Ivrpr = %Lx\n", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Hae0_1;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Hae0_1 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Hae0_2;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Hae0_2 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Hae0_3;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Hae0_3 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Hae0_4;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Hae0_4 = %Lx\n", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Hbase;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Hbase = %Lx\n", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wbase1;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Wbase1 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wmask1;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Wmask1 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tbase1;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Tbase1 = %Lx\n", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wbase2;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Wbase2 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wmask2;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Wmask2 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tbase2;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Tbase2 = %Lx\n", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wbase3;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Wbase3 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wmask3;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Wmask3 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tbase3;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Tbase3 = %Lx\n", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wbase4;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Wbase4 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Wmask4;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Wmask4 = %Lx, ", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tbase4;
+ Value = READ_T2_REGISTER( RegisterQva );
+ DbgPrint( "Tbase4 = %Lx\n", Value );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr0;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr0 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr1;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr1 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr2;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr2 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr3;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr3 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr4;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr4 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr5;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr5 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr6;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr6 PFN=%x, V=%x, Tag=%x, ", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ RegisterQva = &((PT2_CSRS)(T4_CSRS_QVA))->Tdr7;
+ Value = READ_T2_REGISTER( RegisterQva );
+ Tdr = *(PT2_TDR)&Value;
+ DbgPrint( "Tdr7 PFN=%x, V=%x, Tag=%x\n", Tdr.Pfn, Tdr.Valid, Tdr.Tag );
+
+ DbgPrint( "--end T4 dump\n\n" );
+}
+
+#endif //HALDBG
diff --git a/private/ntos/nthals/halalpha/t2.h b/private/ntos/nthals/halalpha/t2.h
new file mode 100644
index 000000000..40b0c5136
--- /dev/null
+++ b/private/ntos/nthals/halalpha/t2.h
@@ -0,0 +1,550 @@
+/*++
+
+Copyright (c) 1994 Digital Equipment Corporation
+
+Module Name:
+
+ t2.h
+
+Abstract:
+
+ This file defines the structures and definitions describing the
+ T2 chipset
+
+Author:
+
+ Steve Brooks 28-Dec 1994
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ Extracted from sable.h to be platform independent for sable, gamma & lynx
+
+--*/
+
+#ifndef _T2H_
+#define _T2H_
+
+//
+// N.B. The structure below defines the address offsets of the control
+// registers when used with the base QVA. It does NOT define the
+// size or structure of the individual registers.
+//
+
+
+typedef struct _T2_CSRS {
+ UCHAR Iocsr; // I/O Control/Status Register
+ UCHAR Cerr1; // CBUS Error Register 1
+ UCHAR Cerr2; // CBUS Error Register 2
+ UCHAR Cerr3; // CBUS Error Register 3
+ UCHAR Perr1; // PCI Error Register 1
+ UCHAR Perr2; // PCI Error Register 2
+ UCHAR Pscr; // PCI Special Cycle Register
+ UCHAR Hae0_1; // High Address Extension Register 1
+ UCHAR Hae0_2; // High Address Extension Register 2
+ UCHAR Hbase; // PCI Hole Base Register
+ UCHAR Wbase1; // Window Base Register 1
+ UCHAR Wmask1; // Window Mask Register 1
+ UCHAR Tbase1; // Translated Base Register 1
+ UCHAR Wbase2; // Window Base Register 2
+ UCHAR Wmask2; // Window Mask Register 2
+ UCHAR Tbase2; // Translated Base Register 2
+ UCHAR Tlbbr; // TLB Bypass Register
+ UCHAR Ivrpr; // IVR Passive Release Register
+ UCHAR Hae0_3; // High Address Extension Register 3
+ UCHAR Hae0_4; // High Address Extension Register 4
+ UCHAR Wbase3; // Window Base Register 3 (T3/T4)
+ UCHAR Wmask3; // Window Mask Register 3 (T3/T4)
+ UCHAR Tbase3; // Translated Base Register 3 (T3/T4)
+ UCHAR filler0;
+ UCHAR Tdr0; // TLB Data Register 0
+ UCHAR Tdr1; // TLB Data Register 1
+ UCHAR Tdr2; // TLB Data Register 2
+ UCHAR Tdr3; // TLB Data Register 3
+ UCHAR Tdr4; // TLB Data Register 4
+ UCHAR Tdr5; // TLB Data Register 5
+ UCHAR Tdr6; // TLB Data Register 6
+ UCHAR Tdr7; // TLB Data Register 7
+ UCHAR Wbase4; // Window Base Register 4 (T3/T4)
+ UCHAR Wmask4; // Window Mask Register 4 (T3/T4)
+ UCHAR Tbase4; // Translated Base Register 4 (T3/T4)
+ UCHAR Air; // Address Indirection Register (T3/T4)
+ UCHAR Var; // Vector Access Register (T3/T4)
+ UCHAR Dir; // Data Indirection Register (T3/T4)
+ UCHAR Ice; // IC Enable Register (T3/T4)
+} T2_CSRS, *PT2_CSRS;
+
+//
+// Define formats of useful T2 registers.
+//
+
+typedef union _T2_IOCSR {
+ struct {
+ ULONG EnableReadIoReq: 1; // 00 - P2 Defunct, MBZ
+ ULONG EnableLoopBack: 1; // 01
+ ULONG EnableStateMachineVisibility: 1; // 02
+ ULONG PciDriveBadParity: 1; // 03
+ ULONG Mba0: 1; // 04
+ ULONG Mba1: 1; // 05
+ ULONG PciInterrupt: 1; // 06
+ ULONG EnableTlbErrorCheck: 1; // 07
+ ULONG EnableCxAckCheckForDma: 1; // 08
+ ULONG EnableDenseWrap: 1; // 09
+ ULONG CbusEnableExclusiveExchange: 1; // 10
+ ULONG Pci64Enable: 1; // 11
+ ULONG CbusCAWriteWrongParity0: 1; // 12
+ ULONG CbusCAWriteWrongParity2: 1; // 13
+ ULONG CbusCADataWriteWrongParityEven: 1; // 14
+ ULONG Mba5: 1; // 15
+ ULONG Mba6: 1; // 16 - P2 Power Supply Error
+ ULONG Mba7: 1; // 17
+ ULONG Mba2: 1; // 18
+ ULONG Mba3: 1; // 19
+ ULONG PciDmaWriteWrongParityHW1: 1; // 20
+ ULONG PciDmaWriteWrongParityHW0: 1; // 21
+ ULONG PciBusReset: 1; // 22
+ ULONG PciInterfaceReset: 1; // 23
+ ULONG EnableCbusErrorInterrupt: 1; // 24
+ ULONG EnablePciMemorySpace: 1; // 25
+ ULONG EnableTlb: 1; // 26
+ ULONG EnableHogMode: 1; // 27
+ ULONG FlushTlb: 1; // 28
+ ULONG EnableCbusParityCheck: 1; // 29
+ ULONG CbusInterfaceReset: 1; // 30
+ ULONG EnablePciLock: 1; // 31
+ ULONG EnableCbusBackToBackCycle: 1; // 32
+ ULONG T2RevisionNumber: 3; // 33
+ ULONG StateMachineVisibilitySelect: 3; // 36
+ ULONG Mba4: 1; // 39
+ ULONG EnablePassiveRelease: 1; // 40
+ ULONG EnablePciRdp64: 1; // 41 (T4)
+ ULONG EnablePciAp64: 1; // 42 (T4)
+ ULONG EnablePciWdp64: 1; // 43 (T4)
+ ULONG CbusCAWriteWrongParity1: 1; // 44
+ ULONG CbusCAWriteWrongParity3: 1; // 45
+ ULONG CbusCADataWriteWrongParityOdd: 1; // 46
+ ULONG T2T4Status: 1; // 47
+ ULONG EnablePpc1: 1; // 48 (T3/T4)
+ ULONG EnablePpc2: 1; // 49 (T3/T4)
+ ULONG EnablePciStall: 1; // 50 (T3/T4)
+ ULONG Mbz0: 1; // 51
+ ULONG PciReadMultiple: 1; // 52
+ ULONG PciWriteMultiple: 1; // 53
+ ULONG ForcePciRdpeDetect: 1; // 54
+ ULONG ForcePciApeDetect: 1; // 55
+ ULONG ForcePciWdpeDetect: 1; // 56
+ ULONG EnablePciNmi: 1; // 57
+ ULONG EnablePciDti: 1; // 58
+ ULONG EnablePciSerr: 1; // 59
+ ULONG EnablePciPerr: 1; // 60
+ ULONG EnablePciRdp: 1; // 61
+ ULONG EnablePciAp: 1; // 62
+ ULONG EnablePciWdp: 1; // 63
+ };
+ ULONGLONG all;
+} T2_IOCSR, *PT2_IOCSR;
+
+typedef union _T2_CERR1 {
+ struct {
+ ULONG UncorrectableReadError: 1; // 00
+ ULONG NoAcknowledgeError: 1; // 01
+ ULONG CommandAddressParityError: 1; // 02
+ ULONG MissedCommandAddressParity: 1; // 03
+ ULONG ResponderWriteDataParityError: 1; // 04
+ ULONG MissedRspWriteDataParityError: 1; // 05
+ ULONG ReadDataParityError: 1; // 06
+ ULONG MissedReadDataParityError: 1; // 07
+ ULONG CaParityErrorLw0: 1; // 08
+ ULONG CaParityErrorLw2: 1; // 09
+ ULONG DataParityErrorLw0: 1; // 10
+ ULONG DataParityErrorLw2: 1; // 11
+ ULONG DataParityErrorLw4: 1; // 12
+ ULONG DataParityErrorLw6: 1; // 13
+ ULONG Reserved1: 2; // 14-15
+ ULONG CmdrWriteDataParityError: 1; // 16
+ ULONG BusSynchronizationError: 1; // 17
+ ULONG InvalidPfnError: 1; // 18
+ ULONG Mbz0: 13; // 19-31
+ ULONG Mbz1: 8; // 32-39
+ ULONG CaParityErrorLw1: 1; // 40
+ ULONG CaParityErrorLw3: 1; // 41
+ ULONG DataParityErrorLw1: 1; // 42
+ ULONG DataParityErrorLw3: 1; // 43
+ ULONG DataParityErrorLw5: 1; // 44
+ ULONG DataParityErrorLw7: 1; // 45
+ ULONG Mbz2: 18; // 46-63
+ };
+ ULONGLONG all;
+} T2_CERR1, *PT2_CERR1;
+
+typedef ULONGLONG T2_CERR2;
+typedef ULONGLONG T2_CERR3;
+
+typedef union _T2_PERR1 {
+ struct {
+ ULONG WriteDataParityError: 1; // 00
+ ULONG AddressParityError: 1; // 01
+ ULONG ReadDataParityError: 1; // 02
+ ULONG ParityError: 1; // 03
+ ULONG SystemError: 1; // 04
+ ULONG DeviceTimeoutError: 1; // 05
+ ULONG NonMaskableInterrupt: 1; // 06
+ ULONG PpcSizeError: 1; // 07 (T3/T4)
+ ULONG WriteDataParityError64: 1; // 08 (T3/T4)
+ ULONG AddressParityError64: 1; // 09 (T3/T4)
+ ULONG ReadDataParityError64: 1; // 10 (T3/T4)
+ ULONG TargetAbort: 1; // 11 (T3/T4)
+ ULONG Mbz0: 4; // 12-15
+ ULONG ForceReadDataParityError64: 1; // 16 (T3/T4)
+ ULONG ForceAddressParityError64: 1; // 17 (T3/T4)
+ ULONG ForceWriteDataParityError64: 1; // 18 (T3/T4)
+ ULONG DetectTargetAbort: 1; // 19 (T3/T4)
+ ULONG Reserved1: 12; // 20-31
+ ULONG Reserved; // 32-63
+ };
+ ULONGLONG all;
+} T2_PERR1, *PT2_PERR1;
+
+typedef union _T2_PERR2 {
+ struct {
+ ULONG ErrorAddress; // 00
+ ULONG PciCommand: 4; // 32
+ ULONG Reserved: 28; // 36-63
+ };
+ ULONGLONG all;
+} T2_PERR2, *PT2_PERR2;
+
+typedef struct _T2_WBASE {
+ union {
+ struct {
+ ULONG PciWindowEndAddress: 12; // 00
+ ULONG Reserved0: 5; // 12
+ ULONG EnablePeerToPeer: 1; // 17
+ ULONG EnableScatterGather: 1; // 18
+ ULONG EnablePciWindow: 1; // 19
+ ULONG PciWindowStartAddress: 12; // 20
+ ULONG Reserved; // 32-63
+ };
+ ULONGLONG all;
+ };
+} T2_WBASE, *PT2_WBASE;
+
+typedef struct _T2_WMASK {
+ union {
+ struct {
+ ULONG Reserved0: 20; // 00
+ ULONG PciWindowMask: 11; // 20
+ ULONG Reserved1: 1; // 31
+ ULONG Reserved; // 32-63
+ };
+ ULONGLONG all;
+ };
+} T2_WMASK, *PT2_WMASK;
+
+typedef struct _T2_TBASE {
+ union {
+ struct {
+ ULONG Reserved0: 9; // 00
+ ULONG TranslatedBaseAddress: 22; // 09
+ ULONG Reserved1: 1; // 31
+ ULONG Reserved; // 32-63
+ };
+ ULONGLONG all;
+ };
+} T2_TBASE, *PT2_TBASE;
+
+typedef struct _T2_HBASE {
+ union {
+ struct {
+ ULONG HoleEndAddress: 9; // 00
+ ULONG Reserved1: 4; // 09
+ ULONG Hole1Enable: 1; // 13
+ ULONG Hole2Enable: 1; // 14
+ ULONG HoleStartAddress: 9; // 15
+ ULONG Reserved2: 8; // 24
+ ULONG Reserved3; // 32-63
+ };
+ ULONGLONG all;
+ };
+} T2_HBASE, *PT2_HBASE;
+
+typedef struct _T2_TDR {
+ ULONG Tag: 30; // 00
+ ULONG Reserved1: 2; // 30
+ ULONG Valid: 1; // 32
+ ULONG Pfn: 18; // 33
+ ULONG Reserved2: 13; // 51
+} T2_TDR, *PT2_TDR;
+
+typedef union _T2_VAR { // T3/T4 Vector Address Register
+ struct {
+ ULONGLONG Vector: 6; // 00-05
+ ULONGLONG Eisa: 1; // 06
+ ULONGLONG PassiveRelease: 1; // 07
+ ULONGLONG Reserved: 56; // 08-63
+ };
+ ULONGLONG all;
+} T2_VAR, *PT2_VAR;
+
+typedef union _T2_ICE { // T3/T4 ICIC Enable Register
+ struct {
+ ULONGLONG EisaFlushAddress: 24; // 00-23
+ ULONGLONG IcEnable: 1; // 24
+ ULONGLONG HalfSpeedEnable: 1; // 25
+ ULONGLONG Reserved: 38; // 26-63
+ };
+ ULONGLONG all;
+} T2_ICE, *PT2_ICE;
+
+//
+// DMA Window Values.
+//
+// The T2 will be initialized to allow 2 DMA windows.
+// The first window will be for the use of of ISA devices and DMA slaves
+// and therefore must have logical addresses below 16MB.
+// The second window will be for bus masters (non-ISA) and so may be
+// above 16MB.
+//
+// The arrangement of the windows will be as follows:
+//
+// Window Logical Start Address Window Size
+// ------ --------------------- -----------
+// Isa 8MB 8MB
+// Master 16MB 16MB
+//
+
+#define ISA_DMA_WINDOW_BASE (__8MB)
+#define ISA_DMA_WINDOW_SIZE (__8MB)
+
+#define MASTER_DMA_WINDOW_BASE (__16MB)
+#define MASTER_DMA_WINDOW_SIZE (__16MB)
+
+
+//
+// Define the software control registers for a DMA window.
+//
+
+typedef struct _WINDOW_CONTROL_REGISTERS {
+ PVOID WindowBase;
+ ULONG WindowSize;
+ PVOID TranslatedBaseRegister[2];
+ PVOID WindowBaseRegister[2];
+ PVOID WindowMaskRegister[2];
+ PVOID WindowTbiaRegister[2];
+} WINDOW_CONTROL_REGISTERS, *PWINDOW_CONTROL_REGISTERS;
+
+//
+// Define types of windows.
+//
+
+typedef enum _T2_WINDOW_NUMBER {
+ T2IsaWindow,
+ T2MasterWindow
+} T2_WINDOW_NUMBER, *PT2_WINDOW_NUMBER;
+
+//
+// Define T2 Window Control routines.
+//
+
+VOID
+HalpT2InitializeSfwWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ T2_WINDOW_NUMBER WindowNumber
+ );
+
+VOID
+HalpT2ProgramDmaWindow(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters,
+ PVOID MapRegisterBase
+ );
+
+VOID
+HalpT2InvalidateTLB(
+ PWINDOW_CONTROL_REGISTERS WindowRegisters
+ );
+
+VOID
+WRITE_T2_REGISTER(
+ PVOID,
+ ULONGLONG
+ );
+
+ULONGLONG
+READ_T2_REGISTER(
+ PVOID
+ );
+
+
+//
+// VOID
+// INITIALIZE_ISA_DMA_CONTROL(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters
+// )
+//
+// Routine Description:
+//
+// Initialize the DMA Control software window registers for the ISA
+// DMA window.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window control.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INITIALIZE_ISA_DMA_CONTROL( WR ) \
+ HalpT2InitializeSfwWindow( (WR), T2IsaWindow );
+
+
+//
+// VOID
+// INITIALIZE_MASTER_DMA_CONTROL(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters
+// )
+//
+// Routine Description:
+//
+// Initialize the DMA Control software window registers for the ISA
+// DMA window.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window control.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INITIALIZE_MASTER_DMA_CONTROL( WR ) \
+ HalpT2InitializeSfwWindow( (WR), T2MasterWindow );
+
+
+//
+// VOID
+// INITIALIZE_DMA_WINDOW(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters,
+// PTRANSLATION_ENTRY MapRegisterBase
+// )
+//
+// Routine Description:
+//
+// Program the control windows so that DMA can be started to the
+// DMA window.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window register
+// control structure.
+//
+// MapRegisterBase - Supplies the logical address of the scatter/gather
+// array in system memory.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INITIALIZE_DMA_WINDOW( WR, MRB ) \
+ HalpT2ProgramDmaWindow( (WR), (MRB) );
+
+
+//
+// VOID
+// INVALIDATE_DMA_TRANSLATIONS(
+// PWINDOW_CONTROL_REGISTERS WindowRegisters
+// )
+//
+// Routine Description:
+//
+// Invalidate all of the cached translations for a DMA window.
+// This function does not need to do any action on the T2 chip
+// because the T2 snoops the bus and keeps the translations coherent
+// via hardware.
+//
+// Arguments:
+//
+// WindowRegisters - Supplies a pointer to the software window control
+// registers.
+//
+// Return Value:
+//
+// None.
+//
+
+#define INVALIDATE_DMA_TRANSLATIONS( WR )
+
+
+//
+// Define the format of a translation entry aka a scatter/gather entry
+// or map register.
+//
+
+typedef struct _TRANSLATION_ENTRY{
+ ULONG Valid: 1;
+ ULONG Pfn: 31;
+ ULONG Reserved;
+} TRANSLATION_ENTRY, *PTRANSLATION_ENTRY;
+
+
+
+//
+// VOID
+// HAL_MAKE_VALID_TRANSLATION(
+// PTRANSLATION_ENTRY Entry,
+// ULONG PageFrameNumber
+// )
+//
+// Routine Description:
+//
+// Make the scatter/gather entry pointed to by Entry valid with
+// a translation to the page indicated by PageFrameNumber.
+//
+// Arguments:
+//
+// Entry - Supplies a pointer to the translation entry to make valid.
+//
+// PageFrameNumber - Supplies the page frame of the valid translation.
+//
+// Return Value:
+//
+// None.
+//
+
+#define HAL_MAKE_VALID_TRANSLATION( ENTRY, PFN ) \
+ { \
+ (ENTRY)->Valid = 1; \
+ (ENTRY)->Pfn = PFN; \
+ (ENTRY)->Reserved = 0; \
+ }
+
+
+//
+// VOID
+// HAL_INVALIDATE_TRANSLATION(
+// PTRANSLATION_ENTRY Entry
+// )
+//
+// Routine Description:
+//
+// Invalidate the translation indicated by Entry.
+//
+// Arguments:
+//
+// Entry - Supplies a pointer to the translation to be invalidated.
+//
+// Return Value:
+//
+// None.
+//
+
+#define HAL_INVALIDATE_TRANSLATION( ENTRY ) \
+ (ENTRY)->Valid = 0;
+
+#endif // T2H
diff --git a/private/ntos/nthals/halalpha/vga.c b/private/ntos/nthals/halalpha/vga.c
new file mode 100644
index 000000000..c8b10394f
--- /dev/null
+++ b/private/ntos/nthals/halalpha/vga.c
@@ -0,0 +1,608 @@
+/*++
+
+Copyright (c) 1992, 1993, 1994 Digital Equipment Corporation
+
+Module Name:
+
+ vga.c
+
+Abstract:
+
+ This module implements device-independent HAL display initialization and
+ output routines for Alpha systems.
+
+ It was stolen from a combination of the jxdisp.c routine in the firmware
+ directory, written by John DeRosa, and the jxdisp.c routines in the MIPS
+ HAL directory.
+
+Author:
+
+ Miche Baker-Harvey (miche) 10-Jun-1992
+
+Environment:
+
+ Kernel mode
+
+Revision History:
+
+ 12-July-1994 Eric Rehm
+ Support RESET_DISPLAY_PARAMETERS callback registered during
+ HalAcquireDisplayOwnership. This callback is supplied by
+ the Video Miniport driver's HwResetHw entry in the HW_INITIALIZATION_DATA
+ structure.
+
+ 17-Feb-1994 Eric Rehm
+ Rewrite ouput routines to be device-independent through callback
+ to firmware VenPrint routine.
+
+ 30-Dec-1993 Joe Notarangelo
+ Eliminate the video initialization code that was compiled only
+ when VIDEO_CALLBACK_IMPLEMENTED is not defined. It is now a
+ requirement that the firmware implement the callback.
+
+ 04-Mar-1993 Joe Mitchell (DEC)
+ Modify HalpScrollDisplay to pause after displaying each screenful of
+ information during a bugcheck.
+ Modify InitializeVGA to call the firmware to init the video display
+ rather than doing the initialization itself.
+
+ 10-Aug-1992 Jeff McLeman (DEC)
+ Put in debug fixes.
+
+ 22-Jul-1992 Jeff McLeman (mcleman)
+ Remove inline asm(MB)s , because Hal access routines manage
+ read/write ordering.
+
+--*/
+
+//
+// Need some include files here
+#include "halp.h"
+#include "arc.h"
+#include "halvga.h"
+#include "fwcallbk.h"
+#include "stdio.h"
+
+//
+// Define forward referenced procedure prototypes.
+//
+
+VOID
+HalpDisplayCharacter (
+ IN UCHAR Character
+ );
+
+VOID
+HalpSetLoc (
+ );
+
+BOOLEAN
+InitializeDisplay (
+ );
+
+BOOLEAN
+HalpInitializeDisplay (
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+VOID
+HalpScrollDisplay(
+ VOID
+ );
+
+VOID
+HalpFlushKeyboardBuffer (
+ VOID
+ );
+
+VOID
+HalpWaitForKeyPress (
+ VOID
+ );
+typedef
+ULONG
+(*PFW_INITIALIZE_VIDEO_CALLBACK) (
+ OUT ULONG AlphaVideoType
+ );
+
+
+//
+// Define static data.
+//
+
+BOOLEAN HalpDisplayInitialized = FALSE;
+BOOLEAN HalpDisplayOwnedByHal;
+ULONG HalpColumn;
+ULONG HalpRow;
+PUCHAR HalpDestination;
+ULONG HalpForegroundColor;
+ULONG HalpBackgroundColor;
+ULONG DisplayWidth;
+ULONG DisplayHeight;
+ULONG MaxRow;
+ULONG MaxColumn;
+
+#define CONTROL_SEQUENCE_MAX_PARAMETER 10
+ULONG Parameter[CONTROL_SEQUENCE_MAX_PARAMETER];
+
+PHAL_RESET_DISPLAY_PARAMETERS HalpResetDisplayParameters;
+
+//
+// Declare externally defined data.
+//
+// none.
+
+
+BOOLEAN
+HalpInitializeDisplay (
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes and clears the display.
+
+ This is called during phase 0 of the Hal initialization.
+
+Arguments:
+
+ LoaderBlock - Supplies a pointer to the loader parameter block.
+
+Return Value:
+
+ If the initialization is successfully completed, than a value of TRUE
+ is returned. Otherwise, a value of FALSE is returned.
+
+--*/
+
+{
+
+ //
+ // Initialize static data.
+ //
+
+ HalpColumn = 0;
+ HalpRow = 0;
+
+ //
+ // Initialize the display controller.
+ //
+
+ if (InitializeDisplay() == TRUE) {
+
+ //
+ // Mark the display as successfully initialized.
+ //
+
+ HalpDisplayInitialized = TRUE;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+BOOLEAN
+InitializeDisplay (
+ )
+
+/*++
+
+Routine Description:
+
+ This routine initializes and clears the display.
+
+ It is initialized to: alphanumeric mode, 16 colors fore & background,
+ 8x16 pixel fonts, 80x25 characters, 640 x 400 display.
+ This is not ARC compliant (no underline, no monochrome support)
+ but its good enough for now and can be enhanced later. (For booting,
+ the ARC spec is overkill anyway.)
+
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ If the video was initialized, TRUE is returned, otherwise FALSE
+
+--*/
+
+{
+ ULONG UnusedParameter;
+ PARC_DISPLAY_STATUS DisplayStatus;
+ char String[16];
+
+ //
+ // Initialize static data.
+ //
+
+ HalpForegroundColor = FW_COLOR_HI_WHITE;
+ HalpBackgroundColor = FW_COLOR_BLUE;
+
+ DisplayStatus = ArcGetDisplayStatus(ARC_CONSOLE_OUTPUT);
+ DisplayWidth = DisplayStatus->CursorMaxXPosition;
+ DisplayHeight = DisplayStatus->CursorMaxYPosition;
+
+ MaxRow = DisplayHeight -1;
+ MaxColumn = DisplayWidth -1;
+
+ //
+ // [ecr] Call the video driver to intialize the video display,
+ // if it has supplied a reset routine.
+ //
+
+ if (HalpResetDisplayParameters) {
+ HalpDisplayOwnedByHal = HalpResetDisplayParameters(MaxColumn+1, MaxRow+1);
+ }
+
+ //
+ // [jrm] Call the firmware to initialize the video display.
+ //
+
+ VenVideoDisplayInitialize(&UnusedParameter);
+
+ //
+ // Initialize the current display column, row, and ownership values.
+ //
+
+ HalpDisplayOwnedByHal = TRUE;
+
+ //
+ // Set the video memory to blue.
+ //
+
+ sprintf(String, "%c%dm%c%2J", ASCII_CSI, HalpBackgroundColor+40,
+ ASCII_CSI);
+ VenPrint(String);
+
+
+ return TRUE;
+}
+
+VOID
+HalAcquireDisplayOwnership (
+ IN PHAL_RESET_DISPLAY_PARAMETERS ResetDisplayParameters
+ )
+
+/*++
+
+Routine Description:
+
+ This routine switches ownership of the display away from the HAL to
+ the system display driver. It is called when the system has reached
+ a point during bootstrap where it is self supporting and can output
+ its own messages. Once ownership has passed to the system display
+ driver any attempts to output messages using HalDisplayString must
+ result in ownership of the display reverting to the HAL and the
+ display hardware reinitialized for use by the HAL.
+
+Arguments:
+
+ ResetDisplayParameters - if non-NULL the address of a function
+ the hal can call to reset the video card. The function returns
+ TRUE if the display was reset.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Set HAL ownership of the display to false.
+ //
+
+ HalpDisplayOwnedByHal = FALSE;
+ HalpResetDisplayParameters=ResetDisplayParameters;
+
+ //
+ // Reset the display to begin in the upper left corner.
+ //
+
+ HalpColumn = 0;
+ HalpRow = 0;
+
+ return;
+}
+
+VOID
+HalpVideoReboot(
+ VOID
+ )
+{
+
+ if (HalpResetDisplayParameters && !HalpDisplayOwnedByHal) {
+
+ //
+ // Video work-around. The video driver has a reset function,
+ // call it before resetting the system in case the bios doesn't
+ // know how to reset the display's video mode.
+ //
+#if HALDBG
+ DbgPrint("HalpVideoReboot: calling HalpResetDisplayParameters (%x,%x)\n",
+ MaxColumn+1, MaxRow+1);
+#endif
+
+ HalpResetDisplayParameters(MaxColumn+1, MaxRow+1);
+ }
+}
+
+VOID
+HalDisplayString (
+ PUCHAR String
+ )
+
+/*++
+
+Routine Description:
+
+ This routine displays a character string on the display screen.
+
+Arguments:
+
+ String - Supplies a pointer to the characters that are to be displayed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ KIRQL OldIrql;
+
+ //
+ // Note that the MIPS version of this routine goes through mapping
+ // the device into the users space; since we have reserved the top
+ // PDE in system space, we dont have to do this - its always mapped.
+ //
+
+ //
+ // Check if the display has already been successfully initialized.
+ // If it has not then we cannot print on the display.
+ //
+
+ if( HalpDisplayInitialized != TRUE ){
+
+#if (DBG) || (HALDBG)
+
+ DbgPrint( "HDS: %s\n", String );
+
+#endif //DBG || HALDBG
+
+ return;
+
+ }
+
+ //
+ // Raise the IRQL to dispatch level and acquire the display adapter lock.
+ //
+
+ KeRaiseIrql(HIGH_LEVEL, &OldIrql);
+ KiAcquireSpinLock(&HalpDisplayAdapterLock);
+
+ //
+ // If ownership of the display has been switched to the system display
+ // driver, then reinitialize the display controller and revert ownership
+ // to the HAL.
+ //
+
+ if (HalpDisplayOwnedByHal == FALSE) {
+ InitializeDisplay();
+ }
+
+ while (*String)
+ {
+ switch (*String)
+ {
+ case '\n':
+ if (HalpRow == MaxRow-1-1) {
+ HalpScrollDisplay();
+ } else {
+ ++HalpRow;
+ }
+ HalpColumn = 0;
+ break;
+
+ case '\b':
+ if(HalpColumn != 0) {
+ --HalpColumn;
+ }
+ break;
+
+ case '\r':
+ HalpColumn = 0;
+ break;
+
+ default:
+ if (HalpColumn > MaxColumn)
+ {
+ if (HalpRow == MaxRow-1-1) {
+ HalpScrollDisplay();
+ } else {
+ ++HalpRow;
+ }
+ HalpColumn = 0;
+ }
+ HalpDisplayCharacter(*String);
+ HalpColumn++;
+ }
+ ++String;
+ }
+
+ //
+ // Release the display adapter lock and restore the IRQL.
+ //
+
+ KiReleaseSpinLock(&HalpDisplayAdapterLock);
+ KeLowerIrql(OldIrql);
+
+ return;
+}
+
+VOID
+HalQueryDisplayParameters (
+ OUT PULONG WidthInCharacters,
+ OUT PULONG HeightInLines,
+ OUT PULONG CursorColumn,
+ OUT PULONG CursorRow
+ )
+
+/*++
+
+Routine Description:
+
+ This routine return information about the display area and current
+ cursor position.
+
+Arguments:
+
+ WidthInCharacter - Supplies a pointer to a varible that receives
+ the width of the display area in characters.
+
+ HeightInLines - Supplies a pointer to a variable that receives the
+ height of the display area in lines.
+
+ CursorColumn - Supplies a pointer to a variable that receives the
+ current display column position.
+
+ CursorRow - Supplies a pointer to a variable that receives the
+ current display row position.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Set the display parameter values and return.
+ //
+
+ *WidthInCharacters = DisplayWidth;
+ *HeightInLines = DisplayHeight;
+ *CursorColumn = HalpColumn;
+ *CursorRow = HalpRow;
+ return;
+}
+
+VOID
+HalSetDisplayParameters (
+ IN ULONG CursorColumn,
+ IN ULONG CursorRow
+ )
+
+/*++
+
+Routine Description:
+
+ This routine set the current cursor position on the display area.
+
+Arguments:
+
+ CursorColumn - Supplies the new display column position.
+
+ CursorRow - Supplies a the new display row position.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ //
+ // Set the display parameter values and return.
+ //
+
+ if (CursorColumn > DisplayWidth) {
+ CursorColumn = DisplayWidth;
+ }
+
+ if (CursorRow > DisplayHeight) {
+ CursorRow = DisplayHeight;
+ }
+
+ HalpColumn = CursorColumn;
+ HalpRow = CursorRow;
+ return;
+}
+
+VOID
+HalpDisplayCharacter (
+ IN UCHAR Character
+ )
+
+/*++
+
+Routine Description:
+
+ This routine displays a character at the current x and y positions in
+ the frame buffer.
+
+
+Arguments:
+
+ Character - Supplies a character to be displayed.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ char String[16];
+
+ sprintf(String, "%c%d;%dH%c%d;%dm%c",
+ ASCII_CSI, HalpRow+1, HalpColumn+1,
+ ASCII_CSI, HalpForegroundColor+30, HalpBackgroundColor+40,
+ Character);
+ VenPrint(String);
+
+}
+
+
+VOID
+HalpScrollDisplay (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This routine scrolls the display up one line.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ char String[16];
+
+ //
+ // Force a FwScrollDisplay by positioning FwRow off the
+ // bottom of the screen and then doing a line feed.
+ //
+
+ sprintf(String, "%c%dB%c", ASCII_CSI, 255, ASCII_LF);
+ VenPrint(String);
+
+}