summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halncr
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nthals/halncr')
-rw-r--r--private/ntos/nthals/halncr/drivesup.c7
-rw-r--r--private/ntos/nthals/halncr/hal.rc11
-rw-r--r--private/ntos/nthals/halncr/hal.src20
-rw-r--r--private/ntos/nthals/halncr/i386/halnls.h5
-rw-r--r--private/ntos/nthals/halncr/i386/halp.h5
-rw-r--r--private/ntos/nthals/halncr/i386/ix8259.inc5
-rw-r--r--private/ntos/nthals/halncr/i386/ixbeep.asm5
-rw-r--r--private/ntos/nthals/halncr/i386/ixbusdat.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixcmos.asm5
-rw-r--r--private/ntos/nthals/halncr/i386/ixcmos.inc5
-rw-r--r--private/ntos/nthals/halncr/i386/ixdat.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixenvirv.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixhwsup.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixidle.asm5
-rw-r--r--private/ntos/nthals/halncr/i386/ixinfo.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixisa.h5
-rw-r--r--private/ntos/nthals/halncr/i386/ixisabus.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixisasup.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixkdcom.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixkdcom.h5
-rw-r--r--private/ntos/nthals/halncr/i386/ixmca.h5
-rw-r--r--private/ntos/nthals/halncr/i386/ixmcabus.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixmcasup.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixnmi.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixpcibrd.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixpcibus.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixpciint.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixphwsup.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixprofil.asm5
-rw-r--r--private/ntos/nthals/halncr/i386/ixstall.asm481
-rw-r--r--private/ntos/nthals/halncr/i386/ixswint.asm5
-rw-r--r--private/ntos/nthals/halncr/i386/ixsysbus.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixthunk.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ixusage.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ncr.h94
-rw-r--r--private/ntos/nthals/halncr/i386/ncr.inc453
-rw-r--r--private/ntos/nthals/halncr/i386/ncrarb.h157
-rw-r--r--private/ntos/nthals/halncr/i386/ncrcat.c3223
-rw-r--r--private/ntos/nthals/halncr/i386/ncrcat.h308
-rw-r--r--private/ntos/nthals/halncr/i386/ncrcatlk.asm120
-rw-r--r--private/ntos/nthals/halncr/i386/ncrcatp.h232
-rw-r--r--private/ntos/nthals/halncr/i386/ncrclock.asm724
-rw-r--r--private/ntos/nthals/halncr/i386/ncrdetct.c5
-rw-r--r--private/ntos/nthals/halncr/i386/ncrhwsup.c170
-rw-r--r--private/ntos/nthals/halncr/i386/ncrintr.asm823
-rw-r--r--private/ntos/nthals/halncr/i386/ncrioacc.asm730
-rw-r--r--private/ntos/nthals/halncr/i386/ncripi.asm362
-rw-r--r--private/ntos/nthals/halncr/i386/ncrirql.asm1223
-rw-r--r--private/ntos/nthals/halncr/i386/ncrlarc.c392
-rw-r--r--private/ntos/nthals/halncr/i386/ncrlock.asm103
-rw-r--r--private/ntos/nthals/halncr/i386/ncrmcabs.c243
-rw-r--r--private/ntos/nthals/halncr/i386/ncrmem.h494
-rw-r--r--private/ntos/nthals/halncr/i386/ncrmp.c2443
-rw-r--r--private/ntos/nthals/halncr/i386/ncrnls.h62
-rw-r--r--private/ntos/nthals/halncr/i386/ncrnmi.c422
-rw-r--r--private/ntos/nthals/halncr/i386/ncrpsi.h291
-rw-r--r--private/ntos/nthals/halncr/i386/ncrqic.c329
-rw-r--r--private/ntos/nthals/halncr/i386/ncrstart.asm987
-rw-r--r--private/ntos/nthals/halncr/i386/ncrstop.c219
-rw-r--r--private/ntos/nthals/halncr/i386/ncrsus.c678
-rw-r--r--private/ntos/nthals/halncr/i386/ncrsus.h361
-rw-r--r--private/ntos/nthals/halncr/i386/ncrsyint.asm711
-rw-r--r--private/ntos/nthals/halncr/i386/pcip.h5
-rw-r--r--private/ntos/nthals/halncr/i386/xxbiosa.asm5
-rw-r--r--private/ntos/nthals/halncr/i386/xxbiosc.c5
-rw-r--r--private/ntos/nthals/halncr/i386/xxdisp.c5
-rw-r--r--private/ntos/nthals/halncr/i386/xxflshbf.c5
-rw-r--r--private/ntos/nthals/halncr/i386/xxhal.c5
-rw-r--r--private/ntos/nthals/halncr/i386/xxioacc.asm5
-rw-r--r--private/ntos/nthals/halncr/i386/xxkdsup.c5
-rw-r--r--private/ntos/nthals/halncr/i386/xxmemory.c5
-rw-r--r--private/ntos/nthals/halncr/i386/xxstubs.c5
-rw-r--r--private/ntos/nthals/halncr/i386/xxtime.c5
-rw-r--r--private/ntos/nthals/halncr/makefile6
-rw-r--r--private/ntos/nthals/halncr/makefile.inc2
-rw-r--r--private/ntos/nthals/halncr/sources110
76 files changed, 17201 insertions, 0 deletions
diff --git a/private/ntos/nthals/halncr/drivesup.c b/private/ntos/nthals/halncr/drivesup.c
new file mode 100644
index 000000000..38259e5f4
--- /dev/null
+++ b/private/ntos/nthals/halncr/drivesup.c
@@ -0,0 +1,7 @@
+//
+// This file simply includes the common sources from the current HAL
+// directory. When the structure is finally changed, the real file should
+// be in this directory.
+//
+
+#include "..\drivesup.c"
diff --git a/private/ntos/nthals/halncr/hal.rc b/private/ntos/nthals/halncr/hal.rc
new file mode 100644
index 000000000..3cba4ad89
--- /dev/null
+++ b/private/ntos/nthals/halncr/hal.rc
@@ -0,0 +1,11 @@
+#include <windows.h>
+
+#include <ntverp.h>
+
+#define VER_FILETYPE VFT_DLL
+#define VER_FILESUBTYPE VFT2_UNKNOWN
+#define VER_FILEDESCRIPTION_STR "Hardware Abstraction Layer DLL"
+#define VER_INTERNALNAME_STR "hal.dll"
+
+#include "common.ver"
+
diff --git a/private/ntos/nthals/halncr/hal.src b/private/ntos/nthals/halncr/hal.src
new file mode 100644
index 000000000..fd1f28579
--- /dev/null
+++ b/private/ntos/nthals/halncr/hal.src
@@ -0,0 +1,20 @@
+//
+// This file simply includes the common sources from the current HAL
+// directory. When the structure is finally changed, the real file should
+// be in this directory.
+//
+
+#include "..\hal.src"
+
+//
+// New APIs for NCR enhancements
+//
+
+ HalCatBusAvailable
+ HalCatBusIo
+ HalCatBusReset
+ HalPowerOffSystem
+ HalGetSUSErrorLogEntry
+ HalSetWatchDogPeriod
+ HalBumpWatchDogCount
+ HalSetStatusChangeInterruptState
diff --git a/private/ntos/nthals/halncr/i386/halnls.h b/private/ntos/nthals/halncr/i386/halnls.h
new file mode 100644
index 000000000..e829faba8
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/halnls.h
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\halnls.h"
diff --git a/private/ntos/nthals/halncr/i386/halp.h b/private/ntos/nthals/halncr/i386/halp.h
new file mode 100644
index 000000000..a9dbf1e13
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/halp.h
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\halp.h"
diff --git a/private/ntos/nthals/halncr/i386/ix8259.inc b/private/ntos/nthals/halncr/i386/ix8259.inc
new file mode 100644
index 000000000..b9e0a196a
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ix8259.inc
@@ -0,0 +1,5 @@
+;
+; Include code from halx86
+; This is a cpp style symbolic link
+
+include ..\halx86\i386\ix8259.inc
diff --git a/private/ntos/nthals/halncr/i386/ixbeep.asm b/private/ntos/nthals/halncr/i386/ixbeep.asm
new file mode 100644
index 000000000..f53bd3e58
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixbeep.asm
@@ -0,0 +1,5 @@
+;
+; Include code from halx86
+; This is a cpp style symbolic link
+
+include ..\halx86\i386\ixbeep.asm
diff --git a/private/ntos/nthals/halncr/i386/ixbusdat.c b/private/ntos/nthals/halncr/i386/ixbusdat.c
new file mode 100644
index 000000000..a42039752
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixbusdat.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixbusdat.c"
diff --git a/private/ntos/nthals/halncr/i386/ixcmos.asm b/private/ntos/nthals/halncr/i386/ixcmos.asm
new file mode 100644
index 000000000..7f4e7393e
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixcmos.asm
@@ -0,0 +1,5 @@
+;
+; Include code from halx86
+; This is a cpp style symbolic link
+
+include ..\halx86\i386\ixcmos.asm
diff --git a/private/ntos/nthals/halncr/i386/ixcmos.inc b/private/ntos/nthals/halncr/i386/ixcmos.inc
new file mode 100644
index 000000000..2fe289fb0
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixcmos.inc
@@ -0,0 +1,5 @@
+;
+; Include code from halx86
+; This is a cpp style symbolic link
+
+include ..\halx86\i386\ixcmos.inc
diff --git a/private/ntos/nthals/halncr/i386/ixdat.c b/private/ntos/nthals/halncr/i386/ixdat.c
new file mode 100644
index 000000000..f6b0e34de
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixdat.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixdat.c"
diff --git a/private/ntos/nthals/halncr/i386/ixenvirv.c b/private/ntos/nthals/halncr/i386/ixenvirv.c
new file mode 100644
index 000000000..e194820ba
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixenvirv.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixenvirv.c"
diff --git a/private/ntos/nthals/halncr/i386/ixhwsup.c b/private/ntos/nthals/halncr/i386/ixhwsup.c
new file mode 100644
index 000000000..ea91dc8d0
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixhwsup.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixhwsup.c"
diff --git a/private/ntos/nthals/halncr/i386/ixidle.asm b/private/ntos/nthals/halncr/i386/ixidle.asm
new file mode 100644
index 000000000..9bdd670f3
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixidle.asm
@@ -0,0 +1,5 @@
+;
+; Include code from halx86
+; This is a cpp style symbolic link
+
+include ..\halx86\i386\ixidle.asm
diff --git a/private/ntos/nthals/halncr/i386/ixinfo.c b/private/ntos/nthals/halncr/i386/ixinfo.c
new file mode 100644
index 000000000..7f211f7a9
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixinfo.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixinfo.c"
diff --git a/private/ntos/nthals/halncr/i386/ixisa.h b/private/ntos/nthals/halncr/i386/ixisa.h
new file mode 100644
index 000000000..f67b35f49
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixisa.h
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixisa.h"
diff --git a/private/ntos/nthals/halncr/i386/ixisabus.c b/private/ntos/nthals/halncr/i386/ixisabus.c
new file mode 100644
index 000000000..c1edfb067
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixisabus.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixisabus.c"
diff --git a/private/ntos/nthals/halncr/i386/ixisasup.c b/private/ntos/nthals/halncr/i386/ixisasup.c
new file mode 100644
index 000000000..58c426544
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixisasup.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixisasup.c"
diff --git a/private/ntos/nthals/halncr/i386/ixkdcom.c b/private/ntos/nthals/halncr/i386/ixkdcom.c
new file mode 100644
index 000000000..29bb8308e
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixkdcom.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixkdcom.c"
diff --git a/private/ntos/nthals/halncr/i386/ixkdcom.h b/private/ntos/nthals/halncr/i386/ixkdcom.h
new file mode 100644
index 000000000..22f1aac09
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixkdcom.h
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixkdcom.h"
diff --git a/private/ntos/nthals/halncr/i386/ixmca.h b/private/ntos/nthals/halncr/i386/ixmca.h
new file mode 100644
index 000000000..f401e096e
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixmca.h
@@ -0,0 +1,5 @@
+//
+// Include code from halmca
+// This is a cpp style symbolic link
+
+#include "..\halmca\i386\ixmca.h"
diff --git a/private/ntos/nthals/halncr/i386/ixmcabus.c b/private/ntos/nthals/halncr/i386/ixmcabus.c
new file mode 100644
index 000000000..8ef2ef197
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixmcabus.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halmca\i386\ixmcabus.c"
diff --git a/private/ntos/nthals/halncr/i386/ixmcasup.c b/private/ntos/nthals/halncr/i386/ixmcasup.c
new file mode 100644
index 000000000..625d7e412
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixmcasup.c
@@ -0,0 +1,5 @@
+//
+// Include code from halmca
+// This is a cpp style symbolic link
+
+#include "..\halmca\i386\ixmcasup.c"
diff --git a/private/ntos/nthals/halncr/i386/ixnmi.c b/private/ntos/nthals/halncr/i386/ixnmi.c
new file mode 100644
index 000000000..2ab99a52b
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixnmi.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixnmi.c"
diff --git a/private/ntos/nthals/halncr/i386/ixpcibrd.c b/private/ntos/nthals/halncr/i386/ixpcibrd.c
new file mode 100644
index 000000000..02fd82821
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixpcibrd.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixpcibrd.c"
diff --git a/private/ntos/nthals/halncr/i386/ixpcibus.c b/private/ntos/nthals/halncr/i386/ixpcibus.c
new file mode 100644
index 000000000..640cebfba
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixpcibus.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixpcibus.c"
diff --git a/private/ntos/nthals/halncr/i386/ixpciint.c b/private/ntos/nthals/halncr/i386/ixpciint.c
new file mode 100644
index 000000000..5243acee5
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixpciint.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixpciint.c"
diff --git a/private/ntos/nthals/halncr/i386/ixphwsup.c b/private/ntos/nthals/halncr/i386/ixphwsup.c
new file mode 100644
index 000000000..a1cdab598
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixphwsup.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixphwsup.c"
diff --git a/private/ntos/nthals/halncr/i386/ixprofil.asm b/private/ntos/nthals/halncr/i386/ixprofil.asm
new file mode 100644
index 000000000..c33b273ae
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixprofil.asm
@@ -0,0 +1,5 @@
+;
+; Include code from halx86
+; This is a cpp style symbolic link
+
+include ..\halx86\i386\ixprofil.asm
diff --git a/private/ntos/nthals/halncr/i386/ixstall.asm b/private/ntos/nthals/halncr/i386/ixstall.asm
new file mode 100644
index 000000000..4e33c55fb
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixstall.asm
@@ -0,0 +1,481 @@
+
+ title "Stall Execution Support"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; ixstall.asm
+;
+; Abstract:
+;
+; This module implements the code necessary to field and process the
+; interval clock interrupt.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 12-Jan-1990
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+; bryanwi 20-Sep-90
+;
+; Add KiSetProfileInterval, KiStartProfileInterrupt,
+; KiStopProfileInterrupt procedures.
+; KiProfileInterrupt ISR.
+; KiProfileList, KiProfileLock are delcared here.
+;
+; shielint 10-Dec-90
+; Add performance counter support.
+; Move system clock to irq8, ie we now use RTC to generate system
+; clock. Performance count and Profile use timer 1 counter 0.
+; The interval of the irq0 interrupt can be changed by
+; KiSetProfileInterval. Performance counter does not care about the
+; interval of the interrupt as long as it knows the rollover count.
+; Note: Currently I implemented 1 performance counter for the whole
+; i386 NT.
+;
+; John Vert (jvert) 11-Jul-1991
+; Moved from ke\i386 to hal\i386. Removed non-HAL stuff
+;
+; shie-lin tzong (shielint) 13-March-92
+; Move System clock back to irq0 and use RTC (irq8) to generate
+; profile interrupt. Performance counter and system clock use time1
+; counter 0 of 8254.
+;
+; Landy Wang (corollary!landy) 04-Dec-92
+; Created this module by moving routines from ixclock.asm to here.
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\ncr.inc
+include i386\ix8259.inc
+include i386\kimacro.inc
+include mac386.inc
+include i386\ixcmos.inc
+ .list
+
+ EXTRNP _DbgBreakPoint,0,IMPORT
+ EXTRNP _HalpAcquireCmosSpinLock ,0
+ EXTRNP _HalpReleaseCmosSpinLock ,0
+
+;
+; Constants used to initialize CMOS/Real Time Clock
+;
+
+D_INT032 EQU 8E00h ; access word for 386 ring 0 interrupt gate
+RTCIRQ EQU 8 ; IRQ number for RTC interrupt
+REGISTER_B_ENABLE_PERIODIC_INTERRUPT EQU 01000010B
+ ; RT/CMOS Register 'B' Init byte
+ ; Values for byte shown are
+ ; Bit 7 = Update inhibit
+ ; Bit 6 = Periodic interrupt enable
+ ; Bit 5 = Alarm interrupt disable
+ ; Bit 4 = Update interrupt disable
+ ; Bit 3 = Square wave disable
+ ; Bit 2 = BCD data format
+ ; Bit 1 = 24 hour time mode
+ ; Bit 0 = Daylight Savings disable
+
+REGISTER_B_DISABLE_PERIODIC_INTERRUPT EQU 00000010B
+
+;
+; RegisterAInitByte sets 8Hz clock rate, used during init to set up
+; KeStallExecutionProcessor, etc. (See RegASystemClockByte below.)
+;
+
+RegisterAInitByte EQU 00101101B ; RT/CMOS Register 'A' init byte
+ ; 32.768KHz Base divider rate
+ ; 8Hz int rate, period = 125.0ms
+PeriodInMicroSecond EQU 125000 ;
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+HalpP0BugBugStallCount dd 0
+
+_DATA ends
+
+INIT SEGMENT PARA PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "Initialize Stall Execution Counter"
+;++
+;
+; VOID
+; HalpInitializeStallExecution (
+; IN CCHAR ProcessorNumber
+; )
+;
+; Routine Description:
+;
+; This routine initialize the per Microsecond counter for
+; KeStallExecutionProcessor
+;
+; Arguments:
+;
+; ProcessorNumber - Processor Number
+;
+; Return Value:
+;
+; None.
+;
+; Note:
+;
+; Current implementation assumes that all the processors share
+; the same Real Time Clock. So, the dispatcher database lock is
+; acquired before entering this routine to guarantee only one
+; processor can access the routine.
+;
+;--
+
+KiseInterruptCount equ [ebp-12] ; local variable
+
+cPublicProc _HalpInitializeStallExecution ,1
+
+ifndef NT_UP
+;;
+;; This function currently doesn't work from any processor but the
+;; boot processor - for now stub out the others
+;;
+
+ mov eax, PCR[PcPrcb]
+ cmp byte ptr [eax].PbNumber, 0
+ je @f
+
+ mov eax, HalpP0BugBugStallCount
+ mov PCR[PcStallScaleFactor], eax
+ stdRET _HalpInitializeStallExecution
+@@:
+endif
+
+ push ebp ; save ebp
+ mov ebp, esp ; set up 12 bytes for local use
+ sub esp, 12
+
+ pushfd ; save caller's eflag
+
+;
+; Initialize Real Time Clock to interrupt us for every 125ms at
+; IRQ 8.
+;
+
+ cli ; make sure interrupts are disabled
+
+;
+; Get and save current 8259 masks
+;
+
+ xor eax,eax
+
+;
+; Assume there is no third and fourth PICs
+;
+; Get interrupt Mask on PIC2
+;
+
+ in al,PIC2_PORT1
+ shl eax, 8
+
+;
+; Get interrupt Mask on PIC1
+;
+
+ in al,PIC1_PORT1
+ push eax ; save the masks
+ mov eax, NOT (( 1 SHL PIC_SLAVE_IRQ) + (1 SHL RTCIRQ))
+ ; Mask all the irqs except irq 2 and 8
+ SET_IRQ_MASK ; Set 8259's int mask register
+
+;
+; Since RTC interrupt will come from IRQ 8, we need to
+; Save original irq 8 descriptor and set the descriptor to point to
+; our own handler.
+;
+
+ sidt fword ptr [ebp-8] ; get IDT address
+ mov ecx, [ebp-6] ; (ecx)->IDT
+
+ mov eax, (RTCIRQ+PRIMARY_VECTOR_BASE)
+
+ shl eax, 3 ; 8 bytes per IDT entry
+ add ecx, eax ; now at the correct IDT RTC entry
+
+ push dword ptr [ecx] ; (TOS) = original desc of IRQ 8
+ push dword ptr [ecx + 4] ; each descriptor has 8 bytes
+
+ ;
+ ; Pushing the appropriate entry address now (instead of
+ ; the IDT start address later) to make the pop at the end simpler.
+ ;
+ push ecx ; (TOS) -> &IDT[HalProfileVector]
+
+ mov eax, offset FLAT:RealTimeClockHandler
+
+ mov word ptr [ecx], ax ; Lower half of handler addr
+ mov word ptr [ecx+2], KGDT_R0_CODE ; set up selector
+ mov word ptr [ecx+4], D_INT032 ; 386 interrupt gate
+
+ shr eax, 16 ; (ax)=higher half of handler addr
+ mov word ptr [ecx+6], ax
+
+ mov dword ptr KiseinterruptCount, 0 ; set no interrupt yet
+
+ stdCall _HalpAcquireCmosSpinLock ; intr disabled
+
+ mov ax,(RegisterAInitByte SHL 8) OR 0AH ; Register A
+ CMOS_WRITE ; Initialize it
+;
+; Don't clobber the Daylight Savings Time bit in register B, because we
+; stash the LastKnownGood "environment variable" there.
+;
+ mov ax, 0bh
+ CMOS_READ
+ and al, 1
+ mov ah, al
+ or ah, REGISTER_B_ENABLE_PERIODIC_INTERRUPT
+ mov al, 0bh
+ CMOS_WRITE ; Initialize it
+ mov al,0CH ; Register C
+ CMOS_READ ; Read to initialize
+ mov al,0DH ; Register D
+ CMOS_READ ; Read to initialize
+ mov dword ptr [KiseInterruptCount], 0
+
+ stdCall _HalpReleaseCmosSpinLock
+
+;
+; Now enable the interrupt and start the counter
+; (As a matter of fact, only IRQ8 can come through.)
+;
+ xor eax, eax ; (eax) = 0, initialize loopcount
+ALIGN 16
+ sti
+ jmp kise10
+
+ALIGN 16
+kise10:
+ sub eax, 1 ; increment the loopcount
+ jnz short kise10
+
+if DBG
+;
+; Counter overflowed
+;
+
+ stdCall _DbgBreakPoint
+endif
+ jmp short kise10
+
+;
+; Our RealTimeClock interrupt handler. The control comes here through
+; irq 8.
+; Note: we discard first real time clock interrupt and compute the
+; permicrosecond loopcount on receiving of the second real time
+; interrupt. This is because the first interrupt is generated
+; based on the previous real time tick interval.
+;
+
+RealTimeClockHandler:
+
+ inc dword ptr KiseInterruptCount ; increment interrupt count
+ cmp dword ptr KiseInterruptCount,1 ; Is this the first interrupt?
+ jnz short kise25 ; no, its the second go process it
+ pop eax ; get rid of original ret addr
+ push offset FLAT:kise10 ; set new return addr
+
+
+ stdCall _HalpAcquireCmosSpinLock ; intr disabled
+
+ mov ax,(RegisterAInitByte SHL 8) OR 0AH ; Register A
+ CMOS_WRITE ; Initialize it
+;
+; Don't clobber the Daylight Savings Time bit in register B, because we
+; stash the LastKnownGood "environment variable" there.
+;
+ mov ax, 0bh
+ CMOS_READ
+ and al, 1
+ mov ah, al
+ or ah, REGISTER_B_ENABLE_PERIODIC_INTERRUPT
+ mov al, 0bh
+ CMOS_WRITE ; Initialize it
+ mov al,0CH ; Register C
+ CMOS_READ ; Read to initialize
+ mov al,0DH ; Register D
+ CMOS_READ ; Read to initialize
+
+ stdCall _HalpReleaseCmosSpinLock
+;
+; Dismiss the interrupt.
+;
+ mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
+ out PIC2_PORT0, al
+ mov al, PIC2_EOI ; specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+
+ xor eax, eax ; reset loop counter
+
+ iretd
+
+kise25:
+
+;
+; ** temporary - check for incorrect KeStallExecutionProcessorLoopCount
+;
+
+if DBG
+ cmp eax, 0
+ jnz short kise30
+ stdCall _DbgBreakPoint
+
+endif
+ ; never return
+;
+; ** End temporay code
+;
+
+kise30:
+ neg eax
+ xor edx, edx ; (edx:eax) = divident
+ mov ecx, PeriodInMicroSecond; (ecx) = time spent in the loop
+ div ecx ; (eax) = loop count per microsecond
+ cmp edx, 0 ; Is remainder =0?
+ jz short kise40 ; yes, go kise40
+ inc eax ; increment loopcount by 1
+kise40:
+ mov PCR[PcStallScaleFactor], eax
+ mov HalpP0BugBugStallCount, eax
+
+;
+; Reset return address to kexit
+;
+
+ pop eax ; discard original return address
+ push offset FLAT:kexit ; return to kexit
+ mov eax, (HIGHEST_LEVEL_FOR_8259 - RTCIRQ)
+
+;
+; Shutdown periodic interrupt
+;
+ stdCall _HalpAcquireCmosSpinLock
+ mov ax,(RegisterAInitByte SHL 8) OR 0AH ; Register A
+ CMOS_WRITE ; Initialize it
+ mov ax, 0bh
+ CMOS_READ
+ and al, 1
+ mov ah, al
+ or ah, REGISTER_B_DISABLE_PERIODIC_INTERRUPT
+ mov al, 0bh
+ CMOS_WRITE ; Initialize it
+ mov al,0CH ; Register C
+ CMOS_READ ; dismiss pending interrupt
+ stdCall _HalpReleaseCmosSpinLock
+
+;
+; Dismiss the interrupt.
+;
+ mov eax, RTCIRQ
+ mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
+ out PIC2_PORT0, al
+ mov al, PIC2_EOI ; specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+
+ and word ptr [esp+8], NOT 0200H ; Disable interrupt upon return
+ iretd
+
+kexit: ; Interrupts are disabled
+ pop ecx ; (ecx) -> &IDT[HalProfileVector]
+ pop [ecx+4] ; restore higher half of RTC desc
+ pop [ecx] ; restore lower half of RTC desc
+
+ pop eax ; (eax) = origianl 8259 int masks
+ SET_IRQ_MASK
+
+ popfd ; restore caller's eflags
+ mov esp, ebp
+ pop ebp ; restore ebp
+ stdRET _HalpInitializeStallExecution
+
+stdENDP _HalpInitializeStallExecution
+
+INIT ends
+
+_TEXT SEGMENT PARA PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "Stall Execution"
+;++
+;
+; VOID
+; KeStallExecutionProcessor (
+; IN ULONG MicroSeconds
+; )
+;
+; Routine Description:
+;
+; This function stalls execution for the specified number of microseconds.
+; KeStallExecutionProcessor
+;
+; Arguments:
+;
+; MicroSeconds - Supplies the number of microseconds that execution is to be
+; stalled.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+MicroSeconds equ [esp + 4]
+
+
+cPublicProc _KeStallExecutionProcessor ,1
+cPublicFpo 1, 0
+
+ mov ecx, MicroSeconds ; (ecx) = Microseconds
+ jecxz short kese10 ; return if no loop needed
+
+ mov eax, PCR[PcStallScaleFactor] ; get per microsecond
+ ; loop count for the processor
+ mul ecx ; (eax) = desired loop count
+
+if DBG
+;
+; Make sure we the loopcount is less than 4G and is not equal to zero
+;
+
+ cmp edx, 0
+ jz short @f
+ int 3
+
+@@: cmp eax,0
+ jnz short @f
+ int 3
+@@:
+endif
+ALIGN 16
+ jmp kese05
+
+ALIGN 16
+kese05: sub eax, 1 ; (eax) = (eax) - 1
+ jnz short kese05
+kese10:
+ stdRET _KeStallExecutionProcessor
+
+stdENDP _KeStallExecutionProcessor
+
+_TEXT ends
+
+ end
diff --git a/private/ntos/nthals/halncr/i386/ixswint.asm b/private/ntos/nthals/halncr/i386/ixswint.asm
new file mode 100644
index 000000000..68b302dfe
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixswint.asm
@@ -0,0 +1,5 @@
+;
+; Include code from halx86
+; This is a cpp style symbolic link
+
+include ..\halx86\i386\ixswint.asm
diff --git a/private/ntos/nthals/halncr/i386/ixsysbus.c b/private/ntos/nthals/halncr/i386/ixsysbus.c
new file mode 100644
index 000000000..b4776da76
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixsysbus.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixsysbus.c"
diff --git a/private/ntos/nthals/halncr/i386/ixthunk.c b/private/ntos/nthals/halncr/i386/ixthunk.c
new file mode 100644
index 000000000..6f15aad73
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixthunk.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixthunk.c"
diff --git a/private/ntos/nthals/halncr/i386/ixusage.c b/private/ntos/nthals/halncr/i386/ixusage.c
new file mode 100644
index 000000000..519ec31f3
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ixusage.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixusage.c"
diff --git a/private/ntos/nthals/halncr/i386/ncr.h b/private/ntos/nthals/halncr/i386/ncr.h
new file mode 100644
index 000000000..2963c59fc
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncr.h
@@ -0,0 +1,94 @@
+/*++
+
+Copyright (C) 1992 NCR Corporation
+
+
+Module Name:
+
+ ncr.h
+
+Author:
+
+Abstract:
+
+ System Load Equates for NCR multiprocessing hardware based on Voyager
+ architecture.
+
+++*/
+
+
+#define NCR_VERSION_NUMBER 35001
+
+#define NCR_MAX_NUMBER_PROCESSORS 16
+#define NCR_MAX_NUMBER_DYADIC_PROCESSORS 8
+#define NCR_MAX_NUMBER_QUAD_PROCESSORS 16
+#define NCR_CPI_VECTOR_BASE 0x60
+#define NCR_QIC_CPI_VECTOR_BASE 0x70
+#define NCR_QIC_SPURIOUS_VECTOR 0x50
+#define NCR_IPI_LEVEL_CPI 0
+#define NCR_CLOCK_LEVEL_CPI 2
+#define NCR_SYSTEM_INTERRUPT 8
+#define NCR_SINGLE_BIT_ERROR 0xF
+
+#define NCR_SMCA_9 1
+#define NCR_SMCA_11_3 3
+#define NCR_SMCA_12_4 4
+#define NCR_SMCA_13_5 5
+#define NCR_SMCA_14_6 6
+#define NCR_SMCA_15_7 7
+
+//
+// CPU flags
+//
+
+#define CPU_DYADIC 0x1
+#define CPU_QUAD 0x2
+#define CPU_EXTENDED 0x4
+
+
+typedef struct ProcessorPrivateData {
+ unsigned long MyProcessorFlags;
+ unsigned long MyLogicalMask;
+ unsigned long MyLogicalNumber;
+ unsigned long MyPICsIrql;
+ unsigned long MyAcquireCount;
+ unsigned long MyLockColl;
+ unsigned long MySpinCount;
+ unsigned long MySpinTSCLowDWord;
+ unsigned long MySpinTSCHighDWord;
+ unsigned long MyHighestSpinCount;
+ unsigned long MyHighestLock;
+ unsigned long MyHighestAddress;
+ unsigned long MyClaimedIRQs;
+ unsigned long MyClaimedIRQsCount;
+} *PProcessorPrivateData;
+
+/*
+ * Values for NCRPlatform
+ */
+#define NCR3450 0x35333433
+#define NCR3550 0x30353834
+#define NCR3360 0x33333630
+
+
+
+
+/*
+ * This structure is used to Send QIC Cross Processor Interrupts (CPI)
+ */
+
+typedef struct _QIC_IPI {
+ struct _QIC_LEVEL {
+ ULONG Ipi;
+ ULONG Filler[7];
+ } QIC_LEVEL[8];
+} QIC_IPI, *PQIC_IPI;
+
+
+
+
+#if DBG
+#define DBGMSG(a) DbgPrint a
+#else
+#define DBGMSG(a)
+#endif
diff --git a/private/ntos/nthals/halncr/i386/ncr.inc b/private/ntos/nthals/halncr/i386/ncr.inc
new file mode 100644
index 000000000..59d181e9f
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncr.inc
@@ -0,0 +1,453 @@
+;
+; Copyright (c) 1992 NCR Corporation
+;
+; Module Name:
+;
+; ncr.inc
+;
+; Abstract:
+;
+; This module contains the equates for defining the system memory
+; map for NCR Multiprocessor systems using the Voyager architecture
+; (3450/3550)
+;
+; Author:
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+;--
+
+;
+; Maximum number of processors include boot processor and non-boot processors
+
+NCR_MAX_NUMBER_PROCESSORS equ 16
+NCR_MAX_NUMBER_DYADIC_PROCESSORS equ 8
+NCR_MAX_NUMBER_QUAD_PROCESSORS equ 16
+
+;
+;
+
+NCR_CPI_VECTOR_BASE equ 60H
+NCR_QIC_CPI_VECTOR_BASE equ 70H
+NCR_SECONDARY_VECTOR_BASE equ 40H
+NCR_QIC_SPURIOUS_VECTOR equ 50H
+NCR_IPI_LEVEL_CPI equ 0 ; cpi used for ipi
+NCR_CLOCK_LEVEL_CPI equ 2 ; cpi used for clock broadcast
+NCR_SYSTEM_INTERRUPT equ 8 ; system interrupt
+NCR_SINGLE_BIT_ERROR equ 0FH ; single bit error
+NCR_STARTUP_CPI equ 2 ; cpi used to start nonboot procs
+NCR_STARTUP_VECTOR_VIC equ (NCR_STARTUP_CPI+NCR_CPI_VECTOR_BASE) * 4
+NCR_STARTUP_VECTOR_QIC equ (NCR_STARTUP_CPI+NCR_QIC_CPI_VECTOR_BASE) * 4
+
+;
+; CPU flags
+;
+
+CPU_DYADIC equ 01h
+CPU_QUAD equ 02h
+CPU_EXTENDED equ 04h
+
+
+;
+; Define Voyager Configuration and Test (CAT) register set
+;
+
+CAT_BASE_ADDRESS equ 0F800h ; configuration register base
+CAT_ID_SELECT_PORT equ 97h ; ASIC select register
+
+_CAT_REGISTERS struc
+ cat_CatIdReg db ? ; Offset 0x00
+ cat_AsicInformationReg db ? ; Offset 0x01
+ cat_ControlReg db ? ; Offset 0x02
+ cat_DataPort1 db ? ; Offset 0x03
+ cat_ConfigurationReg db ? ; Offset 0x04
+ cat_Reserved0 db ?
+ cat_SubAddressRegLsb db ? ; Offset 0x06
+ cat_SubAddressRegMsb db ? ; Offset 0x07
+ cat_DataPort2 db ? ; Offset 0x08
+ cat_DataPort3 db ? ; Offset 0x09
+ cat_PDataRead db ? ; Offset 0x0a
+ cat_Reserved1 db 3 dup(?)
+ cat_JtagCommandReg db ? ; Offset 0x0e
+ cat_StatusReg db ? ; Offset 0x0f
+_CAT_REGISTERS ends
+
+
+MCADDR_CAT_ID equ 0C0h
+
+CAT_READ macro reg
+ mov dx, CAT_BASE_ADDRESS+cat_&reg
+ in al, dx
+ endm
+
+CAT_WRITE macro reg, dbyte
+ ifnb <dbyte>
+ mov al, dbyte
+ endif
+ mov dx, CAT_BASE_ADDRESS+cat_&reg
+ out dx, al
+ endm
+
+
+;++
+;
+; SET_IRQ_MASK
+;
+; Macro Description:
+;
+; This macro sets 8259 interrupt mask register with the mask
+; passed from eax register.
+;
+; Note: Currently, only two 8259s are support. As a result,
+; only ax contains valid mask.
+;
+; Arguments:
+;
+; (eax) = mask for setting 8259 interrupt mask register
+;
+;--
+
+
+QIC_IRQ_ENABLE_MASK equ 0fah ; Mask for enabling the disabling interrupts on Qic
+
+
+SET_IRQ_MASK macro
+local a,b,c ; define local labels
+
+;
+; Turn off P5 counters
+;
+; push eax
+; mov ecx,011h
+; db 0fh,32h
+; push eax
+; and eax,0fe3ffe3fh
+; mov edx,0
+; db 0fh,30h
+; pop eax
+;
+; mov edx, eax
+; pop eax
+; push edx
+
+ mov edx, PCR[PcHal.PcrMyProcessorFlags]
+ test edx, CPU_QUAD
+ jnz short b
+
+ out PIC1_PORT1, al ; set master 8259 mask
+ shr eax, 8 ; shift slave 8259 mask to al
+ out PIC2_PORT1, al ; set slave 8259 mask
+
+ jmp short c
+
+b:
+ test edx, CPU_EXTENDED
+ jz short a
+
+ out PIC1_PORT1, al ; set master 8259 mask
+ ror eax,8 ; set slave pic mask
+ out PIC2_PORT1, al ; set slave 8259 mask
+ rol eax,8 ; restore eax for Qic operation
+a:
+ or al,QIC_IRQ_ENABLE_MASK
+ QIC_WRITE QicMask1
+
+c:
+;
+; Turn counters back on
+;
+; pop eax
+; mov ecx,011h
+; mov edx,0
+; db 0fh,30h
+;
+endm
+
+
+
+;
+; Define Voyager Interrupt Controller (VIC) register set
+;
+
+VIC_BASE_ADDRESS equ 0FC00h ; base address for VIC registers
+QIC_BASE_ADDRESS equ 0FC70h ; base address for QIC registers
+
+
+_VIC_REGISTERS struc
+ vic_CpiLevel0Reg db ? ; Offset 0x00
+ vic_CpiLevel1Reg db ? ; Offset 0x01
+ vic_Reserved0 db 6 dup (?)
+ vic_CpiLevel2Reg db ? ; Offset 0x08
+ vic_CpiLevel3Reg db ? ; Offset 0x09
+ vic_Reserved1 db 6 dup (?)
+ vic_CpiLevel4Reg db ? ; Offset 0x10
+ vic_CpiLevel5Reg db ? ; Offset 0x11
+ vic_Reserved2 db 6 dup (?)
+ vic_CpiLevel6Reg db ? ; Offset 0x18
+ vic_CpiLevel7Reg db ? ; Offset 0x19
+ vic_Reserved3 db 6 dup (?)
+ vic_ActivityReg db ? ; Offset 0x20
+ vic_ProcessorIdReg db ? ; Offset 0x21
+ vic_Reserved4 db 6 dup (?)
+ vic_ProcessorAliveReg db ? ; Offset 0x28
+ vic_ProcessorWhoAmIReg db ? ; Offset 0x29
+ vic_Reserved5 db 6 dup (?)
+ vic_FakeInterruptRegLsb db ? ; Offset 0x30
+ vic_FakeInterruptRegMsb db ? ; Offset 0x31
+ vic_Reserved6 db 6 dup (?)
+ vic_ClaimRegLsb db ? ; Offset 0x38
+ vic_ClaimRegMsb db ? ; Offset 0x39
+ vic_Reserved9 db 6 dup (?)
+ vic_SpareInterruptReg db ? ; Offset 0x40
+ vic_CpiVectorBaseReg db ? ; Offset 0x41
+ vic_Reserved10 db 6 dup (?)
+ vic_ExtMasterVectorBaseReg db ? ; Offset 0x48
+ vic_ExtSlaveVectorBaseReg db ? ; Offset 0x49
+ vic_Reserved11 db 6 dup (?)
+ vic_AddressOffsetReg db ? ; Offset 0x50
+ vic_ParityErrorReg db ? ; Offset 0x51
+ vic_Reserved12 db 6 dup (?)
+ vic_AsicConfigurationReg db ? ; Offset 0x58
+ vic_RevisionLevelReg db ? ; Offset 0x59
+ vic_Reserved13 db 6 dup (?)
+ vic_RedirectIrqReg0 db ? ; Offset 0x60
+ vic_RedirectIrqReg1 db ? ; Offset 0x61
+_VIC_REGISTERS ends
+
+
+_QIC_REGISTERS struc
+ qic_Configuration db ? ; Offset 0x00
+ qic_ProcessorId db ? ; Offset 0x01
+ qic_ExtendedProcessorSelect db ? ; Offset 0x02
+ qic_SpuriousVectorReg db ? ; Offset 0x03
+ qic_Reserved1 db 4 dup (?)
+ qic_PerformanceTimerVector db ? ; Offset 0x08
+ qic_VicCpiVectorBaseReg db ? ; Offset 0x09
+ qic_QuadCpiVectorBaseReg db ? ; Offset 0x0a
+ qic_LocalMemoryErrorVectorReg db ? ; Offset 0x0b
+ qic_Reserved2 db 4 dup (?)
+ qic_QicMask0 db ? ; Offset 0x10
+ qic_QicMask1 db ? ; Offset 0x11
+ qic_QicIrrReg0 db ? ; Offset 0x12
+ qic_QicIrrReg1 db ? ; Offset 0x13
+ qic_Reserved3 db 4 dup (?)
+ qic_ProcessorWhoAmIReg db ? ; Offset 0x18
+ qic_Reserved4 db 1 dup (?)
+ qic_Clear0Reg db ? ; Offset 0x1a
+ qic_Clear1Reg db ? ; Offset 0x1b
+ qic_Reserved5 db 4 dup (?)
+ qic_PerformanceTimerInitialCount db ? ; Offset 0x20
+ qic_PerformanceTimerCurrentCount db ? ; Offset 0x22
+ qic_Reserved6 db 45 dup (?)
+ qic_QuadCpi0StatusReg db ? ; Offset 0x50
+ qic_Reserved7 db 7 dup (?)
+ qic_QuadCpi1StatusReg db ? ; Offset 0x58
+ qic_Reserved8 db 7 dup (?)
+ qic_QuadCpi2StatusReg db ? ; Offset 0x60
+ qic_Reserved9 db 7 dup (?)
+ qic_QuadCpi3StatusReg db ? ; Offset 0x68
+ qic_Reserved10 db 7 dup (?)
+ qic_QuadCpi4StatusReg db ? ; Offset 0x70
+ qic_Reserved11 db 7 dup (?)
+ qic_QuadCpi5StatusReg db ? ; Offset 0x78
+ qic_Reserved12 db 7 dup (?)
+ qic_QuadCpi6StatusReg db ? ; Offset 0x80
+ qic_Reserved13 db 7 dup (?)
+ qic_QuadCpi7StatusReg db ? ; Offset 0x88
+_QIC_REGISTERS ends
+
+
+
+
+
+;
+; Processor Identification register definition
+;
+
+ProcessorIdNumber equ 07h
+ProcessorIdSelect equ 08h
+
+;
+; Cross Processor Interrupt Base Vector register definition
+;
+
+InterruptType equ 008h ; 0 = cpi, 1 = system int or
+CpiBaseVectorMask equ 0F0h ; single bit error
+
+
+;
+; Read/Write VIC macro definitions
+;
+
+VIC_READ macro reg
+ mov dx, VIC_BASE_ADDRESS+vic_&reg
+ in al, dx
+ endm
+
+VIC_WRITE macro reg, dbyte
+ ifnb <dbyte>
+ mov al, dbyte
+ endif
+ mov dx, VIC_BASE_ADDRESS+vic_&reg
+ out dx, al
+ endm
+
+
+;
+; Read the who_am_i register. If this is a Dyadic then clear carry flag and return who_am_i
+; if this is a Quad then set carry flag and translate who_am_i
+;
+
+
+WHO_AM_I macro
+local a,b
+ mov dx, VIC_BASE_ADDRESS+vic_ProcessorWhoAmIReg
+ in al,dx
+ movzx eax, al
+ mov dl,al
+ and edx,0c0h ; check for quad processor
+ cmp edx,0c0h
+ jne short a
+
+;
+; this is a Quad
+;
+
+ mov dl,al
+ and edx,0fh ; this must change for 32 way currently ccvv is left
+ push ecx
+
+ mov eax,1h
+ mov ecx,edx
+ shr ecx,2h ; get shift for processor bit
+ shl eax,cl ; now put processor bit in right position
+ mov ecx,edx ; now lets adjust for processor slot
+ and ecx,3h ; now isolate voyager slot number
+ shl ecx,2h ; 1 slot is 4 processors
+ shl eax,cl ; now mask is corrent
+
+ pop ecx
+ stc
+ jmp short b
+a:
+;
+; this is a Dyadic
+;
+ push ebx
+ push ecx
+ stdCall _NCRTranslateCMOSMask, <eax>
+ pop ecx
+ pop ebx
+
+ clc
+b:
+ endm
+
+
+
+
+;
+; Translate the Processors logical mask into a VIC hardware mask for sending CPIs
+; to processors on Dyadic boards
+;
+
+
+TRANSLATE_LOGICAL_TO_VIC macro
+local loop,almost,done
+ push ebx ; save registers
+
+ xor ebx,ebx ; set logical processor number to zero
+ dec ebx ; dec logical so we and inc right away
+ xor edx,edx ; clear VIC mask
+ align dword
+loop:
+ inc ebx ; logical processor number
+ shr eax,1 ; shift logical mask into carry
+ jz short almost ; if logical mask zero we are almost done
+ jnb short loop ; if this processor mask not set check next
+ or edx,dword ptr _NCRLogicalNumberToPhysicalMask[ebx*4] ; or in the VIC mask for this processor
+
+ jmp short loop
+almost:
+ jnb short done ; if logical bit not set we are done
+ or edx,dword ptr _NCRLogicalNumberToPhysicalMask[ebx*4] ; or in the VIC mask for this processor
+done:
+ mov eax,edx ; put VIC mask into eax for return value
+
+ pop ebx ; restore registers
+ endm
+
+
+
+
+PROCESSOR_SLOT macro
+ bsf eax,eax
+ shr eax,2
+ endm
+
+
+;
+; Read/Write QIC macro definitions
+;
+
+QIC_READ macro reg
+ mov dx, QIC_BASE_ADDRESS+qic_&reg
+ in al, dx
+ endm
+
+QIC_WRITE macro reg, dbyte
+ ifnb <dbyte>
+ mov al, dbyte
+ endif
+ mov dx, QIC_BASE_ADDRESS+qic_&reg
+ out dx, al
+ endm
+
+
+
+;; Constants
+
+TRUE equ 1
+FALSE equ 0
+
+
+;
+; the kernel reserved space for us in our pcr. this structure defines
+; that space. it MUST coincide with the corresponding 'C' structure.
+;
+
+PcrE struc
+ PcrMyProcessorFlags dd 0 ; Processor Flags that Indicate type of processor
+ PcrMyLogicalMask dd 0 ; logical processor mask
+ PcrMyLogicalNumber dd 0 ; logical processor number
+ PcrMyPICsIrql dd 0 ; last Irql written to PICs
+ PcrMyAcquireCount dd 0
+ PcrMyLockColl dd 0
+ PcrMySpinCount dd 0
+
+ PcrMySpinTSCLowDWord dd 0
+ PcrMySpinTSCHighDWord dd 0
+
+
+ PcrMyHighestSpinCount dd 0
+ PcrMyHighestLock dd 0
+ PcrMyHighestAddress dd 0
+ PcrMyClaimedIRQs dd 0
+ PcrMyClaimedIRQsCount dd 0
+PcrE ends
+
+;
+; Values for NCRPlatform
+;
+NCR3450 equ 35333433H
+NCR3550 equ 30353834H
+NCR3360 equ 33333630H
+
+;
+; functions to turn on and off the performance counters
+;
+
diff --git a/private/ntos/nthals/halncr/i386/ncrarb.h b/private/ntos/nthals/halncr/i386/ncrarb.h
new file mode 100644
index 000000000..85929330a
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrarb.h
@@ -0,0 +1,157 @@
+/*++
+
+Copyright (C) 1992 NCR Corporation
+
+
+Module Name:
+
+ ncrarb.h
+
+Author:
+
+Abstract:
+
+ System equates for dealing with the NCR Arbiter ASIC.
+
+++*/
+
+#ifndef _NCRARB_
+#define _NCRARB_
+
+
+/* Level 4 Arbiter ASIC ID */
+#define SBA_ID_L4 0xC1
+
+/* Arbiter Register Addresses and their bit definitions */
+
+#define SBA_Dev_Id 0x00
+#define SBA_Dev_Info 0x01
+#define SBA_CAT_Cntl1 0x02
+#define SBA_Extended_Reg_Data 0x03
+#define SBA_Extended_Reg_Addr 0x06
+
+#define SBA_Intr_Stat1 0x08
+# define SBA_Proto_Err_A 0x80
+# define SBA_Proto_Err_B 0x40
+# define SBA_Toe_A 0x20
+# define SBA_Toe_B 0x10
+# define SBA_Elatchd_A 0x08
+# define SBA_Elatchd_B 0x04
+# define SBA_Par_Int_A 0x02
+# define SBA_Par_Int_B 0x01
+
+#define SBA_Intr_Stat2 0x09
+# define SBA_Reserved 0x80
+# define SBA_Sw_Nmi 0x40
+# define SBA_Error_Int 0x20
+# define SBA_Power_Fail 0x10
+# define SBA_Exp_Cougar_Nmi 0x08
+# define SBA_Exp_Mc_Toe 0x04
+# define SBA_Cougar_Nmi 0x02
+# define SBA_Mc_Toe 0x01
+
+#define SBA_SysInt_Enables 0x0A
+# define SBA_Toe_S 0x80
+# define SBA_Par_Int_S 0x40
+# define SBA_Err_Int_S 0x20
+# define SBA_Power_Fail_S 0x10
+# define SBA_Exp_Cougar_Nmi_S 0x08
+# define SBA_Exp_Mc_Toe_S 0x04
+# define SBA_Cougar_Nmi_S 0x02
+# define SBA_Mc_Toe_S 0x01
+
+#define SBA_GNMI_Enables 0x0B
+# define SBA_Toe_G 0x80
+# define SBA_Par_Int_G 0x40
+# define SBA_Err_Int_G 0x20
+# define SBA_Power_Fail_G 0x10
+# define SBA_Exp_Cougar_Nmi_G 0x08
+# define SBA_Exp_Mc_Toe_G 0x04
+# define SBA_Cougar_Nmi_G 0x02
+# define SBA_Mc_Toe_G 0x01
+
+#define SBA_Control 0x0C
+
+#define SBA_Intr_Clear 0x0D
+# define SBA_Err_Int_Clr 0x10
+# define SBA_Par_Clr_A 0x08
+# define SBA_Par_Clr_B 0x04
+# define SBA_Err_Clr_A 0x02
+# define SBA_Err_Clr_B 0x01
+
+#define SBA_Misc 0x0E
+
+#define SBA_CAT_Cntl2 0x0F
+# define SBA_Reset_Not_Compl 0x80
+# define SBA_Cat_Inst_Perr 0x08
+
+/* Extended Registers; Accessed via SBA_Extended_Reg_Data &
+** SBA_Extended_Reg_Data above
+*/
+
+#define SBA_Size_Subaddress 0x08
+
+#define SBA_Ext_Err0_BusA 0x00
+#define SBA_Ext_Err1_BusA 0x01
+#define SBA_Ext_Err2_BusA 0x02
+# define SBA_ErrParInt 0x20
+#define SBA_Ext_Err3_BusA 0x03
+
+#define SBA_Ext_Err4_BusB 0x04
+#define SBA_Ext_Err5_BusB 0x05
+#define SBA_Ext_Err6_BusB 0x06
+#define SBA_Ext_Err7_BusB 0x07
+
+
+
+
+/* Valuable Arbiter error information to be captured when SYS_INT or
+** G_NMI occurs.
+*/
+typedef struct SBA_INFO {
+ UCHAR Flag; /* for state of information in struct */
+ union {
+ CAT_REGISTERS CatRegs;
+ struct {
+ UCHAR Dummy0;
+ UCHAR Dummy1;
+ UCHAR Dummy2;
+ UCHAR Dummy3;
+ UCHAR Dummy4;
+ UCHAR Dummy5;
+ UCHAR Dummy6;
+ UCHAR Dummy7;
+ UCHAR InterruptStatus1;
+ UCHAR InterruptStatus2;
+ UCHAR SysIntEnables;
+ UCHAR GlobalNmiEnables;
+ UCHAR ArbControl;
+ UCHAR InterruptClear;
+ UCHAR Misc;
+ UCHAR DummyF;
+ } ArbRegisters;
+ } CatRegisters;
+ UCHAR ExtError0BusA; /* for PAR_INT */
+ UCHAR ExtError1BusA; /* for PAR_INT */
+ UCHAR ExtError2BusA; /* for ERROR_L */
+ UCHAR ExtError3BusA; /* for ERROR_L */
+ UCHAR ExtError4BusB; /* for PAR_INT */
+ UCHAR ExtError5BusB; /* for PAR_INT */
+ UCHAR ExtError6BusB; /* for ERROR_L */
+ UCHAR ExtError7BusB; /* for ERROR_L */
+} SBA_INFO, *PSBA_INFO;
+
+/* defines for union referencing */
+#define Intr_Stat1 CatRegisters.ArbRegisters.InterruptStatus1
+#define Intr_Stat2 CatRegisters.ArbRegisters.InterruptStatus2
+#define SysIntEnables CatRegisters.ArbRegisters.SysIntEnables
+#define GNMIEnables CatRegisters.ArbRegisters.GlobalNmiEnables
+#define ArbControl CatRegisters.ArbRegisters.ArbControl
+#define InterruptClear CatRegisters.ArbRegisters.InterruptClear
+#define Misc CatRegisters.ArbRegisters.Misc
+
+
+#endif // _NCRARB_
+
+
+
diff --git a/private/ntos/nthals/halncr/i386/ncrcat.c b/private/ntos/nthals/halncr/i386/ncrcat.c
new file mode 100644
index 000000000..c0680ee4a
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrcat.c
@@ -0,0 +1,3223 @@
+/*++
+
+Copyright (c) 1993 NCR Corporation
+
+Module Name:
+
+ ncrcat.c
+
+Abstract:
+
+ Provides the interface to the NCR CAT bus.
+
+Author:
+
+ Rick Ulmer (rick.ulmer@columbiasc.ncr.com) 29-Jul-1993
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "ncr.h"
+#include "ncrcat.h"
+#include "ncrcatp.h"
+#include "ncrpsi.h"
+#include "ncrarb.h"
+
+
+VOID HalpAcquireCatBusSpinLock();
+VOID HalpReleaseCatBusSpinLock();
+
+
+
+PMODULE NCRCatModuleList = NULL;
+PMODULE NCRCatModule = NULL;
+USHORT NCRCatBasePort;
+USHORT NCRCatCommandPort;
+USHORT NCRCatDataPort;
+SHORT NCRMinModuleAddress = 0;
+SHORT NCRMaxModuleAddress = PSI;
+
+//
+// Used to signal HalReturnToFirmware to powerdown instead of reboot
+//
+BOOLEAN NCRPowerOffSystem = FALSE;
+
+
+
+extern ULONG NCRLarcEnabledPages[]; // LARC size by Voyager slot
+
+
+/*
+ * Function prototypes
+ */
+
+
+PMODULE
+NCRCatModulePresent(
+ IN UCHAR ModuleAddress
+ );
+
+
+UCHAR
+NCRCatSubModulePresent(
+ );
+
+
+PUCHAR
+NCRCatReadModuleData(
+ );
+
+
+VOID
+NCRCatExtractSetupInformation(
+ PUCHAR EEpromData
+ );
+
+
+VOID
+NCRCatDefaultSetupInformation(
+ );
+
+
+PMODULE
+NCRCatSelect(
+ UCHAR ModuleAddress
+ );
+
+
+PASIC
+NCRCatGetAsic(
+ UCHAR AsicId
+ );
+
+
+LONG
+NCRCatConnect(
+ );
+
+
+LONG
+NCRCatDisconnect(
+ );
+
+
+VOID
+NCRCatRestoreState(
+ );
+
+
+LONG
+NCRCatAutoIncrement(
+ PASIC Asic
+ );
+
+
+LONG
+NCRCatNoAutoIncrement(
+ PASIC Asic
+ );
+
+
+LONG
+NCRCatSubaddressSetup(
+ PASIC Asic,
+ USHORT Subaddress
+ );
+
+
+LONG
+NCRCatRegisterIo(
+ PASIC Asic,
+ PCAT_CONTROL CatControl,
+ PUCHAR Buffer
+ );
+
+
+LONG
+NCRCatSubaddressIo(
+ PASIC Asic,
+ PCAT_CONTROL CatControl,
+ PUCHAR Buffer
+ );
+
+
+LONG
+NCRCatRead(
+ PASIC Asic,
+ UCHAR RegisterNumber,
+ PUCHAR Buffer
+ );
+
+
+LONG
+NCRCatWrite(
+ PASIC Asic,
+ UCHAR RegisterNumber,
+ PUCHAR Data
+ );
+
+
+LONG
+NCRCatSubaddressRead(
+ PASIC Asic,
+ PCAT_CONTROL CatControl,
+ PUCHAR Buffer
+ );
+
+
+LONG
+NCRCatWriteComplete(
+ PASIC Asic,
+ USHORT Address,
+ UCHAR Expected
+ );
+
+
+LONG
+NCRCatSubaddressWrite(
+ PASIC Asic,
+ PCAT_CONTROL CatControl,
+ PUCHAR Buffer
+ );
+
+
+UCHAR
+NCRCatInstruction(
+ UCHAR RegisterNumber,
+ UCHAR Operation
+ );
+
+
+LONG
+NCRCatSendInstruction(
+ PASIC Asic,
+ UCHAR Instruction
+ );
+
+
+VOID
+NCRCatBuildHeader(
+ PUCHAR Header,
+ SHORT HeaderBytes,
+ SHORT LargestRegister,
+ SHORT SmallestRegister
+ );
+
+
+LONG
+NCRCatSendData(
+ PASIC Aisc,
+ PUCHAR Data,
+ LONG InternalRegister,
+ LONG ExternalSpecial
+ );
+
+
+VOID
+NCRCatInsertData(
+ PUCHAR String,
+ SHORT StartBit,
+ PUCHAR Data,
+ SHORT NumberOfBits
+ );
+
+
+VOID
+NCRCatExtractData(
+ PUCHAR String,
+ SHORT StartBit,
+ PUCHAR Data,
+ SHORT NumberOfBits
+ );
+
+
+LONG
+NCRCatShiftOutData(
+ PUCHAR Data,
+ SHORT DataBytes,
+ SHORT HeaderBytes,
+ SHORT PadBits
+ );
+
+
+LONG
+NCRCatGetData(
+ PASIC Asic,
+ PUCHAR Data,
+ LONG InternalRegister
+ );
+
+
+LONG
+NCRCatIoLpb(
+ PCAT_CONTROL CatControl,
+ PUCHAR Buffer
+ );
+
+
+
+VOID
+NCRCatModuleName (
+ LONG Module,
+ PUNICODE_STRING ModuleName
+ );
+
+
+VOID
+NCRCatAsicName (
+ LONG Module,
+ LONG Asic,
+ PUNICODE_STRING AsicName
+ );
+
+
+
+/*
+ * End of function prototypes.
+ */
+
+
+BOOLEAN
+HalCatBusAvailable (
+ )
+
+/*++
+
+Routine Description:
+ Check to see if the Cat Bus is available on this system. If no modules
+ are found then the Cat Bus is not available.
+
+Arguments:
+ None.
+
+Return Value:
+ TRUE - Cat Bus is available.
+
+ FALSE - Cat Bus is not available
+
+--*/
+
+{
+ if (NCRCatModuleList) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+
+
+
+LONG
+HalCatBusIo (
+ IN PCAT_CONTROL CatControl,
+ IN OUT PUCHAR Buffer
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+ CatControl -
+
+ Buffer -
+
+Return Value:
+
+--*/
+
+{
+LONG status;
+#ifdef CATDEBUG
+ULONG i;
+PUCHAR pos;
+#endif // CATDEBUG
+
+/*
+ * Get the Cat bus lock.
+ */
+
+HalpAcquireCatBusSpinLock();
+
+/*
+ * Perform the Cat bus function
+ */
+
+status = HalpCatBusIo(CatControl,Buffer);
+
+/*
+ * Release the Cat Bus lock.
+ */
+
+HalpReleaseCatBusSpinLock();
+
+#ifdef CATDEBUG
+DBGMSG(("HalCatBusIo: Module 0x%x, Asic 0x%x, Address 0x%x\n", CatControl->Module, CatControl->Asic, CatControl->Address));
+
+if (status == CATNOERR) {
+ if ((CatControl->Command == READ_REGISTER) || (CatControl->Command == READ_SUBADDR))
+ {
+ DBGMSG(("\tRead Data: "));
+ pos = Buffer;
+ for ( i = 0; i < CatControl->NumberOfBytes; i++ )
+ {
+ DBGMSG(("0x%2x ", *pos++));
+ }
+ DBGMSG(("\n"));
+ }
+ else
+ {
+ DBGMSG(("\tWrote Data: "));
+ pos = Buffer;
+ for ( i = 0; i < CatControl->NumberOfBytes; i++ )
+ {
+ DBGMSG(("0x%2x ", *pos++));
+ }
+ DBGMSG(("\n"));
+ }
+ } else {
+ DBGMSG(("HalCatBusIo Error: Status = 0x%x\n", status));
+ }
+#endif // CATDEBUG
+
+
+return status;
+}
+
+
+VOID
+HalCatBusReset (
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ NCRCatRestoreState();
+}
+
+
+
+LONG
+HalpCatBusIo (
+ IN PCAT_CONTROL CatControl,
+ IN OUT PUCHAR Buffer
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PASIC asic;
+ LONG status;
+
+/*
+ * Special processing required since LPB is not on the CAT bus.
+ */
+
+ if (CatControl->Module == CAT_LPB_MODULE) {
+ status = NCRCatIoLpb(CatControl, Buffer);
+ return (status);
+ }
+
+/*RMU add code here to detect if the CAT bus has been reset.... */
+
+ WRITE_PORT_UCHAR((PUCHAR)SELECT_PORT, (UCHAR)DESELECT);
+
+ if ((NCRCatSelect(CatControl->Module)) == NULL)
+ status = CATNOMOD;
+ else if ((asic = NCRCatGetAsic(CatControl->Asic)) == NULL)
+ status = CATNOASIC;
+ else {
+ switch(CatControl->Command) {
+ case READ_REGISTER:
+ case WRITE_REGISTER:
+
+
+ status = NCRCatRegisterIo(asic, CatControl, Buffer);
+ break;
+
+ case READ_SUBADDR:
+ case WRITE_SUBADDR:
+ status = NCRCatSubaddressIo(asic, CatControl, Buffer);
+ break;
+ default:
+ status = CATINVAL;
+ break;
+ }
+ }
+
+/*
+ * UNIX guys took this out because of problems, so we will too.
+ *
+ if (status == CATIO) {
+ NCRCatRestoreState();
+ } else {
+*/
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
+/*
+ }
+*/
+
+ WRITE_PORT_UCHAR((PUCHAR)SELECT_PORT, (UCHAR)DESELECT);
+ return (status);
+}
+
+VOID
+HalpInitializeCatBusDriver (
+ )
+
+/*++
+
+Routine Description:
+ Read the ASIC information for each module from the subaddress space
+ of the CAT_I ASIC (EEPROM).
+
+Arguments:
+ None
+
+Return Value:
+ None
+
+--*/
+
+{
+ PMODULE *module_p;
+ UCHAR module_address, number_submodule, *data;
+ CAT_CONTROL cat_control;
+ UCHAR cat_data;
+
+/*
+ * Get the Command and Data Port address
+ */
+
+ NCRCatBasePort = (USHORT)(READ_PORT_UCHAR((PUCHAR)BASE_PORT) << 8);
+ NCRCatCommandPort = NCRCatBasePort + COMMAND_OFFSET;
+ NCRCatDataPort = NCRCatBasePort + DATA_OFFSET;
+
+
+/*
+ * For each module that is present, build a data structure for the
+ * module and each of its ASICs.
+ */
+
+
+ for (module_p = &NCRCatModuleList, module_address = (UCHAR)NCRMinModuleAddress;
+ module_address <= (UCHAR)NCRMaxModuleAddress; module_address++) {
+
+ WRITE_PORT_UCHAR((PUCHAR)SELECT_PORT, (UCHAR)DESELECT);
+ WRITE_PORT_UCHAR((PUCHAR)SELECT_PORT, (UCHAR)module_address);
+
+
+ if (((NCRCatModule = *module_p = NCRCatModulePresent(module_address))) == NULL) {
+ continue;
+ }
+
+/*
+ * For 16way there way be submodules in addition to modules; if a
+ * submodule is present but the eeprom image is bad, just continue.
+ * This should never happen since firmware has already checked it.
+ */
+
+ if ((number_submodule = NCRCatSubModulePresent()) > 0) {
+
+ PMODULE parent_module;
+ UCHAR submodule_data, submodule;
+ LONG status;
+
+ parent_module = NCRCatModule;
+
+ for (NCRCatModule = NCRCatModule->SubModules, submodule = 1; NCRCatModule != NULL;
+ NCRCatModule = NCRCatModule->Next, submodule++) {
+
+ /*
+ * Select the submodule by reading the SUBMODSELECT register
+ * (register 8). The most significant bit (bit 7) is the hold
+ * bit and should always be set to zero; bits 2-6 should not be
+ * altered; bits 0-1 will contain the submod that is to be
+ * selected. An ASIC structure for the CAT_I was allocated by
+ * NCRCatModulePresent().
+ */
+
+ cat_control.Module = NCRCatModule->ModuleAddress;
+ cat_control.Asic = CAT_I;
+ cat_control.Command = READ_REGISTER;
+ cat_control.Address = SUBMODSELECT;
+ cat_control.NumberOfBytes = 1;
+
+ status = NCRCatRegisterIo(NCRCatModule->Asic, &cat_control,
+ (PUCHAR)&submodule_data);
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
+
+ if (status)
+ continue;
+
+ submodule_data = (submodule_data & 0x7C) | submodule;
+
+ cat_control.Module = NCRCatModule->ModuleAddress;
+ cat_control.Asic = CAT_I;
+ cat_control.Command = WRITE_REGISTER;
+ cat_control.Address = SUBMODSELECT;
+ cat_control.NumberOfBytes = 1;
+
+ status = NCRCatRegisterIo(NCRCatModule->Asic, &cat_control,
+ (PUCHAR)&submodule_data);
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
+
+ if (status)
+ continue;
+
+ if ((data = NCRCatReadModuleData()) != NULL)
+ NCRCatExtractSetupInformation(data);
+ }
+ NCRCatModule = parent_module;
+ } else {
+ if ((data = NCRCatReadModuleData()) == NULL) {
+ NCRCatDefaultSetupInformation();
+ } else {
+ NCRCatExtractSetupInformation(data);
+ }
+ }
+ module_p = &NCRCatModule->Next;
+ }
+
+ *module_p = NULL;
+
+ WRITE_PORT_UCHAR((PUCHAR)SELECT_PORT, (UCHAR)DESELECT);
+
+
+//
+// Lets steer all hardware failures to NMI and not SYSINT
+// after this setup SYSINT should not occur.
+//
+
+ cat_control.Module = PRIMARYMC;
+ cat_control.Asic = PMC_ARB;
+ cat_control.Command = WRITE_REGISTER;
+ cat_control.Address = SBA_SysInt_Enables;
+ cat_control.NumberOfBytes = 1;
+
+ cat_data = 0x0; // Disable all SYS_INT interrupts
+
+ HalCatBusIo(&cat_control, &cat_data);
+
+ cat_control.Address = SBA_GNMI_Enables;
+ cat_control.NumberOfBytes = 1;
+
+ cat_data = 0xff; // Enable all G_NMI interrupts
+
+ HalCatBusIo(&cat_control, &cat_data);
+}
+
+
+PMODULE
+NCRCatModulePresent(
+ IN UCHAR ModuleAddress
+ )
+
+/*++
+
+Routine Description:
+ Determine if the module is present.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PMODULE module;
+ UCHAR input;
+
+ WRITE_PORT_UCHAR((PUCHAR)SELECT_PORT, (UCHAR)ModuleAddress);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)IRCYC);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)HEADER);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)0xAA);
+ input = READ_PORT_UCHAR((PUCHAR)NCRCatDataPort);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
+
+ if (input != HEADER) {
+ return (NULL);
+ }
+
+/*
+ * If the module is present, allocate a data structure and
+ * assign the default values so we can later do a read.
+ */
+
+ if ((module = (PMODULE)ExAllocatePool(NonPagedPool,sizeof(MODULE))) != NULL) {
+ RtlZeroMemory((PVOID)module,sizeof(MODULE));
+ module->ModuleAddress = ModuleAddress;
+ module->EEpromSize = EEPROM_SIZE;
+ module->ScanPathConnected = FALSE;
+ }
+ return (module);
+}
+
+
+UCHAR
+NCRCatSubModulePresent(
+ )
+
+/*++
+
+Routine Description:
+ Determine if the module has submodules for 16way.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+
+ PMODULE submodule, *submodule_p;
+ CAT_CONTROL cat_control;
+ UCHAR number_submodules, submodule_present;
+ LONG status, i;
+
+ /*
+ * Submodules are unique to the processor boards.
+ */
+
+ if( !((NCRCatModule->ModuleAddress >= PROCESSOR0 &&
+ NCRCatModule->ModuleAddress <= PROCESSOR3) ||
+ (NCRCatModule->ModuleAddress >= PROCESSOR4 &&
+ NCRCatModule->ModuleAddress <= PROCESSOR7)) )
+ return(0);
+
+ /*
+ * Allocate and define an ASIC data structure for the CAT_I so we can
+ * do our first read.
+ */
+
+ if (NCRCatModule->Asic == NULL) {
+ if (!(NCRCatModule->Asic =
+ (PASIC)ExAllocatePool(NonPagedPool,sizeof(ASIC)))) {
+ return(0);
+ }
+ RtlZeroMemory((PVOID)NCRCatModule->Asic, sizeof(ASIC));
+ NCRCatModule->Asic->AsicId = CAT_I;
+ NCRCatModule->Asic->SubaddressSpace = SUBADDR_HI;
+ }
+ /*
+ * Read the SUBMODPRESENT register (register 9) of CAT_I to determine
+ * if there are any submodules present. If there are, allocate a
+ * module_t structure for each.
+ */
+
+ cat_control.Module = NCRCatModule->ModuleAddress;
+ cat_control.Asic = CAT_I;
+ cat_control.Command = READ_REGISTER;
+ cat_control.Address = SUBMODPRESENT;
+ cat_control.NumberOfBytes = 1;
+
+ status = NCRCatRegisterIo(NCRCatModule->Asic, &cat_control, (PUCHAR)&number_submodules);
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
+
+ if (status)
+ return(0);
+
+ /*
+ * The two least significant bits of the SUBMODPRESENT register contain the
+ * number of submodules. These bits are active low.
+ * muoe941414 - jtt - 4/28/94
+ * These bits actually tell which submodules are present (each one
+ * representing a submodule). Submodpres is a bit place indicator
+ * of what modules are present (there is always a base board - 1 in
+ * lowest position).
+ */
+
+ number_submodules = ~(number_submodules | 0xFC);
+
+ if(number_submodules)
+ submodule_present = (number_submodules << BASE_BOARD_SHIFT) | BASE_BOARD_PRESENT;
+ else
+ submodule_present = 0;
+
+ /*
+ * For each submodule, allocate a submodule structure and fill in
+ * default values for the eeprom read.
+ */
+
+ submodule_p = &(NCRCatModule->SubModules);
+ for (i = 1; number_submodules != 0, i <= MAXSUBMOD; i++) {
+ /*
+ * muoe941414 - jtt - 4/28/94
+ * check first if submodule is present (corresponding bit set in
+ * submodpres string
+ */
+
+ if (!(submodule_present & (1 << (i - 1))))
+ continue;
+ if ((*submodule_p = submodule = (PMODULE)ExAllocatePool(NonPagedPool,sizeof(MODULE))) != NULL) {
+ /*
+ * The submodule address is kept in the three most significant bits of
+ * the module address.
+ */
+ RtlZeroMemory((PVOID)submodule, sizeof(MODULE));
+ submodule->ModuleAddress = ((i << 5) | NCRCatModule->ModuleAddress);
+ submodule->EEpromSize = EEPROM_SIZE;
+ submodule->ScanPathConnected = FALSE;
+ submodule_p = &submodule->Next;
+
+ /*
+ * Allocate a ASIC structure for CAT_I for each submodule; we will need
+ * it to select the submodle when we return to catinit_L5().
+ */
+ if (!(submodule->Asic = (PASIC)ExAllocatePool(NonPagedPool,sizeof(ASIC)))) {
+ ExFreePool((PVOID)submodule);
+ *submodule_p = NULL;
+ return(i - 1);
+ }
+ RtlZeroMemory((PVOID)submodule->Asic, sizeof(ASIC));
+ submodule->Asic->AsicId = CAT_I;
+ submodule->Asic->SubaddressSpace = SUBADDR_HI;
+ }
+ }
+ *submodule_p = NULL;
+ return(number_submodules);
+}
+
+
+
+PUCHAR
+NCRCatReadModuleData(
+ )
+
+/*++
+
+Routine Description:
+ Read the module data from the EEPROM and checksum it. If the checksum
+ fails for any reason, a NULL pointer is returned. If the checksum is
+ correct a pointer to the EEPROM data is returned.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ CAT_CONTROL cat_control;
+ PASIC asic;
+ USHORT xsum_end;
+ USHORT xsum;
+ PUSHORT data;
+ USHORT i;
+ USHORT size_of_eeprom;
+ LONG status;
+
+/*
+ * Allocate and define an ASIC data structure for the CAT_I so we can do our first read.
+ * If it is a processor board, the CAT_I will have been allocated by NCRCatSubModulePresent.
+ * If an error occurs, do not free the Asic structure since we may or may not have creatd it and
+ * it will be needed by NCRCatDefaultSetup if we fail.
+ */
+
+ if (NCRCatModule->Asic == NULL) {
+ if (!(asic = NCRCatModule->Asic = (PASIC)ExAllocatePool(NonPagedPool,sizeof(ASIC)))) {
+ return (NULL);
+ }
+ RtlZeroMemory((PVOID)asic, sizeof(ASIC));
+
+ asic->AsicId = CAT_I;
+ asic->SubaddressSpace = SUBADDR_HI;
+ } else {
+ asic = NCRCatModule->Asic;
+ }
+
+/*
+ * Read the checksum offset from the EEPROM and make sure it looks valid.
+ */
+
+ cat_control.Module = NCRCatModule->ModuleAddress;
+ cat_control.Asic = CAT_I;
+ cat_control.Command = READ_SUBADDR;
+ cat_control.Address = XSUM_END_OFFSET;
+ cat_control.NumberOfBytes = 2;
+
+ status = NCRCatSubaddressIo(asic,&cat_control,(PUCHAR)&xsum_end);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
+
+ if (status) {
+ return (NULL);
+ }
+
+ cat_control.Module = NCRCatModule->ModuleAddress;
+ cat_control.Asic = CAT_I;
+ cat_control.Command = READ_SUBADDR;
+ cat_control.Address = EEPROM_SIZE_OFFSET;
+ cat_control.NumberOfBytes = 2;
+
+ status = NCRCatSubaddressIo(asic,&cat_control,(PUCHAR)&size_of_eeprom);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
+
+ if (status) {
+ return (NULL);
+ }
+
+ if ((xsum_end < sizeof(MODULE_HEADER)) || (xsum_end > size_of_eeprom)) {
+ return (NULL);
+ }
+
+/*
+ * Allocate a buffer for the data and read it from the EEPROM
+ */
+
+ if ((data = (PUSHORT) ExAllocatePool(NonPagedPool, (ULONG)xsum_end)) == NULL) {
+ return (NULL);
+ }
+
+ RtlZeroMemory((PVOID)data,(ULONG)xsum_end);
+
+ cat_control.Address = EEPROM_DATA_START;
+ cat_control.NumberOfBytes = xsum_end;
+
+ status = NCRCatSubaddressIo(asic, &cat_control, (PUCHAR)data);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
+
+ if (status) {
+ ExFreePool((PVOID)data);
+ return (NULL);
+ }
+
+
+/*
+ * Checksum the data to make sure it is valid.
+ */
+
+ for (i = 0, xsum = 0; i < (USHORT)(xsum_end / 2); i++)
+ xsum += *((PUSHORT)(data +i));
+
+ if (xsum != 0) {
+ ExFreePool((PVOID)data);
+ return (NULL);
+ }
+
+/*
+ * Return the EEPROM data. Also, as a side effect, the NCRCatModule->asic field
+ * is left pointing to the ASIC data structure that was allocated.
+ */
+ return ((PUCHAR)data);
+
+}
+
+
+
+VOID
+NCRCatExtractSetupInformation(
+ PUCHAR EEpromData
+ )
+
+/*++
+
+Routine Description:
+ Extract the setup information from the data read from the EEPROM.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PASIC asic, *asic_pointer;
+ PMODULE_HEADER module_header;
+ PSCAN_PATH_TABLE scan_path_table;
+ PASIC_DATA_TABLE asic_data_table;
+ PJTAG_TABLE jtag_table;
+ USHORT asic_number, scan_path_offset;
+ LONG i;
+
+ module_header = (PMODULE_HEADER)EEpromData;
+ NCRCatModule->EEpromSize = module_header->EEpromSize;
+ NCRCatModule->NumberOfAsics = module_header->NumberOfAsics;
+
+
+ for (asic_number = 0, asic = NCRCatModule->Asic, scan_path_offset = module_header->ScanPathOffset;
+ asic_number < module_header->NumberOfAsics; asic_number++, scan_path_offset +=
+ sizeof(SCAN_PATH_TABLE), asic_pointer = &asic->Next, asic = NULL) {
+
+/*
+ * On the first pass, we have an asic that was allocated when the
+ * data block was read from the EEPROM.
+ */
+
+ if (asic == NULL) {
+ if (!(asic = *asic_pointer = ExAllocatePool(NonPagedPool,sizeof(ASIC)))) {
+ ExFreePool((PVOID)EEpromData);
+ return;
+ }
+ RtlZeroMemory((PVOID)asic, sizeof(ASIC));
+ }
+
+
+ asic->AsicLocation = (UCHAR)asic_number;
+
+/*
+ * Set up a pointer to the new scan path table
+ */
+
+ scan_path_table = (PSCAN_PATH_TABLE)(EEpromData + scan_path_offset);
+ asic->AsicId = scan_path_table->AsicId;
+
+/*
+ * Set up a pointer to the asic_data_table
+ */
+
+ asic_data_table = (PASIC_DATA_TABLE)(EEpromData + scan_path_table->AsicDataOffset);
+ for (i = 0; i < 4; i++) {
+ asic->JtagId[i] = asic_data_table->JtagId[i];
+ }
+ asic->SubaddressSpace = ((1 << asic_data_table->SubaddressBits) - 1);
+
+
+/*
+ * Set up a pointer to the jtab_table
+ */
+
+ jtag_table = (PJTAG_TABLE)(EEpromData + asic_data_table->JtagOffset);
+ asic->InstructionRegisterLength = jtag_table->InstructionRegisterLength;
+ asic->BitLocation = (USHORT)NCRCatModule->InstructionBits;
+ NCRCatModule->InstructionBits += asic->InstructionRegisterLength;
+
+ if (asic->InstructionRegisterLength > NCRCatModule->LargestRegister) {
+ NCRCatModule->LargestRegister = asic->InstructionRegisterLength;
+ }
+
+ if (asic->InstructionRegisterLength < NCRCatModule->SmallestRegister ||
+ NCRCatModule->SmallestRegister == 0) {
+ NCRCatModule->SmallestRegister = asic->InstructionRegisterLength;
+ }
+ }
+ asic_pointer = NULL;
+
+ ExFreePool((PVOID)EEpromData);
+}
+
+VOID
+NCRCatDefaultSetupInformation(
+ )
+
+/*++
+
+Routine Description:
+ Assign defaults to the module if the EEPROM checksum is not correct.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PASIC asic, *asic_pointer;
+ USHORT i;
+
+ switch (NCRCatModule->ModuleAddress) {
+ case PROCESSOR0:
+ case PROCESSOR1:
+ case PROCESSOR2:
+ case PROCESSOR3:
+ case PROCESSOR4:
+ case PROCESSOR5:
+ case PROCESSOR6:
+ case PROCESSOR7:
+ NCRCatModule->EEpromSize = EEPROM_SIZE;
+ NCRCatModule->NumberOfAsics = 1;
+ break;
+
+ case MEMORY0:
+ case MEMORY1:
+ NCRCatModule->EEpromSize = EEPROM_SIZE;
+ NCRCatModule->NumberOfAsics = 7;
+ break;
+
+ case PRIMARYMC:
+ NCRCatModule->EEpromSize = EEPROM_SIZE;
+ NCRCatModule->NumberOfAsics = 9;
+ break;
+
+ case SECONDARYMC:
+ NCRCatModule->EEpromSize = EEPROM_SIZE;
+ NCRCatModule->NumberOfAsics = 7;
+ break;
+
+ case PSI:
+ NCRCatModule->EEpromSize = PSI_EEPROM_SIZE;
+ NCRCatModule->NumberOfAsics = 1;
+ break;
+
+ default:
+ NCRCatModule->EEpromSize = EEPROM_SIZE;
+ NCRCatModule->NumberOfAsics = 1;
+ break;
+ }
+
+ NCRCatModule->InstructionBits = NCRCatModule->NumberOfAsics * CHAR_SIZE;
+ NCRCatModule->LargestRegister = 8;
+ NCRCatModule->SmallestRegister = 8;
+ NCRCatModule->SubModules = NULL;
+
+ for (i = 0, asic = NCRCatModule->Asic,asic_pointer = &NCRCatModule->Asic;
+ i < NCRCatModule->NumberOfAsics; i++) {
+
+ if (*asic_pointer == NULL) {
+ if (!(asic = *asic_pointer = ExAllocatePool(NonPagedPool,sizeof(ASIC)))) {
+ return;
+ }
+ }
+
+ RtlZeroMemory((PVOID)asic,sizeof(ASIC));
+
+ asic->AsicId = (UCHAR)i;
+ asic->AsicLocation = (UCHAR)i;
+ asic->BitLocation = (UCHAR)(i * CHAR_SIZE);
+ asic->InstructionRegisterLength = 8;
+ asic->SubaddressSpace = SUBADDR_HI;
+ asic_pointer = &asic->Next;
+ }
+}
+
+PMODULE
+NCRCatSelect(
+ UCHAR ModuleAddress
+ )
+
+/*++
+
+Routine Description:
+ This function is used to select a module. If the module address matches the
+ address passed in, a pointer to the module structure is returned. Otherwise,
+ NULL is returned.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PMODULE module, submodule;
+ CAT_CONTROL cat_control;
+ UCHAR module_address, submodule_address, data;
+ LONG status;
+
+
+ /*
+ * Extract the real module and submodule addresses.
+ * If any of the three most significant bits of the module
+ * address are set, we have a submodule.
+ */
+
+ submodule_address = ModuleAddress;
+ module_address = ModuleAddress & 0x1f;
+
+ for (module = NCRCatModuleList; module != NULL; module = module->Next) {
+ if (module->ModuleAddress != module_address)
+ continue;
+
+//
+// Select the module
+//
+ WRITE_PORT_UCHAR((PUCHAR)SELECT_PORT, (UCHAR)module_address);
+
+ /*
+ * muoe941245 - jtt - 5/10/94
+ * If it is a submodule, "catmodule" is not set which
+ * can cause problems in the following catregio(),
+ * especially if it is NULL.
+ */
+ NCRCatModule = module;
+
+ if (submodule_address == module_address)
+ return(module);
+
+ /*
+ * Must be looking for a submodule (16way). Select the
+ * submodule by writing the submodule address in the
+ * two least significant bits of the CAT_I;
+ */
+ for (submodule = module->SubModules; submodule != NULL;
+ submodule = submodule->Next) {
+ if (submodule->ModuleAddress != submodule_address)
+ continue;
+ cat_control.Module = submodule->ModuleAddress;
+ cat_control.Asic = CAT_I;
+ cat_control.Command = WRITE_REGISTER;
+ cat_control.Address = SUBMODSELECT;
+ cat_control.NumberOfBytes = 1;
+
+ data = submodule->ModuleAddress >> 5;
+ status = NCRCatRegisterIo(submodule->Asic, &cat_control, (PUCHAR)&data);
+
+ if (!status) {
+ NCRCatModule = submodule;
+ } else {
+ NCRCatModule = NULL;
+ }
+ return(NCRCatModule);
+ }
+ /*
+ * Should not have to deselect here. The next operation will send a DESELECT.
+ */
+ break;
+ }
+ NCRCatModule = NULL;
+ return (NULL);
+}
+
+PASIC
+NCRCatGetAsic(
+ UCHAR AsicId
+ )
+
+/*++
+
+Routine Description:
+ Tries to match the AsicId with an AsicId in the current selected module.
+ If there is no match, NULL is returned.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PASIC asic;
+
+ for (asic = NCRCatModule->Asic; asic != NULL; asic = asic->Next) {
+ if (asic->AsicId == AsicId) {
+ return (asic);
+ }
+ }
+
+ return (NULL);
+}
+
+
+LONG
+NCRCatConnect(
+ )
+
+/*++
+
+Routine Description:
+ Called to connect the CAT_I with all of the other ASICs on the module.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PASIC asic;
+ UCHAR value;
+ LONG status;
+
+ if (NCRCatModule->ScanPathConnected == TRUE) {
+ return (CATNOERR);
+ }
+
+ if (!(asic = NCRCatGetAsic(CAT_I))) {
+ return (CATIO);
+ }
+
+ if (status = NCRCatRead(asic, SCANPATH, &value)) {
+ return (status);
+ }
+
+ value |= CONNECT_ASICS;
+
+ if (status = NCRCatWrite(asic, SCANPATH, &value)) {
+ return (status);
+ }
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
+
+ NCRCatModule->ScanPathConnected = TRUE;
+
+ return (CATNOERR);
+}
+
+
+
+LONG
+NCRCatDisconnect(
+ )
+
+/*++
+
+Routine Description:
+ Called to disconnect the CAT_I from all the ASICs on the module.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ PASIC asic;
+ UCHAR value;
+ LONG status;
+
+ if (NCRCatModule->ScanPathConnected == FALSE) {
+ return (CATNOERR);
+ }
+
+ if (!(asic = NCRCatGetAsic(CAT_I))) {
+ return (CATIO);
+ }
+
+ if (status = NCRCatRead(asic, SCANPATH, &value)) {
+ return (status);
+ }
+
+ value &= DISCONNECT_ASIC;
+
+ if (status = NCRCatWrite(asic, SCANPATH, &value)) {
+ return (status);
+ }
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
+
+ NCRCatModule->ScanPathConnected = FALSE;
+ return (CATNOERR);
+}
+
+
+VOID
+NCRCatRestoreState(
+ )
+
+/*++
+
+Routine Description:
+ This function is called when an I/O error has occured. The best thing to do
+ is to do a blind disconnect and hope this fixes the problem.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ UCHAR instruction;
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)IRCYC); // Instruct the module
+ instruction = NCRCatInstruction(SCANPATH, WRITE_CONFIG);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)instruction);
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)DRCYC);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)RESET_STATE);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
+
+ NCRCatModule->ScanPathConnected = FALSE;
+}
+
+
+LONG
+NCRCatAutoIncrement(
+ PASIC Asic
+ )
+
+/*++
+
+Routine Description:
+ When reading/writing from/to the subaddress space of an ASIC, the catautoinc bit
+ can be set so that registers 6 & 7 are incremented by the hardware after each
+ read/write from/to register 3.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ UCHAR newvalue;
+ UCHAR oldvalue;
+ LONG status;
+
+ if (status = NCRCatRead(Asic, AUTO_INC_REG, &oldvalue)) {
+ return (status);
+ }
+
+ if ((newvalue = (oldvalue | AUTO_INC)) != oldvalue) {
+ status = NCRCatWrite(Asic, AUTO_INC_REG, &newvalue);
+ }
+
+ return status;
+}
+
+LONG
+NCRCatNoAutoIncrement(
+ PASIC Asic
+ )
+
+/*++
+
+Routine Description:
+ This function is used to reset the auto increment bit for subaddress reads/writes.
+ This allows reads/writes from/to the subaddress space via register 3 with out
+ incrementing registers 6 & 7.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ UCHAR newvalue;
+ UCHAR oldvalue;
+ LONG status;
+
+ if (status = NCRCatRead(Asic, AUTO_INC_REG, &oldvalue)) {
+ return (status);
+ }
+
+ if ((newvalue = (oldvalue & NO_AUTO_INC)) != oldvalue) {
+ status = NCRCatWrite(Asic, AUTO_INC_REG, &newvalue);
+ }
+
+ return (status);
+}
+
+
+
+LONG
+NCRCatSubaddressSetup(
+ PASIC Asic,
+ USHORT Subaddress
+ )
+
+/*++
+
+Routine Description:
+ Sets up register 6 & 7 for a subaddress read. Note: If the subaddres space
+ requires 8 bits or less for addressing, register 7 may be user defined. If
+ there is no subaddress space registers 6 & 7 may be user defined.
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LONG status;
+ UCHAR address;
+
+ if (Asic->SubaddressSpace == (USHORT)SUBADDR_ZERO) {
+ return (CATIO);
+ }
+
+/*
+ * Set up register 6 with the low byte of the sub address
+ */
+ address = (UCHAR)(Subaddress & 0xff);
+ if (status = NCRCatWrite(Asic, SUBADDRLO, &address)) {
+ return (status);
+ }
+
+/*
+ * Set up register 7 with the high byte of the sub address
+ */
+
+ if (Asic->SubaddressSpace > SUBADDR_LO) {
+ address = (UCHAR)(Subaddress >> CHAR_SIZE);
+ status = NCRCatWrite(Asic, SUBADDRHI, &address);
+ }
+ return (status);
+}
+
+
+
+LONG
+NCRCatRegisterIo(
+ PASIC Asic,
+ PCAT_CONTROL CatControl,
+ PUCHAR Buffer
+ )
+
+/*++
+
+Routine Description:
+ The function is used to read/write from/to any number of register of an ASIC.
+ If a read is being performed, the buffer is assumed to be large enough to
+ hold the data that is being read.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ UCHAR register_number;
+ PUCHAR buffer;
+ USHORT number_bytes;
+ LONG status;
+
+ if ((USHORT)(CatControl->Address + CatControl->NumberOfBytes) > (USHORT)MAXNUMREG) {
+ return (CATFAULT);
+ }
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
+
+ if (Asic->AsicId == CAT_I) {
+ if (status = NCRCatDisconnect()) {
+ return (status);
+ }
+ } else {
+ if (status = NCRCatConnect()) {
+ return (status);
+ }
+ }
+
+ if (CatControl->Command == READ_REGISTER) {
+ for (register_number = (UCHAR)CatControl->Address, number_bytes = CatControl->NumberOfBytes,
+ buffer = Buffer; number_bytes > 0;
+ register_number++, number_bytes--, buffer++) {
+
+ if (status = NCRCatRead(Asic, register_number, buffer)) {
+ return (status);
+ }
+ }
+ } else { /* CatControl->Command == WRITE_REGISTER */
+
+ for (register_number = (UCHAR)CatControl->Address, number_bytes = CatControl->NumberOfBytes,
+ buffer = Buffer; number_bytes > 0;
+ register_number++, number_bytes--, buffer++) {
+
+ if (status = NCRCatWrite(Asic, register_number, buffer)) {
+ return (status);
+ }
+ }
+ }
+
+ if (Asic->AsicId != CAT_I) {
+ status = NCRCatDisconnect();
+ }
+
+ return (status);
+}
+
+
+
+
+LONG
+NCRCatSubaddressIo(
+ PASIC Asic,
+ PCAT_CONTROL CatControl,
+ PUCHAR Buffer
+ )
+
+/*++
+
+Routine Description:
+ This function is used to read/write from/to the subaddress space of an ASIC.
+ If a read is being performed, the buffer is assumed to be large enough to hold
+ the data that is being read.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LONG status;
+
+ if ((ULONG)(CatControl->Address + CatControl->NumberOfBytes - 1) > Asic->SubaddressSpace) {
+ return (CATFAULT);
+ }
+
+ if ((CatControl->Module >= PROCESSOR0 && CatControl->Module <= PROCESSOR3 ||
+ CatControl->Module >= PROCESSOR4 && CatControl->Module <= PROCESSOR7) &&
+ ((ULONG)(CatControl->Address + CatControl->NumberOfBytes) >
+ (ULONG)NCRCatModule->EEpromSize)) {
+ return (CATACCESS);
+ }
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
+
+ if (Asic->AsicId == CAT_I) {
+ if (status = NCRCatDisconnect())
+ return (status);
+ } else { /* Asic->AsicId != CAT_I */
+ if (status = NCRCatConnect())
+ return (status);
+ }
+
+ if (CatControl->Command == READ_SUBADDR) {
+ if (status = NCRCatSubaddressRead(Asic, CatControl, Buffer))
+ return (status);
+ } else {
+ if (status = NCRCatSubaddressWrite(Asic, CatControl, Buffer))
+ return (status);
+ }
+ if (Asic->AsicId != CAT_I)
+ status = NCRCatDisconnect();
+
+ return (status);
+}
+
+
+LONG
+NCRCatRead(
+ PASIC Asic,
+ UCHAR RegisterNumber,
+ PUCHAR Buffer
+ )
+
+/*++
+
+Routine Description:
+ Function used to read one register from one asic at a time.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LONG status;
+ LONG internal_register = TRUE;
+ UCHAR instruction;
+
+ instruction = NCRCatInstruction(RegisterNumber, READ_CONFIG);
+
+ if (status = NCRCatSendInstruction(Asic, instruction))
+ return (status);
+
+ if (RegisterNumber > SUBADDRHI)
+ internal_register = FALSE;
+
+ if (status = NCRCatGetData(Asic, Buffer, internal_register))
+ return (status);
+
+ return (status);
+}
+
+
+
+LONG
+NCRCatWrite(
+ PASIC Asic,
+ UCHAR RegisterNumber,
+ PUCHAR Data
+ )
+
+/*++
+
+Routine Description:
+ Function used to write to one register of one ASIC at a time. It
+ is assumed that the CatSelect call has already been used to select
+ the desired module.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ LONG status;
+ LONG internal_register = TRUE;
+ LONG external_special = FALSE;
+ UCHAR instruction;
+
+ instruction = NCRCatInstruction(RegisterNumber, WRITE_CONFIG);
+
+ if (status = NCRCatSendInstruction(Asic, instruction))
+ return (status);
+
+ if (RegisterNumber > SUBADDRHI) {
+ internal_register = FALSE;
+ if (RegisterNumber < MAXNUMREG) {
+ external_special = TRUE;
+ }
+ }
+
+ if (status = NCRCatSendData(Asic, Data, internal_register, external_special))
+ return (status);
+
+ return (status);
+}
+
+
+
+LONG
+NCRCatSubaddressRead(
+ PASIC Asic,
+ PCAT_CONTROL CatControl,
+ PUCHAR Buffer
+ )
+
+/*++
+
+Routine Description:
+ Function used to read data from the subaddress space. If the CAT_I subaddress
+ space is being read (EEPROM), extra RUN cycles are required for the read.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ UCHAR instruction;
+ PUCHAR buffer;
+ USHORT number_bytes;
+ LONG status;
+
+ if (CatControl->NumberOfBytes > 1) {
+ if (status = NCRCatAutoIncrement(Asic))
+ return (status);
+ }
+
+ if (status = NCRCatSubaddressSetup(Asic, CatControl->Address)) {
+ return (status);
+ }
+
+ instruction = NCRCatInstruction(SUBADDRDATA, READ_CONFIG);
+
+ if (status = NCRCatSendInstruction(Asic, instruction)) {
+ return (status);
+ }
+
+ for (number_bytes = CatControl->NumberOfBytes, buffer = Buffer; number_bytes > 0;
+ number_bytes--, buffer++) {
+
+ if (status = NCRCatGetData(Asic, buffer, FALSE))
+ break;
+ }
+ return (status);
+}
+
+
+LONG
+NCRCatWriteComplete(
+ PASIC Asic,
+ USHORT Address,
+ UCHAR Expected
+ )
+
+/*++
+
+Routine Description:
+ Function used to determine if a write to the subaddress space of the CAT_I (EEPROM) has been
+ completed. The write is complete when the data read matches what was written. The data that
+ is read should be the one's complement of the data written until the write completes.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ UCHAR data;
+ LONG status;
+ ULONG i, j;
+ UCHAR instruction;
+
+ if (status = NCRCatNoAutoIncrement(Asic))
+ return (status);
+
+ if (status = NCRCatSubaddressSetup(Asic, Address))
+ return (status);
+
+ for (i = 0; i < MAXREADS; i++) {
+ for ( j = 0; j < WRITEDELAY; j++)
+ KeStallExecutionProcessor((ULONG)10);
+
+/* Old code
+ if (status = NCRCatRead(Asic, SUBADDRDATA, &data))
+ return(status);
+*/
+ instruction = NCRCatInstruction(SUBADDRDATA, READ_CONFIG);
+
+ if (status = NCRCatSendInstruction(Asic,instruction))
+ return(status);
+
+ if (status = NCRCatGetData(Asic, &data, FALSE))
+ return(status);
+
+ if (data == Expected)
+ return (CATNOERR);
+ }
+ return (CATIO);
+}
+
+
+
+LONG
+NCRCatSubaddressWrite(
+ PASIC Asic,
+ PCAT_CONTROL CatControl,
+ PUCHAR Buffer
+ )
+
+/*++
+
+Routine Description:
+ Function that writes to the subaddress space of an ASIC.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ USHORT subaddress;
+ USHORT remaining_bytes;
+ USHORT number_bytes;
+ USHORT i;
+ UCHAR instruction;
+ PUCHAR buffer;
+ LONG status;
+
+/*
+ * The CAT_I subaddress space (EEPROM) may be written one byte at
+ * time. However, the EEPROM waits for 20 microsec before starting
+ * the write. If an additional byte of data is received before the
+ * 20 microsec timeout, the EEPROM waits for yet another byte of data.
+ * This contiues until the 64 byte EEPROM buffer is filled or a timeout
+ * occures. At that point the data is written to the EEPROM.
+ */
+
+ if ((CatControl->Asic == CAT_I) && (CatControl->Address < NCRCatModule->EEpromSize)) {
+/*
+ * Write the data up to a page & then wait for the EEPROM write to complete.
+ */
+
+ for (subaddress = CatControl->Address, remaining_bytes = CatControl->NumberOfBytes,
+ buffer = Buffer; remaining_bytes > 0; subaddress += number_bytes,
+ remaining_bytes -= number_bytes) {
+
+ number_bytes = EEPROMPAGESIZE - (USHORT)(subaddress % EEPROMPAGESIZE);
+
+ if (number_bytes > remaining_bytes)
+ number_bytes = remaining_bytes;
+
+ if (status = NCRCatAutoIncrement(Asic))
+ return (status);
+
+ if (status = NCRCatSubaddressSetup(Asic, subaddress))
+ return (status);
+
+ instruction = NCRCatInstruction(SUBADDRDATA, WRITE_CONFIG);
+
+ if (status = NCRCatSendInstruction(Asic, instruction))
+ return (status);
+
+/*
+ * When writing to the EEPROM, error checking must be delayed until
+ * the the end of the block write. This is due to the amount of
+ * time it take to send data over the CAT bus and the EEPROM
+ * timeout.
+ */
+ for (i = 0; i < number_bytes; i++) {
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)DRCYC);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)*buffer++);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
+ }
+
+/*
+ * If the read starts in the PSI EEPROM and continues into the
+ * the subaddress space past the EEPROM the data compare must
+ * stop. Writing to this area toggles bits so the data that is
+ * written may not match what is read later.
+ */
+
+ if ((ULONG)(subaddress + number_bytes - 1) < (ULONG)NCRCatModule->EEpromSize) {
+/*
+ * Read the last byte and compare it with last byte written.
+ * The data should be the one's complement of the data written
+ * until the write completes.
+ */
+ if (status = NCRCatWriteComplete(Asic, (USHORT)(subaddress + number_bytes - 1),
+ *(buffer - 1))) {
+
+ return (status);
+ }
+
+ }
+
+ }
+
+
+ } else { /* ((Aisc != CAT_I) || (CatControl->Address >= NCRCatControl->EEpromSize)) */
+
+ if (status = NCRCatAutoIncrement(Asic))
+ return (status);
+
+ if (status = NCRCatSubaddressSetup(Asic, CatControl->Address))
+ return (status);
+
+ instruction = NCRCatInstruction(SUBADDRDATA, WRITE_CONFIG);
+
+ if (status = NCRCatSendInstruction(Asic, instruction))
+ return (status);
+
+ for (number_bytes = CatControl->NumberOfBytes, buffer = Buffer; number_bytes > 0;
+ number_bytes--, buffer++) {
+
+ if (status = NCRCatSendData(Asic, buffer, FALSE, FALSE))
+ return (status);
+ }
+ }
+ return (CATNOERR);
+}
+
+
+
+UCHAR
+NCRCatInstruction(
+ UCHAR RegisterNumber,
+ UCHAR Operation
+ )
+
+/*++
+
+Routine Description:
+ Function builds an instruction by determing the parity bit needed for
+ even parity and puting this value in bit 7 and zero in bit 6. The
+ register number is placed in bits 2-5 and the operation (read/write)
+ value in bits 0 and 1.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ UCHAR parity;
+
+/*
+ * Parity is the parity of the register number + 1 (READ_REGISTER
+ * and WRITE_REGISTER always add '1' to the number of bits == 1)
+ */
+
+ parity = (UCHAR)(1 + (RegisterNumber & 0x01) +
+ ((UCHAR)(RegisterNumber & 0x02) >> 1) +
+ ((UCHAR)(RegisterNumber & 0x04) >> 2) +
+ ((UCHAR)(RegisterNumber & 0x08) >> 3)) % 2;
+
+ return (((parity << 7) | (RegisterNumber << 2) | Operation));
+}
+
+
+LONG
+NCRCatSendInstruction(
+ PASIC Asic,
+ UCHAR Instruction
+ )
+
+/*++
+
+Routine Description:
+ Function inserts an instruction inside of a string to be shifted
+ out of the NCRCatDataPort so that all of the ASICs execept the one we are
+ instructing will be placed in bypass mode. If the scan path has not been
+ connected, then we can only talk to the CAT_I. In this case, we have very
+ little work to do.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ UCHAR instruction_sequence[MAX_SCAN_PATH];
+ UCHAR header_sequence[MAX_REG_SIZE];
+ SHORT i;
+ SHORT instruction_bytes;
+ SHORT header_bytes;
+ SHORT pad_bits;
+ LONG status = CATNOERR;
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)IRCYC);
+
+ if (NCRCatModule->ScanPathConnected == FALSE) {
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)HEADER);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)Instruction);
+
+ if ((READ_PORT_UCHAR((PUCHAR)NCRCatDataPort)) != HEADER)
+ status = CATIO;
+
+ return (status);
+ }
+
+ instruction_bytes = NCRCatModule->InstructionBits / CHAR_SIZE;
+
+ if (pad_bits = NCRCatModule->InstructionBits % CHAR_SIZE) {
+ pad_bits = CHAR_SIZE - pad_bits;
+ instruction_bytes++;
+ }
+
+ header_bytes = NCRCatModule->LargestRegister / CHAR_SIZE;
+
+ if (NCRCatModule->LargestRegister % CHAR_SIZE)
+ header_bytes++;
+
+ for (i = 0; i < (instruction_bytes + header_bytes); i++) {
+ *(instruction_sequence + i) = 0xff;
+ }
+
+ NCRCatBuildHeader(header_sequence, header_bytes, NCRCatModule->LargestRegister,
+ NCRCatModule->SmallestRegister);
+
+ NCRCatInsertData(instruction_sequence, NCRCatModule->InstructionBits, header_sequence,
+ (SHORT)(header_bytes * CHAR_SIZE));
+
+ NCRCatInsertData(instruction_sequence, Asic->BitLocation, &Instruction,
+ Asic->InstructionRegisterLength);
+
+ status = NCRCatShiftOutData(instruction_sequence, instruction_bytes, header_bytes, pad_bits);
+
+ return (status);
+}
+
+VOID
+NCRCatBuildHeader(
+ PUCHAR Header,
+ SHORT HeaderBytes,
+ SHORT LargestRegister,
+ SHORT SmallestRegister
+ )
+
+/*++
+
+Routine Description:
+ Function builds a header to be placed out on the CAT bus. It is used
+ to make sure that a register did not unexpectedly go into bypass.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ SHORT one_bits;
+ SHORT i;
+ PUCHAR last_byte;
+
+ if (SmallestRegister == 1)
+ one_bits = 1;
+ else
+ one_bits = (USHORT)(SmallestRegister - 1) % CHAR_SIZE;
+
+ for (i = 0; i < HeaderBytes; i++)
+ *(Header+i) = 0;
+
+ for (i = one_bits, last_byte = (PUCHAR)(Header + (HeaderBytes - 1)); i > 0; i--)
+ *last_byte = ((*last_byte) << 1) + 1;
+}
+
+
+LONG
+NCRCatSendData(
+ PASIC Asic,
+ PUCHAR Data,
+ LONG InternalRegister,
+ LONG ExternalRegister
+ )
+
+/*++
+
+Routine Description:
+ Function generates a sequence to be shifted out of the NCRCatDataPort
+ so that the data is send to the desired ASIC and an one is shifted to all
+ of the other ASICs (they are in bypass mode).
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ UCHAR data_sequence[MAX_SCAN_PATH];
+ UCHAR header_sequence[MAX_REG_SIZE];
+ SHORT i;
+ SHORT data_bytes;
+ SHORT header_bytes;
+ SHORT pad_bits;
+ SHORT header_location;
+ LONG status = CATNOERR;
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)DRCYC);
+
+ if (NCRCatModule->ScanPathConnected == FALSE) {
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)HEADER);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)*Data);
+
+ if (READ_PORT_UCHAR((PUCHAR)NCRCatDataPort) != HEADER)
+ status = CATIO;
+
+ if (InternalRegister == FALSE) {
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
+
+ if (ExternalRegister == TRUE) {
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)END);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
+ }
+ }
+ return (status);
+ }
+
+ data_bytes = (SHORT)((NCRCatModule->NumberOfAsics - 1) + Asic->InstructionRegisterLength) /
+ (SHORT)CHAR_SIZE;
+
+ if (pad_bits = (SHORT)((NCRCatModule->NumberOfAsics - 1) +
+ Asic->InstructionRegisterLength) % (SHORT)CHAR_SIZE) {
+
+ pad_bits = CHAR_SIZE - pad_bits;
+ data_bytes++;
+ }
+
+ header_bytes = (SHORT)(Asic->InstructionRegisterLength / CHAR_SIZE);
+
+ if ((SHORT)(Asic->InstructionRegisterLength % CHAR_SIZE))
+ header_bytes++;
+
+ NCRCatBuildHeader(header_sequence, header_bytes, Asic->InstructionRegisterLength, 1);
+
+ for (i = 0; i < (data_bytes + header_bytes); i++)
+ *(data_sequence + i) = 0xff;
+
+
+ header_location = (NCRCatModule->NumberOfAsics - 1) + Asic->InstructionRegisterLength;
+
+ NCRCatInsertData(data_sequence, header_location, header_sequence, (SHORT)(header_bytes * CHAR_SIZE));
+ NCRCatInsertData(data_sequence, Asic->AsicLocation, Data, Asic->InstructionRegisterLength);
+
+ status = NCRCatShiftOutData(data_sequence, data_bytes, header_bytes, pad_bits );
+
+ return (status);
+}
+
+
+VOID
+NCRCatInsertData(
+ PUCHAR String,
+ SHORT StartBit,
+ PUCHAR Data,
+ SHORT NumberOfBits
+ )
+
+/*++
+
+Routine Description:
+ Given a string, the function places the data inside of the string
+ starting a bit location string_bit. The most significant byte will
+ be placed in the first 8 bits starting at string_bit location. If
+ the data does not fall on a byte boundry, the data should be placed
+ in the high order bits. The low order bits should be padded with 1's.
+ The first byte of the string is considered the most significant byte
+ and should be the last byte shifted out.
+
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ SHORT data_bits; // running count of data bits placed in the string
+ SHORT data_bits_remaining; // data bits remaining in current char
+ SHORT string_bits_needed; // string bits needed to fill current char
+ SHORT bits_in_string; // bits inserted in the string during current operation
+ PUCHAR tmp_string;
+ PUCHAR tmp_data;
+
+ for (data_bits = 0, tmp_string = String + (StartBit / CHAR_SIZE), tmp_data = Data;
+ NumberOfBits > 0; data_bits += bits_in_string, StartBit += bits_in_string,
+ NumberOfBits -= bits_in_string ) {
+
+ data_bits_remaining = CHAR_SIZE - (data_bits % CHAR_SIZE);
+ string_bits_needed = CHAR_SIZE - (StartBit % CHAR_SIZE);
+
+ if (data_bits_remaining == CHAR_SIZE && string_bits_needed == CHAR_SIZE) {
+ *tmp_string++ = *tmp_data++;
+ bits_in_string = CHAR_SIZE;
+
+ } else if (data_bits_remaining == CHAR_SIZE) { /* string_bits_needed != CHAR */
+ *tmp_string++ &= (UCHAR)((0xff << string_bits_needed ) |
+ (*tmp_data >> (CHAR_SIZE - string_bits_needed)));
+ bits_in_string = string_bits_needed;
+
+ } else if (string_bits_needed == CHAR_SIZE) { /* data_bits_remaining != CHAR_SIZE */
+
+ *tmp_string &= (0xff >> data_bits_remaining) |
+ (*tmp_data++ << (CHAR_SIZE - data_bits_remaining));
+ bits_in_string = data_bits_remaining;
+
+ } else {
+ /*RMU this is an error case... */
+ }
+ }
+}
+
+
+
+VOID
+NCRCatExtractData(
+ PUCHAR String,
+ SHORT StartBit,
+ PUCHAR Data,
+ SHORT NumberOfBits
+ )
+
+/*++
+
+Routine Description:
+ Function extract NumberBits of data from the string and places them in
+ the string Data.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ SHORT data_bits; // running count of data bits in the data string
+ SHORT data_bits_needed; // data bits needed from to fill current char
+ SHORT string_bits_remaining; // string bits remaining in current char
+ SHORT bits_extracted; // bits extracted from the string with last operation
+ PUCHAR tmp_string;
+ PUCHAR tmp_data;
+
+ for (data_bits = 0, tmp_data = Data, (tmp_string = String + (StartBit / CHAR_SIZE));
+ NumberOfBits > 0; data_bits += bits_extracted, StartBit += bits_extracted,
+ NumberOfBits -= bits_extracted ) {
+
+ data_bits_needed = CHAR_SIZE - (data_bits % CHAR_SIZE);
+ string_bits_remaining = CHAR_SIZE - (StartBit % CHAR_SIZE);
+
+ if (string_bits_remaining == CHAR_SIZE && data_bits_needed == CHAR_SIZE) {
+ *tmp_data++ = *tmp_string;
+ bits_extracted = CHAR_SIZE;
+ }
+ else if (string_bits_remaining == CHAR_SIZE) { /* data_bits_needed != CHAR_SIZE */
+ *tmp_data++ |= *tmp_string >> (CHAR_SIZE - data_bits_needed);
+ bits_extracted = data_bits_needed;
+ }
+ else if (data_bits_needed == CHAR_SIZE) { /* string_bits_remaining != CHAR_SIZE */
+ *tmp_data |= *tmp_string++ << (CHAR_SIZE - string_bits_remaining);
+ bits_extracted = string_bits_remaining;
+ }
+ else {
+ /*RMU this is an error case ASSERT? */
+ }
+ }
+}
+
+
+LONG
+NCRCatShiftOutData(
+ PUCHAR Data,
+ SHORT DataBytes,
+ SHORT HeaderBytes,
+ SHORT PadBits
+ )
+
+/*++
+
+Routine Description:
+ Function shifts out data starting with the last byte in the
+ data string (header is shifted out first). Also checks to make sure
+ the header shifted out matches the header shifted back in.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ SHORT i;
+ SHORT start_bit;
+ UCHAR input = 0;
+ UCHAR header = 0;
+
+ for (i = DataBytes + HeaderBytes - 1; i >= HeaderBytes; i--) {
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)*(Data + i));
+ }
+
+ for (i = HeaderBytes - 1; i >= 0; i--, header = 0) { /* check the header */
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)*(Data + i));
+
+ input = READ_PORT_UCHAR((PUCHAR)NCRCatDataPort);
+ start_bit = ((DataBytes + i) * CHAR_SIZE) - PadBits;
+ NCRCatExtractData(Data, start_bit, &header, CHAR_SIZE);
+
+ if (input != header)
+ return (CATIO);
+ }
+ return (CATNOERR);
+}
+
+
+
+LONG
+NCRCatGetData(
+ PASIC Asic,
+ PUCHAR Data,
+ LONG InternalRegister
+ )
+
+/*++
+
+Routine Description:
+ Functions writes 0xAA in the NCRCatDataPort to be shifted out. Then
+ the results of the shift are read from the NCRCatDataPort and placed in the
+ string "string". This loop continues until the requested data has been
+ placed in the string "string". Then the requested data is extracted from
+ the string "string" and placed in the "Data" string.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ SHORT i;
+ SHORT string_bits;
+ SHORT string_bytes;
+ SHORT trailer_bytes;
+ SHORT pad_bits;
+ UCHAR string[MAX_SCAN_PATH];
+ UCHAR trailer[MAX_REG_SIZE];
+ UCHAR input;
+ LONG status = CATNOERR;
+
+ if (NCRCatModule->ScanPathConnected == FALSE) {
+
+/*
+ * For external register and subaddress space, use the RUN command
+ * to generate extra clock cycles for data access.
+ */
+ if (InternalRegister == FALSE) {
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)RUN);
+ }
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)DRCYC);
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)HEADER);
+ *Data = READ_PORT_UCHAR((PUCHAR)NCRCatDataPort);
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)0xAA);
+
+ if (READ_PORT_UCHAR((PUCHAR)NCRCatDataPort) != HEADER)
+ status = CATIO;
+
+ return (status);
+ }
+
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatCommandPort, (UCHAR)DRCYC);
+
+ string_bits = NCRCatModule->NumberOfAsics - 1 + Asic->InstructionRegisterLength;
+ string_bytes = string_bits / CHAR_SIZE;
+
+ if (pad_bits = string_bits % CHAR_SIZE) {
+ pad_bits = CHAR_SIZE - pad_bits;
+ string_bytes++;
+ }
+
+ trailer_bytes = Asic->InstructionRegisterLength / CHAR_SIZE;
+
+ if (Asic->InstructionRegisterLength % CHAR_SIZE)
+ trailer_bytes++;
+
+ NCRCatBuildHeader((PUCHAR)(trailer), trailer_bytes, Asic->InstructionRegisterLength, 1);
+
+/*
+ * Shift out the trailer while data is being shifted into the string.
+ */
+ for (i = trailer_bytes - 1; i >= 0; i--) {
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)*(trailer + i));
+ *(string + string_bytes + i) = READ_PORT_UCHAR((PUCHAR)NCRCatDataPort);
+ }
+
+/*
+ * Shift out 0xAA until the trailer is shifted back into the string
+ */
+ for (i = string_bytes - 1; i >= 0; i--) {
+ WRITE_PORT_UCHAR((PUCHAR)NCRCatDataPort, (UCHAR)0xAA);
+ *(string + i) = READ_PORT_UCHAR((PUCHAR)NCRCatDataPort);
+ }
+
+ *Data = 0;
+ NCRCatExtractData(string, (SHORT)(pad_bits + (trailer_bytes * CHAR_SIZE) +
+ Asic->AsicLocation), Data, Asic->InstructionRegisterLength);
+
+ for (i = 0; i < trailer_bytes; i++) {
+ input = 0;
+ NCRCatExtractData(string, (SHORT)(pad_bits + (CHAR_SIZE * i)), &input, CHAR_SIZE);
+
+ if (*(trailer + i) != input) {
+ status = CATIO;
+ break;
+ }
+ }
+ return (status);
+}
+
+
+
+LONG
+NCRCatIoLpb(
+ PCAT_CONTROL CatControl,
+ PUCHAR Buffer
+ )
+
+/*++
+
+Routine Description:
+ The following code is for accessing the LPB EEprom image. Since the LPB
+ is not on the cat bus, we must map in this area before accessing it in
+ physical memory.
+
+Arguments:
+
+
+Return Value:
+
+
+--*/
+
+{
+ return (CATNOERR);
+}
+
+
+
+
+VOID
+NCRCatModuleName (
+ LONG Module,
+ PUNICODE_STRING ModuleName
+ )
+
+/*++
+
+Routine Description:
+ Given a module ID return the module name.
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ NTSTATUS status;
+
+ switch (Module) {
+
+ case PROCESSOR0:
+ status = RtlAppendUnicodeToString(ModuleName, L"Processor 0");
+ break;
+
+ case PROCESSOR1:
+ status = RtlAppendUnicodeToString(ModuleName, L"Processor 1");
+ break;
+
+ case PROCESSOR2:
+ status = RtlAppendUnicodeToString(ModuleName, L"Processor 2");
+ break;
+
+ case PROCESSOR3:
+ status = RtlAppendUnicodeToString(ModuleName, L"Processor 3");
+ break;
+
+ case MEMORY0:
+ status = RtlAppendUnicodeToString(ModuleName, L"Memory 0");
+ break;
+
+ case MEMORY1:
+ status = RtlAppendUnicodeToString(ModuleName, L"Memory 1");
+ break;
+
+ case PRIMARYMC:
+ status = RtlAppendUnicodeToString(ModuleName, L"PrimaryMicroChannel");
+ break;
+
+ case SECONDARYMC:
+ status = RtlAppendUnicodeToString(ModuleName, L"SecondaryMicroChannel");
+ break;
+
+ case PSI:
+ status = RtlAppendUnicodeToString(ModuleName, L"PowerSupplyInterface");
+ break;
+
+ case CAT_LPB_MODULE:
+ status = RtlAppendUnicodeToString(ModuleName, L"LocalPeripheralBoard");
+ break;
+
+ default:
+ status = RtlIntegerToUnicodeString(Module, 16, ModuleName);
+ break;
+ }
+}
+
+
+
+
+PWSTR ProcessorAsicNames[16] = {
+ L"CAT_I",
+ L"A_PBC",
+ L"B_PBC",
+ L"3",
+ L"4",
+ L"5",
+ L"6",
+ L"CPU_CATI7",
+ L"8",
+ L"CPU_Config2",
+ L"A",
+ L"CPU_Config4",
+ L"CPU_Config5",
+ L"CPU_Config6",
+ L"CPU_Config7",
+ L"PBC_Status"
+ };
+
+
+
+
+PWSTR MemoryAsicNames[7] = {
+ L"CAT_I",
+ L"MMC1",
+ L"MMA1",
+ L"MMD1_0",
+ L"MMD1_1",
+ L"MMD1_2",
+ L"MMD1_3"
+ };
+
+
+
+PWSTR PMCAsicNames[9] = {
+ L"CAT_I",
+ L"PMC_MCADDR",
+ L"PMC_DMA",
+ L"PMC_DS1",
+ L"PMC_DS0",
+ L"PMC_VIC",
+ L"PMC_ARB",
+ L"PMC_DS2",
+ L"PMC_DS3",
+ };
+
+
+
+
+PWSTR SMCAsicNames[9] = {
+ L"CAT_I",
+ L"PMC_MCADDR",
+ L"PMC_DMA",
+ L"PMC_DS1",
+ L"PMC_DS0",
+ L"5",
+ L"6",
+ L"PMC_DS2",
+ L"PMC_DS3",
+ };
+
+
+
+
+
+VOID
+NCRCatAsicName (
+ LONG Module,
+ LONG Asic,
+ PUNICODE_STRING AsicName
+ )
+
+/*++
+
+Routine Description:
+ Given a Module ID and an Asic ID return the Asic name.
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ NTSTATUS status;
+
+ switch (Module) {
+ case PROCESSOR0:
+ case PROCESSOR1:
+ case PROCESSOR2:
+ case PROCESSOR3:
+ if (Asic > PBC_Status) {
+ status = RtlIntegerToUnicodeString(Asic,
+ 16, AsicName);
+ } else {
+ status = RtlAppendUnicodeToString( AsicName,
+ ProcessorAsicNames[Asic]);
+ }
+ break;
+
+ case MEMORY0:
+ case MEMORY1:
+ if (Asic > MMD1_3) {
+ status = RtlIntegerToUnicodeString(Asic,
+ 16, AsicName);
+ } else {
+ status = RtlAppendUnicodeToString( AsicName,
+ MemoryAsicNames[Asic]);
+ }
+ break;
+
+ case PSI:
+ switch (Asic) {
+ case CAT_I:
+ status = RtlAppendUnicodeToString( AsicName,
+ L"CAT_I");
+ break;
+
+ default:
+ status = RtlIntegerToUnicodeString(Asic,
+ 16, AsicName);
+ break;
+ }
+
+ break;
+
+ case PRIMARYMC:
+ if (Asic > PMC_DS3) {
+ status = RtlIntegerToUnicodeString(Asic,
+ 16, AsicName);
+ } else {
+ status = RtlAppendUnicodeToString( AsicName,
+ PMCAsicNames[Asic]);
+ }
+ break;
+
+ case SECONDARYMC:
+ if (Asic > SMC_DS3) {
+ status = RtlIntegerToUnicodeString(Asic,
+ 16, AsicName);
+ } else {
+ status = RtlAppendUnicodeToString( AsicName,
+ SMCAsicNames[Asic]);
+ }
+
+ break;
+
+
+ default:
+ status = RtlIntegerToUnicodeString(Asic, 16, AsicName);
+ break;
+ }
+
+
+
+}
+
+
+
+VOID
+HalpCatReportModuleAsics (
+ PUNICODE_STRING UnicodeModule,
+ PMODULE Module
+ )
+
+/*++
+
+Routine Description:
+ Place information about module Asics into the registry.
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PASIC asic;
+
+ UNICODE_STRING unicode_asics;
+ OBJECT_ATTRIBUTES asics_attributes;
+ WCHAR asics_buffer[256];
+
+ UNICODE_STRING unicode_asic;
+ OBJECT_ATTRIBUTES asic_attributes;
+ WCHAR asic_buffer[256];
+
+ UNICODE_STRING unicode_asic_id;
+
+ UNICODE_STRING unicode_name;
+ WCHAR name_buffer[256];
+
+ HANDLE asics_handle;
+ HANDLE asic_handle;
+
+ NTSTATUS status;
+ ULONG tmp;
+
+/* Asics */
+
+ unicode_asics.Length = 0;
+ unicode_asics.MaximumLength=256;
+ unicode_asics.Buffer = asics_buffer;
+ RtlZeroMemory(unicode_asics.Buffer,unicode_asics.MaximumLength);
+
+ RtlCopyUnicodeString(&unicode_asics,UnicodeModule);
+ status = RtlAppendUnicodeToString(&unicode_asics,L"\\Asics");
+
+ InitializeObjectAttributes( &asics_attributes, &unicode_asics,
+ OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ status = ZwCreateKey(&asics_handle, KEY_READ | KEY_WRITE, &asics_attributes, 0,
+ (PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
+
+
+ for (asic = Module->Asic; asic != NULL; asic = asic->Next) {
+
+/* Asic directory */
+
+ unicode_asic.Length = 0;
+ unicode_asic.MaximumLength=256;
+ unicode_asic.Buffer = asic_buffer;
+ RtlZeroMemory(unicode_asic.Buffer,unicode_asic.MaximumLength);
+
+ RtlCopyUnicodeString(&unicode_asic,&unicode_asics);
+ status = RtlAppendUnicodeToString(&unicode_asic,L"\\");
+
+ unicode_name.Length = 0;
+ unicode_name.MaximumLength=256;
+ unicode_name.Buffer = name_buffer;
+
+ NCRCatAsicName(Module->ModuleAddress, asic->AsicId, &unicode_name);
+
+ status = RtlAppendUnicodeStringToString(&unicode_asic,&unicode_name);
+
+ InitializeObjectAttributes( &asic_attributes, &unicode_asic,
+ OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ status = ZwCreateKey(&asic_handle, KEY_READ | KEY_WRITE, &asic_attributes, 0,
+ (PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
+
+
+
+// Asic ID
+
+ RtlInitUnicodeString(&unicode_asic_id,L"ID");
+ tmp = asic->AsicId;
+ status = ZwSetValueKey(asic_handle, &unicode_asic_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+
+// Asic JtagId
+
+ RtlInitUnicodeString(&unicode_asic_id,L"JtagID");
+ tmp = *((PULONG)(&(asic->JtagId[0])));
+ status = ZwSetValueKey(asic_handle, &unicode_asic_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+
+// Asic Type
+ RtlInitUnicodeString(&unicode_asic_id,L"Type");
+ tmp = asic->AsicType;
+ status = ZwSetValueKey(asic_handle, &unicode_asic_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+// Asic Location
+ RtlInitUnicodeString(&unicode_asic_id,L"Location");
+ tmp = asic->AsicLocation;
+ status = ZwSetValueKey(asic_handle, &unicode_asic_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+
+ RtlInitUnicodeString(&unicode_asic_id,L"InstructionRegisterLength");
+ tmp = asic->InstructionRegisterLength;
+ status = ZwSetValueKey(asic_handle, &unicode_asic_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+
+ RtlInitUnicodeString(&unicode_asic_id,L"BitLocation");
+ tmp = asic->BitLocation;
+ status = ZwSetValueKey(asic_handle, &unicode_asic_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+
+ RtlInitUnicodeString(&unicode_asic_id,L"SubaddressSpace");
+ tmp = asic->SubaddressSpace;
+ status = ZwSetValueKey(asic_handle, &unicode_asic_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+
+ status = ZwClose(asic_handle);
+ }
+
+ status = ZwClose(asics_handle);
+}
+
+
+
+
+VOID
+HalpCatReportModuleSubModules (
+ PUNICODE_STRING UnicodeModule,
+ PMODULE Module
+ )
+
+/*++
+
+Routine Description:
+ Place information about system modules into the registry.
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PMODULE module;
+
+ UNICODE_STRING unicode_submodules;
+ OBJECT_ATTRIBUTES submodules_attributes;
+ WCHAR submodules_buffer[256];
+
+ UNICODE_STRING unicode_module;
+ OBJECT_ATTRIBUTES module_attributes;
+ WCHAR module_buffer[256];
+
+ UNICODE_STRING unicode_module_id;
+
+ UNICODE_STRING unicode_name;
+ WCHAR name_buffer[256];
+
+ HANDLE submodules_handle;
+ HANDLE module_handle;
+
+ NTSTATUS status;
+ ULONG tmp;
+
+
+ unicode_submodules.Length = 0;
+ unicode_submodules.MaximumLength=256;
+ unicode_submodules.Buffer = submodules_buffer;
+ RtlZeroMemory(unicode_submodules.Buffer,unicode_submodules.MaximumLength);
+
+ RtlCopyUnicodeString(&unicode_submodules,UnicodeModule);
+ status = RtlAppendUnicodeToString(&unicode_submodules,L"\\SubModules");
+
+ InitializeObjectAttributes( &submodules_attributes, &unicode_submodules,
+ OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ status = ZwCreateKey(&submodules_handle, KEY_READ | KEY_WRITE, &submodules_attributes, 0,
+ (PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
+
+
+ for (module = Module->SubModules; module != NULL; module = module->Next) {
+
+/* Module directory */
+
+ unicode_module.Length = 0;
+ unicode_module.MaximumLength=256;
+ unicode_module.Buffer = module_buffer;
+ RtlZeroMemory(unicode_module.Buffer,unicode_module.MaximumLength);
+
+ RtlCopyUnicodeString(&unicode_module,&unicode_submodules);
+ status = RtlAppendUnicodeToString(&unicode_module,L"\\");
+
+ unicode_name.Length = 0;
+ unicode_name.MaximumLength=256;
+ unicode_name.Buffer = name_buffer;
+
+ NCRCatModuleName(module->ModuleAddress,&unicode_name);
+
+ status = RtlAppendUnicodeStringToString(&unicode_module,&unicode_name);
+
+ InitializeObjectAttributes( &module_attributes, &unicode_module,
+ OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ status = ZwCreateKey(&module_handle, KEY_READ | KEY_WRITE, &module_attributes, 0,
+ (PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
+
+/* Module ID */
+
+ RtlInitUnicodeString(&unicode_module_id,L"ID");
+ tmp = module->ModuleAddress;
+ status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+// EEProm size
+ RtlInitUnicodeString(&unicode_module_id,L"EEpromSize");
+ tmp = module->EEpromSize;
+ status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+// Number of Asics
+ RtlInitUnicodeString(&unicode_module_id,L"NumberOfAsics");
+ tmp = module->NumberOfAsics;
+ status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+// InstructionBits
+ RtlInitUnicodeString(&unicode_module_id,L"InstructionBits");
+ tmp = module->InstructionBits;
+ status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+// LargestRegister
+ RtlInitUnicodeString(&unicode_module_id,L"LargestRegister");
+ tmp = module->LargestRegister;
+ status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+// Smallest Register
+ RtlInitUnicodeString(&unicode_module_id,L"SmallestRegister");
+ tmp = module->SmallestRegister;
+ status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+
+ if (module->SubModules) {
+ HalpCatReportModuleSubModules(&unicode_module,module);
+ }
+
+ if (module->Asic) {
+ HalpCatReportModuleAsics(&unicode_module,module);
+ }
+
+ status = ZwClose(module_handle);
+ }
+ status = ZwClose(submodules_handle);
+}
+
+
+
+
+
+VOID
+HalpCatReportSystemModules (
+ )
+
+/*++
+
+Routine Description:
+ Place information about system modules into the registry.
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PMODULE module;
+ PASIC asic;
+
+ PWSTR catbus_path = L"\\Registry\\Machine\\Hardware\\DeviceMap\\CatBus";
+ PWSTR modules_path = L"\\Registry\\Machine\\Hardware\\DeviceMap\\CatBus\\Modules";
+
+
+ UNICODE_STRING unicode_catbus;
+ OBJECT_ATTRIBUTES catbus_attributes;
+ UNICODE_STRING unicode_catbus_id;
+
+ UNICODE_STRING unicode_modules;
+ OBJECT_ATTRIBUTES modules_attributes;
+
+ UNICODE_STRING unicode_module;
+ OBJECT_ATTRIBUTES module_attributes;
+ WCHAR module_buffer[256];
+
+ UNICODE_STRING unicode_module_id;
+
+ UNICODE_STRING unicode_name;
+ WCHAR name_buffer[256];
+
+ HANDLE catbus_handle;
+ HANDLE modules_handle;
+ HANDLE module_handle;
+
+ NTSTATUS status;
+ ULONG tmp;
+
+
+/*
+ * CatBus
+ */
+ RtlInitUnicodeString(&unicode_catbus,catbus_path);
+
+ InitializeObjectAttributes( &catbus_attributes, &unicode_catbus,
+ OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ status = ZwCreateKey(&catbus_handle, KEY_READ | KEY_WRITE, &catbus_attributes, 0,
+ (PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
+
+// NCR Hal Version Number
+ RtlInitUnicodeString(&unicode_catbus_id,L"HalVersion");
+ tmp = NCR_VERSION_NUMBER;
+ status = ZwSetValueKey(catbus_handle, &unicode_catbus_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+
+/*
+ * Modules
+ */
+ RtlInitUnicodeString(&unicode_modules,modules_path);
+
+ InitializeObjectAttributes( &modules_attributes, &unicode_modules,
+ OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ status = ZwCreateKey(&modules_handle, KEY_READ | KEY_WRITE, &modules_attributes, 0,
+ (PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
+
+
+ for (module = NCRCatModuleList; module != NULL; module = module->Next) {
+
+/* Module directory */
+
+ unicode_module.Length = 0;
+ unicode_module.MaximumLength=256;
+ unicode_module.Buffer = module_buffer;
+ RtlZeroMemory(unicode_module.Buffer,unicode_module.MaximumLength);
+
+ RtlCopyUnicodeString(&unicode_module,&unicode_modules);
+ status = RtlAppendUnicodeToString(&unicode_module,L"\\");
+
+ unicode_name.Length = 0;
+ unicode_name.MaximumLength=256;
+ unicode_name.Buffer = name_buffer;
+
+ NCRCatModuleName(module->ModuleAddress,&unicode_name);
+
+ status = RtlAppendUnicodeStringToString(&unicode_module,&unicode_name);
+
+ InitializeObjectAttributes( &module_attributes, &unicode_module,
+ OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ status = ZwCreateKey(&module_handle, KEY_READ | KEY_WRITE, &module_attributes, 0,
+ (PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
+
+/* Module ID */
+
+ RtlInitUnicodeString(&unicode_module_id,L"ID");
+ tmp = module->ModuleAddress;
+ status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+// EEProm size
+ RtlInitUnicodeString(&unicode_module_id,L"EEpromSize");
+ tmp = module->EEpromSize;
+ status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+// Number of Asics
+ RtlInitUnicodeString(&unicode_module_id,L"NumberOfAsics");
+ tmp = module->NumberOfAsics;
+ status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+// InstructionBits
+ RtlInitUnicodeString(&unicode_module_id,L"InstructionBits");
+ tmp = module->InstructionBits;
+ status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+// LargestRegister
+ RtlInitUnicodeString(&unicode_module_id,L"LargestRegister");
+ tmp = module->LargestRegister;
+ status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+// Smallest Register
+ RtlInitUnicodeString(&unicode_module_id,L"SmallestRegister");
+ tmp = module->SmallestRegister;
+ status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+
+ if (module->SubModules) {
+ //
+ // This is a Quad board
+ //
+ // Larc size
+ //
+ RtlInitUnicodeString(&unicode_module_id,L"LARCPages");
+ tmp = NCRLarcEnabledPages[module->ModuleAddress&0xf];
+ status = ZwSetValueKey(module_handle, &unicode_module_id, 0, REG_DWORD, &tmp, sizeof(ULONG));
+
+ HalpCatReportModuleSubModules(&unicode_module,module);
+ }
+
+ if (module->Asic) {
+ HalpCatReportModuleAsics(&unicode_module,module);
+ }
+
+ status = ZwClose(module_handle);
+ }
+ status = ZwClose(modules_handle);
+ status = ZwClose(catbus_handle);
+
+
+}
+
+
+
+VOID
+HalpCatPowerOffSystem (
+ )
+
+/*++
+
+Routine Description:
+ Sends command to PSI to shut off the power to the system.
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ CAT_CONTROL cat_control;
+ UCHAR data;
+
+
+ cat_control.Module = PSI;
+ cat_control.Asic = CAT_I;
+
+//
+// check position of Front panel switch to see if we need to enable it
+// if the switch is in the off position then enable it
+//
+
+ cat_control.Command = READ_SUBADDR;
+ cat_control.Address = PSI_General_Ps_Status_L5;
+ cat_control.NumberOfBytes = 1;
+
+ HalCatBusIo(&cat_control, &data);
+
+ if (!(data & PSI_PowerSwitch_On)) {
+ cat_control.Command = WRITE_SUBADDR;
+ cat_control.Address = PSI_General_Ps_Status_L5;
+ cat_control.NumberOfBytes = 1;
+
+ data = PSI_Enable_FrontSwitch;
+
+ HalCatBusIo(&cat_control, &data);
+ }
+
+ cat_control.Command = WRITE_SUBADDR;
+ cat_control.Address = PSI_General_Ps_Status_L5;
+ cat_control.NumberOfBytes = 1;
+
+ data = PSI_Set_AlarmEnable;
+
+ HalCatBusIo(&cat_control, &data);
+
+ //
+ // Power down the machine
+ //
+
+ data = PSI_SoftwarePowerDown1;
+
+ HalCatBusIo(&cat_control, &data);
+
+ return;
+}
+
+
+VOID
+HalPowerOffSystem (
+ BOOLEAN PowerOffSystem
+ )
+
+/*++
+
+Routine Description:
+ Set a flag so HalReturnToFirmware will poweroff instead of reboot.
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ NCRPowerOffSystem = PowerOffSystem;
+}
+
+
+
+
+
+
+
+
diff --git a/private/ntos/nthals/halncr/i386/ncrcat.h b/private/ntos/nthals/halncr/i386/ncrcat.h
new file mode 100644
index 000000000..73df6d7aa
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrcat.h
@@ -0,0 +1,308 @@
+/*++
+
+Copyright (C) 1992 NCR Corporation
+
+
+Module Name:
+
+ ncrcat.h
+
+Author:
+
+Abstract:
+
+ System equates for dealing with the NCR Cat Bus.
+
+++*/
+
+#ifndef _NCRCAT_
+#define _NCRCAT_
+
+/*
+ * Cat bus driver error codes
+ */
+
+#define CATNOERR 0
+#define CATIO 1 /* I/O error */
+#define CATFAULT 2 /* Bad address */
+#define CATACCESS 3 /* Permission denied */
+#define CATINVAL 4 /* Invalid argument */
+#define CATNOMOD 5 /* Module not found */
+#define CATNOASIC 6 /* Asic not found */
+
+
+/*
+ * CAT Bus Driver Commands
+ */
+
+
+#define READ_REGISTER 1 /* Read a register */
+#define WRITE_REGISTER 2 /* Write a register */
+#define READ_SUBADDR 3 /* Read from the subaddress area */
+#define WRITE_SUBADDR 4 /* Write to the subaddress area */
+
+
+/*
+ * Modules and ASICs for the Level 5
+ */
+
+#define PROCESSOR0 0x10 /* Processor Module 0 */
+#define PROCESSOR1 0x11 /* Processor Module 1 */
+#define PROCESSOR2 0x12 /* Processor Module 2 */
+#define PROCESSOR3 0x13 /* Processor Module 3 */
+#define NoModule0 0x1b /* No Module address */
+#define PROCESSOR4 0x1c /* Processor Module 4 */
+#define PROCESSOR5 0x1d /* Processor Module 5 */
+#define PROCESSOR6 0x1e /* Processor Module 6 */
+#define PROCESSOR7 0x1f /* Processor Module 7 */
+#define QUAD_BBID 1
+#define QUAD_LL2_AID 2
+#define QUAD_LL2_BID 3
+#define QUAD_BB0 (QUAD_BBID<<5|PROCESSOR0)
+#define QUAD_BB1 (QUAD_BBID<<5|PROCESSOR1)
+#define QUAD_BB2 (QUAD_BBID<<5|PROCESSOR2)
+#define QUAD_BB3 (QUAD_BBID<<5|PROCESSOR3)
+#define QUAD_BB4 (QUAD_BBID<<5|PROCESSOR4)
+#define QUAD_BB5 (QUAD_BBID<<5|PROCESSOR5)
+#define QUAD_BB6 (QUAD_BBID<<5|PROCESSOR6)
+#define QUAD_BB7 (QUAD_BBID<<5|PROCESSOR7)
+#define QUAD_LL2_A0 (QUAD_LL2_AID<<5|PROCESSOR0)
+#define QUAD_LL2_A1 (QUAD_LL2_AID<<5|PROCESSOR1)
+#define QUAD_LL2_A2 (QUAD_LL2_AID<<5|PROCESSOR2)
+#define QUAD_LL2_A3 (QUAD_LL2_AID<<5|PROCESSOR3)
+#define QUAD_LL2_A4 (QUAD_LL2_AID<<5|PROCESSOR4)
+#define QUAD_LL2_A5 (QUAD_LL2_AID<<5|PROCESSOR5)
+#define QUAD_LL2_A6 (QUAD_LL2_AID<<5|PROCESSOR6)
+#define QUAD_LL2_A7 (QUAD_LL2_AID<<5|PROCESSOR7)
+#define QUAD_LL2_B0 (QUAD_LL2_BID<<5|PROCESSOR0)
+#define QUAD_LL2_B1 (QUAD_LL2_BID<<5|PROCESSOR1)
+#define QUAD_LL2_B2 (QUAD_LL2_BID<<5|PROCESSOR2)
+#define QUAD_LL2_B3 (QUAD_LL2_BID<<5|PROCESSOR3)
+#define QUAD_LL2_B4 (QUAD_LL2_BID<<5|PROCESSOR4)
+#define QUAD_LL2_B5 (QUAD_LL2_BID<<5|PROCESSOR5)
+#define QUAD_LL2_B6 (QUAD_LL2_BID<<5|PROCESSOR6)
+#define QUAD_LL2_B7 (QUAD_LL2_BID<<5|PROCESSOR7)
+#define CATbaseModule(id) ((id)&0x1f)
+#define CATsubModule(id) ((id)>>5)
+
+#define MEMORY0 0x14 /* Memory Module 0 */
+#define MEMORY1 0x15 /* Memory Module 1 */
+#define PRIMARYMC 0x18 /* Primary Micro Channel */
+#define SECONDARYMC 0x19 /* Secondary Micro Channel */
+#define PSI 0x1A /* Power Supply Interface Module */
+#define CAT_LPB_MODULE 0x00 /* Local Peripheral Board - non CAT */
+
+#define CAT_I 0x00 /* Configure and Test Interface ASIC; Always */
+ /* ASIC 0 on every module */
+
+#define NUM_PROCESSOR_CARDS 4
+#define NUM_MEMORY_CARDS 2
+#define NUM_MC_SLOTS 8
+#define NUM_MC_BUSES 2
+
+
+
+/*
+ * CAT_I is the only ASIC on the Processor Module
+ */
+
+/*
+ * ASIC IDs for the Memory Module
+ */
+
+#define MMC1 1 /* Magellan Memory Controller 1 ASIC */
+#define MMA1 2 /* Magellan Memory Address 1 ASIC */
+#define MMD1_0 3 /* Magellan Memeory Data 1 Slice 0 */
+#define MMD1_1 4 /* Magellan Memeory Data 1 Slice 1 */
+#define MMD1_2 5 /* Magellan Memeory Data 1 Slice 2 */
+#define MMD1_3 6 /* Magellan Memeory Data 1 Slice 3 */
+
+/*
+ * ASIC IDs for the Primary Micro Channel
+ */
+
+#define PMC_MCADDR 1 /* Micro Channel Address/Controller */
+#define PMC_DMA 2 /* DMA Controller */
+#define PMC_DS1 3 /* Memory Controller Data Slice 1 */
+#define PMC_DS0 4 /* Memory Controller Data Slice 0 */
+#define PMC_VIC 5 /* Voyager Interrupt Controller ASIC */
+#define PMC_ARB 6 /* Dual System Bus Arbiter ASIC */
+#define PMC_DS2 7 /* Memory Controller Data Slice 2 */
+#define PMC_DS3 8 /* Memory Controller Data Slice 3 */
+
+/*
+ * ASIC IDs for the Secondary Micro Channel
+ */
+
+/*
+ * SMC ASIC ID's listed in scan path order
+ */
+
+#define SMC_MCADDR 1 /* Micro Channel Address/Controller */
+#define SMC_DS1 3 /* Memory Controller Data Slice 1 */
+#define SMC_DS0 4 /* Memory Controller Data Slice 0 */
+#define SMC_DMA 2 /* DMA Controller */
+#define SMC_DS2 7 /* Memory Controller Data Slice 2 */
+#define SMC_DS3 8 /* Memory Controller Data Slice 3 */
+
+
+
+
+/*
+ * common CATI registers
+ */
+
+typedef struct _CAT_REGISTERS {
+ UCHAR Config0; /* CAT id */
+ UCHAR Config1; /* CAT device info */
+ UCHAR Control2; /* CAT control bits */
+ UCHAR Config3; /* subaddress read/write */
+ UCHAR Config4; /* user defined configuration */
+ UCHAR Config5; /* user defined configuration */
+ UCHAR SubAddress6; /* low byte */
+ UCHAR SubAddress7; /* high byte */
+ UCHAR Config8; /* user defined configuration */
+ UCHAR Config9; /* user defined configuration */
+ UCHAR ConfigA; /* user defined configuration */
+ UCHAR ConfigB; /* user defined configuration */
+ UCHAR ConfigC; /* user defined configuration */
+ UCHAR ConfigD; /* user defined configuration */
+ UCHAR ConfigE; /* user defined configuration */
+ UCHAR StatusF; /* CAT status bits */
+} CAT_REGISTERS, *PCAT_REGISTERS;
+
+
+/*
+ * Processor Asic
+ */
+
+#define PBC_Status 0x0F
+
+/* ASIC ID's for the Processor Module */
+#define A_PBC 1
+#define B_PBC 2
+
+/* ASIC ID's for the Quad Baseboard (QBB) */
+#define QDATA1 1
+#define QDATA0 2
+#define QABC 3
+
+/* ASIC ID's for the Large Level 2 Cache Submodule (LL2) */
+#define QCC0 4
+#define QCC1 5
+#define QCD0 6
+#define QCD1 7
+
+/*
+ * Micro Channel I/F Address/Contrlo (MCADDR) ASICs
+ */
+
+#define MCADDR 0xC0
+
+/*
+ * Micro Channel Interface Data Slice (MCDATA) ASICs; One for each System Bus
+ */
+
+#define MCDATA_A 0xC4 /* MCDATA for bus A */
+#define MCDATA_B 0xC5 /* MCDATA for bus B */
+
+/*
+ * System Bus Arbiter (SBA) ASIC
+ */
+
+#define SBA 0xC1
+
+/*
+ * Voyager Interrupt Controller (VIC) ASIC
+ */
+
+#define VIC 0xC8
+
+/*
+ * DMA Controller (DMA) ASIC
+ */
+
+#define DMA 0xC9
+
+/*
+ * COUGAR ASIC
+ */
+
+#define COUGAR 0xE0
+
+/*
+ * LPB EEPROM Address
+ */
+
+#define LPB_EEPROM_ADDRESS 0xFFF5E000 /* LPB EEPROM */
+
+
+
+
+typedef struct _CAT_CONTROL {
+ UCHAR Module; // Module ID
+ UCHAR Asic; // ASIC ID
+ UCHAR Command; // CAT bus driver command
+ USHORT Address; // Register or Sub address
+ USHORT NumberOfBytes; // Number of bytes to read/write
+} CAT_CONTROL, *PCAT_CONTROL;
+
+
+
+//
+// Micro Channel slot information
+//
+
+#define NUM_POS_REGISTERS 8
+#define POS_Setup 0x96
+#define POS_Slot0 0x78 /* select slot 0 */
+
+//
+// POS Space Definitions
+//
+
+#define POS_0 0x100
+#define POS_1 0x101
+#define POS_2 0x102
+#define POS_3 0x103
+#define POS_4 0x104
+#define POS_5 0x105
+#define POS_6 0x106
+#define POS_7 0x107
+
+
+/*
+ * Cat bus driver function prototypes.
+ */
+
+BOOLEAN
+HalCatBusAvailable (
+ );
+
+LONG
+HalCatBusIo (
+ IN PCAT_CONTROL CatControl,
+ IN OUT PUCHAR Buffer
+ );
+
+
+VOID
+HalCatBusReset (
+ );
+
+
+
+LONG
+HalpCatBusIo (
+ IN PCAT_CONTROL CatControl,
+ IN OUT PUCHAR Buffer
+ );
+
+
+VOID
+HalPowerOffSystem (
+ IN BOOLEAN PowerOffSystem
+ );
+
+
+#endif // _NCRCAT_
diff --git a/private/ntos/nthals/halncr/i386/ncrcatlk.asm b/private/ntos/nthals/halncr/i386/ncrcatlk.asm
new file mode 100644
index 000000000..b720a4142
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrcatlk.asm
@@ -0,0 +1,120 @@
+ title "CAT Bus Lock Routines"
+;++
+;
+; Module Name:
+;
+; ncrcatlk.asm
+;
+; Abstract:
+;
+; Procedures necessary to lock CAT bus.
+;
+; Author:
+;
+; Rick Ulmer (rick.ulmer@columbiasc.ncr.com) 29 Apr 1993
+;
+; Revision History:
+;
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include mac386.inc
+ .list
+
+ extrn _HalpCatBusLock:DWORD
+
+_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
+;
+; Hold the value of the eflags register before a CAT bus spinlock is
+; acquired (used in HalpAcquire/ReleaseCatBusSpinLock().
+;
+_HalpCatBusFlags dd 0
+
+_DATA ends
+
+ subttl "HalpAcquireCatBusSpinLock"
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; Routine Description:
+;
+; Acquires a spinlock to access the CAT bus. The CAT bus is
+; accessed at different irql levels, so to be safe, we 'cli'.
+; We could replace that to raise irql to PROFILE_LEVEL, but that's
+; a lot of code.
+;
+; Arguments:
+;
+; None
+;
+; Return Value:
+;
+; Interrupt is disabled.
+; Irql level not affected.
+; Flags saved in _HalpCatBusLockFlags.
+;--
+
+cPublicProc _HalpAcquireCatBusSpinLock ,0
+ push eax
+
+ align 4
+HArsl01:
+ pushfd
+ cli
+ lea eax, _HalpCatBusLock
+ ACQUIRE_SPINLOCK eax, HArsl90
+ pop _HalpCatBusFlags ; save flags for release S.L.
+ pop eax
+ stdRET _HalpAcquireCatBusSpinLock
+
+ align 4
+HArsl90:
+ popfd
+ SPIN_ON_SPINLOCK eax, <HArsl01>
+
+stdENDP _HalpAcquireCatBusSpinLock
+
+
+ subttl "HalpReleaseCatBusSpinLock"
+;++
+;
+; Routine Description:
+;
+; Release spinlock, and restore flags to the state it was before
+; acquiring the spinlock.
+;
+; Arguments:
+;
+; None
+;
+; Return Value:
+;
+; Interrupts restored to their state before acquiring spinlock.
+; Irql level not affected.
+;
+;--
+
+cPublicProc _HalpReleaseCatBusSpinLock ,0
+ push eax
+ ;
+ ; restore eflags as it was before acquiring spinlock. Put it on
+ ; stack before releasing spinlock (so other cpus cannot overwrite
+ ; it with their own eflags).
+ ;
+ push _HalpCatBusFlags ; old eflags on stack.
+ lea eax, _HalpCatBusLock
+ RELEASE_SPINLOCK eax
+ popfd ; restore eflags.
+ pop eax
+ stdRET _HalpReleaseCatBusSpinLock
+stdENDP _HalpReleaseCatBusSpinLock
+
+_TEXT ends
+
+ end
diff --git a/private/ntos/nthals/halncr/i386/ncrcatp.h b/private/ntos/nthals/halncr/i386/ncrcatp.h
new file mode 100644
index 000000000..44f2caffa
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrcatp.h
@@ -0,0 +1,232 @@
+/*++
+
+Copyright (C) 1992 NCR Corporation
+
+
+Module Name:
+
+ ncrcat.h
+
+Author:
+
+Abstract:
+
+ System equates for dealing with the NCR Cat Bus.
+
+++*/
+
+#ifndef _NCRCATP_
+#define _NCRCATP_
+
+/*
+ * Ports
+ */
+
+#define MAX_REG_SIZE 0x04 /* Maximum instruction register size */
+#define MAX_SCAN_PATH 0x100 /* Maximum size of a scan path */
+
+#define SUBADDR_ZERO 0x00 /* No sub address space */
+#define SUBADDR_LO 0xff /* 256 byte sub address space */
+#define SUBADDR_HI 0xffff /* 64K sub address space */
+#define MAXSUBADDR 0xffff /* Maximum sub address space */
+#define PSI_EEPROM_SIZE 0x8000 /* Size of the PSI EEPROM */
+#define EEPROM_SIZE 0x2000 /* Default size of the EEPROM */
+#define MAXNUMREG 0x10 /* Maximum number of registers in an ASIC */
+
+/* Ports */
+#define SELECT_PORT 0x97 /* port value to select module */
+#define BASE_PORT 0x98 /* contains base address */
+#define DATA_OFFSET 0x0D /* base addr + DATA_OFFSET => data port */
+#define COMMAND_OFFSET 0x0E /* base addr + COMMAND_OFFSET => command port */
+
+#define RESET 0x00 /* Reset the CAT bus w/o updating */
+#define DESELECT 0xFF /* Deselect the CAT bus */
+
+/* Valid CAT controller commands */
+#define IRCYC 0x01 /* start instruction register cycle */
+#define DRCYC 0x02 /* start data register cycle */
+#define RUN 0x0F /* move to execute state */
+#define END 0x80 /* end operation */
+#define HOLD 0x90 /* hold in idle state */
+#define STEP 0xE0 /* single step an "intest" vector */
+#define CLEMSON 0xFF /* return cat controller to CLEMSON mode */
+
+/* Supported ASIC Commands */
+#define READ_CONFIG 0x01 /* read config register */
+#define WRITE_CONFIG 0x02 /* write config register */
+#define BYPASS 0xFF /* place asic in bypass mode */
+
+/* Defines for CAT_I control */
+#define AUTO_INC 0x04 /* OR w/ reg 2 for auto increment */
+#define NO_AUTO_INC 0xFB /* AND w/ reg 2 for no auto increment */
+#define CONNECT_ASICS 0x01 /* OR w/ reg 5 value to connect scan path */
+#define DISCONNECT_ASIC 0xFE /* AND w/ reg 5 value to disconnect scan path */
+#define RESET_STATE 0x00 /* Used to blindly disconnect the scan path */
+
+/* Defines for special registers */
+#define ASIC_ID_REG 0x00 /* Reg which contains the ASIC ID; Level 4 */
+#define ASIC_TYPE_REG 0x01 /* Reg which contains ASIC type; Level 4*/
+#define AUTO_INC_REG 0x02 /* Reg which contains auto increment bit */
+#define SUBADDRDATA 0x03 /* Reg w/ data for subaddr read/write */
+#define SCANPATH 0x05 /* Reg which contains scan path bit; Level 5 */
+#define SUBADDRLO 0x06 /* Reg w/ low byte for subaddr read/write */
+#define SUBADDRHI 0x07 /* Reg w/ high byte for subaddr read/write */
+#define SUBMODSELECT 0x08 /* Reg which contains submodule select bits */
+#define SUBMODPRESENT 0x09 /* Reg which contains submodule present bits */
+
+#define MAXSUBMOD 0x3 /* max # of submodules, BB counts as one */
+#define BASE_BOARD_SHIFT 0x1 /* shift required to or in presence of BB */
+#define BASE_BOARD_PRESENT 0x1 /* signifies presence of BB */
+
+#define HEADER 0x7F /* Header to check hw is setup correctly */
+#define DEFAULT_INST 0x01 /* The default CAT_I instruction is xxxxxx01 */
+#define CHAR_SIZE 0x08 /* Number of bits in a "char" */
+#define EEPROMPAGESIZE 0x40 /* Number of bytes in a EEPROM page */
+#define MAXREADS 0x10 /* Max EEPROM reads to varify write */
+#define WRITEDELAY 0x250 /* Number of tenmicrosec delays for write to */
+
+
+
+typedef struct _ASIC {
+ UCHAR AsicType; // ASIC type
+ UCHAR AsicId; // ASIC ID
+ UCHAR JtagId[4]; // JTAG ID
+ UCHAR AsicLocation; // Location within scan path, start with 0
+ USHORT BitLocation; // Location with bit stream, start with 0
+ UCHAR InstructionRegisterLength; // Instruction register length
+ USHORT SubaddressSpace; // Amount of sub address space
+ struct _ASIC *Next; // Next ASIC in linked list
+} ASIC, *PASIC;
+
+
+
+
+
+typedef struct _MODULE {
+ UCHAR ModuleAddress; // Module address
+ USHORT EEpromSize; // Size of the EEPROM
+ USHORT NumberOfAsics; // Number of ASICs
+ USHORT InstructionBits; // Instruction bits in the scan path
+ USHORT LargestRegister; // Largest register in the scan path
+ USHORT SmallestRegister; // Smallest register in the scan path
+ USHORT ScanPathConnected; // Scan path connected
+ PASIC Asic; // First ASIC in scan path, always a CAT_I
+ struct _MODULE *SubModules; // Submodule pointer
+ struct _MODULE *Next; // Next module in linked list
+} MODULE, *PMODULE;
+
+
+
+
+/*
+ * eeprom data structure
+ */
+
+/*
+ * Module Header
+ */
+
+#pragma pack(1)
+typedef struct _MODULE_HEADER {
+ UCHAR ModuleId[4]; // maybe unionize
+ UCHAR VersionId; // version id
+ UCHAR ConfigId; // configuration id
+ USHORT BoundryId; // boundary scan id
+ USHORT EEpromSize; // size of EEPROM
+ UCHAR Assembly[11]; // assembly #
+ UCHAR AssemblyRevision; // assembly revision
+ UCHAR Tracer[4]; // tracer number
+ USHORT AssemblyCheckSum; // assembly check sum
+ USHORT PowerConsumption; // power requirements
+ USHORT NumberOfAsics; // number of asics
+ USHORT MinBistTime; // min. bist time
+ USHORT ErrorLogOffset; // error log offset
+ USHORT ScanPathOffset; // scan path table offset
+ USHORT CctOffset; // cct offset
+ USHORT LogLength; // length of error log
+ USHORT CheckSumEnd; // offset to end of cksum
+ UCHAR Reserved[4]; // reserved
+ UCHAR StartingSentinal; // starting sentinal
+ UCHAR PartNumber[13]; // prom part number
+ UCHAR Version[10]; // version number
+ UCHAR Signature[8]; // signature
+ USHORT EEpromCheckSum; // eeprom checksum
+ ULONG DataStampOffset; // date stamp offset
+ UCHAR EndingSentinal; // ending sentinal
+} MODULE_HEADER, *PMODULE_HEADER;
+
+#pragma pack()
+
+#define EEPROM_DATA_START 0x00
+#define EEPROM_SIZE_OFFSET 0x08
+#define XSUM_END_OFFSET 0x2A
+
+
+/*
+ * Scan Path Table
+ */
+
+
+#pragma pack(1)
+typedef struct _SCAN_PATH_TABLE {
+ UCHAR AsicId; // ASIC ID
+ UCHAR BypassFlag; // Bypass Flag
+ USHORT AsicDataOffset; // ASIC data table
+ USHORT ConfigDataOffset; // config tbl ptr
+} SCAN_PATH_TABLE, *PSCAN_PATH_TABLE;
+
+#pragma pack()
+
+/*
+ * JTAG Table
+ */
+
+#pragma pack(1)
+typedef struct _JTAG_TABLE {
+ UCHAR IdCode[4]; // IDCODE
+ UCHAR RunBist[4]; // RUNBIST
+ UCHAR InTest[4]; // INTEST
+ UCHAR SamplePreload[4]; // SAMPLE/PRELOAD
+ UCHAR InstructionRegisterLength; // IR length
+} JTAG_TABLE, *PJTAG_TABLE;
+#pragma pack()
+
+/*
+ * Asic Information Table
+ */
+
+#pragma pack(1)
+typedef struct _ASIC_DATA_TABLE {
+ UCHAR JtagId[4]; // JTAG ID
+ USHORT LengthBsr; // BSR length
+ USHORT LengthBistRegister; // BIST register length
+ ULONG BistClockLength; // BIST clock length
+ USHORT SubaddressBits; // # bits in subaddress
+ USHORT SeedBits; // BIST seed length
+ USHORT SignatureBits; // BIST signature length
+ USHORT JtagOffset; // JTAG tbl ptr
+} ASIC_DATA_TABLE, *PASIC_DATA_TABLE;
+#pragma pack()
+
+#pragma pack(1)
+typedef struct _MODULE_ID {
+ UCHAR ModuleName[5]; // MODULE IDENTIFIER
+} MODULE_ID, *PMODULE_ID;
+#pragma pack()
+
+
+VOID
+HalpInitializeCatBusDriver (
+ );
+
+VOID
+HalpCatReportSystemModules (
+ );
+
+
+VOID
+HalpCatPowerOffSystem (
+ );
+
+
+#endif // _NCRCATP
diff --git a/private/ntos/nthals/halncr/i386/ncrclock.asm b/private/ntos/nthals/halncr/i386/ncrclock.asm
new file mode 100644
index 000000000..da69aee8a
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrclock.asm
@@ -0,0 +1,724 @@
+ title "Interval Clock Interrupt"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; ncrclock.asm
+;
+; Abstract:
+;
+; This module implements the code necessary to field and process the
+; interval clock interrupt.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 12-Jan-1990
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+; bryanwi 20-Sep-90
+;
+; Add KiSetProfileInterval, KiStartProfileInterrupt,
+; KiStopProfileInterrupt procedures.
+; KiProfileInterrupt ISR.
+; KiProfileList, KiProfileLock are delcared here.
+;
+; shielint 10-Dec-90
+; Add performance counter support.
+; Move system clock to irq8, ie we now use RTC to generate system
+; clock. Performance count and Profile use timer 1 counter 0.
+; The interval of the irq0 interrupt can be changed by
+; KiSetProfileInterval. Performance counter does not care about the
+; interval of the interrupt as long as it knows the rollover count.
+; Note: Currently I implemented 1 performance counter for the whole
+; i386 NT. It works on UP and SystemPro.
+;
+; John Vert (jvert) 11-Jul-1991
+; Moved from ke\i386 to hal\i386. Removed non-HAL stuff
+;
+; shie-lin tzong (shielint) 13-March-92
+; Move System clock back to irq0 and use RTC (irq8) to generate
+; profile interrupt. Performance counter and system clock use time1
+; counter 0 of 8254.
+;
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\ix8259.inc
+include i386\ixcmos.inc
+include i386\kimacro.inc
+include mac386.inc
+include i386\ncr.inc
+ .list
+
+ EXTRNP _DbgBreakPoint,0,IMPORT
+ extrn KiI8259MaskTable:DWORD
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _KeUpdateSystemTime,0
+ EXTRNP _KeUpdateRunTime,1,IMPORT
+ EXTRNP _HalEndSystemInterrupt,2
+ EXTRNP _HalBeginSystemInterrupt,3
+ EXTRNP _HalpAcquireCmosSpinLock ,0
+ EXTRNP _HalpReleaseCmosSpinLock ,0
+ EXTRNP _KeSetTimeIncrement,2,IMPORT
+ EXTRNP _HalQicRequestIpi,2
+ extrn _NCRActiveProcessorLogicalMask:DWORD
+ extrn _NCRLogicalNumberToPhysicalMask:DWORD
+ extrn _HalpSystemHardwareLock:DWORD
+ extrn _NCRLogicalDyadicProcessorMask:DWORD
+ extrn _NCRLogicalQuadProcessorMask:DWORD
+
+;
+; Constants used to initialize timer 0
+;
+
+TIMER1_DATA_PORT0 EQU 40H ; Timer1, channel 0 data port
+TIMER1_CONTROL_PORT0 EQU 43H ; Timer1, channel 0 control port
+TIMER1_IRQ EQU 0 ; Irq 0 for timer1 interrupt
+
+COMMAND_8254_COUNTER0 EQU 00H ; Select count 0
+COMMAND_8254_RW_16BIT EQU 30H ; Read/Write LSB firt then MSB
+COMMAND_8254_MODE2 EQU 4 ; Use mode 2
+COMMAND_8254_BCD EQU 0 ; Binary count down
+COMMAND_8254_LATCH_READ EQU 0 ; Latch read command
+
+PERFORMANCE_FREQUENCY EQU 1193000
+
+;
+; ==== Values used for System Clock ====
+;
+
+;
+; Convert the interval to rollover count for 8254 Timer1 device.
+; Timer1 counts down a 16 bit value at a rate of 1.193181667M counts-per-sec.
+;
+;
+; The best fit value closest to 10ms (but not below) is 10.0144012689ms:
+; ROLLOVER_COUNT 11949
+; TIME_INCREMENT 100144
+; Calculated error is -.0109472 s/day
+;
+; The best fit value closest to 15ms (but not above) is 14.9952019ms:
+; ROLLOVER_COUNT 17892
+; TIME_INCREMENT 149952
+; Calculated error is -.0109472 s/day
+;
+; On 486 class machines or better we use a 10ms tick, on 386
+; class machines we use a 15ms tick
+;
+
+ROLLOVER_COUNT EQU 11949
+TIME_INCREMENT EQU 100144
+
+_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
+
+ public _HalpIpiClock
+_HalpIpiClock dd 0 ; Processors to IPI clock pulse to
+
+;
+; 8254 spinlock. This must be acquired before touching the 8254 chip.
+;
+ public _Halp8254Lock
+
+_Halp8254Lock dd 0
+
+ public HalpPerfCounterLow
+ public HalpPerfCounterHigh
+HalpPerfCounterLow dd 0
+HalpPerfCounterHigh dd 0
+HalpPerfCounterInit dd 0
+
+_DATA ends
+
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "Initialize Clock"
+;++
+;
+; VOID
+; HalpInitializeClock (
+; )
+;
+; Routine Description:
+;
+; This routine initialize system time clock using 8254 timer1 counter 0
+; to generate an interrupt at every 15ms interval at 8259 irq0
+;
+; See the definition of TIME_INCREMENT and ROLLOVER_COUNT if clock rate
+; needs to be changed.
+;
+; Arguments:
+;
+; None
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicProc _HalpInitializeClock ,0
+
+ pushfd ; save caller's eflag
+ cli ; make sure interrupts are disabled
+
+;
+; Set clock rate
+;
+
+ mov al,COMMAND_8254_COUNTER0+COMMAND_8254_RW_16BIT+COMMAND_8254_MODE2
+ out TIMER1_CONTROL_PORT0, al ;program count mode of timer 0
+ IoDelay
+ mov ecx, ROLLOVER_COUNT
+ mov al, cl
+ out TIMER1_DATA_PORT0, al ; program timer 0 LSB count
+ IoDelay
+ mov al,ch
+ out TIMER1_DATA_PORT0, al ; program timer 0 MSB count
+
+ popfd ; restore caller's eflag
+
+;
+; Fill in PCR value with TIME_INCREMENT
+;
+ mov edx, TIME_INCREMENT
+ stdCall _KeSetTimeIncrement, <edx, edx>
+
+ mov HalpPerfCounterInit, 1 ; Indicate performance counter
+ ; has been initialized.
+ stdRET _HalpInitializeClock
+
+stdENDP _HalpInitializeClock
+
+ page ,132
+ subttl "Query Performance Counter"
+;++
+;
+; LARGE_INTEGER
+; KeQueryPerformanceCounter (
+; OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL
+; )
+;
+; Routine Description:
+;
+; This routine returns current 64-bit performance counter and,
+; optionally, the Performance Frequency.
+;
+; Note this routine can NOT be called at Profiling interrupt
+; service routine. Because this routine depends on IRR0 to determine
+; the actual count.
+;
+; Also note that the performace counter returned by this routine
+; is not necessary the value when this routine is just entered.
+; The value returned is actually the counter value at any point
+; between the routine is entered and is exited.
+;
+; Arguments:
+;
+; PerformanceFrequency [TOS+4] - optionally, supplies the address
+; of a variable to receive the performance counter frequency.
+;
+; Return Value:
+;
+; Current value of the performance counter will be returned.
+;
+;--
+
+;
+; Parameter definitions
+;
+
+KqpcFrequency EQU [esp+12] ; User supplied Performance Frequence
+
+cPublicProc _KeQueryPerformanceCounter ,1
+
+ push ebx
+ push esi
+
+;
+; First check to see if the performance counter has been initialized yet.
+; Since the kernel debugger calls KeQueryPerformanceCounter to support the
+; !timer command, we need to return something reasonable before 8254
+; initialization has occured. Reading garbage off the 8254 is not reasonable.
+;
+ cmp HalpPerfCounterInit, 0
+ jne Kqpc01 ; ok, perf counter has been initialized
+
+;
+; Initialization hasn't occured yet, so just return zeroes.
+;
+ mov eax, 0
+ mov edx, 0
+ jmp Kqpc20
+
+Kqpc01:
+Kqpc11: pushfd
+ cli
+ lea eax, _Halp8254Lock
+ ACQUIRE_SPINLOCK eax, Kqpc198
+
+;
+; Fetch the base value. Note that interrupts are off.
+;
+; NOTE:
+; Need to watch for Px reading the 'CounterLow', P0 updates both
+; then Px finishes reading 'CounterHigh' [getting the wrong value].
+; After reading both, make sure that 'CounterLow' didn't change.
+; If it did, read it again. This way, we won't have to use a spinlock.
+;
+
+@@:
+ mov ebx, HalpPerfCounterLow
+ mov esi, HalpPerfCounterHigh ; [esi:ebx] = Performance counter
+
+ cmp ebx, HalpPerfCounterLow ;
+ jne @b
+;
+; Fetch the current counter value from the hardware
+;
+
+ mov al, COMMAND_8254_LATCH_READ+COMMAND_8254_COUNTER0
+ ;Latch PIT Ctr 0 command.
+ out TIMER1_CONTROL_PORT0, al
+ IODelay
+ in al, TIMER1_DATA_PORT0 ;Read PIT Ctr 0, LSByte.
+ IODelay
+ movzx ecx,al ;Zero upper bytes of (ECX).
+ in al, TIMER1_DATA_PORT0 ;Read PIT Ctr 0, MSByte.
+ mov ch, al ;(CX) = PIT Ctr 0 count.
+
+ lea eax, _Halp8254Lock
+ RELEASE_SPINLOCK eax
+
+;
+; Now enable interrupts such that if timer interrupt is pending, it can
+; be serviced and update the PerformanceCounter. Note that there could
+; be a long time between the sti and cli because ANY interrupt could come
+; in in between.
+;
+
+ popfd ; don't re-enable interrupts if
+ nop ; the caller had them off!
+ jmp $+2
+
+
+;
+; Fetch the base value again.
+;
+
+@@:
+ mov eax, HalpPerfCounterLow
+ mov edx, HalpPerfCounterHigh ; [edx:eax] = new counter value
+
+ cmp eax, HalpPerfCounterLow
+ jne @b
+
+;
+; Compare the two reads of Performance counter. If they are different,
+; simply returns the new Performance counter. Otherwise, we add the hardware
+; count to the performance counter to form the final result.
+;
+
+ cmp eax, ebx
+ jne short Kqpc20
+ cmp edx, esi
+ jne short Kqpc20
+ neg ecx ; PIT counts down from 0h
+ add ecx, ROLLOVER_COUNT
+ add eax, ecx
+ adc edx, 0 ; [edx:eax] = Final result
+
+;
+; Return the counter
+;
+
+Kqpc20:
+ ; return value is in edx:eax
+
+;
+; Return the freq. if caller wants it.
+;
+
+ or dword ptr KqpcFrequency, 0 ; is it a NULL variable?
+ jz short Kqpc99 ; if z, yes, go exit
+
+ mov ecx, KqpcFrequency ; (ecx)-> Frequency variable
+ mov DWORD PTR [ecx], PERFORMANCE_FREQUENCY ; Set frequency
+ mov DWORD PTR [ecx+4], 0
+
+Kqpc99:
+ pop esi ; restore esi and ebx
+ pop ebx
+ stdRET _KeQueryPerformanceCounter
+
+Kqpc198: popfd
+ SPIN_ON_SPINLOCK eax,<Kqpc11>
+
+stdENDP _KeQueryPerformanceCounter
+
+;++
+;
+; 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.
+;--
+cPublicProc _HalCalibratePerformanceCounter,1
+ mov eax, [esp+4] ; ponter to Number
+ pushfd ; save previous interrupt state
+ cli ; disable interrupts (go to high_level)
+
+ lock dec dword ptr [eax] ; count down
+
+@@: cmp dword ptr [eax], 0 ; wait for all processors to signal
+ jnz short @b
+
+ ;
+ ; Nothing to calibrate on a NCR MP machine...
+ ;
+
+ popfd ; restore interrupt flag
+ stdRET _HalCalibratePerformanceCounter
+
+stdENDP _HalCalibratePerformanceCounter
+
+
+
+
+ page ,132
+ subttl "System Clock Interrupt"
+;++
+;
+; Routine Description:
+;
+;
+; This routine is entered as the result of an interrupt generated by CLOCK2.
+; Its function is to dismiss the interrupt, raise system Irql to
+; CLOCK2_LEVEL, update performance counter and transfer control to the
+; standard system routine to update the system time and the execution
+; time of the current thread
+; and process.
+;
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+; Does not return, jumps directly to KeUpdateSystemTime, which returns
+;
+; Sets Irql = CLOCK2_LEVEL and dismisses the interrupt
+;
+;--
+ ENTER_DR_ASSIST Hci_a, Hci_t
+
+cPublicProc _HalpClockInterrupt ,0
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT Hci_a, Hci_t
+
+;
+; (esp) - base of trap frame
+;
+
+;
+; dismiss interrupt and raise Irql
+;
+
+ cmp byte ptr PCR[PcIrql], CLOCK2_LEVEL
+ jae SpuriousClock
+
+ push NCR_CPI_VECTOR_BASE ; SEE NOTE BELOW!
+ sub esp, 4 ; allocate space to save OldIrql
+ stdCall _HalBeginSystemInterrupt, <CLOCK2_LEVEL,CLOCK_VECTOR,esp>
+ or al,al ; check for spurious interrupt
+ jz SpuriousClock2
+
+; turn off the interrupt via system control port b - since HalMakeBeep also
+; accesses system control port b (speaker control) and uses the 8254 spin lock,
+; we will too
+
+Hci11: pushfd
+ cli
+ lea eax, _Halp8254Lock
+ ACQUIRE_SPINLOCK eax,Hci99
+
+ in al, 61h
+ jmp $+2
+ or al, 80h
+ out 61h, al
+ jmp $+2
+
+ align dword
+@@:
+ lea ebx, _Halp8254Lock
+ RELEASE_SPINLOCK ebx
+ popfd
+
+;
+; Both IPI's and Clock interrupts are processed at the same priority
+; level by the hardware. NT needs IPI priorities to be higher then
+; the Clock interrupt (irq 0) - we handle this by EOI-ing the clock
+; interrupt before calling the kernel so IPI interrupts can still
+; arrive. If another clock interrupt comes in, it will be ignored.
+;
+; The kernel will also call HalEndSystemInterrupt to dismiss the clock
+; interrupt. The vector passed to the kernel is one which will not cause
+; the hardware to be EOIed
+;
+
+; end of interrupt & restore irql
+ ; (oldirq) Don't lower
+ ; Vector to EOI
+
+ stdCall _HalEndSystemInterrupt, <CLOCK2_LEVEL,CLOCK_VECTOR>
+
+
+;
+; Update performance counter
+;
+ProcessClock:
+;
+; (esp) = OldIrql
+; (esp+4) = Bogus Vector
+; (esp+8) = base of trap frame
+; (ebp) = pointer to trap frame
+;
+
+ add HalpPerfCounterLow, ROLLOVER_COUNT ; update performace counter
+ adc HalpPerfCounterHigh, dword ptr 0
+
+ ;
+ ; Broadcast clock CPI to all other processors on the system
+ ;
+
+ mov eax, PCR[PcHal].PcrMyLogicalMask
+ not eax
+ and eax, _NCRActiveProcessorLogicalMask
+ jz SkipQuad
+ mov _HalpIpiClock, eax ; Indicate which processors are getting clock interrupt
+
+ push eax
+ and eax,_NCRLogicalDyadicProcessorMask ; see which processors are dyadics
+ jz short SkipDyadic
+
+ TRANSLATE_LOGICAL_TO_VIC
+ VIC_WRITE CpiLevel2Reg, al ; Broadcast interrupt to all other active CPUs
+
+SkipDyadic:
+ pop eax ; restore Active processor mask
+ and eax,_NCRLogicalQuadProcessorMask ; see which processors are quad
+ jz short SkipQuad
+
+ stdCall _HalQicRequestIpi, <eax, NCR_CLOCK_LEVEL_CPI>
+
+SkipQuad:
+
+
+ align dword
+@@:
+ cmp PCR[PcHal].PcrMyLogicalNumber, 0 ; P0 calls UpdateSystemTime
+ je short _HalpUpdateSystemTime
+
+ stdCall _KeUpdateRunTime,<dword ptr [esp]> ; else, UpdateRunTime
+
+ INTERRUPT_EXIT
+
+ public _HalpUpdateSystemTime
+_HalpUpdateSystemTime:
+ mov eax, TIME_INCREMENT
+ jmp _KeUpdateSystemTime@0
+
+
+SpuriousClock:
+
+;
+; A spurious interrupt to a clock interrupt can occur because we either
+; haven't raised our mask, or because we are multiplexing the clock vector's
+; IRQ with NT's IPI vector IRQ.
+;
+
+ push CLOCK_VECTOR
+ sub esp, 4 ; allocate space to save OldIrql
+ stdCall _HalBeginSystemInterrupt, <IPI_LEVEL,CLOCK_VECTOR,esp>
+
+ ; if it's spurious here, then
+ or eax, eax ; the interrupt was masked and the HW
+ jz SpuriousClock3 ; will take care of re-routing it
+;
+; We recieved a clock tick while while our irql was >= clock_level and
+; below ipi_level. The clock tick can't be processed until we get below
+; clock_level, and we can't raise above ipi_level to mask it off so we
+; eat the clock interrupt and use the soft-emulation (PcIRR) to process a
+; clock tick later
+;
+
+; turn off the interrupt via system control port b - since HalMakeBeep also
+; accesses system control port b (speaker control) and uses the 8254 spin lock,
+; we will too
+
+Hci21: pushfd
+ cli
+ lea eax, _Halp8254Lock
+ ACQUIRE_SPINLOCK eax,Hci198
+
+ in al, 61h
+ jmp $+2
+ or al, 80h
+ out 61h, al
+ jmp $+2
+
+ align dword
+@@:
+ lea ebx, _Halp8254Lock
+ RELEASE_SPINLOCK ebx
+ popfd
+
+;;;;
+;;;; BUGBUG - Setting the bit to delay processing of the clock interrupt
+;;;; causes the machine to stop under moderate stress - can't even get
+;;;; get into the debugger. By removing the delayed processing, the
+;;;; problem seems to have gone away - I don't know why. At some point
+;;;; this needs to be fixed.
+;;;;
+;;;; NOTE - check delayed processing of CPIs from within HalBeginSystem
+;;;; Interrupt. Perhaps this is causing the problem (with the broadcast
+;;;; clock cpi)
+;;;;
+;;;;; BUGBUG: Hardcoded value
+
+ or dword ptr PCR[PcIRR], 1 shl 4
+
+ INTERRUPT_EXIT ; EOI this vector
+
+SpuriousClock2:
+if DBG
+ int 3 ; Should never get here
+endif
+
+SpuriousClock3:
+ add esp, 8 ; spurious, no EndOfInterrupt
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+Hci99: popfd
+ SPIN_ON_SPINLOCK eax,<Hci11>
+
+Hci198: popfd
+ SPIN_ON_SPINLOCK eax,<Hci21>
+
+stdENDP _HalpClockInterrupt
+
+
+ page ,132
+ subttl "Emulate System Clock Interrupt"
+;++
+;
+; Routine Description:
+;
+; This routine is entered as the result of an a delayed clock interrupt.
+; The clock has already been EOI-ed, so this function simply setups
+; a frame and jumps into the normal clocktick code without touching
+; the clock device or interrupt hardware.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+; Does not return, jumps directly to KeUpdateSystemTime, which returns
+;--
+
+ ENTER_DR_ASSIST Heci_a, Heci_t
+
+ align dword
+ public _NCREmulateClockTick
+_NCREmulateClockTick proc
+
+ pop eax
+ pushfd
+ push cs
+ push eax
+
+;
+; Save machine state on trap frame
+;
+
+ ENTER_INTERRUPT Heci_a, Heci_t
+
+ push NCR_CPI_VECTOR_BASE ; BOGUS vector to prevent EOI
+ push PCR[PcIrql] ; save previous IRQL
+ mov byte ptr PCR[PcIrql], CLOCK2_LEVEL; set new irql
+ sti
+ jmp ProcessClock ; Join ClockInterrupt code
+
+_NCREmulateClockTick endp
+
+;++
+;
+; ULONG
+; HalSetTimeIncrement (
+; IN ULONG DesiredIncrement
+; )
+;
+; /*++
+;
+; Routine Description:
+;
+; This routine initialize system time clock to generate an
+; interrupt at every DesiredIncrement interval.
+;
+; Arguments:
+;
+; DesiredIncrement - desired interval between every timer tick (in
+; 100ns unit.)
+;
+; Return Value:
+;
+; The *REAL* time increment set.
+;--
+cPublicProc _HalSetTimeIncrement,1
+
+ mov eax, TIME_INCREMENT
+ stdRET _HalSetTimeIncrement
+
+stdENDP _HalSetTimeIncrement
+
+_TEXT ends
+ end
diff --git a/private/ntos/nthals/halncr/i386/ncrdetct.c b/private/ntos/nthals/halncr/i386/ncrdetct.c
new file mode 100644
index 000000000..f61f96fb1
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrdetct.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ncrdetct.c"
diff --git a/private/ntos/nthals/halncr/i386/ncrhwsup.c b/private/ntos/nthals/halncr/i386/ncrhwsup.c
new file mode 100644
index 000000000..89e36b2e7
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrhwsup.c
@@ -0,0 +1,170 @@
+
+/*++
+
+Copyright (c) 1992 NCR - MSBU
+
+Module Name:
+
+ ncrhwsup.c
+
+Abstract:
+
+
+Author:
+
+ Richard Barton (o-richb) 11-Mar-1992
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "ncr.h"
+#include "ncrcat.h"
+#include "ncrpsi.h"
+
+extern ULONG NCRActiveProcessorCount;
+
+ULONG NCRSysIntCount;
+ULONG NCRSingleBitCount;
+
+ULONG NCRLockedExchangeAndAdd(PULONG, ULONG);
+
+
+VOID
+NCRHandleSysInt (TrapFramePtr, ExceptionRecordPtr)
+IN PKTRAP_FRAME TrapFramePtr;
+IN PVOID ExceptionRecordPtr;
+/*++
+
+Routine Description:
+ Handles the NCR hardware generated System Interrupt
+
+Arguments:
+
+Return Value:
+ none.
+
+--*/
+{
+
+ DbgBreakPoint();
+ return ;
+
+#if 0
+ ULONG i;
+
+ i = NCRLockedExchangeAndAdd(&NCRSysIntCount, 1);
+ if (i != 0) {
+ for (i = 100000;
+ ((NCRSysIntCount != NCRActiveProcessorCount) &&
+ (i > 0)); --i) ;
+ KiIpiServiceRoutine(TrapFramePtr, ExceptionRecordPtr);
+ return;
+ }
+
+ DbgPrint("NCRHandleSysInt");
+ DbgBreakPoint();
+
+ NCRSysIntCount = 0;
+#endif
+}
+
+
+VOID
+NCRHandleSingleBitError (TrapFramePtr, ExceptionRecordPtr)
+IN PKTRAP_FRAME TrapFramePtr;
+IN PVOID ExceptionRecordPtr;
+/*++
+
+Routine Description:
+ Handles the NCR hardware generated Single Bit Error Interrupt and a
+ Status Change
+
+Arguments:
+
+Return Value:
+ none.
+
+--*/
+{
+ CAT_CONTROL cat_control;
+ PSI_INFORMATION psi_information;
+
+ cat_control.Module = PSI;
+ cat_control.Asic = CAT_I;
+
+//
+// Lets get the CatBus spin lock because the status change interrupt is a broadcast
+// interrupt that goes to all CPU's
+//
+
+ HalpAcquireCatBusSpinLock();
+
+//
+// read status registers from PSI. This will tell us if a status change interrupt occured.
+//
+ cat_control.Command = READ_REGISTER;
+ cat_control.Address = 0;
+ cat_control.NumberOfBytes = sizeof(CAT_REGISTERS);
+ HalpCatBusIo(&cat_control,(PUCHAR)&(psi_information.CatRegisters.CatRegs));
+
+ if (psi_information.INTERRUPT_STATUS) {
+
+ //
+ // A status change interrupt has occured. Lets go read detailed status information so
+ // the interrupt will be cleared.
+ //
+
+ //
+ // read power supply mask registers
+ //
+ cat_control.Command = READ_SUBADDR;
+ cat_control.Address = PSI_Pwr_Supply_Status_L5;
+ cat_control.NumberOfBytes = 8;
+ HalpCatBusIo(&cat_control,(PUCHAR)&(psi_information.PowerSupplyStatus));
+ //
+ // read disk power registers
+ //
+ cat_control.Command = READ_SUBADDR;
+ cat_control.Address = PSI_DiskStatus_L5;
+ cat_control.NumberOfBytes = 16;
+ HalpCatBusIo(&cat_control,(PUCHAR)&(psi_information.DiskPowerStatus[0]));
+ //
+ // read DVM registers
+ //
+ cat_control.Command = READ_SUBADDR;
+ cat_control.Address = PSI_Dvm_Select_L5;
+ cat_control.NumberOfBytes = 1;
+ HalpCatBusIo(&cat_control,(PUCHAR)&(psi_information.DvmSelect));
+
+ cat_control.Command = READ_SUBADDR;
+ cat_control.Address = DVM_DBASE;
+ cat_control.NumberOfBytes = 4;
+ HalpCatBusIo(&cat_control,(PUCHAR)&(psi_information.DvmData0));
+
+ } else {
+
+ //
+ // This path means another CPU has handled the status change.
+ //
+ // NOTE: If single bit error reporting were enabled then this path could also
+ // mean a single bit error occured.
+ //
+
+ }
+
+ //
+ // Release the CatBus spin lock.
+ //
+
+ HalpReleaseCatBusSpinLock();
+
+ if (psi_information.INTERRUPT_STATUS) {
+ DBGMSG(("A Status Change Interrupt was received: 0x%x\n",psi_information.INTERRUPT_STATUS));
+ }
+}
diff --git a/private/ntos/nthals/halncr/i386/ncrintr.asm b/private/ntos/nthals/halncr/i386/ncrintr.asm
new file mode 100644
index 000000000..f5c9c6899
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrintr.asm
@@ -0,0 +1,823 @@
+ title "NCR Specific Interrupt Handlers"
+;++
+;
+; Copyright (c) 1992 NCR - MSBU
+;
+; Module Name:
+;
+; ncrintr.asm
+;
+; Abstract:
+;
+; This module implements the code necessary to field and process
+; interrupts specific to the NCR - MSBU platforms.
+;
+; Author:
+;
+; Richard R. Barton (o-richb) 11 Mar 1992
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\ix8259.inc
+include i386\kimacro.inc
+include mac386.inc
+include i386\ncr.inc
+include i386\ixcmos.inc
+ .list
+
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _KeUpdateRunTime,1,IMPORT
+ EXTRNP _HalEndSystemInterrupt,2
+ EXTRNP _HalBeginSystemInterrupt,3
+ EXTRNP _NCRHandleSysInt,2
+ EXTRNP _NCRHandleSingleBitError,2
+ EXTRNP _NCRHandleQicSpuriousInt,2
+ EXTRNP _HalpProfileInterrupt2ndEntry
+ EXTRNP _HalpAcquireCmosSpinLock ,0
+ EXTRNP _HalpReleaseCmosSpinLock ,0
+ EXTRNP _HalQicRequestIpi,2
+ extrn _HalpUpdateSystemTime:near
+ extrn _NCRLogicalNumberToPhysicalMask:DWORD
+ extrn _HalpIpiClock:DWORD
+ extrn _NCRActiveProcessorLogicalMask:DWORD
+ extrn _NCRPlatform:DWORD
+ extrn _NCRStatusChangeInterruptEnabled:DWORD
+ extrn _NCRLogicalDyadicProcessorMask:DWORD
+ extrn _NCRLogicalQuadProcessorMask:DWORD
+
+
+_DATA SEGMENT DWORD USE32 PUBLIC 'DATA'
+ public _NCRIpiProfile
+_NCRIpiProfile dd 0
+_DATA ends
+
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "Broadcast Clock Handler"
+;++
+;
+; Routine Description:
+;
+; This interrupt handler receives the clock interrupt for processors
+; that did not handle the interrupt from the rtc.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+;--
+
+ ENTER_DR_ASSIST NCRClockBroadcast_a, NCRClockBroadcast_t
+
+cPublicProc _NCRClockBroadcastHandler,0
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT NCRClockBroadcast_a, NCRClockBroadcast_t
+
+ mov eax, PCR[PcHal.PcrMyProcessorFlags]
+ test eax, CPU_DYADIC
+ jz short DoQuad
+
+;
+; get slave ISR value and check to see if this is really a SMCA IRQ10
+; if it is then go handle that interrupt and exit
+;
+ ; NOTE: NCR needs to test the following fix. By not using interrupt
+ ; 10 on the secondary MCA bus this following work-around is nop-ed.
+
+
+ in al, PIC2_PORT0
+ test al, 00000100B
+ jnz HandleIrq10
+
+; (esp) - base of trap frame
+;
+ push NCR_CPI_VECTOR_BASE + NCR_CLOCK_LEVEL_CPI
+ sub esp, 4 ; placeholder for OldIrql
+
+;; stdCall _HalBeginSystemInterrupt,<CLOCK2_LEVEL,NCR_CPI_VECTOR_BASE + NCR_CLOCK_LEVEL_CPI,esp>
+ stdCall _HalBeginSystemInterrupt, <PROFILE_LEVEL,NCR_CPI_VECTOR_BASE + NCR_CLOCK_LEVEL_CPI,esp>
+ jmp short NoQuad
+
+DoQuad:
+
+ push NCR_QIC_CPI_VECTOR_BASE + NCR_CLOCK_LEVEL_CPI
+ sub esp, 4 ; placeholder for OldIrql
+ stdCall _HalBeginSystemInterrupt, <PROFILE_LEVEL,NCR_QIC_CPI_VECTOR_BASE + NCR_CLOCK_LEVEL_CPI,esp>
+
+NoQuad:
+
+ or al,al ; check for spurious interrupt
+ jz SpuriousClockBroadcast
+
+ mov esi, PCR[PcHal.PcrMyLogicalNumber]
+ lock btr _HalpIpiClock, esi ; reset our clock tick bit
+ jnc short bch_30 ; if it wasn't set, then don't updatetime
+
+ or esi, esi ; is this P0?
+ jz ClockBroadcastP0 ; Yes, then UpdateSystemTime
+
+;
+; (esp) = OldIrql
+; (esp+4) = vector
+;
+ stdCall _KeUpdateRunTime, <dword ptr [esp]>
+ align dword
+bch_30:
+ bt _NCRIpiProfile, esi ; Profile broadcast pending?
+ jc short ProfileBroadcast ; Yes, go do it
+
+ INTERRUPT_EXIT ; All done
+
+ align dword
+ProfileBroadcast:
+ lock btr _NCRIpiProfile, esi ; clear our bit
+ jmp _HalpProfileInterrupt2ndEntry@0
+
+SpuriousClockBroadcast:
+ add esp, 8 ; spurious, no EndOfInterrupt
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+HandleIrq10:
+ int NCR_SECONDARY_VECTOR_BASE + 10
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+bch_35:
+;
+; P0 also has a profile interrupt pending. For simpilicty just
+; send ourselves another interrupt to handle the profile interrupt
+;
+
+ mov eax, PCR[PcHal.PcrMyProcessorFlags]
+ test eax, CPU_DYADIC
+ jz short DoQuad0
+
+ mov eax,dword ptr _NCRLogicalNumberToPhysicalMask[0]
+ VIC_WRITE CpiLevel2Reg, al ; Send ourselves another broadcast
+ jmp _HalpUpdateSystemTime ; Go update system time
+
+DoQuad0:
+
+ xor eax,eax
+ stdCall _HalQicRequestIpi, <eax, NCR_CLOCK_LEVEL_CPI>
+ jmp _HalpUpdateSystemTime ; Go update system time
+
+ align dword
+ClockBroadcastP0:
+;
+; P0 has a clock interrupt broadcast to it
+;
+ test _NCRIpiProfile, 1 ; Profile broadcast pending?
+ jnz short bch_35
+ jmp _HalpUpdateSystemTime ; Go update system time
+
+stdENDP _NCRClockBroadcastHandler
+
+
+ page ,132
+ subttl "NCR Profile Handler"
+;++
+;
+; Routine Description:
+;
+; This interrupt handler receives the profile interrupt and
+; broadcasts it to all other processors
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+;--
+
+ ENTER_DR_ASSIST NCRProfile_a, NCRProfile_t
+
+ align dword
+ public _NCRProfileHandler
+_NCRProfileHandler proc
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT NCRProfile_a, NCRProfile_t
+
+;
+; (esp) - base of trap frame
+;
+ push PROFILE_VECTOR
+ sub esp, 4 ; placeholder for OldIrql
+
+ stdCall _HalBeginSystemInterrupt, <PROFILE_LEVEL,PROFILE_VECTOR,esp>
+ or al,al ; check for spurious interrupt
+ jz SpuriousProfile
+
+;
+; Broadcast profile interrupt to all other processors
+;
+
+ mov eax, _NCRActiveProcessorLogicalMask ; all processors
+ xor eax, PCR[PcHal.PcrMyLogicalMask] ; less current one
+ or _NCRIpiProfile, eax ; set their bits
+
+ push eax
+ and eax,_NCRLogicalDyadicProcessorMask ; see which processors are dyadics
+ jz short SkipDyadic
+
+ TRANSLATE_LOGICAL_TO_VIC
+ VIC_WRITE CpiLevel2Reg, al
+SkipDyadic:
+ pop eax ; restore Active processor mask
+ and eax,_NCRLogicalQuadProcessorMask ; see which processors are quad
+ jz short SkipQuad
+
+ stdCall _HalQicRequestIpi, <eax, NCR_CLOCK_LEVEL_CPI>
+
+SkipQuad:
+
+
+;
+; This is the RTC interrupt, so we have to clear the
+; interrupt flag on the RTC.
+;
+ stdCall _HalpAcquireCmosSpinLock
+
+;
+; clear interrupt flag on RTC by banging on the CMOS. On some systems this
+; doesn't work the first time we do it, so we do it twice. It is rumored that
+; some machines require more than this, but that hasn't been observed with NT.
+;
+
+ mov al,0CH ; Register C
+ CMOS_READ ; Read to initialize
+ mov al,0CH ; Register C
+ CMOS_READ ; Read to initialize
+
+ stdCall _HalpReleaseCmosSpinLock
+ jmp _HalpProfileInterrupt2ndEntry@0
+
+SpuriousProfile:
+ add esp, 8 ; spurious, no EndOfInterrupt
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+_NCRProfileHandler endp
+
+
+ page ,132
+ subttl "System Interrupt Handler"
+;++
+;
+; Routine Description:
+;
+; This interrupt handler receives the hardware generated system interrupt.
+;
+; Due to a VIC errata, this handler can also be invoked on a CPI 0 (IPI)
+; that was simultaneous with a system interrupt or a single bit error
+; (except on 3360, where only a simultaneous system interrupt can cause
+; this condition). The proper way to handle this condition is as follows:
+;
+; 3360: handle system interrupt first (since we know we had one) and
+; perform IPI processing if the error was non-fatal
+;
+; 3450/3550: since we don't necessarily have a sysint and since sysint
+; processing requires CAT accesses (time consuming), should process
+; potential IPI first. If there wasn't one, then should perform
+; sysint processing (else exit - if there is a sysint it will
+; come back in).
+;
+;
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+;--
+
+ ENTER_DR_ASSIST NCRSysInt_a, NCRSysInt_t
+
+ align dword
+ public _NCRSysIntHandler
+_NCRSysIntHandler proc
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT NCRSysInt_a, NCRSysInt_t
+
+;
+; (esp) - base of trap frame
+;
+
+; NOTE: since the 3360 currently does not use the sysint, will not perform
+; the processing as identified above. Will need to when (if) it is used.
+
+
+; see if there is an IPI to process first
+
+ int NCR_CPI_VECTOR_BASE + NCR_IPI_LEVEL_CPI
+
+
+; should only perform system interrupt processing (below) if there was not
+; an valid IPI (processed above) - TO BE ADDED LATER, IF DESIRED
+
+
+ push NCR_CPI_VECTOR_BASE + NCR_SYSTEM_INTERRUPT
+ sub esp, 4 ; placeholder for OldIrql
+
+ stdCall _HalBeginSystemInterrupt, <HIGH_LEVEL,NCR_CPI_VECTOR_BASE + NCR_SYSTEM_INTERRUPT,esp>
+
+ or al,al ; check for spurious interrupt
+ jz SpuriousSysInt
+
+
+;
+; NOTE: On 3450 and greater machines a sysint should never occur. This is because
+; the Arbiter ASIC has been configured to send all hardware failures to the NMI vector
+; and not sysints. This configuration code is located in ncrsus.c in the function
+; HalpInitializeSUSInterface. The only way we can take this code path is if a
+; IPI 0 and status change/single bit error occured at the same time. So we will
+; process the ipi now and let the status change/single bit error handler process its
+; interrupt.
+;
+
+
+ mov eax, _NCRPlatform ; get Platform so we can check for 3360
+ cmp eax, NCR3360
+ jne short SkipSysInt ; if system is 3450 and greater then skip sys handler
+ ; because we cannot get a sysint. This condition is
+ ; caused by a a IPI0 and a Status change.
+
+;
+; (esp) = OldIrql
+; (esp+4) = vector
+;
+
+ stdCall _NCRHandleSysInt, <ebp, 0>
+
+SkipSysInt:
+
+ INTERRUPT_EXIT ; will return to caller, no DebugCheck
+
+SpuriousSysInt:
+ add esp, 8 ; spurious, no EndOfInterrupt
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+_NCRSysIntHandler endp
+
+
+
+ page ,132
+ subttl "Qic Spurious Handler"
+;++
+;
+; Routine Description:
+;
+; This interrupt handler receives the spurious interrupts from the Qic.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+;--
+
+ ENTER_DR_ASSIST NCRQicSpurInt_a, NCRQicSpurInt_t
+
+ align dword
+ public _NCRQicSpuriousHandler
+_NCRQicSpuriousHandler proc
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT NCRQicSpurInt_a, NCRQicSpurInt_t
+
+;
+; (esp) - base of trap frame
+;
+
+ push NCR_QIC_SPURIOUS_VECTOR
+ sub esp, 4 ; placeholder for OldIrql
+
+ stdCall _HalBeginSystemInterrupt, <HIGH_LEVEL,NCR_QIC_SPURIOUS_VECTOR,esp>
+
+ or al,al ; check for spurious interrupt
+ jz SpuriousQicSpurInt
+
+;
+; (esp) = OldIrql
+; (esp+4) = vector
+;
+
+ stdCall _NCRHandleQicSpuriousInt, <ebp, 0>
+
+
+ INTERRUPT_EXIT ; will return to caller, no DebugCheck
+
+SpuriousQicSpurInt:
+ add esp, 8 ; spurious, no EndOfInterrupt
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+_NCRQicSpuriousHandler endp
+
+
+ page ,132
+ subttl "VIC Errata Handler"
+
+;++
+;
+; Routine Description:
+;
+; This interrupt handler receives a SMCA interrupt whos vector
+; has been replace with a vector in the CPI range.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+;--
+
+ ENTER_DR_ASSIST NCRVICErrata1_a, NCRVICErrata1_t
+
+ align dword
+ public _NCRVICErrataHandler1
+_NCRVICErrataHandler1 proc
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT NCRVICErrata1_a, NCRVICErrata1_t
+
+;
+; (esp) - base of trap frame
+;
+
+;
+; get slave ISR value
+;
+ in al, PIC2_PORT0
+ test al, 00000010B
+ jz short SpuriousVICErrata1
+ int NCR_SECONDARY_VECTOR_BASE + 9
+SpuriousVICErrata1:
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+_NCRVICErrataHandler1 endp
+
+
+;++
+;
+; Routine Description:
+;
+; This interrupt handler receives a SMCA interrupt whos vector
+; has been replace with a vector in the CPI range.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+;--
+
+ ENTER_DR_ASSIST NCRVICErrata3_a, NCRVICErrata3_t
+
+ align dword
+ public _NCRVICErrataHandler3
+_NCRVICErrataHandler3 proc
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT NCRVICErrata3_a, NCRVICErrata3_t
+
+;
+; (esp) - base of trap frame
+;
+
+;
+; get slave ISR value
+;
+ in al, PIC2_PORT0
+ test al, 00001000B
+ jnz short SMCA_11
+ int NCR_SECONDARY_VECTOR_BASE + 3
+ jmp short SMCA_3
+SMCA_11:
+ int NCR_SECONDARY_VECTOR_BASE + 11
+SMCA_3:
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+_NCRVICErrataHandler3 endp
+
+
+
+;++
+;
+; Routine Description:
+;
+; This interrupt handler receives a SMCA interrupt whos vector
+; has been replace with a vector in the CPI range.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+;--
+
+ ENTER_DR_ASSIST NCRVICErrata4_a, NCRVICErrata4_t
+
+ align dword
+ public _NCRVICErrataHandler4
+_NCRVICErrataHandler4 proc
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT NCRVICErrata4_a, NCRVICErrata4_t
+
+;
+; (esp) - base of trap frame
+;
+
+;
+; get slave ISR value
+;
+ in al, PIC2_PORT0
+ test al, 00010000B
+ jnz short SMCA_12
+ int NCR_SECONDARY_VECTOR_BASE + 4
+ jmp short SMCA_4
+SMCA_12:
+ int NCR_SECONDARY_VECTOR_BASE + 12
+SMCA_4:
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+_NCRVICErrataHandler4 endp
+
+;++
+;
+; Routine Description:
+;
+; This interrupt handler receives a SMCA interrupt whos vector
+; has been replace with a vector in the CPI range.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+;--
+
+ ENTER_DR_ASSIST NCRVICErrata5_a, NCRVICErrata5_t
+
+ align dword
+ public _NCRVICErrataHandler5
+_NCRVICErrataHandler5 proc
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT NCRVICErrata5_a, NCRVICErrata5_t
+
+;
+; (esp) - base of trap frame
+;
+
+;
+; get slave ISR value
+;
+ in al, PIC2_PORT0
+ test al, 00100000B
+ jnz short SMCA_13
+ int NCR_SECONDARY_VECTOR_BASE + 5
+ jmp short SMCA_5
+SMCA_13:
+ int NCR_SECONDARY_VECTOR_BASE + 13
+SMCA_5:
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+_NCRVICErrataHandler5 endp
+
+
+;++
+;
+; Routine Description:
+;
+; This interrupt handler receives a SMCA interrupt whos vector
+; has been replace with a vector in the CPI range.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+;--
+
+ ENTER_DR_ASSIST NCRVICErrata6_a, NCRVICErrata6_t
+
+ align dword
+ public _NCRVICErrataHandler6
+_NCRVICErrataHandler6 proc
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT NCRVICErrata6_a, NCRVICErrata6_t
+
+;
+; (esp) - base of trap frame
+;
+
+;
+; get slave ISR value
+;
+ in al, PIC2_PORT0
+ test al, 01000000B
+ jnz short SMCA_14
+ int NCR_SECONDARY_VECTOR_BASE + 6
+ jmp short SMCA_6
+SMCA_14:
+ int NCR_SECONDARY_VECTOR_BASE + 14
+SMCA_6:
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+_NCRVICErrataHandler6 endp
+
+
+
+;++
+;
+; Routine Description:
+;
+; This interrupt handler receives a SMCA interrupt whos vector
+; has been replace with a vector in the CPI range.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+;--
+
+ ENTER_DR_ASSIST NCRVICErrata7_a, NCRVICErrata7_t
+
+ align dword
+ public _NCRVICErrataHandler7
+_NCRVICErrataHandler7 proc
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT NCRVICErrata7_a, NCRVICErrata7_t
+
+;
+; (esp) - base of trap frame
+;
+
+;
+; get slave ISR value
+;
+ in al, PIC2_PORT0
+ test al, 10000000B
+ jnz short SMCA_15
+ int NCR_SECONDARY_VECTOR_BASE + 7
+ jmp short SMCA_7
+SMCA_15:
+ int NCR_SECONDARY_VECTOR_BASE + 15
+SMCA_7:
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+_NCRVICErrataHandler7 endp
+
+
+;++
+;
+; Routine Description:
+;
+; This interrupt handler receives a SMCA interrupt whos vector
+; has been replace with a vector in the CPI range.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+;--
+
+ ENTER_DR_ASSIST NCRVICErrata15_a, NCRVICErrata15_t
+
+ align dword
+ public _NCRVICErrataHandler15
+_NCRVICErrataHandler15 proc
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT NCRVICErrata15_a, NCRVICErrata15_t
+
+;
+; (esp) - base of trap frame
+;
+
+;
+; get slave ISR value
+;
+ in al, PIC2_PORT0
+ test al, 10000000B
+ jnz short SMCA_15b
+
+;
+; This is a Single Bit Error or a Status Change
+;
+ test _NCRStatusChangeInterruptEnabled,1 ; send interrupt to a device driver?
+ jnz short ToDeviceDriver
+;
+; (esp) - base of trap frame
+;
+ push NCR_CPI_VECTOR_BASE + NCR_SINGLE_BIT_ERROR
+ sub esp, 4 ; placeholder for OldIrql
+
+ stdCall _HalBeginSystemInterrupt, <HIGH_LEVEL,NCR_CPI_VECTOR_BASE + NCR_SINGLE_BIT_ERROR,esp>
+ or al,al ; check for spurious interrupt
+ jz SpuriousSingleBit
+;
+; (esp) = OldIrql
+; (esp+4) = vector
+;
+
+ stdCall _NCRHandleSingleBitError, <ebp, 0>
+ INTERRUPT_EXIT ; will return to caller, no DebugCheck
+
+SpuriousSingleBit:
+ add esp, 8 ; spurious, no EndOfInterrupt
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+
+ToDeviceDriver:
+ int PRIMARY_VECTOR_BASE + 027H ; call status change interrupt at vector 57
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+SMCA_15b:
+ int NCR_SECONDARY_VECTOR_BASE + 15
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+_NCRVICErrataHandler15 endp
+
+
+
+_TEXT ends
+ end
+
+
diff --git a/private/ntos/nthals/halncr/i386/ncrioacc.asm b/private/ntos/nthals/halncr/i386/ncrioacc.asm
new file mode 100644
index 000000000..8929e56ad
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrioacc.asm
@@ -0,0 +1,730 @@
+ title "ix ioaccess"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; ncrioacc.asm
+;
+; Abstract:
+;
+; Procedures to correctly touch I/O registers.
+;
+; Author:
+;
+; Bryan Willman (bryanwi) 16 May 1990
+; Rick Ulmer (rick.ulmer@columbiasc.ncr.com) 1 March 1994
+;
+; Environment:
+;
+; User or Kernel, although privledge (IOPL) may be required.
+;
+; Revision History:
+;
+; RMU - Added support for SMC for NCR 35xx systems.
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+ .list
+
+
+ extrn _NCRSegmentIoRegister:DWORD
+
+
+
+
+_TEXT$00 SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; I/O port space read and write functions.
+;
+; These have to be actual functions on the 386, because we need
+; to use assembler, but cannot return a value if we inline it.
+;
+; This set of functions manipulates I/O registers in PORT space.
+; (Uses x86 in and out instructions)
+;
+; WARNING: Port addresses must always be in the range 0 to 64K, because
+; that's the range the hardware understands.
+;
+;--
+
+;++
+;
+; UCHAR
+; READ_PORT_UCHAR(
+; PUCHAR Port
+; )
+;
+; Arguments:
+; (esp+4) = Port
+;
+; Returns:
+; Value in Port.
+;
+;--
+cPublicProc _READ_PORT_UCHAR ,1
+cPublicFpo 1, 0
+
+ mov edx,[esp+4] ; (dx) = Port
+ ; port = ??srpppph
+ ; sr = segment register
+ ; pppp = port
+
+ test edx, 00010000h ; test for secondary access
+ jnz short ReadUcharSmca
+;
+; PMCA access
+;
+ in al,dx
+ stdRET _READ_PORT_UCHAR
+
+
+ReadUcharSmca:
+;
+; SMCA access
+;
+ mov ecx,_NCRSegmentIoRegister ; get segment register
+ ror edx, 8 ; get segreg as byte in dh
+ pushfd
+ cli ; disable interrupts
+ mov BYTE PTR[ecx], dh ; set segment register
+ rol edx, 8 ; restore port
+;
+ in al,dx
+;
+ mov BYTE PTR[ecx], 0 ; clear segment register back to zero
+ popfd ; enable interrupt
+
+ stdRET _READ_PORT_UCHAR
+
+stdENDP _READ_PORT_UCHAR
+
+
+
+;++
+;
+; USHORT
+; READ_PORT_USHORT(
+; PUSHORT Port
+; )
+;
+; Arguments:
+; (esp+4) = Port
+;
+; Returns:
+; Value in Port.
+;
+;--
+cPublicProc _READ_PORT_USHORT ,1
+cPublicFpo 1, 0
+
+ mov edx,[esp+4] ; (dx) = Port
+ ; port = ??srpppph
+ ; sr = segment register
+ ; pppp = port
+ test edx, 00010000h ; test for secondary access
+ jnz short ReadUshortSmca
+;
+; PMCA access
+;
+ in ax,dx
+ stdRET _READ_PORT_USHORT
+
+ReadUshortSmca:
+;
+; SMCA access
+;
+ mov ecx,_NCRSegmentIoRegister ; get segment register
+ ror edx, 8 ; get segreg as byte in dh
+ pushfd
+ cli ; disable interrupts
+ mov BYTE PTR[ecx], dh ; set segment register
+ rol edx, 8 ; restore port
+;
+ in ax,dx
+;
+ mov BYTE PTR[ecx], 0 ; clear segment register back to zero
+ popfd ; enable interrupt
+ stdRET _READ_PORT_USHORT
+
+stdENDP _READ_PORT_USHORT
+
+
+
+;++
+;
+; ULONG
+; READ_PORT_ULONG(
+; PULONG Port
+; )
+;
+; Arguments:
+; (esp+4) = Port
+;
+; Returns:
+; Value in Port.
+;
+;--
+cPublicProc _READ_PORT_ULONG ,1
+cPublicFpo 1, 0
+
+ mov edx,[esp+4] ; (dx) = Port
+ ; port = ??srpppph
+ ; sr = segment register
+ ; pppp = port
+ test edx, 00010000h ; test for secondary access
+ jnz short ReadUlongSmca
+;
+; PMCA access
+;
+ in eax,dx
+ stdRET _READ_PORT_ULONG
+
+
+ReadUlongSmca:
+;
+; SMCA access
+;
+ mov ecx,_NCRSegmentIoRegister ; get segment register
+ ror edx, 8 ; get segreg as byte in dh
+ pushfd
+ cli ; disable interrupts
+ mov BYTE PTR[ecx], dh ; set segment register
+ rol edx, 8 ; restore port
+;
+ in eax,dx
+;
+ mov BYTE PTR[ecx], 0 ; clear segment register back to zero
+ popfd ; enable interrupt
+ stdRET _READ_PORT_ULONG
+
+stdENDP _READ_PORT_ULONG
+
+
+
+;++
+;
+; VOID
+; READ_PORT_BUFFER_UCHAR(
+; PUCHAR Port,
+; PUCHAR Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _READ_PORT_BUFFER_UCHAR ,3
+cPublicFpo 3, 0
+
+ mov eax, edi ; Save edi
+
+ mov edx,[esp+4] ; (dx) = Port
+ ; port = ??srpppph
+ ; sr = segment register
+ ; pppp = port
+ test edx, 00010000h ; test for secondary access
+ jnz short ReadBufferUcharSmca
+;
+; PMCA access
+;
+ mov edi,[esp+8] ; (edi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ rep insb
+ mov edi, eax
+ stdRET _READ_PORT_BUFFER_UCHAR
+
+ReadBufferUcharSmca:
+;
+; SMCA access
+;
+ mov edi,[esp+8] ; (edi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ push ebx ; save ebx
+ mov ebx,_NCRSegmentIoRegister ; get segment register
+ ror edx, 8 ; get segreg as byte in dh
+ pushfd
+ cli ; disable interrupts
+ mov BYTE PTR[ebx], dh ; set segment register
+ rol edx, 8 ; restore port
+;
+ rep insb
+;
+ mov BYTE PTR[ebx], 0 ; clear segment register back to zero
+ popfd ; enable interrupt
+ pop ebx ; restore ebx
+ mov edi, eax
+ stdRET _READ_PORT_BUFFER_UCHAR
+
+stdENDP _READ_PORT_BUFFER_UCHAR
+
+
+;++
+;
+; VOID
+; READ_PORT_BUFFER_USHORT(
+; PUSHORT Port,
+; PUSHORT Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _READ_PORT_BUFFER_USHORT ,3
+cPublicFpo 3, 0
+
+ mov eax, edi ; Save edi
+
+ mov edx,[esp+4] ; (dx) = Port
+ ; port = ??srpppph
+ ; sr = segment register
+ ; pppp = port
+ test edx, 00010000h ; test for secondary access
+ jnz short ReadBufferUshortSmca
+;
+; PMCA access
+;
+ mov edi,[esp+8] ; (edi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ rep insw
+ mov edi, eax
+ stdRET _READ_PORT_BUFFER_USHORT
+
+ReadBufferUshortSmca:
+;
+; SMCA access
+;
+ mov edi,[esp+8] ; (edi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ push ebx ; save ebx
+ mov ebx,_NCRSegmentIoRegister ; get segment register
+ ror edx, 8 ; get segreg as byte in dh
+ pushfd
+ cli ; disable interrupts
+ mov BYTE PTR[ebx], dh ; set segment register
+ rol edx, 8 ; restore port
+;
+ rep insw
+;
+ mov BYTE PTR[ebx], 0 ; clear segment register back to zero
+ popfd ; enable interrupt
+ pop ebx ; restore ebx
+ mov edi, eax
+ stdRET _READ_PORT_BUFFER_USHORT
+
+stdENDP _READ_PORT_BUFFER_USHORT
+
+
+;++
+;
+; VOID
+; READ_PORT_BUFFER_ULONG(
+; PULONG Port,
+; PULONG Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _READ_PORT_BUFFER_ULONG ,3
+cPublicFpo 3, 0
+
+ mov eax, edi ; Save edi
+
+ mov edx,[esp+4] ; (dx) = Port
+ ; port = ??srpppph
+ ; sr = segment register
+ ; pppp = port
+ test edx, 00010000h ; test for secondary access
+ jnz short ReadBufferUlongSmca
+;
+; PMCA access
+;
+ mov edi,[esp+8] ; (edi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ rep insd
+ mov edi, eax
+ stdRET _READ_PORT_BUFFER_ULONG
+
+ReadBufferUlongSmca:
+;
+; SMCA access
+;
+ mov edi,[esp+8] ; (edi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ push ebx ; save ebx
+ mov ebx,_NCRSegmentIoRegister ; get segment register
+ ror edx, 8 ; get segreg as byte in dh
+ pushfd
+ cli ; disable interrupts
+ mov BYTE PTR[ebx], dh ; set segment register
+ rol edx, 8 ; restore port
+;
+ rep insd
+;
+ mov BYTE PTR[ebx], 0 ; clear segment register back to zero
+ popfd ; enable interrupt
+ pop ebx ; restore ebx
+ mov edi, eax
+ stdRET _READ_PORT_BUFFER_ULONG
+
+stdENDP _READ_PORT_BUFFER_ULONG
+
+
+
+;++
+;
+; VOID
+; WRITE_PORT_UCHAR(
+; PUCHAR Port,
+; UCHAR Value
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Value
+;
+;--
+cPublicProc _WRITE_PORT_UCHAR ,2
+cPublicFpo 2, 0
+
+ mov edx,[esp+4] ; (dx) = Port
+ ; port = ??srpppph
+ ; sr = segment register
+ ; pppp = port
+ test edx, 00010000h ; test for secondary access
+ jnz short WriteUcharSmca
+;
+; PMCA access
+;
+ mov al,[esp+8] ; (al) = Value
+ out dx,al
+ stdRET _WRITE_PORT_UCHAR
+
+WriteUcharSmca:
+;
+; SMCA access
+;
+ mov ecx,_NCRSegmentIoRegister ; get segment register
+ mov al,[esp+8] ; (al) = Value
+ ror edx, 8 ; get segreg as byte in dh
+ pushfd
+ cli ; disable interrupts
+ mov BYTE PTR[ecx], dh ; set segment register
+ rol edx, 8 ; restore port
+;
+ out dx,al
+;
+ mov BYTE PTR[ecx], 0 ; clear segment register back to zero
+ popfd ; enable interrupt
+ stdRET _WRITE_PORT_UCHAR
+
+stdENDP _WRITE_PORT_UCHAR
+
+
+
+;++
+;
+; VOID
+; WRITE_PORT_USHORT(
+; PUSHORT Port,
+; USHORT Value
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Value
+;
+;--
+cPublicProc _WRITE_PORT_USHORT ,2
+cPublicFpo 2, 0
+
+ mov edx,[esp+4] ; (dx) = Port
+ ; port = ??srpppph
+ ; sr = segment register
+ ; pppp = port
+ test edx, 00010000h ; test for secondary access
+ jnz short WriteUshortSmca
+;
+; PMCA access
+;
+ mov eax,[esp+8] ; (ax) = Value
+ out dx,ax
+ stdRET _WRITE_PORT_USHORT
+
+
+WriteUshortSmca:
+;
+; SMCA access
+;
+ mov ecx,_NCRSegmentIoRegister ; get segment register
+ mov eax,[esp+8] ; (ax) = Value
+ ror edx, 8 ; get segreg as byte in dh
+ pushfd
+ cli ; disable interrupts
+ mov BYTE PTR[ecx], dh ; set segment register
+ rol edx, 8 ; restore port
+;
+ out dx,ax
+;
+ mov BYTE PTR[ecx], 0 ; clear segment register back to zero
+ popfd ; enable interrupt
+ stdRET _WRITE_PORT_USHORT
+
+stdENDP _WRITE_PORT_USHORT
+
+
+
+;++
+;
+; VOID
+; WRITE_PORT_ULONG(
+; PULONG Port,
+; ULONG Value
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Value
+;
+;--
+cPublicProc _WRITE_PORT_ULONG ,2
+cPublicFpo 2, 0
+
+ mov edx,[esp+4] ; (dx) = Port
+ ; port = ??srpppph
+ ; sr = segment register
+ ; pppp = port
+ test edx, 00010000h ; test for secondary access
+ jnz short WriteUlongSmca
+;
+; PMCA access
+;
+ mov eax,[esp+8] ; (eax) = Value
+ out dx,eax
+ stdRET _WRITE_PORT_ULONG
+
+
+WriteUlongSmca:
+;
+; SMCA access
+;
+ mov ecx,_NCRSegmentIoRegister ; get segment register
+ mov eax,[esp+8] ; (eax) = Value
+ ror edx, 8 ; get segreg as byte in dh
+ pushfd
+ cli ; disable interrupts
+ mov BYTE PTR[ecx], dh ; set segment register
+ rol edx, 8 ; restore port
+;
+ out dx,eax
+;
+ mov BYTE PTR[ecx], 0 ; clear segment register back to zero
+ popfd ; enable interrupt
+ stdRET _WRITE_PORT_ULONG
+
+stdENDP _WRITE_PORT_ULONG
+
+
+
+;++
+;
+; VOID
+; WRITE_PORT_BUFFER_UCHAR(
+; PUCHAR Port,
+; PUCHAR Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _WRITE_PORT_BUFFER_UCHAR ,3
+cPublicFpo 3, 0
+
+ mov eax,esi ; Save esi
+ mov edx,[esp+4] ; (dx) = Port
+ ; port = ??srpppph
+ ; sr = segment register
+ ; pppp = port
+ test edx, 00010000h ; test for secondary access
+ jnz short WriteBufferUcharSmca
+;
+; PMCA access
+;
+ mov esi,[esp+8] ; (esi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ rep outsb
+ mov esi,eax
+ stdRET _WRITE_PORT_BUFFER_UCHAR
+
+WriteBufferUcharSmca:
+;
+; SMCA access
+;
+ mov esi,[esp+8] ; (esi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ push ebx ; save ebx
+ mov ebx,_NCRSegmentIoRegister ; get segment register
+ ror edx, 8 ; get segreg as byte in dh
+ pushfd
+ cli ; disable interrupts
+ mov BYTE PTR[ebx], dh ; set segment register
+ rol edx, 8 ; restore port
+;
+ rep outsb
+;
+ mov BYTE PTR[ebx], 0 ; clear segment register back to zero
+ popfd ; enable interrupt
+ pop ebx ; restore ebx
+ mov esi,eax
+ stdRET _WRITE_PORT_BUFFER_UCHAR
+
+stdENDP _WRITE_PORT_BUFFER_UCHAR
+
+
+;++
+;
+; VOID
+; WRITE_PORT_BUFFER_USHORT(
+; PUSHORT Port,
+; PUSHORT Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _WRITE_PORT_BUFFER_USHORT ,3
+cPublicFpo 3, 0
+
+ mov eax,esi ; Save esi
+ mov edx,[esp+4] ; (dx) = Port
+ ; port = ??srpppph
+ ; sr = segment register
+ ; pppp = port
+ test edx, 00010000h ; test for secondary access
+ jnz short WriteBufferUshortSmca
+;
+; PMCA access
+;
+ mov esi,[esp+8] ; (esi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ rep outsw
+ mov esi,eax
+ stdRET _WRITE_PORT_BUFFER_USHORT
+
+
+WriteBufferUshortSmca:
+;
+; SMCA access
+;
+ mov esi,[esp+8] ; (esi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ push ebx ; save ebx
+ mov ebx,_NCRSegmentIoRegister ; get segment register
+ ror edx, 8 ; get segreg as byte in dh
+ pushfd
+ cli ; disable interrupts
+ mov BYTE PTR[ebx], dh ; set segment register
+ rol edx, 8 ; restore port
+;
+ rep outsw
+;
+ mov BYTE PTR[ebx], 0 ; clear segment register back to zero
+ popfd ; enable interrupt
+ pop ebx ; restore ebx
+ mov esi,eax
+ stdRET _WRITE_PORT_BUFFER_USHORT
+
+stdENDP _WRITE_PORT_BUFFER_USHORT
+
+
+;++
+;
+; VOID
+; WRITE_PORT_BUFFER_ULONG(
+; PULONG Port,
+; PULONG Buffer,
+; ULONG Count
+; )
+;
+; Arguments:
+; (esp+4) = Port
+; (esp+8) = Buffer address
+; (esp+12) = Count
+;
+;--
+cPublicProc _WRITE_PORT_BUFFER_ULONG ,3
+cPublicFpo 3, 0
+
+ mov eax,esi ; Save esi
+ mov edx,[esp+4] ; (dx) = Port
+ ; port = ??srpppph
+ ; sr = segment register
+ ; pppp = port
+ test edx, 00010000h ; test for secondary access
+ jnz short WriteBufferUlongSmca
+;
+; PMCA access
+;
+ mov esi,[esp+8] ; (esi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ rep outsd
+ mov esi,eax
+ stdRET _WRITE_PORT_BUFFER_ULONG
+
+
+WriteBufferUlongSmca:
+;
+; SMCA access
+;
+ mov esi,[esp+8] ; (esi) = buffer
+ mov ecx,[esp+12] ; (ecx) = transfer count
+ push ebx ; save ebx
+ mov ebx,_NCRSegmentIoRegister ; get segment register
+ ror edx, 8 ; get segreg as byte in dh
+ pushfd
+ cli ; disable interrupts
+ mov BYTE PTR[ebx], dh ; set segment register
+ rol edx, 8 ; restore port
+;
+ rep outsd
+;
+ mov BYTE PTR[ebx], 0 ; clear segment register back to zero
+ popfd ; enable interrupt
+ pop ebx ; restore ebx
+ mov esi,eax
+ stdRET _WRITE_PORT_BUFFER_ULONG
+
+stdENDP _WRITE_PORT_BUFFER_ULONG
+
+
+_TEXT$00 ends
+
+ end
diff --git a/private/ntos/nthals/halncr/i386/ncripi.asm b/private/ntos/nthals/halncr/i386/ncripi.asm
new file mode 100644
index 000000000..ebbea00d8
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncripi.asm
@@ -0,0 +1,362 @@
+
+ title "Interprocessor Interrupt"
+;++
+;
+;Copyright (c) 1992 NCR Corporation
+;
+;Module Name:
+;
+; ncripi.asm
+;
+;Abstract:
+;
+; Provides the HAL support for Interprocessor Interrupts.
+;
+;Author:
+;
+; Richard Barton (o-richb) 24-Jan-1992
+;
+;Revision History:
+;
+;--
+.386p
+ .xlist
+include i386\kimacro.inc
+include callconv.inc ; calling convention macros
+include hal386.inc
+include i386\ncr.inc
+include i386\ix8259.inc
+
+
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _KiCoprocessorError,0,IMPORT
+ EXTRNP _KeRaiseIrql,2
+ EXTRNP _HalBeginSystemInterrupt,3
+ EXTRNP _HalEndSystemInterrupt,2
+ EXTRNP _KiIpiServiceRoutine,2,IMPORT
+ EXTRNP _HalEnableSystemInterrupt,3
+ EXTRNP _NCRClearQicIpi,1
+ extrn _NCRLogicalNumberToPhysicalMask:DWORD
+
+ page ,132
+ subttl "Post InterProcessor Interrupt"
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+
+
+;++
+;
+; VOID
+; NCR3360EnableNmiButtoni(
+; VOID
+; );
+;
+;Routine Description:
+;
+; Programs the recessed button on the 3360 to generate an NMI.
+;
+; 3360 SPECIFIC CODE ONLY !!!!!
+;
+;Arguments:
+;
+; Mask - Supplies a mask of the processors to interrupt
+;
+;Return Value:
+;
+; None.
+;
+;--
+
+;
+; in NMI handler, if you are interested in making sure button was source of
+; NMI, check bit 6 (of 0 thru 7) of IO port 0xf820. If 0, button was pressed,
+; 1 means NMI came from somewhere else.
+;
+; Also, in NMI interrupt handler, if NMI came fo...
+
+
+cPublicProc _NCR3360EnableNmiButton, 0
+
+ mov ah, 41h ; start with processor ASIC 0 (FRED ASIC)
+ mov cx, 2 ; loop through 2 processor cards
+
+PollAsics:
+ mov al, ah ; get ASIC select data
+ out 97h, al ; select ASIC through CAT Access port
+ mov dx, 0f800h ; read CAT ID
+ in al, dx ;
+ cmp al, 0ffh ; 0xff means no processor card is present
+ je @f
+
+ ; setup processor ASICs for g_nmi
+
+ mov dx, 0f80dh ; turn on GNMI in FRED ASIC
+ in al, dx
+ or al, 1
+ out dx, al
+
+@@:
+ add ah, 20h ; go to next processor card
+
+ loop PollAsics ; loop 'til done
+
+
+ mov al, 0c1h ; select arbiter ASIC
+ out 97h, al
+
+ mov dx, 0f80bh ; enable EXP_FALCON_NMI (pushbutton NMI)
+ in al, dx
+ or al, 8
+ out dx, al
+
+ mov al, 0ffh ; take CAT subsystem out of setup
+ out 97h, al
+
+
+ mov dx, 0f823h ; enable pushbutton NMI by disabling, then
+ in al, dx ; reenable
+ and al, 11011111b ; disable by setting MEM_DIS_L to 0
+ out dx, al
+ or al, 00100000b ; enable by setting MEM_DIS_L to 0
+ out dx, al
+
+ stdRET _NCR3360EnableNmiButton
+stdENDP _NCR3360EnableNmiButton
+
+
+
+;++
+;
+; VOID
+; HalVicRequestIpi(
+; IN ULONG Mask
+; );
+;
+;Routine Description:
+;
+; Requests an interprocessor interrupt using the VIC
+;
+;Arguments:
+;
+; Mask - Supplies a mask of the processors to interrupt
+;
+;Return Value:
+;
+; None.
+;
+;--
+
+cPublicProc _HalVicRequestIpi ,1
+ mov eax, dword ptr 4[esp]
+ TRANSLATE_LOGICAL_TO_VIC
+ VIC_WRITE CpiLevel0Reg, al
+ stdRET _HalVicRequestIpi
+stdENDP _HalVicRequestIpi
+
+
+ page ,132
+ subttl "80387 Irq13 Interrupt Handler"
+
+;++
+;
+; VOID
+; HalpIrq13Handler (
+; );
+;
+; Routine Description:
+;
+; When the 80387 detects an error, it raises its error line. This
+; was supposed to be routed directly to the 386 to cause a trap 16
+; (which would actually occur when the 386 encountered the next FP
+; instruction).
+;
+; However, the ISA design routes the error line to IRQ13 on the
+; slave 8259. So an interrupt will be generated whenever the 387
+; discovers an error.
+;
+; This routine handles that interrupt and passes control to the kernel
+; coprocessor error handler.
+;
+; Arguments:
+;
+; None.
+; Interrupt is disabled.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+ ENTER_DR_ASSIST Hi13_a, Hi13_t
+
+cPublicProc _HalpIrq13Handler ,0
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT Hi13_a, Hi13_t ; (ebp) -> Trap frame
+
+;
+; HalBeginSystemInterrupt will save previous IRQL
+;
+ cli
+ push 13 + PRIMARY_VECTOR_BASE
+ sub esp, 4 ; placeholder for OldIrql
+
+ stdCall _HalBeginSystemInterrupt, <I386_80387_IRQL,13 + PRIMARY_VECTOR_BASE,esp>
+
+ or al,al ; check for spurious interrupt
+ jz SpuriousIrq13
+
+ stdCall _KiCoprocessorError ; call CoprocessorError handler
+
+;
+; Clear the busy latch so that the 386 doesn't mistakenly think
+; that the 387 is still busy.
+;
+
+ xor al,al
+ out I386_80387_BUSY_PORT, al
+
+ INTERRUPT_EXIT ; will return to caller
+
+SpuriousIrq13:
+ add esp, 8 ; spurious, no EndOfInterrupt
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+stdENDP _HalpIrq13Handler
+
+
+ page ,132
+ subttl "Interprocessor Interrupt Handler"
+
+;++
+;
+; VOID
+; NCRVicIPIHandler (
+; );
+;
+; Routine Description:
+;
+; This routine handles an incoming cross-processor interrupt.
+;
+; Arguments:
+;
+; None.
+; Interrupt is disabled.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+ ENTER_DR_ASSIST Ipi_a, Ipi_t
+
+cPublicProc _NCRVicIPIHandler,0
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT Ipi_a, Ipi_t ; (ebp) -> Trap frame
+
+;
+; HalBeginSystemInterrupt will save previous IRQL
+;
+
+ push NCR_CPI_VECTOR_BASE+NCR_IPI_LEVEL_CPI
+ sub esp, 4 ; placeholder for OldIrql
+
+ stdCall _HalBeginSystemInterrupt, <IPI_LEVEL,NCR_CPI_VECTOR_BASE+NCR_IPI_LEVEL_CPI,esp>
+
+ or al,al ; check for spurious interrupt
+ jz short SpuriousIpi
+
+; Pass TrapFrame to Ipi service rtn
+; Pass Null ExceptionFrame
+
+ stdCall _KiIpiServiceRoutine, <ebp,0>
+
+; BUGBUG shielint ignore returncode
+
+NCRIpiisDone:
+ INTERRUPT_EXIT ; will return to caller
+
+ align 4
+SpuriousIpi:
+ add esp, 8 ; spurious, no EndOfInterrupt
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+stdENDP _NCRVicIPIHandler
+
+
+;++
+;
+; VOID
+; NCRQicIPIHandler (
+; );
+;
+; Routine Description:
+;
+; This routine handles an incoming cross-processor interrupt for the Quad Processor.
+;
+; Arguments:
+;
+; None.
+; Interrupt is disabled.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+ ENTER_DR_ASSIST QicIpi_a, QicIpi_t
+
+cPublicProc _NCRQicIPIHandler,0
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT QicIpi_a, QicIpi_t ; (ebp) -> Trap frame
+
+;
+; HalBeginSystemInterrupt will save previous IRQL
+;
+
+ push NCR_QIC_CPI_VECTOR_BASE+NCR_IPI_LEVEL_CPI
+ sub esp, 4 ; placeholder for OldIrql
+
+ stdCall _HalBeginSystemInterrupt, <IPI_LEVEL,NCR_QIC_CPI_VECTOR_BASE+NCR_IPI_LEVEL_CPI,esp>
+
+ or al,al ; check for spurious interrupt
+ jz short SpuriousQicIpi
+
+; Pass TrapFrame to Ipi service rtn
+; Pass Null ExceptionFrame
+
+ stdCall _KiIpiServiceRoutine, <ebp,0>
+
+; BUGBUG shielint ignore returncode
+
+NCRQicIpiisDone:
+ INTERRUPT_EXIT ; will return to caller
+
+ align 4
+SpuriousQicIpi:
+ add esp, 8 ; spurious, no EndOfInterrupt
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+stdENDP _NCRQicIPIHandler
+
+
+
+
+_TEXT ENDS
+
+ END
diff --git a/private/ntos/nthals/halncr/i386/ncrirql.asm b/private/ntos/nthals/halncr/i386/ncrirql.asm
new file mode 100644
index 000000000..c30cdf910
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrirql.asm
@@ -0,0 +1,1223 @@
+ title "Irql Processing"
+;++
+;
+; Copyright (c) 1992 NCR Corporation
+;
+; Module Name:
+;
+; ncrirql.asm
+;
+; Abstract:
+;
+; This module implements the code necessary to raise and lower i386
+; Irql and dispatch software interrupts with the 8259 PIC.
+;
+; Author:
+;
+; Richard Barton (o-richb) 24-Jan-1992
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+;--
+
+.486p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\ix8259.inc
+include i386\kimacro.inc
+include i386\ncr.inc
+include mac386.inc
+ .list
+
+
+ EXTRNP _KeBugCheck,1,IMPORT
+ EXTRNP _KeSetEventBoostPriority, 2, IMPORT
+ EXTRNP _KeWaitForSingleObject,5, IMPORT
+
+ extrn _HalpApcInterrupt:NEAR
+ extrn _HalpDispatchInterrupt:NEAR
+ extrn _KiUnexpectedInterrupt:NEAR
+ extrn _NCREmulateClockTick:NEAR
+ extrn _HalpBusType:DWORD
+
+ifdef NT_UP
+ LOCK_ADD equ add
+ LOCK_DEC equ dec
+else
+ LOCK_ADD equ lock add
+ LOCK_DEC equ lock dec
+endif
+;
+; Initialization control words equates for the PICs
+;
+
+ICW1_ICW4_NEEDED equ 01H
+ICW1_CASCADE equ 00H
+ICW1_INTERVAL8 equ 00H
+ICW1_LEVEL_TRIG equ 08H
+ICW1_EDGE_TRIG equ 00H
+ICW1_ICW equ 10H
+
+ICW4_8086_MODE equ 001H
+ICW4_NORM_EOI equ 000H
+ICW4_NON_BUF_MODE equ 000H
+ICW4_SPEC_FULLY_NESTED equ 010H
+ICW4_NOT_SPEC_FULLY_NESTED equ 000H
+
+OCW2_NON_SPECIFIC_EOI equ 020H
+OCW2_SPECIFIC_EOI equ 060H
+OCW2_SET_PRIORITY equ 0c0H
+
+PIC_SLAVE_IRQ equ 2
+PIC1_BASE equ 30H
+PIC2_BASE equ 38H
+
+;
+; Interrupt flag bit maks for EFLAGS
+;
+
+EFLAGS_IF equ 200H
+EFLAGS_SHIFT equ 9
+
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+;
+; PICsInitializationString - Master PIC initialization command string
+;
+
+
+PICsInitializationString dw PIC1_PORT0
+
+;
+; Master PIC initialization command
+;
+
+ db ICW1_ICW + ICW1_LEVEL_TRIG + ICW1_INTERVAL8 +\
+ ICW1_CASCADE + ICW1_ICW4_NEEDED
+ db PIC1_BASE
+ db 1 SHL PIC_SLAVE_IRQ
+ db ICW4_NOT_SPEC_FULLY_NESTED + \
+ ICW4_NON_BUF_MODE + \
+ ICW4_NORM_EOI + \
+ ICW4_8086_MODE
+;
+; Slave PIC initialization command strings
+;
+
+ dw PIC2_PORT0
+ db ICW1_ICW + ICW1_LEVEL_TRIG + ICW1_INTERVAL8 +\
+ ICW1_CASCADE + ICW1_ICW4_NEEDED
+ db PIC2_BASE
+ db PIC_SLAVE_IRQ
+ db ICW4_NOT_SPEC_FULLY_NESTED + \
+ ICW4_NON_BUF_MODE + \
+ ICW4_NORM_EOI + \
+ ICW4_8086_MODE
+ dw 0 ; end of string
+
+ align 4
+ public KiI8259MaskTable
+KiI8259MaskTable label dword
+ dd 00000000000000000000000000000000B ; irql 0 low
+ dd 00000000000000000000000000000000B ; irql 1 apc
+ dd 00000000000000000000000000000000B ; irql 2 dpc
+ dd 00000000000000000000000000000000B ; irql 3 .
+ dd 11111111100000000000000000000000B ; irql 4 .
+ dd 11111111110000000000000000000000B ; irql 5 .
+ dd 11111111111000000000000000000000B ; irql 6 .
+ dd 11111111111100000000000000000000B ; irql 7 .
+ dd 11111111111110000000000000000000B ; irql 8 .
+ dd 11111111111111000000000000000000B ; irql 9 .
+ dd 11111111111111100000000000000000B ; irql 10 .
+ dd 11111111111111110000000000000000B ; irql 11 .\
+ dd 11111111111111111000000000000000B ; irql 12 . irql
+ dd 11111111111111111100000000000000B ; irql 13 . device
+ dd 11111111111111111110000000000000B ; irql 14 . range
+ dd 11111111111111111111000000000000B ; irql 15 ./
+ dd 11111111111111111111100000000000B ; irql 16 .
+ dd 11111111111111111111110000000000B ; irql 17 .
+ dd 11111111111111111111111000000000B ; irql 18 .
+ dd 11111111111111111111111000000000B ; irql 19 .
+ dd 11111111111111111111111010000000B ; irql 20 .
+ dd 11111111111111111111111011000000B ; irql 21 .
+ dd 11111111111111111111111011100000B ; irql 22 .
+ dd 11111111111111111111111011110000B ; irql 23 .
+ dd 11111111111111111111111011111000B ; irql 24 .
+ dd 11111111111111111111111011111000B ; irql 25 .
+ dd 11111111111111111111111011111010B ; irql 26 .
+ dd 11111111111111111111111111111110B ; irql 27 profile/clock
+; ^ bubug- change to a 0 (see below)
+ dd 11111111111111111111111111111110B ; irql 28 clock
+ dd 11111111111111111111111111111111B ; irql 29 ipi
+ dd 11111111111111111111111111111111B ; irql 30 power
+ dd 11111111111111111111111111111111B ; irql 31 high
+; | | |
+; | | +- NT IPI vector &
+; | | clock interrupt
+; | | multiplexed here.
+; | | raised to ipi level
+; | |
+; | +--- CPI Clock broadcasts
+; | here. raise to clock
+; | level.
+; |
+; +--- RTC for NT Profile vector
+; raised to profile level
+
+;
+; Warning - I moved the CPI Clock to below profile for now.
+;
+
+
+;
+; This table is used to mask all pending interrupts below a given Irql
+; out of the IRR
+;
+ align 4
+
+FindHigherIrqlMask label dword
+ dd 11111111111111111111111111111111B ; irql 0
+ dd 11111111111111111111111111111100B ; irql 1 (APC)
+ dd 11111111111111111111111111111000B ; irql 2 (DISPATCH)
+ dd 11111111111111111111111111110000B ; irql 3
+ dd 00000111111111111111111111110000B ; irql 4
+ dd 00000011111111111111111111110000B ; irql 5
+ dd 00000001111111111111111111110000B ; irql 6
+ dd 00000000111111111111111111110000B ; irql 7
+ dd 00000000011111111111111111110000B ; irql 8
+ dd 00000000001111111111111111110000B ; irql 9
+ dd 00000000000111111111111111110000B ; irql 10
+ dd 00000000000011111111111111110000B ; irql 11
+ dd 00000000000001111111111111110000B ; irql 12
+ dd 00000000000000111111111111110000B ; irql 13
+ dd 00000000000000011111111111110000B ; irql 14
+ dd 00000000000000001111111111110000B ; irql 15
+ dd 00000000000000000111111111110000B ; irql 16
+ dd 00000000000000000011111111110000B ; irql 17
+ dd 00000000000000000001111111110000B ; irql 18
+ dd 00000000000000000001111111110000B ; irql 19
+ dd 00000000000000000001011111110000B ; irql 20
+ dd 00000000000000000001001111110000B ; irql 20
+ dd 00000000000000000001000111110000B ; irql 22
+ dd 00000000000000000001000011110000B ; irql 23
+ dd 00000000000000000001000001110000B ; irql 24
+ dd 00000000000000000001000001110000B ; irql 25
+ dd 00000000000000000001000001010000B ; irql 26
+ dd 00000000000000000000000000010000B ; irql 27 profile/clock
+; ^ Warning - change to a 1 (see above)
+ dd 00000000000000000000000000000000B ; irql 28 clock
+ dd 00000000000000000000000000000000B ; irql 29 ipi
+ dd 00000000000000000000000000000000B ; irql 30 power
+ dd 00000000000000000000000000000000B ; irql 31 high
+; | | |
+; | | +- We only emulate clock
+; | | interrupts here, not IPIs.
+; | | So this is set to clock
+; | | level
+; | |
+; | +--- CPI Clock broadcasts
+; | here. raise to clock
+; | level
+; |
+; +--- RTC for NT Profile vector
+; raised to profile level
+
+ align 4
+;
+; The following tables define the addresses of software interrupt routers
+;
+
+;
+; Use this table if there is NO machine state frame on stack already
+;
+
+ public SWInterruptHandlerTable
+SWInterruptHandlerTable label dword
+ dd offset FLAT:_KiUnexpectedInterrupt ; irql 0
+ dd offset FLAT:_HalpApcInterrupt ; irql 1
+ dd offset FLAT:_HalpDispatchInterrupt ; irql 2
+ dd offset FLAT:_KiUnexpectedInterrupt ; irql 3
+ dd offset FLAT:_NCREmulateClockTick ; 8259 irq#0
+ dd offset FLAT:HalpHardwareInterrupt01 ; 8259 irq#1
+ dd offset FLAT:HalpHardwareInterrupt02 ; 8259 irq#2
+ dd offset FLAT:HalpHardwareInterrupt03 ; 8259 irq#3
+ dd offset FLAT:HalpHardwareInterrupt04 ; 8259 irq#4
+ dd offset FLAT:HalpHardwareInterrupt05 ; 8259 irq#5
+ dd offset FLAT:HalpHardwareInterrupt06 ; 8259 irq#6
+ dd offset FLAT:HalpHardwareInterrupt07 ; 8259 irq#7
+ dd offset FLAT:HalpHardwareInterrupt08 ; 8259 irq#8
+ dd offset FLAT:HalpHardwareInterrupt09 ; 8259 irq#9
+ dd offset FLAT:HalpHardwareInterrupt10 ; 8259 irq#10
+ dd offset FLAT:HalpHardwareInterrupt11 ; 8259 irq#11
+ dd offset FLAT:HalpHardwareInterrupt12 ; 8259 irq#12
+ dd offset FLAT:HalpHardwareInterrupt13 ; 8259 irq#13
+ dd offset FLAT:HalpHardwareInterrupt14 ; 8259 irq#14
+ dd offset FLAT:HalpHardwareInterrupt15 ; 8259 irq#15
+
+;
+; The following table picks up the highest pending software irq level
+; from software irr
+;
+
+ public SWInterruptLookUpTable
+SWInterruptLookUpTable label byte
+ db 0 ; SWIRR=0, so highest pending SW irql= 0
+ db 0 ; SWIRR=1, so highest pending SW irql= 0
+ db 1 ; SWIRR=2, so highest pending SW irql= 1
+ db 1 ; SWIRR=3, so highest pending SW irql= 1
+ db 2 ; SWIRR=4, so highest pending SW irql= 2
+ db 2 ; SWIRR=5, so highest pending SW irql= 2
+ db 2 ; SWIRR=6, so highest pending SW irql= 2
+ db 2 ; SWIRR=7, so highest pending SW irql= 2
+ db 3 ; SWIRR=8, so highest pending SW irql= 3
+ db 3 ; SWIRR=9, so highest pending SW irql= 3
+ db 3 ; SWIRR=A, so highest pending SW irql= 3
+ db 3 ; SWIRR=B, so highest pending SW irql= 3
+ db 3 ; SWIRR=C, so highest pending SW irql= 3
+ db 3 ; SWIRR=D, so highest pending SW irql= 3
+ db 3 ; SWIRR=E, so highest pending SW irql= 3
+ db 3 ; SWIRR=F, so highest pending SW irql= 3
+
+ db 4 ; SWIRR=10, so highest pending SW irql= 4
+ db 4 ; SWIRR=11, so highest pending SW irql= 4
+ db 4 ; SWIRR=12, so highest pending SW irql= 4
+ db 4 ; SWIRR=13, so highest pending SW irql= 4
+ db 4 ; SWIRR=14, so highest pending SW irql= 4
+ db 4 ; SWIRR=15, so highest pending SW irql= 4
+ db 4 ; SWIRR=16, so highest pending SW irql= 4
+ db 4 ; SWIRR=17, so highest pending SW irql= 4
+ db 4 ; SWIRR=18, so highest pending SW irql= 4
+ db 4 ; SWIRR=19, so highest pending SW irql= 4
+ db 4 ; SWIRR=1A, so highest pending SW irql= 4
+ db 4 ; SWIRR=1B, so highest pending SW irql= 4
+ db 4 ; SWIRR=1C, so highest pending SW irql= 4
+ db 4 ; SWIRR=1D, so highest pending SW irql= 4
+ db 4 ; SWIRR=1E, so highest pending SW irql= 4
+ db 4 ; SWIRR=1F, so highest pending SW irql= 4
+
+
+
+; public SWInterruptLookUpTable, FindFirstSetBit
+;FindFirstSetBit label byte
+; db 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+; db 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+;
+;
+; public AcquireBufferPosition, SpinLockRecord
+;
+;AcquireBufferPosition dd 0
+;SpinLockRecord dd 4096 dup (0)
+
+
+ifdef IRQL_METRICS
+
+ public HalRaiseIrqlCount
+ public HalLowerIrqlCount
+ public HalQuickLowerIrqlCount
+ public HalApcSoftwareIntCount
+ public HalDpcSoftwareIntCount
+ public HalHardwareIntCount
+ public HalPostponedIntCount
+ public Hal8259MaskCount
+
+HalRaiseIrqlCount dd 0
+HalLowerIrqlCount dd 0
+HalQuickLowerIrqlCount dd 0
+HalApcSoftwareIntCount dd 0
+HalDpcSoftwareIntCount dd 0
+HalHardwareIntCount dd 0
+HalPostponedIntCount dd 0
+Hal8259MaskCount dd 0
+
+endif
+_DATA ENDS
+
+ page ,132
+ subttl "Raise Irql"
+
+_TEXT SEGMENT PARA PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
+;++
+;
+; KIRQL
+; FASTCALL
+; KfRaiseIrql (
+; IN KIRQL NewIrql
+; )
+;
+; Routine Description:
+;
+; This routine is used to raise IRQL to the specified value.
+; Also, a mask will be used to mask off all the lower lever 8259
+; interrupts.
+;
+; Arguments:
+;
+; (cl) = NewIrql - the new irql to be raised to
+;
+; Return Value:
+;
+; OldIrql
+;
+;--
+
+cPublicFastCall KfRaiseIrql ,1
+cPublicFpo 0,0
+ mov al, PCR[PcIrql] ; get current irql
+ mov PCR[PcIrql], cl
+
+ifdef IRQL_METRICS
+ lock inc HalRaiseIrqlCount
+endif
+if DBG
+ cmp al, cl ; old > new?
+ ja short Kri99 ; yes, go bugcheck
+
+ fstRET KfRaiseIrql
+
+cPublicFpo 2,2
+Kri99:
+ push eax ; put new irql where we can find it
+ push ecx ; put old irql where we can find it
+ mov byte ptr PCR[PcIrql],0 ; avoid recursive error
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
+endif
+ fstRET KfRaiseIrql
+
+fstENDP KfRaiseIrql
+
+
+;++
+;
+; KIRQL
+; KeRaiseIrqlToDpcLevel (
+; )
+;
+; Routine Description:
+;
+; This routine is used to raise IRQL to DPC level.
+;
+; Arguments:
+;
+; Return Value:
+;
+; OldIrql - the addr of a variable which old irql should be stored
+;
+;--
+
+cPublicProc _KeRaiseIrqlToDpcLevel,0
+cPublicFpo 0, 0
+
+ mov al, PCR[PcIrql] ; (al) = Old Irql
+ mov byte ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
+
+ifdef IRQL_METRICS
+ inc HalRaiseIrqlCount
+endif
+if DBG
+ cmp al, DISPATCH_LEVEL ; old > new?
+ ja short Krid99 ; yes, go bugcheck
+
+ stdRET _KeRaiseIrqlToDpcLevel
+
+cPublicFpo 0,1
+Krid99: movzx eax, al
+ push eax ; put old irql where we can find it
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
+endif
+ stdRET _KeRaiseIrqlToDpcLevel
+
+stdENDP _KeRaiseIrqlToDpcLevel
+
+
+;++
+;
+; KIRQL
+; KeRaiseIrqlToSynchLevel (
+; )
+;
+; Routine Description:
+;
+; This routine is used to raise IRQL to SYNC level.
+;
+; Arguments:
+;
+; Return Value:
+;
+; OldIrql - the addr of a variable which old irql should be stored
+;
+;--
+
+cPublicProc _KeRaiseIrqlToSynchLevel,0
+cPublicFpo 0, 0
+
+ mov al, PCR[PcIrql] ; (al) = Old Irql
+ mov byte ptr PCR[PcIrql], SYNCH_LEVEL ; set new irql
+
+ifdef IRQL_METRICS
+ inc HalRaiseIrqlCount
+endif
+if DBG
+ cmp al, SYNCH_LEVEL ; old > new?
+ ja short Kris99 ; yes, go bugcheck
+
+ stdRET _KeRaiseIrqlToSynchLevel
+
+cPublicFpo 0,1
+Kris99: movzx eax, al
+ push eax ; put old irql where we can find it
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
+endif
+ stdRET _KeRaiseIrqlToSynchLevel
+
+stdENDP _KeRaiseIrqlToSynchLevel
+
+ page ,132
+ subttl "Lower irql"
+
+;++
+;
+; VOID
+; FASTCALL
+; KfLowerIrql (
+; IN KIRQL NewIrql
+; )
+;
+; Routine Description:
+;
+; This routine is used to lower IRQL to the specified value.
+; The IRQL and PIRQL will be updated accordingly. Also, this
+; routine checks to see if any software interrupt should be
+; generated. The following condition will cause software
+; interrupt to be simulated:
+; any software interrupt which has higher priority than
+; current IRQL's is pending.
+;
+; NOTE: This routine simulates software interrupt as long as
+; any pending SW interrupt level is higher than the current
+; IRQL, even when interrupts are disabled.
+;
+; On a UP system, HalEndSystenInterrupt is treated as a
+; LowerIrql.
+;
+; Arguments:
+;
+; (cl) = NewIrql - the new irql to be set.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicFastCall KfLowerIrql ,1
+cPublicFpo 0,1
+ pushfd ; save caller's eflags
+ movzx ecx, cl ; (ecx) = NewIrql
+
+ifdef IRQL_METRICS
+ lock inc HalLowerIrqlCount
+endif
+
+if DBG
+ cmp cl,PCR[PcIrql]
+ ja KliBug
+endif
+ cli
+ mov edx, PCR[PcIRR]
+ and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
+ ; pending interrupts we need to
+ ; dispatch now.
+ jz KliSWInterruptsDone
+
+cPublicFpo 0,1
+ push ecx ; Save NewIrql
+
+KliDoSWInterrupt:
+ bsr ecx, edx ; find highest priority interrupt.
+ ; (ecx) is bit position
+;
+; lower to irql level we are emulating
+;
+ mov PCR[PcIrql], ecx
+ cmp ecx, PCR[PcHal.PcrMyPICsIrql]
+ jae short Kli50
+
+ mov PCR[PcHal.PcrMyPICsIrql], ecx
+ mov eax, KiI8259MaskTable[ecx*4]
+ or eax, PCR[PcIDR]
+ SET_IRQ_MASK
+
+Kli50:
+ mov eax, 1
+ shl eax, cl
+ xor PCR[PcIRR], eax ; clear bit in IRR
+
+ call SWInterruptHandlerTable[ecx*4]
+
+;
+; When the trap handler returns, we will end up here
+;
+
+ mov ecx, [esp] ; Restore NewIrql
+ mov edx, PCR[PcIRR]
+ and edx, FindHigherIrqlMask[ecx*4] ; (edx) is the bitmask of
+ jnz KliDoSWInterrupt ; get next pending interrupt
+
+ add esp, 4
+cPublicFpo 0,0
+
+KliSWInterruptsDone:
+ mov PCR[PcIrql], ecx ; save NewIrql
+ cmp ecx, PCR[PcHal.PcrMyPICsIrql]
+ jb KliLowerPICMasks ; really lower the masks
+ popfd
+ fstRET KfLowerIrql
+
+KliLowerPICMasks:
+;
+; really lower each PICs mask
+;
+ mov PCR[PcHal.PcrMyPICsIrql], ecx
+ mov eax, KiI8259MaskTable[ecx*4]
+ or eax, PCR[PcIDR]
+ SET_IRQ_MASK
+
+ popfd
+ fstRET KfLowerIrql
+
+if DBG
+cPublicFpo 1,3
+KliBug:
+ push ecx ; new irql for debugging
+ push PCR[PcIrql] ; old irql for debugging
+ mov byte ptr PCR[PcIrql],HIGH_LEVEL ; avoid recursive error
+ stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL> ; never return
+endif
+fstENDP KfLowerIrql
+
+cPublicProc _HalpEndSoftwareInterrupt,1
+cPublicFpo 1,0
+ mov ecx, [esp+4]
+ fstCall KfLowerIrql
+ stdRet _HalpEndSoftwareInterrupt
+stdENDP _HalpEndSoftwareInterrupt
+
+ page ,132
+ subttl "Get current irql"
+;++
+;
+; KIRQL
+; KeGetCurrentIrql (VOID)
+;
+; Routine Description:
+;
+; This routine returns to current IRQL.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; The current IRQL.
+;
+;--
+
+cPublicProc _KeGetCurrentIrql ,0
+cPublicFpo 0,0
+ xor eax,eax
+ mov al, byte ptr PCR[PcIrql] ; Current irql is in the PCR
+ stdRET _KeGetCurrentIrql
+stdENDP _KeGetCurrentIrql
+
+;++
+;
+; KIRQL
+; FASTCALL
+; KfAcquireSpinLock (
+; IN PKSPIN_LOCK SpinLock
+; )
+;
+; Routine Description:
+;
+; This function raises to DISPATCH_LEVEL and then acquires a the
+; kernel spin lock.
+;
+; Arguments:
+;
+; (ecx) = SpinLock - Supplies a pointer to an kernel spin lock.
+;
+; Return Value:
+;
+; OldIrql
+;
+;--
+
+cPublicFastCall KfAcquireSpinLock,1
+cPublicFpo 0,0
+
+ mov al, PCR[PcIrql] ; (al) = Old Irql
+ mov byte ptr PCR[PcIrql], DISPATCH_LEVEL ; set new irql
+if DBG
+ cmp al, DISPATCH_LEVEL ; old > new?
+ ja short asl99 ; yes, go bugcheck
+endif
+ifdef IRQL_METRICS
+ inc HalRaiseIrqlCount
+endif
+
+sl10: ACQUIRE_SPINLOCK ecx,<short sl20>
+ fstRET KfAcquireSpinLock
+
+ public KfAcquireSpinLockSpinning
+KfAcquireSpinLockSpinning: ; label for profiling
+
+align 4
+sl20: SPIN_ON_SPINLOCK ecx,<short sl10>
+
+if DBG
+cPublicFpo 2, 1
+asl99:
+ push eax ; put old irql where we can find it
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL> ; never return
+endif
+ fstRET KfAcquireSpinLock
+fstENDP KfAcquireSpinLock
+
+ PAGE
+ SUBTTL "Acquire Synch Kernel Spin Lock"
+;++
+;
+; KIRQL
+; FASTCALL
+; KeAcquireSpinLockRaiseToSynch (
+; IN PKSPIN_LOCK SpinLock
+; )
+;
+; Routine Description:
+;
+; This function acquires the SpinLock at SYNCH_LEVEL. The function
+; is optmized for hoter locks (the lock is tested before acquired,
+; any spin should occur at OldIrql)
+;
+; Arguments:
+;
+; (ecx) = SpinLock - Supplies a pointer to an kernel spin lock.
+;
+; Return Value:
+;
+; OldIrql - pointer to place old irql
+;
+;--
+
+align 16
+cPublicFastCall KeAcquireSpinLockRaiseToSynch,1
+cPublicFpo 0,0
+
+;
+; Disable interrupts
+;
+
+sls10: cli
+
+;
+; Try to obtain spinlock. Use non-lock operation first
+;
+ TEST_SPINLOCK ecx,<short sls20>
+ ACQUIRE_SPINLOCK ecx,<short sls20>
+
+
+;
+; Got the lock, raise to SYNCH_LEVEL
+;
+
+ mov ecx, SYNCH_LEVEL
+ fstCall KfRaiseIrql ; (al) = OldIrql
+
+;
+; Enable interrupts and return
+;
+
+ sti
+ fstRET KeAcquireSpinLockRaiseToSynch
+
+
+;
+; Lock is owned, spin till it looks free, then go get it again.
+;
+
+sls20: sti
+ SPIN_ON_SPINLOCK ecx,sls10
+
+fstENDP KeAcquireSpinLockRaiseToSynch
+
+
+
+;++
+;
+; VOID
+; FASTCALL
+; KfReleaseSpinLock (
+; IN PKSPIN_LOCK SpinLock,
+; IN KIRQL NewIrql
+; )
+;
+; Routine Description:
+;
+; This function releases a kernel spin lock and lowers to the new irql
+;
+; In a UP hal spinlock serialization is accomplished by raising the
+; IRQL to DISPATCH_LEVEL. The SpinLock is not used.
+;
+; Arguments:
+;
+; (ecx) = SpinLock - Supplies a pointer to an executive spin lock.
+; (dl) = NewIrql - New irql value to set
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+align 16
+cPublicFastCall KfReleaseSpinLock ,2
+cPublicFpo 0,0
+
+ RELEASE_SPINLOCK ecx ; release it
+
+ mov ecx, edx ; (ecx) = NewIrql
+ jmp @KfLowerIrql@4
+
+fstENDP KfReleaseSpinLock
+
+;++
+;
+; VOID
+; FASTCALL
+; ExAcquireFastMutex (
+; IN PFAST_MUTEX FastMutex
+; )
+;
+; Routine description:
+;
+; This function acquire ownership of the FastMutex
+;
+; Arguments:
+;
+; (ecx) = FastMutex - Supplies a pointer to the fast mutex
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicFastCall ExAcquireFastMutex,1
+cPublicFpo 0,1
+
+ push ecx ; Push FAST_MUTEX addr
+ mov ecx, APC_LEVEL
+ fstCall KfRaiseIrql
+
+ pop ecx ; (ecx) = Fast Mutex
+
+cPublicFpo 0,0
+ LOCK_DEC dword ptr [ecx].FmCount ; Get count
+ jz short afm_ret ; The owner? Yes, Done
+
+ inc dword ptr [ecx].FmContention
+
+cPublicFpo 0,1
+ push ecx
+ push eax
+ add ecx, FmEvent ; Wait on Event
+ stdCall _KeWaitForSingleObject,<ecx,WrExecutive,0,0,0>
+ pop eax
+ pop ecx
+
+cPublicFpo 0,0
+afm_ret:
+ mov byte ptr [ecx].FmOldIrql, al
+ fstRet ExAcquireFastMutex
+
+fstENDP ExAcquireFastMutex
+
+;++
+;
+; BOOLEAN
+; FASTCALL
+; ExTryToAcquireFastMutex (
+; IN PFAST_MUTEX FastMutex
+; )
+;
+; Routine description:
+;
+; This function acquire ownership of the FastMutex
+;
+; Arguments:
+;
+; (ecx) = FastMutex - Supplies a pointer to the fast mutex
+;
+; Return Value:
+;
+; Returns TRUE if the FAST_MUTEX was acquired; otherwise false
+;
+;--
+
+cPublicFastCall ExTryToAcquireFastMutex,1
+cPublicFpo 0,0
+
+;
+; Try to acquire
+;
+ cmp dword ptr [ecx].FmCount, 1 ; Busy?
+ jne short tam25 ; Yes, abort
+
+cPublicFpo 0,1
+ push ecx ; Push FAST_MUTEX
+ mov ecx, APC_LEVEL
+ fstCall KfRaiseIrql ; (al) = OldIrql
+
+ mov ecx, [esp] ; Restore FAST_MUTEX
+ mov [esp], eax ; Save OldIrql
+
+ mov eax, 1 ; Value to compare against
+ mov edx, 0 ; Value to set
+ lock cmpxchg dword ptr [ecx].FmCount, edx ; Attempt to acquire
+ jnz short tam20 ; got it?
+
+cPublicFpo 0,0
+ pop edx ; (edx) = OldIrql
+ mov eax, 1 ; return TRUE
+ mov byte ptr [ecx].FmOldIrql, dl ; Store OldIrql
+ fstRet ExTryToAcquireFastMutex
+
+tam20: pop ecx ; (ecx) = OldIrql
+ fstCall KfLowerIrql ; restore OldIrql
+tam25: xor eax, eax ; return FALSE
+ fstRet ExTryToAcquireFastMutex ; all done
+
+fstENDP ExTryToAcquireFastMutex
+
+
+;++
+;
+; VOID
+; FASTCALL
+; ExReleaseFastMutex (
+; IN PFAST_MUTEX FastMutex
+; )
+;
+; Routine description:
+;
+; This function releases ownership of the FastMutex
+;
+; Arguments:
+;
+; (ecx) FastMutex - Supplies a pointer to the fast mutex
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicFastCall ExReleaseFastMutex,1
+
+cPublicFpo 0,0
+ mov al, byte ptr [ecx].FmOldIrql ; (cl) = OldIrql
+
+ LOCK_ADD dword ptr [ecx].FmCount, 1 ; Remove our count
+ xchg ecx, eax ; (cl) = OldIrql
+ js short rfm05 ; if < 0, set event
+ jnz @KfLowerIrql@4 ; if != 0, don't set event
+
+rfm05: add eax, FmEvent
+ push ecx
+ stdCall _KeSetEventBoostPriority, <eax, 0>
+ pop ecx
+ jmp @KfLowerIrql@4
+
+
+fstENDP ExReleaseFastMutex
+
+
+;++
+;
+; VOID
+; HalpDisableAllInterrupts (VOID)
+;
+; Routine Description:
+;
+; This routine is called during a system crash. The hal needs all
+; interrupts disabled.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; None - all interrupts are masked off
+;
+;--
+
+cPublicProc _HalpDisableAllInterrupts,0
+cPublicFpo 0,0
+
+ ;
+ ; Mask interrupts off at PIC
+ ; (raising to high_level does not work on lazy irql implementation)
+ ;
+ mov eax, KiI8259MaskTable[HIGH_LEVEL*4]; get pic masks for the new irql
+ or eax, PCR[PcIDR] ; mask irqs which are disabled
+ SET_IRQ_MASK ; set 8259 masks
+
+ mov byte ptr PCR[PcIrql], HIGH_LEVEL ; set new irql
+
+ stdRET _HalpDisableAllInterrupts
+
+stdENDP _HalpDisableAllInterrupts
+
+
+
+ page ,132
+ subttl "Postponed Hardware Interrupt Dispatcher"
+;++
+;
+; VOID
+; HalpHardwareInterruptNN (
+; VOID
+; );
+;
+; Routine Description:
+;
+; These routines branch through the IDT to simulate the appropriate
+; hardware interrupt. They use the "INT nn" instruction to do this.
+;
+; Arguments:
+;
+; None.
+;
+; Returns:
+;
+; None.
+;
+; Environment:
+;
+; IRET frame is on the stack
+;
+;--
+cPublicProc _HalpHardwareInterruptTable
+cPublicFpo 0,0
+
+ public HalpHardwareInterrupt00
+HalpHardwareInterrupt00 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 0
+ ret
+
+ public HalpHardwareInterrupt01
+HalpHardwareInterrupt01 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 1
+ ret
+
+ public HalpHardwareInterrupt02
+HalpHardwareInterrupt02 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 2
+ ret
+
+ public HalpHardwareInterrupt03
+HalpHardwareInterrupt03 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 3
+ ret
+
+ public HalpHardwareInterrupt04
+HalpHardwareInterrupt04 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 4
+ ret
+
+ public HalpHardwareInterrupt05
+HalpHardwareInterrupt05 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 5
+ ret
+
+ public HalpHardwareInterrupt06
+HalpHardwareInterrupt06 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 6
+ ret
+
+ public HalpHardwareInterrupt07
+HalpHardwareInterrupt07 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 7
+ ret
+
+ public HalpHardwareInterrupt08
+HalpHardwareInterrupt08 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 8
+ ret
+
+ public HalpHardwareInterrupt09
+HalpHardwareInterrupt09 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 9
+ ret
+
+ public HalpHardwareInterrupt10
+HalpHardwareInterrupt10 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 10
+ ret
+
+ public HalpHardwareInterrupt11
+HalpHardwareInterrupt11 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 11
+ ret
+
+ public HalpHardwareInterrupt12
+HalpHardwareInterrupt12 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 12
+ ret
+
+ public HalpHardwareInterrupt13
+HalpHardwareInterrupt13 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 13
+ ret
+
+ public HalpHardwareInterrupt14
+HalpHardwareInterrupt14 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 14
+ ret
+
+ public HalpHardwareInterrupt15
+HalpHardwareInterrupt15 label byte
+ifdef IRQL_METRICS
+ lock inc HalHardwareIntCount
+endif
+ int PRIMARY_VECTOR_BASE + 15
+ ret
+stdENDP _HalpHardwareInterruptTable
+
+ page ,132
+ subttl "Interrupt Controller Chip Initialization"
+;++
+;
+; VOID
+; HalpInitializePICs (
+; )
+;
+; Routine Description:
+;
+; This routine sends the 8259 PIC initialization commands and
+; masks all the interrupts on 8259s.
+;
+; Arguments:
+;
+; None
+;
+; Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalpInitializePICs ,0
+
+ push esi ; save caller's esi
+ cli ; disable interrupt
+ lea esi, PICsInitializationString
+ lodsw ; (AX) = PIC port 0 address
+Hip10: movzx edx, ax
+ outsb ; output ICW1
+ IODelay
+ inc edx ; (DX) = PIC port 1 address
+ outsb ; output ICW2
+ IODelay
+ outsb ; output ICW3
+ IODelay
+ outsb ; output ICW4
+ IODelay
+ mov al, 0FFH ; mask all 8259 irqs
+ out dx,al ; write mask to PIC
+ lodsw
+ cmp ax, 0 ; end of init string?
+ jne short Hip10 ; go init next PIC
+
+ mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
+ out PIC1_PORT0, al
+
+ mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
+ out PIC2_PORT0, al
+
+ pop esi ; restore caller's esi
+ sti ; enable interrupt
+ stdRET _HalpInitializePICs
+stdENDP _HalpInitializePICs
+
+
+_TEXT ends
+
+ end
diff --git a/private/ntos/nthals/halncr/i386/ncrlarc.c b/private/ntos/nthals/halncr/i386/ncrlarc.c
new file mode 100644
index 000000000..e486fcdbc
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrlarc.c
@@ -0,0 +1,392 @@
+/*++
+
+Copyright (c) 1992 NCR Corporation
+
+Module Name:
+
+ ncrlarc.c
+
+Abstract:
+
+
+Author:
+
+ Rick Ulmer
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+//#include "halp.h"
+#include "ki.h"
+#include "stdio.h"
+#include "ncr.h"
+#include "ncrcat.h"
+#include "ncrsus.h"
+
+extern PPROCESSOR_BOARD_INFO SUSBoardInfo;
+extern ULONG NCRLogicalDyadicProcessorMask;
+extern ULONG NCRLogicalQuadProcessorMask;
+extern ULONG NCRLogicalNumberToPhysicalMask[];
+extern ULONG NCRExistingQuadProcessorMask;
+extern ULONG NCRActiveProcessorMask;
+
+extern ULONG NCRLarcPageMask;
+
+#define PASS_LARC_TEST 1
+#define LARC_TEST 2
+#define LARC_BANK0 4
+#define LARC_BANK1 8
+#define LARC_8MB 0x80
+#define LARC_2MB 0x40
+#define LARC_PAGES 8
+#define LARC_TIMEOUT 40000 // This is what the UNIX Guys use.
+
+
+ULONG NCRLarcEnabledPages[8] = {0}; // LARC size by Voyager slot
+
+
+PCHAR
+NCRUnicodeToAnsi(
+ IN PUNICODE_STRING UnicodeString,
+ OUT PCHAR AnsiBuffer,
+ IN ULONG MaxAnsiLength
+ )
+{
+ PCHAR Dst;
+ PWSTR Src;
+ ULONG Length;
+
+ Length = UnicodeString->Length / sizeof( WCHAR );
+ if (Length >= MaxAnsiLength) {
+ Length = MaxAnsiLength - 1;
+ }
+ Src = UnicodeString->Buffer;
+ Dst = AnsiBuffer;
+ while (Length--) {
+ *Dst++ = (UCHAR)*Src++;
+ }
+ *Dst = '\0';
+ return AnsiBuffer;
+}
+
+
+
+VOID
+HalpInitializeLarc (
+ )
+/*++
+
+Routine Description:
+ Initialize any Larc's that may exist on any Quad processor boards
+
+Arguments:
+ none.
+
+Return Value:
+ none.
+
+--*/
+
+{
+ PLIST_ENTRY ModuleListHead;
+ PLIST_ENTRY Next;
+ PLDR_DATA_TABLE_ENTRY DataTableEntry;
+ CHAR Buffer[256];
+ UCHAR AnsiBuffer[ 32 ];
+ ULONG i;
+ PHYSICAL_ADDRESS kernel_physical;
+ ULONG base;
+ UCHAR addr[2];
+ CAT_CONTROL cat_control;
+ LONG status;
+ UCHAR data;
+ UCHAR enable;
+ BOOLEAN larc_found = FALSE;
+ ULONG timeout_count;
+ LONG pages, page, banks;
+
+ DBGMSG(("HalpInitializeLarc: KeLoaderBlock = 0x%x\n",KeLoaderBlock));
+
+ //
+ // Dump the loaded module list
+ //
+
+ if (KeLoaderBlock != NULL) {
+ ModuleListHead = &KeLoaderBlock->LoadOrderListHead;
+
+ } else {
+ DBGMSG(("HalpInitializeLarc: KeLoaderBlock is NULL returning...\n"));
+ return;
+ }
+
+ Next = ModuleListHead->Flink;
+
+ if (Next != NULL) {
+
+ i = 0;
+
+ DBGMSG(("HalpInitializeLarc: ModuleListHead = 0x%x\n", ModuleListHead));
+
+ DBGMSG(("HalpInitializeLarc: Next = 0x%x\n", Next));
+ while (Next != ModuleListHead) {
+
+ DataTableEntry = CONTAINING_RECORD(Next,
+ LDR_DATA_TABLE_ENTRY,
+ InLoadOrderLinks);
+
+ sprintf (Buffer, "HalpInitializeLarc: Name: %s Base: 0x%x\n",
+ NCRUnicodeToAnsi(&DataTableEntry->BaseDllName,AnsiBuffer,sizeof(AnsiBuffer)),
+ DataTableEntry->DllBase
+ );
+
+ DBGMSG((Buffer));
+
+ if (strncmp(AnsiBuffer,"ntoskrnl",8) == 0) {
+ kernel_physical = MmGetPhysicalAddress(DataTableEntry->DllBase);
+
+ DBGMSG(("HalpInitializeLarc: Found kernel at Virtual address 0x%x and Physical Address 0x%x\n",
+ DataTableEntry->DllBase,
+ kernel_physical.LowPart));
+ break;
+ }
+
+ if (i++ == 30) {
+ DBGMSG(("HalpInitializeLarc: ModuleList too long breaking out\n"));
+ break;
+ }
+ Next = Next->Flink;
+ DBGMSG(("HalpInitializeLarc: Next = 0x%x\n", Next));
+ }
+ }
+
+ base = 0xffc00000 & kernel_physical.LowPart; // round down to 4MB boundary
+
+ addr[0] = base >> 24;
+ addr[1] = base >> 16;
+
+//
+// Lets check for larc info
+//
+
+ DBGMSG(("HalpInitializeLarc: Lets look to Quad boards and larc\n"));
+
+ for (i = 0; i < SUSBoardInfo->NumberOfBoards; i++ ) {
+ if (SUSBoardInfo->QuadData[i].Type != QUAD) {
+ continue;
+ }
+ switch (SUSBoardInfo->QuadData[i].Slot) {
+ case 1:
+ cat_control.Module = QUAD_BB0;
+ break;
+ case 2:
+ cat_control.Module = QUAD_BB1;
+ break;
+ case 3:
+ cat_control.Module = QUAD_BB2;
+ break;
+ case 4:
+ cat_control.Module = QUAD_BB3;
+ break;
+ }
+ cat_control.Asic = QABC;
+
+ //
+ // get LARC bank info
+ //
+
+ cat_control.Command = READ_SUBADDR;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x3;
+ status = HalCatBusIo(&cat_control, &enable);
+
+ if (((enable & (LARC_BANK0|LARC_BANK1)) == 0) || (status != CATNOERR)) {
+ //
+ // no LARC on this board
+ //
+ continue;
+ }
+
+ larc_found = TRUE;
+
+ DBGMSG(("HalpInitializeLarc: Found LARC in Slot %d, with Self_test Reg = 0x%x\n",
+ SUSBoardInfo->QuadData[i].Slot,
+ enable));
+ //
+ // Disable all 4MB pages
+ //
+
+
+ data = 0;
+ cat_control.Command = WRITE_SUBADDR;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x0;
+ status = HalCatBusIo(&cat_control, &data);
+
+ //
+ // Set new LARC base
+ //
+
+ cat_control.NumberOfBytes = 2;
+ cat_control.Address = 0x1;
+ status = HalCatBusIo(&cat_control, addr);
+
+ //
+ // now lets test the LARC
+ //
+
+ enable |= LARC_TEST; // Run LARC test
+
+ cat_control.Command = WRITE_SUBADDR;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x3;
+ status = HalCatBusIo(&cat_control, &enable);
+ }
+
+
+ if (!larc_found) {
+ return;
+ }
+
+ //
+ // lets wait for all LARC test to complete
+ //
+
+ DBGMSG(("HalpInitializeLarc: Now waiting for LARC self-test to complete.\n"));
+
+ for (i = 0; i < SUSBoardInfo->NumberOfBoards; i++ ) {
+ if (SUSBoardInfo->QuadData[i].Type != QUAD) {
+ continue;
+ }
+ switch (SUSBoardInfo->QuadData[i].Slot) {
+ case 1:
+ cat_control.Module = QUAD_BB0;
+ break;
+ case 2:
+ cat_control.Module = QUAD_BB1;
+ break;
+ case 3:
+ cat_control.Module = QUAD_BB2;
+ break;
+ case 4:
+ cat_control.Module = QUAD_BB3;
+ break;
+ }
+ cat_control.Asic = QABC;
+
+ cat_control.Command = READ_SUBADDR;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x3;
+ timeout_count = 0;
+
+ do {
+ status = HalCatBusIo(&cat_control, &enable);
+ if (status != CATNOERR) {
+ return;
+ }
+ if ((enable & (LARC_BANK0|LARC_BANK1)) == 0) {
+ break; // no LARC on this QUAD board
+ }
+ } while ((enable & LARC_TEST) && (++timeout_count < LARC_TIMEOUT));
+ DBGMSG(("HalpInitializeLarc: LARC in slot %d, complete: enable = 0x%x, timeout_count =%d\n",
+ SUSBoardInfo->QuadData[i].Slot, enable, timeout_count));
+ }
+ DBGMSG(("HalpInitializeLarc: All LARCS test complete.....\n"));
+
+
+
+ //
+ // Lets enable the LARCS
+ //
+
+ DBGMSG(("HalpInitializeLarc: Now Enabling LARC pages\n"));
+
+ for (i = 0; i < SUSBoardInfo->NumberOfBoards; i++ ) {
+ if (SUSBoardInfo->QuadData[i].Type != QUAD) {
+ continue;
+ }
+ switch (SUSBoardInfo->QuadData[i].Slot) {
+ case 1:
+ cat_control.Module = QUAD_BB0;
+ break;
+ case 2:
+ cat_control.Module = QUAD_BB1;
+ break;
+ case 3:
+ cat_control.Module = QUAD_BB2;
+ break;
+ case 4:
+ cat_control.Module = QUAD_BB3;
+ break;
+ }
+ cat_control.Asic = QABC;
+
+ cat_control.Command = READ_SUBADDR;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x3;
+ status = HalCatBusIo(&cat_control, &enable);
+
+ if (((enable & (LARC_BANK0|LARC_BANK1)) == 0) || (status != CATNOERR)) {
+ //
+ // no LARC on this board
+ //
+ continue;
+ }
+
+ if ((enable & PASS_LARC_TEST) == 0) {
+ //
+ // this LARC did not pass self-test
+ //
+ continue;
+ }
+
+
+ if (enable & LARC_BANK0) {
+ banks = 1;
+ } else {
+ banks = 0;
+ }
+
+ if (enable & LARC_BANK1) {
+ banks += 1;
+ }
+
+ if (enable & LARC_8MB) {
+ pages = 4 * banks;
+ } else {
+ pages = banks;
+ }
+
+ cat_control.Command = READ_SUBADDR;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x0;
+ status = HalCatBusIo(&cat_control, &enable);
+
+ DBGMSG(("HalpInitializeLarc: banks = %d, pages = %d\n",banks, pages));
+
+ NCRLarcEnabledPages[SUSBoardInfo->QuadData[i].Slot-1] = pages;
+
+ for (page = 1; pages > 0; page <<= 1, pages--) {
+ enable |= page;
+ }
+
+ enable &= NCRLarcPageMask; // now apply enable mask
+
+ cat_control.Command = WRITE_SUBADDR;
+
+ DBGMSG(("HalpInitializeLarc: Slot %d, enable Mask = 0x%x\n",
+ SUSBoardInfo->QuadData[i].Slot,
+ enable));
+
+ status = HalCatBusIo(&cat_control, &enable);
+ }
+
+ DBGMSG(("HalpInitializeLarc: Done\n"));
+}
+
+
+
diff --git a/private/ntos/nthals/halncr/i386/ncrlock.asm b/private/ntos/nthals/halncr/i386/ncrlock.asm
new file mode 100644
index 000000000..9ee3b35bd
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrlock.asm
@@ -0,0 +1,103 @@
+
+ title "NCR Lock Routines"
+;++
+;
+; Copyright (c) 1992 NCR - MSBU
+;
+; Module Name:
+;
+; ncrlock.asm
+;
+; Abstract:
+;
+; This module implements the code necessary to perform atomic
+; operations specific to the NCR - MSBU platforms.
+;
+; Author:
+;
+; Richard R. Barton (o-richb) 20 Mar 1992
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+;
+;--
+
+.386p
+include callconv.inc ; calling convention macros
+ .xlist
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "Locked Or"
+;++
+;
+; Routine Description:
+;
+; This function atomically ors the second argument with the given
+; pointer to an unsigned long.
+;
+; Arguments:
+;
+; Pointer to unsigned long.
+;
+; Thing to or it with.
+;
+; Return Value:
+;
+; None
+;
+;--
+
+cPublicProc _NCRLockedOr ,2
+
+ mov ecx, 1*4[esp]
+ mov eax, 2*4[esp]
+
+ lock or [ecx], eax
+
+ stdRET _NCRLockedOr
+
+stdENDP _NCRLockedOr
+
+
+ page ,132
+ subttl "Locked Exchange and Add"
+;++
+;
+; Routine Description:
+;
+; This function atomically adds the second argument with the given
+; pointer to an unsigned long.
+;
+; Arguments:
+;
+; Pointer to unsigned long.
+;
+; Thing to add it with.
+;
+; Return Value:
+;
+; Return value is previous value pointed to by 2nd argument
+;
+;--
+
+cPublicProc _NCRLockedExchangeAndAdd ,2
+
+ mov ecx, 1*4[esp]
+ mov eax, 2*4[esp]
+
+; lock xadd [ecx], eax
+ db 0F0H, 0FH, 0C1H, 01H
+
+ stdRET _NCRLockedExchangeAndAdd
+
+stdENDP _NCRLockedExchangeAndAdd
+
+_TEXT ends
+ end
diff --git a/private/ntos/nthals/halncr/i386/ncrmcabs.c b/private/ntos/nthals/halncr/i386/ncrmcabs.c
new file mode 100644
index 000000000..9d37fc7f6
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrmcabs.c
@@ -0,0 +1,243 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ ncrmcabus.c
+
+Abstract:
+
+Author:
+
+Environment:
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+
+
+ULONG
+HalpGetMCAInterruptVector(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ );
+
+ULONG
+HalpGetSMCAInterruptVector(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ );
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(PAGE,HalpGetMCAInterruptVector)
+#endif
+
+
+ULONG
+HalpGetMCAInterruptVector(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the system interrupt vector and IRQL level
+ corresponding to the specified bus interrupt level and/or vector. The
+ system interrupt vector and IRQL are suitable for use in a subsequent call
+ to KeInitializeInterrupt.
+
+Arguments:
+
+ BusHandle - Per bus specific structure
+
+ Irql - Returns the system request priority.
+
+ Affinity - Returns the system wide irq affinity.
+
+Return Value:
+
+ Returns the system interrupt vector corresponding to the specified device.
+
+--*/
+{
+ UNREFERENCED_PARAMETER( BusInterruptVector );
+
+ //
+ // On standard PCs, IRQ 2 is the cascaded interrupt, and it really shows
+ // up on IRQ 9.
+ //
+ if (BusInterruptLevel == 2) {
+ BusInterruptLevel = 9;
+ }
+
+ if (BusInterruptLevel > 15) {
+ return 0;
+ }
+
+ //
+ // Get parent's translation from here..
+ //
+
+ // RMU
+ BusInterruptVector = BusInterruptLevel;
+
+ return BusHandler->ParentHandler->GetInterruptVector (
+ BusHandler->ParentHandler,
+ RootHandler,
+ BusInterruptLevel,
+ BusInterruptVector,
+ Irql,
+ Affinity
+ );
+}
+
+
+
+ULONG
+HalpGetSMCAInterruptVector(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the system interrupt vector and IRQL level
+ corresponding to the specified bus interrupt level and/or vector. The
+ system interrupt vector and IRQL are suitable for use in a subsequent call
+ to KeInitializeInterrupt.
+
+Arguments:
+
+ BusHandle - Per bus specific structure
+
+ Irql - Returns the system request priority.
+
+ Affinity - Returns the system wide irq affinity.
+
+Return Value:
+
+ Returns the system interrupt vector corresponding to the specified device.
+
+--*/
+{
+ UNREFERENCED_PARAMETER( BusInterruptVector );
+
+ //
+ // On standard PCs, IRQ 2 is the cascaded interrupt, and it really shows
+ // up on IRQ 9.
+ //
+ if (BusInterruptLevel == 2) {
+ BusInterruptLevel = 9;
+ }
+
+ if (BusInterruptLevel > 15) {
+ return 0;
+ }
+
+ //
+ // Get parent's translation from here..
+ //
+
+ // RMU
+ BusInterruptVector = BusInterruptLevel + 0x10;
+
+ return BusHandler->ParentHandler->GetInterruptVector (
+ BusHandler->ParentHandler,
+ RootHandler,
+ BusInterruptLevel,
+ BusInterruptVector,
+ Irql,
+ Affinity
+ );
+}
+
+
+
+BOOLEAN
+HalpTranslateSMCBusAddress(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This function translates a SMC bus-relative address space and address into
+ a system physical address.
+
+Arguments:
+
+ BusAddress - Supplies the bus-relative address
+
+ AddressSpace - Supplies the address space number.
+ Returns the host address space number.
+
+ AddressSpace == 0 => memory space
+ AddressSpace == 1 => I/O space
+
+ TranslatedAddress - Supplies a pointer to return the translated address
+
+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
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER( BusHandler );
+ UNREFERENCED_PARAMETER( RootHandler );
+
+ if (BusAddress.HighPart != 0) {
+ // Unsupported range
+ return (FALSE);
+ }
+
+ switch (*AddressSpace) {
+ case 0: // MEMORY space
+ TranslatedAddress->LowPart = BusAddress.LowPart;
+ TranslatedAddress->HighPart = 0;
+ break;
+ case 1: // IO space
+ TranslatedAddress->LowPart = BusAddress.LowPart | 0x00010000;
+ TranslatedAddress->HighPart = 0;
+ break;
+ default: // UNKOWN address space
+ return FALSE;
+ }
+
+ return(TRUE);
+}
diff --git a/private/ntos/nthals/halncr/i386/ncrmem.h b/private/ntos/nthals/halncr/i386/ncrmem.h
new file mode 100644
index 000000000..aec0a83b6
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrmem.h
@@ -0,0 +1,494 @@
+/*++
+
+Copyright (C) 1992 NCR Corporation
+
+
+Module Name:
+
+ ncrmem.h
+
+Author:
+
+Abstract:
+
+ System equates for dealing with the NCR Memory boads.
+
+++*/
+
+#ifndef _NCRMEM_
+#define _NCRMEM_
+
+
+/*
+ * Memory module
+ */
+
+#define NUM_MEMORY_CARDS_L5 2
+#define NUM_MMC_PER_CARD 1
+#define NUM_MMA_PER_CARD 1
+#define NUM_MMD_PER_CARD 4
+
+#define NUM_POSSIBLE_SIMMS 48
+#define EDC_FIELD (32+7)
+#define INTERLEAVES_PER_BOARD 2
+#define MAX_BANKS 2
+
+
+/* defines for union referencing */
+
+#define CONFIG0 CatRegisters.CatRegs.Config0
+#define CONFIG1 CatRegisters.CatRegs.Config1
+#define CONTROL2 CatRegisters.CatRegs.Control2
+#define CONFIG3 CatRegisters.CatRegs.Config3
+#define CONFIG4 CatRegisters.CatRegs.Config4
+#define CONFIG5 CatRegisters.CatRegs.Config5
+#define SUBADDRESS6 CatRegisters.CatRegs.SubAddress6
+#define SUBADDRESS7 CatRegisters.CatRegs.SubAddress7
+#define CONFIG8 CatRegisters.CatRegs.Config8
+#define CONFIG9 CatRegisters.CatRegs.Config9
+#define CONFIGA CatRegisters.CatRegs.ConfigA
+#define CONFIGB CatRegisters.CatRegs.ConfigB
+#define CONFIGC CatRegisters.CatRegs.ConfigC
+#define CONFIGD CatRegisters.CatRegs.ConfigD
+#define CONFIGE CatRegisters.CatRegs.ConfigE
+#define StatusF CatRegisters.CatRegs.StatusF
+
+
+
+/*
+ *
+ * Description : Config registers for the Magellan Memory Address 1 ASIC.
+ */
+
+/* Main CAT registers */
+#define MMA1_Config 0x00
+# define MMA1_128bit 0x01
+# define MMA1_I0TwoBanks 0x10
+# define MMA1_I1TwoBanks 0x20
+#define MMA1_ParityTest 0x01
+# define MMA1_ParB3 0x80
+# define MMA1_ParB2 0x40
+# define MMA1_ParB1 0x20
+# define MMA1_ParB0 0x10
+# define MMA1_ParA3 0x08
+# define MMA1_ParA2 0x04
+# define MMA1_ParA1 0x02
+# define MMA1_ParA0 0x01
+
+#define MMA1_Byte_A_Error 0x0d /* Byte in Error Register */
+#define MMA1_Byte_B_Error 0x0e /* Byte in Error Register */
+# define MMA1_Prty_Byte3 0x08 /* Parity error in byte 3 */
+# define MMA1_Prty_Byte2 0x04 /* Parity error in byte 2 */
+# define MMA1_Prty_Byte1 0x02 /* Parity error in byte 1 */
+# define MMA1_Prty_Byte0 0x01 /* Parity error in byte 0 */
+
+#define MMA1_Subport_Data 0x03
+#define MMA1_Subport_Addr 0x06
+
+/* addr0 decodes MMA */
+#define MEM 0x02
+#define MOP 0x01
+#define ADDR_MASK 0xfffffff8 /* lowest 3 bits are not valid */
+#define BYTE0 0x01
+#define BYTE1 0x02
+#define BYTE2 0x04
+#define BYTE3 0x08
+
+#define BANK1 0x10 /* bit 4 of interleave error address */
+
+/* macros */
+#define MEM_BIT(_x) ( (((_x) & MEM) == MEM) ? 0x1 : 0x0 )
+#define MOP_BIT(_x) ( (((_x) & MOP) == MOP) ? 0x1 : 0x0 )
+
+/* Subaddress CAT Extension registers */
+#define MMA1_Sub_Start 0x00 /* First sub address extension regs */
+#define MMA1_Sub_Size 32 /* The number of subaddress extension regs */
+#define MMA1_BusB_Sub_Start 0x10 /* First Bus B register */
+#define MMA1_Bus_Sub_Size 0x0C /* Size of Bus specific registers */
+#define MMA1_Interleave_0_Start 0x0D /* First Byte of Interleave 0 */
+#define MMA1_Interleave_1_Start 0x1C /* First Byte of Interleave 1 */
+#define MMA1_Interleave_Size 0x04 /* Size of Interleave registers */
+//
+// (ts) 2/24/95 Changes for Disco Memory Support
+//
+
+#define DMAC1_Sub_Start (MMA1_Sub_Start+MMA_SubAddress)
+#define DMAC1_BusB_Sub_Start (MMA1_BusB_Sub_Start+MMA_SubAddress)
+#define DMAC1_Interleave_0_Start (MMA1_Interleave_0_Start+MMA_SubAddress)
+#define DMAC1_Interleave_1_Start (MMA1_Interleave_Size+MMA_SubAddress)
+/* For the DMAC1 the MMA1 direct address registers are at 0x40 - 0x4f
+ * For the DMAC1 the MMA1 subaddress registers are at 0x20 - 0x3f
+ */
+
+#define MMA_Direct 0x40
+#define MMA_SubAddress 0x20
+
+
+typedef struct _MMA1_INFO {
+ ULONG JtagId;
+ UCHAR Flag;
+ union {
+ CAT_REGISTERS CatRegs;
+ struct {
+ UCHAR Dummy0;
+ UCHAR ParityTest;
+ UCHAR Dummy2;
+ UCHAR Dummy3;
+ UCHAR InterleaveLA0;
+ UCHAR InterleaveLA1;
+ UCHAR Dummy6;
+ UCHAR IoStartAddress;
+ UCHAR Dummy8;
+ UCHAR IoEndAddress;
+ UCHAR I1StartAddress;
+ UCHAR DummyB;
+ UCHAR I1EndAddress;
+ UCHAR ErrorByteA;
+ UCHAR ErrorByteB;
+ UCHAR DummyF;
+ } MmaRegisters;
+ } CatRegisters;
+ UCHAR LastBusAAddressError0; /* for PAR_INT diagnosis */
+ UCHAR LastBusAAddressError1; /* for PAR_INT diagnosis */
+ UCHAR LastBusAAddressError2; /* for PAR_INT diagnosis */
+ UCHAR LastBusAAddressError3; /* for PAR_INT diagnosis */
+
+ UCHAR GoodBusAAddressError0; /* for PAR_INT diagnosis */
+ UCHAR GoodBusAAddressError1; /* for PAR_INT diagnosis */
+ UCHAR GoodBusAAddressError2; /* for PAR_INT diagnosis */
+ UCHAR GoodBusAAddressError3; /* for PAR_INT diagnosis */
+
+ UCHAR BusAErrorAddress0; /* for ERROR_L diagnosis */
+ UCHAR BusAErrorAddress1; /* for ERROR_L diagnosis */
+ UCHAR BusAErrorAddress2; /* for ERROR_L diagnosis */
+ UCHAR BusAErrorAddress3; /* for ERROR_L diagnosis */
+
+ UCHAR Interleave0Error0;
+ UCHAR Interleave0Error1;
+ UCHAR Interleave0Error2;
+ UCHAR Interleave0Error3;
+
+ UCHAR LastBusBAddressError0; /* for PAR_INT diagnosis */
+ UCHAR LastBusBAddressError1; /* for PAR_INT diagnosis */
+ UCHAR LastBusBAddressError2; /* for PAR_INT diagnosis */
+ UCHAR LastBusBAddressError3; /* for PAR_INT diagnosis */
+
+ UCHAR GoodBusBAddressError0; /* for PAR_INT diagnosis */
+ UCHAR GoodBusBAddressError1; /* for PAR_INT diagnosis */
+ UCHAR GoodBusBAddressError2; /* for PAR_INT diagnosis */
+ UCHAR GoodBusBAddressError3; /* for PAR_INT diagnosis */
+
+ UCHAR BusBErrorAddress0; /* for ERROR_L diagnosis */
+ UCHAR BusBErrorAddress1; /* for ERROR_L diagnosis */
+ UCHAR BusBErrorAddress2; /* for ERROR_L diagnosis */
+ UCHAR BusBErrorAddress3; /* for ERROR_L diagnosis */
+
+ UCHAR Interleave1Error0;
+ UCHAR Interleave1Error1;
+ UCHAR Interleave1Error2;
+ UCHAR Interleave1Error3;
+
+ UCHAR FirstError[2]; /* new for DMAC1 */
+ UCHAR SecondError[2]; /* new for DMAC1 */
+ UCHAR DisconnectGroups[2]; /* new for DMAC1 */
+ UCHAR BusyIndication[2]; /* new for DMAC1 */
+
+} MMA1_INFO, *PMMA1_INFO;
+
+
+/* defines for union referencing */
+#define BYTE_ERROR_A CatRegisters.MmaRegisters.ErrorByteA
+#define BYTE_ERROR_B CatRegisters.MmaRegisters.ErrorByteB
+
+
+
+/*
+ *
+ * Description : Config registers for the Magellan Memory Data 1 ASIC.
+ *
+ */
+
+
+/* Main CAT registers */
+
+#define MMC1_Subport_Data 0x03
+#define MMC1_Subport_Addr 0x06
+
+#define MMC1_Parity_Status_A 0x00
+#define MMC1_Parity_Status_B 0x10
+# define MMC1_Addr_Parity_Err 0x02
+# define MMC1_Data_Parity_Err 0x01
+
+#define MMC1_Config1 0x08
+# define MMC1_SBErr_DetectDisable 0x04
+# define MMC1_LBEDIS_DetectDisable 0x40
+
+/* Subaddress space */
+#define MMC1_Inter_0_Status 0x09
+#define MMC1_Inter_1_Status 0x19
+# define MMC1_Clear_Interleave 0x01
+
+#define MMC1_Interleave_0_Info_0 0x0A
+#define MMC1_Interleave_1_Info_0 0x1A
+# define MMC1_BusA_Cpu0 0x01
+# define MMC1_BusA_Cpu1 0x02
+# define MMC1_BusA_Cpu2 0x04
+# define MMC1_BusA_Cpu3 0x08
+# define MMC1_BusB_Cpu0 0x10
+# define MMC1_BusB_Cpu1 0x20
+# define MMC1_BusB_Cpu2 0x40
+# define MMC1_BusB_Cpu3 0x80
+
+#define MMC1_Interleave_0_Info_1 0x0B
+#define MMC1_Interleave_1_Info_1 0x1B
+
+
+#define MMC1_Intr0_Single_Bit_Status 0x0D
+#define MMC1_Intr1_Single_Bit_Status 0x1D
+# define MMC1_SBerr 0x01
+# define MMC1_SB_LPE_0 0x02
+# define MMC1_SB_LPE_1 0x04
+# define MMC1_SB_LPE_2 0x08
+# define MMC1_SB_ErrInt 0x40
+# define MMC1_ErrStore 0x80
+
+#define MMC1_Intr0_Single_Bit_Info_0 0x0E
+#define MMC1_Intr0_Single_Bit_Info_1 0x0F
+#define MMC1_Intr1_Single_Bit_Info_0 0x1E
+#define MMC1_Intr1_Single_Bit_Info_1 0x1F
+
+
+/* Subaddress CAT Extension registers */
+#define MMC1_Sub_Start 0x00 /* First sub address extension regs */
+#define MMC1_Sub_Size 32 /* The number of subaddress extension regs */
+#define MMC1_BusB_Sub_Start 0x10 /* First sub address for Bus B */
+#define MMC1_Bus_Sub_Size 0x09 /* Size of sub address for Bus */
+#define MMC1_Interleave_0_Start 0x09 /* First sub address for Interleave 0 */
+#define MMC1_Interleave_1_Start 0x19 /* First sub address for Interleave 1 */
+#define MMC1_Interleave_Size 0x07 /* Size of interleave space */
+
+/* Error interrupt status MMC */
+#define MBIT 0x01
+#define MOWN 0x02
+#define ILV_LOCK 0x04
+#define LBE 0x40
+#define LPE_MASK 0x38
+#define LPE_SHIFT 3
+#define ERR_STORE 0x80
+
+#define LPE_BITS(_x) ( (int)((_x) & LPE_MASK) >> LPE_SHIFT )
+/* Interrupt info 0 */
+#define SB_ID_MASK 0xf0
+#define SB_ID_SHIFT 4
+#define SA_ID_MASK 0x0f
+
+/* Interrupt info 1 */
+#define LST8 0x01
+#define LST8_SHIFT 8
+#define SA_MID 0x02
+#define SB_MID 0x04
+#define E_AP256 0x08
+#define E_BOP_MASK 0xf0
+
+/* error status */
+#define CO_ERR 0x10
+#define CO_DPE 0x08
+#define LK_LPE 0x04
+
+#define ERROR_L_MASK (CO_ERR | CO_DPE | LK_LPE | MOWN | MBIT)
+
+/* last_control_X0 decodes MMC */
+#define MID 0x10
+#define ID_MASK 0x0f
+#define MACK_MASK 0x60
+#define MACK_SHIFT 5
+
+/* last_control_X1 decodes MMC */
+#define LOCKG 0x80
+#define LOCKL 0x40
+#define MIC 0x20
+#define AP256 0x10
+#define BOP_MASK 0x0f
+
+/* macros */
+#define MIC_BIT(_x) ( (((_x) & MIC) == MIC) ? 0x1 : 0x0 )
+#define MACK_BITS(_x) ( (int)((_x) & MACK_MASK) >> MACK_SHIFT )
+
+typedef struct _MMC1_INFO {
+ ULONG JtagId;
+ UCHAR Flag;
+ union {
+ CAT_REGISTERS CatRegs;
+ struct {
+ UCHAR Dummy0;
+ UCHAR Dummy1;
+ UCHAR Dummy2;
+ UCHAR Dummy3;
+ UCHAR Dummy4;
+ UCHAR Dummy5;
+ UCHAR Dummy6;
+ UCHAR Dummy7;
+ UCHAR Mode1;
+ UCHAR ActiveProcessors;
+ UCHAR Mode2;
+ UCHAR RefreshCount;
+ UCHAR RASActiveCount;
+ UCHAR DummyD;
+ UCHAR DummyE;
+ UCHAR DummyF;
+ } MmcRegisters;
+ } CatRegisters;
+ UCHAR ParityInterruptAStatus; /* MEM module detectd parity */
+ UCHAR LastControlA0; /* for PAR_INT diagnosis */
+ UCHAR LastControlA1; /* for PAR_INT diagnosis */
+ UCHAR GoodControlA0; /* for PAR_INT diagnosis */
+ UCHAR GoodControlA1; /* for PAR_INT diagnosis */
+ UCHAR ErrorAStatus; /* MEM module generated ERROR_L */
+ UCHAR ErrorA0; /* for ERROR_L diagnosis */
+ UCHAR ErrorA1; /* for ERROR_L diagnosis */
+ UCHAR ErrorAId; /* MIC timeout ERROR_L */
+ UCHAR Interleave0Status;
+ UCHAR Interleave0Info0;
+ UCHAR Interleave0Info1;
+ UCHAR Interleave0Lst;
+ UCHAR SingleInterruptI0Status;
+ UCHAR SingleInterruptI00;
+ UCHAR SingleInterruptI01;
+ UCHAR ParityInterruptBStatus; /* MEM module detectd parity */
+ UCHAR LastControlB0; /* for PAR_INT diagnosis */
+ UCHAR LastControlB1; /* for PAR_INT diagnosis */
+ UCHAR GoodControlB0; /* for PAR_INT diagnosis */
+ UCHAR GoodControlB1; /* for PAR_INT diagnosis */
+ UCHAR ErrorBStatus; /* MEM module generated ERROR_L */
+ UCHAR ErrorB0; /* for ERROR_L diagnosis */
+ UCHAR ErrorB1; /* for ERROR_L diagnosis */
+ UCHAR ErrorBId; /* MIC timeout ERROR_L */
+ UCHAR Interleave1Status;
+ UCHAR Interleave1Info0;
+ UCHAR Interleave1Info1;
+ UCHAR Interleave1Lst;
+ UCHAR SingleInterruptI1Status;
+ UCHAR SingleInterruptI10;
+ UCHAR SingleInterruptI11;
+//
+// (ts) 2/24/95 Changes for Disco Memory Support
+//
+ UCHAR FirstError[2]; /* new for DMAC1 */
+ UCHAR SecondError[2]; /* new for DMAC1 */
+ UCHAR DisconnectGroups[2]; /* new for DMAC1 */
+ UCHAR BusyIndication[2]; /* new for DMAC1 */
+} MMC1_INFO, *PMMC1_INFO;
+
+
+/*
+ * Description : Config registers for the Magellan Memory Data 1 ASIC.
+ *
+ */
+
+
+/* Main CAT registers */
+
+#define MMD1_TestMode 0x04
+# define MMD1_OddPar 0x20 /* gen parity error */
+
+#define MMD1_Interleave0_Error 0x3 /* Interleave error register */
+# define MMD1_Intro_Line0_Sbe 0x08 /* single bit error */
+# define MMD1_Intro_Line0_Mbe 0x04 /* multiple-bit error */
+# define MMD1_Intro_Line1_Sbe 0x02 /* single bit error */
+# define MMD1_Intro_Line1_Mbe 0x01 /* multiple-bit error */
+
+#define MMD1_Interleave1_Error 0x8 /* Interleave error register */
+# define MMD1_Intr1_Line0_Sbe 0x08 /* single bit error */
+# define MMD1_Intr1_Line0_Mbe 0x04 /* multiple-bit error */
+# define MMD1_Intr1_Line1_Sbe 0x02 /* single bit error */
+# define MMD1_Intr1_Line1_Mbe 0x01 /* multiple-bit error */
+
+#define ECCERROR 0x20
+#define DATAPERR 0x02
+#define PERR_BITS 0x03
+
+#define MERR_ML1 0x08
+#define SERR_ML1 0x04
+#define MERR_ML0 0x02
+#define SERR_ML0 0x01
+
+#define MMD1_ECC_DIAG 0x05 /* ECC Diagnostic register */
+
+#define MMD1_Syn_Diag_0 0x09 /* ECC Syndrome register */
+#define MMD1_Syn_Diag_1 0x0a /* ECC Syndrome register */
+#define MMD1_Syn_Diag_2 0x0b /* ECC Syndrome register */
+#define MMD1_Syn_Diag_3 0x0c /* ECC Syndrome register */
+# define MMD1_CHK_MASK 0x7f /* check bit mask */
+
+#define MMD1_Bus_B_Parity 0x0d /* bus B Parity error */
+#define MMD1_Bus_A_Parity 0x0e /* bus A Parity error */
+# define MMD1_High_Byte 0x02 /* bus parity on high byte */
+# define MMD1_Low_Byte 0x01 /* bus parity on low byte */
+
+#define MMD1_STATUS 0x0f
+# define MMD1_Cat_Stuff 0x09 /* cat bus stuff dont change */
+# define MMD1_EDC_Error 0x20 /* EDC error captured */
+# define MMD1_Data_Parity_Error 0x01 /* Data parity error captured */
+
+
+typedef struct _MMD1_INFO {
+ UCHAR Flag;
+ union {
+ CAT_REGISTERS CatRegs;
+ struct {
+ UCHAR Dummy0;
+ UCHAR Dummy1;
+ UCHAR Dummy2;
+ UCHAR I0EccStatus;
+ UCHAR TestMode;
+ UCHAR ECCDiag;
+ UCHAR Dummy6;
+ UCHAR Dummy7;
+ UCHAR I1EccStatus;
+ UCHAR SyndromeI0ML0;
+ UCHAR SyndromeI0ML1;
+ UCHAR SyndromeI1ML0;
+ UCHAR SyndromeI1ML1;
+ UCHAR ParityAStatus;
+ UCHAR ParityBStatus;
+ UCHAR Status;
+ } MmdRegisters;
+ } CatRegisters;
+} MMD1_INFO, *PMMD1_INFO;
+
+/* defines for union referencing */
+#define INTERLEAVE0_ERROR CatRegisters.MmdRegisters.I0ECCStatus
+#define INTERLEAVE1_ERROR CatRegisters.MmdRegisters.I1ECCStatus
+#define SYN_DIAG_0 CatRegisters.MmdRegisters.SyndromeI0Ml0
+#define SYN_DIAG_1 CatRegisters.MmdRegisters.SyndromeI0Ml1
+#define SYN_DIAG_2 CatRegisters.MmdRegisters.SyndromeI1Ml0
+#define SYN_DIAG_3 CatRegisters.MmdRegisters.SyndromeI1Ml1
+#define BUS_A_PARITY CatRegisters.MmdRegisters.ParityAStatus
+#define BUS_B_PARITY CatRegisters.MmdRegisters.ParityBStatus
+#define MMDSTATUS CatRegisters.MmdRegisters.Status
+
+
+
+typedef struct _FRU_LOCATION {
+ UCHAR BusType;
+ UCHAR BusNumber;
+ UCHAR BusSlotNumber;
+} FRU_LOCATION, *PFRU_LOCATION;
+
+
+
+typedef struct _MEMORY_CARD_INFO {
+ ULONG FruAsic;
+ ULONG FruSimm;
+ ULONG AsicConfidenceLevel;
+ ULONG SimmConfidenceLevel;
+ FRU_LOCATION Location;
+ MMC1_INFO Mmc1Info;
+ MMA1_INFO Mma1Info;
+ MMD1_INFO Mmd1Info[NUM_MMD_PER_CARD];
+} MEMORY_CARD_INFO, *PMEMORY_CARD_INFO;
+
+
+
+
+#endif // _NCRMEM_
diff --git a/private/ntos/nthals/halncr/i386/ncrmp.c b/private/ntos/nthals/halncr/i386/ncrmp.c
new file mode 100644
index 000000000..0c41cbb59
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrmp.c
@@ -0,0 +1,2443 @@
+/*++
+
+Copyright (c) 1992 NCR Corporation
+
+Module Name:
+
+ ncrmp.c
+
+Abstract:
+
+
+Author:
+
+ Richard Barton (o-richb) 24-Jan-1992
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "ixkdcom.h"
+#include "ncr.h"
+#include "stdio.h"
+#include "ncrnls.h"
+#include "ncrcat.h"
+#include "ncrcatp.h"
+#include "ncrsus.h"
+#include "ncrmem.h"
+
+UCHAR HalName[] = "NCR 3x series MP HAL";
+
+ADDRESS_USAGE HalpNCRIoSpace = {
+ NULL, CmResourceTypePort, InternalUsage,
+ {
+ 0xF800, 0x100, // IO space reserved for CAT
+ 0xFC00, 0x100, // IO space reserved for VIC
+ 0x97, 0x2, // IO space for 3450 and up CAT SELECT/BASE port
+ 0,0
+ }
+};
+
+ULONG NCRDebug = 0x2;
+ // 0x01 - none
+ // 0x02 - stop on memory edits
+ // 0x04 - enable nmi button on 3360
+ // 0x08 - enable boot on 3550
+ // 0x10 - disable reprogram of QCC and QABC Asics for cache ownership
+ // 0x20 - Enable LARCs
+
+
+ULONG NCRProcessorsToBringup = 0xFFFF;
+ULONG NCRExistingProcessorMask = 0x00;
+ULONG NCRExistingDyadicProcessorMask = 0x00;
+ULONG NCRExistingQuadProcessorMask = 0x00;
+ULONG NCRExtendedProcessorMask = 0x00;
+ULONG NCRExtendedProcessor0Mask = 0x00;
+ULONG NCRExtendedProcessor1Mask = 0x00;
+ULONG NCRActiveProcessorMask = 0x00;
+ULONG NCRActiveProcessorLogicalMask = 0x00;
+ULONG NCRActiveProcessorCount = 0;
+ULONG NCRMaxProcessorCount = NCR_MAX_NUMBER_QUAD_PROCESSORS;
+ULONG LimitMemory = 0;
+
+ULONG NCRNeverClaimIRQs = 0xffffffff; // we start out claiming none
+
+#if 0
+
+//
+// BUGBUG - (shielint) This is requested by Ncr.
+// For now don't let cpus claim any IRQ by setting the flag to -1.
+// NCR/ATT will revisit this problem after NT4.0 release.
+//
+
+ULONG DefaultNeverClaimIRQs = 1 // lets don't claim the timer interrupt
+
+#else
+
+ULONG DefaultNeverClaimIRQs = 0xffffffff; // lets don't claim the timer interrupt
+
+#endif
+
+ULONG NCRMaxIRQsToClaim = 0;
+ULONG NCRGlobalClaimedIRQs = 0;
+
+ULONG NCRLogicalNumberToPhysicalMask[NCR_MAX_NUMBER_PROCESSORS] = {0};
+
+ULONG NCRProcessorIDR[NCR_MAX_NUMBER_PROCESSORS];
+
+ULONG NCRLarcPageMask = 0x1; // only one page by default (4 Meg)
+
+#ifdef DBG
+ULONG NCRProcessorClaimedIRQs[NCR_MAX_NUMBER_PROCESSORS] = {0};
+ULONG NCRClaimCount = 0;
+ULONG NCRStolenCount = 0;
+ULONG NCRUnclaimCount = 0;
+#endif
+
+ULONG NCRLogicalDyadicProcessorMask = 0x00;
+ULONG NCRLogicalQuadProcessorMask = 0x00;
+
+UCHAR NCRSlotExtended0ToVIC[4] = {0, 5, 2, 7};
+UCHAR NCRSlotExtended1ToVIC[4] = {1, 4, 3, 6};
+
+extern ULONG NCRPlatform;
+
+ULONG NCRStatusChangeInterruptEnabled = 0;
+
+extern ULONG HalpDefaultInterruptAffinity;
+
+extern ULONG NCRLarcEnabledPages[]; // LARC size by Voyager slot
+
+/*
+ * Struct used to report secondary MC information to the
+ * Registery
+ */
+
+typedef struct _SMC_RESOURCES {
+ CM_FULL_RESOURCE_DESCRIPTOR ConfigurationData;
+ CM_MCA_POS_DATA PosData[10];
+ } SMC_RESOURCES, *PSMC_RESOURCES;
+
+
+/*
+ * Global variables used for acessing Secondary Microchannel
+ *
+ */
+
+
+ULONG NCRSegmentIoAddress = 0xffe00000;
+PUCHAR NCRSegmentIoRegister = NULL;
+
+/*
+ * Spin lock used to lock the CAT Bus. HalpAcquireCatBusSpinLock and
+ * HalpReleaseCatBusSpinLock use this lock.
+ */
+
+KSPIN_LOCK HalpCatBusLock;
+
+
+typedef struct {
+ ULONG StartingByte;
+ ULONG Pages;
+} NCRClickMapEntry;
+#define ClickMapEntryCount 16
+#define NoExtraDescriptors 16
+
+ULONG NCRAddedDescriptorCount;
+MEMORY_ALLOCATION_DESCRIPTOR NCRAdditionalMemoryDescriptors[NoExtraDescriptors];
+
+
+PVOID NonbootStartupPhysicalPtr;
+PUCHAR NonbootStartupVirtualPtr;
+PUCHAR PageZeroVirtualPtr;
+
+VOID NCRVicIPIHandler(VOID);
+VOID NCRQicIPIHandler(VOID);
+VOID NCRClockBroadcastHandler(VOID);
+
+VOID __cdecl NCRVICErrataHandler1();
+VOID __cdecl NCRVICErrataHandler3();
+VOID __cdecl NCRVICErrataHandler4();
+VOID __cdecl NCRVICErrataHandler5();
+VOID __cdecl NCRVICErrataHandler6();
+VOID __cdecl NCRVICErrataHandler7();
+VOID __cdecl NCRVICErrataHandler15();
+
+VOID __cdecl NCRProfileHandler();
+VOID __cdecl NCRSysIntHandler();
+VOID __cdecl NCRQicSpuriousHandler();
+
+PUCHAR NCRDeterminePlatform(PBOOLEAN);
+VOID NCRFixMemory(PLOADER_PARAMETER_BLOCK);
+VOID NCRLimitMemory(PLOADER_PARAMETER_BLOCK);
+VOID NCRVerifyMemoryRange (ULONG, ULONG, PLOADER_PARAMETER_BLOCK);
+//VOID NCRAdjustMemoryDescriptor(PMEMORY_ALLOCATION_DESCRIPTOR,
+// NCRClickMapEntry *);
+VOID NCRSetupDiagnosticProcessor(PLOADER_PARAMETER_BLOCK);
+
+VOID NCRLockedOr(PULONG, ULONG);
+VOID NCRParseLoaderOptions (PUCHAR Options);
+BOOLEAN NCRGetValue (PUCHAR Options, PUCHAR String, PULONG Value);
+ULONG HalpGetCmosData (ULONG SourceLocation, ULONG SourceAddress,
+ PUCHAR Buffer, ULONG Length);
+
+VOID HalpDisableSingleBitErrorDET();
+VOID HalpInitializeSMCInterface();
+VOID HalpCatReportSMC();
+
+VOID HalEnableStatusChangeInterrupt (
+ IN ULONG
+ );
+
+BOOLEAN
+HalpTranslateSMCBusAddress (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ );
+
+ULONG
+HalpGetMCAInterruptVector (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ );
+
+ULONG
+HalpGetSMCAInterruptVector (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ );
+
+
+ULONG
+HalpNCRGetSystemInterruptVector(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ );
+
+HalpGetPosData (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Offset,
+ IN ULONG Length
+ );
+
+NTSTATUS
+HalpAdjustEisaResourceList (
+ IN PVOID BusHandler,
+ IN PVOID RootHandler,
+ IN OUT PIO_RESOURCE_REQUIREMENTS_LIST *pResourceList
+ );
+
+#define HalpAdjustMCAResourceList HalpAdjustEisaResourceList;
+
+
+BOOLEAN
+HalpInitMP (
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+VOID
+HalpMapCR3 (
+ IN ULONG VirtAddress,
+ IN PVOID PhysicalAddress,
+ IN ULONG Length
+ );
+
+ULONG
+HalpBuildTiledCR3 (
+ IN PKPROCESSOR_STATE ProcessorState
+ );
+
+VOID
+HalpFreeTiledCR3 (
+ VOID
+ );
+
+VOID HalpInitOtherBuses (VOID);
+
+ULONG NCRTranslateCMOSMask(ULONG);
+ULONG NCRTranslateToCMOSMask(ULONG);
+VOID NCRFindExtendedProcessors();
+VOID NCRMapIpiAddresses();
+
+VOID NCRAdjustDynamicClaims();
+
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,HalpInitMP)
+#pragma alloc_text(INIT,HalStartNextProcessor)
+#pragma alloc_text(INIT,HalReportResourceUsage)
+#pragma alloc_text(INIT,HalReportResourceUsage)
+#pragma alloc_text(INIT,HalpInitOtherBuses)
+#pragma alloc_text(INIT,NCRFixMemory)
+#pragma alloc_text(INIT,NCRLimitMemory)
+//#pragma alloc_text(INIT,NCRAdjustMemoryDescriptor)
+#pragma alloc_text(INIT,NCRVerifyMemoryRange)
+#pragma alloc_text(INIT,NCRSetupDiagnosticProcessor)
+#pragma alloc_text(INIT,NCRParseLoaderOptions)
+#pragma alloc_text(INIT,NCRGetValue)
+#pragma alloc_text(INIT,HalpFreeTiledCR3)
+#pragma alloc_text(INIT,HalpMapCR3)
+#pragma alloc_text(INIT,HalpBuildTiledCR3)
+#pragma alloc_text(INIT,HalpInitializeCatBusDriver)
+#pragma alloc_text(INIT,HalpDisableSingleBitErrorDET)
+#pragma alloc_text(INIT,HalpInitializeSUSInterface)
+#pragma alloc_text(INIT,HalpInitializeSMCInterface)
+#pragma alloc_text(INIT,HalpCatReportSystemModules)
+#pragma alloc_text(INIT,HalpCatReportSMC)
+#endif
+
+
+
+BOOLEAN
+HalpInitMP (
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+/*++
+
+Routine Description:
+ Allows MP initialization from HalInitSystem.
+
+Arguments:
+ Same as HalInitSystem
+
+Return Value:
+ none.
+
+--*/
+{
+ PKPCR pPCR;
+ UCHAR Buffer[64];
+ UCHAR id;
+ PUCHAR PlatformStringPtr;
+ ULONG MyLogicalNumber;
+ ULONG MyLogicalMask;
+ BOOLEAN ConfiguredMp;
+ ULONG trans;
+ CAT_CONTROL cat_control;
+
+ pPCR = KeGetPcr();
+ MyLogicalNumber =
+ ((PProcessorPrivateData)pPCR->HalReserved)->MyLogicalNumber;
+
+ if (Phase == 0) {
+
+ //
+ // Register NCR machine IO space, so drivers don't try to
+ // use it
+ //
+
+ HalpRegisterAddressUsage (&HalpNCRIoSpace);
+
+ NCRParseLoaderOptions (LoaderBlock->LoadOptions);
+
+ /*
+ * only the boot processor sees phase zero.
+ */
+ if ((PlatformStringPtr = NCRDeterminePlatform(&ConfiguredMp)) == NULL) {
+ sprintf(Buffer, MSG_UNKOWN_NCR_PLATFORM, NCRPlatform);
+ HalDisplayString(Buffer);
+
+ /*
+ may not want to continue here, but for now let's
+ go on, assuming a UP machine
+ */
+
+ NCRExistingProcessorMask = 0x1;
+
+ } else {
+ sprintf(Buffer, MSG_NCR_PLATFORM, PlatformStringPtr);
+ HalDisplayString(Buffer);
+
+ HalpGetCmosData(1, 0x88A, (PUCHAR)&NCRExistingProcessorMask, 4);
+
+ trans = NCRTranslateCMOSMask(NCRExistingProcessorMask);
+ NCRExtendedProcessorMask = 0x0;
+
+ DBGMSG(("HalpInitMP: CMOS NCRExistingProcessorMask = 0x%x, translated = 0x%x\n",
+ NCRExistingProcessorMask,
+ trans));
+
+ NCRExistingProcessorMask = trans;
+
+
+ // additional stuff only if MSBU machine
+
+ if (NCRPlatform != NCR3360) {
+
+ KeInitializeSpinLock(&HalpCatBusLock);
+
+ /*
+ * This is to allow tweeking the memory descriptors.
+ */
+
+ NCRFixMemory(LoaderBlock);
+
+ /*
+ * This is to determine whether we ought to save COM1
+ * for the diagnostic processors use.
+ */
+ NCRSetupDiagnosticProcessor(LoaderBlock);
+
+ }
+
+ if (NCRPlatform == NCR3360) {
+ id = 1;
+ HalpSetCmosData(1, 0x41E, &id, 1);
+
+ if (NCRDebug & 0x04) {
+ NCR3360EnableNmiButton();
+ }
+ }
+
+ }
+
+
+
+ if (LimitMemory) {
+ NCRLimitMemory (LoaderBlock);
+ }
+
+ PageZeroVirtualPtr = HalpMapPhysicalMemory(0, 1);
+
+ if ((NCRExistingProcessorMask ^ NCRActiveProcessorMask) != 0) {
+ /*
+ * there are non-boot processors to bring up...
+ *
+ * allocate some space to put the non-boot processors
+ * startup code.
+ */
+ NonbootStartupPhysicalPtr =
+ (PVOID)HalpAllocPhysicalMemory(LoaderBlock,
+ (1*1024*1024),
+ 1, FALSE);
+ NonbootStartupVirtualPtr =
+ (PUCHAR)HalpMapPhysicalMemory(NonbootStartupPhysicalPtr,
+ 1);
+ }
+
+ if (NCRPlatform != NCR3360) {
+
+ HalpInitializeSUSInterface();
+
+ DBGMSG(("HalpInitMP: End of Phase 0, NCRExistingProcessorMask = 0x%x, NCRActiveProcessorMask = 0x%x\n",
+ NCRExistingProcessorMask,
+ NCRActiveProcessorMask));
+
+ NCRMapIpiAddresses(); // Map all QIC Ipi address
+ NCRFindIpiAddress(0); // lookup processor 0 Ipi address
+
+#ifdef NEVER
+ DBGMSG(("HalpInitMP: Lets break into the debug..\n"));
+ _asm {
+ int 3
+ }
+#endif // NEVER
+
+ } else {
+ NCRExistingDyadicProcessorMask = NCRExistingProcessorMask;
+ }
+
+
+
+ } else {
+ // Phase 1...
+
+ DBGMSG(("HalpInitMP: Start Phase %d for Proc %d\n", Phase, MyLogicalNumber));
+
+
+ /*
+ * set up idt for cpis
+ */
+ HalpEnableInterruptHandler (
+ InternalUsage, // Report as device vector
+ NCR_CPI_VECTOR_BASE + NCR_IPI_LEVEL_CPI,
+ NCR_CPI_VECTOR_BASE + NCR_IPI_LEVEL_CPI, // IDT
+ IPI_LEVEL, // System Irql
+ NCRVicIPIHandler, // ISR
+ LevelSensitive );
+
+
+ NCRSetHandlerAddressToIDT((NCR_QIC_CPI_VECTOR_BASE +
+ NCR_IPI_LEVEL_CPI),
+ NCRQicIPIHandler);
+
+
+ /*
+ * put the broadcast clock handler at the
+ * same irql as the clock. that way enabling
+ * the clock enables the broadcast.
+ */
+ HalpEnableInterruptHandler (
+ InternalUsage, // Report as device vector
+ NCR_CPI_VECTOR_BASE + NCR_CLOCK_LEVEL_CPI,
+ NCR_CPI_VECTOR_BASE + NCR_CLOCK_LEVEL_CPI, // IDT
+ CLOCK2_LEVEL, // System Irql
+ NCRClockBroadcastHandler, // ISR
+ LevelSensitive );
+
+ NCRSetHandlerAddressToIDT((NCR_QIC_CPI_VECTOR_BASE +
+ NCR_CLOCK_LEVEL_CPI),
+ NCRClockBroadcastHandler);
+
+ KiSetHandlerAddressToIDT(PROFILE_VECTOR,
+ NCRProfileHandler);
+
+ /*
+ * Set up handlers for sysints
+ */
+
+
+ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE +
+ NCR_SYSTEM_INTERRUPT),
+ NCRSysIntHandler);
+
+ HalEnableSystemInterrupt((NCR_CPI_VECTOR_BASE +
+ NCR_SYSTEM_INTERRUPT),
+ (HIGH_LEVEL -
+ (NCR_SYSTEM_INTERRUPT & 0x7)),
+ LevelSensitive);
+
+ // due to a VIC errata, may get a bad vector (offset
+ // by 8) for a CPI when a sysint or sbe is active.
+ // Only CPIs 0 (NCR_IPI_LEVEL_CPI) and 2
+ // (NCR_CLOCK_LEVEL_CPI) are currently are used. Thus,
+ // need to handle CPIs 0/2 at CPI vectors 8/10 as
+ // well. Since CPI 10 is not used for anything else,
+ // it can be set identical to CPI 2. However, CPI 8
+ // is used by sysint. Thus, the handler for CPI 8
+ // needs to handle this case
+
+ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE +
+ NCR_CLOCK_LEVEL_CPI + 8),
+ NCRClockBroadcastHandler);
+
+ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE +
+ NCR_SMCA_9),
+ NCRVICErrataHandler1);
+
+ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE +
+ NCR_SMCA_9 + 8),
+ NCRVICErrataHandler1);
+
+ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE +
+ NCR_SMCA_11_3),
+ NCRVICErrataHandler3);
+
+ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE +
+ NCR_SMCA_11_3 + 8),
+ NCRVICErrataHandler3);
+
+ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE +
+ NCR_SMCA_12_4),
+ NCRVICErrataHandler4);
+
+ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE +
+ NCR_SMCA_12_4 + 8),
+ NCRVICErrataHandler4);
+
+ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE +
+ NCR_SMCA_13_5),
+ NCRVICErrataHandler5);
+
+ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE +
+ NCR_SMCA_13_5 + 8),
+ NCRVICErrataHandler5);
+
+ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE +
+ NCR_SMCA_14_6),
+ NCRVICErrataHandler6);
+
+ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE +
+ NCR_SMCA_14_6 + 8),
+ NCRVICErrataHandler6);
+
+ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE +
+ NCR_SMCA_15_7),
+ NCRVICErrataHandler7);
+
+ NCRSetHandlerAddressToIDT((NCR_CPI_VECTOR_BASE +
+ NCR_SMCA_15_7 + 8),
+ NCRVICErrataHandler15);
+
+ //
+ // Lets go ahead an enable the interrupt for single bit/status change.
+ // The following HalEnableSystemInterrupt call will enable the interrupt
+ // that will be serviced by NCRVICErrataHandler15. The reason we enable
+ // interrupt level 7 is because the single bit/status interrupt is on vector
+ // CPI+f and is a level 7 interrupt.
+ //
+
+ if (NCRPlatform != NCR3360) {
+
+ // This code was removed since enabled this vector
+ // also enables 0x37. (Microchanel IRQ 7). If there
+ // is a device connected to IRQ 7 which has an interrupt
+ // asserted, it could start sending interrupts as soon
+ // as ncr_single_bit_error is enabled - which is before
+ // the corrisponding driver could be loaded.
+
+ HalEnableSystemInterrupt((NCR_CPI_VECTOR_BASE +
+ NCR_SMCA_15_7),
+ (HIGH_LEVEL -
+ (NCR_SMCA_15_7 & 0x7)),
+ LevelSensitive);
+
+ }
+
+
+ //
+ // If this is a processor on the Quad board then we need to handle the
+ // Qic Spurious interrupt
+ //
+
+
+ MyLogicalMask = 0x1 << MyLogicalNumber;
+
+ if (MyLogicalMask & NCRLogicalQuadProcessorMask) {
+ NCRSetHandlerAddressToIDT(NCR_QIC_SPURIOUS_VECTOR, NCRQicSpuriousHandler);
+ }
+
+ if (MyLogicalNumber != 0) {
+ /*
+ * not the boot processor
+ */
+ HalpInitializeStallExecution((CCHAR)MyLogicalNumber);
+
+ /*
+ * Allow clock interrupts on all processors
+ */
+ HalEnableSystemInterrupt(CLOCK_VECTOR,
+ CLOCK2_LEVEL, LevelSensitive);
+
+ /*
+ * Allow profile interrupt on all processors
+ */
+ HalEnableSystemInterrupt(PROFILE_VECTOR,
+ PROFILE_LEVEL, LevelSensitive);
+
+ }
+
+ NCRLockedOr(&NCRActiveProcessorLogicalMask,
+ ((PProcessorPrivateData)pPCR->HalReserved)->MyLogicalMask);
+ }
+
+ return(TRUE);
+}
+
+NCRSetHandlerAddressToIDT (
+ IN ULONG IdtEntry,
+ IN VOID (*Handler)(VOID)
+ )
+{
+
+
+ HalpRegisterVector (InternalUsage, IdtEntry, IdtEntry, (HIGH_LEVEL - (IdtEntry & 0x7)));
+ KiSetHandlerAddressToIDT (IdtEntry, Handler);
+}
+
+BOOLEAN
+HalAllProcessorsStarted (
+ VOID
+ )
+{
+ return TRUE;
+}
+
+VOID
+HalReportResourceUsage (
+ VOID
+ )
+/*++
+
+Routine Description:
+ The registery is now enabled - time to report resources which are
+ used by the HAL.
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ ANSI_STRING AHalName;
+ UNICODE_STRING UHalName;
+
+ HalInitSystemPhase2 ();
+
+ RtlInitAnsiString (&AHalName, HalName);
+ RtlAnsiStringToUnicodeString (&UHalName, &AHalName, TRUE);
+
+ HalpReportResourceUsage (
+ &UHalName, // descriptive name
+ MicroChannel // NCR's are MCA machines
+ );
+
+ RtlFreeUnicodeString (&UHalName);
+
+ //
+ // Registry is now online, check for any PCI buses to support
+ //
+
+ HalpInitializePciBus ();
+
+ if (NCRPlatform != NCR3360) {
+ HalpCatReportSystemModules();
+ if (NCRSegmentIoRegister != NULL) {
+ HalpCatReportSMC();
+ }
+ }
+}
+
+
+
+VOID
+NCRFixMemory (
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+/*++
+
+Routine Description:
+ Consult the firmware click map to determine what the memory
+ really looks like. Fix up the memory descriptors as necessary.
+
+ Note this function only adds memory which is in the clickmap
+ to NTs memory descriptors.
+
+Arguments:
+ Pointer to the loader block
+
+Return Value:
+ none.
+
+--*/
+{
+ ULONG BPage, EPage, Temp;
+ PVOID ClickMapPage;
+ NCRClickMapEntry *BaseOfClickMap;
+ NCRClickMapEntry *ClickMapEntryPtr;
+ MEMORY_ALLOCATION_DESCRIPTOR TempDesc;
+
+ /*
+ * First get the physical address of the firmware's click map.
+ */
+ HalpGetCmosData(1, 0xA23, (PUCHAR)&BaseOfClickMap, 4);
+ if (BaseOfClickMap == NULL) {
+#if DBG
+ HalDisplayString("NCRFixMemory: No click map?!\n");
+#endif
+ return;
+ }
+
+ /*
+ * Now get a virtual address for the firmware's click map.
+ */
+ ClickMapPage = (PVOID)((ULONG)BaseOfClickMap & ~(PAGE_SIZE - 1));
+ ClickMapPage = HalpMapPhysicalMemory(ClickMapPage, 2);
+ if (ClickMapPage == NULL) {
+#if DBG
+ HalDisplayString("NCRFixMemory: Can't map in click map?!\n");
+#endif
+ return;
+ }
+
+ ClickMapEntryPtr = (NCRClickMapEntry *)((ULONG)ClickMapPage +
+ ((ULONG)BaseOfClickMap & (PAGE_SIZE - 1)));
+ BaseOfClickMap = ClickMapEntryPtr;
+
+
+ /*
+ * Run the firmware's click map and verify NT has some type of
+ * descriptor for all memory in the click map.
+ */
+
+ // The hal allocates various memory by just removing it from the memory
+ // map, we can't add that memory back in.
+
+ // make bogus descriptor for 0-16M
+ TempDesc.MemoryType = -1;
+ TempDesc.BasePage = 0;
+ TempDesc.PageCount = 0x1000;
+ InsertHeadList(&LoaderBlock->MemoryDescriptorListHead, &TempDesc.ListEntry);
+
+ for (ClickMapEntryPtr = BaseOfClickMap;
+ ((ClickMapEntryPtr < &BaseOfClickMap[ClickMapEntryCount]) &&
+ (ClickMapEntryPtr->Pages != 0)); ++ClickMapEntryPtr) {
+
+ BPage = ClickMapEntryPtr->StartingByte >> PAGE_SHIFT;
+ EPage = BPage + ClickMapEntryPtr->Pages;
+
+ NCRVerifyMemoryRange (BPage, EPage, LoaderBlock);
+ }
+
+ RemoveEntryList(&TempDesc.ListEntry);
+
+ /*
+ * Clear the mapping to the scratchpad. Not all of it is
+ * reinitialized on a warm reset and the data may get corrupted.
+ * We mapped in two pages.
+ */
+ Temp = (ULONG)MiGetPteAddress(ClickMapPage);
+ *(PULONG)Temp = 0;
+ *((PULONG)Temp+1) = 0;
+ /*
+ * Flush the TLB.
+ */
+ _asm {
+ mov eax, cr3
+ mov cr3, eax
+ }
+}
+
+VOID NCRVerifyMemoryRange (
+ IN ULONG StartPage,
+ IN ULONG EndPage,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+/*++
+
+Routine Description:
+ Ensure there is an NT descriptor for this memory range. Any
+ part of the range which does not have a descriptor is added
+ as available memory.
+
+Arguments:
+
+Return Value:
+ none.
+
+--*/
+{
+ ULONG sp, ep;
+ PLIST_ENTRY NextListEntry;
+ PMEMORY_ALLOCATION_DESCRIPTOR Desc;
+
+ if (StartPage == EndPage) {
+ return ;
+ }
+
+ for (NextListEntry = LoaderBlock->MemoryDescriptorListHead.Flink;
+ NextListEntry != &LoaderBlock->MemoryDescriptorListHead;
+ NextListEntry = NextListEntry->Flink) {
+
+ //
+ // Check each descriptor to see if it intersects with the range
+ // in question
+ //
+
+ Desc = CONTAINING_RECORD(NextListEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ sp = Desc->BasePage;
+ ep = sp + Desc->PageCount;
+
+ if (sp < StartPage) {
+ if (ep > StartPage && ep < EndPage) {
+ // bump target area past this descriptor
+ StartPage = ep;
+ }
+
+ if (ep > EndPage) {
+ //
+ // Target area is contained totally within this
+ // descriptor. This range is fully accounted for.
+ //
+
+ StartPage = EndPage;
+ }
+
+ } else {
+ // sp >= StartPage
+
+ if (sp < EndPage) {
+ if (ep < EndPage) {
+ //
+ // This descriptor is totally within the target area -
+ // check the area on either side of this desctipor
+ //
+
+ NCRVerifyMemoryRange (StartPage, sp, LoaderBlock);
+ StartPage = ep;
+
+ } else {
+ // bump begining page of this descriptor
+ EndPage = sp;
+ }
+ }
+ }
+
+ //
+ // Anything left of target area?
+ //
+
+ if (StartPage == EndPage) {
+ return ;
+ }
+ } // next descrtiptor
+
+ //
+ // The range StartPage - EndPage is a missing range from NTs descriptor
+ // list. Add it as available memory.
+ //
+
+ if (NCRAddedDescriptorCount == NoExtraDescriptors) {
+ return ;
+ }
+
+ Desc = &NCRAdditionalMemoryDescriptors[NCRAddedDescriptorCount];
+ NCRAddedDescriptorCount += 1;
+
+ Desc->MemoryType = MemoryFree;
+ Desc->BasePage = StartPage;
+ Desc->PageCount = EndPage - StartPage;
+ InsertTailList(&LoaderBlock->MemoryDescriptorListHead, &Desc->ListEntry);
+}
+
+
+
+#if 0
+VOID
+NCRFixMemory(LoaderBlockPtr)
+PLOADER_PARAMETER_BLOCK LoaderBlockPtr;
+/*++
+
+Routine Description:
+ Consult the firmware click map to determine what the memory
+ really looks like. Fix up the memory descriptors as necessary.
+
+ Note that we may remove memory descriptors due to the clickmap
+ disagreeing. However, we will only add memory descriptors to
+ the end as necessary. Therefore, in theory, it is possible to
+ have unused memory. But not likely.
+
+ New descriptors may be added due to holes in physical
+ memory caused by memory mapped adapters.
+ This means that firmware is expected to give the
+ loader (via BIOS int 15 function 88) the amount of contiguous
+ extended memory with the lowest addresses.
+
+Arguments:
+ Pointer to the loader block
+
+Return Value:
+ none.
+
+--*/
+{
+ ULONG MaxDescriptorPage;
+ ULONG Temp;
+ ULONG StartingPage;
+ PLIST_ENTRY NextListEntry;
+ PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptorPtr;
+ PMEMORY_ALLOCATION_DESCRIPTOR HighestMemoryDescriptor;
+ PMEMORY_ALLOCATION_DESCRIPTOR NextFreeMemoryDescriptor;
+ PVOID ClickMapPage;
+ NCRClickMapEntry *BaseOfClickMap;
+ NCRClickMapEntry *ClickMapEntryPtr;
+
+ /*
+ * First get the physical address of the firmware's click map.
+ */
+ HalpGetCmosData(1, 0xA23, (PUCHAR)&BaseOfClickMap, 4);
+ if (BaseOfClickMap == NULL) {
+#if DBG
+ HalDisplayString("NCRFixMemory: No click map?!\n");
+#endif
+ return;
+ }
+
+ /*
+ * Now get a virtual address for the firmware's click map.
+ */
+ ClickMapPage = (PVOID)((ULONG)BaseOfClickMap & ~(PAGE_SIZE - 1));
+ ClickMapPage = HalpMapPhysicalMemory(ClickMapPage, 2);
+ if (ClickMapPage == NULL) {
+#if DBG
+ HalDisplayString("NCRFixMemory: Can't map in click map?!\n");
+#endif
+ return;
+ }
+ ClickMapEntryPtr = (NCRClickMapEntry *)((ULONG)ClickMapPage +
+ ((ULONG)BaseOfClickMap & (PAGE_SIZE - 1)));
+ BaseOfClickMap = ClickMapEntryPtr;
+
+ /*
+ * the firmware guys say that contiguous memory
+ * will always be coalesced into one clickmap
+ * entry. we "trust but verify."
+ */
+ for (; ((ClickMapEntryPtr <
+ &BaseOfClickMap[ClickMapEntryCount-1]) &&
+ (ClickMapEntryPtr->Pages != 0)); ++ClickMapEntryPtr) {
+ Temp = ClickMapEntryPtr->StartingByte +
+ (ClickMapEntryPtr->Pages << PAGE_SHIFT);
+ while (((ClickMapEntryPtr+1)->Pages != 0) &&
+ ((ClickMapEntryPtr+1)->StartingByte <= Temp)) {
+ /*
+ * this should never happen...but if it does
+ * it's easily fixed
+ */
+ NCRClickMapEntry *NextClickMapEntryPtr;
+
+ DBGMSG(("NCRFixMemory: Fixing clickmap!?!\n"));
+
+ NextClickMapEntryPtr = ClickMapEntryPtr + 1;
+ /*
+ * note that this ending byte address is used
+ * to determine whether we iterate again.
+ */
+ Temp = NextClickMapEntryPtr->StartingByte +
+ (NextClickMapEntryPtr->Pages << PAGE_SHIFT);
+
+ if (Temp <= ClickMapEntryPtr->StartingByte) {
+ /*
+ * Whoa!!! this ain't so easy to fix.
+ * I'm not interested in sorting right now.
+ */
+ DbgBreakPoint();
+ }
+
+ /*
+ * here again, in theory, if the planets are really
+ * off their courses we could decrease the page
+ * count
+ */
+ ClickMapEntryPtr->Pages =
+ (Temp - ClickMapEntryPtr->StartingByte) >>
+ PAGE_SHIFT;
+
+ /*
+ * we just removed an entry...shift all subsequent
+ * entries down
+ */
+ for (++NextClickMapEntryPtr;
+ (NextClickMapEntryPtr <
+ &BaseOfClickMap[ClickMapEntryCount]);
+ ++NextClickMapEntryPtr) {
+ (NextClickMapEntryPtr-1)->StartingByte =
+ NextClickMapEntryPtr->StartingByte;
+ (NextClickMapEntryPtr-1)->Pages =
+ NextClickMapEntryPtr->Pages;
+ if (NextClickMapEntryPtr->Pages == 0) {
+ /*
+ * we just copied the sentinel
+ */
+ break;
+ }
+ }
+ }
+ }
+
+ /*
+ * go through all the memory descriptor entries...
+ */
+ HighestMemoryDescriptor = NULL;
+ NextListEntry = LoaderBlockPtr->MemoryDescriptorListHead.Flink;
+ while (NextListEntry != &LoaderBlockPtr->MemoryDescriptorListHead) {
+ MemoryDescriptorPtr =
+ CONTAINING_RECORD(NextListEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ /*
+ * find clickmap entry that contains this memory descriptor
+ */
+ for (ClickMapEntryPtr = BaseOfClickMap;
+ ((ClickMapEntryPtr <
+ &BaseOfClickMap[ClickMapEntryCount]) &&
+ (ClickMapEntryPtr->Pages != 0)); ++ClickMapEntryPtr) {
+ StartingPage = ClickMapEntryPtr->StartingByte >>
+ PAGE_SHIFT;
+ Temp = StartingPage + ClickMapEntryPtr->Pages;
+ MaxDescriptorPage = MemoryDescriptorPtr->BasePage +
+ MemoryDescriptorPtr->PageCount;
+
+ if ((MemoryDescriptorPtr->BasePage >= StartingPage) &&
+ (MemoryDescriptorPtr->BasePage < Temp)) {
+ /*
+ * this memory descriptor starts in this
+ * clickmap entry...
+ */
+ if (MaxDescriptorPage > Temp) {
+ /*
+ * and goes beyond
+ */
+ NCRAdjustMemoryDescriptor(MemoryDescriptorPtr,
+ ClickMapEntryPtr);
+ }
+ break;
+ }
+ if ((MaxDescriptorPage > StartingPage) &&
+ (MaxDescriptorPage <= Temp)) {
+ /*
+ * this memory descriptor ends in this
+ * clickmap entry...
+ */
+ if (MemoryDescriptorPtr->BasePage <
+ StartingPage) {
+ /*
+ * but starts before
+ */
+ NCRAdjustMemoryDescriptor(MemoryDescriptorPtr,
+ ClickMapEntryPtr);
+ }
+ break;
+ }
+ if ((MemoryDescriptorPtr->BasePage < StartingPage) &&
+ (MaxDescriptorPage > Temp)) {
+ /*
+ * this memory descriptor is a superset of
+ * this clickmap entry
+ */
+ NCRAdjustMemoryDescriptor(MemoryDescriptorPtr,
+ ClickMapEntryPtr);
+ break;
+ }
+ }
+
+ /*
+ * question...it's possible with the adjustments we did above
+ * to have a memory descriptor with zero pages. should we
+ * remove it too? i've seen other memory descriptors with
+ * zero pages. for now we don't remove them.
+ *
+ * Also the ClickMap doesn't contain any memory for regions
+ * between 640-1M, but the memory descriptor may. we leave
+ * those memory descriptors alone.
+ */
+ if ((ClickMapEntryPtr >= &BaseOfClickMap[ClickMapEntryCount] ||
+ ClickMapEntryPtr->Pages == 0) &&
+ (MemoryDescriptorPtr->BasePage < 0x9f ||
+ MemoryDescriptorPtr->BasePage+MemoryDescriptorPtr->PageCount > 0x100) ) {
+
+ /*
+ * no part of this memory descriptor was found to be
+ * contained within any clickmap entry...remove it
+ */
+ NCRAdjustMemoryDescriptor(MemoryDescriptorPtr,
+ NULL);
+ /*
+ * a memory descriptor was removed. it's probably
+ * safest to just start over
+ */
+ NextListEntry =
+ LoaderBlockPtr->MemoryDescriptorListHead.Flink;
+ continue;
+ }
+
+ /*
+ * remember the entry for the memory range with the highest
+ * address
+ */
+ if ((HighestMemoryDescriptor == NULL) ||
+ (HighestMemoryDescriptor->BasePage <
+ MemoryDescriptorPtr->BasePage)) {
+ HighestMemoryDescriptor = MemoryDescriptorPtr;
+ }
+
+ NextListEntry = NextListEntry->Flink;
+ }
+
+ /*
+ * We depend on NextListEntry being the list head later.
+ */
+
+ MaxDescriptorPage = HighestMemoryDescriptor->BasePage +
+ HighestMemoryDescriptor->PageCount;
+
+ NextFreeMemoryDescriptor = NCRAdditionalMemoryDescriptors;
+ /*
+ * Go through firmware's click map and find the entry that contains
+ * the highest memory descriptor.
+ */
+ for (ClickMapEntryPtr = BaseOfClickMap;
+ ((ClickMapEntryPtr < &BaseOfClickMap[ClickMapEntryCount]) &&
+ (ClickMapEntryPtr->Pages != 0)); ++ClickMapEntryPtr) {
+ StartingPage = ClickMapEntryPtr->StartingByte >> PAGE_SHIFT;
+ Temp = StartingPage + ClickMapEntryPtr->Pages;
+ if (MaxDescriptorPage >= Temp) {
+ continue;
+ }
+
+ /*
+ * The click map has memory above the highest memory
+ * descriptor.
+ *
+ * We always add a new memory descriptor to the list.
+ */
+
+ NextFreeMemoryDescriptor->MemoryType = MemoryFree;
+ NextFreeMemoryDescriptor->BasePage = StartingPage;
+ NextFreeMemoryDescriptor->PageCount =
+ ClickMapEntryPtr->Pages;
+ if (MaxDescriptorPage > NextFreeMemoryDescriptor->BasePage) {
+ /*
+ * another descriptor already contains part of this
+ * clickmap entry...adjust the new descriptor so
+ * that it excludes the already accounted for memory.
+ * note that we should get into this condition
+ * at most once.
+ */
+ NextFreeMemoryDescriptor->PageCount -=
+ MaxDescriptorPage -
+ NextFreeMemoryDescriptor->BasePage;
+ NextFreeMemoryDescriptor->BasePage = MaxDescriptorPage;
+ }
+ InsertTailList(NextListEntry,
+ &NextFreeMemoryDescriptor->ListEntry);
+
+ /*
+ * This is the new highest memory descriptor.
+ */
+ HighestMemoryDescriptor = NextFreeMemoryDescriptor;
+ MaxDescriptorPage = HighestMemoryDescriptor->BasePage +
+ HighestMemoryDescriptor->PageCount;
+
+ /*
+ * We can never run out since the maximum was
+ * declared.
+ */
+ ++NextFreeMemoryDescriptor;
+ }
+
+ /*
+ * Clear the mapping to the scratchpad. Not all of it is
+ * reinitialized on a warm reset and the data may get corrupted.
+ * We mapped in two pages.
+ */
+ Temp = (ULONG)MiGetPteAddress(ClickMapPage);
+ *(PULONG)Temp = 0;
+ *((PULONG)Temp+1) = 0;
+ /*
+ * Flush the TLB.
+ */
+ _asm {
+ mov eax, cr3
+ mov cr3, eax
+ }
+}
+
+VOID
+NCRAdjustMemoryDescriptor(MemoryDescriptorPtr, ClickMapEntryPtr)
+PMEMORY_ALLOCATION_DESCRIPTOR MemoryDescriptorPtr;
+NCRClickMapEntry *ClickMapEntryPtr;
+/*++
+
+Routine Description:
+ Make the memory descriptor fit into the clickmap entry
+
+Arguments:
+ Pointer to the memory descriptor
+
+ Pointer to the clickmap entry
+
+Return Value:
+ none.
+
+--*/
+{
+ ULONG Temp;
+ UCHAR Buffer[64];
+
+#if DBG
+ if ((NCRDebug & 0x2) &&
+ (MemoryDescriptorPtr->MemoryType != LoaderFree) &&
+ (MemoryDescriptorPtr->MemoryType != LoaderLoadedProgram) &&
+ (MemoryDescriptorPtr->MemoryType != MemoryFirmwareTemporary) &&
+ (MemoryDescriptorPtr->MemoryType != MemoryFirmwarePermanent) &&
+ (MemoryDescriptorPtr->MemoryType != LoaderOsloaderStack)) {
+ /*
+ * looks like it's already been allocated to
+ * to something other than available
+ */
+ DbgBreakPoint();
+ }
+#endif
+
+ sprintf(Buffer,
+ "MD: Type: %d; BasePage: 0x%08X; PageCount: 0x%X\n",
+ MemoryDescriptorPtr->MemoryType,
+ MemoryDescriptorPtr->BasePage,
+ MemoryDescriptorPtr->PageCount);
+ DBGMSG((Buffer));
+
+ if (ClickMapEntryPtr == NULL) {
+ /*
+ * remove the entry from the list
+ */
+ RemoveEntryList(&MemoryDescriptorPtr->ListEntry);
+ return;
+ }
+
+ sprintf(Buffer,
+ "CM: StartingByte: 0x%08X; Pages: 0x%X\n",
+ ClickMapEntryPtr->StartingByte,
+ ClickMapEntryPtr->Pages);
+ DBGMSG((Buffer));
+
+ Temp = ClickMapEntryPtr->StartingByte >> PAGE_SHIFT;
+ if (MemoryDescriptorPtr->BasePage < Temp) {
+ /*
+ * the memory descriptor starts before the clickmap
+ * entry.
+ */
+ MemoryDescriptorPtr->PageCount -=
+ Temp - MemoryDescriptorPtr->BasePage;
+ MemoryDescriptorPtr->BasePage = Temp;
+ }
+
+ Temp += ClickMapEntryPtr->Pages;
+ if ((MemoryDescriptorPtr->BasePage +
+ MemoryDescriptorPtr->PageCount) > Temp) {
+ /*
+ * the memory descriptor ends after the clickmap
+ * entry.
+ */
+ MemoryDescriptorPtr->PageCount =
+ Temp - MemoryDescriptorPtr->BasePage;
+ }
+}
+
+#endif
+
+VOID
+NCRLimitMemory(LoaderBlockPtr)
+PLOADER_PARAMETER_BLOCK LoaderBlockPtr;
+/*++
+
+Routine Description:
+ For performance work the machine can be booted to only
+ use some of the memory in the machine with the /MAXMEM setting.
+
+ Here we will go through the memory list and remove and free memory
+ above the LimitMemory address
+
+Arguments:
+ Pointer to the loader block
+
+Return Value:
+ none.
+
+--*/
+{
+ ULONG LimitPage;
+ PLIST_ENTRY NextListEntry;
+ PMEMORY_ALLOCATION_DESCRIPTOR MemDesc;
+
+ //
+ // Calculate highest page address
+ //
+
+ LimitPage = LimitMemory * 1024 * 1024 / PAGE_SIZE;
+
+ //
+ // Walk memory descritpor list looking for any pages above LimitPage
+ //
+
+ NextListEntry = LoaderBlockPtr->MemoryDescriptorListHead.Flink;
+ while (NextListEntry != &LoaderBlockPtr->MemoryDescriptorListHead) {
+ MemDesc = CONTAINING_RECORD(NextListEntry,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry);
+
+ NextListEntry = NextListEntry->Flink;
+
+ if (MemDesc->BasePage + MemDesc->PageCount > LimitPage) {
+ //
+ // For memory descriptor which extends above LimitPage
+ // Either remove the memory descriptor from the system, or
+ // shrink it.
+ //
+
+ if (MemDesc->MemoryType != MemoryFree) {
+ DBGMSG(("NCRLimitMemory: non free memory region not freed"));
+ continue;
+ }
+
+ if (MemDesc->BasePage > LimitPage) {
+ RemoveEntryList(&MemDesc->ListEntry);
+ } else {
+ MemDesc->PageCount = MemDesc->BasePage + MemDesc->PageCount - LimitPage;
+ }
+ }
+ }
+}
+
+
+VOID
+NCRSetupDiagnosticProcessor(LoaderBlockPtr)
+PLOADER_PARAMETER_BLOCK LoaderBlockPtr;
+/*++
+
+Routine Description:
+ Determine whether the diagnostic processor is using COM1. If so,
+ make sure that the serial driver leaves COM1 alone.
+
+ Note that the interface used will have to be changed to use
+ the registry when the serial driver makes the switch.
+
+Arguments:
+ Pointer to the loader block
+
+Return Value:
+ none.
+
+--*/
+{
+ extern PUCHAR KdComPortInUse;
+
+ UCHAR FirmwareFlags;
+
+ HalpGetCmosData(1, 0x7803, (PUCHAR)&FirmwareFlags, 1);
+ if ((FirmwareFlags & 0x80) == 0) {
+ /*
+ * Kernel debug not set.
+ */
+ return;
+ }
+
+ if (KdComPortInUse == (PUCHAR)COM1_PORT) {
+ /*
+ * The debugger is using COM1.
+ */
+ return;
+ }
+
+ HalDisplayString(MSG_DIAG_ENABLED);
+ UNREFERENCED_PARAMETER(LoaderBlockPtr);
+}
+
+VOID
+NCRParseLoaderOptions (PUCHAR Options)
+{
+ ULONG l;
+
+ if (Options == NULL)
+ return;
+
+ NCRGetValue (Options, "NCRDEBUG", &NCRDebug);
+
+ NCRGetValue (Options, "MAXMEM", &LimitMemory);
+
+ if (NCRGetValue (Options, "PROCESSORS", &l)) {
+ if (l >= 1 && l <= NCR_MAX_NUMBER_QUAD_PROCESSORS)
+ NCRMaxProcessorCount = l;
+ }
+
+ if (NCRGetValue (Options, "NEVERCLAIM", &l)) {
+ DefaultNeverClaimIRQs = l;
+ }
+
+ if (NCRGetValue (Options, "LARCPAGEMASK", &l)) {
+ NCRLarcPageMask = l;
+ }
+}
+
+
+BOOLEAN
+NCRGetValue (PUCHAR Options, PUCHAR String, PULONG Value)
+{
+ PUCHAR p, s, t;
+
+ // strstr (Options, String);
+ for (p=Options; *p; p++) {
+ for (s=String, t=p; *t == *s; s++, t++) {
+ if (*s == 0)
+ break;
+ }
+
+ if (*s == 0)
+ break;
+ }
+
+ if (*p == 0) {
+ return FALSE;
+ }
+
+
+ for (p += strlen (String); *p && (*p < '0' || *p > '9'); p++) ;
+
+ // atol (p)
+ for (*Value = 0L; *p >= '0' && *p <= '9'; p++) {
+ *Value = *Value * 10 + *p - '0';
+ }
+
+ return TRUE;
+}
+
+
+
+#define MAX_PT 8
+
+extern StartPx_PMStub();
+
+
+PVOID MpFreeCR3[MAX_PT]; // remember pool memory to free
+
+ULONG
+HalpBuildTiledCR3 (
+ IN PKPROCESSOR_STATE ProcessorState
+ )
+/*++
+
+Routine Description:
+ When the x86 processor is reset it starts in real-mode. In order to
+ move the processor from real-mode to protected mode with flat addressing
+ the segment which loads CR0 needs to have it's linear address mapped
+ to machine the phyiscal location of the segment for said instruction so
+ the processor can continue to execute the following instruction.
+
+ This function is called to built such a tiled page directory. In
+ addition, other flat addresses are tiled to match the current running
+ flat address for the new state. Once the processor is in flat mode,
+ we move to a NT tiled page which can then load up the remaining processors
+ state.
+
+Arguments:
+ ProcessorState - The state the new processor should start in.
+
+Return Value:
+ Physical address of Tiled page directory
+
+
+--*/
+{
+#define GetPdeAddress(va) ((PHARDWARE_PTE)((((((ULONG)(va)) >> 22) & 0x3ff) << 2) + (PUCHAR)MpFreeCR3[0]))
+#define GetPteAddress(va) ((PHARDWARE_PTE)((((((ULONG)(va)) >> 12) & 0x3ff) << 2) + (PUCHAR)pPageTable))
+
+// bugbug kenr 27mar92 - fix physical memory usage!
+
+ MpFreeCR3[0] = ExAllocatePool (NonPagedPool, PAGE_SIZE);
+ RtlZeroMemory (MpFreeCR3[0], PAGE_SIZE);
+
+ //
+ // Map page for real mode stub (one page)
+ //
+ HalpMapCR3 ((ULONG) NonbootStartupPhysicalPtr,
+ NonbootStartupPhysicalPtr,
+ PAGE_SIZE);
+
+ //
+ // Map page for protect mode stub (one page)
+ //
+ HalpMapCR3 ((ULONG) &StartPx_PMStub, NULL, 0x1000);
+
+
+ //
+ // Map page(s) for processors GDT
+ //
+ HalpMapCR3 (ProcessorState->SpecialRegisters.Gdtr.Base, NULL,
+ ProcessorState->SpecialRegisters.Gdtr.Limit);
+
+
+ //
+ // Map page(s) for processors IDT
+ //
+ HalpMapCR3 (ProcessorState->SpecialRegisters.Idtr.Base, NULL,
+ ProcessorState->SpecialRegisters.Idtr.Limit);
+
+ return MmGetPhysicalAddress (MpFreeCR3[0]).LowPart;
+}
+
+
+VOID
+HalpMapCR3 (
+ IN ULONG VirtAddress,
+ IN PVOID PhysicalAddress,
+ IN ULONG Length
+ )
+/*++
+
+Routine Description:
+ Called to build a page table entry for the passed page directory.
+ Used to build a tiled page directory with real-mode & flat mode.
+
+Arguments:
+ VirtAddress - Current virtual address
+ PhysicalAddress - Optional. Physical address to be mapped to, if passed
+ as a NULL then the physical address of the passed
+ virtual address is assumed.
+ Length - number of bytes to map
+
+Return Value:
+ none.
+
+--*/
+{
+ ULONG i;
+ PHARDWARE_PTE PTE;
+ PVOID pPageTable;
+ PHYSICAL_ADDRESS pPhysicalPage;
+
+
+ while (Length) {
+ PTE = GetPdeAddress (VirtAddress);
+ if (!PTE->PageFrameNumber) {
+ pPageTable = ExAllocatePool (NonPagedPool, PAGE_SIZE);
+ RtlZeroMemory (pPageTable, PAGE_SIZE);
+
+ for (i=0; i<MAX_PT; i++) {
+ if (!MpFreeCR3[i]) {
+ MpFreeCR3[i] = pPageTable;
+ break;
+ }
+ }
+ ASSERT (i<MAX_PT);
+
+ pPhysicalPage = MmGetPhysicalAddress (pPageTable);
+ PTE->PageFrameNumber = (pPhysicalPage.LowPart >> PAGE_SHIFT);
+ PTE->Valid = 1;
+ PTE->Write = 1;
+ }
+
+ pPhysicalPage.LowPart = PTE->PageFrameNumber << PAGE_SHIFT;
+ pPhysicalPage.HighPart = 0;
+ pPageTable = MmMapIoSpace (pPhysicalPage, PAGE_SIZE, TRUE);
+
+ PTE = GetPteAddress (VirtAddress);
+
+ if (!PhysicalAddress) {
+ PhysicalAddress = (PVOID)MmGetPhysicalAddress ((PVOID)VirtAddress).LowPart;
+ }
+
+ PTE->PageFrameNumber = ((ULONG) PhysicalAddress >> PAGE_SHIFT);
+ PTE->Valid = 1;
+ PTE->Write = 1;
+
+ MmUnmapIoSpace (pPageTable, PAGE_SIZE);
+
+ PhysicalAddress = 0;
+ VirtAddress += PAGE_SIZE;
+ if (Length > PAGE_SIZE) {
+ Length -= PAGE_SIZE;
+ } else {
+ Length = 0;
+ }
+ }
+}
+
+
+
+VOID
+HalpFreeTiledCR3 (
+ VOID
+ )
+/*++
+
+Routine Description:
+ Free's any memory allocated when the tiled page directory was built.
+
+Arguments:
+ none
+
+Return Value:
+ none
+--*/
+{
+ ULONG i;
+
+ for (i=0; MpFreeCR3[i]; i++) {
+ ExFreePool (MpFreeCR3[i]);
+ MpFreeCR3[i] = 0;
+ }
+}
+
+
+
+
+ULONG
+HalpNCRGetSystemInterruptVector(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ BusInterruptLevel - Supplies the bus specific interrupt level.
+
+ BusInterruptVector - Supplies the bus specific interrupt vector.
+
+ Irql - Returns the system request priority.
+
+ Affinity - Returns the system wide irq affinity.
+
+Return Value:
+
+ Returns the system interrupt vector corresponding to the specified device.
+
+--*/
+{
+ ULONG SystemVector;
+
+ UNREFERENCED_PARAMETER( BusHandler );
+ UNREFERENCED_PARAMETER( RootHandler );
+
+ SystemVector = BusInterruptVector + PRIMARY_VECTOR_BASE;
+
+ if (SystemVector < PRIMARY_VECTOR_BASE ||
+ HalpIDTUsage[SystemVector].Flags & IDTOwned ) {
+
+ //
+ // This is an illegal BusInterruptVector and cannot be connected.
+ //
+
+ return(0);
+ }
+
+ *Irql = (KIRQL)(HIGHEST_LEVEL_FOR_8259 - BusInterruptLevel);
+ *Affinity = HalpDefaultInterruptAffinity;
+ ASSERT(HalpDefaultInterruptAffinity);
+
+ return SystemVector;
+}
+
+
+
+VOID
+HalpInitOtherBuses (
+ VOID
+ )
+{
+ PBUS_HANDLER InternalBus;
+ PBUS_HANDLER McaBus;
+ PBUS_HANDLER Bus;
+ CAT_CONTROL cat_control;
+ UCHAR data;
+ LONG status;
+
+
+ if (NCRPlatform != NCR3360) {
+ HalpInitializeCatBusDriver();
+ HalpDisableSingleBitErrorDET();
+ HalpInitializeSMCInterface();
+ NCRFindExtendedProcessors();
+ if ((NCRDebug & 0x20) == 1) {
+ HalpInitializeLarc();
+ }
+
+
+//
+// Turn off cache ownership it NCRDebug bit is set and you only have one Quad board installed
+// in slot 1
+//
+
+ if ((NCRDebug & 0x10) && (NCRExistingProcessorMask == 0xf)) {
+
+ DBGMSG(("HalpInitOtherBuses: Changing QCC Asic on Quad\n"));
+ cat_control.Module = QUAD_LL2_A0;
+ cat_control.Asic = QCC0;
+ cat_control.Command = READ_REGISTER;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x4;
+ status = HalpCatBusIo(&cat_control,&data);
+
+ DBGMSG(("HalpInitOtherBuses: QCC0 A0 Nside Config 0 read 0x%x\n", data));
+
+ data |= 0x40;
+
+ cat_control.Module = QUAD_LL2_A0;
+ cat_control.Asic = QCC0;
+ cat_control.Command = WRITE_REGISTER;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x4;
+ status = HalpCatBusIo(&cat_control,&data);
+
+ cat_control.Module = QUAD_LL2_B0;
+ cat_control.Asic = QCC0;
+ cat_control.Command = READ_REGISTER;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x4;
+ status = HalpCatBusIo(&cat_control,&data);
+
+ DBGMSG(("HalpInitOtherBuses: QCC0 B0 Nside Config 0 read 0x%x\n", data));
+
+ data |= 0x40;
+
+ cat_control.Module = QUAD_LL2_B0;
+ cat_control.Asic = QCC0;
+ cat_control.Command = WRITE_REGISTER;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x4;
+ status = HalpCatBusIo(&cat_control,&data);
+
+ cat_control.Module = QUAD_LL2_A0;
+ cat_control.Asic = QCC1;
+ cat_control.Command = READ_REGISTER;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x4;
+ status = HalpCatBusIo(&cat_control,&data);
+
+ DBGMSG(("HalpInitOtherBuses: QCC1 A0 Nside Config 0 read 0x%x\n", data));
+
+ data |= 0x40;
+
+ cat_control.Module = QUAD_LL2_A0;
+ cat_control.Asic = QCC1;
+ cat_control.Command = WRITE_REGISTER;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x4;
+ status = HalpCatBusIo(&cat_control,&data);
+
+ cat_control.Module = QUAD_LL2_B0;
+ cat_control.Asic = QCC1;
+ cat_control.Command = READ_REGISTER;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x4;
+ status = HalpCatBusIo(&cat_control,&data);
+
+ DBGMSG(("HalpInitOtherBuses: QCC1 B0 Nside Config 0 read 0x%x\n", data));
+
+ data |= 0x40;
+
+ cat_control.Module = QUAD_LL2_B0;
+ cat_control.Asic = QCC1;
+ cat_control.Command = WRITE_REGISTER;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x4;
+ status = HalpCatBusIo(&cat_control,&data);
+
+
+ cat_control.Module = QUAD_BB0;
+ cat_control.Asic = QABC;
+ cat_control.Command = READ_REGISTER;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0xb;
+ status = HalCatBusIo(&cat_control,&data);
+
+ DBGMSG(("HalpInitOtherBuses: QABC Nbus Config read 0x%x\n", data));
+
+ data |= 0x10;
+
+ cat_control.Module = QUAD_BB0;
+ cat_control.Asic = QABC;
+ cat_control.Command = WRITE_REGISTER;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0xb;
+ status = HalCatBusIo(&cat_control,&data);
+ }
+
+
+ InternalBus = HalpHandlerForBus( Internal, 0);
+ InternalBus->GetInterruptVector = HalpNCRGetSystemInterruptVector;
+
+ //
+ // Change MCA bus #0
+ //
+
+ McaBus = HalpHandlerForBus( MicroChannel, 0);
+ McaBus->GetInterruptVector = HalpGetMCAInterruptVector;
+
+
+ //
+ // Build MCA bus #1 if present
+ //
+
+ if (NCRSegmentIoRegister != NULL) {
+ Bus = HalpAllocateBusHandler (MicroChannel, Pos, 1, Internal, 0, 0);
+ Bus->GetBusData = HalpGetPosData;
+ Bus->GetInterruptVector = HalpGetSMCAInterruptVector;
+ Bus->TranslateBusAddress = HalpTranslateSMCBusAddress;
+ Bus->AdjustResourceList = HalpAdjustMCAResourceList;
+ }
+ }
+}
+
+
+
+VOID
+HalpDisableSingleBitErrorDET (
+
+ )
+/*++
+
+Routine Description:
+ Disable Single Bit Error Reporting
+
+Arguments:
+ none
+
+Return Value:
+ none
+--*/
+{
+ CAT_CONTROL cat_control;
+ UCHAR data;
+ LONG status;
+
+//
+// Disable single bit error interrupt MMC on memory board 0
+//
+
+ cat_control.Module = MEMORY0;
+ cat_control.Asic = MMC1;
+
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = MMC1_Config1;
+ cat_control.Command = READ_REGISTER;
+ status = HalpCatBusIo(&cat_control,&data);
+
+ if (status == CATNOERR) {
+//
+// disable reporting via mem_error_int
+// correction still enabled
+//
+ data |= MMC1_SBErr_DetectDisable;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = MMC1_Config1;
+ cat_control.Command = WRITE_REGISTER;
+ HalpCatBusIo(&cat_control,&data);
+ }
+
+
+//
+// Disable single bit error interrupt MMC on memory board 1
+//
+
+ cat_control.Module = MEMORY1;
+ cat_control.Asic = MMC1;
+
+
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = MMC1_Config1;
+ cat_control.Command = READ_REGISTER;
+ status = HalpCatBusIo(&cat_control,&data);
+
+ if (status == CATNOERR) {
+//
+// disable reporting via mem_error_int
+// correction still enabled
+//
+ data |= MMC1_SBErr_DetectDisable;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = MMC1_Config1;
+ cat_control.Command = WRITE_REGISTER;
+ HalpCatBusIo(&cat_control,&data);
+ }
+
+}
+
+
+VOID
+HalpInitializeSMCInterface (
+
+ )
+/*++
+
+Routine Description:
+ Check for SMC board and it present setup segment register.
+
+Arguments:
+ none
+
+Return Value:
+ none
+--*/
+
+{
+ CAT_CONTROL cat_control;
+ UCHAR data;
+ LONG status;
+ PHYSICAL_ADDRESS physical_address;
+ PUCHAR mapped_segment_address;
+
+ cat_control.Module = SECONDARYMC;
+ cat_control.Asic = CAT_I;
+ cat_control.Command = READ_REGISTER;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0;
+ status = HalpCatBusIo(&cat_control,&data);
+
+ if (status != CATNOMOD) {
+
+/*
+ * SMC is installed in this unit
+ */
+ DBGMSG(("HalpInitializeSMCInterface: SMC has been detected...\n"));
+
+ physical_address.HighPart = 0;
+ physical_address.LowPart = NCRSegmentIoAddress;
+
+ mapped_segment_address = (PUCHAR) MmMapIoSpace(physical_address, sizeof(UCHAR), FALSE);
+
+ if (mapped_segment_address != NULL) {
+ NCRSegmentIoRegister = mapped_segment_address;
+ }
+
+/*RMU temp fix for arb control register on DMA asic. */
+
+ WRITE_PORT_UCHAR((PUCHAR)0x10090, (UCHAR)0x8f);
+ }
+}
+
+
+
+
+
+
+VOID
+HalpCatReportSMC (
+ )
+
+/*++
+
+Routine Description:
+ Place information about system modules into the registry.
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ PMODULE module;
+ PASIC asic;
+
+ PWSTR smc_path = L"\\Registry\\Machine\\Hardware\\DESCRIPTION\\System\\MultifunctionAdapter\\1";
+
+
+ UNICODE_STRING unicode_smc;
+ OBJECT_ATTRIBUTES smc_attributes;
+ HANDLE smc_handle;
+
+
+ UNICODE_STRING unicode_name;
+
+ UNICODE_STRING unicode_mca;
+
+ NTSTATUS status;
+ ULONG tmp;
+
+ CONFIGURATION_COMPONENT component;
+
+ ULONG ConfigurationDataLength;
+ SMC_RESOURCES SmcConfig;
+ int i;
+
+
+/*
+ *
+ */
+ RtlInitUnicodeString(&unicode_smc,smc_path);
+
+ InitializeObjectAttributes( &smc_attributes, &unicode_smc,
+ OBJ_CASE_INSENSITIVE, NULL, NULL);
+
+ status = ZwCreateKey(&smc_handle, KEY_READ | KEY_WRITE, &smc_attributes, 0,
+ (PUNICODE_STRING)NULL, REG_OPTION_VOLATILE, NULL);
+
+
+
+ RtlInitUnicodeString(&unicode_name,L"Component Information");
+ RtlZeroMemory (&component, sizeof(CONFIGURATION_COMPONENT));
+ component.AffinityMask = 0xffffffff;
+
+ status = ZwSetValueKey(
+ smc_handle,
+ &unicode_name,
+ 0,
+ REG_BINARY,
+ &component.Flags,
+ FIELD_OFFSET(CONFIGURATION_COMPONENT, ConfigurationDataLength) -
+ FIELD_OFFSET(CONFIGURATION_COMPONENT, Flags)
+ );
+
+
+ RtlInitUnicodeString(&unicode_name,L"Configuration Data");
+ RtlZeroMemory (&SmcConfig, sizeof(SMC_RESOURCES));
+
+ ConfigurationDataLength = sizeof(SMC_RESOURCES);
+
+ //
+ // Set up InterfaceType and BusNumber for the component.
+ //
+
+ SmcConfig.ConfigurationData.InterfaceType = MicroChannel;
+ SmcConfig.ConfigurationData.BusNumber = 1;
+ SmcConfig.ConfigurationData.PartialResourceList.Count = 1;
+
+ SmcConfig.ConfigurationData.PartialResourceList.PartialDescriptors[0].Type =
+ CmResourceTypeDeviceSpecific;
+
+ SmcConfig.ConfigurationData.PartialResourceList.PartialDescriptors[0].ShareDisposition =
+ CmResourceShareUndetermined;
+
+ SmcConfig.ConfigurationData.PartialResourceList.PartialDescriptors[0].u.DeviceSpecificData.DataSize =
+ sizeof(CM_MCA_POS_DATA)*10;
+
+ for (i = 0; i < 8; i++) {
+ HalGetBusData(Pos, 1, i, &SmcConfig.PosData[i], sizeof(CM_MCA_POS_DATA));
+ }
+
+
+ //
+ // Write the newly constructed configuration data to the hardware registry
+ //
+
+ status = ZwSetValueKey(
+ smc_handle,
+ &unicode_name,
+ 0,
+ REG_FULL_RESOURCE_DESCRIPTOR,
+ &SmcConfig,
+ ConfigurationDataLength
+ );
+
+
+
+ RtlInitUnicodeString(&unicode_name,L"Identifier");
+ RtlInitUnicodeString(&unicode_mca,L"MCA");
+ status = ZwSetValueKey(smc_handle, &unicode_name, 0, REG_SZ,
+ unicode_mca.Buffer,
+ unicode_mca.Length + sizeof(UNICODE_NULL));
+
+ status = ZwClose(smc_handle);
+
+}
+
+
+
+
+VOID
+HalSetStatusChangeInterruptState(
+ ULONG State
+ )
+
+/*++
+
+Routine Description:
+ This HAL function will enable or disable the revectoring of the
+ Status Change Interrupt to vector 57.
+
+Arguments:
+
+Return Value:
+
+--*/
+
+{
+ if (State) {
+ NCRStatusChangeInterruptEnabled = 0x1;
+ } else {
+ NCRStatusChangeInterruptEnabled = 0x0;
+ }
+
+}
+
+
+
+
+ULONG
+NCRTranslateCMOSMask(
+ ULONG CmosMask
+ )
+
+/*++
+
+Routine Description:
+ This function translates the CMOS processor Mask into what we want to use.
+ This function must change for 32 way
+
+ CMOS format is: each nibble contains all processors 0 in the system where each bit
+ position denotes the processor slot. Therefore a system with
+ one Quad board has a mask of (0x1111), 2 Quad boards has a
+ mask of (0x3333), 3 Quad boards has a mask of (0x7777), and
+ 4 Quad boards has a mask of (0xffff).
+
+ Our format is: each nibble contains all processors on one Quad board where each
+ bit position denotes the processor on one board. Therefore a
+ system with one Quad board has a mask of (0x000f), 2 Quad boards
+ has a mask of (0x00ff), 3 Quad boards has a mask of (0x0ffff), and
+ 4 Quad boards has a mask of (xffff);
+
+Arguments:
+
+Return Value:
+ The Processor Mask that the Hal wants to use for bringing up the system.
+
+
+--*/
+
+{
+ ULONG working_mask = CmosMask;
+ ULONG existing_mask = 0x0;
+ int i, j;
+
+ // loop thru each processor number
+
+ for (i = 0; i < 4; i++ ) {
+
+ // loop thru each processor slot
+
+ for (j = 0; j < 4; j++) {
+ if (working_mask & 0x1) {
+ existing_mask |= ((1 << i) << (j<<2));
+ }
+ working_mask >>= 1;
+ }
+ }
+
+ return existing_mask;
+}
+
+
+ULONG
+NCRTranslateToCMOSMask(
+ ULONG Mask
+ )
+
+/*++
+
+Routine Description:
+ Do the oppsite of NCRTranslateCMOSMask()
+
+Arguments:
+
+Return Value:
+ The Processor Mask that CMOS uses.
+
+
+--*/
+
+{
+ ULONG working_mask = Mask;
+ ULONG cmos_mask = 0x0;
+ int i;
+
+ for (i = 0; i < 4; i++ ) {
+
+ if (working_mask & 1) {
+ cmos_mask |= (0x1 << i);
+ }
+
+ if (working_mask & 2) {
+ cmos_mask |= (0x10 << i);
+ }
+ working_mask >>= 4;
+ }
+ return cmos_mask;
+}
+
+
+VOID
+NCRFindExtendedProcessors(
+ )
+/*++
+
+Routine Description:
+ Loop over the CAT bus and find all extended processors
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+ CAT_CONTROL cat_control;
+ UCHAR data;
+ UCHAR qabc_ext;
+ LONG status;
+ UCHAR module;
+ int slot;
+
+
+ for(slot = 0; slot < 4; slot++) {
+
+ switch (slot) {
+ case 0:
+ module = QUAD_BB0;
+ break;
+ case 1:
+ module = QUAD_BB1;
+ break;
+ case 2:
+ module = QUAD_BB2;
+ break;
+ case 3:
+ module = QUAD_BB3;
+ break;
+ }
+ cat_control.Module = module;
+ cat_control.Asic = QABC;
+ cat_control.Command = READ_SUBADDR;
+ cat_control.NumberOfBytes = 1;
+ cat_control.Address = 0x8;
+ status = HalpCatBusIo(&cat_control,&qabc_ext);
+
+ if (status == CATNOERR) {
+// NCRExtendedProcessor0Mask |= (qabc_ext & 0xf) << (qabc_ext << 2);
+ NCRExtendedProcessor0Mask |= (qabc_ext & 0xf) << (slot << 2);
+ NCRExtendedProcessor1Mask |= (qabc_ext >> 4) << (slot << 2);
+ }
+ }
+ NCRExtendedProcessorMask = NCRExtendedProcessor0Mask | NCRExtendedProcessor1Mask;
+
+ DBGMSG(("NCRFindExtendedProcessors: Extended 0 = 0x%x, 1 = 0x%x\n",
+ NCRExtendedProcessor0Mask, NCRExtendedProcessor1Mask));
+}
+
+
+
+
+
+
+
+
+VOID
+NCRAdjustDynamicClaims(
+ )
+/*++
+
+Routine Description:
+ Determine how man interrupts a processor should claim. This is called when
+ processors are enabled and with interrups are enabled and disabled
+
+Arguments:
+
+Return Value:
+
+--*/
+{
+
+ ULONG processors = 0;
+ ULONG max_claimable_irqs = 0;
+ ULONG processor;
+ ULONG irq_count;
+ ULONG mask;
+
+ //
+ // Count the number of processors that can take device interrupts.
+ //
+
+ for (mask = HalpDefaultInterruptAffinity; mask != 0; mask >>= 1) {
+ if (mask & 0x1) {
+ processors++;
+ }
+ }
+
+ for (processor = 0; processor < NCRActiveProcessorCount; processor++) {
+
+ mask = NCRProcessorIDR[processor];
+ mask |= NCRNeverClaimIRQs; // do not count never claim IRQs
+
+ irq_count = 0;
+
+ for (mask = ~mask; (mask != 0); mask >>= 1) {
+ if (mask & 0x1) {
+ irq_count++;
+ }
+ }
+ if (irq_count > max_claimable_irqs) {
+ max_claimable_irqs = irq_count;
+ }
+ }
+
+ if ((max_claimable_irqs % processors) == 0) {
+ max_claimable_irqs /= processors;
+ } else {
+ max_claimable_irqs /= processors;
+ max_claimable_irqs++;
+ }
+ if (max_claimable_irqs == 0) {
+ max_claimable_irqs = 1;
+ }
+ NCRMaxIRQsToClaim = max_claimable_irqs;
+}
+
+
+#ifdef DBG
+
+
+VOID
+NCRConsoleDebug(
+ ULONG MsgNumber,
+ ULONG Data
+ )
+
+{
+ CHAR buffer[256];
+
+ switch (MsgNumber) {
+
+ case 1:
+ sprintf(buffer, "HalInitializeProcessor called for processor %d\n", Data);
+ HalDisplayString(buffer);
+ break;
+ case 2:
+ sprintf(buffer, "HalStartNextProcessor trying to wakeup 0x%x\n", Data);
+ HalDisplayString(buffer);
+ break;
+ case 3:
+ sprintf(buffer, "HalStartNextProcessor Processor is now awake\n", Data);
+ HalDisplayString(buffer);
+ break;
+
+
+
+ }
+}
+
+#endif
+
+
+NTSTATUS
+HalpGetMcaLog (
+ OUT PMCA_EXCEPTION Exception,
+ OUT PULONG ReturnedLength
+ )
+{
+ return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS
+HalpMcaRegisterDriver(
+ IN PMCA_DRIVER_INFO DriverInfo
+ )
+{
+ return STATUS_NOT_SUPPORTED;
+}
+
+
+ULONG
+FASTCALL
+HalSystemVectorDispatchEntry (
+ IN ULONG Vector,
+ OUT PKINTERRUPT_ROUTINE **FlatDispatch,
+ OUT PKINTERRUPT_ROUTINE *NoConnection
+ )
+{
+ return FALSE;
+}
diff --git a/private/ntos/nthals/halncr/i386/ncrnls.h b/private/ntos/nthals/halncr/i386/ncrnls.h
new file mode 100644
index 000000000..17d4646df
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrnls.h
@@ -0,0 +1,62 @@
+/*++
+
+Copyright (c) 1993 Microsoft Corporation
+
+Module Name:
+
+ ncrnls.h
+
+Abstract:
+
+ Strings which are used in the HAL
+
+ English
+
+--*/
+
+#define MSG_NCR_PLATFORM "NCR platform: %s\n"
+#define MSG_UNKOWN_NCR_PLATFORM "HAL: 0x%08X: Unrecognized NCR platform\n"
+#define MSG_HARDWARE_ERROR3 "Call your NCR hardware vendor for support\n\n"
+#define MSG_DIAG_ENABLED "Diagnostic processor using COM1\n"
+
+#define MSG_GLOBAL_NMI "Global NMI"
+#define MSG_SHUTDOWN_OCCURRED "Shutdown occurred"
+#define MSG_LOCAL_EXTERNAL_ERROR "Local extern error"
+#define MSG_SB_READ_DATA_PARITY_ERROR "SB Read Data Parity Error"
+#define MSG_SB_ERROR_L_TERMINATION "SB ERROR_L Termination"
+#define MSG_P5_INTERNAL_ERROR "P5 internal error"
+#define MSG_PROCESSOR_HALTED "Processor halted"
+
+#define MSG_SB_ADDRESS_PARITY_ERROR "SB Address parity error"
+#define MSG_SB_DATA_PARITY_ERROR "SB data parity error"
+#define MSG_SHUTDOWN_ERROR_INT_L "Shutdown ERR_INT_L"
+#define MSG_EXTERNAL_ERROR_INT_L "External error ERR_INT_L"
+#define MSG_P_IERR_L_ERROR_INT_L "P_IERR_L error ERR_INT_L"
+
+#define MSG_VDLC_DATA_ERROR "VDLC data error"
+#define MSG_LST_ERROR "LST error"
+#define MSG_BUS_A_DATA_PARITY_ERROR "Bus A data parity error"
+#define MSG_BUS_B_DATA_PARITY_ERROR "Bus B data parity error"
+#define MSG_LST_UNCORRECTABLE_ERROR "LST uncorrectable error"
+
+#define MSG_MC_MASTER_ERROR "MC master error"
+#define MSG_SA_MASTER_ERROR "SA master error"
+#define MSG_SB_MASTER_ERROR "SB master error"
+#define MSG_MC_TOE_ERROR "MC TOE error"
+#define MSG_ASYNC_ERROR "ASYNC error"
+#define MSG_SYNC_ERROR "SYNC error"
+#define MSG_REFRESH_ERROR "Refresh error"
+#define MSG_SXERROR_L "SxERROR_L error"
+
+#define MSG_FRED "FRED %x: Error Enables = %p Nmi Enables = %p\n"
+#define MSG_A_PARITY "PORT A address parity: %A BIOE = %s. Data parity %A MISC = %s\n"
+#define MSG_B_PARITY "PORT B address parity: %A BIOE = %s. Data parity %A MISC = %s\n"
+#define MSG_A_TOE "PORT A TOE address: %A ID/BOP = %s\n"
+#define MSG_B_TOE "PORT B TOE address: %A ID/BOP = %s\n"
+#define MSG_A_GOOD "%1Bus A good address: %A Status = %s\n"
+#define MSG_B_GOOD "%1Bus B good address: %A Status = %s\n"
+#define MSG_A_LAST "%1Bus A last address: %A\n"
+#define MSG_B_LAST "%1Bus B last address: %A\n"
+#define MSG_MC_ADDRESS "%1MC error address: %A Status = %s\n"
+#define MSG_MC_TIMEOUT "MC timeout error: Status = %s\n"
+#define MSG_MC_PARITY "%1MC address parity error. Status = %s\n"
diff --git a/private/ntos/nthals/halncr/i386/ncrnmi.c b/private/ntos/nthals/halncr/i386/ncrnmi.c
new file mode 100644
index 000000000..097142365
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrnmi.c
@@ -0,0 +1,422 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ ncrnmi.c
+
+Abstract:
+
+ Provides ncr x86 NMI handler
+
+Author:
+
+ kenr
+
+Revision History:
+
+--*/
+#include "halp.h"
+#include "bugcodes.h"
+#include "ncr.h"
+#include "ncrnls.h"
+
+#define SYSTEM_CONTROL_PORT_A 0x92
+#define SYSTEM_CONTROL_PORT_B 0x61
+#define EISA_EXTENDED_NMI_STATUS 0x461
+
+extern ULONG NCRPlatform;
+
+VOID HalpDumpAsicPorts (UCHAR *p, ULONG arg, ...);
+VOID HalpDumpBitsField (UCHAR bits, char *BitMsgs[]);
+VOID HexSubPort (PUCHAR *o, ULONG l);
+VOID HalpDumpFred (UCHAR FredId);
+VOID HalpDumpVMC (UCHAR VMCId);
+VOID HalpDumpMCADDR (UCHAR MCADDRId);
+VOID HalpDumpArbiter (UCHAR ArbiterId);
+
+BOOLEAN HalpSUSSwNmi();
+
+ULONG NmiLock;
+UCHAR HexString[] = "0123456789ABCDEF";
+
+char *NmiStatusRegisterBits[] = {
+ MSG_GLOBAL_NMI, // 0
+ MSG_SHUTDOWN_OCCURRED, // 1
+ MSG_LOCAL_EXTERNAL_ERROR, // 2
+ MSG_SB_READ_DATA_PARITY_ERROR, // 3
+ MSG_SB_ERROR_L_TERMINATION, // 4
+ MSG_P5_INTERNAL_ERROR, // 5
+ NULL, // 6
+ MSG_PROCESSOR_HALTED // 7
+};
+
+char *ParityErrorIntStatusBits[] = {
+ MSG_SB_ADDRESS_PARITY_ERROR, // 0
+ MSG_SB_DATA_PARITY_ERROR, // 1
+ NULL, // 2
+ NULL, // 3
+ NULL, // 4
+ MSG_SHUTDOWN_ERROR_INT_L, // 5
+ MSG_EXTERNAL_ERROR_INT_L, // 6
+ MSG_P_IERR_L_ERROR_INT_L // 7
+};
+
+char *VMCErrorStatusZeroBits[] = {
+ MSG_VDLC_DATA_ERROR, // 0
+ MSG_LST_ERROR, // 1
+ MSG_BUS_A_DATA_PARITY_ERROR, // 2
+ MSG_BUS_B_DATA_PARITY_ERROR, // 3
+ MSG_LST_UNCORRECTABLE_ERROR, // 4
+ NULL, // 5
+ NULL, // 6
+ NULL // 7
+};
+
+char *SBErrorIntStatusBits[] = {
+ MSG_MC_MASTER_ERROR, // 0
+ MSG_SA_MASTER_ERROR, // 1
+ MSG_SA_MASTER_ERROR, // 2
+ MSG_MC_TOE_ERROR, // 3
+ MSG_ASYNC_ERROR, // 4
+ MSG_SYNC_ERROR, // 5
+ MSG_REFRESH_ERROR, // 6
+ MSG_SXERROR_L // 7
+};
+
+char *InterruptStatusOneBits[] = {
+ "PAR_INT_B", // 0
+ "PAR_INT_A", // 1
+ "ELATCHD_B", // 2
+ "ELATCHD_A", // 3
+ "TOE_B", // 4
+ "TOE_A", // 5
+ "PROTO_ERR_B", // 6
+ "PROTO_ERR_A" // 7
+};
+
+char *InterruptStatusTwoBits[] = {
+ "MC_TOE", // 0
+ "COUGAR_NMI", // 1
+ "EXP_MC_TOE", // 2
+ "EXP_COUGAR_NMI", // 3
+ "POWER_FAIL", // 4
+ "ERROR_INT", // 5
+ "SW_NMI", // 6
+ NULL // 7
+};
+
+VOID
+HalHandleNMI(
+ IN OUT PVOID NmiInfo
+ )
+/*++
+
+Routine Description:
+
+ Called DURING an NMI. The system will BugCheck when an NMI occurs.
+ This function can return the proper bugcheck code, bugcheck itself,
+ or return success which will cause the system to iret from the nmi.
+
+ This function is called during an NMI - no system services are available.
+ In addition, you don't want to touch any spinlock which is normally
+ used since we may have been interrupted while owning it, etc, etc...
+
+Warnings:
+
+ Do NOT:
+ Make any system calls
+ Attempt to acquire any spinlock used by any code outside the NMI handler
+ Change the interrupt state. Do not execute any IRET inside this code
+
+ Passing data to non-NMI code must be done using manual interlocked
+ functions. (xchg instructions).
+
+Arguments:
+
+ NmiInfo - Pointer to NMI information structure (TBD)
+ - NULL means no NMI information structure was passed
+
+Return Value:
+
+ BugCheck code
+
+--*/
+{
+ UCHAR StatusByte;
+
+ _asm {
+nmi00:
+ lock bts NmiLock, 0
+ jnc nmilocked
+
+nmi10:
+ test NmiLock, 1
+ jnz short nmi10
+ jmp short nmi00
+nmilocked:
+ }
+
+ if (NmiLock & 2) {
+ // some other processor has already processed the Nmi and
+ // determined that the machine should crash - just stop
+ // this processor
+
+
+
+ NmiLock = 2; // free busy bit
+ KeEnterKernelDebugger ();
+ return;
+ }
+
+
+ if (NCRPlatform != NCR3360) {
+
+//
+// If is this is the Dump switch
+//
+ if (HalpSUSSwNmi() == TRUE) {
+ NmiLock = 2;
+ KeEnterKernelDebugger();
+ return;
+ }
+ }
+
+ HalDisplayString (MSG_HARDWARE_ERROR1);
+ HalDisplayString (MSG_HARDWARE_ERROR3);
+
+ StatusByte = READ_PORT_UCHAR((PUCHAR) SYSTEM_CONTROL_PORT_B);
+
+ if (StatusByte & 0x80) {
+ HalDisplayString (MSG_NMI_PARITY);
+ }
+
+ if (StatusByte & 0x40) {
+ HalDisplayString (MSG_NMI_CHANNEL_CHECK);
+ }
+
+ if (NCRPlatform == NCR3360) {
+ HalpDumpFred (0x41); // fred 1
+ HalpDumpFred (0x61); // fred 2
+
+ HalpDumpVMC (0x81); // memory 1
+ HalpDumpVMC (0x91); // memory 2
+
+ HalpDumpArbiter (0xC1); // arbiter
+ HalpDumpMCADDR (0xC0); // mcaddr
+ } else {
+//
+// For 3450 and 3550 let SUS go do FRU analysis and log the error to SUS
+// error log. After SUS logs the error the system will reboot and the
+// HwMon service will copy the SUS error log to the NT error log.
+//
+
+ HalDisplayString ("NMI: 345x/35xx SUS Logging Error\n");
+ HalpSUSLogError();
+ }
+
+ HalDisplayString (MSG_HALT);
+ NmiLock = 2;
+ KeEnterKernelDebugger ();
+}
+
+
+VOID HalpDumpFred (UCHAR FredId)
+{
+ UCHAR c;
+
+ WRITE_PORT_UCHAR ((PUCHAR) 0x97, FredId);
+ c = READ_PORT_UCHAR ((PUCHAR) 0xf801);
+ if (c & 0xf0 != 0x20) {
+ return ;
+ }
+
+ HalpDumpAsicPorts (MSG_FRED, FredId, 0xf808, 0xf80d);
+
+ c = READ_PORT_UCHAR ((PUCHAR) 0xf809);
+ HalpDumpBitsField (c, NmiStatusRegisterBits);
+
+ c = READ_PORT_UCHAR ((PUCHAR) 0xf80b);
+ HalpDumpBitsField (c, ParityErrorIntStatusBits);
+ HalDisplayString("\n");
+}
+
+VOID HalpDumpVMC (UCHAR VMCId)
+{
+ UCHAR c;
+
+ WRITE_PORT_UCHAR ((PUCHAR) 0x97, VMCId);
+ c = READ_PORT_UCHAR ((PUCHAR) 0xf800);
+ if (c != 0x81 && c != VMCId) {
+ return ;
+ }
+
+ HalpDumpAsicPorts ("VMC %x: S0 = %p S1 = %p S2 = %p BD/D = %p\n",
+ VMCId, 0xf804, 0xf808, 0xf809, 0xf80a);
+
+ c = READ_PORT_UCHAR ((PUCHAR) 0xf80d);
+ HalpDumpBitsField (c, VMCErrorStatusZeroBits);
+
+ if (c & 0x04) {
+ HalpDumpAsicPorts (MSG_A_PARITY, 0x13, 0x14, 0x18, 0x19);
+ }
+
+ if (c & 0x08) {
+ HalpDumpAsicPorts (MSG_B_PARITY, 0x23, 0x24, 0x28, 0x29);
+ }
+
+ WRITE_PORT_UCHAR ((PUCHAR) 0x97, 0xc1); // select arbiter
+ c = READ_PORT_UCHAR ((PUCHAR) 0xf808);
+ WRITE_PORT_UCHAR ((PUCHAR) 0x97, VMCId);
+
+ if (c & 0x20) { // check for s_error
+ HalpDumpAsicPorts (MSG_A_TOE, 0x1d, 0x1e);
+
+ }
+
+ if (c & 0x10) { // check for s_error
+ HalpDumpAsicPorts (MSG_B_TOE, 0x2d, 0x2e);
+ }
+ HalDisplayString("\n");
+}
+
+VOID HalpDumpMCADDR (UCHAR MCADDRId)
+{
+ UCHAR c;
+
+ WRITE_PORT_UCHAR ((PUCHAR) 0x97, MCADDRId);
+ c = READ_PORT_UCHAR ((PUCHAR) 0xf800);
+ if (c != MCADDRId) {
+ return ;
+ }
+ WRITE_PORT_UCHAR ((PUCHAR) 0xF807, 0);
+
+ HalpDumpAsicPorts ("MCADDR: %x\n", MCADDRId);
+ HalpDumpAsicPorts (MSG_A_GOOD, 0x40, 0x43, 0x44);
+ HalpDumpAsicPorts (MSG_B_GOOD, 0x45, 0x48, 0x49);
+ HalpDumpAsicPorts (MSG_A_LAST, 0x4a, 0x4d);
+ HalpDumpAsicPorts (MSG_B_LAST, 0x4e, 0x51);
+
+ WRITE_PORT_UCHAR ((PUCHAR) 0xF806, 0x55);
+ c = READ_PORT_UCHAR((PUCHAR) 0xF803);
+ HalpDumpBitsField (c, SBErrorIntStatusBits);
+ HalpDumpAsicPorts (MSG_MC_ADDRESS, 0x55, 0x5c, 0x5d);
+ // status bits decode as:
+ // 0x04 = 1 is memory, 0 is I/O
+
+ if (c & 0x08) {
+ HalpDumpAsicPorts (MSG_MC_TIMEOUT, 0x58);
+ }
+
+ HalpDumpAsicPorts (MSG_MC_PARITY, 0x5e, 0x5e);
+ HalDisplayString ("\n");
+}
+
+VOID HalpDumpArbiter (UCHAR ArbiterId)
+{
+ UCHAR c;
+
+ WRITE_PORT_UCHAR ((PUCHAR) 0x97, ArbiterId);
+ c = READ_PORT_UCHAR ((PUCHAR) 0xf800);
+ if (c != ArbiterId) {
+ return ;
+ }
+
+ HalpDumpAsicPorts ("Aribter: %x\n", ArbiterId);
+
+ c = READ_PORT_UCHAR((PUCHAR) 0xF808);
+ HalpDumpBitsField (c, InterruptStatusOneBits);
+
+ c = READ_PORT_UCHAR((PUCHAR) 0xF809);
+ HalpDumpBitsField (c, InterruptStatusTwoBits);
+ HalDisplayString ("\n");
+}
+
+
+
+VOID HalpDumpBitsField (UCHAR bits, char *BitMsgs[])
+{
+ UCHAR i;
+
+ for (i=0; i < 8; i++) {
+ if (bits & 1 && BitMsgs[i]) {
+ HalDisplayString (" ");
+ HalDisplayString (BitMsgs[i]);
+ HalDisplayString ("\n");
+ }
+ bits >>= 1;
+ }
+}
+
+
+VOID HalpDumpAsicPorts (PUCHAR p, ULONG arg, ...)
+{
+ UCHAR c;
+ PUCHAR o;
+ UCHAR s[150];
+ PULONG stack;
+ ULONG l;
+
+ o = s;
+ stack = &arg;
+ while (*p) {
+ if (*p == '%') {
+ p++;
+ l = *(stack++);
+ switch (*(p++)) {
+
+ // truncate sting if bit-0 is not set
+ case '1':
+ WRITE_PORT_UCHAR ((PUCHAR) 0xF806, (UCHAR) l);
+ c = READ_PORT_UCHAR((PUCHAR) 0xF803);
+ if ((c & 1) == 0) {
+ return ;
+ }
+ break;
+
+ case 'p': // port value
+ c = READ_PORT_UCHAR((PUCHAR) l);
+ *(o++) = HexString[c >> 4];
+ *(o++) = HexString[c & 0xF];
+ break;
+
+ case 's': // sub-port value
+ HexSubPort (&o, l);
+ break;
+
+ case 'A': // address at
+ HexSubPort (&o, l); // sub-port
+ HexSubPort (&o, l-1);
+ HexSubPort (&o, l-2);
+ HexSubPort (&o, l-3);
+ break;
+
+ case 'x': // hex byte
+ *(o++) = HexString[l >> 4];
+ *(o++) = HexString[l & 0xF];
+ break;
+
+ default:
+ *(o++) = '?';
+ break;
+ }
+ } else {
+ *(o++) = *(p++);
+ }
+ }
+ *o = 0;
+ HalDisplayString (s);
+}
+
+VOID HexSubPort (PUCHAR *o, ULONG l)
+{
+ UCHAR c;
+
+ WRITE_PORT_UCHAR ((PUCHAR) 0xF806, (UCHAR) l);
+ c = READ_PORT_UCHAR((PUCHAR) 0xF803);
+
+ o[0][0] = HexString[c >> 4];
+ o[0][1] = HexString[c & 0xF];
+ *o += 2;
+}
diff --git a/private/ntos/nthals/halncr/i386/ncrpsi.h b/private/ntos/nthals/halncr/i386/ncrpsi.h
new file mode 100644
index 000000000..2bda2f117
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrpsi.h
@@ -0,0 +1,291 @@
+/*++
+
+Copyright (C) 1992 NCR Corporation
+
+
+Module Name:
+
+ ncrpsi.h
+
+Author:
+
+Abstract:
+
+ System equates for dealing with the NCR PSI boad.
+
+++*/
+
+#ifndef _NCRPSI_
+#define _NCRPSI_
+
+/*
+ * CAT_I is the only ASIC on the Power Supply Interface Module
+ */
+
+
+/* UNDEFINED STATUS BITS */
+
+#define PSI_Security_Switch_L5 0x01
+
+/* END UNDEFINED STATUS BITS */
+
+
+#define NUM_POWER_SUPPLIES_L5 5
+#define NUM_FANS_L5 8
+
+#define PSI_Interrupt_Status_L5 0x08
+
+ /* Read Values */
+
+#define PSI_DC_Failed0_L5 0x01
+#define PSI_PwrSupplyMon_L5 0x02
+#define PSI_Fault_L5 0x04
+#define PSI_TimerAlarm_L5 0x08
+#define PSI_DVM_Int_L5 0x20
+#define PSI_StatusChange_L5 0x80
+
+ /* Write Values */
+
+#define PSI_ClearFault_L5 0x00
+
+
+#define PSI_Status_Change_1_L5 0x09
+
+#define PSI_Temp2_L5 0x02
+#define PSI_Temp1_L5 0x04
+#define PSI_Diag_Stat_L5 0x40
+
+#define PSI_Status_Change_3_L5 0x0A
+#define PSI_Fan1_Failed_L5 0x01
+#define PSI_Fan2_Failed_L5 0x02
+#define PSI_Fan3_Failed_L5 0x04
+#define PSI_Fan4_Failed_L5 0x08
+#define PSI_Fan5_Failed_L5 0x10
+#define PSI_Fan6_Failed_L5 0x20
+#define PSI_Fan7_Failed_L5 0x40
+#define PSI_Fan8_Failed_L5 0x80
+
+#define PSI_Fault_Status_L5 0x0B
+#define PSI_VSB_OverCurrent_L5 0x01
+#define PSI_PMC_OverCurrent_L5 0x02
+#define PSI_SMC_OverCurrent_L5 0x04
+#define PSI_TempFault_L5 0x80
+
+#define PSI_TMS_Activity_L5 0x0C
+#define PSI_TMSX_0 0x01
+#define PSI_TMSX_1 0x02
+#define PSI_TMSX_2 0x04
+#define PSI_TMSX_3 0x08
+#define PSI_TMSX_4 0x10
+#define PSI_TMSX_5 0x20
+#define PSI_TMSX_MC 0x40
+#define PSI_TMSX_Spare 0x80
+
+#define PSI_General_XS1_L5 0x0D
+
+ /* Read Values */
+
+#define PSI_Red_Disk_LED_L5 0x01
+#define PSI_Grn_Disk_LED_L5 0x02
+#define PSI_Red_Stat_LED_L5 0x04
+#define PSI_Grn_Stat_LED_L5 0x08
+#define PSI_Diag_Stat_L5 0x40
+#define PSI_Q_Cold_Reset_L5 0x80
+
+/* Write Values */
+
+#define PSI_Red_Disk_LED_Off_L5 0x00
+#define PSI_Red_Disk_LED_On_L5 0x10
+#define PSI_Grn_Disk_LED_Off_L5 0x01
+#define PSI_Grn_Disk_LED_On_L5 0x11
+#define PSI_Red_Stat_LED_Off_L5 0x02
+#define PSI_Red_Stat_LED_On_L5 0x12
+#define PSI_Grn_Stat_LED_Off_L5 0x03
+#define PSI_Grn_Stat_LED_On_L5 0x13
+#define PSI_Diag_Stat_Off_L5 0x06
+#define PSI_Diag_Stat_On_L5 0x16
+#define PSI_Assert_Cold_Reset_L5 0x07
+#define PSI_Unassert_Cold_Reset_L5 0x17
+
+#define PSI_Sys_Status_L5 0x0E
+#define PSI_S_128_256_L5 0x04
+#define PSI_Test_L5 0x08
+#define PSI_Enable_Fault_L5 0x40
+#define PSI_Enable_HX_Off_L5 0x80
+
+
+#define PSI_Pwr_Supply_Status_L5 0x8000
+
+ /* read values */
+
+#define PSI_DC_Fail0 0x01
+#define PSI_AC_Fail0 0x02
+#define PSI_PSMon_INT 0x04
+#define PSI_PowerOff_Request 0x08
+#define PSI_HX_Off 0x10
+#define PSI_SecuritySwitch_On 0x20
+#define PSI_CmosBattery_Low 0x40
+#define PSI_CmosBattery_Fail 0x80
+
+ /* write values */
+
+#define PSI_Clear_PowerOff_Request 0x13
+#define PSI_Clear_HXOff_Request 0x14
+#define PSI_Clear_CmosBattery_Fail 0x17
+
+#define PSI_Pwr_Supply_Mask_L5 0x8001
+
+ /* read values */
+
+#define PSI_Redundant_Config 0x20
+
+ /* write values */
+
+#define PSI_PowerSupply1_Mask 0x10
+#define PSI_PowerSupply2_Mask 0x11
+#define PSI_PowerSupply3_Mask 0x12
+#define PSI_PowerSupply4_Mask 0x13
+#define PSI_PowerSupply5_Mask 0x14
+
+#define PSI_Pwr_Supply_Pres_L5 0x8002
+#define PSI_PowerSupply1_Present 0x01
+#define PSI_PowerSupply2_Present 0x02
+#define PSI_PowerSupply3_Present 0x04
+#define PSI_PowerSupply4_Present 0x08
+#define PSI_PowerSupply5_Present 0x10
+#define PSI_UPS_Present 0x20
+#define PSI_True 0x40
+#define PSI_PowerSupply_Failure 0x80
+
+#define PSI_Pwr_Supply_DCFail_L5 0x8003
+#define PSI_DcFail1 0x01
+#define PSI_DcFail2 0x02
+#define PSI_DcFail3 0x04
+#define PSI_DcFail4 0x08
+#define PSI_DcFail5 0x10
+#define PSI_DcChange 0x80
+
+#define PSI_Pwr_Supply_AcFail_L5 0x8004
+#define PSI_AcFail1 0x01
+#define PSI_AcFail2 0x02
+#define PSI_AcFail3 0x04
+#define PSI_AcFail4 0x08
+#define PSI_AcFail5 0x10
+#define PSI_AcChange 0x80
+
+#define PSI_Pwr_Supply_Fail_L5 0x8005
+#define PSI_PwrFail1 0x01
+#define PSI_PwrFail2 0x02
+#define PSI_PwrFail3 0x04
+#define PSI_PwrFail4 0x08
+#define PSI_PwrFail5 0x10
+#define PSI_PsChange 0x80
+
+#define PSI_Pwr_Supply_UpsFail_L5 0x8006
+#define PSI_UpsFail1 0x01
+#define PSI_UpsFail2 0x02
+#define PSI_UpsFail3 0x04
+#define PSI_UpsFail4 0x08
+#define PSI_UpsFail5 0x10
+#define PSI_UpsPresent 0x20
+#define PSI_UpsChargeLow 0x40
+#define PSI_UpsChange 0x80
+
+#define PSI_General_Ps_Status_L5 0x8007
+
+ /* read values */
+
+#define PSI_PowerSwitch_On 0x01
+#define PSI_PowerSwitch_Enabled 0x02
+#define PSI_Alarm_Enabled 0x08
+#define PSI_SecureSwitch_Enabled 0x10
+#define PSI_Cold_Reset 0x20
+#define PSI_Cold_Start 0x80
+
+ /* write values */
+
+#define PSI_SoftwarePowerDown0 0x00
+#define PSI_SoftwarePowerDown1 0x10
+#define PSI_Clear_AlarmEnable 0x01
+#define PSI_Set_AlarmEnable 0x11
+#define PSI_Disable_FrontSwitch 0x02
+#define PSI_Enable_FrontSwitch 0x12
+#define PSI_LPB_Reset 0x13
+#define PSI_SwClear_On 0x14
+#define PSI_Clear_ColdReset 0x05
+#define PSI_Set_ColdReset 0x15
+#define PSI_Clear_ColdStart0 0x07
+#define PSI_Clear_ColdStart1 0x17
+
+#define PSI_DiskGroupEnable_L5 0x8010
+#define PSI_DiskStatus_L5 0x8020
+#define PSI_DiskLatchInstalled_L5 0x8028
+#define PSI_Dvm_Select_L5 0x8030
+#define PSI_Dvm_Int_En_L5 0x80
+#define DVM_CONTROL (0x8030)
+#define DVM_DBASE (0x8038)
+#define DVM_SAMPLE (0x80)
+#define DVM_SAMPLE_TIME (5000000) // 500ms in 100ns ticks
+
+#define PSI_WDT_Command_Register_L5 0x804b
+
+ /* write values */
+
+#define PSI_Set_TDM_Bit 0x04
+
+typedef struct _PSI_INFORMATION {
+ union {
+ CAT_REGISTERS CatRegs;
+ struct {
+ UCHAR Dummy0;
+ UCHAR Dummy1;
+ UCHAR Dummy2;
+ UCHAR Dummy3;
+ UCHAR Dummy4;
+ UCHAR Dummy5;
+ UCHAR Dummy6;
+ UCHAR Dummy7;
+ UCHAR InterruptStatus;
+ UCHAR Status1;
+ UCHAR Status3;
+ UCHAR Fault;
+ UCHAR Tms;
+ UCHAR General1;
+ UCHAR SystemConfig;
+ UCHAR DummyF;
+ } PsiRegisters;
+ } CatRegisters;
+
+ /* Begin Subaddress space */
+
+ UCHAR PowerSupplyStatus; /* begin address 8000 */
+ UCHAR PowerSupplyMask;
+ UCHAR PowerSupplyPres;
+ UCHAR PowerSupplyDcFail;
+ UCHAR PowerSupplyAcFail;
+ UCHAR PowerSupplyPsFail;
+ UCHAR PowerSupplyUpsFail;
+ UCHAR GeneralPowerSupplyStatus;
+ UCHAR DiskPowerStatus[8]; /* begin address 8020 */
+ UCHAR DiskInstallStatus[8]; /* begin address 8028 */
+ UCHAR DvmSelect; /* begin address 8030 */
+ UCHAR DvmData0;
+ UCHAR DvmData1;
+ UCHAR DvmData2;
+ UCHAR DvmData3;
+
+} PSI_INFORMATION, *PPSI_INFORMATION;
+
+/* defines for union referencing */
+#define INTERRUPT_STATUS CatRegisters.PsiRegisters.InterruptStatus
+#define STATUS_CHANGE_1 CatRegisters.PsiRegisters.Status1
+#define STATUS_CHANGE_3 CatRegisters.PsiRegisters.Status3
+#define GENERAL_1 CatRegisters.PsiRegisters.General1
+#define FAULT_STATUS CatRegisters.PsiRegisters.Fault
+#define SYSTEM_CONFIG CatRegisters.PsiRegisters.SystemConfig
+
+#define PSI_SHUTDOWN 0 /* tells kernel power fail code to shutdown */
+#define PSI_POWERFAIL 1 /* tells kernel power fail code to powerfail */
+
+
+#endif // _NCRPSI_
diff --git a/private/ntos/nthals/halncr/i386/ncrqic.c b/private/ntos/nthals/halncr/i386/ncrqic.c
new file mode 100644
index 000000000..197acb3bd
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrqic.c
@@ -0,0 +1,329 @@
+/*++
+
+Copyright (c) 1992 NCR Corporation
+
+Module Name:
+
+ ncrqic.c
+
+Abstract:
+
+
+Author:
+
+ Rick Ulmer
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "ncr.h"
+#include "ncrsus.h"
+#include "stdio.h"
+
+PQIC_IPI IpiAddresses[NCR_MAX_NUMBER_QUAD_PROCESSORS];
+PQIC_IPI PhysicalIpiAddresses[NCR_MAX_NUMBER_QUAD_PROCESSORS];
+
+extern PPROCESSOR_BOARD_INFO SUSBoardInfo;
+extern ULONG NCRLogicalDyadicProcessorMask;
+extern ULONG NCRLogicalQuadProcessorMask;
+extern ULONG NCRLogicalNumberToPhysicalMask[];
+extern ULONG NCRExistingQuadProcessorMask;
+
+extern ULONG NCRActiveProcessorMask;
+
+ULONG NCRQicSpurCount = 0;
+
+
+VOID
+HalQicRequestIpi (
+ IN KAFFINITY Mask,
+ IN ULONG Level
+ );
+
+VOID
+HalRequestIpi (
+ IN KAFFINITY Mask
+ )
+/*++
+
+Routine Description:
+ Send Ipi's to processors
+
+Arguments:
+ Processors Mask;
+
+Return Value:
+ none.
+
+--*/
+
+{
+ if (Mask & NCRLogicalDyadicProcessorMask) {
+ HalVicRequestIpi(Mask & NCRLogicalDyadicProcessorMask);
+ }
+
+ if (Mask & NCRLogicalQuadProcessorMask) {
+ HalQicRequestIpi(Mask & NCRLogicalQuadProcessorMask, NCR_IPI_LEVEL_CPI);
+ }
+}
+
+
+VOID
+HalQicRequestIpi (
+ IN KAFFINITY Mask,
+ IN ULONG Level
+ )
+/*++
+
+Routine Description:
+ Send Ipi's to processors
+
+Arguments:
+ Processors Mask;
+
+Return Value:
+ none.
+
+--*/
+
+{
+ PKPCR pPCR;
+ ULONG my_logical_mask;
+
+ PQIC_IPI IpiAddress;
+ ULONG logical_mask;
+ ULONG cpu_id;
+
+
+ pPCR = KeGetPcr();
+ my_logical_mask = ((PProcessorPrivateData)pPCR->HalReserved)->MyLogicalMask;
+
+ logical_mask = Mask;
+
+ cpu_id = 0;
+
+ //
+ // See if we need to send the cpi two ourselves
+ //
+
+ if (my_logical_mask & logical_mask) {
+ WRITE_PORT_UCHAR((PUCHAR)(0xFCC0+(0x8*Level)),0x1);
+ logical_mask ^= my_logical_mask;
+ }
+
+
+ //
+ // Now send to all other processors
+ //
+
+ while (logical_mask) {
+ if (logical_mask & 0x01) {
+ IpiAddress = IpiAddresses[cpu_id];
+ IpiAddress->QIC_LEVEL[Level].Ipi = 1;
+ }
+ cpu_id++;
+ logical_mask >>= 1;
+ }
+}
+
+
+
+VOID
+HalQicStartupIpi (
+ ULONG ProcessorNumber
+ )
+/*++
+
+Routine Description:
+ Send Ipi's to processors
+
+Arguments:
+ Processors Mask;
+
+Return Value:
+ none.
+
+--*/
+
+{
+ register QIC_IPI *IpiAddress;
+
+ IpiAddress = PhysicalIpiAddresses[ProcessorNumber];
+ IpiAddress->QIC_LEVEL[2].Ipi = 1;
+}
+
+
+
+
+ULONG
+NCRClearQicIpi (
+ IN Level
+ )
+/*++
+
+Routine Description:
+ Send Ipi's to processors
+
+Arguments:
+ Processors Mask;
+
+Return Value:
+ none.
+
+--*/
+
+{
+ PKPCR pPCR;
+ ULONG my_logical_number;
+ register QIC_IPI *IpiAddress;
+
+
+ pPCR = KeGetPcr();
+ my_logical_number = ((PProcessorPrivateData)pPCR->HalReserved)->MyLogicalNumber;
+
+//
+// Clear the interrupt
+//
+
+ WRITE_PORT_UCHAR((PUCHAR)0xfc8b, (UCHAR) (0x1<<Level));
+
+// there is some window during bootup where we are hitting this code before
+// IpiAddresses is filled in
+
+ IpiAddress = IpiAddresses[my_logical_number];
+
+ return (IpiAddress->QIC_LEVEL[Level].Ipi);
+}
+
+
+
+VOID
+NCRFindIpiAddress (
+ ULONG ProcessorNumber
+ )
+
+{
+ ULONG physical_processor_number;
+ ULONG physical_mask;
+ ULONG mask;
+ ULONG i;
+
+ physical_mask = NCRLogicalNumberToPhysicalMask[ProcessorNumber];
+
+ physical_processor_number = 0;
+
+ for ( mask = 0x1; mask < (0x1 << NCR_MAX_NUMBER_PROCESSORS); mask <<= 1, physical_processor_number++) {
+ if (mask & physical_mask) {
+ break;
+ }
+ }
+ IpiAddresses[ProcessorNumber] = PhysicalIpiAddresses[physical_processor_number];
+}
+
+
+
+
+
+VOID
+NCRMapIpiAddresses (
+ )
+
+{
+ ULONG i;
+ PQUAD_DESCRIPTION quad_desc;
+ PCHAR cpiaddr[8] = {0};
+ ULONG cpipage[8] = {0};
+ ULONG modules;
+ ULONG slot;
+ ULONG cpu_offset;
+ ULONG proc_id;
+ ULONG physical_processor_number;
+ ULONG mask;
+
+ if (NCRExistingQuadProcessorMask == 0) {
+ return;
+ }
+
+ physical_processor_number = 0;
+
+ for ( mask = NCRExistingQuadProcessorMask; mask != 0; mask >>= 1, physical_processor_number++) {
+
+ if (!(mask & 1)) {
+ continue;
+ }
+
+ slot = (physical_processor_number / 4);
+ proc_id = physical_processor_number % 4;
+
+ DBGMSG(("NCRMapIpiAddress: Physical Proc 0x%x, slot = 0x%x, proc_id = 0x%x\n",
+ physical_processor_number, slot, proc_id));
+
+ modules = SUSBoardInfo->NumberOfBoards;
+ quad_desc = SUSBoardInfo->QuadData;
+
+ cpu_offset = proc_id * 0x100;
+
+ DBGMSG(("NCRMapIpiAddress: modules = %d\n",modules));
+
+ for ( i = 0; i < modules; quad_desc++, i++) {
+
+ DBGMSG(("NCRMapIpiAddress: quad_desc Type = 0x%x, slot = 0x%x\n",quad_desc->Type, quad_desc->Slot));
+
+ if ( quad_desc->Slot == (slot+1)) {
+ if (quad_desc->Type == QUAD ) {
+ if (cpipage[slot] == 0 ) {
+ cpipage[slot] = (ULONG) quad_desc->IpiBaseAddress & ~POFFMASK;
+ cpiaddr[slot] = HalpMapPhysicalMemory(cpipage[slot],1);
+ }
+ PhysicalIpiAddresses[physical_processor_number] =
+ cpiaddr[slot]+(cpu_offset+(quad_desc->IpiBaseAddress & POFFMASK));
+
+ DBGMSG(("NCRMapIpiAddress: Proc %d, Address = 0x%x\n",
+ physical_processor_number,
+ PhysicalIpiAddresses[physical_processor_number]));
+
+ break;
+ } else {
+ break;
+ }
+ }
+ }
+ }
+}
+
+
+VOID
+NCRHandleQicSpuriousInt (TrapFramePtr, ExceptionRecordPtr)
+IN PKTRAP_FRAME TrapFramePtr;
+IN PVOID ExceptionRecordPtr;
+/*++
+
+Routine Description:
+ Handles the NCR Qic Spurious interrupts
+
+Arguments:
+
+Return Value:
+ none.
+
+--*/
+{
+ UCHAR qic_irr0;
+ UCHAR qic_irr1;
+
+ NCRQicSpurCount++;
+
+#ifdef NEVER
+ qic_irr0 = READ_PORT_UCHAR(0xfc82);
+ qic_irr1 = READ_PORT_UCHAR(0xfc83);
+
+ DBGMSG(("NCRHandleQicSpurious: Count %d, QicIrr0 = 0x%x, QicIrr1 = 0x%x\n",
+ NCRQicSpurCount, qic_irr0, qic_irr1));
+#endif
+}
diff --git a/private/ntos/nthals/halncr/i386/ncrstart.asm b/private/ntos/nthals/halncr/i386/ncrstart.asm
new file mode 100644
index 000000000..e36fb91e9
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrstart.asm
@@ -0,0 +1,987 @@
+ title "Multiprocessor Startup"
+;++
+;
+;Copyright (c) 1992 NCR Corporation
+;
+;Module Name:
+;
+; ncrstart.asm
+;
+;Abstract:
+;
+; Provides the HAL support for starting processors.
+;
+;Author:
+;
+; Richard Barton (o-richb) 24-Jan-1992
+;
+;Revision History:
+;
+;--
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+include i386\ix8259.inc
+include i386\ncr.inc
+
+
+ extrn _DbgPrint:PROC
+ EXTRNP _HalpBuildTiledCR3,1
+ EXTRNP _HalpFreeTiledCR3,0
+ EXTRNP _HalEnableSystemInterrupt,3
+ EXTRNP _NCRFindIpiAddress,1
+ EXTRNP _NCRClearQicIpi,1
+ EXTRNP _HalQicStartupIpi,1
+ EXTRNP _NCRTranslateCMOSMask,1
+ EXTRNP _NCRTranslateToCMOSMask,1
+ EXTRNP _NCRAdjustDynamicClaims,0
+if DBG
+ EXTRNP _NCRConsoleDebug,2
+endif
+ extrn _NCRProcessorsToBringup:DWORD
+ extrn _NCRExistingProcessorMask:DWORD
+ extrn _NCRExistingDyadicProcessorMask:DWORD
+ extrn _NCRExistingQuadProcessorMask:DWORD
+ extrn _NCRExtendedProcessorMask:DWORD
+ extrn _NCRExtendedProcessor0Mask:DWORD
+ extrn _NCRExtendedProcessor1Mask:DWORD
+ extrn _NCRLogicalDyadicProcessorMask:DWORD
+ extrn _NCRLogicalQuadProcessorMask:DWORD
+ extrn _NCRActiveProcessorMask:DWORD
+ extrn _NCRActiveProcessorCount:DWORD
+ extrn _NCRMaxProcessorCount:DWORD
+ extrn _NCRLogicalNumberToPhysicalMask:DWORD
+ extrn _NCRSlotExtended0ToVIC:BYTE
+ extrn _NCRSlotExtended1ToVIC:BYTE
+ extrn _NonbootStartupVirtualPtr:DWORD
+ extrn _NonbootStartupPhysicalPtr:DWORD
+ extrn _PageZeroVirtualPtr:DWORD
+ extrn _HalpDefaultInterruptAffinity:DWORD
+ extrn _HalpActiveProcessors:DWORD
+ extrn _NCRProcessorIDR:DWORD
+ extern _DefaultNeverClaimIRQs:DWORD
+ extern _NCRNeverClaimIRQs:DWORD
+
+ EXTRNP _HalpInitializePICs,0
+
+
+PxParamBlock struc
+ SPx_Mask dd ?
+ SPx_TiledCR3 dd ?
+ SPx_P0EBP dd ?
+ SPx_PB db processorstatelength dup (?)
+PxParamBlock ends
+
+ page ,132
+ subttl "Initialize boot processor"
+
+_TEXT SEGMENT PARA PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; VOID
+; HalInitializeProcessor(
+; ULONG Number
+; );
+;
+;Routine Description:
+;
+; Initialize hal pcr values for current processor (if any)
+; (called shortly after processor reaches kernel, before
+; HalInitSystem if P0)
+;
+; IPI's and KeRaise/LowerIrq's must be available once this function
+; returns. (IPI's are only used once two or more processors are
+; available)
+;
+; This routine makes some VIC accesses assuming that it's running on
+; an NCR box. The real check won't happen until HalInitMP().
+;
+;Arguments:
+;
+; Number - Logical processor number of calling processor
+;
+;Return Value:
+;
+; None.
+;
+;--
+
+cPublicProc _HalInitializeProcessor ,1
+
+;
+; Initialize IDR in PCR to allow irq 2 only.
+;
+
+ mov dword ptr PCR[PcIDR],0fffffffbh
+ mov dword ptr PCR[PcStallScaleFactor], INITIAL_STALL_COUNT
+ mov dword ptr PCR[PcHal.PcrMyClaimedIRQs], 0
+ mov dword ptr PCR[PcHal.PcrMyClaimedIRQsCount],0
+
+
+;
+; all processors execute this first section
+;
+; remember this processors logical number
+;
+
+ mov ecx, 4[esp]
+ mov PCR[PcHal.PcrMyLogicalNumber], ecx
+
+;
+; Set IDR table to same value as PcIDR
+;
+ mov _NCRProcessorIDR[ecx*4],0fffffffbh
+
+
+;RMU
+;if DBG
+; push ebx
+; push ecx
+; push edx
+; mov eax,1
+; stdCall _NCRConsoleDebug, <eax,ecx>
+; pop edx
+; pop ecx
+; pop ebx
+;endif
+;RMU
+
+
+ mov eax, 1
+ shl eax, cl
+ lock or _HalpActiveProcessors, eax
+
+if 0
+ ; begin - spinlock test code - kenr
+ push eax
+ push edx
+
+ mov eax, 1
+ shl eax, cl ; (eax) = pmask
+ shl eax, 16 ; mask into high word of dword
+
+ mov fs:PcHal.PcrCheckForBit, eax ; (pmask<<16)
+
+ or eax, 1 ; set low byte to 1
+ mov fs:PcHal.PcrSpinAcquireBits, eax ; (pmask<<16) | 1
+
+ not eax
+ and eax, 0ffff0000h
+ mov fs:PcHal.PcrSpinReleaseMask, eax ; ~(pmask<<16)
+
+
+ mov eax, ecx
+ inc eax ; handoff id
+ shl eax, 8
+ or eax, 1 ; (handoff << 8) | 1
+ mov fs:PcHal.PcrSpinId, eax
+
+
+ pop edx
+ pop eax
+ ; end - spinlock test code
+endif
+
+
+;
+; remember this processors physical mask
+;
+ WHO_AM_I
+ jb IAmQuad
+
+;
+; Processor init code for Dyadic
+;
+
+ lock or _NCRActiveProcessorMask, eax
+ lock inc _NCRActiveProcessorCount
+
+ mov edx, CPU_DYADIC
+ mov PCR[PcHal.PcrMyProcessorFlags],edx
+;
+; setup translation databases:
+;
+ mov edx, 1
+ shl edx, cl ; edx contains logical mask
+ mov PCR[PcHal.PcrMyLogicalMask], edx
+ lock or _NCRLogicalDyadicProcessorMask, edx
+ lock or _HalpDefaultInterruptAffinity, edx
+;
+; Get the real hardware VIC mask so we can send CPIs
+;
+ mov dx, VIC_BASE_ADDRESS+vic_ProcessorWhoAmIReg
+ xor eax,eax
+ in al,dx
+ mov _NCRLogicalNumberToPhysicalMask[ecx*4], eax
+
+;
+; make sure all processors can take interrupts (have this processor claim none)
+;
+ VIC_WRITE ClaimRegLsb, 0
+ VIC_WRITE ClaimRegMsb, 0
+
+ or ecx, ecx
+ jz InitBoot
+;
+; nonboot processor only stuff
+;
+ stdCall _HalpInitializePICs
+
+;
+; no need to send EOI for startup CPI since just initialized PICs above
+;
+
+;
+; make sure each processor can get IPI
+;
+ stdCall _HalEnableSystemInterrupt, <NCR_CPI_VECTOR_BASE+NCR_IPI_LEVEL_CPI,IPI_LEVEL,0>
+
+ stdRET _HalInitializeProcessor
+;
+; boot processor only stuff
+;
+ align dword
+InitBoot:
+;
+; setup the cross-processor vector base
+;
+ mov eax, NCR_CPI_VECTOR_BASE
+ VIC_WRITE CpiVectorBaseReg
+;
+; temporary fix for VIC errata - true spurious primary MC interrupts (where
+; HW removes the request during INTA cycle) can result in a secondary MC based
+; vector being supplied by the VIC (with the ISR bit actually set, but no
+; real interrupt). Since currently no interrupts are routed through the
+; secondary MC vector space, will simply set the secondary MC vector space
+; equal to the primary vector space.
+;
+ mov eax, NCR_SECONDARY_VECTOR_BASE
+ VIC_WRITE ExtMasterVectorBaseReg
+ mov eax, NCR_SECONDARY_VECTOR_BASE+8
+ VIC_WRITE ExtSlaveVectorBaseReg
+
+ stdRET _HalInitializeProcessor
+;
+; Processor init code for Quad processor
+;
+
+IAmQuad:
+
+;
+; save logical processor number to hardware mask
+;
+
+ mov _NCRLogicalNumberToPhysicalMask[ecx*4], eax
+
+;
+; now lets see if we are extended or not
+;
+
+ mov edx,eax ; save process mask
+ PROCESSOR_SLOT ; get the process slot for this CPU
+ shl eax,2h ; calculate shift to isolate mask to one board
+ push ecx ; save ecx (contains logical processor number)
+ mov ecx,eax
+ mov eax,edx ; now get processor mask
+ shr eax,cl ; now isolate processor on this board
+ mov ecx,eax ; save processor by board mask
+
+ push edx ; save edx with processor mask
+ QIC_READ ExtendedProcessorSelect ; get the extended processor mask
+ pop edx
+
+ test eax,ecx ; test for extended processor 0
+ jnz short ExtendedProcessor0
+
+ shr eax,4h ; isolate extended processor 1 mask
+
+ test eax,ecx ; test for extended processor 1
+ jnz short ExtendedProcessor
+ pop ecx
+ mov eax,edx
+ mov edx, CPU_QUAD
+
+ jmp short NotExtended;
+
+ExtendedProcessor0:
+
+;
+; For Extended Processor 0 lets setup all other processors on the Quad Board
+;
+ xor ecx,ecx
+ push edx ; save who am I mask
+ align dword
+ExtendedLoop:
+
+ mov al,cl
+ or al,8
+ QIC_WRITE ProcessorId
+
+ mov al,0ffh
+ QIC_WRITE QicMask0
+
+ mov al,QIC_IRQ_ENABLE_MASK
+ QIC_WRITE QicMask1
+
+ xor al,al
+ QIC_WRITE ProcessorId
+
+ inc ecx
+ cmp ecx,4
+ jne short ExtendedLoop
+
+;
+; Qic setup
+;
+
+;
+; Disable propagation of SBE and SINT to non-extened processors
+;
+ QIC_READ Configuration
+ or al,7
+ QIC_WRITE Configuration
+
+ mov al, NCR_CPI_VECTOR_BASE
+ QIC_WRITE VicCpiVectorBaseReg
+
+ mov al, NCR_QIC_CPI_VECTOR_BASE
+ QIC_WRITE QuadCpiVectorBaseReg
+
+ mov al,0ffh
+ QIC_WRITE Clear1Reg
+
+ mov al,NCR_QIC_SPURIOUS_VECTOR
+ QIC_WRITE SpuriousVectorReg
+
+ pop edx ; restore the who am I mask
+
+ExtendedProcessor:
+ pop ecx
+ mov eax,edx
+ mov edx, CPU_QUAD
+ or edx, CPU_EXTENDED
+ push eax
+ mov eax, 1
+ shl eax, cl
+ lock or _HalpDefaultInterruptAffinity, eax
+ pop eax
+NotExtended:
+ mov PCR[PcHal.PcrMyProcessorFlags],edx
+;
+;
+ lock or _NCRActiveProcessorMask, eax
+ lock inc _NCRActiveProcessorCount
+
+ mov edx, 1
+ shl edx, cl ; edx contains logical mask
+ lock or _NCRLogicalQuadProcessorMask, edx
+ mov PCR[PcHal.PcrMyLogicalMask], edx
+
+
+;
+; make sure all processors can take interrupts (have this processor claim none)
+;
+ VIC_WRITE ClaimRegLsb, 0
+ VIC_WRITE ClaimRegMsb, 0
+
+ or ecx, ecx
+ jz QuadInitBoot
+
+ stdCall _NCRFindIpiAddress, <ecx> ; lookup IPI address so we can send and clear IPI's
+ stdCall _NCRClearQicIpi, <2> ; clear the startup IPI
+
+;
+; nonboot processor only stuff
+;
+ mov eax, PCR[PcHal.PcrMyProcessorFlags]
+ test eax,CPU_EXTENDED
+ jz short NoPic
+
+ stdCall _HalpInitializePICs
+
+NoPic:
+ stdRET _HalInitializeProcessor
+;
+; boot processor only stuff
+;
+ align dword
+QuadInitBoot:
+;
+; setup the cross-processor vector base
+;
+ mov eax, NCR_CPI_VECTOR_BASE
+ VIC_WRITE CpiVectorBaseReg
+
+;
+; temporary fix for VIC errata - true spurious primary MC interrupts (where
+; HW removes the request during INTA cycle) can result in a secondary MC based
+; vector being supplied by the VIC (with the ISR bit actually set, but no
+; real interrupt). Since currently no interrupts are routed through the
+; secondary MC vector space, will simply set the secondary MC vector space
+; equal to the primary vector space.
+;
+
+ mov eax, NCR_SECONDARY_VECTOR_BASE
+ VIC_WRITE ExtMasterVectorBaseReg
+ mov eax, NCR_SECONDARY_VECTOR_BASE+8
+ VIC_WRITE ExtSlaveVectorBaseReg
+
+;
+; Qic setup
+;
+
+ mov al, NCR_CPI_VECTOR_BASE
+ QIC_WRITE VicCpiVectorBaseReg
+
+ mov al, NCR_QIC_CPI_VECTOR_BASE
+ QIC_WRITE QuadCpiVectorBaseReg
+
+ mov al,0ffh
+ QIC_WRITE Clear1Reg
+
+ stdRET _HalInitializeProcessor
+stdENDP _HalInitializeProcessor
+
+
+
+ page ,132
+ subttl "Start non-boot processor"
+
+
+;++
+;
+; BOOLEAN
+; HalStartNextProcessor (
+; IN PLOADER_BLOCK pLoaderBlock,
+; IN PKPROCESSOR_STATE pProcessorState
+; )
+;
+; Routine Description:
+;
+; This routine is called by the kernel durning kernel initialization
+; to obtain more processors. It is called until no more processors
+; are available.
+;
+; If another processor exists this function is to initialize it to
+; the passed in processorstate structure, and return TRUE.
+;
+; If another processor does not exists, then a FALSE is returned.
+;
+; Also note that the loader block has been setup for the next processor.
+; The new processor logical thread number can be obtained from it, if
+; required.
+;
+;
+; we need to consult with firmware tables to determine which processors
+; are okay to start. note that we can not return false until there are
+; no processors left. so we stay here until we either start another
+; processor, there are no processors left to start, or all our attempts
+; to start another processor fail.
+;
+; Arguments:
+; pLoaderBlock, - Loader block which has been intialized for the
+; next processor.
+;
+; pProcessorState - The processor state which is to be loaded into
+; the next processor.
+;
+;
+; Return Value:
+;
+; TRUE - ProcessorNumber was dispatched.
+; FALSE - A processor was not dispatched. no other processors exists.
+;
+;--
+
+pLoaderBlock equ dword ptr [ebp+8] ; zero based
+pProcessorState equ dword ptr [ebp+12]
+
+;
+; Local variables
+;
+
+PxFrame equ [ebp - size PxParamBlock]
+
+cPublicProc _HalStartNextProcessor ,2
+;
+; note that we can screen processors two ways: we can limit the number
+; of processors to start or we can choose which physical processors we
+; will start. this is mainly for debugging and benchmarking purposes.
+;
+; how many processors are we going to allow
+;
+ mov ecx, _NCRActiveProcessorCount
+ cmp ecx, _NCRMaxProcessorCount
+ jae Done
+;
+; which processors are left
+;
+ mov eax, _NCRExistingProcessorMask
+ xor eax, _NCRActiveProcessorMask
+;
+; which processors are we going to allow
+;
+ and eax, _NCRProcessorsToBringup
+ jz Done
+
+ push ebp
+ mov ebp, esp
+
+ sub esp, size PxParamBlock
+
+ push esi
+ push edi
+ push ebx
+
+ push eax ; processors to choose from
+
+ mov esi, OFFSET FLAT:StartPx_RMStubE
+ mov ecx, esi
+ mov esi, OFFSET FLAT:StartPx_RMStub
+ sub ecx, esi
+ mov edi, _NonbootStartupVirtualPtr
+ add edi, size PxParamBlock
+ rep movsb ; Copy RMStub to low memory
+
+ lea edi, PxFrame.SPx_PB
+ mov esi, pProcessorState
+ mov ecx, processorstatelength ; Copy processorstate
+ rep movsb ; to PxFrame
+
+ stdCall _HalpBuildTiledCR3, <pProcessorState>
+
+ mov PxFrame.SPx_Mask, 0
+ mov PxFrame.SPx_TiledCR3, eax
+ mov PxFrame.SPx_P0EBP, ebp
+
+ mov ecx, size PxParamBlock ; copy param block
+ lea esi, PxFrame ; to low memory stub
+ mov edi, _NonbootStartupVirtualPtr
+ mov eax, edi
+ rep movsb
+
+ add eax, size PxParamBlock
+ mov ebx, OFFSET FLAT:StartPx_RMStub
+ sub eax, ebx ; (eax) = adjusted pointer
+ mov bx, word ptr [PxFrame.SPx_PB.PsContextFrame.CsSegCs]
+ mov [eax.SPrxFlatCS], bx ; patch realmode stub with
+ mov [eax.SPrxPMStub], offset _StartPx_PMStub ; valid long jump
+
+;
+; determine which one processor we are going to start. think i'll try
+; alternating buses.
+;
+
+ mov eax, dword ptr [esp] ; retrieve processors awaiting
+ bsf ecx, eax
+
+;
+; check to see if we are starting a dyadic or quad processor
+;
+ mov eax,1
+ shl eax,cl
+
+ test eax,_NCRExistingQuadProcessorMask
+ jnz StartQuadProcessor
+
+;
+; Startup code for a Dyadic processor
+;
+ mov ecx, eax ; now we only care about the startup mask
+;
+; fix the startee processors vector to allow it to receive the cpi
+;
+ mov ebx, _PageZeroVirtualPtr
+ add ebx, NCR_STARTUP_VECTOR_VIC
+
+ cli
+ push dword ptr [ebx] ; Save current vector
+
+ mov eax, _NonbootStartupPhysicalPtr
+ shl eax, 12 ; seg:0
+ add eax, size PxParamBlock
+ mov dword ptr [ebx], eax ; start Px here
+;
+; enable the cpi for the startee processor (although unnecessary for 3360 -
+; it's left enabled by BIOS)
+;
+ push ebx
+ push ecx
+ stdCall _NCRTranslateToCMOSMask, <ecx>
+ bsf ecx, eax
+ mov al, cl
+ pop ecx
+ pop ebx
+ or al, ProcessorIdSelect
+ VIC_WRITE ProcessorIdReg ; assume startee's id
+ mov edx, ecx ; save processor number
+ mov eax, 1
+ mov ecx, NCR_STARTUP_CPI
+ shl eax, cl
+ not al
+ mov ecx, edx ; restore processor number
+ out PIC1_PORT1, al ; clear cpi's irq
+ VIC_WRITE ProcessorIdReg, 0 ; restore own id
+
+ mov eax,ecx ; get the startee mask
+;
+; interrupt the startee
+;
+ push ebx
+ push ecx
+ stdCall _NCRTranslateToCMOSMask, <eax>
+ VIC_WRITE CpiLevel2Reg
+ pop ecx
+ pop ebx
+
+ mov eax,ecx ; get the startee mask
+
+ jmp StarteeWakeNow
+;
+; Startup code for a Quad Processor
+;
+
+StartQuadProcessor:
+
+ test eax,_NCRExtendedProcessor0Mask
+ jnz short StarteeExtended
+
+ mov ebx, _PageZeroVirtualPtr
+ add ebx, NCR_STARTUP_VECTOR_QIC
+
+ jmp short SkipVicSetup
+StarteeExtended:
+;
+; fix the startee processors vector to allow it to receive the cpi
+;
+ mov ebx, _PageZeroVirtualPtr
+ add ebx, NCR_STARTUP_VECTOR_VIC
+
+SkipVicSetup:
+
+ cli
+ push dword ptr [ebx] ; Save current vector
+
+ mov eax, _NonbootStartupPhysicalPtr
+ shl eax, 12 ; seg:0
+ add eax, size PxParamBlock
+ mov dword ptr [ebx], eax ; start Px here
+
+;
+; generate startee processors mask
+;
+ mov eax, 1
+ shl eax, cl ; mask of processor to start
+
+ test eax,_NCRExtendedProcessor0Mask
+ jz short StarteeNotExtended
+
+;
+; We are starting an Extended processor, we do this my using the VIC and not the QIC
+;
+
+;
+; This is extended processor 0
+;
+
+ PROCESSOR_SLOT
+ movzx eax, byte ptr _NCRSlotExtended0ToVIC[eax]
+
+;
+; enable the cpi for the startee processor (although unnecessary for 3360 -
+; it's left enabled by BIOS)
+;
+ push eax ; save the vic processor number
+
+ or al, ProcessorIdSelect
+ VIC_WRITE ProcessorIdReg ; assume startee's id
+ mov dl, cl ; save processor number
+ mov eax, 1
+ mov ecx, NCR_STARTUP_CPI
+ shl eax, cl
+ not al
+ mov cl, dl ; restore processor number
+ out PIC1_PORT1, al ; clear cpi's irq
+ VIC_WRITE ProcessorIdReg, 0 ; restore own id
+
+ pop eax
+ push ecx
+ mov ecx, eax
+;
+; generate startee processors mask
+;
+ mov eax, 1
+ shl eax, cl ; mask of VIC processor to start
+
+; interrupt the startee
+
+ VIC_WRITE CpiLevel2Reg
+ pop ecx
+
+ mov eax, 1
+ shl eax, cl ; mask of processor started
+
+ jmp short StarteeWakeNow
+
+StarteeNotExtended:
+
+ push ecx
+ stdCall _HalQicStartupIpi, <ecx>
+ pop ecx
+
+ mov eax, 1
+ shl eax, cl ; mask of processor started
+
+StarteeWakeNow:
+
+;RMU
+;if DBG
+; push eax
+; push ebx
+; push ecx
+; push edx
+; mov edx,2
+; stdCall _NCRConsoleDebug, <edx,eax>
+; pop edx
+; pop ecx
+; pop ebx
+; pop eax
+;endif
+;RMU
+
+
+;
+; wait for startee to say it's active. we should have a timeout on this
+; loop. however, what if the startee went off in the weeds and corrupted
+; something. if we timeout here we can't be sure what the other processor
+; is doing.
+;
+ align dword
+@@: cmp eax, PxFrame.SPx_Mask
+ jne @b
+
+
+;RMU
+;if DBG
+; push eax
+; push ebx
+; push ecx
+; push edx
+; mov edx,3
+; stdCall _NCRConsoleDebug, <edx,eax>
+; pop edx
+; pop ecx
+; pop ebx
+; pop eax
+;endif
+;RMU
+
+
+
+ pop dword ptr [ebx] ; restore vector
+ add esp, 1*4 ; pop saved mask
+
+ sti
+
+ stdCall _HalpFreeTiledCR3 ; free memory used for tiled
+
+ pop ebx
+ pop edi
+ pop esi
+ mov esp, ebp
+ pop ebp
+
+;
+; tell 'em we started another one
+;
+ mov eax, 1
+ stdRET _HalStartNextProcessor
+
+
+;
+; All processors are online so now lets start the claiming process
+;
+
+ align dword
+Done:
+;
+; now that all CPU's are online we need to calculate how many interrupts
+; each CPU can claim
+;
+
+ stdCall _NCRAdjustDynamicClaims
+
+;
+; setting the never claim mask to correct value will start the claim process
+;
+
+ mov eax, _DefaultNeverClaimIRQs;
+ mov _NCRNeverClaimIRQs, eax
+
+ xor eax,eax
+ stdRET _HalStartNextProcessor
+
+
+stdENDP _HalStartNextProcessor
+
+
+_TEXT ENDS
+
+
+;
+; heavy-duty plagarism from systempro stuff follows:
+;
+
+
+_TEXT16 SEGMENT DWORD PUBLIC USE16 'CODE' ; start 16 bit code
+
+
+;++
+;
+; VOID
+; StartPx_RMStub
+;
+; Routine Description:
+;
+; When a new processor is started, it starts in real-mode and is
+; sent to a copy of this function which has been copied into low memory.
+; (below 1m and accessable from real-mode).
+;
+; Once CR0 has been set, this function jmp's to a StartPx_PMStub
+;
+; Arguments:
+; none
+;
+; Return Value:
+; does not return, jumps to StartPx_PMStub
+;
+;--
+
+cPublicProc StartPx_RMStub ,0
+ cli
+
+ db 066h ; load the GDT
+ lgdt fword ptr cs:[SPx_PB.PsSpecialRegisters.SrGdtr]
+
+ db 066h ; load the IDT
+ lidt fword ptr cs:[SPx_PB.PsSpecialRegisters.SrIdtr]
+
+ mov eax, cs:[SPx_TiledCR3]
+ mov cr3, eax
+
+ mov ebp, dword ptr cs:[SPx_P0EBP]
+ mov ecx, dword ptr cs:[SPx_PB.PsContextFrame.CsSegDs]
+ mov ebx, dword ptr cs:[SPx_PB.PsSpecialRegisters.SrCr3]
+ mov eax, dword ptr cs:[SPx_PB.PsSpecialRegisters.SrCr0]
+
+ mov cr0, eax ; into prot mode
+
+ db 066h
+ db 0eah ; reload cs:eip
+SPrxPMStub dd 0
+SPrxFlatCS dw 0
+
+StartPx_RMStubE equ $
+stdENDP StartPx_RMStub
+
+
+_TEXT16 ends ; End 16 bit code
+
+_TEXT SEGMENT ; Start 32 bit code
+
+
+;++
+;
+; VOID
+; StartPx_PMStub
+;
+; Routine Description:
+;
+; This function completes the processor's state loading, and signals
+; the requesting processor that the state has been loaded.
+;
+; Arguments:
+; ebx - requested CR3 for this processors_state
+; cx - requested ds for this processors_state
+; ebp - EBP of P0
+;
+; Return Value: ; does not return - completes the loading of the processors_state
+;
+;--
+ align 16 ; to make sure we don't cross a page boundry
+ ; before reloading CR3
+
+cPublicProc _StartPx_PMStub ,0
+
+ ; process is now in the load image copy of this function.
+ ; (ie, it's not the low memory copy)
+
+ mov cr3, ebx ; get real CR3
+ mov ds, cx ; set real ds
+
+ lea esi, PxFrame.SPx_PB.PsSpecialRegisters
+
+ lldt word ptr ds:[esi].SrLdtr ; load ldtr
+ ltr word ptr ds:[esi].SrTr ; load tss
+
+ lea edi, PxFrame.SPx_PB.PsContextFrame
+ mov es, word ptr ds:[edi].CsSegEs ; Set other selectors
+ mov fs, word ptr ds:[edi].CsSegFs
+ mov gs, word ptr ds:[edi].CsSegGs
+ mov ss, word ptr ds:[edi].CsSegSs
+
+ add esi, SrKernelDr0
+ .errnz (SrKernelDr1 - SrKernelDr0 - 1 * 4)
+ .errnz (SrKernelDr2 - SrKernelDr0 - 2 * 4)
+ .errnz (SrKernelDr3 - SrKernelDr0 - 3 * 4)
+ .errnz (SrKernelDr6 - SrKernelDr0 - 4 * 4)
+ .errnz (SrKernelDr7 - SrKernelDr0 - 5 * 4)
+ lodsd
+ mov dr0, eax ; load dr0-dr7
+ lodsd
+ mov dr1, eax
+ lodsd
+ mov dr2, eax
+ lodsd
+ mov dr3, eax
+ lodsd
+ mov dr6, eax
+ lodsd
+ mov dr7, eax
+
+ mov esp, dword ptr ds:[edi].CsEsp
+ mov esi, dword ptr ds:[edi].CsEsi
+ mov ecx, dword ptr ds:[edi].CsEcx
+
+ push dword ptr ds:[edi].CsEflags
+ popfd ; load eflags
+
+ push dword ptr ds:[edi].CsEip ; make a copy of remaining
+ push dword ptr ds:[edi].CsEax ; registers which need
+ push dword ptr ds:[edi].CsEbx ; loaded
+ push dword ptr ds:[edi].CsEdx
+ push dword ptr ds:[edi].CsEdi
+ push dword ptr ds:[edi].CsEbp
+
+ ; eax, ebx, edx are still free
+
+ WHO_AM_I
+ mov [PxFrame.SPx_Mask], eax
+
+ ; Set remaining registers
+ pop ebp
+ pop edi
+ pop edx
+ pop ebx
+ pop eax
+ stdRET _StartPx_PMStub ; Set eip
+
+stdENDP _StartPx_PMStub
+
+_TEXT ends ; end 32 bit code
+
+ END
diff --git a/private/ntos/nthals/halncr/i386/ncrstop.c b/private/ntos/nthals/halncr/i386/ncrstop.c
new file mode 100644
index 000000000..31172977b
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrstop.c
@@ -0,0 +1,219 @@
+/*++
+
+Copyright (c) 1992 NCR Corporation
+
+Module Name:
+
+ ncrstop.c
+
+Abstract:
+
+ Provides the interface to the firmware for x86.
+
+Author:
+
+ Richard R. Barton (o-richb) 04-Feb-1992
+
+Revision History:
+
+--*/
+#include "halp.h"
+#include "ncr.h"
+
+/*
+ * Some plagarism from ixreboot.c
+ */
+
+//
+// Defines to let us diddle the CMOS clock and the keyboard
+//
+
+#define CMOS_CTRL (PUCHAR )0x70
+#define CMOS_DATA (PUCHAR )0x71
+
+
+// below 2 defines are for 3450/3550 machines
+
+#define SHUT_DOWN 0x8F
+#define SHUT5 0x05
+
+#define RESET 0xfe
+#define KEYBPORT (PUCHAR )0x64
+
+extern ULONG NCRPlatform;
+
+extern BOOLEAN NCRPowerOffSystem;
+
+//
+// Private function prototypes
+//
+
+VOID
+HalpReboot (
+ VOID
+ );
+
+
+VOID
+HalReturnToFirmware(
+ IN FIRMWARE_ENTRY Routine
+ )
+
+/*++
+
+Routine Description:
+
+ Returns control to the firmware routine specified.
+
+ BUGBUG This can probably do useful things (like rebooting) for some
+ values of Routine.
+
+Arguments:
+
+ Routine - Supplies a value indicating which firmware routine to invoke.
+
+Return Value:
+
+ Does not return.
+
+--*/
+
+{
+ switch (Routine) {
+ case HalPowerDownRoutine:
+ if (NCRPlatform != NCR3360) {
+ HalpCatPowerOffSystem();
+ }
+
+ case HalHaltRoutine:
+ case HalRestartRoutine:
+ case HalRebootRoutine:
+
+ //
+ // Never returns
+ //
+
+ if ((NCRPlatform != NCR3360) && (NCRPowerOffSystem == TRUE)) {
+ HalpCatPowerOffSystem();
+ } else {
+ HalpVideoReboot();
+ HalpReboot();
+ }
+ break;
+ default:
+ DBGMSG(("HalReturnToFirmware called\n"));
+ DbgBreakPoint();
+ break;
+ }
+}
+
+
+VOID
+HalpReboot (
+ VOID
+ )
+
+/*++
+
+Routine Description:
+
+ This procedure resets the CMOS clock to the standard timer settings
+ so the bios will work, and then issues a reset command to the keyboard
+ to cause a warm boot.
+
+ It is very machine dependent, this implementation is intended for
+ PC-AT like machines.
+
+ This code copied from the "old debugger" sources.
+
+ N.B.
+
+ Will NOT return.
+
+--*/
+
+{
+ UCHAR Scratch;
+ PUSHORT Magic;
+
+ //
+ // By sticking 0x1234 at physical location 0x472, we can bypass the
+ // memory check after a reboot.
+ //
+
+ Magic = HalpMapPhysicalMemory(0, 1);
+ Magic[0x472 / sizeof(USHORT)] = 0x1234;
+
+ //
+ // Turn off interrupts
+ //
+
+ HalpAcquireCmosSpinLock();
+
+ _asm {
+ cli
+ }
+
+ //
+ // Reset the cmos clock to a standard value
+ // (We are setting the periodic interrupt control on the MC147818)
+ //
+
+ //
+ // Disable periodic interrupt
+ //
+
+ WRITE_PORT_UCHAR(CMOS_CTRL, 0x0b); // Set up for control reg B.
+ KeStallExecutionProcessor(1);
+
+ Scratch = READ_PORT_UCHAR(CMOS_DATA);
+ KeStallExecutionProcessor(1);
+
+ Scratch &= 0xbf; // Clear periodic interrupt enable
+
+ WRITE_PORT_UCHAR(CMOS_DATA, Scratch);
+ KeStallExecutionProcessor(1);
+
+ //
+ // Set "standard" divider rate
+ //
+
+ WRITE_PORT_UCHAR(CMOS_CTRL, 0x0a); // Set up for control reg A.
+ KeStallExecutionProcessor(1);
+
+ Scratch = READ_PORT_UCHAR(CMOS_DATA);
+ KeStallExecutionProcessor(1);
+
+ Scratch &= 0xf0; // Clear rate setting
+ Scratch |= 6; // Set default rate and divider
+
+ WRITE_PORT_UCHAR(CMOS_DATA, Scratch);
+ KeStallExecutionProcessor(1);
+
+ //
+ // Set a "neutral" cmos address to prevent weirdness
+ // (Why is this needed? Source this was copied from doesn't say)
+ //
+
+ WRITE_PORT_UCHAR(CMOS_CTRL, 0x15);
+ KeStallExecutionProcessor(1);
+
+ //
+ // for 3450/3550 machines - Set shutdown flag to reset
+ //
+
+ if ((NCRPlatform == NCR3450) || (NCRPlatform == NCR3550)) {
+ WRITE_PORT_UCHAR(CMOS_CTRL, SHUT_DOWN);
+ WRITE_PORT_UCHAR(CMOS_DATA, SHUT5);
+ }
+
+ //
+ // Send the reset command to the keyboard controller
+ //
+
+ WRITE_PORT_UCHAR(KEYBPORT, RESET);
+
+ _asm {
+ hlt
+ }
+}
diff --git a/private/ntos/nthals/halncr/i386/ncrsus.c b/private/ntos/nthals/halncr/i386/ncrsus.c
new file mode 100644
index 000000000..b454cef24
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrsus.c
@@ -0,0 +1,678 @@
+/*++
+
+Copyright (c) 1993 NCR Corporation
+
+Module Name:
+
+ ncrsus.c
+
+Abstract:
+
+ Provides the interface to the NCR SUS.
+
+Author:
+
+ Rick Ulmer (rick.ulmer@columbiasc.ncr.com) 8-Sep-1993
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "ncr.h"
+#include "ncrcat.h"
+#include "ncrsus.h"
+#include "ncrarb.h"
+
+
+PNST_SUS_LOG SUSErrorLogHeader;
+PUCHAR SUSErrorLogData;
+PUCHAR CurrentSUSErrorEntryPosition;
+USHORT CurrentSUSErrorEntryBytesRemaining;
+
+
+PKERNEL_SUS_MAILBOX SUSMailbox;
+PPROCESSOR_BOARD_INFO SUSBoardInfo;
+PCPU_INFO SUSCpuInfo;
+
+extern ULONG NCRExistingProcessorMask;
+extern ULONG NCRExistingDyadicProcessorMask;
+extern ULONG NCRExistingQuadProcessorMask;
+
+ULONG HalpGetCmosData (ULONG SourceLocation, ULONG SourceAddress,
+ PUCHAR Buffer, ULONG Length);
+
+ULONG HalpSetCmosData (ULONG SourceLocation, ULONG SourceAddress,
+ PUCHAR Buffer, ULONG Length);
+
+
+BOOLEAN HalpCheckSUSLogSanity();
+
+VOID HalpWriteCheckSum(
+ PUCHAR CheckSumStart,
+ PUCHAR CheckSumEnd,
+ PUCHAR CheckSumLowByte,
+ PUCHAR CheckSumHighByte
+ );
+
+ULONG NCRTranslateCMOSMask(ULONG);
+
+
+
+VOID
+HalpInitializeSUSInterface (
+ )
+
+{
+ PHYSICAL_ADDRESS physical_log_address;
+ ULONG LowPart;
+ UCHAR data;
+ ULONG i;
+
+
+//
+// Get pointers to SUS Error Log
+//
+
+ SUSErrorLogHeader = NULL;
+ SUSErrorLogData = NULL;
+
+ LowPart = 0;
+
+ HalpGetCmosData(1,SUS_LOG_PTR,
+ (PUCHAR)&LowPart,NST_LOG_PTR_SIZE);
+
+ SUSErrorLogHeader = (PNST_SUS_LOG)HalpMapPhysicalMemory(LowPart,
+ COMPUTE_PAGES_SPANNED(LowPart,sizeof(NST_SUS_LOG)));
+
+
+ if (SUSErrorLogHeader != NULL) {
+
+ LowPart += SUSErrorLogHeader->PhysicalLogBegin;
+
+ SUSErrorLogData = (PUCHAR)HalpMapPhysicalMemory(LowPart,
+ COMPUTE_PAGES_SPANNED(LowPart,SUSErrorLogHeader->PhysicalLogEnd));
+
+
+ if (SUSErrorLogData == NULL) {
+ // MmUnmapIoSpace(SUSErrorLogHeader,sizeof(NST_SUS_LOG));
+ SUSErrorLogHeader = NULL;
+ }
+ }
+
+
+//
+// Make sure SUS error log is OK
+//
+/*RMU
+This is just during debug.......
+
+ if (SUSErrorLogHeader) {
+ SUSErrorLogHeader->FirstUnreadRecord = SUSErrorLogHeader->FirstValidRecord;
+ SUSErrorLogHeader->UnreadBytesInLog = SUSErrorLogHeader->ValidBytesInLog;
+ }
+*/
+
+
+ if (!HalpCheckSUSLogSanity()) {
+ DBGMSG(("SUS Error log is corrputed......................\n"));
+ SUSErrorLogHeader = NULL;
+ SUSErrorLogData = NULL;
+ }
+
+
+
+/*RMU debug phase */
+
+//
+// Get Pointer to SUS/Kernel mailbox
+//
+
+
+ LowPart = 0;
+
+ HalpGetCmosData(1,SUS_MAILBOX_PTR,
+ (PUCHAR)&LowPart,4);
+
+ SUSMailbox = (PKERNEL_SUS_MAILBOX)HalpMapPhysicalMemory(LowPart,
+ COMPUTE_PAGES_SPANNED(LowPart,sizeof(KERNEL_SUS_MAILBOX)));
+
+ SUSMailbox->OSMailboxVersion = FIRST_PASS_INTERFACE;
+ SUSMailbox->OSFlags = OS_KNOWS_SYSINT;
+
+
+//
+// Get Pointer to the SUS board info struct.
+//
+
+ LowPart = (ULONG)SUSMailbox->BoardData;
+
+ SUSBoardInfo = (PPROCESSOR_BOARD_INFO)HalpMapPhysicalMemory(LowPart,
+ COMPUTE_PAGES_SPANNED(LowPart,sizeof(PROCESSOR_BOARD_INFO)));
+
+ DBGMSG(("HalpInitializeSUSInterface: SUSMailbox = 0x%x\n", SUSMailbox));
+ DBGMSG(("HalpInitializeSUSInterface: SUSBoardInfo = 0x%x\n", SUSBoardInfo));
+
+
+//
+// Get Pointer to the SUS cpu info struct.
+//
+
+ LowPart = (ULONG)SUSMailbox->Cpu_Data;
+
+ SUSCpuInfo = (PCPU_INFO)HalpMapPhysicalMemory(LowPart,
+ COMPUTE_PAGES_SPANNED(LowPart,sizeof(CPU_INFO)));
+
+ DBGMSG(("HalpInitializeSUSInterface: SUSCpuInfo = 0x%x\n", SUSCpuInfo));
+
+
+//
+// Now lets go look for all the processor in the system and fill in
+// NCRExistingDyadicProcessorMask and NCRExistingQuadProcessorMask
+//
+
+
+ for (i = 0; i < SUSCpuInfo->NumberOfCpus; i++ ) {
+
+ data = SUSCpuInfo->CpuData[i].CPU_HardwareId;
+
+ if ((data & 0xc0) == 0xc0) {
+
+ //
+ // this is a Quad processor
+ //
+ // convert the who_am_i into the proper mask
+ //
+ // format:
+ //
+ // 1100ccss
+ //
+ // cc = processor bits
+ // ss = slot bits
+ //
+
+ NCRExistingQuadProcessorMask |= (1<<((data & 0xf)>>2))<<(((data&3)<<2));
+
+ } else {
+
+ //
+ // this is a Dyadic processor
+ //
+
+ NCRExistingDyadicProcessorMask |= NCRTranslateCMOSMask(data);
+ }
+ }
+
+
+ DBGMSG(("HalpInitializeSUSInterface: Dyadic Mask = 0x%x, Quad Mask = 0x%x\n",
+ NCRExistingDyadicProcessorMask, NCRExistingQuadProcessorMask));
+
+
+
+
+
+
+//
+// Set firmware to perform a cold reset and not take a dump.
+//
+
+ HalpGetCmosData(1,SUS_RESET_PTR,
+ (PUCHAR)&data,1);
+
+ data |= 0x01;
+
+ HalpSetCmosData(1,SUS_RESET_PTR,
+ (PUCHAR)&data,1);
+
+ HalpWriteCheckSum((PUCHAR)SUS_HIGH_AVAIL_XSUM_START,
+ (PUCHAR)SUS_HIGH_AVAIL_XSUM_END,
+ (PUCHAR)SUS_HIGH_AVAIL_XSUM_LOW,
+ (PUCHAR)SUS_HIGH_AVAIL_XSUM_HIGH);
+}
+
+
+
+
+
+
+VOID
+HalpSUSLogError (
+
+ )
+
+{
+//
+// This routine tells SUS to go do FRU analysis. After the FRU
+// analysis the system will reboot
+//
+
+ DBGMSG(("HalpSUSLogError has been called......\n"));
+
+ SUSMailbox->OSFlags |= OS_IN_PROGRESS;
+ SUSMailbox->MailboxOS = SYSINT_HANDSHAKE;
+
+
+//
+// Send interrupt from SP to DP
+//
+
+ WRITE_PORT_UCHAR((PUCHAR)0xf820,(UCHAR)0x11);
+}
+
+
+
+BOOLEAN
+HalpSUSSwNmi (
+
+ )
+
+{
+
+ DBGMSG(("HalpSUSSwNmi has been called......\n"));
+
+ if (SUSMailbox->MailboxSUS == DUMP_BUTTON_INTERRUPT) {
+
+ SUSMailbox->MailboxOS = NO_COMMAND;
+ SUSMailbox->OSFlags |= OS_IN_PROGRESS;
+ KeStallExecutionProcessor(1000000); // give DP a chance 1 sec
+
+ SUSMailbox->MailboxOS = IGNORE_DUMP_BUTTON;
+ SUSMailbox->OSFlags &= ~OS_IN_PROGRESS;
+
+ while (SUSMailbox->MailboxSUS == DUMP_BUTTON_INTERRUPT) {
+ KeStallExecutionProcessor(1);
+ };
+
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+
+
+
+
+
+
+
+BOOLEAN
+HalpCheckSUSLogSanity (
+ )
+
+
+{
+ USHORT bytes_in_log;
+ PSUS_ERROR_RECORD_HEADER SUS_header;
+
+ PUCHAR next_write_record;
+ PUCHAR logical_log_end;
+
+ if (SUSErrorLogHeader == NULL) {
+ return FALSE;
+ }
+
+ next_write_record = ADDRESS_OF(NEXT_WRITE_RECORD);
+ logical_log_end = ADDRESS_OF(LOGICAL_LOG_END);
+
+ if( (FIRST_VALID_RECORD >= PHYS_LOG_END) ||
+ (FIRST_UNREAD_RECORD > PHYS_LOG_END) ||
+ (LOGICAL_LOG_END > PHYS_LOG_END) ||
+ (NEXT_WRITE_RECORD > PHYS_LOG_END) ||
+ (VALID_BYTES_IN_LOG > PHYS_LOG_END) ||
+ (UNREAD_BYTES_IN_LOG > PHYS_LOG_END) ||
+ (UNREAD_BYTES_IN_LOG > VALID_BYTES_IN_LOG) ||
+ (VALID_BYTES_IN_LOG > LOGICAL_LOG_END) ) {
+ return FALSE;
+ }
+
+ if (VALID_BYTES_IN_LOG == 0)
+ return TRUE;
+
+
+ //
+ // Make sure the VALID_BYTES_IN_LOG is correct and that the log can be
+ // traversed starting with the FIRST_VALID_RECORD.
+ //
+
+ for (bytes_in_log = 0,
+ SUS_header = (PSUS_ERROR_RECORD_HEADER)ADDRESS_OF(FIRST_VALID_RECORD);
+ bytes_in_log < VALID_BYTES_IN_LOG; ) {
+
+
+ if (SUS_header > (PSUS_ERROR_RECORD_HEADER)logical_log_end)
+ return FALSE;
+
+ if ((SUS_header == (PSUS_ERROR_RECORD_HEADER)logical_log_end))
+ SUS_header = (PSUS_ERROR_RECORD_HEADER)SUSErrorLogData;
+
+ if (SUS_header->RecordLength <= 0)
+ return FALSE;
+
+ if ((bytes_in_log += SUS_header->RecordLength) > VALID_BYTES_IN_LOG)
+ return FALSE;
+
+ SUS_header = (PSUS_ERROR_RECORD_HEADER)((ULONG)SUS_header +
+ (ULONG)SUS_header->RecordLength);
+ }
+
+ if( bytes_in_log != VALID_BYTES_IN_LOG )
+ return FALSE;
+
+
+ if (UNREAD_BYTES_IN_LOG == 0)
+ return TRUE;
+
+//
+// Make sure the UNREAD_BYTES_IN_LOG is correct and that the log can be
+// traversed starting with the FIRST_UNREAD_RECORD.
+//
+ for (bytes_in_log = 0,
+ SUS_header = (PSUS_ERROR_RECORD_HEADER)ADDRESS_OF(FIRST_UNREAD_RECORD);
+ bytes_in_log < UNREAD_BYTES_IN_LOG; ) {
+
+ if (SUS_header > (PSUS_ERROR_RECORD_HEADER)logical_log_end)
+ return FALSE;
+
+ if ((SUS_header == (PSUS_ERROR_RECORD_HEADER)logical_log_end))
+ SUS_header = (PSUS_ERROR_RECORD_HEADER)SUSErrorLogData;
+
+ if (SUS_header->RecordLength <= 0)
+ return FALSE;
+
+ if ((bytes_in_log += SUS_header->RecordLength) > UNREAD_BYTES_IN_LOG)
+ return FALSE;
+
+ SUS_header = (PSUS_ERROR_RECORD_HEADER)((ULONG)SUS_header +
+ (ULONG)SUS_header->RecordLength);
+ }
+
+ if( bytes_in_log != UNREAD_BYTES_IN_LOG )
+ return FALSE;
+
+ return TRUE;
+}
+
+
+
+
+
+LONG
+HalGetSUSErrorLogEntry (
+ PUCHAR ErrorEntry
+ )
+
+{
+ PSUS_ERROR_RECORD_HEADER SUS_header;
+ USHORT entry_length;
+
+ if ((SUSErrorLogHeader == NULL) || (SUSErrorLogData == NULL)) {
+ return -1;
+ }
+
+ if (UNREAD_BYTES_IN_LOG) {
+
+ SUS_header = (PSUS_ERROR_RECORD_HEADER)ADDRESS_OF(FIRST_UNREAD_RECORD);
+ entry_length = SUS_header->RecordLength;
+
+ if (entry_length > HAL_MAX_SUS_ENTRY_SIZE) {
+ entry_length = HAL_MAX_SUS_ENTRY_SIZE;
+ }
+
+ RtlMoveMemory(ErrorEntry,SUS_header,entry_length);
+
+ UNREAD_BYTES_IN_LOG -= SUS_header->RecordLength;
+ FIRST_UNREAD_RECORD += SUS_header->RecordLength;
+
+ if ((FIRST_UNREAD_RECORD == LOGICAL_LOG_END) &&
+ (UNREAD_BYTES_IN_LOG)) {
+
+ FIRST_UNREAD_RECORD = 0;
+ }
+
+ } else {
+ entry_length = 0;
+ }
+ return entry_length;
+}
+
+
+
+
+VOID
+HalSetWatchDogPeriod (
+ ULONG Period
+ )
+
+{
+ if (SUSMailbox) {
+ SUSMailbox->OSFlags |= UPDATING_WDPERIOD;
+ SUSMailbox->WatchDogPeriod = Period;
+ SUSMailbox->WatchDogCount = 0;
+ SUSMailbox->OSFlags &= ~UPDATING_WDPERIOD;
+ }
+}
+
+
+VOID
+HalBumpWatchDogCount (
+ )
+
+{
+ if (SUSMailbox) {
+ SUSMailbox->WatchDogCount++;
+ }
+}
+
+
+
+
+
+
+
+VOID
+HalpBeginSUSErrorEntry (
+ ULONG EntryType,
+ ULONG EntrySize
+ )
+
+{
+ USHORT record_length;
+ PSUS_ERROR_RECORD_HEADER SUS_header;
+
+ USHORT i;
+
+
+//
+// Make sure the log is in a good state.
+//
+
+ if (!HalpCheckSUSLogSanity()) {
+ CurrentSUSErrorEntryPosition = NULL;
+ CurrentSUSErrorEntryBytesRemaining = 0;
+ return;
+ }
+
+
+//
+// Make sure the Error Entry is valid
+//
+
+ if ((EntryType != NST_ErrorType) && (EntryType != ASCII_ErrorType)) {
+ return;
+ }
+
+
+ record_length = EntrySize + sizeof(SUS_ERROR_RECORD_HEADER);
+
+//
+// increate by 1 for the null terminator
+//
+ record_length++;
+
+
+//
+// is it too big to fit?
+//
+
+ if (record_length > PHYS_LOG_END)
+ return;
+
+ /* Check for fit before physical end of log */
+ /*
+ * if this record will NOT fit within physical end of log,
+ * it causes a wrap of the error log
+ * if the log is in a wrapped state, valid records at end of log will
+ * be lost
+ * Delete the valid bytes that are at the end of the log
+ * Point first valid to top of log
+ * if first unread will be lost in the wrap, unread records at the
+ * end of the log will be lost
+ * Delete the unread bytes that are at the end of the log
+ * Point first unread to top of log
+ * Set new logical end to where next record was to write
+ * Set next write record to the top of the log
+ */
+
+ if ((record_length + NEXT_WRITE_RECORD) > PHYS_LOG_END) {
+ if (FIRST_VALID_RECORD >= NEXT_WRITE_RECORD) {
+ VALID_BYTES_IN_LOG -= LOGICAL_LOG_END - FIRST_VALID_RECORD;
+ FIRST_VALID_RECORD = 0;
+ }
+ if (FIRST_UNREAD_RECORD >= NEXT_WRITE_RECORD) {
+ UNREAD_BYTES_IN_LOG -= LOGICAL_LOG_END - FIRST_UNREAD_RECORD;
+ FIRST_UNREAD_RECORD = 0;
+ }
+ LOGICAL_LOG_END = NEXT_WRITE_RECORD;
+ NEXT_WRITE_RECORD = 0;
+ }
+
+
+ /* Check for overwriting currently unread records */
+
+ while(UNREAD_BYTES_IN_LOG && (NEXT_WRITE_RECORD <= FIRST_UNREAD_RECORD) &&
+ ((record_length + NEXT_WRITE_RECORD) > FIRST_UNREAD_RECORD)) {
+
+ UNREAD_BYTES_IN_LOG -= RECORDLENGTH(ADDRESS_OF(FIRST_UNREAD_RECORD));
+ FIRST_UNREAD_RECORD += RECORDLENGTH(ADDRESS_OF(FIRST_UNREAD_RECORD));
+
+ if (FIRST_UNREAD_RECORD >= LOGICAL_LOG_END) {
+ FIRST_UNREAD_RECORD = 0;
+ }
+ }
+
+
+ /* Check for overwriting currently valid records */
+
+ while (VALID_BYTES_IN_LOG && (NEXT_WRITE_RECORD <= FIRST_VALID_RECORD)&&
+ ((record_length + NEXT_WRITE_RECORD) > FIRST_VALID_RECORD)) {
+
+ VALID_BYTES_IN_LOG -= RECORDLENGTH(ADDRESS_OF(FIRST_VALID_RECORD));
+ FIRST_VALID_RECORD += RECORDLENGTH(ADDRESS_OF(FIRST_VALID_RECORD));
+ if (FIRST_VALID_RECORD >= LOGICAL_LOG_END) {
+ FIRST_VALID_RECORD = 0;
+ LOGICAL_LOG_END = VALID_BYTES_IN_LOG;
+ }
+ }
+
+ UNREAD_BYTES_IN_LOG += record_length;
+ VALID_BYTES_IN_LOG += record_length;
+
+ SUS_header = (PSUS_ERROR_RECORD_HEADER)ADDRESS_OF(NEXT_WRITE_RECORD);
+
+ RtlZeroMemory((PVOID)SUS_header, (ULONG)record_length);
+
+ SUS_header->RecordType = EntryType;
+ SUS_header->RecordLength = record_length;
+
+ CurrentSUSErrorEntryPosition = (PUCHAR)ADDRESS_OF(NEXT_WRITE_RECORD) +
+ sizeof(SUS_ERROR_RECORD_HEADER);
+
+ CurrentSUSErrorEntryBytesRemaining = EntrySize;
+
+ /*
+ * Adjust all of the offsets to include the new record.
+ */
+
+ NEXT_WRITE_RECORD += record_length;
+
+ if (NEXT_WRITE_RECORD > LOGICAL_LOG_END)
+ LOGICAL_LOG_END = NEXT_WRITE_RECORD;
+}
+
+
+
+VOID
+HalpWriteToSUSErrorEntry (
+ PUCHAR EntryData
+ )
+
+{
+ USHORT entry_length;
+ USHORT i;
+ PUCHAR char_pointer;
+
+ if (CurrentSUSErrorEntryBytesRemaining == 0) {
+ return;
+ }
+
+ entry_length = 0;
+ char_pointer = EntryData;
+
+ while (*char_pointer) {
+ char_pointer++;
+ entry_length++;
+ }
+
+ if (entry_length == 0)
+ return;
+
+ if (entry_length > CurrentSUSErrorEntryBytesRemaining) {
+ entry_length = CurrentSUSErrorEntryBytesRemaining;
+ }
+
+
+//
+// Copy Entry segment into the Error Log
+//
+
+ RtlMoveMemory(CurrentSUSErrorEntryPosition,EntryData,entry_length);
+
+ CurrentSUSErrorEntryBytesRemaining -= entry_length;
+ CurrentSUSErrorEntryPosition += entry_length;
+}
+
+
+
+
+VOID HalpWriteCheckSum(
+ PUCHAR CheckSumStart,
+ PUCHAR CheckSumEnd,
+ PUCHAR CheckSumLowByte,
+ PUCHAR CheckSumHighByte
+ )
+
+
+
+{
+ USHORT check_sum = 0;
+ USHORT zero_sum;
+ PUCHAR address;
+ UCHAR data;
+
+
+ for (address = CheckSumStart; address <= CheckSumEnd; address++) {
+ HalpGetCmosData(1,(ULONG)address,
+ (PUCHAR)&data,1);
+ check_sum = check_sum + data;
+ }
+
+ zero_sum = 0 - check_sum;
+
+ HalpSetCmosData(1,SUS_HIGH_AVAIL_XSUM_LOW,
+ (PUCHAR)&zero_sum,2);
+}
+
+
+
+
diff --git a/private/ntos/nthals/halncr/i386/ncrsus.h b/private/ntos/nthals/halncr/i386/ncrsus.h
new file mode 100644
index 000000000..b9981cc7a
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrsus.h
@@ -0,0 +1,361 @@
+/*++
+
+Copyright (C) 1992 NCR Corporation
+
+
+Module Name:
+
+ ncrsus.h
+
+Author:
+
+Abstract:
+
+ System equates for dealing with the NCR SUS.
+
+++*/
+
+#ifndef _NCRSUS_
+#define _NCRSUS_
+
+
+#define SUS_LOG_PTR 0xA27 /* CMOS location where the SUS Error */
+ /* Log pointer is kept. */
+
+#define HAL_MAX_SUS_ENTRY_SIZE 0x2000 // Maximum Error Log entry size
+
+#pragma pack(1)
+
+typedef struct _NST_SUS_LOG {
+ USHORT PhysicalLogBegin; /* Offset from the header */
+ USHORT PhysicalLogEnd; /* Offset from the PhysicalLogBegin */
+ USHORT FirstValidRecord; /* Offset from the PhysicalLogBegin */
+ USHORT FirstUnreadRecord; /* Offset from the PhysicalLogBegin */
+ USHORT NextWriteRecord; /* Offset from the PhysicalLogBegin */
+ USHORT LogicalLogEnd; /* Offset from the PhysicalLogBegin */
+ USHORT ValidBytesInLog; /* Number of valid bytes in the log */
+ USHORT UnreadBytesInLog; /* Number of unread bytes in the log */
+} NST_SUS_LOG, *PNST_SUS_LOG;
+#pragma pack()
+
+
+#pragma pack(1)
+typedef struct _SUS_ERROR_RECORD_HEADER {
+ USHORT RecordType; /* Type of record */
+ USHORT RecordLength; /* Length of record in bytes */
+} SUS_ERROR_RECORD_HEADER, *PSUS_ERROR_RECORD_HEADER;
+#pragma pack()
+
+
+
+#define NST_ErrorType 0x01 /* Conforms to NST ASCII Format */
+#define ASCII_ErrorType 0x02 /* Non NST, but All ASCII (SUS Can Display) */
+
+#define LOGSIZE PHYS_LOG_END
+
+#define PHYS_LOG_BEGIN (SUSErrorLogHeader->PhysicalLogBegin)
+#define PHYS_LOG_END (SUSErrorLogHeader->PhysicalLogEnd)
+#define FIRST_VALID_RECORD (SUSErrorLogHeader->FirstValidRecord)
+#define FIRST_UNREAD_RECORD (SUSErrorLogHeader->FirstUnreadRecord)
+#define NEXT_WRITE_RECORD (SUSErrorLogHeader->NextWriteRecord)
+#define LOGICAL_LOG_END (SUSErrorLogHeader->LogicalLogEnd)
+#define VALID_BYTES_IN_LOG (SUSErrorLogHeader->ValidBytesInLog)
+#define UNREAD_BYTES_IN_LOG (SUSErrorLogHeader->UnreadBytesInLog)
+#define ADDRESS_OF(OFFSET) (SUSErrorLogData + OFFSET)
+#define RECORDLENGTH(ADDRESS) (((PSUS_ERROR_RECORD_HEADER)(ADDRESS))->RecordLength)
+
+
+#define NST_LOG_PTR_SIZE 4 /* error log ptr size in cmos */
+
+#define CBIOS_SEGMENT 0x40 /* start of bios data area */
+#define CBIOS_OFFSET 0x0E /* extended data segment offset */
+#define CBIOS_AREA ((CBIOSSEGMENT << 4) + CBIOSOFFSET)
+#define POST_NERROFF 0x17 /* offset for number of post errors */
+#define POST_LOGOFF 0x18 /* offset where error log begins */
+#define POST_SPECIFIC "%d%02d" /* post error log specific portion */
+#define POST_ERROR_ID 23 /* used in error log tag */
+#define POST_SPEC_SIZE 10 /* size of post specific portion */
+#define NONE_ID 02
+
+#define E_POSTDOS_TAGS 230000000
+#define E_NONE_TAGS 20000000
+
+#define POST_ERROR_TAG (E_POSTDOS_TAGS + POSTERRORID)
+#define NONE_ERROR_TAG (E_NONE_TAGS + NONEID)
+
+
+#define SUS_MAILBOX_PTR 0xb1a /* XCMOS location for the SUS/OS MAILBOX */
+
+
+#define SUS_RESET_PTR 0xa33 /* XCMOS location for the SUS reboot flag */
+#define SUS_HIGH_AVAIL_XSUM_START 0xa20
+#define SUS_HIGH_AVAIL_XSUM_END 0xb1d
+#define SUS_HIGH_AVAIL_XSUM_LOW 0xb1e
+#define SUS_HIGH_AVAIL_XSUM_HIGH 0xb1f
+
+
+#define NUMBER_OF_POS_REGS 8
+
+#pragma pack(1)
+typedef struct _MC_SLOT_INFORMATION{
+ UCHAR MCSlot;
+ UCHAR POSValues[NUMBER_OF_POS_REGS];
+} MC_SLOT_INFORMATION, *PMC_SLOT_INFORMATION;
+#pragma pack()
+
+#define NUMBER_OF_MC_BUSSES 2
+#define SLOTS_PER_MC_BUS 8
+#define MAX_CPUS 16 // 16 way CPU system
+
+/* Index to MC_SlotInfo[xMC_BUS][] */
+#define PMC_BUS 0
+#define SMC_BUS 1
+
+#define MAX_PROCESSOR_BOARDS 4 /* 4 processor slot system */
+#define MAX_CACHE_LEVELS 4 /* # of cache levels supported */
+#define MAX_SHARED_CPUS 4 /* # of CPUs that can share a LARC */
+
+/*
+ * Defines for BoardDescription
+ * structure
+ */
+
+/* Defines for Type */
+#define DYADIC_OR_MONADIC 0
+#define QUAD 1
+
+#define POFFMASK 0xfff // Mask for offset into page.
+
+
+/* Define for LocalMemoryStateBits */
+#define BANK_0_PRESENT 0x01
+#define BANK_0_FUNCTIONAL 0x02
+#define BANK_1_PRESENT 0x04
+#define BANK_1_FUNTIONAL 0x08
+
+/* type defines for CPU info */
+#define BASIC_CPU_INFO_TYPE 0
+#define CPU_INFO_VERSION_0 0
+
+/*
+ * Defines for ProcBoardInfo
+ * and QuadDescription structurs
+ */
+#define QUAD_BOARD_INFO_TYPE 0
+#define QUAD_BOARD_INFO_VERSION_0 0
+#define QUAD_DESCRIPTION_TYPE 1
+#define QUAD_DESCRIPTION_VERSION_0 0
+#define DYADIC_DESCRIPTION_TYPE 0
+#define DYADIC_DESCRIPTION_VERSION 0
+
+
+#pragma pack(1)
+typedef struct _QUAD_DESCRIPTION {
+ UCHAR Type;
+ UCHAR StructureVersion;
+ ULONG IpiBaseAddress;
+ ULONG LarcBankSize;
+ ULONG LocalMemoryStateBits;
+ UCHAR Slot;
+ } QUAD_DESCRIPTION, *PQUAD_DESCRIPTION;
+#pragma pack()
+
+
+#pragma pack(1)
+typedef struct _PROCESSOR_BOARD_INFO {
+ UCHAR Type;
+ UCHAR StructureVersion;
+ UCHAR NumberOfBoards;
+ QUAD_DESCRIPTION QuadData[MAX_PROCESSOR_BOARDS];
+ } PROCESSOR_BOARD_INFO, *PPROCESSOR_BOARD_INFO;
+#pragma pack()
+
+#pragma pack(1)
+typedef struct _CACHE_DESCRIPTION {
+ UCHAR Level;
+ ULONG TotalSize;
+ USHORT LineSize;
+ UCHAR Associativity;
+ UCHAR CacheType;
+ UCHAR WriteType;
+ UCHAR NumberCpusSharedBy;
+ UCHAR SharedCpusHardware_Ids[MAX_SHARED_CPUS];
+ } CACHE_DESCRIPTION, *PCACHE_DESCRIPTION;
+#pragma pack()
+
+
+#pragma pack(1)
+typedef struct _CPU_DESCRIPTION {
+ UCHAR CPU_HardwareId;
+ PCHAR FRU_String;
+ UCHAR NumberOfCacheLevels;
+ CACHE_DESCRIPTION CacheLevelData[MAX_CACHE_LEVELS];
+ } CPU_DESCRIPTION, *PCPU_DESCRIPTION;
+#pragma pack()
+
+
+#pragma pack(1)
+typedef struct _CPU_INFO {
+ UCHAR Type;
+ UCHAR StructureVersion;
+ UCHAR NumberOfCpus;
+ CPU_DESCRIPTION CpuData[MAX_CPUS];
+ } CPU_INFO, *PCPU_INFO;
+#pragma pack()
+
+
+
+/*
+ * This structure will be used by SUS and the OS.
+ */
+
+
+#pragma pack(1)
+typedef struct _KERNEL_SUS_MAILBOX {
+ UCHAR MailboxSUS; /* Written to by SUS to give
+ commands/response to the OS */
+ UCHAR MailboxOS; /* Written to by the OS to give
+ commands/response to SUS */
+ UCHAR SUSMailboxVersion; /* Tells the OS which iteration of the
+ interface SUS supports */
+ UCHAR OSMailboxVersion; /* Tells SUS which iteration of the
+ interface the OS supports */
+ ULONG OSFlags; /* Flags set by the OS as info for
+ SUS */
+ ULONG SUSFlags; /* Flags set by SUS as info for OS */
+ ULONG WatchDogPeriod; /* Watchdog period (in seconds) which
+ the DP uses to see if the OS is
+ dead */
+ ULONG WatchDogCount; /* Updated by the OS on every tic. */
+ ULONG MemoryForSUSErrorLog; /* Flat 32 bit address which tells
+ SUS where to stuff the SUS error
+ log on a dump */
+ MC_SLOT_INFORMATION MCSlotInfo[NUMBER_OF_MC_BUSSES][SLOTS_PER_MC_BUS];
+ /* Storage for MCA POS data */
+ PPROCESSOR_BOARD_INFO BoardData;
+ PCPU_INFO Cpu_Data;
+ /* All new fields must be added from this point */
+} KERNEL_SUS_MAILBOX, *PKERNEL_SUS_MAILBOX;
+#pragma pack()
+
+/*
+ * Common defines for MailBox_SUS
+ */
+#define NO_COMMAND 0x00 /* Default state - indicates that no action/response has been written */
+/*
+ * Defines for start of day VERSION INFO the can be put in both MailBoxes.
+ */
+#define FIRST_PASS_INTERFACE 0x10
+
+/*
+ * SUS messages to the OS
+ */
+#define DUMP_BUTTON_INTERRUPT 0x01
+#define KERNEL_SUS_STRUCTURE_VALID 0x02
+/*
+ * SUS responses to OS messages
+ */
+#define SYSINT_COMPLETE 0x03
+
+/*
+ * OS responses to SUS messages
+ */
+#define IGNORE_DUMP_BUTTON 0x01
+#define TAKE_A_DUMP 0x02
+/*
+ * OS messages to SUS
+ */
+#define SYSINT_HANDSHAKE 0x03
+#define TAKE_MEMORY_DUMP 0x04
+#define SYSINT_WAS_RECOVERED 0x05
+
+/*
+ * Defines for Flags_OS
+ */
+#define OS_KNOWS_SYSINT 0x00000001
+#define OS_IN_PROGRESS 0x00000002
+#define UPDATING_WDPERIOD 0x00000004
+/*
+ * Defines for SUS_Flags
+ */
+#define SUS_BOOTING 0x00000001
+#define SUS_IN_PROGRESS 0x00000002
+/*
+ * Constant for delay util we give up looking for an OS
+ */
+#define SYSINT_HANDOFF_TIMEOUT (60*5*1000)
+
+/* defines for watchdog timer interface */
+#define WDMIN 5 /* 5 seconds is minimum WD period */
+#define WRITE_TIMEOUT 5 /* 5 milliseconds is max period update time */
+
+/*
+ * The following defines allocate the slots in the mailbox.
+ * THIS SOULD CHANGE TO THE STRUCTURE KERNEL_SUS_MAILBOX
+ */
+#define SUS_MBOX_SLOT 0
+#define KERNEL_MBOX_SLOT 1
+
+
+/* Size of copy used with MemoryFor_SUS_ErrorLog
+ */
+
+/* This is the interface from the OS to SUS. You can reverse this
+ * example to go the other way.
+ */
+
+/*
+
+Kernel SUS
+-------------------------------------------- ---------------------------------
+KernelSUSMailbox.MailboxOS = REQUEST_TASK_X
+Interrupt is sent to DP
+ KernelSUSMailbox.MailboxSUS = NO_COMMAND
+ KernelSUSMailbox.SUSFlags |= SUS_IN_PROGRESS
+
+Wait 5 Sec for KernelSUSMailbox.SUSFlags & DO TASK_X
+ SUS_IN_PROGRESS
+ KernelSUSMailbox.MailboxSUS = SYSINT_COMPLETE
+ KernelSUSMailbox.SUSFlags &= ~SUS_IN_PROGRESS
+
+Wait ? Sec for KernelSUSMailbox.MailboxSUS ==
+ TASK_X_COMPLETE
+KernelSUSMailbox.MailboxOS = NO_COMMAND
+
+ */
+
+
+
+
+
+LONG
+HalGetSUSErrorLogEntry (
+ PUCHAR ErrorEntry
+ );
+
+VOID
+HalSetWatchDogPeriod (
+ ULONG Period
+ );
+
+VOID
+HalBumpWatchDogCount (
+ );
+
+
+VOID
+HalpBeginSUSErrorEntry (
+ ULONG EntryType,
+ ULONG EntrySize
+ );
+
+VOID
+HalpWriteToSUSErrorEntry (
+ PUCHAR EntryData
+ );
+
+VOID
+HalpInitializeSUSInterface (
+ );
+
+#endif // _NCRSUS_
diff --git a/private/ntos/nthals/halncr/i386/ncrsyint.asm b/private/ntos/nthals/halncr/i386/ncrsyint.asm
new file mode 100644
index 000000000..2e2e811d4
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/ncrsyint.asm
@@ -0,0 +1,711 @@
+;++
+;
+;Copyright (c) 1992 NCR Corporation
+;
+;Module Name:
+;
+; ncrsyint.asm
+;
+;Abstract:
+;
+; This module implements the HAL routines to enable/disable system
+; interrupts.
+;
+;Author:
+;
+; Richard Barton (o-richb) 24-Jan-1992
+;
+;Environment:
+;
+; Kernel Mode
+;
+;Revision History:
+;
+;--
+
+
+.486p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\ix8259.inc
+include i386\kimacro.inc
+include mac386.inc
+include i386\ncr.inc
+ .list
+
+ EXTRNP KfLowerIrql,1,,FASTCALL
+ EXTRNP _NCRClearQicIpi,1
+ EXTRNP _HalQicRequestIpi,2
+ EXTRNP _NCRAdjustDynamicClaims,0
+ extrn KiI8259MaskTable:DWORD
+ extrn _NCRLogicalNumberToPhysicalMask:DWORD
+ extrn _NCRProcessorIDR:DWORD
+ extrn _NCRNeverClaimIRQs:DWORD
+ extrn _NCRMaxIRQsToClaim:DWORD
+ extrn _NCRGlobalClaimedIRQs:DWORD
+ifdef DBG
+ extrn _NCRProcessorClaimedIRQs:DWORD
+ extrn _NCRClaimCount:DWORD
+ extrn _NCRStolenCount:DWORD
+ extrn _NCRUnclaimCount:DWORD
+endif
+
+
+ifdef IRQL_METRICS
+ extrn HalPostponedIntCount:dword
+endif
+
+
+_TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME CS:FLAT, DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+
+;++
+;BOOLEAN
+;HalBeginSystemInterrupt(
+; IN KIRQL Irql
+; IN CCHAR Vector,
+; OUT PKIRQL OldIrql
+; )
+;
+;
+;
+;Routine Description:
+;
+; This routine is used to determine whether the given interrupt is
+; spurious and to raise the irql to the given value.
+; It is called before the interrupt service routine code is executed.
+;
+; N.B. This routine does NOT preserve EAX or EBX
+;
+; On a UP machine the interrupt dismissed at BeginSystemInterrupt time.
+; This is fine since the irql is being raise to mask it off.
+; HalEndSystemInterrupt is simply a LowerIrql request.
+;
+;
+;Arguments:
+;
+; Irql - Supplies the IRQL to raise to
+;
+; Vector - Supplies the vector of the interrupt being handled
+;
+; OldIrql- Location to return OldIrql
+;
+;
+;Return Value:
+;
+; FALSE - Interrupt is spurious and should be ignored
+;
+; TRUE - Interrupt is real and Irql raised.
+;
+;--
+HbsiIrql equ byte ptr [esp+4]
+HbsiVector equ byte ptr [esp+8]
+HbsiOldIrql equ dword ptr [esp+12]
+
+cPublicProc _HalBeginSystemInterrupt ,3
+cPublicFpo 3,0
+ movzx ebx,HbsiVector ; (eax) = System Vector
+ sub ebx, PRIMARY_VECTOR_BASE ; (eax) = 8259 IRQ #
+ cmp ebx, 1FH ; if greater then CPI
+ ja HalpNotSpurious
+
+;
+; we could be spurious at irq 7
+;
+ mov eax,ebx ; lets mask off whether it is
+ and eax,0fh ; secondary or primary
+ cmp eax, 7H
+ jne HbsiCheckIrq0F
+
+ align dword
+HbsiCheckIrq07:
+;
+; Check to see if this is a spurious interrupt at irq7
+;
+ in al, PIC1_PORT0 ; (al) = content of PIC 1 ISR
+ test al, 10000000B ; Is In-Service register set?
+ jnz short HalpNotSpurious ; No, so this is NOT a spurious int
+ xor eax, eax ; return FALSE
+ stdRET _HalBeginSystemInterrupt
+
+ align dword
+HbsiCheckIrq0F:
+
+;
+; we could be spurious with irq F
+;
+ mov eax,ebx ; lets mask off whether it is
+ and eax,0fh ; secondary or primary
+ cmp eax, 0FH
+ jne HalpNotSpurious
+
+;
+; Check to see if this is a spurious interrupt at irq F
+;
+ in al, PIC2_PORT0 ; (al) = content of PIC 1 ISR
+ test al, 10000000B ; Is In-Service register set?
+ jnz short HalpNotSpurious ; No, this is NOT a spurious int,
+ ; go do the normal interrupt stuff
+
+;
+; This is a spurious interrupt.
+; Because the slave PIC is cascaded to irq2 of master PIC, we need to
+; dismiss the interupt on master PIC's irq2.
+;
+
+ mov al, PIC2_EOI ; Specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+
+ xor eax, eax ; return FALSE
+ stdRET _HalBeginSystemInterrupt
+
+ align dword
+HalpNotSpurious:
+if DBG
+ cmp ebx, 4FH
+ jbe @f
+ int 3
+ align dword
+@@:
+
+endif
+;
+; Store OldIrql
+;
+ mov eax, HbsiOldIrql
+ mov cl, PCR[PcIrql]
+ mov [eax], cl
+
+;
+; Raise IRQL to requested level
+;
+ mov al, HbsiIrql ; (eax) = irql
+ ; (ebx) = IRQ #
+;
+; Now we check to make sure the Irql of this interrupt > current Irql.
+; If it is not, we dismiss it as spurious and set the appropriate bit
+; in the IRR so we can dispatch the interrupt when Irql is lowered
+;
+ cmp al, cl
+ jbe Hbsi300
+;
+; now check for a cpi.
+;
+
+ cmp ebx, NCR_CPI_VECTOR_BASE - PRIMARY_VECTOR_BASE ; check for VIC ipi
+ mov PCR[PcIrql], al ; set new Irql
+ jb CheckClaim
+
+ cmp ebx, NCR_QIC_CPI_VECTOR_BASE - PRIMARY_VECTOR_BASE ; check for QIC ipi
+ jb VicEOI
+
+ and ebx,7H ; only the mask of irq
+ stdCall _NCRClearQicIpi, <ebx>
+
+ jmp NCRCPIEOId
+
+VicEOI:
+ and bl, 7H ; only the mask of irq
+ mov al, bl
+ or al, PIC1_EOI_MASK ; create specific eoi mask for master
+ out PIC1_PORT0, al ; dismiss the interrupt
+
+NCRCPIEOId:
+ sti
+ mov eax, 1 ; return TRUE, interrupt dismissed
+ stdRET _HalBeginSystemInterrupt
+
+;RMU
+;
+; Logic used to dynamicly claim device interrupts
+;
+
+CheckClaim:
+ mov ecx, ebx ; get vector
+
+;
+; Lets check for a status change interrupt because it is a broadcast interrupt
+; and is sent to all processors. In this case we skip the Claim logic completely.
+; If we try to claim this interrupt it will cause problems because it is valid for a
+; processor to get this interrupt while another processor has it claimed.
+;
+
+ cmp ecx, 027h ; status change interrupt is at vector PRIMARY_VECTOR_BASE + 027H
+ jz DontClaim ; done claim if equal
+
+;
+;
+;
+
+ and ecx, 0fh ; now is irql
+ mov eax, 1 ; build irq mask
+ shl eax, cl
+
+ test eax, _NCRNeverClaimIRQs ; see if we should never claim it irq
+ jnz DontClaim
+
+ mov ecx, _NCRGlobalClaimedIRQs
+ mov edx, PCR[PcHal.PcrMyClaimedIRQs]
+ and ecx, eax ; set if irq claimed globally
+ and edx, eax ; set if irq claimed privately
+
+ test edx, ecx ; if irq already claimed
+ jz AdjustClaim
+
+DontClaim:
+ sti
+ mov eax, 1 ; return TRUE, interrupt dismissed
+ stdRET _HalBeginSystemInterrupt
+
+AdjustClaim:
+ test edx, edx
+ not edx ; is it claimed privately?
+ jnz PrivateUnclaim ; yes, then clear claim
+
+ test ecx,ecx ; is it claimed by another?
+ jnz Unclaimed ; don't unclaim
+
+ mov ecx, PCR[PcHal.PcrMyClaimedIRQsCount] ; see if you have our fair share
+ cmp ecx, _NCRMaxIRQsToClaim ; of irqs claimed then handle if
+ jl ClaimForMe ; but don't claim
+
+HandleNoClaim:
+ sti
+ mov eax, 1 ; return TRUE, interrupt dismissed
+ stdRET _HalBeginSystemInterrupt
+
+ClaimForMe:
+
+ mov edx, eax
+ push ebx ; save vector
+ mov ebx, PCR[PcHal.PcrMyClaimedIRQs] ; our claimed irqs
+ or ebx, eax
+ mov eax, _NCRGlobalClaimedIRQs ; what global claim should be
+GlobalClaim:
+ test eax,edx ; this irq has been stolen
+ jnz IRQStolen ; by another processor
+ mov ecx,ebx
+ or ecx,eax
+lock cmpxchg _NCRGlobalClaimedIRQs, ecx
+ jne GlobalClaim
+
+ add esp,4 ; throw away saved vector we do
+ ; not need it
+;
+; Lets claim the interrupt now
+;
+ mov eax,ebx
+ mov PCR[PcHal.PcrMyClaimedIRQs],eax ; claim irq privately
+
+ VIC_WRITE ClaimRegLsb ; set VIC claim registers
+ shr eax,8
+ VIC_WRITE ClaimRegMsb
+ inc PCR[PcHal.PcrMyClaimedIRQsCount]
+
+ mov eax,PCR[PcHal.PcrMyClaimedIRQsCount]
+ VIC_WRITE ActivityReg
+
+ifdef DBG
+ mov ecx,PCR[PcNumber]
+ mov eax,PCR[PcHal.PcrMyClaimedIRQs]
+ mov _NCRProcessorClaimedIRQs[ecx*4], eax
+ inc _NCRClaimCount;
+endif
+
+; done claiming
+ClaimDone:
+
+ sti
+ mov eax, 1 ; return TRUE, interrupt dismissed
+ stdRET _HalBeginSystemInterrupt
+
+IRQStolen:
+
+ifdef DBG
+ inc _NCRStolenCount;
+endif
+
+ pop ebx ; restore vector
+ and ebx, 0fh ; clear high nibble due to SMC or Status Change vector
+ cmp ebx, 8 ; EOI to master or slave?
+ mov al, bl
+ jae short SHbsiEOIMaster ; EIO to both master and slave
+ or al, PIC1_EOI_MASK ; create specific eoi mask for master
+ out PIC1_PORT0, al ; dismiss the interrupt
+ jmp short SHbsiMasterEOId
+
+SHbsiEOIMaster:
+ mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
+ out PIC2_PORT0, al
+ mov al, PIC2_EOI ; specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+SHbsiMasterEOId:
+
+ xor eax, eax ; return FALSE, spurious interrupt
+ stdRET _HalBeginSystemInterrupt
+
+ align dword
+Hbsi300:
+;
+; Raise Irql to prevent it from happening again
+;
+
+;
+; Get the PIC masks for Irql
+;
+ movzx eax, cl
+ mov PCR[PcHal.PcrMyPICsIrql], eax
+ mov eax, KiI8259MaskTable[eax*4]
+ or eax, PCR[PcIDR]
+;
+; Write the new interrupt mask register back to the 8259
+;
+ SET_IRQ_MASK
+;
+; if this isn't a CPI, EOI the interrupt to give the VIC a chance
+; to reroute it
+;
+ cmp ebx, NCR_CPI_VECTOR_BASE - PRIMARY_VECTOR_BASE ; EOI for CPI?
+ jae NCRPostponeCPI ; no need to EOI CPI
+;
+;RMU
+; Logic used to unclaim interrupts. This is done when drivers have disabled
+; an interrupt.
+;
+;
+ mov ecx, ebx ; get vector
+ and ecx, 0fh ; now is irql
+ mov eax, 1 ; build irq mask
+ shl eax, cl
+ mov edx, PCR[PcHal.PcrMyClaimedIRQs]
+ and edx, eax ; claiming fixed?
+ jz Unclaimed ; don't unclaim
+
+ mov ecx, PCR[PcHal.PcrMyClaimedIRQsCount] ; if we don't have our fair
+ cmp ecx, _NCRMaxIRQsToClaim ; share of irqs claimed then
+ jle Unclaimed ; don't unclaim
+
+ not edx ; clear irq bit
+ mov eax, _NCRGlobalClaimedIRQs ; what global claim should be
+GlobalUnclaim:
+ mov ecx, edx
+ and ecx, eax
+lock cmpxchg _NCRGlobalClaimedIRQs, ecx
+ jne GlobalUnclaim
+
+PrivateUnclaim:
+ mov eax, PCR[PcHal.PcrMyClaimedIRQs]
+ and eax, edx
+
+ mov PCR[PcHal.PcrMyClaimedIRQs],eax
+ VIC_WRITE ClaimRegLsb
+ shr eax,8
+ VIC_WRITE ClaimRegMsb
+ dec PCR[PcHal.PcrMyClaimedIRQsCount]
+
+ mov eax,PCR[PcHal.PcrMyClaimedIRQsCount]
+ VIC_WRITE ActivityReg
+
+ifdef DBG
+ mov ecx,PCR[PcNumber]
+ mov eax,PCR[PcHal.PcrMyClaimedIRQs]
+ mov _NCRProcessorClaimedIRQs[ecx*4], eax
+ inc _NCRUnclaimCount;
+endif
+
+;
+Unclaimed:
+
+ and ebx, 0fh ; clear high nibble due to SMC or Status Change vector
+ cmp ebx, 8 ; EOI to master or slave?
+ mov al, bl
+ jae short HbsiEOIMaster ; EIO to both master and slave
+ or al, PIC1_EOI_MASK ; create specific eoi mask for master
+ out PIC1_PORT0, al ; dismiss the interrupt
+ jmp short HbsiMasterEOId
+
+HbsiEOIMaster:
+ mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
+ out PIC2_PORT0, al
+ mov al, PIC2_EOI ; specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+HbsiMasterEOId:
+
+ifdef IRQL_METRICS
+ lock inc HalPostponedIntCount
+endif
+
+ xor eax, eax ; return FALSE, spurious interrupt
+ stdRET _HalBeginSystemInterrupt
+
+ align dword
+NCRPostponeCPI:
+;
+; CPIs must be reissued since when we EOI them they're gone
+;
+
+ cmp ebx, NCR_QIC_CPI_VECTOR_BASE - PRIMARY_VECTOR_BASE ; check for QIC ipi
+ jb VicCPI
+
+ movzx ecx, bl
+ sub ecx, NCR_QIC_CPI_VECTOR_BASE - PRIMARY_VECTOR_BASE
+ and ecx, 7
+
+;
+; Clear the current CPI so we can reissue it again
+;
+
+ push ecx
+ stdCall _NCRClearQicIpi, <ecx>
+ pop ecx
+
+;
+; now reissue the same CPI... since our mask is raised and we've EOId
+; the other we'll get this one when we lower our masks
+;
+
+ mov eax, PCR[PcHal.PcrMyLogicalMask]
+ stdCall _HalQicRequestIpi,<eax,ecx>
+
+ jmp ReissuedCPIDone
+VicCPI:
+ movzx ecx, bl
+ sub ecx, NCR_CPI_VECTOR_BASE - PRIMARY_VECTOR_BASE
+ and ecx, 7
+ mov al, cl
+ or al, PIC1_EOI_MASK ; create specific eoi mask for master
+ out PIC1_PORT0, al ; dismiss the interrupt
+
+;
+; now reissue the same CPI...since our mask is raised and we've EOId
+; the other we'll get this one when we lower our masks.
+;
+ shr ecx, 1 ; we're determining which VIC
+ lea edx, [ecx*8] ; offset corresponds to the
+ adc edx, VIC_BASE_ADDRESS ; given vector
+ mov eax, PCR[PcHal.PcrMyLogicalNumber]
+ mov eax, dword ptr _NCRLogicalNumberToPhysicalMask[eax*4]
+ out dx, al
+
+ReissuedCPIDone:
+
+ifdef IRQL_METRICS
+ lock inc HalPostponedIntCount
+endif
+
+ xor eax, eax ; return FALSE, spurious interrupt
+ stdRET _HalBeginSystemInterrupt
+
+stdENDP _HalBeginSystemInterrupt
+
+;++
+;BOOLEAN
+;HalEndSystemInterrupt(
+; IN KIRQL Irql
+; IN CCHAR Vector,
+; )
+;
+;
+;
+;Routine Description:
+;
+; This routine is used to dismiss the specified interrupt vector and
+; to lower the irql to the given value.
+; It is called after the interrupt service routine code is executed.
+;
+; N.B. This routine does NOT preserve EAX or EBX
+;
+;Arguments:
+;
+; Irql - Supplies the interrupt level of the interrupt to be dismissed
+;
+; Vector - Supplies the vector of the interrupt to be dismissed
+;
+;Return Value:
+;
+; None.
+;
+;--
+HesiIrql equ [esp+4]
+HesiVector equ [esp+8]
+
+cPublicProc _HalEndSystemInterrupt ,2
+cPublicFpo 2,0
+ movzx eax, byte ptr HesiVector ; (eax) = System Vector
+ sub eax, PRIMARY_VECTOR_BASE ; (eax) = 8259 IRQ #
+if DBG
+ cmp eax, 4FH
+ jbe Hesi00
+ int 3
+ align dword
+Hesi00:
+
+endif
+
+;
+; Dismiss interrupt. Current interrupt is already masked off. note that
+; cpi's are eoi'ed at the beginning.
+;
+ cmp eax, NCR_CPI_VECTOR_BASE - PRIMARY_VECTOR_BASE ; EOI for CPI?
+ mov ecx, HesiIrql ; (cl) = NewIrql
+ jae short Hesi10 ; no need to EOI CPI
+ and eax, 0fh ; clear high nibble due to SMC or Status Change vector
+
+ cmp eax, 8 ; EOI to master or slave?
+
+ jae short Hesi100 ; EIO to both master and slave
+ or al, PIC1_EOI_MASK ; create specific eoi mask for master
+ out PIC1_PORT0, al ; dismiss the interrupt
+
+Hesi10:
+ fstCall KfLowerIrql ; (cl) = NewIrql
+ stdRet _HalEndSystemInterrupt
+
+Hesi100:
+ mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
+ out PIC2_PORT0, al
+ mov al, PIC2_EOI ; specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+
+ fstCall KfLowerIrql ; (cl) = NewIrql
+ stdRet _HalEndSystemInterrupt
+
+stdENDP _HalEndSystemInterrupt
+
+;++
+;VOID
+;HalDisableSystemInterrupt(
+; IN CCHAR Vector,
+; IN KIRQL Irql
+; )
+;
+;
+;
+;Routine Description:
+;
+; Disables a system interrupt.
+;
+;Arguments:
+;
+; Vector - Supplies the vector of the interrupt to be disabled
+;
+; Irql - Supplies the interrupt level of the interrupt to be disabled
+;
+;Return Value:
+;
+; None.
+;
+;--
+
+cPublicProc _HalDisableSystemInterrupt ,2
+cPublicFpo 2,0
+
+;
+
+ movzx ecx, byte ptr [esp+4] ; (ecx) = Vector
+ and ecx, 0FH ; (ecx) = 8259 irq #
+ mov edx, 1
+ shl edx, cl ; (ebx) = bit in IMR to disable
+ cli
+ or PCR[PcIDR], edx
+
+;
+; save IDR in table for use by NCRAdjustDynamicClaims
+;
+ mov eax,PCR[PcNumber]
+ or _NCRProcessorIDR[eax*4],edx
+;
+ xor eax, eax
+;
+; Get the current interrupt mask register from the 8259
+;
+ in al, PIC2_PORT1
+ shl eax, 8
+ in al, PIC1_PORT1
+;
+; Mask off the interrupt to be disabled
+;
+ or eax, edx
+;
+; Write the new interrupt mask register back to the 8259
+;
+ out PIC1_PORT1, al
+ shr eax, 8
+ out PIC2_PORT1, al
+ PIC2DELAY
+
+ sti
+
+ stdCall _NCRAdjustDynamicClaims
+
+ stdRET _HalDisableSystemInterrupt
+
+stdENDP _HalDisableSystemInterrupt
+
+;++
+;
+;BOOLEAN
+;HalEnableSystemInterrupt(
+; IN ULONG Vector,
+; IN KIRQL Irql,
+; IN KINTERRUPT_MODE InterruptMode
+; )
+;
+;
+;Routine Description:
+;
+; Enables a system interrupt
+;
+;Arguments:
+;
+; Vector - Supplies the vector of the interrupt to be enabled
+;
+; Irql - Supplies the interrupt level of the interrupt to be enabled.
+;
+;Return Value:
+;
+; None.
+;
+;--
+
+cPublicProc _HalEnableSystemInterrupt ,3
+cPublicFpo 3,0
+
+ mov ecx, dword ptr [esp+4] ; (ecx) = Vector
+ and ecx, 0FH
+ mov eax, 1
+ shl eax, cl ; (ebx) = bit in IMR to enable
+ not eax
+
+ cli
+ and PCR[PcIDR], eax
+;
+; save IDR in table for use by NCRAdjustDynamicClaims
+;
+ mov edx,PCR[PcNumber]
+ and _NCRProcessorIDR[edx*4],eax
+;
+; Get the PIC masks for Irql 0
+;
+ mov eax, KiI8259MaskTable[0]
+ or eax, PCR[PcIDR]
+;
+; Write the new interrupt mask register back to the 8259
+;
+ SET_IRQ_MASK
+
+ sti
+
+ stdCall _NCRAdjustDynamicClaims
+
+ mov eax, 1 ; return TRUE
+ stdRET _HalEnableSystemInterrupt
+
+stdENDP _HalEnableSystemInterrupt
+
+
+_TEXT ENDS
+
+ END
diff --git a/private/ntos/nthals/halncr/i386/pcip.h b/private/ntos/nthals/halncr/i386/pcip.h
new file mode 100644
index 000000000..476bab1e4
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/pcip.h
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\pcip.h"
diff --git a/private/ntos/nthals/halncr/i386/xxbiosa.asm b/private/ntos/nthals/halncr/i386/xxbiosa.asm
new file mode 100644
index 000000000..bc0173a17
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/xxbiosa.asm
@@ -0,0 +1,5 @@
+;
+; Include code from halx86
+; This is a cpp style symbolic link
+
+include ..\halx86\i386\xxbiosa.asm
diff --git a/private/ntos/nthals/halncr/i386/xxbiosc.c b/private/ntos/nthals/halncr/i386/xxbiosc.c
new file mode 100644
index 000000000..60cf92748
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/xxbiosc.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\xxbiosc.c"
diff --git a/private/ntos/nthals/halncr/i386/xxdisp.c b/private/ntos/nthals/halncr/i386/xxdisp.c
new file mode 100644
index 000000000..d48977df0
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/xxdisp.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\xxdisp.c"
diff --git a/private/ntos/nthals/halncr/i386/xxflshbf.c b/private/ntos/nthals/halncr/i386/xxflshbf.c
new file mode 100644
index 000000000..b054121cf
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/xxflshbf.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\xxflshbf.c"
diff --git a/private/ntos/nthals/halncr/i386/xxhal.c b/private/ntos/nthals/halncr/i386/xxhal.c
new file mode 100644
index 000000000..198d08346
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/xxhal.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\xxhal.c"
diff --git a/private/ntos/nthals/halncr/i386/xxioacc.asm b/private/ntos/nthals/halncr/i386/xxioacc.asm
new file mode 100644
index 000000000..8445c3404
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/xxioacc.asm
@@ -0,0 +1,5 @@
+;
+; Include code from halx86
+; This is a cpp style symbolic link
+
+include ..\halx86\i386\xxioacc.asm
diff --git a/private/ntos/nthals/halncr/i386/xxkdsup.c b/private/ntos/nthals/halncr/i386/xxkdsup.c
new file mode 100644
index 000000000..6e569b5ac
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/xxkdsup.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\xxkdsup.c"
diff --git a/private/ntos/nthals/halncr/i386/xxmemory.c b/private/ntos/nthals/halncr/i386/xxmemory.c
new file mode 100644
index 000000000..920714540
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/xxmemory.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\xxmemory.c"
diff --git a/private/ntos/nthals/halncr/i386/xxstubs.c b/private/ntos/nthals/halncr/i386/xxstubs.c
new file mode 100644
index 000000000..8421fb30a
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/xxstubs.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\xxstubs.c"
diff --git a/private/ntos/nthals/halncr/i386/xxtime.c b/private/ntos/nthals/halncr/i386/xxtime.c
new file mode 100644
index 000000000..92abb2aeb
--- /dev/null
+++ b/private/ntos/nthals/halncr/i386/xxtime.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\xxtime.c"
diff --git a/private/ntos/nthals/halncr/makefile b/private/ntos/nthals/halncr/makefile
new file mode 100644
index 000000000..6ee4f43fa
--- /dev/null
+++ b/private/ntos/nthals/halncr/makefile
@@ -0,0 +1,6 @@
+#
+# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source
+# file to this component. This file merely indirects to the real make file
+# that is shared by all the components of NT OS/2
+#
+!INCLUDE $(NTMAKEENV)\makefile.def
diff --git a/private/ntos/nthals/halncr/makefile.inc b/private/ntos/nthals/halncr/makefile.inc
new file mode 100644
index 000000000..cb912aa51
--- /dev/null
+++ b/private/ntos/nthals/halncr/makefile.inc
@@ -0,0 +1,2 @@
+obj\i386\hal.def: hal.src
+ $(TARGET_CPP) /EP -Di386 $(C_DEFINES) hal.src > obj\i386\hal.def
diff --git a/private/ntos/nthals/halncr/sources b/private/ntos/nthals/halncr/sources
new file mode 100644
index 000000000..34be96362
--- /dev/null
+++ b/private/ntos/nthals/halncr/sources
@@ -0,0 +1,110 @@
+
+!IF 0
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ sources.
+
+Abstract:
+
+ This file specifies the target component being built and the list of
+ sources files needed to build that component. Also specifies optional
+ compiler switches and libraries that are unique for the component being
+ built.
+
+
+Author:
+
+ Steve Wood (stevewo) 12-Apr-1990
+
+NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl
+
+!ENDIF
+
+MAJORCOMP=ntos
+MINORCOMP=hal
+
+TARGETNAME=halncr
+TARGETPATH=\nt\public\sdk\lib
+
+HALTYPE=MCA
+
+!IF $(386)
+
+TARGETTYPE=HAL
+NT_UP=0
+
+!ELSE
+
+TARGETTYPE=DRIVER
+
+!ENDIF
+
+INCLUDES=..\..\inc;..\..\ke;..\..\io
+
+SOURCES=
+
+i386_SOURCES=hal.rc \
+ drivesup.c \
+ bushnd.c \
+ rangesup.c \
+ i386\ixbeep.asm \
+ i386\ixbusdat.c \
+ i386\ixdat.c \
+ i386\ixisabus.c \
+ i386\ixinfo.c \
+ i386\ixpcibus.c \
+ i386\ixpciint.c \
+ i386\ixpcibrd.c \
+ i386\ixsysbus.c \
+ i386\ixcmos.asm \
+ i386\ixenvirv.c \
+ i386\ixidle.asm \
+ i386\ixhwsup.c \
+ i386\ixkdcom.c \
+ i386\ixphwsup.c \
+ i386\ixprofil.asm \
+ i386\ixmcabus.c \
+ i386\ixmcasup.c \
+ i386\ixstall.asm \
+ i386\ixswint.asm \
+ i386\ixthunk.c \
+ i386\ixusage.c \
+ i386\xxbiosa.asm \
+ i386\xxbiosc.c \
+ i386\xxdisp.c \
+ i386\xxhal.c \
+ i386\xxkdsup.c \
+ i386\xxmemory.c \
+ i386\xxstubs.c \
+ i386\xxtime.c \
+ i386\ncrclock.asm \
+ i386\ncrdetct.c \
+ i386\ncrhwsup.c \
+ i386\ncrintr.asm \
+ i386\ncripi.asm \
+ i386\ncrirql.asm \
+ i386\ncrnmi.c \
+ i386\ncrlock.asm \
+ i386\ncrsyint.asm \
+ i386\ncrstart.asm \
+ i386\ncrstop.c \
+ i386\ncrmp.c \
+ i386\ncrcatlk.asm \
+ i386\ncrcat.c \
+ i386\ncrsus.c \
+ i386\ncrioacc.asm \
+ i386\ncrmcabs.c \
+ i386\ncrqic.c \
+ i386\ncrlarc.c
+
+
+DLLDEF=obj\*\hal.def
+
+!IF $(386)
+
+NTTARGETFILES=$(TARGETPATH)\i386\halncr.lib
+
+!ENDIF