summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halsp/i386
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nthals/halsp/i386')
-rw-r--r--private/ntos/nthals/halsp/i386/halnls.h5
-rw-r--r--private/ntos/nthals/halsp/i386/halp.h5
-rw-r--r--private/ntos/nthals/halsp/i386/ix8259.inc5
-rw-r--r--private/ntos/nthals/halsp/i386/ixbusdat.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixcmos.asm5
-rw-r--r--private/ntos/nthals/halsp/i386/ixcmos.inc5
-rw-r--r--private/ntos/nthals/halsp/i386/ixdat.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixenvirv.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixfirm.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixhwsup.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixidle.asm5
-rw-r--r--private/ntos/nthals/halsp/i386/ixinfo.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixisa.h5
-rw-r--r--private/ntos/nthals/halsp/i386/ixisabus.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixisasup.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixkdcom.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixkdcom.h5
-rw-r--r--private/ntos/nthals/halsp/i386/ixmca.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixmcaa.asm5
-rw-r--r--private/ntos/nthals/halsp/i386/ixnmi.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixpcibrd.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixpcibus.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixpciint.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixphwsup.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixreboot.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixstall.asm5
-rw-r--r--private/ntos/nthals/halsp/i386/ixsysbus.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixthunk.c5
-rw-r--r--private/ntos/nthals/halsp/i386/ixusage.c5
-rw-r--r--private/ntos/nthals/halsp/i386/pcip.h5
-rw-r--r--private/ntos/nthals/halsp/i386/spacer.c227
-rw-r--r--private/ntos/nthals/halsp/i386/spacer.h193
-rw-r--r--private/ntos/nthals/halsp/i386/spbeep.asm246
-rw-r--r--private/ntos/nthals/halsp/i386/spclock.asm1096
-rw-r--r--private/ntos/nthals/halsp/i386/spdetect.asm559
-rw-r--r--private/ntos/nthals/halsp/i386/spipi.asm750
-rw-r--r--private/ntos/nthals/halsp/i386/spirql.asm799
-rw-r--r--private/ntos/nthals/halsp/i386/spmp.inc258
-rw-r--r--private/ntos/nthals/halsp/i386/spprofil.asm453
-rw-r--r--private/ntos/nthals/halsp/i386/spreboot.asm151
-rw-r--r--private/ntos/nthals/halsp/i386/spspin.asm382
-rw-r--r--private/ntos/nthals/halsp/i386/spsproc.c501
-rw-r--r--private/ntos/nthals/halsp/i386/spsproca.asm373
-rw-r--r--private/ntos/nthals/halsp/i386/spswint.asm325
-rw-r--r--private/ntos/nthals/halsp/i386/spsysbus.c249
-rw-r--r--private/ntos/nthals/halsp/i386/spsysint.asm393
-rw-r--r--private/ntos/nthals/halsp/i386/xxbiosa.asm5
-rw-r--r--private/ntos/nthals/halsp/i386/xxbiosc.c5
-rw-r--r--private/ntos/nthals/halsp/i386/xxdisp.c5
-rw-r--r--private/ntos/nthals/halsp/i386/xxflshbf.c5
-rw-r--r--private/ntos/nthals/halsp/i386/xxhal.c5
-rw-r--r--private/ntos/nthals/halsp/i386/xxioacc.asm5
-rw-r--r--private/ntos/nthals/halsp/i386/xxkdsup.c5
-rw-r--r--private/ntos/nthals/halsp/i386/xxmemory.c5
-rw-r--r--private/ntos/nthals/halsp/i386/xxstubs.c5
-rw-r--r--private/ntos/nthals/halsp/i386/xxtime.c5
56 files changed, 7155 insertions, 0 deletions
diff --git a/private/ntos/nthals/halsp/i386/halnls.h b/private/ntos/nthals/halsp/i386/halnls.h
new file mode 100644
index 000000000..e829faba8
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/halp.h b/private/ntos/nthals/halsp/i386/halp.h
new file mode 100644
index 000000000..a9dbf1e13
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ix8259.inc b/private/ntos/nthals/halsp/i386/ix8259.inc
new file mode 100644
index 000000000..b9e0a196a
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixbusdat.c b/private/ntos/nthals/halsp/i386/ixbusdat.c
new file mode 100644
index 000000000..a42039752
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixcmos.asm b/private/ntos/nthals/halsp/i386/ixcmos.asm
new file mode 100644
index 000000000..7f4e7393e
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixcmos.inc b/private/ntos/nthals/halsp/i386/ixcmos.inc
new file mode 100644
index 000000000..2fe289fb0
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixdat.c b/private/ntos/nthals/halsp/i386/ixdat.c
new file mode 100644
index 000000000..f6b0e34de
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixenvirv.c b/private/ntos/nthals/halsp/i386/ixenvirv.c
new file mode 100644
index 000000000..e194820ba
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixfirm.c b/private/ntos/nthals/halsp/i386/ixfirm.c
new file mode 100644
index 000000000..f666e405c
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/ixfirm.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixfirm.c"
diff --git a/private/ntos/nthals/halsp/i386/ixhwsup.c b/private/ntos/nthals/halsp/i386/ixhwsup.c
new file mode 100644
index 000000000..ea91dc8d0
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixidle.asm b/private/ntos/nthals/halsp/i386/ixidle.asm
new file mode 100644
index 000000000..9bdd670f3
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixinfo.c b/private/ntos/nthals/halsp/i386/ixinfo.c
new file mode 100644
index 000000000..7f211f7a9
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixisa.h b/private/ntos/nthals/halsp/i386/ixisa.h
new file mode 100644
index 000000000..f67b35f49
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixisabus.c b/private/ntos/nthals/halsp/i386/ixisabus.c
new file mode 100644
index 000000000..c1edfb067
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixisasup.c b/private/ntos/nthals/halsp/i386/ixisasup.c
new file mode 100644
index 000000000..58c426544
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixkdcom.c b/private/ntos/nthals/halsp/i386/ixkdcom.c
new file mode 100644
index 000000000..29bb8308e
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixkdcom.h b/private/ntos/nthals/halsp/i386/ixkdcom.h
new file mode 100644
index 000000000..22f1aac09
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixmca.c b/private/ntos/nthals/halsp/i386/ixmca.c
new file mode 100644
index 000000000..378abfb24
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/ixmca.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixmca.c"
diff --git a/private/ntos/nthals/halsp/i386/ixmcaa.asm b/private/ntos/nthals/halsp/i386/ixmcaa.asm
new file mode 100644
index 000000000..d018edfc4
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/ixmcaa.asm
@@ -0,0 +1,5 @@
+;
+; Include code from halx86
+; This is a cpp style symbolic link
+
+include ..\halx86\i386\ixmcaa.asm
diff --git a/private/ntos/nthals/halsp/i386/ixnmi.c b/private/ntos/nthals/halsp/i386/ixnmi.c
new file mode 100644
index 000000000..2ab99a52b
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixpcibrd.c b/private/ntos/nthals/halsp/i386/ixpcibrd.c
new file mode 100644
index 000000000..02fd82821
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixpcibus.c b/private/ntos/nthals/halsp/i386/ixpcibus.c
new file mode 100644
index 000000000..640cebfba
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixpciint.c b/private/ntos/nthals/halsp/i386/ixpciint.c
new file mode 100644
index 000000000..5243acee5
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixphwsup.c b/private/ntos/nthals/halsp/i386/ixphwsup.c
new file mode 100644
index 000000000..a1cdab598
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixreboot.c b/private/ntos/nthals/halsp/i386/ixreboot.c
new file mode 100644
index 000000000..15d7bd898
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/ixreboot.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\ixreboot.c"
diff --git a/private/ntos/nthals/halsp/i386/ixstall.asm b/private/ntos/nthals/halsp/i386/ixstall.asm
new file mode 100644
index 000000000..115c6c9c1
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/ixstall.asm
@@ -0,0 +1,5 @@
+;
+; Include code from halx86
+; This is a cpp style symbolic link
+
+include ..\halx86\i386\ixstall.asm
diff --git a/private/ntos/nthals/halsp/i386/ixsysbus.c b/private/ntos/nthals/halsp/i386/ixsysbus.c
new file mode 100644
index 000000000..b4776da76
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixthunk.c b/private/ntos/nthals/halsp/i386/ixthunk.c
new file mode 100644
index 000000000..6f15aad73
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/ixusage.c b/private/ntos/nthals/halsp/i386/ixusage.c
new file mode 100644
index 000000000..519ec31f3
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/pcip.h b/private/ntos/nthals/halsp/i386/pcip.h
new file mode 100644
index 000000000..476bab1e4
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/spacer.c b/private/ntos/nthals/halsp/i386/spacer.c
new file mode 100644
index 000000000..4d74bb4c2
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spacer.c
@@ -0,0 +1,227 @@
+/*++
+
+Copyright (c) 1993 ACER America Corporation
+
+Module Name:
+
+ acer.c
+
+Abstract:
+
+ ACER Write-back Secondary Cache Control c code.
+
+ This module implements the code which detects and enables the
+ secondary write-back cache on ACER products (ICL also).
+
+Environment:
+
+ Kernel mode only.
+
+--*/
+
+#include "halp.h"
+#include "spacer.h" // i/o addresses & bit definitions
+
+
+ULONG HalpGetCmosData (
+ IN ULONG BusNumber,
+ IN ULONG SlotNumber,
+ IN PVOID Buffer,
+ IN ULONG Length
+ );
+
+
+VOID HalpAcerInitializeCache ( VOID ); // externally used
+BOOLEAN has_write_back_cache( VOID ); // local only
+
+
+// ************************ routines ****************************
+
+BOOLEAN has_write_back_cache( VOID )
+/*++
+
+Routine Description:
+
+ This routine checks to see if this machine supports a secondary
+ write-back cache.
+
+ This routine checks if the machine is an ACER, ALTOS, or ICL product.
+
+ eisa id: acr32xx - acer product
+ eisa id: acs32xx - altos product
+ eisa id: icl00xx - icl product
+
+ The only thing that tells us whether or not the CPU has a secondary
+ write-back cache is the least significant byte of the EISA id.
+
+ xx = 61h for cpu0 indicates the presence of a write-back cache
+
+
+Arguments:
+
+ None
+
+Return Value:
+
+ TRUE machine supports a secondary write-back cache.
+ FALSE machine is not known to support a write-back cache.
+
+--*/
+
+{
+ UCHAR id0, id1, id2, id3;
+
+ // grab cpu0's eisa id information
+ id0 = READ_PORT_UCHAR( (PUCHAR) ACER_CPU0_EISA_ID0 );
+ id1 = READ_PORT_UCHAR( (PUCHAR) ACER_CPU0_EISA_ID1 );
+ id2 = READ_PORT_UCHAR( (PUCHAR) ACER_CPU0_EISA_ID2 );
+
+
+ // are we a acer or altos machine?
+ if ( (id0 == (UCHAR) ACER_ID0 &&
+ id1 == (UCHAR) ACER_ID1 &&
+ id2 == (UCHAR) ACER_ID2 ) ||
+ (id0 == (UCHAR) ALTOS_ID0 &&
+ id1 == (UCHAR) ALTOS_ID1 &&
+ id2 == (UCHAR) ALTOS_ID2 ) ) {
+
+ // check the lsw id cpu to see if it has a write back cache
+ // All acer/altos/icl machines can only have 1 cpu type, so if the
+ // first cpu supports a write-back cache then all of them do.
+ id3 = READ_PORT_UCHAR( (PUCHAR) ACER_CPU0_EISA_ID3 );
+
+ if ( id3 == (UCHAR) ACER_EISA_ID_WB_CPU0 )
+ return TRUE; // gotcha
+
+ }
+
+
+ // are we an icl mx machine?
+ if ( (id0 == (UCHAR) ICL_ID0 &&
+ id1 == (UCHAR) ICL_ID1 &&
+ id2 == (UCHAR) ICL_ID2 ) ) {
+
+ // check the lsw id cpu to see if it has a write back cache
+ // All acer/altos/icl machines can only have 1 cpu type, so if the
+ // first cpu supports a write-back cache then all of them do.
+ id3 = READ_PORT_UCHAR( (PUCHAR) ACER_CPU0_EISA_ID3 );
+
+ if ( id3 == (UCHAR) ICL_EISA_ID_WB_CPU0 )
+ return TRUE; // gotcha
+
+ }
+
+ return FALSE; // when in doubt be safe
+}
+
+
+VOID
+HalpAcerInitializeCache (
+ VOID
+ )
+/*++
+
+Routine Description:
+
+ This routine enables the write-back cache available on certain
+ ACER product. If the write-back cache is supported then it enables
+ it.
+
+ NOTE: 1) This routine assumes that the caller has provided any required
+ synchronization to query the realtime clock information. Or that
+ the HAL code which is calling this routine has serialized access.
+ 2) For CSR bit definitions see the acer.h file
+
+
+ You cannot call dbgprint to talk to the debugger since the port is not
+ initialized yet.
+
+Arguments:
+
+ None
+
+Return Value:
+
+ None.
+
+SideEffects:
+
+ NMI mask is enabled.
+
+--*/
+
+{
+
+ UCHAR shadow_ram_setup; // tmp var for current shadow stat
+ UCHAR high_ram_setup; // tmp var for current ram setup
+
+
+ // say hello to the outside world
+ //HalDisplayString(ACER_HAL_VERSION_NUMBER);
+ //HalDisplayString("Acer HAL: Searching for secondary write-back cache\n");
+
+
+ // check to see if this particular ACER model even has a
+ // write-back cache
+ if ( !has_write_back_cache() ) {
+ //HalDisplayString("Acer HAL: No write-back cache found\n");
+ return;
+ }
+
+
+ // retrieve BIOS setup shadow ram status
+ // read in byte, mask off bit 0 - 1-RAM BIOS 0-ROM BIOS
+ HalpGetCmosData((ULONG) 0, (ULONG) ACER_SHADOW_IDX,
+ (PVOID) &shadow_ram_setup, (ULONG) 1 );
+
+
+ // Set up shadow_ram_setup:
+ // bit 0 - 1-BIOS Shadow 0=No Shadowing
+
+ shadow_ram_setup &= RAM_ROM_MASK;
+
+ if ( shadow_ram_setup == 0 ) {
+ //HalDisplayString("Acer HAL: NO BIOS RAM Shadowing\n");
+ } else {
+ //HalDisplayString("Acer HAL: BIOS RAM Shadowing\n");
+ }
+
+ // retrieve BIOS setup 15MB-16MB ram status
+ // mask off bit 1 -
+ // 1-(15MB-16MB) RAM 0-(15MB-16MB) EISA
+
+ HalpGetCmosData((ULONG) 0, (ULONG) ACER_15M_16M_IDX,
+ (PVOID) &high_ram_setup, (ULONG) 1 );
+
+
+ // 15MB-16MB memory setup (high_ram_setup):
+ // bit 5 1=EISA 0=System RAM
+ // note: the polarity is opposite from what getcmosdata read
+
+ high_ram_setup &= DRAM_EISA_MASK; // just grab bit 1
+ high_ram_setup ^= DRAM_EISA_MASK; // invert polarity
+ high_ram_setup <<= 4; // place at bit<4>
+
+ if ( high_ram_setup == 0) {
+ //HalDisplayString("Acer HAL: 15Mb to 16Mb Allocated to System RAM\n");
+ } else {
+ //HalDisplayString("Acer HAL: 15Mb to 16Mb Allocated to I/O Space\n");
+ }
+
+ // Enable write-back secondary cache on cpus 0 & 1
+ // by setting bit<2>
+ WRITE_PORT_UCHAR( (PUCHAR) ACER_PORT_CPU01,
+ (UCHAR) (WRITE_BALLOC_ON | shadow_ram_setup | high_ram_setup));
+
+
+ // always set write-back secondary cache on cpus 2 & 3
+ // even if system does not have cpus 2 & 3
+ WRITE_PORT_UCHAR( (PUCHAR) ACER_PORT_CPU23,
+ (UCHAR) (WRITE_BALLOC_ON | shadow_ram_setup | high_ram_setup));
+
+ // flush the last pending i/o write by reading a safe io location
+ READ_PORT_UCHAR( (PUCHAR) EISA_FLUSH_ADDR );
+
+ // that's all folks
+ //HalDisplayString("Acer HAL: Write-back cache enabled!\n");
+}
diff --git a/private/ntos/nthals/halsp/i386/spacer.h b/private/ntos/nthals/halsp/i386/spacer.h
new file mode 100644
index 000000000..c1cc4ac22
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spacer.h
@@ -0,0 +1,193 @@
+/*++ BUILD Version: 0001 // Increment this if a change has global effects
+
+Copyright (c) 1993 ACER America Corporation
+
+Module Name:
+
+ acer.h
+
+Abstract:
+
+ This header file defines the unique interfaces, defines and structures
+ for the ACER product line
+
+Revision History:
+ 1.0b - plm initial release
+ 1.1b - acer.c: halpacereisa: handle scrabled eisa data gracefully.
+
+--*/
+
+#define ACER_HAL_VERSION_NUMBER "Acer HAL Version 1.1b for October Windows NT Beta.\n"
+
+
+/* ACER Special I/O Port defintions
+ * I/O Port Address 0xcc4h
+ * |
+ * 0: cpu0 & cpu1
+ * c: cpu2 & cpu3
+ *
+ * bits < 7 6 5 4 3 2 1 0 > (WRITE-ONLY)
+ * 0 0 | 0 0 | 0 |
+ * | | BIOS Shadow Control
+ * | | 0: ROM BIOS
+ * | | 1: RAM BIOS
+ * | |
+ * | |
+ * | Write-Back Cache Control
+ * | 0: write-thru ( write-back disabled)
+ * | 1: write-back enabled
+ * |
+ * 15Mb to 16Mb Memory Setup
+ * 0: Ram
+ * 1: EISA
+ *
+ */
+
+
+// where do i find the CSR which controls the write-back enabling?
+#define ACER_PORT_CPU01 0xcc4 // write only - setup reg. cpu 0,1
+#define ACER_PORT_CPU23 0xccc4 // write onlY - setup reg. cpu 2,3
+
+#define WRITE_BALLOC_ON 0x04 // bit<2> - enable write-back cache bit
+#define WRITE_BALLOC_OFF 0x00 // bit<2> - disable write-back cache bit
+
+/* ACER RT/CMOS contents
+ *
+ * index 35h bit<1>: 15Mb to 16Mb Memory Setup
+ * 0: EISA
+ * 1: Ram
+ * all other bits RESERVED
+ *
+ * index 39h bit<0>: BIOS Shadow Control
+ * 0: ROM BIOS
+ * 1: RAM BIOS
+ * all other bits RESERVED
+ *
+ */
+
+// RT/CMOS indexes where special Acer machine config info is kept
+// where is the information kept that tells me if bios shadowing is eabled?
+#define ACER_SHADOW_IDX 0x39 // RT/CMOS index for shadow bios control
+
+#define RAM_ROM_MASK 0x01 // bit<0>, 0:RAM BIOS 1:ROM BIOS
+
+// where is the information kept that tells me if 15M-16M is EISA or RAM?
+#define ACER_15M_16M_IDX 0x35 // RT/CMOS index for 15Mb-16Mb mem cntrl
+
+#define DRAM_EISA_MASK 0x02 // bit<1>, 0:EISA 1:RAM
+
+// EISA ID base addresses for cpu0
+#define ACER_CPU0_EISA_ID0 0x0c80 /* 1 digit + part of digit 2 */
+#define ACER_CPU0_EISA_ID1 0x0c81 /* rest of digit 2 + digit 3 */
+#define ACER_CPU0_EISA_ID2 0x0c82 /* msw id */
+#define ACER_CPU0_EISA_ID3 0x0c83 /* msw id */
+
+// ACER EISA ID's
+#define ACER_ID0 0x04 /* acr32xx */
+#define ACER_ID1 0x72
+#define ACER_ID2 0x32
+
+// ALTOS EISA ID's
+#define ALTOS_ID0 0x04 /* acs32xx */
+#define ALTOS_ID1 0x73
+#define ALTOS_ID2 0x32
+
+// ICL EISA ID's
+#define ICL_ID0 0x24 /* icl00xx */
+#define ICL_ID1 0x6c
+#define ICL_ID2 0x00
+
+
+// EISA IDs of ACER/ALTOS machines which support a write-back secondary cache
+#define ACER_EISA_ID_WB_CPU0 0x61
+
+// EISA IDs of ICL machine (acer oem) which supports write-back scndry cache
+// NOTE: THESE IDS ARE STILL TBD!!!
+#define ICL_EISA_ID_WB_CPU0 0x61
+
+// EISA constants
+#define MAX_IRQS_PER_EISABUS 16 // how many irq to search for
+#define MAX_EISA_SLOTS 16 // number of eisa slots
+
+// magic number for kefindconfigurationentry
+//#define EISA_DATA_OFFSET 24 // offset to data portion of eisa pointer
+
+// cpu0's i/o address space for cpu1's pic's
+//
+// NOTE: These defines MUST MATCH EXACTLY the equ's found in spirql.asm
+//
+#define CPU1_PIC1_PORT0 0xc024
+#define CPU1_PIC1_PORT1 0xc0a4
+#define CPU1_PIC2_PORT0 0xc025
+#define CPU1_PIC2_PORT1 0xc0a5
+
+#define CPU0_PIC1_PORT0 0x020
+#define CPU0_PIC1_PORT1 0x0a0
+
+// cpu0's eisa level/edge register
+#define EISA_LEVEL_EDGE_PIC1 0x04d0
+#define EISA_LEVEL_EDGE_PIC2 0x04d1
+
+#define SET_TO_EDGE ((UCHAR) 0x0000)
+#define SET_TO_LEVEL ((UCHAR) -1)
+
+// eisa level/edge register bit which MUST BE edges
+#define EISA_LEVEL_EDGE_PIC1_INIT 0xb8
+#define EISA_LEVEL_EDGE_PIC2_INIT 0xde
+
+// eisa 8259
+#define READ_IRR 0x0a
+#define READ_ISR 0x0b
+
+// a safe eisa i/o location that can be read to force any caches
+// to flush any pending i/o writes. This just happens to be
+// the eisa manufacturer i.d. location
+#define EISA_FLUSH_ADDR 0x0c80
+
+// This define MUST EXACTLY MATCH asm equ located in file spmp.inc
+#define SMP_ACER 3
+
+#define MAX_ACER_CPUS 4 // maximum number of cpus a acer can hold
+
+//
+// acer_irq_distribution callback data structure
+//
+typedef struct _ACER_IRQ_DISTRIBUTION {
+
+ BOOLEAN distribte_irqs; // shall i try to distribute irqs across cpus
+
+ // cpu x pics can handle level irqs?
+ BOOLEAN px_set_to_level_irqs[ MAX_ACER_CPUS ];
+
+ // number of irqs which have been assigned, used for load balancing
+ SHORT px_numb_irqs_assigned[ MAX_ACER_CPUS ];
+
+ // only a certain number of irqs per pic pair can handle level triggerring
+ BOOLEAN eisa_level_compatable[ MAX_IRQS_PER_EISABUS ];
+
+} ACER_IRQ_DISTRIBUTION, *PACER_IRQ_DISTRIBUTION;
+
+// default number of irq's assinged
+#define ACER_IRQS_ASSIGED_CPU0 1 // stay away from 0 for init case
+#define ACER_IRQS_ASSIGED_CPU1 0
+#define ACER_IRQS_ASSIGED_CPU2 0
+#define ACER_IRQS_ASSIGED_CPU3 0
+
+
+// what irqs can be level distriubted?
+#define ACER_DISTRIBUTE_LEVEL_IRQ0 FALSE
+#define ACER_DISTRIBUTE_LEVEL_IRQ1 FALSE
+#define ACER_DISTRIBUTE_LEVEL_IRQ2 FALSE
+#define ACER_DISTRIBUTE_LEVEL_IRQ3 TRUE
+#define ACER_DISTRIBUTE_LEVEL_IRQ4 TRUE
+#define ACER_DISTRIBUTE_LEVEL_IRQ5 TRUE
+#define ACER_DISTRIBUTE_LEVEL_IRQ6 FALSE
+#define ACER_DISTRIBUTE_LEVEL_IRQ7 TRUE
+#define ACER_DISTRIBUTE_LEVEL_IRQ8 FALSE
+#define ACER_DISTRIBUTE_LEVEL_IRQ9 TRUE
+#define ACER_DISTRIBUTE_LEVEL_IRQ10 TRUE
+#define ACER_DISTRIBUTE_LEVEL_IRQ11 TRUE
+#define ACER_DISTRIBUTE_LEVEL_IRQ12 TRUE
+#define ACER_DISTRIBUTE_LEVEL_IRQ13 FALSE
+#define ACER_DISTRIBUTE_LEVEL_IRQ14 TRUE
+#define ACER_DISTRIBUTE_LEVEL_IRQ15 TRUE
diff --git a/private/ntos/nthals/halsp/i386/spbeep.asm b/private/ntos/nthals/halsp/i386/spbeep.asm
new file mode 100644
index 000000000..fcde8b5d8
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spbeep.asm
@@ -0,0 +1,246 @@
+ title "Hal Beep"
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; spbeep.asm
+;
+;Abstract:
+;
+; HAL routine to make noise. It needs to synchronize its access to the
+; 8254, since we also use the 8254 for the profiling interrupt.
+;
+;
+;Author:
+;
+; John Vert (jvert) 31-Jul-1991
+;
+;Revision History:
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+include mac386.inc
+include i386\spmp.inc
+
+ .list
+
+ extrn _Halp8254Lock:DWORD
+ extrn _SpType:BYTE
+
+;
+; Defines used to program the i8254 for the speaker.
+;
+
+I8254_TIMER_CONTROL_PORT EQU 43h
+I8254_TIMER_DATA_PORT EQU 42h
+I8254_TIMER_CLOCK_IN EQU 1193167
+I8254_TIMER_TONE_MAX EQU 65536
+I8254_TIMER_CONTROL_SELECT EQU 0B6h
+SPEAKER_CONTROL_PORT EQU 61h
+SPEAKER_OFF_MASK EQU 0FCh
+SPEAKER_ON_MASK EQU 03h
+
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "HalMakeBeep"
+;++
+;
+; BOOLEAN
+; HalMakeBeep(
+; IN ULONG Frequency
+; )
+;
+; Routine Description:
+;
+; This function sets the frequency of the speaker, causing it to sound a
+; tone. The tone will sound until the speaker is explicitly turned off,
+; so the driver is responsible for controlling the duration of the tone.
+;
+;Arguments:
+;
+; Frequency - Supplies the frequency of the desired tone. A frequency of
+; 0 means the speaker should be shut off.
+;
+;Return Value:
+;
+; TRUE - Operation was successful (frequency within range or zero)
+; FALSE - Operation was unsuccessful (frequency was out of range)
+; Current tone (if any) is unchanged.
+;
+;--
+
+Frequency equ [ebp + 8]
+
+cPublicProc _HalMakeBeep, 1
+
+ push ebp ; save ebp
+ mov ebp, esp ;
+ push ebx ; save ebx
+
+Hmb10Sp:pushfd ; save flags
+ cli ; disable interrupts
+
+ lea eax, _Halp8254Lock
+ ACQUIRE_SPINLOCK eax,Hmb99Sp
+
+ cmp _SpType, SMP_SYSPRO2 ; On SysPro2 do it differently
+ je HalMakeBeepSmp
+
+ ;
+ ; Stop the speaker.
+ ;
+
+ in al, SPEAKER_CONTROL_PORT
+ jmp $+2
+ and al, SPEAKER_OFF_MASK
+ out SPEAKER_CONTROL_PORT, al
+ jmp $+2
+
+ ;
+ ; Calculate Tone: Tone = 1.193MHz / Frequency.
+ ; N.B. Tone must fit in 16 bits.
+ ;
+
+ mov ecx, DWORD PTR [Frequency] ; ecx <- frequency
+ or ecx, ecx ; (ecx) == 0?
+ je SHORT Hmb30Sp ; goto Hmb30Sp
+
+ mov eax, I8254_TIMER_CLOCK_IN ; eax <- 1.193MHz, the clockin
+ ; for the speaker tone
+ sub edx, edx ; edx <- zero
+ div ecx ; eax <- 1.193MHz / frequency
+ cmp eax, I8254_TIMER_TONE_MAX ; (eax) < 2**16?
+ jb SHORT Hmb20Sp ; goto Hmb20Sp
+
+ ;
+ ; Invalid frequency. Return FALSE.
+ ;
+
+ sub al, al
+ jmp SHORT Hmb40Sp
+Hmb20Sp:
+ ;
+ ; Program the 8254 with the calculated tone.
+ ;
+
+ push eax ; save Tone
+ mov al, I8254_TIMER_CONTROL_SELECT
+ out I8254_TIMER_CONTROL_PORT, al ; select timer control register
+ jmp $+2
+
+ pop eax ; restore Tone
+ out I8254_TIMER_DATA_PORT, al ; program 8254 with Tone lsb
+ jmp $+2
+ mov al, ah
+ out I8254_TIMER_DATA_PORT, al ; program 8254 with Tone msb
+ jmp $+2
+
+ ;
+ ; Turn the speaker on.
+ ;
+
+ in al, SPEAKER_CONTROL_PORT
+ jmp $+2
+ or al, SPEAKER_ON_MASK
+ out SPEAKER_CONTROL_PORT, al
+ jmp $+2
+
+Hmb30Sp:
+ ;
+ ; Return TRUE.
+ ;
+
+ mov al, 1
+
+Hmb40Sp:
+ lea ebx, _Halp8254Lock
+ RELEASE_SPINLOCK ebx
+
+ popfd
+ pop ebx ; restore ebx
+ pop ebp ; restore ebp
+ stdRET _HalMakeBeep
+
+Hmb99Sp:popfd
+ SPIN_ON_SPINLOCK eax,<Hmb10Sp>
+
+
+HalMakeBeepSmp:
+; A BELIZE/PHOENIX machine MUST always enable and disable the beep via
+; CPU 0 regardless of the originating CPU. This is done through indexed
+; IO.
+;
+; Note the indexed IO is serialized with the 8254 spinlock
+
+
+ ;
+ ; Stop the speaker.
+ ;
+
+ INDEXED_IO_READ 0,SPEAKER_CONTROL_PORT
+ and al, SPEAKER_OFF_MASK
+
+ INDEXED_IO_WRITE 0,SPEAKER_CONTROL_PORT,al
+
+ ;
+ ; Calculate Tone: Tone = 1.193MHz / Frequency.
+ ; N.B. Tone must fit in 16 bits.
+ ;
+
+ mov ecx, DWORD PTR [Frequency] ; ecx <- frequency
+ or ecx, ecx ; (ecx) == 0?
+ je Hmb30Sp ; goto Hmb30
+
+ mov eax, I8254_TIMER_CLOCK_IN ; eax <- 1.193MHz, the clockin
+ ; for the speaker tone
+ sub edx, edx ; edx <- zero
+ div ecx ; eax <- 1.193MHz / frequency
+ cmp eax, I8254_TIMER_TONE_MAX ; (eax) < 2**16?
+ jb SHORT Hmb20 ; goto Hmb20
+
+ ;
+ ; Invalid frequency. Return FALSE.
+ ;
+
+ sub al, al
+ jmp Hmb40Sp
+Hmb20:
+ ;
+ ; Program the 8254 with the calculated tone.
+ ;
+
+ push eax ; save Tone
+ mov al, I8254_TIMER_CONTROL_SELECT
+
+ INDEXED_IO_WRITE 0,I8254_TIMER_CONTROL_PORT,al
+
+ pop eax ; restore Tone
+
+ INDEXED_IO_WRITE 0,I8254_TIMER_DATA_PORT,al
+ mov al, ah
+
+ INDEXED_IO_WRITE 0,I8254_TIMER_DATA_PORT,al
+
+ ;
+ ; Turn the speaker on.
+ ;
+
+ INDEXED_IO_READ 0,SPEAKER_CONTROL_PORT
+ or al, SPEAKER_ON_MASK
+
+ INDEXED_IO_WRITE 0,SPEAKER_CONTROL_PORT,al
+ jmp Hmb30Sp
+
+stdENDP _HalMakeBeep
+_TEXT ends
+ end
diff --git a/private/ntos/nthals/halsp/i386/spclock.asm b/private/ntos/nthals/halsp/i386/spclock.asm
new file mode 100644
index 000000000..9b0f38c7a
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spclock.asm
@@ -0,0 +1,1096 @@
+ title "Interval Clock Interrupt"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; spclock.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 callconv.inc
+include hal386.inc
+include i386\ix8259.inc
+include i386\ixcmos.inc
+include i386\kimacro.inc
+include mac386.inc
+include i386\spmp.inc
+ .list
+
+ EXTRNP _DbgBreakPoint,0,IMPORT
+ extrn KiI8259MaskTable:DWORD
+ EXTRNP _KeUpdateSystemTime,0
+ EXTRNP _KeUpdateRunTime,1,IMPORT
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _HalEndSystemInterrupt,2
+ EXTRNP _HalBeginSystemInterrupt,3
+ EXTRNP _HalRequestIpi,1
+ EXTRNP _HalpAcquireCmosSpinLock ,0
+ EXTRNP _HalpReleaseCmosSpinLock ,0
+ EXTRNP _KeStallExecutionProcessor, 1
+ extrn _HalpProcessorPCR:DWORD
+ extrn _HalpSystemHardwareLock:DWORD
+ extrn _HalpFindFirstSetRight:BYTE
+ extrn _Sp8259PerProcessorMode:BYTE
+ EXTRNP _KeSetTimeIncrement,2,IMPORT
+ EXTRNP _HalpMcaQueueDpc, 0
+ extrn _SpType:BYTE
+
+;
+; 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 1193182
+
+;
+; ==== 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_10MS EQU 11949
+TIME_INCREMENT_10MS EQU 100144
+
+;
+; Value for KeQueryPerf retries.
+;
+
+MAX_PERF_RETRY equ 3 ; Odly enough 3 is plenty.
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+;
+; The following array stores the per microsecond loop count for each
+; central processor.
+;
+
+ 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
+HalpPerfP0Value dd 0
+HalpCalibrateFlag db 0
+ db 0
+ dw 0
+
+HalpRollOverCount dd 0
+
+ public _HalpClockWork, _HalpClockSetMSRate, _HalpClockMcaQueueDpc
+_HalpClockWork label dword
+ _HalpClockSetMSRate db 0
+ _HalpClockMcaQueueDpc db 0
+ _bReserved1 db 0
+ _bReserved2 db 0
+
+;
+; Storage for variable to ensure that queries are always
+; greater than the last.
+;
+
+HalpLastQueryLowValue dd 0
+HalpLastQueryHighValue dd 0
+HalpForceDataLock dd 0
+
+; endmod
+
+_DATA ends
+
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME 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
+
+;
+; Use 15ms or 10ms clock tick?
+;
+
+ mov edx, TIME_INCREMENT_10MS ; yes, use 10ms clock
+ mov ecx, ROLLOVER_COUNT_10MS
+;
+; Fill in PCR value with TIME_INCREMENT
+; (edx) = TIME_INCREMENT
+; (ecx) = ROLLOVER_COUNT
+;
+ cmp byte ptr PCR[PcHal.PcrNumber], 0
+ jne short icl_10
+
+ push ecx
+ stdCall _KeSetTimeIncrement, <edx, edx>
+ pop ecx
+
+ pushfd ; save caller's eflag
+ cli ; make sure interrupts are disabled
+
+;
+; Set clock rate
+; (ecx) = RollOverCount
+;
+
+ 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 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
+ mov HalpRollOverCount, ecx ; Set RollOverCount & initialized
+ stdRET _HalpInitializeClock
+
+
+icl_10:
+ pushfd ; save caller's eflag
+ cli ; make sure interrupts are disabled
+;
+; initialize clock, non-p0
+; (ecx) = ROLLOVER_COUNT
+;
+
+ 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 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
+ stdRET _HalpInitializeClock
+
+stdENDP _HalpInitializeClock
+
+;++
+;
+; VOID
+; HalCalibratePerformanceCounter (
+; IN volatile PLONG Number
+; )
+;
+; /*++
+;
+; Routine Description:
+;
+; This routine calibrates the performance counter value for a
+; multiprocessor system. The calibration can be done by zeroing
+; the current performance counter, or by calculating a per-processor
+; skewing between each processors counter.
+;
+; 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
+
+ test _Sp8259PerProcessorMode, SP_SMPCLOCK
+ jz short cal_exit ; 8254 per processor?
+
+ xor ecx, ecx
+ 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
+ in al, TIMER1_DATA_PORT0 ; Read PIT Ctr 0, MSByte.
+ mov ch, al ; (CX) = PIT Ctr 0 count.
+
+ cmp byte ptr PCR[PcHal.PcrNumber], 0 ; is this the processor
+ jz short cal_p0 ; which updates HalpPerfCounter?
+
+@@: cmp HalpCalibrateFlag, 0 ; wait for P0 to post it's counter
+ jz short @b
+
+ sub ecx, HalpPerfP0Value ; compute difference
+ neg ecx
+ mov PCR[PcHal.PcrPerfSkew], ecx
+
+cal_exit:
+ popfd
+ stdRET _HalCalibratePerformanceCounter
+
+cal_p0: mov HalpPerfP0Value, ecx ; post our timer value
+ mov HalpCalibrateFlag, 1 ; signal we are done
+ jmp short cal_exit
+
+stdENDP _HalCalibratePerformanceCounter
+
+ 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+20] ; User supplied Performance Frequence
+RetryPerfCount EQU [esp] ; Local retry variable
+
+
+cPublicProc _KeQueryPerformanceCounter ,1
+
+ push ebx
+ push esi
+ push edi
+ push 0 ; make space for RetryPerfCount
+
+;
+; 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 HalpRollOverCount, 0
+ jne short Kqpc11 ; ok, perf counter has been initialized
+
+;
+; Initialization hasn't occured yet, so just return zeroes.
+;
+ mov eax, 0
+ mov edx, 0
+ jmp Kqpc50
+
+Kqpc11: pushfd
+ cli
+
+Kqpc20:
+ 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 short @b
+
+
+;
+; Fetch the current counter value from the hardware
+;
+
+;
+; Background: Belize style systems have an 8254 per Processor.
+;
+; In short the original implementation kinda assumes that each
+; timer on each processor will be in perfect sycnh with each other.
+; This is a bad assumption, and the reason why we have attempted
+; to use only the timer on P0.
+;
+; There is an existing window where the return value may not be accurate.
+; The window will occur when multiple queries are made back to back
+; in an MP environment, and there are a lot of IPIs going on. Intuitive,
+; right. The problem is that this routine may return a value with the
+; the hardware system timer on P0 that has already generated an interrupt
+; and reset its rollover, but the software has yet to process the interrupt
+; to update the performance counter value. When this occurs, the second
+; querry will seem to have a lower value than the first.
+;
+; So, why don't I just fix it. Well the cause of the problem is the
+; overhead associated with handling the interrupt, and the fact that
+; the IPI has a higher IRQL. In addition, a busy system could be
+; issueing multiple IPIs back to back, which could extend this window
+; even further.
+;
+; I have managed to close the window most of the way for most normal
+; conditions. It takes several minutes on a busy system, with
+; multiple applications running with back to back queries to get
+; an invalid value. It can happen though.
+;
+; A retry implementation has been instrumented on top off the
+; Indexed IO implementation to finally close the window.
+; It seems to work OK.
+;
+; In reality, I think the fix is sufficient. The performance counter
+; is not designed propperly (via only software) to yield very accurate
+; values on sub timer tic (10-15msec) ranges on multiprocessor systems.
+;
+; Problems with this design:
+;
+; On an idle system threads executing from P0 will always
+; use less overhead than threads executing on P1.
+; On a ProLiant 2000 with 2 P5-66s the difference in 2
+; consecutive KeQueryPerformanceCounter calls from P0
+; is about 14, while from P1 is about 22. Unfortunately
+; on a busy system P0 performs about the same, but P1
+; is much slower due to the overhead involved in performing
+; an Indexed_IO. This means the busyier your system gets
+; the less accurate your performance values will become.
+;
+; The solution:
+;
+; A system wide hardware timer needs to be used. This is about the
+; only way to get accurate performance numbers from multiple
+; processors without causing unnecessary software overhead.
+;
+; Supposedly there is a 48 bit counter that we may be able to use
+; with SystemPro XL, and ProLiant systems, unfortunately it does
+; not appear that any OS is currently using this feature, so
+; its dependability may be suspect.
+;
+; JSL
+;
+
+;
+; Essentially all we are doing is always using the timer value on P0.
+; The indexed_io is a mechanism for one processor to access IOSPACE
+; on another processor's IOSPACE. I suspect this will have a greater
+; impact on performance than just reading the timer locally.
+; By using the indexed_io you are gauranteed of going out on the bus.
+;
+; But, hey if the user understands anything about performance, they
+; know that there will be some amount of overhead each time you make
+; this KeQueryPerformanceCounter call.
+;
+
+;
+; Increment the Retry counter now for convenience
+;
+
+ inc dword ptr RetryPerfCount+4
+
+;
+; This is Belize specific.
+;
+
+ cmp _SpType, SMP_SYSPRO2
+ jne timer_p0
+
+
+ ;
+ ; Only use Indexed_IO on a nonP0 processor
+ ;
+
+ cmp byte ptr PCR[PcHal.PcrNumber], 0 ; is this the processor
+ je timer_p0 ; which updates HalpPerfCounter?
+
+ ;
+ ; So read the timer of P0.
+ ;
+
+ push ebx
+ mov bl, 0
+ mov al, COMMAND_8254_LATCH_READ+COMMAND_8254_COUNTER0
+ ; Latch PIT Ctr 0 command.
+ INDEXED_IO_WRITE bl,TIMER1_CONTROL_PORT0,al
+ IODelay
+ INDEXED_IO_READ bl,TIMER1_DATA_PORT0 ; Read PIT Ctr 0, LSByte.
+ movzx ecx, al
+ INDEXED_IO_READ bl,TIMER1_DATA_PORT0 ; Read PIT Ctr 0, MSByte.
+ IODelay
+ mov ch,al ; (CX) = PIT Ctr 0 count.
+ pop ebx
+
+ lea eax, _Halp8254Lock
+ RELEASE_SPINLOCK eax
+ jmp short TimerValDone
+
+timer_p0:
+
+
+ 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
+
+
+
+TimerValDone:
+
+ mov al, PCR[PcHal.PcrNumber] ; get current processor #
+
+;
+; This is Belize specific.
+;
+
+ cmp _SpType, SMP_SYSPRO2
+ je NoCPU0Update
+
+;
+; If not on P0 then make sure P0 isn't in the process of
+; of updating its timer. Do this by checking the status
+; of the PIC using indexed_io.
+; Make sure that only one thread at time reads P0 PIC.
+;
+
+ cmp al, 0 ; Are we p0
+ je NoCPU0Update
+
+;
+; Check IRQL at PO before going any further
+;
+
+ push edx
+ mov edx, _HalpProcessorPCR[0] ; PCR of processor 0
+ cmp byte ptr ds:[edx].PcIrql,CLOCK2_LEVEL
+ pop edx
+ jb short NoCPU0Update
+ push ebx
+
+Kqpc11p:
+;
+; Check P0 PIC and confirm Timer Interrupt status.
+; Perform Spin Lock before reading P0 PIC.
+;
+
+ pushfd
+ cli
+ lea ebx, _Halp8254Lock
+ ACQUIRE_SPINLOCK ebx, Kqpc198p ; Spin if another thread is here
+ INDEXED_IO_READ 0,PIC1_PORT1 ; read CPU 0 port 21 for masks
+ RELEASE_SPINLOCK ebx
+ popfd
+ pop ebx
+ test al, 1h ; check for IRQ 0 masked off
+ mov al, PCR[PcHal.PcrNumber] ; get current processor #
+ jz short NoCPU0Update
+
+;
+; Try ReadAgain if below retry count.
+;
+
+ cmp RetryPerfCount+4, MAX_PERF_RETRY
+ ja short NoCPU0Update
+
+ReadAgain:
+;
+; This readagain is only executed when P0 is
+; at CLOCK2_LEVEL or greater.
+; AND when Timer IRQ is active (ie interrupt in progress).
+; This is done to close the window of an interrupt
+; occuring and the irql hasn't been raised yet.
+;
+
+ popfd
+ jmp Kqpc11 ; go back and read again
+
+NoCPU0Update:
+
+
+;
+; 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 ; allow interrupt in case counter
+ ; has wrapped
+
+ pushfd
+ cli
+
+;
+; In Belize mode we do not care about this since we use the P0 clock.
+;
+
+ cmp _SpType, SMP_SYSPRO2
+ je short Kqpc35
+
+;
+; If we moved processors while interrupts were enabled, start over
+;
+
+ cmp al, PCR[PcHal.PcrNumber]
+ jne Kqpc20
+Kqpc35:
+
+
+;
+; Fetch the base value again.
+;
+
+@@: mov eax, HalpPerfCounterLow
+ mov edx, HalpPerfCounterHigh ; [edx:eax] = new counter value
+ cmp eax, HalpPerfCounterLow ; did it move?
+ jne short @b ; re-read
+
+
+;
+; Compare the two reads of Performance counter. If they are different,
+; start over
+;
+
+ cmp eax, ebx
+ jne Kqpc20
+ cmp edx, esi
+ jne Kqpc20
+
+ neg ecx ; PIT counts down from 0h
+ add ecx, HalpRollOverCount
+
+;
+; In Belize mode we do not care about this since we use the P0 clock.
+;
+
+ cmp _SpType, SMP_SYSPRO2
+ je short Kqpc37
+
+ add ecx, PCR[PcHal.PcrPerfSkew]
+Kqpc37:
+
+ popfd ; restore interrupt flag
+
+ xchg ecx, eax
+ mov ebx, edx
+ cdq
+
+ add eax, ecx
+ adc edx, ebx ; [edx:eax] = Final result
+
+;
+; We only want to execute this code In Belize mode.
+;
+
+ cmp _SpType, SMP_SYSPRO2
+ jne Kqpc50
+
+ ;
+ ; Ok compare this result with the last result.
+ ; We will force the value to be greater than the last value,
+ ; after we have used up all of our retry counts.
+ ;
+ ; This should slam shut that annoying Window that causes
+ ; applications to recieve a 2nd query less then the first.
+ ;
+ ; This is not an most elegant solution, but fortunately
+ ; this situation is hit only on a rare occasions.
+ ;
+ ; Yeah, I know that this value can roll over
+ ; if someone runs some perf tests, and comes back in a
+ ; few weeks and wants to run some more. In this situation
+ ; the the very first call to this function will yield an
+ ; invalid value. This is the price of the fix.
+ ;
+
+ ;
+ ; Protect the global data with a spinlock
+ ;
+
+ push ebx
+Kqpc42: pushfd
+ cli
+ lea ebx, HalpForceDataLock
+ ACQUIRE_SPINLOCK ebx, Kqpc199 ; Spin if another thread is here
+
+;
+; Compare this value to the last value, if less then
+; fix it up.
+;
+
+ cmp edx, HalpLastQueryHighValue
+ ja short Kqpc44
+
+ cmp eax, HalpLastQueryLowValue
+ ja short Kqpc44
+
+;
+; Release the spinlock.
+;
+
+ RELEASE_SPINLOCK ebx
+ popfd
+ pop ebx
+
+;
+; Try Again if below count.
+;
+
+ cmp RetryPerfCount, MAX_PERF_RETRY
+ jbe Kqpc11 ; go back and read again
+
+;
+; Exhausted retry count so Fix up the values and leave.
+;
+
+ mov eax, HalpLastQueryLowValue
+ inc eax
+ mov edx, HalpLastQueryHighValue
+
+ jmp short Kqpc50
+
+Kqpc44:
+;
+; Save off the perf values for next time.
+;
+
+ mov HalpLastQueryLowValue, eax
+ mov HalpLastQueryHighValue, edx
+
+;
+; Release the spinlock.
+;
+
+ RELEASE_SPINLOCK ebx
+ popfd
+ pop ebx
+
+
+;
+; Return the counter
+;
+
+Kqpc50:
+ ; 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 edi ; remove locals
+ pop edi ; restore regs
+ pop esi
+ pop ebx
+
+ stdRET _KeQueryPerformanceCounter
+
+Kqpc198: popfd
+ SPIN_ON_SPINLOCK eax,<Kqpc11>
+
+;
+; This is just where we are spinning while we are waiting to read the PIC
+;
+Kqpc198p: popfd
+ SPIN_ON_SPINLOCK ebx,<Kqpc11p>
+;
+; This is just where we are spinning while waiting global last perf data
+;
+Kqpc199: popfd
+ SPIN_ON_SPINLOCK ebx,<Kqpc42>
+
+stdENDP _KeQueryPerformanceCounter
+; endmod
+
+ 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
+;
+
+Hci10:
+ push CLOCK_VECTOR
+ sub esp, 4 ; allocate space to save OldIrql
+ stdCall _HalBeginSystemInterrupt, <CLOCK2_LEVEL,CLOCK_VECTOR,esp>
+ or al,al ; check for spurious interrupt
+ jz Hci100
+
+;
+; Update performance counter
+;
+
+ mov eax, HalpRollOverCount
+ xor ebx, ebx
+ add HalpPerfCounterLow, eax ; update performace counter
+ adc HalpPerfCounterHigh, ebx
+
+ cmp _HalpClockWork, ebx
+ jz short Hci20
+
+ cmp _HalpClockMcaQueueDpc, bl
+ jz short Hci20
+
+ mov _HalpClockMcaQueueDpc, bl
+
+;
+; Queue MCA Dpc
+;
+ stdCall _HalpMcaQueueDpc
+
+Hci20:
+;
+; (esp) = OldIrql
+; (esp+4) = Vector
+; (esp+8) = base of trap frame
+; (ebp) = address of trap frame
+; (eax) = time increment
+;
+ mov eax, TIME_INCREMENT_10MS
+
+ mov ebx, _HalpIpiClock ; Emulate clock ticks to any processors?
+ or ebx, ebx
+ jz _KeUpdateSystemTime@0
+
+;
+; On the SystemPro we know the processor which needs an emulated clock tick.
+; Just set that processors bit and IPI him
+;
+
+@@:
+ movzx ecx, _HalpFindFirstSetRight[ebx] ; lookup first processor
+ btr ebx, ecx
+ mov ecx, _HalpProcessorPCR[ecx*4] ; PCR of processor
+ mov [ecx].PcHal.PcrIpiClockTick, 1 ; Set internal IPI event
+ or ebx, ebx ; any other processors?
+ jnz short @b ; yes, loop
+
+ stdCall _HalRequestIpi, <_HalpIpiClock> ; IPI the processor(s)
+
+ mov eax, TIME_INCREMENT_10MS
+ jmp _KeUpdateSystemTime@0
+
+Hci100:
+ add esp, 8
+ SPURIOUS_INTERRUPT_EXIT
+
+stdENDP _HalpClockInterrupt
+
+
+ page ,132
+ subttl "NonPrimaryClockTick"
+;++
+;
+; VOID
+; HalpNonPrimaryClockInterrupt (
+; );
+;
+; Routine Description:
+; ISR for clock interrupts for every processor except one.
+;
+; Arguments:
+;
+; None.
+; Interrupt is dismissed
+;
+; Return Value:
+;
+; None.
+;
+;--
+ ENTER_DR_ASSIST Hni_a, Hni_t
+cPublicProc _HalpNonPrimaryClockInterrupt ,0
+ ENTER_INTERRUPT Hni_a, Hni_t
+
+; Dismiss interrupt and raise irql
+
+ push CLOCK_VECTOR
+ sub esp, 4 ; allocate space to save OldIrql
+ stdCall _HalBeginSystemInterrupt, <CLOCK2_LEVEL,CLOCK_VECTOR,esp>
+ or al,al ; check for spurious interrupt
+ jz Hni100
+
+ ; TOS const PreviousIrql
+ stdCall _KeUpdateRunTime,<dword ptr [esp]>
+
+ INTERRUPT_EXIT ; will do an iret
+
+Hni100:
+ add esp, 8
+ SPURIOUS_INTERRUPT_EXIT
+
+stdENDP _HalpNonPrimaryClockInterrupt
+
+ page ,132
+ subttl "Emulate NonPrimaryClockTick"
+;++
+;
+; VOID
+; HalpSWNonPrimaryClockTick (
+; );
+;
+; Routine Description:
+; On the SystemPro the second processor does not get it's own clock
+; ticks. The HAL emulates them by sending an IPI which sets an overloaded
+; software interrupt level of SWCLOCK_LEVEL. When the processor attempts
+; to lower it's irql level below SWCLOCK_LEVEL the soft interrupt code
+; lands us here as if an interrupt occured.
+;
+; Arguments:
+;
+; None.
+; Interrupt is dismissed
+;
+; Return Value:
+;
+; None.
+;
+ ENTER_DR_ASSIST Hsi_a, Hsi_t
+
+ public _HalpSWNonPrimaryClockTick
+_HalpSWNonPrimaryClockTick proc
+;
+; Create IRET frame on stack
+;
+ pop eax
+ pushfd
+ push cs
+ push eax
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT Hsi_a, Hsi_t
+
+ public _HalpSWNonPrimaryClockTick2ndEntry
+_HalpSWNonPrimaryClockTick2ndEntry:
+
+; Save previous IRQL and set new priority level
+
+ push fs:PcIrql ; save previous IRQL
+ mov byte ptr fs:PcIrql, SWCLOCK_LEVEL ; set new irql
+ btr dword ptr fs:PcIRR, SWCLOCK_LEVEL ; clear the pending bit in IRR
+
+ sti
+
+ ; TOS const PreviousIrql
+ stdCall _KeUpdateRunTime,<dword ptr [esp]>
+
+ SOFT_INTERRUPT_EXIT ; will do an iret
+
+
+_HalpSWNonPrimaryClockTick 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_10MS ; yes, use 10ms clock
+ stdRET _HalSetTimeIncrement
+
+stdENDP _HalSetTimeIncrement
+
+_TEXT ends
+ end
+
diff --git a/private/ntos/nthals/halsp/i386/spdetect.asm b/private/ntos/nthals/halsp/i386/spdetect.asm
new file mode 100644
index 000000000..c040fa155
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spdetect.asm
@@ -0,0 +1,559 @@
+;++
+;
+; Copyright (c) 1991 Microsoft Corporation
+;
+; Module Name:
+;
+; spdetect.asm
+;
+; Abstract:
+;
+; This modules detects a SystemPro or compatible. It is INCLUDED
+; by SPIPI and other binaries whom need to know how to detect a
+; SystemPro type MP machine (ie, setup). It must assemble more or
+; less standalone and run in protect mode.
+;
+; Author:
+;
+; Ken Reneris (kenr) 13-Jan-1992
+;
+; Revision History:
+;
+;--
+
+include halsp\i386\spmp.inc
+include callconv.inc ; calling convention macros
+
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+
+; spSystemType: SystemType is read from 0c80-0c83h.
+; 0c80-0c81: 0e11: Compressed CPQ (5 bit encoding).
+; 0c82: System Board type.
+; 0c83: System Board revision level.
+
+spSystemCpuTable dd 0e1101h ; CPQ01xx 386 ASP
+ dd 0e1111h ; CPQ11xx 486 ASP
+ dd 0e1150h ; CPQ50xx plug in processor
+ dd 0e1159h ; CPQ59xx plug in processor
+ dd 0e115bh ; CPQffxx plug in processor
+ dd 0e1115h ; CPQ15xx (smp version)
+ dd 0e1152h ; CPQ15xx (smp version)
+ dd 0e1108h ; CPQ15xx
+ dd 0592a0h ; ALRa0xx PowerPro
+ dd 0592b0h ; ALRb0xx PowerPro plug in processor
+ dd 047232h ; Acer SP clone (4p version)
+ dd 246c00h ; ICL MX
+ dd 246c02h ; ICL (acer 700xx)
+ dd 352310h ; Micronycs MPro motherboard
+ dd 352311h ; Micronycs MPro
+ dd 0592a1h ; ALRa1xx PowerPro (DX2-66 mobo)
+ dd 0592a2h ; ALRa2xx PowerPro (reserved mobos)
+ dd 0592b1h ; ALRb1xx PowerPro (reserved p2's)
+ dd 4dc901h ; Siemens Nixdorf PCE-4T/33
+ dd 4dc950h ; Siemens Nixdorf PCE-4T/33
+ dd 047219h ; AcerFrame 700
+ dd 047232h ; AcerFrame 3000MP560
+ dd 0h
+CPUTABLE_SIZE equ ($-spSystemCpuTable)/4
+
+; Types match up to CpuTable.
+spSystemTypeTable db SMP_SYSPRO1 ; CPQ01xx 386 ASP
+ db SMP_SYSPRO1 ; CPQ11xx 486 ASP
+ db SMP_SYSPRO1 ; CPQ50xx plug in processor
+ db SMP_SYSPRO1 ; CPQ59xx plug in processor
+ db SMP_SYSPRO1 ; CPQffxx plug in processor
+ db SMP_SYSPRO2 ; CPQ15xx (smp version)
+ db SMP_SYSPRO2 ; CPQ15xx (smp version)
+ db SMP_SYSPRO1 ; CPQ15xx
+ db SMP_SYSPRO1 ; ALRa0xx PowerPro
+ db SMP_SYSPRO1 ; ALRb0xx PowerPro
+ db SMP_ACER ; Acer SP clone (4p version)
+ db SMP_ACER ; ICL MX
+ db SMP_ACER ; ICL (acer 700xx)
+ db SMP_SYSPRO1 ; Micronycs MPro motherboard
+ db SMP_SYSPRO1 ; Micronycs MPro
+ db SMP_SYSPRO1 ; ALRa1xx PowerPro (DX2-66 mobo)
+ db SMP_SYSPRO1 ; ALRa2xx PowerPro (reserved mobos)
+ db SMP_SYSPRO1 ; ALRb1xx PowerPro (reserved p2's)
+ db SMP_SYSPRO1 ; Siemens Nixdorf PCE-4T/33
+ db SMP_SYSPRO1 ; Siemens Nixdorf PCE-4T/33
+ db SMP_ACER ; AcerFrame 700
+ db SMP_ACER ; AcerFrame 3000MP560
+
+TYPETABLE_SIZE equ ($-spSystemTypeTable)
+.errnz (CPUTABLE_SIZE - TYPETABLE_SIZE - 1)
+
+;
+; Order to check eisa ports in..
+;
+SpPortOrder dw 0000, 0F000h, 0C000h, 0D000h, -1
+
+ public _SpType, _SpCpuCount, _SpProcessorControlPort
+_SpType db -1 ; Lowest SMP_SYSPRO type found
+_SpCpuCount db 0 ; # of Cpus found
+_SpProcessorControlPort dw 00000h+PCR_OFFSET
+ dw 0F000h+PCR_OFFSET
+ dw 0C000h+PCR_OFFSET
+ dw 0D000h+PCR_OFFSET
+RestoreESP dd 0
+RestoreESP1 dd 0
+SpCOMPAQ db 'COMPAQ'
+SpEISA db 'EISA'
+Sp80386 db '80386'
+Sp80486 db '80486'
+
+_DATA ends
+
+ page ,132
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+; BOOLEAN
+; DetectSystemPro (
+; OUT PBOOLEAN IsConfiguredMp
+; );
+;
+; Routine Description:
+; This function is only called on EISA machines
+;
+; Determines the type of system (specifically for eisa machines).
+;
+; Arguments:
+; IsConfiguredMp - If the machine is a SystemPro, then this value is
+; set to TRUE if it's an MP SystemPro, else FALSE.
+;
+; Return Value:
+; FALSE - not a supported machine for this HAL
+; TRUE - is SystemPro
+; etc...
+;
+;--
+cPublicProc _DetectSystemPro ,1
+
+ push edi
+ push esi
+ push ebx ; Save C Runtime
+
+ movzx edx, SpPortOrder[0] ; Check system board for
+ call CheckEisaCard ; SystemPro belize ID
+if 0
+ or eax, eax
+ jz dsp_idnotknown
+endif
+ cmp al, SMP_SYSPRO2
+ je dsp_belize ; if belize, go count belize style
+
+ xor ebx, ebx ; CpuCount
+ xor esi, esi ; Base EisaCard address
+
+dsp10: movzx edx, SpPortOrder[esi*2]
+ cmp dx, -1 ; End of list?
+ je short dsp30 ; Yes, done
+
+ call CheckEisaCard ; Check Eisa card for cpu
+ or eax, eax ; If not cpu, then skip it
+ jz short dsp20
+
+ cmp _SpType, al
+ jc @f
+ mov _SpType, al ; SpType = min(SpType, eax)
+@@:
+ cmp ebx, 4 ; MaxSupported CPUs already found?
+ jae dsp20 ; Yes, then skip this one
+
+ movzx edx, SpPortOrder[esi*2]
+ add edx, PCR_OFFSET
+ mov _SpProcessorControlPort[ebx*2], dx
+
+ inc ebx ; CpuCount += 1
+
+dsp20: inc esi ; Next EisaCard I/O addr to check
+ jmp short dsp10
+
+dsp30: xor eax, eax ; Assume FALSE
+ifdef SETUP
+ cmp bl, 2 ; Did we find at least 2 CPUs?
+else
+ cmp bl, 1 ; Did we find at least 1 CPU?
+endif
+ jc short SpExit ; No, then exit
+
+ mov _SpCpuCount, bl
+ mov al, 1 ; return non-zero
+
+ mov ebx, dword ptr [esp+16]
+ mov byte ptr [ebx], al ; *IsConfiguredMp = TRUE
+
+SpExit: pop ebx
+ pop esi
+ pop edi
+ stdRET _DetectSystemPro
+
+;-----
+
+dsp_belize:
+ mov _SpType, al ; SpType = SYSPRO2
+
+ ;
+ ; Put Belize SystemPro into Symmetric mode
+ ;
+
+ mov dx, SMP_MODE_PORT
+ mov al, SMP_SYMMETRICAL_MODE
+ out dx, al
+
+ ;
+ ; Count CPUs, belize style. And assign logcal IDs to CPUs
+ ;
+ xor ecx,ecx ;physical cpu
+ xor ebx,ebx ;logical cpu
+
+dsp50:
+ mov dx,SMP_INDEX_PORT
+ mov al,cl ; al = physical CPU slot number
+ out dx, al ; select physical CPU slot in al
+ mov dx,SMP_ASSIGNMENT_PORT
+ in al,dx ; read CPU number
+ cmp al,SMP_MAX_PROCESSORS ; Q:Valid CPU?
+ jae short dsp60 ; n:Check next physical CPU slot
+ mov al,bl ; y:Make physical CPU a logical CPU
+ out dx,al
+ inc ebx ; next logical CPU to assign
+dsp60:
+ inc ecx ; next physical CPU slot to check
+ cmp ecx,SMP_MAX_PROCESSORS
+ jb short dsp50 ; look in next cpu slot
+
+ jmp short dsp30 ; ebx = number of cpus found
+
+;-----
+if 0 ; Note: this code is not fully working (did not pass hct's)
+public dsp_idnotknown
+dsp_idnotknown:
+;
+; The eisa ID was not recongonized - attempt to use the protect mode
+; int-15 interface to determine if this is a SystemPro compatible
+; computer. Any SystemPro detected in this manner is assumed to
+; be of type SMP_SYSPRO1 which only has 2 processors.
+;
+; Note: There is a fair amount of paranoia in the following code
+; becuase we trust the rom as little as possible.
+;
+
+ xor eax, eax
+ xor ecx, ecx
+ mov cx, ss ; Verify SS value is what it is
+ cmp ecx, KGDT_R0_DATA ; expect it to be; otherwise this code
+ jne short SpExit ; can't work
+
+ pushf ; Save current DF & EF
+
+ sub esp, 15*8
+ sidt fword ptr [esp] ; get IDT address
+ mov esi, dword ptr [esp+2] ; (esi) = IDT
+ mov edi, esp ; (edi) = address to copy vectors to
+
+ push es ; Save selectors in case rom
+ push ds ; trashes state
+ push fs
+ push gs
+ push esi
+ push ebp
+ cld
+ cli
+ pushf
+
+ ;
+ ; Save and hook some IDT vectors. If we get some type of trap
+ ; here or in the rom, then we will restore the state and return
+ ; back that a systempro was not detected
+ ;
+
+ mov eax, esi
+ mov ecx, 15*8/4
+ rep movsd ; Save IDT vectors
+
+ mov RestoreESP, esp ; Save current ESP for restore
+
+ mov ecx, offset FLAT:dsp_handlefault
+ mov dx, cs
+ shl edx, 16
+ mov dx, cx
+ mov cx, 08E00h ; Install int32 gate for vectors
+
+ mov [eax+0*8+0] , edx
+ mov [eax+0*8+4] , ecx ; Trap IDT 0 Divide Error
+ mov [eax+4*8+0] , edx
+ mov [eax+4*8+4] , ecx ; Trap IDT 4 INTO
+ mov [eax+5*8+0] , edx
+ mov [eax+5*8+4] , ecx ; Trap IDT 5 BOUND
+ mov [eax+6*8+0] , edx
+ mov [eax+6*8+4] , ecx ; Trap IDT 6 Invalid OpCode
+ mov [eax+11*8+0], edx
+ mov [eax+11*8+4], ecx ; Trap IDT 11 Segment not present
+ mov [eax+12*8+0], edx
+ mov [eax+12*8+4], ecx ; Trap IDT 12 Stack fault
+ mov [eax+13*8+0], edx
+ mov [eax+13*8+4], ecx ; Trap IDT 13 GP fault
+ mov [eax+14*8+0], edx
+ mov [eax+14*8+4], ecx ; Trap IDT 14 Page fault
+
+ ;
+ ; Map in 64K of the ROM in order to use protect mode int-15 interface.
+ ; (see Compaq eisa spec)
+ ;
+ stdCall _HalpMapPhysicalMemory, <0f0000h, 16> ; map 64K of ROM
+ mov ebp, eax ; save ROM starting address
+
+ ;
+ ; Verify there is a ROM, search for the word 'COMPAQ' in the ROM
+ ; addresses FE000-FE0FF. (see Compaq eisa spec)
+ ;
+ lea esi, SpCOMPAQ ; 'COMPAQ'
+ mov ebx, 6 ; strlen ('COMPAQ')
+ lea edi, [ebp+0e000h] ; address to scan
+ mov ecx, 0ffh ; length of scan
+ call SpScanForString
+ jne dsp_handlefault ; if not found then abort
+
+ ;
+ ; Also verify the 'EISA' work at rom address FFFD0-FFFFF
+ ; (see Compaq eisa spec)
+ ;
+ lea esi, SpEISA ; 'EISA'
+ mov ebx, 4 ; strlen ('EISA')
+ lea edi, [ebp+0ffd0h] ; address to scan
+ mov ecx, 02fh ; length of scan
+ call SpScanForString
+ jne dsp_handlefault ; if not found then abort
+
+ ;
+ ; Look in slot 11 and slot 15 for processors
+ ;
+ sub esp, 400 ; make space for Config Data Block
+ mov ecx, 11 ; check slot 11 first
+ xor ebx, ebx ; assume no processors found
+
+dsp_95:
+ push ebp ; save virtual rom address
+ push ecx ; save current slot #
+ push ebx ; save # processors found
+
+ xor eax, eax
+ lea edi, [esp+12]
+ mov ecx, 300/4
+ rep stosd ; clear destionation buffer
+
+ mov ax, 0D881h ; Read Config Info, 32bit
+ lea esi, [esp+12] ; destionation address
+
+ mov RestoreESP1, esp ; Some roms don't iret correctly
+ sub esp, 10h ; Some roms clobber some stack
+ pushf
+ push cs
+ lea ebx, [ebp+0f859h] ; 'industry standard' int-15 address
+ call ebx ; INT-15 (trashes most registers)
+ mov esp, RestoreESP1 ; restore ESP
+ jc short dsp_110 ; Not valid, check next slot
+
+ ;
+ ; Check type field
+ ;
+ lea edi, [esp+12+23h] ; address of type string
+ lea esi, Sp80386 ; '80386'
+ mov ebx, 5 ; strlen ('80386')
+ mov ecx, 80
+ call SpScanForString
+ je short dsp_105
+
+ lea edi, [esp+12+23h] ; address of type string
+ lea esi, Sp80486 ; '80486'
+ mov ebx, 5 ; strlen ('80486')
+ mov ecx, 80
+ call SpScanForString
+ jne short dsp_110
+
+dsp_105:
+ ; string was either 80386 or 80486
+ inc dword ptr [esp] ; count one more processor
+
+dsp_110:
+ pop ebx ; (ebx) = number processors found
+ pop ecx ; (ecx) = slot #
+ pop ebp ; (ebp) = virtual rom address
+
+ or ebx, ebx ; if a processor is not in the first
+ jz short dsp_handlefault ; slot, then don't look in second
+
+ cmp ebx, 2 ; if # of processors is trash
+ ja short dsp_handlefault ; then abort
+
+ mov eax, ecx
+ cmp eax, 11 ; Did we just test slot 11?
+ mov ecx, 15
+ je dsp_95 ; Yes, now test 15
+ cmp eax, 15 ; Did we just test slot 15?
+ je short dsp_cleanup ; Yes, then we are done
+
+ ; slot # isn't 11 or 15, abort
+
+dsp_handlefault: ; Sometype of fault, or abort
+ mov eax, KGDT_R0_DATA ; make sure ss has the correct value
+ mov ss, ax
+ xor ebx, ebx ; No processors found
+
+dsp_cleanup:
+; (ebx) = # of processors
+ mov esp, SS:RestoreESP ; Make sure esp is correct
+
+ popf
+ pop ebp
+ pop edi ; (edi) = IDT address
+ pop gs ; restore selectors
+ pop fs
+ pop ds
+ pop es
+ mov esi, esp ; (esi) = original IDT vectors
+ mov ecx, 15*8/4
+ rep movsd ; restore IDT vectors
+ add esp, 15*8 ; cleanup stack
+ popf
+
+ mov _SpType, SMP_SYSPRO1 ; assume original systempro
+
+ cmp ebx, 2 ; at least 2 processors found?
+ jc short dsp_150 ; no, continue
+;
+; Verify that the second processor board is enabled
+;
+ movzx edx, SpPortOrder[1*2]
+ add edx, EBC_OFFSET ; (edx) = 0zC84
+ in al, dx ; Read control bits
+ test al, 1 ; Is Eisa CPU board enabled?
+ jnz short dsp_150 ; Yes, continue
+ dec ebx ; don't count it
+
+dsp_150:
+ jmp dsp30 ; exit
+endif
+
+stdENDP _DetectSystemPro
+
+;++
+; SpScanForString
+;
+; Routine Description:
+; Scans address range looking for matching string
+;
+; Arguments:
+; (edi) = Start of address range to scan
+; (ecx) = Length of address range
+; (esi) = String to scan for
+; (ebx) = Length of string
+;
+; Returns:
+; ZR - String found
+; NZ - String not found
+;
+;--
+SpScanForString proc
+ sub ecx, ebx ; don't go past end
+ inc ecx
+
+ mov al, [esi] ; (al) = first char to scan for
+ inc esi ; skip past first char
+ dec ebx
+
+ss10: repne scasb ; look for first byte
+ jecxz short ss20 ; byte found? No, exit
+
+ push ecx
+ push edi
+ push esi
+ mov ecx, ebx ; length of string to compare
+ repe cmpsb ; is string at this location?
+ or ecx, ecx ; ZF if strings match
+ pop esi
+ pop edi
+ pop ecx
+
+ jnz short ss10 ; continue looking
+ ret ; ZR
+
+ss20: inc ecx ; NZ
+ ret
+
+SpScanForString endp
+
+
+;++
+; CheckEisaCard
+;
+; Routine Description:
+; Used only by DetectSystemPro.
+;
+; Arguments:
+; (edx) = Eisa ID port to check
+;
+; Returns:
+; (eax) = 0 card was not a valid cpu
+; non-zero Cpu type
+;
+;--
+CheckEisaCard proc
+ push edi
+ push esi
+ push ebx
+
+ mov esi, edx
+ add edx, PRODUCT_ID_OFFSET ; Product ID port
+
+ xor eax, eax
+ in al, dx ; 0zC80
+ test al, 80h ; if bit 8 off?
+ jnz short NoMatch ; no, then not an Eisa card
+
+ shl eax, 8
+ inc edx
+ in al, dx ; 0zC81
+ shl eax, 8
+ inc edx
+ in al, dx ; (eax)=dword of ports 0zC80-0zC82
+
+ mov ecx, CPUTABLE_SIZE ; Scan CPU table looking for
+ lea edi, spSystemCpuTable ; matching board ID
+ repne scasd
+ jecxz short NoMatch ; Was it found?
+
+ sub ecx, CPUTABLE_SIZE-1
+ neg ecx ; (ecx) = index CPU was found at
+ movzx ecx, byte ptr spSystemTypeTable[ecx]
+
+ or esi, esi ; SystemBoard?
+ jz short @f ; Yes, then it is assumed enabled
+
+ cmp cl, SMP_ACER ; If acer, assume it's enabled
+ je short @f ; (machine incorrectly reports
+ ; 'disable' on every other proc)
+ mov edx, esi
+ add edx, EBC_OFFSET ; (edx) = 0zC84
+ in al, dx ; Read control bits
+ test al, 1 ; Is Eisa CPU board enabled?
+ jz short NoMatch ; No, then skip it
+@@:
+ mov eax, ecx
+ jmp short cei_exit
+NoMatch:
+ xor eax, eax
+cei_exit:
+ pop ebx
+ pop esi
+ pop edi
+ ret
+
+CheckEisaCard endp
+
+_TEXT ENDS
diff --git a/private/ntos/nthals/halsp/i386/spipi.asm b/private/ntos/nthals/halsp/i386/spipi.asm
new file mode 100644
index 000000000..921c5d0e1
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spipi.asm
@@ -0,0 +1,750 @@
+ title "Interprocessor Interrupt"
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; spipi.asm
+;
+;Abstract:
+;
+; SystemPro IPI code.
+; Provides the HAL support for Interprocessor Interrupts for hte
+; MP SystemPro implementation.
+;
+;Author:
+;
+; Ken Reneris (kenr) 13-Jan-1992
+;
+;Revision History:
+;
+;--
+.386p
+; .xlist
+
+;
+; Include SystemPro detection code
+;
+
+include i386\spdetect.asm
+
+;
+; Normal includes
+;
+
+include hal386.inc
+include i386\kimacro.inc
+include i386\ix8259.inc
+include callconv.inc ; calling convention macros
+
+ EXTRNP _KiCoprocessorError,0,IMPORT
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _KeRaiseIrql,2
+ EXTRNP _HalBeginSystemInterrupt,3
+ EXTRNP _HalEndSystemInterrupt,2
+ EXTRNP _KiIpiServiceRoutine,2,IMPORT
+ EXTRNP _HalEnableSystemInterrupt,3
+ EXTRNP _HalpInitializePICs,0
+ EXTRNP _HalDisplayString,1
+ EXTRNP _HalEnableSystemInterrupt,3
+ EXTRNP _HalDisableSystemInterrupt,2
+ EXTRNP _HalpMapPhysicalMemory,2
+ EXTRNP _HalpAcerInitializeCache,0
+ extrn _HalpDefaultInterruptAffinity:DWORD
+ extrn _HalpActiveProcessors:DWORD
+ extrn _HalpCpuCount:DWORD
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+ public _HalpFindFirstSetRight, _Sp8259PerProcessorMode
+_HalpFindFirstSetRight db 0, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0
+_Sp8259PerProcessorMode db 0
+
+align 4
+ public _HalpProcessorPCR
+_HalpProcessorPCR dd MAXIMUM_PROCESSORS dup (?) ; PCR pointer for each processor
+
+_HalpPINTAddrTable label word
+ dw SMP_MPINT0
+ dw SMP_MPINT1
+ dw SMP_MPINT3
+ dw SMP_MPINT4
+ dw SMP_MPINT5
+ dw SMP_MPINT6
+ dw SMP_MPINT7
+ dw SMP_MPINT8
+ dw SMP_MPINT9
+ dw SMP_MPINT10
+ dw SMP_MPINT11
+ dw SMP_MPINT12
+ dw SMP_MPINT13
+ dw SMP_MPINT14
+ dw SMP_MPINT15
+
+HALPPINTADDRTABLESIZE equ ($-_HalpPINTAddrTable)/TYPE(_HalpPINTAddrTable)
+
+BadHalString db 'HAL: SystemPro HAL.DLL cannot be run on non SystemPro'
+ db '/compatible', cr,lf
+ db ' Replace the hal.dll with the correct hal', cr, lf
+ db ' System is HALTING *********', 0
+
+_DATA ends
+
+ page ,132
+ subttl "Post InterProcessor Interrupt"
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME 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 KeReadir/LowerIrq's must be available once this function
+; returns. (IPI's are only used once two or more processors are
+; available)
+;
+; . Enable IPI interrupt (makes sense for P1, P2, ...).
+; . Save Processor Number in PCR.
+; . if (P0)
+; . determine what kind of system is it,
+; . if (NotSysProCompatible) Halt;
+; . program VECTOR_PORT to accept IPI at IRQ13.
+; . InitializePICs.
+; . if (P1)
+; . Save ProcesserControlPort (PCR) to PCRegion, per processor.
+; . Enable PINTs on CPU.
+;
+;Arguments:
+;
+; Number - Logical processor number of calling processor
+;
+;Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalInitializeProcessor ,1
+ ;
+ ; Initialize various PCR values
+ ; PcIDR in PCR - enable slave IRQ
+ ; PcStallScaleFactor - bogusly large value for now
+ ; PcHal.PcrNumber - logical processor #
+ ; PcHal.PcrPic - Set if processor has it's own pics.
+ ; The SystemPro only defines one pic set on P0, but some clones
+ ; put more pics on each other processor. This isn't vastly
+ ; better, but it is better then processor. This isn't vastly 'em
+ ; PcHal.PcrIpiType - Address to jmp to once ipi is verified.
+ ; This is done to optimize how to deal with a varity of 'work-
+ ; arounds' due to non-smp nature of SP clones
+ ;
+
+ cli
+ mov fs:PcIDR, 0fffffffbh
+ movzx eax, byte ptr [esp+4]
+ mov fs:PcHal.PcrNumber, al ; Save processor # in PCR
+ lock bts _HalpActiveProcessors, eax
+ lock inc _HalpCpuCount
+ mov dword ptr fs:PcStallScaleFactor, INITIAL_STALL_COUNT
+ mov dword ptr fs:PcHal.PcrPerfSkew, 0
+ mov fs:PcHal.PcrIpiSecondLevelDispatch, offset _HalpNo2ndDispatch
+
+ ;
+ ; Initialize IDT vector for IPI interrupts
+ ; KiSetHandlerAddressToIDT(I386_80387_VECTOR, HalpIrq13Handler);
+ ;
+ mov ebx, fs:PcIDT
+ lea ecx, _HalpIrq13Handler
+ add ebx, (PRIMARY_VECTOR_BASE + 13) * 8
+ mov word ptr [ebx+0], cx
+ shr ecx, 16
+ mov word ptr [ebx+6], cx
+
+ ;
+ ; Save away flat address of our PCR - (used in emulating clock ticks
+ ; on systempro p1 which doesn't have it's own clock tick)
+ ;
+ mov ecx, fs:PcSelfPcr ; Flat address of this PCR
+ mov _HalpProcessorPCR[eax*4], ecx ; Save it away
+
+
+ or eax, eax
+ jnz ipi_10 ; If !p0 then ipi_10
+
+ mov fs:PcHal.PcrPic, 1 ; P0 has a pic
+ mov fs:PcHal.PcrIpiType, offset P0Ipi
+
+ ; Run on P0 only
+
+ sub esp, 4
+ stdCall _DetectSystemPro,<esp> ; Which type of SystemPro
+ add esp,4
+
+ or eax, eax
+ jz NotSystemPro
+
+ lock or _HalpDefaultInterruptAffinity, 1
+
+ cmp _SpType, SMP_SYSPRO2 ; Belize SystemPro?
+ je short ipi_belize
+
+ ;
+ ; Set all processors IPI to irq13
+ ;
+
+ mov al, PRIMARY_VECTOR_BASE + 13
+ mov dx, 0FC68h ; Set SystemPro P1 Interrupt
+ out dx, al ; Vector to irq13
+
+ cmp _SpType, SMP_ACER ; Acer? Then set other acer
+ jne short ipi_notacer ; processor ports as well
+
+ mov dx, 0C028h
+ out dx, al ; set P2 Interrupt Vector
+ mov dx, 0C02Ch
+ out dx, al ; set P3 Interrupt Vector
+
+ stdCall _HalpAcerInitializeCache
+
+ mov dx, 0C06h ; Check for ASMP or SMP mode
+ in al, dx
+ test al, 10h ; SMP mode bit set?
+ jz short @f ; No, then ASMP mode
+
+ cmp al, 0ffh ; Ambra doesn't implement
+ je short @f ; this port...
+
+
+;; bugbug - problems with bootup device
+;; mov _Sp8259PerProcessorMode, SP_M8259 + SP_SMPDEVINTS
+
+ mov _Sp8259PerProcessorMode, SP_M8259 ; Set to use multiple pic
+@@: jmp short ipi_05 ; implementation
+
+ipi_belize:
+ ;
+ ; Machine is Belize SystemPro
+ ; Set for multiple 8259s, statically distribute device interrupts, and
+ ; use symmetric clock interrupt.
+ ;
+
+ mov _Sp8259PerProcessorMode, SP_M8259 + SP_SMPDEVINTS + SP_SMPCLOCK
+
+ stdCall HalpInitializeBelizeIC
+
+ipi_notacer:
+ipi_05:
+ ; enable IPI vector
+ stdCall _HalEnableSystemInterrupt,<PRIMARY_VECTOR_BASE+13,IPI_LEVEL,0>
+
+ ; Other P0 initialization would go here
+
+ jmp short ipi_30
+
+ipi_10:
+ mov fs:PcHal.PcrIpiType, offset IpiWithNoPic ; default it
+
+ test _Sp8259PerProcessorMode, SP_M8259 ; 8259 on this processor?
+ jz short ipi_20
+
+ ;
+ ; SP machine is set for SMP mode - which has 2 8259s per processor
+ ;
+ mov fs:PcHal.PcrPic, 1 ; Set to use pic on this proc
+
+ cmp _SpType, SMP_ACER
+ jne short ipi_notacer2
+ ;
+ ; Machine is in ACER "SMP" mode - well, this fine SMP mode happens
+ ; to have an asymmetric clock interrupt, so we need to emulate non-
+ ; P0 clock interrupts to it just like we do on the standard SystemPro
+ ;
+ mov fs:PcHal.PcrIpiType, offset IpiWithPicButNoClock
+ stdCall _HalpInitializePICs ; Init this processors PICs
+
+ipi_notacer2:
+ cmp _SpType, SMP_SYSPRO2
+ jne short ipi_notbelize2
+
+ ;
+ ; Machine is Belize SystemPro
+ ;
+ stdCall HalpInitializeBelizeIC
+
+ipi_notbelize2:
+ ;
+ ; Enable IPI vector for non-P0 cpu
+ ;
+ stdCall _HalEnableSystemInterrupt,<PRIMARY_VECTOR_BASE+13, IPI_LEVEL,0>
+
+ipi_20:
+
+ ; Specific non-P0 initialization would go here
+
+ipi_30:
+ movzx eax, byte ptr [esp+4] ; cpu number
+ mov dx, _SpProcessorControlPort[eax*2] ; Port value for this processor
+
+ mov fs:PcHal.PcrControlPort, dx ; Save port value
+ mov fs:PcHal.PcrIpiClockTick, 0 ; Set to not signaled
+
+ cmp _SpType, SMP_SYSPRO2
+ je short @f
+
+ in al, dx ; remove disabled & signaled
+ and al, not (INTDIS or PINT) ; bits
+ out dx, al
+@@:
+ stdRET _HalInitializeProcessor
+
+NotSystemPro:
+; on a non system pro. Display message and HALT system.
+ stdCall _HalDisplayString, <offset BadHalString>
+ hlt
+
+stdENDP _HalInitializeProcessor
+
+
+;++
+;
+; VOID
+; HalpInitializeBelizeIC(
+; VOID
+; );
+;
+;Routine Description:
+;
+; Initialize interrupt control for the Belize SystemPro
+;
+;Return Value:
+;
+; None.
+;
+;--
+cPublicProc HalpInitializeBelizeIC, 0
+ push ebx
+
+ ;
+ ; Belize IPIs go to Belize Irq13 handler
+ ;
+ mov ebx, fs:PcIDT
+ lea ecx, _HalpBelizeIrq13Handler
+ add ebx, (PRIMARY_VECTOR_BASE + 13) * 8
+ mov word ptr [ebx+0], cx
+ shr ecx, 16
+ mov word ptr [ebx+6], cx
+
+ ;
+ ; Disable irq13 sources
+ ;
+
+ mov dx, SMP_MPINT13PORT
+ mov al, (SMP_DSBL_NCPERR + SMP_DSBL_DMACHAIN + SMP_DSBL_MCERR)
+ out dx, al
+
+ ;
+ ; Disable ipi ports
+ ;
+
+ mov ecx, HALPPINTADDRTABLESIZE
+ xor ebx, ebx
+ mov al, SMP_INTx_DISABLE
+@@:
+ mov dx, _HalpPINTAddrTable[ ebx ]
+ out dx, al
+ add ebx, 2
+ loopnz short @b
+
+ stdCall _HalpInitializePICs ; Init this processors PICs
+
+ ;
+ ; Enable PINT
+ ;
+
+ mov dx, SMP_IPI_MPINTx_PORT
+ mov al, SMP_INTx_ENABLE + SMP_INTx_CLR_PINT
+ out dx, al
+
+ pop ebx
+ stdRet HalpInitializeBelizeIC
+stdENDP HalpInitializeBelizeIC
+
+
+;++
+;
+; VOID
+; HalRequestIpi(
+; IN ULONG Mask
+; );
+;
+;Routine Description:
+;
+; Requests an interprocessor interrupt
+;
+;Arguments:
+;
+; Mask - Supplies a mask of the processors to be interrupted
+;
+;Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalRequestIpi ,1
+
+ cmp _SpType, SMP_SYSPRO2
+ jne short ripi_10
+
+ mov eax, dword ptr [esp+4] ; (eax) = Processor bitmask
+if DBG
+ or eax, eax ; must ipi somebody
+ jz short ipibad
+
+ movzx ecx, byte ptr fs:PcHal.PcrNumber
+ bt eax, ecx ; cannot ipi yourself
+ jc short ipibad
+endif
+
+ mov dx, SMP_IPI_MASKPORT
+ or eax, (SMP_IPI_VECTOR shl 24)
+ out dx, eax
+ stdRET _HalRequestIpi
+
+
+ALIGN 4
+ripi_10:
+ mov ecx, dword ptr [esp+4] ; (ecx) = Processor bitmask
+
+if DBG
+ or ecx, ecx ; must ipi somebody
+ jz short ipibad
+
+ movzx eax, byte ptr fs:PcHal.PcrNumber
+ bt ecx, eax ; cannot ipi yourself
+ jc short ipibad
+endif
+@@:
+ movzx eax, _HalpFindFirstSetRight[ecx] ; lookup first processor to ipi
+ btr ecx, eax
+ mov dx, _SpProcessorControlPort[eax*2]
+ in al, dx ; (al) = original content of PCP
+ or al, PINT ; generate Ipi on target
+ out dx, al
+ or ecx, ecx ; ipi any other processors?
+ jnz @b ; yes, loop
+
+ stdRET _HalRequestIpi
+
+if DBG
+ipibad: int 3
+ stdRET _HalRequestIpi
+endif
+
+stdENDP _HalRequestIpi
+
+
+ page ,132
+ subttl "SystemPro Irq13 Interrupt Handler"
+;++
+;
+; VOID
+; HalpIrq13Handler (
+; );
+;
+; Routine Description:
+;
+; This routine is entered as the result of an interrupt generated by inter
+; processor communication or coprocessor error.
+; Its function is to determine the sources of the interrupts and to
+; call its handler.
+;
+; If the interrupt is determined to be generated by coprocessor error,
+; this routine will lower irql to its original level, and finally invoke
+; coprocessor error handler. By doing this, the coprocessor
+; error will be handled at Irql 0 as it should be.
+;
+; N.B. This routine is specific to Compaq SystemPro. On SystemPro, the
+; IRQ13 of P0 is also used by DMA buffer chaining interrupt. Currently,
+; NO NT driver uses the DMA buffer chaining capability. For now, this
+; routine simply ignores it.
+;
+; Arguments:
+;
+; None.
+; Interrupt is dismissed
+;
+; 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
+;
+; Save previous IRQL
+;
+ push 13 + PRIMARY_VECTOR_BASE ; Vector
+ sub esp, 4 ; space for OldIrql
+;
+; Dismiss interrupt.
+;
+ mov dx, fs:PcHal.PcrControlPort
+
+ in al, dx
+ test al, PINT
+ jz Hi100 ; if not a PINT, then go Hi100
+
+;
+; The interrupt has been identified to be Inter-Processor Interrupt
+; We now dismiss the interprocessor interrupt and call its handler
+;
+
+ and al, not (PINT or INTDIS)
+ out dx, al ; clear PINT
+
+ jmp fs:[PcHal.PcrIpiType] ; Go handle ipi accordingly
+
+align 4
+IpiWithNoPic:
+;
+; This processor doesn't have a PIC
+;
+ cmp byte ptr fs:PcIrql, IPI_LEVEL ; is preview IRQL level
+ jnc short Ksi20 ; >= IPI_LEVEL?
+
+
+ ; WARNING: Some SystemPro's actually don't complete the OUT to the
+ ; ProcessorControlRegister by the return of the OUT instruction. This
+ ; code path can do a 'sti' before the pending interrupt bit is cleared
+ ; on these machines. To get around this problem we do an IN from the
+ ; ProcessorControlPort again which will cause the last OUT to complete
+ ; before the IN can.
+ in al, dx
+
+ stdCall _KeRaiseIrql, <IPI_LEVEL,esp>
+
+;
+; It also doesn't have it's own clock interrupt, see if clock interrupt
+; emulation is requested - if so raise a software interrupt to go emulate
+; it when we reach a lower IRQL
+;
+ cmp fs:PcHal.PcrIpiClockTick, 0 ; Emulate ClockTick?
+ jz short Ksi30 ; No, just go service ipi
+
+ mov fs:PcHal.PcrIpiClockTick, 0 ; yes, reset trigger
+ or dword ptr fs:PcIRR, SWClockTick ; Set SW ClockTick bit
+ jmp short Ksi30 ; go process ipi
+
+Ksi20:
+;
+; This processor is >= IPI_LEVEL, this IPI should not be here.
+;
+ in al, dx
+ or al, PINT ; re-post this IPI
+ out dx, al
+ ; clear IF bit in return EFLAGS
+ add esp, 8
+ and dword ptr [esp].TsEflags, NOT 200h
+ SPURIOUS_INTERRUPT_EXIT
+
+align 4
+IpiWithPicButNoClock:
+ cmp fs:PcHal.PcrIpiClockTick, 0 ; Emulate ClockTick?
+ jz short SymmetricIpi
+
+ mov fs:PcHal.PcrIpiClockTick, 0
+ or dword ptr fs:PcIRR, SWClockTick ; Set SW ClockTick bit
+
+align 4
+P0Ipi:
+SymmetricIpi:
+ stdCall _HalBeginSystemInterrupt,<IPI_LEVEL,13 + PRIMARY_VECTOR_BASE,esp>
+; or eax, eax NOTNOW: To add lazy irql support, this
+; jz short KsiSpuripus needs to be added - and IpiWithNoPic
+; would need fixed as well
+
+Ksi30:
+; Pass Null ExceptionFrame
+; Pass TrapFrame to Ipi service rtn
+ stdCall _KiIpiServiceRoutine, <ebp,0>
+
+Hi90: call fs:[PcHal.PcrIpiSecondLevelDispatch]
+
+;
+; Do interrupt exit processing
+;
+
+ INTERRUPT_EXIT ; will return to caller
+
+Hi100:
+ mov esi, eax ; save control register
+ mov edi, edx ; save control port
+
+ cmp byte ptr fs:PcHal.PcrPic, 0 ; A pic on this processor?
+ je short Hi120
+
+ stdCall _HalBeginSystemInterrupt, <IPI_LEVEL,13 + PRIMARY_VECTOR_BASE,esp>
+ jmp short Hi130
+Hi120:
+ stdCall _KeRaiseIrql, <IPI_LEVEL,esp>
+Hi130:
+ test esi, ERR387 ; Interrupt from 387?
+ jz short Hi90 ; No, then unkown exit
+
+ xor al,al
+ out I386_80387_BUSY_PORT, al
+
+ mov eax, esi
+ and eax, NOT ERR387
+ mov edx, edi
+ out dx, al ; clear ERR387
+
+ mov eax, PCR[PcPrcb]
+ cmp byte ptr [eax].PbCpuType, 4 ; Is this a 386?
+ jc short Hi40 ; Yes, then don't check CR0_NE
+
+ mov eax, cr0 ; Is CR0_NE set? If so, then
+ test eax, CR0_NE ; we shouldn't be getting NPX
+ jnz short Hi50 ; interrupts.
+Hi40:
+ stdCall _KiCoprocessorError ; call CoprocessorError handler
+Hi50:
+
+;
+; We did an out to the ProcessorControl port which might have cleared a
+; pending interrupt (PINT) bit. Go process ipi handler just in case.
+;
+ jmp Ksi30
+
+stdENDP _HalpIrq13Handler
+
+
+;++
+;
+; VOID
+; HalpBelizeIrq13Handler (
+; );
+;
+; Routine Description:
+;
+; Same as HalpIrql13Handler, expect specific to the Belize SyetemPro
+;
+; Arguments:
+;
+; None.
+; Interrupt is dismissed
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+ ENTER_DR_ASSIST Hib13_a, Hib13_t
+
+cPublicProc _HalpBelizeIrq13Handler ,0
+ ENTER_INTERRUPT Hib13_a, Hib13_t ; (ebp) -> Trap frame
+
+ push 13 + PRIMARY_VECTOR_BASE ; Vector
+ sub esp, 4 ; space for OldIrql
+
+ stdCall _HalBeginSystemInterrupt,<IPI_LEVEL,13 + PRIMARY_VECTOR_BASE,esp>
+
+ mov dx, SMP_IPI_MPINTx_PORT
+ in al, dx ; read clears pending int
+
+ stdCall _KiIpiServiceRoutine, <ebp,0>
+
+ call fs:[PcHal.PcrIpiSecondLevelDispatch]
+
+
+;
+; Do interrupt exit processing
+;
+
+ INTERRUPT_EXIT ; will return to caller
+
+
+stdENDP _HalpBelizeIrq13Handler
+
+;++
+;
+; VOID
+; HalpNoSecondDispatch (
+; VOID
+; )
+;
+; Routine Description:
+;
+; Does nothing
+;--
+cPublicProc _HalpNo2ndDispatch,0
+ stdRET _HalpNo2ndDispatch
+stdENDP _HalpNo2ndDispatch
+
+
+
+;++
+;
+; ULONG
+; FASTCALL
+; HalSystemVectorDispatchEntry (
+; IN ULONG Vector,
+; OUT PKINTERRUPT_ROUTINE **FlatDispatch,
+; OUT PKINTERRUPT_ROUTINE *NoConnection
+; )
+;
+; Routine Description:
+;
+; If TRUE, returns dispatch address for vector; otherwise, IDT dispatch is
+; assumed
+;
+; Arguments:
+;
+; Vector - System Vector to get dispatch address of
+; FlatDispatch - Returned dispatched address for system vector
+; NoConnection - Returned "no connection" dispatch value for system vector
+;
+;--
+
+cPublicFastCall HalSystemVectorDispatchEntry,3
+
+ xor eax, eax ; reutrn FALSE
+
+ cmp ecx, PRIMARY_VECTOR_BASE + SECOND_IPI_DISPATCH
+ jne short hsvexit
+
+ inc eax ; return TRUE
+
+ mov ecx, PCR[PcSelfPcr] ; return FlatDispatch
+ add ecx, PcHal.PcrIpiSecondLevelDispatch
+ mov [edx], ecx
+
+ mov ecx, [esp+4] ; return NoConnection
+ mov [ecx], offset _HalpNo2ndDispatch
+
+hsvexit:
+ fstRET HalSystemVectorDispatchEntry
+fstENDP HalSystemVectorDispatchEntry
+
+
+_TEXT ENDS
+ END
diff --git a/private/ntos/nthals/halsp/i386/spirql.asm b/private/ntos/nthals/halsp/i386/spirql.asm
new file mode 100644
index 000000000..b3249a7e2
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spirql.asm
@@ -0,0 +1,799 @@
+ title "Irql Processing"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; spirql.asm
+;
+; Abstract:
+;
+; SystemPro IRQL
+;
+; This module implements the code necessary to raise and lower i386
+; Irql and dispatch software interrupts with the 8259 PIC.
+;
+; Author:
+;
+; Shie-Lin Tzong (shielint) 8-Jan-1990
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+; John Vert (jvert) 27-Nov-1991
+; Moved from kernel into HAL
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\ix8259.inc
+include i386\kimacro.inc
+include i386\spmp.inc
+ .list
+
+
+ EXTRNP _KeBugCheck,1,IMPORT
+
+ extrn _HalpApcInterrupt:near
+ extrn _HalpDispatchInterrupt:near
+ extrn _HalpSWNonPrimaryClockTick:near
+ extrn _HalpApcInterrupt2ndEntry:NEAR
+ extrn _HalpDispatchInterrupt2ndEntry:NEAR
+ extrn _HalpSWNonPrimaryClockTick2ndEntry:NEAR
+ extrn _KiUnexpectedInterrupt:near
+
+;
+; 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
+
+;
+; Define the constants of Edge level Pic control.
+;
+; Background: Compaq Belize systems have an 8259 per processor and
+; their own private Edge Level control registers (4d0,4d1).
+;
+
+EDGELEVEL_CONTROL_1 equ 4D0H
+EDGELEVEL_CONTROL_2 equ 4D1H
+
+;
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+;
+; PICsInitializationString - Master PIC initialization command string
+;
+
+PICsInitializationString dw PIC1_PORT0
+
+;
+; Master PIC initialization command
+;
+
+ db ICW1_ICW + ICW1_EDGE_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_EDGE_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
+
+PS2PICsInitializationString 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
+ dd 00000000000000000000000000000000B ; irql 1
+ dd 00000000000000000000000000000000B ; irql 2
+ dd 00000000000000000000000000000000B ; irql 3
+ dd 00000000000000000000000000000000B ; 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
+ dd 11111111111111111100000000000000B ; irql 13
+ dd 11111111111111111100000000000000B ; irql 14
+ dd 11111111111111111101000000000000B ; irql 15
+ dd 11111111111111111101100000000000B ; irql 16
+ dd 11111111111111111101110000000000B ; irql 17
+ dd 11111111111111111101111000000000B ; irql 18
+ dd 11111111111111111101111000000000B ; irql 19
+ dd 11111111111111111101111010000000B ; irql 20
+ dd 11111111111111111101111011000000B ; irql 21
+ dd 11111111111111111101111011100000B ; irql 22
+ dd 11111111111111111101111011110000B ; irql 23
+ dd 11111111111111111101111011111000B ; irql 24
+ dd 11111111111111111101111011111000B ; irql 25
+ dd 11111111111111111101111011111010B ; irql 26
+ dd 11111111111111111101111111111010B ; irql 27
+ dd 11111111111111111101111111111011B ; irql 28
+ dd 11111111111111111111111111111011B ; irql 29
+ dd 11111111111111111111111111111011B ; irql 30
+ dd 11111111111111111111111111111011B ; irql 31
+; |
+; 32109876543210
+; |
+; + - Raise SystemPros IPI vector (13)
+; to IPI_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:_HalpSWNonPrimaryClockTick ; irql 4
+
+;
+; Use this table if there is a machine state frame on stack already
+;
+
+ public SWInterruptHandlerTable2
+SWInterruptHandlerTable2 label dword
+ dd offset FLAT:_KiUnexpectedInterrupt ; irql 0
+ dd offset FLAT:_HalpApcInterrupt2ndEntry ; irql 1
+ dd offset FLAT:_HalpDispatchInterrupt2ndEntry ; irql 2
+ dd offset FLAT:_KiUnexpectedInterrupt ; irql 3
+ dd offset FLAT:_HalpSWNonPrimaryClockTick2ndEntry ; irql 4
+
+;
+; 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
+
+
+;
+; Only P0 has its Edge Level masks on port 4d0 and port 4d1 setup
+; correctly. We hold the P0 values here for the other processors.
+;
+ align 4
+ public _SpP0EdgeLevelValue
+_SpP0EdgeLevelValue dw 0
+
+_DATA ENDS
+
+ page ,132
+ subttl "Raise Irql"
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME 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 - the addr of a variable which old irql should be stored
+;
+;--
+
+cPublicFastCall KfRaiseIrql,1
+cPublicFpo 0,1
+
+ pushfd ; save caller's eflags
+ mov al, fs:PcIrql ; get current irql
+
+if DBG
+ cmp al,cl ; old > new?
+ jbe short Kri99 ; no, we're OK
+ movzx eax, al
+ movzx ecx, cl
+ push ecx ; put new irql where we can find it
+ push eax ; put old irql where we can find it
+ mov byte ptr fs:PcIrql,0 ; avoid recursive error
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL>
+align 4
+Kri99:
+endif
+ cli ; disable interrupt
+
+ cmp byte ptr fs:PcHal.PcrPic, 0
+ je PxRaiseIrql ; dispatch according to processor
+
+@@:
+; P0RaiseIrql
+ cmp cl,DISPATCH_LEVEL ; software level?
+ mov fs:PcIrql, cl ; set the new irql
+ jbe short kri10 ; go skip setting 8259 hardware
+
+ movzx ecx, cl
+ mov dl, al ; Save OldIrql
+ mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
+ or eax, fs:PcIDR ; mask irqs which are disabled
+ SET_8259_MASK ; set 8259 masks
+ mov al, dl ; Restore OldIrql
+
+kri10: popfd ; restore flags (including interrupts)
+ fstRET KfRaiseIrql
+
+
+align 4
+PxRaiseIrql:
+;
+; Even though SystemPro P2 cannot touch 8259 ports, we still need to
+; make sure interrupts are off when requested to raise to IPI_LEVEL or
+; above.
+;
+ cmp cl, IPI_LEVEL ; If raise to IPI_LEVEL?
+ jb short @f ; if ne, don't edit flag
+
+ and dword ptr [esp], NOT EFLAGS_IF ; clear IF bit in return EFLAGS
+align 4
+@@:
+ mov fs:PcIrql, cl ; set the new irql
+ popfd ; restore flags (including interrupts)
+ fstRET KfRaiseIrql
+
+
+fstENDP KfRaiseIrql
+
+
+;++
+;
+; VOID
+; KIRQL
+; KeRaiseIrqlToDpcLevel (
+; )
+;
+; Routine Description:
+;
+; This routine is used to raise IRQL to DPC level.
+; The APIC TPR is used to block all lower-priority HW interrupts.
+;
+; Arguments:
+;
+; Return Value:
+;
+; OldIrql - the addr of a variable which old irql should be stored
+;
+;--
+
+cPublicProc _KeRaiseIrqlToDpcLevel,0
+cPublicFpo 0, 0
+
+ mov ecx, DISPATCH_LEVEL
+ jmp @KfRaiseIrql
+
+stdENDP _KeRaiseIrqlToDpcLevel
+
+
+;++
+;
+; VOID
+; KIRQL
+; KeRaiseIrqlToSynchLevel (
+; )
+;
+; Routine Description:
+;
+; This routine is used to raise IRQL to SYNC level.
+; The APIC TPR is used to block all lower-priority HW interrupts.
+;
+; Arguments:
+;
+; Return Value:
+;
+; OldIrql - the addr of a variable which old irql should be stored
+;
+;--
+
+cPublicProc _KeRaiseIrqlToSynchLevel,0
+
+ mov ecx, SYNCH_LEVEL
+ jmp @KfRaiseIrql
+
+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.
+;
+; Arguments:
+;
+; (cl) = NewIrql - the new irql to be set.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicFastCall KfLowerIrql,1
+
+ pushfd ; save caller's eflags
+if DBG
+ cmp cl,fs:PcIrql
+ jbe short Kli99
+ movzx ecx, cl
+ push ecx ; new irql for debugging
+ push fs:PcIrql ; old irql for debugging
+ mov byte ptr fs:PcIrql,HIGH_LEVEL ; avoid recursive error
+ stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL>
+align 4
+Kli99:
+endif
+ cli
+
+ cmp byte ptr fs:PcHal.PcrPic, 0
+ je PxLowerIrql ; dispatch according to processor
+
+@@:
+; P1LowerIrql:
+ cmp byte ptr fs:PcIrql,DISPATCH_LEVEL ; Software level?
+ jbe short kli02 ; yes, go skip setting 8259 hw
+
+ movzx ecx, cl
+ mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
+ or eax, fs:PcIDR ; mask irqs which are disabled
+ SET_8259_MASK ; set 8259 masks
+
+kli02: mov fs:PcIrql, cl ; set the new irql
+ mov eax, fs:PcIRR ; get SW interrupt request register
+ mov al, SWInterruptLookUpTable[eax] ; get the highest pending
+ ; software interrupt level
+ cmp al, cl ; Is highest SW int level > irql?
+ ja short Kli10 ; yes, go simulate interrupt
+
+ popfd ; restore flags, including ints
+ fstRET KfLowerIrql
+
+; When we come to Kli10, (eax) = soft interrupt index
+
+align 4
+Kli10:
+ call SWInterruptHandlerTable[eax*4] ; SIMULATE INTERRUPT
+ ; to the appropriate handler
+ popfd
+ fstRET KfLowerIrql
+
+PxLowerIrql:
+ cmp cl, IPI_LEVEL ; If lower to IPI_LEVEL?
+ ; cy = yes
+ sbb edx, edx ; edx = 0 (nc), -1 (cy)
+ and edx, EFLAGS_IF
+ or dword ptr [esp], edx ; set EFLAG_IF if irql<IPI_LEVEL
+
+ mov fs:PcIrql, cl ; set the new irql
+ mov eax, fs:PcIRR ; get SW interrupt request register
+ mov al, SWInterruptLookUpTable[eax] ; get the highest pending
+ ; software interrupt level
+ cmp al, cl ; Is highest SW int level > irql?
+ ja short Kli10 ; yes, go simulate interrupt
+
+ popfd ; restore flags, including ints
+ fstRET KfLowerIrql
+
+fstENDP KfLowerIrql
+
+;++
+;
+; VOID
+; HalpEndSystemInterrupt
+; IN KIRQL NewIrql,
+; IN ULONG Vector
+; )
+;
+; 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.
+;
+; Arguments:
+;
+; NewIrql - the new irql to be set.
+;
+; Vector - Vector number of the interrupt
+;
+; Note that esp+8 is the beginning of interrupt/trap frame and upon
+; entering to this routine the interrupts are off.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+HeiNewIrql equ [esp + 4]
+
+cPublicProc _HalEndSystemInterrupt ,2
+
+ xor ecx, ecx
+ mov cl, byte ptr HeiNewIrql ; get new irql value
+
+ cmp byte ptr fs:PcHal.PcrPic, 0
+ je short Hei02
+
+; P1LowerIrql:
+ cmp byte ptr fs:PcIrql, DISPATCH_LEVEL ; Software level?
+ jbe short Hei02 ; yes, go skip setting 8259 hw
+
+ mov eax, KiI8259MaskTable[ecx*4]; get pic masks for the new irql
+ or eax, fs:PcIDR ; mask irqs which are disabled
+ SET_8259_MASK ; set 8259 masks
+
+;
+; Unlike KeLowerIrql, we don't check if the the irql is lowered to
+; below IPI level and enable interrupt for second processor. This is because
+; the correct interrupt flag is already stored in the TsEflags of Trap frame.
+;
+
+align 4
+Hei02: mov fs:PcIrql, cl ; set the new irql
+ mov eax, fs:PcIRR ; get SW interrupt request register
+ mov al, SWInterruptLookUpTable[eax] ; get the highest pending
+ ; software interrupt level
+ cmp al, cl ; Is highest SW int level > irql?
+ ja short Hei10 ; yes, go simulate interrupt
+
+ stdRET _HalEndSystemInterrupt ; cRetURN
+
+; When we come to Kli10, (eax) = soft interrupt index
+align 4
+Hei10: add esp, 12
+ jmp SWInterruptHandlerTable2[eax*4] ; SIMULATE INTERRUPT
+ ; to the appropriate handler
+stdENDP _HalEndSystemInterrupt
+
+;++
+;
+; VOID
+; HalpEndSoftwareInterrupt
+; IN KIRQL NewIrql,
+; )
+;
+; Routine Description:
+;
+; This routine is used to lower IRQL from software interrupt
+; level 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.
+;
+; Arguments:
+;
+; NewIrql - the new irql to be set.
+;
+; Note that esp+8 is the beginning of interrupt/trap frame and upon
+; entering to this routine the interrupts are off.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+HesNewIrql equ [esp + 4]
+
+cPublicProc _HalpEndSoftwareInterrupt,1
+cPublicFpo 1,0
+ mov ecx, [esp+4]
+ fstCall KfLowerIrql
+ cli
+ 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
+ movzx eax,byte ptr fs:PcIrql ; Current irql is in the PCR
+ stdRET _KeGetCurrentIrql
+stdENDP _KeGetCurrentIrql
+
+
+;++
+;
+; 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
+
+ ;
+ ; Raising to HIGH_LEVEL disables interrupts for the SystemPro HAL
+ ;
+
+ mov ecx, HIGH_LEVEL
+ fstCall KfRaiseIrql
+ stdRET _HalpDisableAllInterrupts
+
+stdENDP _HalpDisableAllInterrupts
+
+
+
+ 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
+
+ pushfd
+ 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
+
+ ;
+ ; If P0 then squirrel away 4d0 and 4d1 for the other processor to use.
+ ;
+
+ cmp byte ptr fs:PcHal.PcrNumber, 0 ; Is this processor 0
+ jne short Hip16
+
+ mov dx, EDGELEVEL_CONTROL_2 ; Yes then save 4d0-4d1
+ in al, dx
+ shl eax, 8
+ mov dx, EDGELEVEL_CONTROL_1
+ in al, dx
+ mov _SpP0EdgeLevelValue, ax
+
+ jmp short Hip18
+
+ ;
+ ; If not P0 then program 4d0 and 4d1 to the values P0 used for them!
+ ;
+Hip16:
+ mov ax, _SpP0EdgeLevelValue
+ mov dx, EDGELEVEL_CONTROL_1
+ out dx, al
+ inc edx
+ shr eax, 8
+ mov dx, EDGELEVEL_CONTROL_2
+ out dx, al
+
+Hip18:
+
+ pop esi ; restore caller's esi
+ popfd ; restore interrupts
+ stdRET _HalpInitializePICs
+stdENDP _HalpInitializePICs
+
+
+_TEXT ends
+ end
diff --git a/private/ntos/nthals/halsp/i386/spmp.inc b/private/ntos/nthals/halsp/i386/spmp.inc
new file mode 100644
index 000000000..b50de847a
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spmp.inc
@@ -0,0 +1,258 @@
+;/*
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; spmp.inc
+;
+; Abstract:
+;
+; SystemPro MP include file
+;
+; Author:
+;
+;--
+
+if 0 ; */
+
+// ---------------------------------------------------
+// C section
+// ---------------------------------------------------
+
+#ifndef SPMPC_INCLUDE
+#define SPMPC_INCLUDE 1
+
+//
+// All Values in the C section must match with the assembly.
+//
+
+#define SMP_SYSPRO1 1 // Original SystemPro and Compatibles
+#define SMP_SYSPRO2 2 // SystemPro XL and ProLiant 2000,4000,4500
+#define SMP_ACER 3 // Acer SystemPro Style
+
+#define SP_M8259 1 // Each processor has 8259 set
+#define SP_SMPDEVINTS 2 // Distribute device ints amoung all processors
+#define SP_SMPCLOCK 4 // Clock is broadcast to each processor
+
+#define SECOND_IPI_DISPATCH 24 // Vector offset for second level ipi dispatch
+
+#endif
+
+/*
+endif
+
+; ---------------------------------------------------
+; Assembly section
+; ---------------------------------------------------
+
+;*****************************
+; Compaq MP defines
+;
+
+RESET_WO_EOI equ 00ah ; Reset with out EOI
+WarmResetVector equ 467h ; warm reset vector in ROM data segment
+
+; Multi-Processor Control Register I/O Locations:
+PRODUCT_ID_OFFSET equ 0C80h
+EBC_OFFSET equ 0C84h
+PCR_OFFSET equ 0C6Ah
+
+PROC_ID_PORT equ 0c70h ; who am I
+
+; Multi-Processor Control Register Bit Definitions:
+INTDIS equ 080h ; INTDIS bit in Processor control register
+PINT equ 040h ; PINT bit in Processor control register
+ERR387 equ 020h ; 387ERR bit in Processor control register
+FLUSH equ 010h ; flushes the processor's cache
+SLEEP equ 008h ; puts processor in HOLD
+CACHEON equ 004h ; enables cache
+PRES387 equ 002h ; 387PRES bit in Processor control register
+RESET equ 001h ; RESET processor
+
+;*****************************
+; end of list
+
+
+;
+; The kernel leaves some space (64 byte) of the PCR for the HAL to use
+; as it needs. Currently this space is used for some efficiency in
+; some of the MP specific code and is highly implementation
+; dependant.
+;
+
+
+PcrE struc
+ PcrNumber db 0 ; Processor's number
+ PcrPic db 0 ; 1 if processor has an 8259s
+ PcrIpiClockTick db 0 ; Emulate a clock tick
+ db 0 ; (alignment)
+ PcrIpiType dd 0 ; How to handle different IPI implementations
+ PcrIpiSecondLevelDispatch dd 0 ; To exit IPI interrupt
+ PcrControlPort dw 0 ; Processor's control port
+ PcrPerfSkew dd 0 ; Skew to apply to this P perf counter
+PcrE ends
+
+SECOND_IPI_DISPATCH equ 24 ; Vector offset for second level ipi dispatch
+
+SWClockTick equ 10h ; Software level of emulated clock tick
+SWCLOCK_LEVEL equ 4 ; Software level of emulated clock tick
+
+cr equ 0ah
+lf equ 0dh
+
+SMP_SYSPRO1 equ 1
+SMP_SYSPRO2 equ 2
+SMP_ACER equ 3
+
+;
+; 8259PerProcessorMode bit mask
+;
+
+SP_M8259 equ 1 ; Each processor has 8259 set
+SP_SMPDEVINTS equ 2 ; Distribute device ints amoung all processors
+SP_SMPCLOCK equ 4 ; Clock is broadcast to each processor
+
+
+
+;*****************************
+; Compaq SMP defines
+;
+
+;+++EQU+++ Belize Specific defines (Symmetrical SystemProII).
+;
+; INT/MPx local registers, and their initial value. Registers are offseted
+; by 2 (except INT13-INT14) and there is 15 registers (INT does not have one,
+; it is used for cascade).
+;
+
+TIME_DELAY equ 0ffffffh
+
+SMP_MAX_PROCESSORS equ 8 ;BELIZE/PHOENIX supports 8 cpus MAX
+
+SMP_MPINT0 equ 0cb0h
+SMP_MPINT1 equ 0cb2h
+;SMP_MPINT2 **** DOESNOT EXIST ****
+SMP_MPINT3 equ 0cb4h
+SMP_MPINT4 equ 0cb6h
+SMP_MPINT5 equ 0cb8h
+SMP_MPINT6 equ 0cbah
+SMP_MPINT7 equ 0cbch
+SMP_MPINT8 equ 0cbeh
+SMP_MPINT9 equ 0cc0h
+SMP_MPINT10 equ 0cc2h
+SMP_MPINT11 equ 0cc4h
+SMP_MPINT12 equ 0cc6h
+SMP_MPINT13 equ 0cc8h
+SMP_MPINT14 equ 0ccch
+SMP_MPINT15 equ 0cceh
+
+SMP_IPI_MASKPORT equ 0cd0h ; IntrMask and IntrPort..DWORD
+SMP_IPI_PROG_INTRPORT equ 0cd3h ; IntrPort
+
+; IRQ assigned to IPI_LEVEL. It could be any of the above IRQs.
+;
+SMP_IPI_VECTOR equ 13 ; IRQ13 assigned to IPI
+SMP_IPI_MPINTx_PORT equ SMP_MPINT13 ; IRQ13
+
+
+; SymmetricalMpMode registers (belize mode).
+;
+SMP_MODE_PORT equ 0c67h ; Global: ModeSelectPort
+SMP_CSR_PORT equ 0c6ah ; Local: ControlStatusRegPort
+SMP_WHOAMI_PORT equ 0c70h ; Local: Whoami Port
+SMP_INDEX_PORT equ 0c74h ; Global: Index Port
+SMP_ASSIGNMENT_PORT equ 0c71h ; Global: cpu assignment port
+
+
+; Supported Modes on Symmetrical SysPro ...
+;
+SMP_ASYMMETRICAL_MODE equ 0 ; SysPro compatible mode
+SMP_SYMMETRICAL_MODE equ 1 shl 5 ; Belize mode
+
+
+; PCR, ProcessorControl/StatusRegister Port bit pattern.
+;
+SMP_CTRL_SLEEP equ 1 shl 0 ; 1: assert sleep to CPU
+SMP_CTRL_AWAKE equ 1 shl 1 ; 1: Awake processor
+SMP_CTRL_CACHEON equ 1 shl 2 ; 1: enable intr/extr cache
+SMP_CTRL_CACHEOFF equ 1 shl 3 ; 1: disable intr/extr cache
+SMP_CTRL_FLUSH equ 1 shl 4 ; 1: flush 486 secondary cache
+SMP_CTRL_RESET equ 1 shl 5 ; 1: reset CPU
+
+SMP_RESET_CPU equ (SMP_CTRL_RESET+SMP_CTRL_AWAKE+SMP_CTRL_CACHEON)
+
+SMP_STAT_NCPIN equ 1 shl 1 ; NCP installed, always 1
+SMP_STAT_CACHEON equ 1 shl 2 ; 0: in/ex cache off, 1: on
+SMP_STAT_SLEEP equ 1 shl 3 ; 0: awake, 1: Sleeping
+SMP_STAT_NCPERR equ 1 shl 5 ; 0: no NCP error, 1:NCP error
+
+
+SMP_INTx_SET_PINT equ 1 shl 0
+SMP_INTx_CLR_PINT equ 1 shl 1
+SMP_INTx_ENABLE equ 1 shl 2
+SMP_INTx_DISABLE equ 1 shl 3
+
+
+;* MP INT13 Extended Control/Status Port...
+;
+SMP_MPINT13PORT equ 0cc9h
+
+SMP_ENBL_NCPERR equ 1 shl 0
+SMP_DSBL_NCPERR equ 1 shl 1
+SMP_ENBL_DMACHAIN equ 1 shl 2
+SMP_DSBL_DMACHAIN equ 1 shl 3
+SMP_ENBL_MCERR equ 1 shl 4
+SMP_DSBL_MCERR equ 1 shl 5
+
+
+;
+; The following macro performs an indexed IO read to the specified
+; IO address on the specified processor. The result of the read is
+; placed in the 'al' register.
+;
+; Warning: Assumes 8254 lock is owned
+;
+INDEXED_IO_READ macro cpu,ioaddress
+ push edx
+ push eax
+ mov dx, SMP_INDEX_PORT
+
+ mov al, cpu
+ out dx, al ;select cpu
+
+ inc dx
+ mov ax, ioaddress
+ out dx, ax ;select cpu's IO address to read from
+
+ add dx, 2
+ pop eax
+ in al, dx ;read from the target cpu's IO address
+ pop edx
+ jmp $+2
+endm ;INDEXED_IO_READ
+
+
+;
+; The following macro performs an indexed IO write to the specified
+; IO address on the specified processor.
+;
+INDEXED_IO_WRITE macro cpu,ioaddress,data
+ push edx
+ push eax
+
+ mov dx, SMP_INDEX_PORT
+ mov al, data
+ shl eax, 16
+
+ mov ax, ioaddress
+ shl eax, 8
+
+ mov al, cpu
+ out dx, eax
+
+ pop eax
+ pop edx
+ jmp $+2
+endm ;INDEXED_IO_WRITE
+;*/
diff --git a/private/ntos/nthals/halsp/i386/spprofil.asm b/private/ntos/nthals/halsp/i386/spprofil.asm
new file mode 100644
index 000000000..4933bb8b2
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spprofil.asm
@@ -0,0 +1,453 @@
+ title "Interval Clock Interrupt"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; spprofil.asm
+;
+; Abstract:
+;
+; This module implements the code necessary to initialize,
+; field and process the profile 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.
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+include mac386.inc
+include i386\ix8259.inc
+include i386\ixcmos.inc
+ .list
+
+ EXTRNP _DbgBreakPoint,0,IMPORT
+ EXTRNP _KeProfileInterrupt,1,IMPORT
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _HalEndSystemInterrupt,2
+ EXTRNP _HalBeginSystemInterrupt,3
+ 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
+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
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+RegisterAProfileValue db 00101000B ; default interval = 3.90625 ms
+
+align 4
+ProfileIntervalTable dd 1221 ; unit = 100 ns
+ dd 2441
+ dd 4883
+ dd 9766
+ dd 19531
+ dd 39063
+ dd 78125
+ dd 156250
+ dd 312500
+ dd 625000
+ dd 1250000
+ dd 2500000
+ dd 5000000
+ dd 5000000 OR 80000000H
+
+ProfileIntervalInitTable db 00100011B
+ db 00100100B
+ db 00100101B
+ db 00100110B
+ db 00100111B
+ db 00101000B
+ db 00101001B
+ db 00101010B
+ db 00101011B
+ db 00101100B
+ db 00101101B
+ db 00101110B
+ db 00101111B
+ db 00101111B
+
+;
+; The following array stores the per microsecond loop count for each
+; central processor.
+;
+
+HalpProfileInterval dd -1
+HalpProfilingStopped dd 1
+
+;
+; HALs wishing to reuse the code in this module should set the HAL
+; global variable IxProfileVector to their profile vector.
+;
+ public _IxProfileVector
+_IxProfileVector dd PROFILE_VECTOR
+
+_DATA ends
+
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; HalStartProfileInterrupt(
+; IN ULONG Reserved
+; );
+;
+; Routine Description:
+;
+; What we do here is change the interrupt
+; rate from the slowest thing we can get away with to the value
+; that's been KeSetProfileInterval
+;
+; All processors will run this routine, but it doesn't hurt to have
+; each one reinitialize the CMOS, since none of them will be let go
+; from the stall until they all finish.
+;
+;--
+
+cPublicProc _HalStartProfileInterrupt ,1
+
+;
+; On the SystemPro there is only one profile device, so starting/stopping
+; is only done from one processor.
+;
+; Note: This code uses PbNumber so it doesn't touch any SystemPro specific
+; PCR value (so the code can be re-used by other hals)
+;
+
+ mov eax, PCR[PcPrcb]
+ cmp byte ptr [eax].PbNumber, 0
+ jne epi_exit
+
+
+; Mark profiling as active
+;
+
+ mov HalpProfilingStopped, 0
+
+;
+; Set the interrupt rate to what is actually needed
+;
+ stdCall _HalpAcquireCmosSpinLock ; intr disabled
+
+ mov al, RegisterAProfileValue
+ shl ax, 8
+ mov al, 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
+epi_exit:
+ stdRET _HalStartProfileInterrupt
+
+stdENDP _HalStartProfileInterrupt
+
+
+
+;++
+;
+; HalStopProfileInterrupt(
+; IN ULONG Reserved
+; );
+;
+; Routine Description:
+;
+; What we do here is change the interrupt
+; rate from the high profiling rate to the slowest thing we
+; can get away with for PerformanceCounter rollover notification.
+;
+;--
+
+cPublicProc _HalStopProfileInterrupt ,1
+
+;
+; On the SystemPro there is only one profile device, so starting/stopping
+; is only done from one processor.
+;
+; Note: This code uses PbNumber so it doesn't touch any SystemPro specific
+; PCR value (so the code can be re-used by other hals)
+;
+
+ mov eax, PCR[PcPrcb]
+ cmp byte ptr [eax].PbNumber, 0
+ jne dpi_exit
+
+;
+; Turn off profiling hit computation and profile interrupt
+;
+
+;
+; Don't clobber the Daylight Savings Time bit in register B, because we
+; stash the LastKnownGood "environment variable" there.
+
+ stdCall _HalpAcquireCmosSpinLock ; intr disabled
+ 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 profiling interrupt
+ mov HalpProfilingStopped, 1
+ stdCall _HalpReleaseCmosSpinLock
+dpi_exit:
+ stdRET _HalStopProfileInterrupt
+
+stdENDP _HalStopProfileInterrupt
+
+;++
+; ULONG
+; HalSetProfileInterval (
+; ULONG Interval
+; );
+;
+; Routine Description:
+;
+; This procedure sets the interrupt rate (and thus the sampling
+; interval) for the profiling interrupt.
+;
+; If profiling is active (KiProfilingStopped == 0) the actual
+; hardware interrupt rate will be set. Otherwise, a simple
+; rate validation computation is done.
+;
+; Arguments:
+;
+; (TOS+4) - Interval in 100ns unit.
+;
+; Return Value:
+;
+; Interval actually used by system.
+;--
+
+cPublicProc _HalSetProfileInterval ,1
+
+ mov edx, [esp+4] ; [edx] = interval in 100ns unit
+ and edx, 7FFFFFFFh ; Remove highest bit.
+ mov ecx, 0 ; index = 0
+
+Hspi00:
+ mov eax, ProfileIntervalTable[ecx * 4]
+ cmp edx, eax ; if request interval < suport interval
+ jbe short Hspi10 ; if be, find supported interval
+ inc ecx
+ jmp short Hspi00
+
+Hspi10:
+ and eax, 7FFFFFFFh ; remove highest bit from supported interval
+ jecxz short Hspi20 ; If first entry then use it
+
+ push esi ; See which is closer to requested
+ mov esi, eax ; rate - current entry, or preceeding
+ sub esi, edx
+
+ sub edx, ProfileIntervalTable[ecx * 4 - 4]
+ cmp esi, edx
+ pop esi
+ jc short Hspi20
+
+ dec ecx ; use preceeding entry
+ mov eax, ProfileIntervalTable[ecx * 4]
+
+Hspi20:
+ push eax ; save interval value
+ mov al, ProfileIntervalInitTable[ecx]
+ mov RegisterAProfileValue, al
+ test HalpProfilingStopped,-1
+ jnz short Hspi90
+
+ stdCall _HalStartProfileInterrupt,<0> ; Re-start profile interrupt
+ ; with the new interval
+
+Hspi90: pop eax
+ stdRET _HalSetProfileInterval ; (eax) = cReturn interval
+
+stdENDP _HalSetProfileInterval
+
+ page ,132
+ subttl "System Profile Interrupt"
+;++
+;
+; Routine Description:
+;
+; This routine is entered as the result of a profile interrupt.
+; Its function is to dismiss the interrupt, raise system Irql to
+; PROFILE_LEVEL and transfer control to
+; the standard system routine to process any active profiles.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+; Does not return, jumps directly to KeProfileInterrupt, which returns
+;
+; Sets Irql = PROFILE_LEVEL and dismisses the interrupt
+;
+;--
+ ENTER_DR_ASSIST Hpi_a, Hpi_t
+
+cPublicProc _HalpProfileInterrupt ,0
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT Hpi_a, Hpi_t
+
+;
+; (esp) - base of trap frame
+;
+; HalBeginSystemInterrupt must be called before any sti's
+;
+;
+
+ push _IxProfileVector
+ sub esp, 4 ; allocate space to save OldIrql
+ stdCall _HalBeginSystemInterrupt, <PROFILE_LEVEL,_IxProfileVector,esp>
+
+ or al,al ; check for spurious interrupt
+ jz short Hpi100
+
+;
+; If profiling not enabled, then don't ack device or count this interrupt.
+; (this occurs during bootup when other processors sync PcStallScaleFactor)
+;
+ cmp HalpProfilingStopped,0
+ jne short Hpi90
+
+;
+; On the SystemPro there is only one profile device, so the CMOS is only
+; EOIed once.
+;
+; Note: This code uses PbNumber so it doesn't touch any SystemPro specific
+; PCR value (so the code can be re-used by other hals)
+;
+ mov eax, PCR[PcPrcb]
+ cmp byte ptr [eax].PbNumber, 0
+ jne short _HalpProfileInterrupt2ndEntry@0
+
+
+;
+; 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
+if DBG
+Hpi10: test al, 80h
+ jz short Hpi15
+ mov al,0CH ; Register C
+ CMOS_READ ; Read to initialize
+ jmp short Hpi10
+Hpi15:
+endif ; DBG
+
+ stdCall _HalpReleaseCmosSpinLock
+
+; This entry point is provided for symmetric multiprocessor HALs.
+; Since it only makes sense for one processor to clear the CMOS,
+; all other processors can instead jmp into this entry point.
+;
+
+ align 4
+ public _HalpProfileInterrupt2ndEntry@0
+_HalpProfileInterrupt2ndEntry@0:
+
+ stdCall _KeProfileInterrupt,<ebp> ; (ebp) = trap frame
+
+Hpi90:
+ INTERRUPT_EXIT
+
+Hpi100:
+ add esp, 8 ; spurious, no EndOfInterrupt
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+stdENDP _HalpProfileInterrupt
+
+
+_TEXT ends
+
+ end
diff --git a/private/ntos/nthals/halsp/i386/spreboot.asm b/private/ntos/nthals/halsp/i386/spreboot.asm
new file mode 100644
index 000000000..af936fee1
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spreboot.asm
@@ -0,0 +1,151 @@
+ title "SystemPro reboot"
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; spreboot.asm
+;
+;Abstract:
+;
+; SystemPro reboot code.
+;
+;Author:
+;
+; Ken Reneris (kenr) 13-Jan-1992
+;
+;Revision History:
+;
+;--
+.386p
+ .xlist
+
+include hal386.inc
+include i386\kimacro.inc
+include i386\ix8259.inc
+include callconv.inc ; calling convention macros
+include i386\spmp.inc
+
+ EXTRNP _HalRequestIpi,1
+ EXTRNP _KeStallExecutionProcessor,1
+
+ extrn _SpProcessorControlPort:WORD
+ extrn _SpCpuCount:BYTE
+ extrn _SpType:BYTE
+ extrn _HalpProcessorPCR:DWORD
+
+
+;
+; Defines to let us diddle the CMOS clock and the keyboard
+;
+
+CMOS_CTRL equ 70h
+CMOS_DATA equ 71h
+
+KEYB_RESET equ 0feh
+KEYB_PORT equ 64h
+
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE' ; Start 32 bit code
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; VOID
+; HalpResetAllProcessors (
+; VOID
+; );
+;
+;Routine Description:
+;
+; Called at last phase of reboot code.
+;
+; Some SystemPro clones do not reboot properly by having the keyboard
+; issue a reset. (The bootup roms do not reset the other processors
+; properly).
+;
+; To work around this, we attempt to use P0 to halt all the other
+; processors before reseting the computer.
+;
+; Note: P0 may not respond to an IPI if it's stuck or in the debugger.
+; In this case we will just use the current processor to reset the
+; computer. This will not work on every machine, but the machine
+; was in some sort of crashed state to begin with. (it does work
+; on all compaq SystemPros).
+;
+; N.B.
+;
+; will not return
+;
+;--
+
+cPublicProc _HalpResetAllProcessors, 0
+
+;
+; Belize SystemPros can not halt processors in the same manner; however
+; simply resetting the machine via the keyboard controller works - so
+; skip this code on a belize.
+;
+ cmp _SpType, SMP_SYSPRO2
+ je rb20 ; Belize, just reset
+
+ cmp byte ptr fs:PcHal.PcrNumber, 0 ; boot processor?
+ je HalpRebootNow ; Yes, reset everyone
+
+;
+; Try signal the boot processor to perform the reboot
+;
+ mov ecx, offset FLAT:HalpRebootNow ; Zap P0's IPI handler
+ mov eax, _HalpProcessorPCR[0] ; be reboot function
+ xchg [eax].PcHal.PcrIpiType, ecx
+
+ stdCall _HalRequestIpi,<1> ; Send P0 an IPI
+ stdCall _KeStallExecutionProcessor,<50000> ; Let P0 reboot us
+
+;
+; P0 didn't reboot the machine - just do it with the current processor
+;
+
+HalpRebootNow:
+ xor ecx, ecx
+
+rb10: cmp cl, _SpCpuCount ; halt each processor
+ jae short rb20
+
+
+ mov dx, _SpProcessorControlPort[ecx*2]
+ in al, dx ; (al) = original content of PCP
+ or al, INTDIS ; Disable IPI interrupt
+
+ cmp cl, fs:PcHal.PcrNumber ; cl == currentprocessor?
+ je short @f ; don't halt ourselves
+ or al, SLEEP
+
+ cmp _SpType, SMP_ACER ; On acer MP machines
+ jne short @f ; reset other processors
+ or al, RESET ; (not tested to work on other
+ ; other machines)
+@@: out dx, al
+
+ inc ecx
+ jmp short rb10
+
+rb20:
+ xor eax, eax
+
+;
+; Send the reset command to the keyboard controller
+;
+
+ mov edx, KEYB_PORT
+ mov al, KEYB_RESET
+ out dx, al
+
+@@: hlt
+ jmp @b
+
+stdENDP _HalpResetAllProcessors
+
+_TEXT ENDS
+ END
diff --git a/private/ntos/nthals/halsp/i386/spspin.asm b/private/ntos/nthals/halsp/i386/spspin.asm
new file mode 100644
index 000000000..a5856689e
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spspin.asm
@@ -0,0 +1,382 @@
+if NT_INST
+
+else
+ TITLE "Spin Locks"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+;
+; Module Name:
+;
+; spinlock.asm
+;
+; Abstract:
+;
+; This module implements stubbed x86 spinlock functions for
+; any HAL. Some HALs may implement these function directly
+; to minimize the amount of code required to perform a spinlock.
+; (ie, out Raise & Lower irql in the fall through path)
+;
+; Author:
+;
+; Bryan Willman (bryanwi) 13 Dec 89
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+; Ken Reneris (kenr) 22-Jan-1991
+;--
+
+ PAGE
+
+.486p
+
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+include hal386.inc
+include mac386.inc
+
+ EXTRNP KfRaiseIrql,1,,FASTCALL
+ EXTRNP KfLowerIrql,1,,FASTCALL
+ EXTRNP _KeBugCheck,1,IMPORT
+ EXTRNP _KeSetEventBoostPriority, 2, IMPORT
+ EXTRNP _KeWaitForSingleObject,5, IMPORT
+
+ifdef NT_UP
+ LOCK_ADD equ add
+ LOCK_DEC equ dec
+else
+ LOCK_ADD equ lock add
+ LOCK_DEC equ lock dec
+endif
+
+
+_TEXT SEGMENT PARA PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
+
+ PAGE
+ SUBTTL "Acquire Kernel Spin Lock"
+;++
+;
+; 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 - pointer to place old irql
+;
+;--
+
+align 16
+cPublicFastCall KfAcquireSpinLock ,1
+cPublicFpo 0,0
+
+
+;
+; On a MP build we raise to dispatch_level
+; and then acquire the spinlock
+;
+
+ push ecx ; Save address of spinlock
+
+ mov ecx, DISPATCH_LEVEL
+ fstCall KfRaiseIrql ; (al) = OldIrql
+
+ pop ecx ; (ecx) -> spinlock
+
+;
+; Attempt to assert the lock
+;
+
+sl10: ACQUIRE_SPINLOCK ecx,<short sl20>
+
+ fstRET KfAcquireSpinLock
+
+;
+; Lock is owned, spin till it looks free, then go get it again.
+;
+
+sl20: SPIN_ON_SPINLOCK ecx,sl10
+
+
+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
+
+
+ PAGE
+ SUBTTL "Release Kernel Spin Lock"
+
+;++
+;
+; 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
+;
+; 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
+
+ifndef NT_UP
+ RELEASE_SPINLOCK ecx ; release it
+endif
+ mov ecx, edx ; (ecx) = NewIrql
+ jmp @KfLowerIrql@4 ; to KeLowerIrql
+
+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
+
+
+_TEXT ends
+
+ENDIF ; NT_INST
+
+ end
diff --git a/private/ntos/nthals/halsp/i386/spsproc.c b/private/ntos/nthals/halsp/i386/spsproc.c
new file mode 100644
index 000000000..ca5074944
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spsproc.c
@@ -0,0 +1,501 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+
+Module Name:
+
+ spsproc.c
+
+Abstract:
+
+ SystemPro Start Next Processor c code.
+
+ This module implements the initialization of the system dependent
+ functions that define the Hardware Architecture Layer (HAL) for an
+ MP Compaq SystemPro
+
+Author:
+
+ Ken Reneris (kenr) 22-Jan-1991
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+
+UCHAR HalName[] = "SystemPro or compatible MP Hal";
+
+ADDRESS_USAGE HalpSystemProIoSpace = {
+ NULL, CmResourceTypePort, InternalUsage,
+ {
+ 0xC70, 1, // WhoAmI
+ 0xC6A, 1, // P0 Processor control register
+ 0xFC6A, 1, // P1 Processor control register
+ 0xFC67, 2, // P1 cache control, interrupt vector
+ 0,0
+ }
+};
+
+ADDRESS_USAGE HalpAcerIoSpace = {
+ NULL, CmResourceTypePort, InternalUsage,
+ {
+ 0xCC67, 2, // P2 cache control, interrupt vector
+ 0xCC6A, 1, // P2 Processor control register
+ 0xDC67, 2, // P3 cache control, interrupt vector
+ 0xDC6A, 1, // P3 Processor control register
+ 0,0
+ }
+};
+
+ADDRESS_USAGE HalpBelizeIoSpace = {
+ NULL, CmResourceTypePort, InternalUsage,
+ {
+ 0xC67, 1, // Mode Select
+ 0xC71, 6, // CPU assignment, reserverd[2], CPU index, address, data
+ 0xCB0, 36, // IRQx Control/Status
+ 0xCC9, 1, // INT13 Extended control/status port
+ 0,0
+ }
+};
+
+
+VOID
+HalpMapCR3 (
+ IN ULONG VirtAddress,
+ IN PVOID PhysicalAddress,
+ IN ULONG Length
+ );
+
+ULONG
+HalpBuildTiledCR3 (
+ IN PKPROCESSOR_STATE ProcessorState
+ );
+
+VOID
+HalpFreeTiledCR3 (
+ VOID
+ );
+
+
+VOID
+HalpNonPrimaryClockInterrupt(
+ VOID
+ );
+
+BOOLEAN
+HalpInitMP (
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+
+VOID HalpInitOtherBuses (VOID);
+VOID HalpInitializePciBus (VOID);
+
+#define LOW_MEMORY 0x000100000
+#define MAX_PT 8
+
+extern VOID StartPx_PMStub(VOID);
+
+#ifdef ALLOC_PRAGMA
+#pragma alloc_text(INIT,HalpInitMP)
+#pragma alloc_text(INIT,HalAllProcessorsStarted)
+#pragma alloc_text(INIT,HalReportResourceUsage)
+#pragma alloc_text(INIT,HalReportResourceUsage)
+#pragma alloc_text(INIT,HalpInitOtherBuses)
+#pragma alloc_text(INIT,HalpFreeTiledCR3)
+#pragma alloc_text(INIT,HalpMapCR3)
+#pragma alloc_text(INIT,HalpBuildTiledCR3)
+#endif
+
+
+ULONG MpCount; // zero based. 0 = 1, 1 = 2, ...
+PUCHAR MpLowStub; // pointer to low memory bootup stub
+PVOID MpLowStubPhysicalAddress; // pointer to low memory bootup stub
+PUCHAR MppIDT; // pointer to physical memory 0:0
+PVOID MpFreeCR3[MAX_PT]; // remember pool memory to free
+
+extern ULONG HalpIpiClock; // bitmask of processors to ipi
+extern UCHAR SpCpuCount;
+extern UCHAR Sp8259PerProcessorMode;
+extern UCHAR SpType;
+extern PKPCR HalpProcessorPCR[];
+
+
+BOOLEAN
+HalpInitMP (
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+/*++
+
+Routine Description:
+ Allows MP initialization from HalInitSystem.
+
+Arguments:
+ Same as HalInitSystem
+
+Return Value:
+ none.
+
+--*/
+{
+ ULONG paddress;
+ ULONG adjust;
+ PKPCR pPCR;
+
+ pPCR = KeGetPcr();
+
+ if (Phase == 0) {
+
+ //
+ // Register the IO space used by the SystemPro
+ //
+
+ HalpRegisterAddressUsage (&HalpSystemProIoSpace);
+ switch (SpType) {
+ case 2:
+ HalpRegisterAddressUsage (&HalpBelizeIoSpace);
+ break;
+ case 3:
+ HalpRegisterAddressUsage (&HalpAcerIoSpace);
+ break;
+ }
+
+#if 0
+ //
+ // Register IPI vector
+ //
+
+ HalpRegisterVector (
+ DeviceUsage,
+ 13,
+ 13 + PRIMARY_VECTOR_BASE,
+ IPI_LEVEL );
+#endif
+
+
+ //
+ // Get pointer to real-mode idt table
+ //
+
+ MppIDT = HalpMapPhysicalMemory (0, 1);
+
+ //
+ // Allocate some low memory for processor bootup stub
+ //
+
+ MpLowStubPhysicalAddress = (PVOID)HalpAllocPhysicalMemory (LoaderBlock,
+ LOW_MEMORY, 1, FALSE);
+
+ if (!MpLowStubPhysicalAddress)
+ return TRUE;
+
+ MpLowStub = (PCHAR) HalpMapPhysicalMemory (MpLowStubPhysicalAddress, 1);
+ MpCount = SpCpuCount-1;
+ return TRUE;
+
+ } else {
+
+ //
+ // Phase 1 for another processor
+ //
+
+
+ if (pPCR->Prcb->Number != 0) {
+ if (Sp8259PerProcessorMode & 1) {
+ //
+ // Each processor has it's own pics - we broadcast profile
+ // interrupts to each processor by enabling it on each
+ // processor
+ //
+
+ HalpInitializeStallExecution( pPCR->Prcb->Number );
+
+ HalpEnableInterruptHandler (
+ DeviceUsage, // Report as device vector
+ V2I (PROFILE_VECTOR), // Bus interrupt level
+ PROFILE_VECTOR, // System IDT
+ PROFILE_LEVEL, // System Irql
+ HalpProfileInterrupt, // ISR
+ Latched );
+
+ } else {
+ //
+ // Without a profile interrupt we can not callibrate
+ // KeStallExecutionProcessor, so we inherrit the value from P0.
+ //
+
+ pPCR->StallScaleFactor = HalpProcessorPCR[0]->StallScaleFactor;
+
+ }
+
+ if (Sp8259PerProcessorMode & 4) {
+ //
+ // Each processor can get it's own clock device - we
+ // program each processor's 8254 and enable to interrupt
+ // on each processor
+ //
+
+ HalpInitializeClock ();
+
+ HalpEnableInterruptHandler (
+ DeviceUsage, // Report as device vector
+ V2I (CLOCK_VECTOR), // Bus interrupt level
+ CLOCK_VECTOR, // System IDT
+ CLOCK2_LEVEL, // System Irql
+ HalpNonPrimaryClockInterrupt, // ISR
+ Latched );
+
+ } else {
+
+ //
+ // This processor doesn't have a clock, so we emulate it by
+ // sending an ipi at clock intervals.
+ //
+
+ HalpIpiClock |= 1 << pPCR->Prcb->Number;
+ }
+
+ }
+ }
+}
+
+
+
+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
+ Eisa // SystemPro's are Eisa machines
+ );
+
+ RtlFreeUnicodeString (&UHalName);
+
+ //
+ // Turn on MCA support if present
+ //
+
+ HalpMcaInit();
+
+ //
+ // Registry is now intialized, see if there are any PCI buses
+ //
+
+ HalpInitializePciBus ();
+}
+
+
+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) MpLowStubPhysicalAddress,
+ MpLowStubPhysicalAddress,
+ 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;
+ }
+}
+
+
+
+VOID
+HalpInitOtherBuses (
+ VOID
+ )
+{
+ // no other buses
+}
diff --git a/private/ntos/nthals/halsp/i386/spsproca.asm b/private/ntos/nthals/halsp/i386/spsproca.asm
new file mode 100644
index 000000000..47b0e6b04
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spsproca.asm
@@ -0,0 +1,373 @@
+ title "MP primitives for Compaq SystemPro"
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; spsproca.asm
+;
+;Abstract:
+;
+; SystemPro Start Next Processor assemble code
+;
+; This module along with mpspro.c implement the code to start
+; off the second processor on the Compaq SystemPro.
+;
+;Author:
+;
+; Ken Reneris (kenr) 12-Jan-1992
+;
+;Revision History:
+;
+;--
+
+
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+include mac386.inc
+include i386\spmp.inc
+ .list
+
+ EXTRNP _HalpBuildTiledCR3,1
+ EXTRNP _HalpFreeTiledCR3,0
+
+ extrn _MppIDT:DWORD
+ extrn _MpLowStub:DWORD
+ extrn _MpLowStubPhysicalAddress:DWORD
+ extrn _MpCount:DWORD
+ extrn _SpProcessorControlPort:WORD
+ extrn _SpType:BYTE
+
+
+;
+; Internal defines and structures
+;
+
+PxParamBlock struc
+ SPx_flag dd ?
+ SPx_TiledCR3 dd ?
+ SPx_P0EBP dd ?
+ SPx_ControlPort dd ?
+ SPx_PB db processorstatelength dup (?)
+PxParamBlock ends
+
+
+_TEXT SEGMENT PARA PUBLIC 'CODE' ; Start 32 bit code
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; 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.
+;
+; 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
+ push ebp ; save ebp
+ mov ebp, esp ;
+
+ sub esp, size PxParamBlock ; Make room for local vars
+
+
+ push esi
+ push edi
+ push ebx
+
+ xor eax, eax
+ mov PxFrame.SPx_flag, eax
+
+ cmp _MpCount, eax
+ jbe snp_exit ; exit FALSE
+
+ mov esi, OFFSET FLAT:StartPx_RMStub
+ mov ecx, StartPx_RMStub_Len
+ mov edi, _MpLowStub ; Copy RMStub to low memory
+ add edi, size PxParamBlock
+ rep movsb
+
+ lea edi, PxFrame.SPx_PB
+ mov esi, pProcessorState
+ mov ecx, processorstatelength ; Copy processorstate
+ rep movsb ; to PxFrame
+
+ stdCall _HalpBuildTiledCR3, <pProcessorState>
+
+ mov PxFrame.SPx_TiledCR3, eax
+ mov PxFrame.SPx_P0EBP, ebp
+
+ mov eax, pLoaderBlock ; lookup processor # we are
+ mov eax, [eax].LpbPrcb ; starting
+ movzx eax, byte ptr [eax].PbNumber
+ movzx edx, _SpProcessorControlPort[eax*2] ; Get processor's control port
+ mov PxFrame.SPx_ControlPort, edx ; Pass it along
+
+ mov ecx, size PxParamBlock ; copy param block
+ lea esi, PxFrame ; to low memory stub
+ mov edi, _MpLowStub
+ 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
+
+ mov ebx, _MppIDT
+ add ebx, WarmResetVector
+
+ cli
+ push dword ptr [ebx] ; Save current vector
+
+ mov eax, _MpLowStubPhysicalAddress
+ shl eax, 12 ; seg:0
+ add eax, size PxParamBlock
+ mov dword ptr [ebx], eax ; start Px here
+
+ cmp _SpType, SMP_SYSPRO2 ; Belize?
+ jne short snp10 ; no, reset normal
+
+ mov dx, SMP_INDEX_PORT
+
+ mov eax, pLoaderBlock ; lookup processor # we are
+ mov eax, [eax].LpbPrcb ; starting
+ movzx eax, byte ptr [eax].PbNumber
+ or eax, (SMP_RESET_CPU shl 24) + (SMP_CSR_PORT shl 8)
+
+ out dx, eax ; issue Belize reset to processor
+ jmp short snp20 ; go wait
+
+snp10:
+ mov edx, PxFrame.SPx_ControlPort ; Control port of target
+ in al, dx ; processor
+ or al, RESET ; assert RESET
+ and al, NOT SLEEP ; wakeup P1
+ out dx, al ; reset P1
+
+snp20: cmp PxFrame.SPx_flag, 0 ; wait for Px to get it's
+ jz snp20 ; info
+
+ pop dword ptr [ebx] ; restore WarmResetVector
+ sti
+
+ stdCall _HalpFreeTiledCR3 ; free memory used for tiled
+ ; CR3
+
+ dec _MpCount ; one less
+ mov eax, 1 ; return TRUE
+
+snp_exit:
+ pop ebx
+ pop edi
+ pop esi
+ mov esp, ebp
+ pop ebp
+ stdRET _HalStartNextProcessor
+
+stdENDP _HalStartNextProcessor
+
+
+_TEXT ends ; end 32 bit code
+
+
+_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_RMStub_Len equ $ - StartPx_RMStub
+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
+
+ cmp _SpType, SMP_SYSPRO2 ; Don't send old SP
+ je short spxpm01 ; style Cache on enable
+
+ ; eax, ebx, edx are still free
+ mov edx, [PxFrame.SPx_ControlPort] ; our control port
+ in al, dx ; Get register
+ and al, NOT INTDIS ; allow PINTs on this proc
+ or al, CACHEON ; turn cache on
+ out dx, al
+spxpm01:
+ inc [PxFrame.SPx_flag] ; Signal p0 that we are
+ ; done with it's data
+ ; 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/halsp/i386/spswint.asm b/private/ntos/nthals/halsp/i386/spswint.asm
new file mode 100644
index 000000000..712d4f45f
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spswint.asm
@@ -0,0 +1,325 @@
+ title "Software Interrupts"
+
+;++
+;
+; Copyright (c) 1992 Microsoft Corporation
+;
+; Module Name:
+;
+; ixswint.asm
+;
+; Abstract:
+;
+; This module implements the software interrupt handlers
+; for x86 machines
+;
+; Author:
+;
+; John Vert (jvert) 2-Jan-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
+ .list
+
+ EXTRNP _KiDeliverApc,3,IMPORT
+ EXTRNP _KiDispatchInterrupt,0,IMPORT
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _HalEndSystemInterrupt,2
+ extrn SWInterruptHandlerTable:dword
+ extrn SWInterruptLookUpTable:byte
+ifdef IRQL_METRICS
+ extrn HalApcSoftwareIntCount:dword
+ extrn HalDpcSoftwareIntCount:dword
+endif
+
+_TEXT$02 SEGMENT DWORD USE32 PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "Request Software Interrupt"
+
+;++
+;
+; VOID
+; FASTCALL
+; HalRequestSoftwareInterrupt (
+; IN KIRQL RequestIrql
+; )
+;
+; Routine Description:
+;
+; This routine is used to request a software interrupt to the
+; system. 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.
+;
+; Arguments:
+;
+; (cl) = RequestIrql - Supplies the request IRQL value
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+; equates for accessing arguments
+;
+
+cPublicFastCall HalRequestSoftwareInterrupt ,1
+cPublicFpo 0, 1
+ mov eax,1
+ shl eax, cl ; convert to mask
+ pushfd ; save interrupt mode
+ cli ; disable interrupt
+ or PCR[PcIRR], eax ; set the request bit
+ mov cl, PCR[PcIrql] ; get current IRQL
+
+ mov eax, PCR[PcIRR] ; get SW interrupt request register
+ mov al, SWInterruptLookUpTable[eax] ; get the highest pending
+ ; software interrupt level
+ cmp al, cl ; Is highest SW int level > irql?
+ jbe KsiExit ; No, jmp ksiexit
+ call SWInterruptHandlerTable[eax*4] ; yes, simulate interrupt
+ ; to the appropriate handler
+KsiExit:
+ popfd ; restore original interrupt mode
+ fstRET HalRequestSoftwareInterrupt
+
+fstENDP HalRequestSoftwareInterrupt
+
+ page ,132
+ subttl "Request Software Interrupt"
+
+;++
+;
+; VOID
+; HalClearSoftwareInterrupt (
+; IN KIRQL RequestIrql
+; )
+;
+; Routine Description:
+;
+; This routine is used to clear a possible pending software interrupt.
+; Support for this function is optional, and allows the kernel to
+; reduce the number of spurious software interrupts it receives/
+;
+; Arguments:
+;
+; (cl) = RequestIrql - Supplies the request IRQL value
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicFastCall HalClearSoftwareInterrupt ,1
+cPublicFpo 0, 0
+
+ mov eax,1
+ shl eax, cl ; convert to mask
+
+ not eax
+ and PCR[PcIRR], eax ; clear pending irr bit
+
+ fstRET HalClearSoftwareInterrupt
+
+fstENDP HalClearSoftwareInterrupt
+
+ page ,132
+ subttl "Dispatch Interrupt"
+;++
+;
+; VOID
+; HalpDispatchInterrupt(
+; VOID
+; );
+;
+; Routine Description:
+;
+; This routine is the interrupt handler for a software interrupt generated
+; at DISPATCH_LEVEL. Its function is to save the machine state, raise
+; Irql to DISPATCH_LEVEL, dismiss the interrupt, and call the DPC
+; delivery routine.
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+ ENTER_DR_ASSIST hdpi_a, hdpi_t
+
+ align dword
+ public _HalpDispatchInterrupt
+_HalpDispatchInterrupt proc
+ifdef IRQL_METRICS
+ lock inc HalDpcSoftwareIntCount
+endif
+;
+; Create IRET frame on stack
+;
+ pop eax
+ pushfd
+ push cs
+ push eax
+
+;
+; Save machine state on trap frame
+;
+
+ ENTER_INTERRUPT hdpi_a, hdpi_t
+.FPO ( FPO_LOCALS+1, 0, 0, 0, 0, FPO_TRAPFRAME )
+
+ public _HalpDispatchInterrupt2ndEntry
+_HalpDispatchInterrupt2ndEntry:
+
+; Save previous IRQL and set new priority level
+
+ push PCR[PcIrql] ; save previous IRQL
+ mov byte ptr PCR[PcIrql], DISPATCH_LEVEL; set new irql
+ btr dword ptr PCR[PcIRR], DISPATCH_LEVEL; clear the pending bit in IRR
+
+;
+; Now it is safe to enable interrupt to allow higher priority interrupt
+; to come in.
+;
+
+ sti
+
+;
+; Go do Dispatch Interrupt processing
+;
+ stdCall _KiDispatchInterrupt
+
+;
+; Do interrupt exit processing
+;
+
+ SOFT_INTERRUPT_EXIT ; will do an iret
+
+_HalpDispatchInterrupt endp
+
+ page ,132
+ subttl "APC Interrupt"
+;++
+;
+; HalpApcInterrupt(
+; VOID
+; );
+;
+; Routine Description:
+;
+; This routine is entered as the result of a software interrupt generated
+; at APC_LEVEL. Its function is to save the machine state, raise Irql to
+; APC_LEVEL, dismiss the interrupt, and call the APC delivery routine.
+;
+; Arguments:
+;
+; None
+; Interrupt is Disabled
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+ ENTER_DR_ASSIST hapc_a, hapc_t
+
+ align dword
+ public _HalpApcInterrupt
+_HalpApcInterrupt proc
+ifdef IRQL_METRICS
+ lock inc HalApcSoftwareIntCount
+endif
+;
+; Create IRET frame on stack
+;
+ pop eax
+ pushfd
+ push cs
+ push eax
+
+;
+; Save machine state in trap frame
+;
+ ENTER_INTERRUPT hapc_a, hapc_t
+.FPO ( FPO_LOCALS+1, 0, 0, 0, 0, FPO_TRAPFRAME )
+
+
+ public _HalpApcInterrupt2ndEntry
+_HalpApcInterrupt2ndEntry:
+
+;
+; Save previous IRQL and set new priority level
+;
+
+ push PCR[PcIrql] ; save previous Irql
+ mov byte ptr PCR[PcIrql], APC_LEVEL ; set new Irql
+ btr dword ptr PCR[PcIRR], APC_LEVEL ; dismiss pending APC
+;
+; Now it is safe to enable interrupt to allow higher priority interrupt
+; to come in.
+;
+
+ sti
+
+;
+; call the APC delivery routine.
+;
+
+ mov eax, [ebp]+TsSegCs ; get interrupted code's CS
+ and eax, MODE_MASK ; extract the mode
+
+ test dword ptr [ebp]+TsEFlags, EFLAGS_V86_MASK
+ jz short @f
+
+ or eax, MODE_MASK ; If v86 frame, then set user_mode
+@@:
+
+;
+; call APC deliver routine
+; Previous mode
+; Null exception frame
+; Trap frame
+
+ stdCall _KiDeliverApc, <eax, 0,ebp>
+
+;
+;
+; Do interrupt exit processing
+;
+
+ SOFT_INTERRUPT_EXIT ; will do an iret
+
+_HalpApcInterrupt endp
+
+_TEXT$02 ends
+
+ end
diff --git a/private/ntos/nthals/halsp/i386/spsysbus.c b/private/ntos/nthals/halsp/i386/spsysbus.c
new file mode 100644
index 000000000..65db51aa9
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spsysbus.c
@@ -0,0 +1,249 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ spsysbus.c
+
+Abstract:
+
+Author:
+
+Environment:
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "spmp.inc"
+
+ULONG HalpDefaultInterruptAffinity;
+ULONG HalpCpuCount;
+
+BOOLEAN
+HalpTranslateSystemBusAddress(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ );
+
+ULONG
+HalpGetSystemInterruptVector(
+ 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,HalpGetSystemInterruptVector)
+#endif
+
+extern UCHAR SpCpuCount;
+extern Sp8259PerProcessorMode;
+extern UCHAR RegisteredProcessorCount;
+
+
+BOOLEAN
+HalpTranslateSystemBusAddress(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN PHYSICAL_ADDRESS BusAddress,
+ IN OUT PULONG AddressSpace,
+ OUT PPHYSICAL_ADDRESS TranslatedAddress
+ )
+
+/*++
+
+Routine Description:
+
+ This function translates a 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
+
+--*/
+
+{
+ PSUPPORTED_RANGE pRange;
+
+ pRange = NULL;
+ switch (*AddressSpace) {
+ case 0:
+ // verify memory address is within buses memory limits
+ for (pRange = &BusHandler->BusAddresses->PrefetchMemory; pRange; pRange = pRange->Next) {
+ if (BusAddress.QuadPart >= pRange->Base &&
+ BusAddress.QuadPart <= pRange->Limit) {
+ break;
+ }
+ }
+
+ if (!pRange) {
+ for (pRange = &BusHandler->BusAddresses->Memory; pRange; pRange = pRange->Next) {
+ if (BusAddress.QuadPart >= pRange->Base &&
+ BusAddress.QuadPart <= pRange->Limit) {
+ break;
+ }
+ }
+ }
+
+ break;
+
+ case 1:
+ // verify IO address is within buses IO limits
+ for (pRange = &BusHandler->BusAddresses->IO; pRange; pRange = pRange->Next) {
+ if (BusAddress.QuadPart >= pRange->Base &&
+ BusAddress.QuadPart <= pRange->Limit) {
+ break;
+ }
+ }
+ break;
+ }
+
+ if (pRange) {
+ TranslatedAddress->QuadPart = BusAddress.QuadPart + pRange->SystemBase;
+ *AddressSpace = pRange->SystemAddressSpace;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+ULONG
+HalpGetSystemInterruptVector(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL pIrql,
+ OUT PKAFFINITY pAffinity
+ )
+
+/*++
+
+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;
+ ULONG Cpu;
+ ULONG Affinity;
+ KIRQL Irql;
+
+ UNREFERENCED_PARAMETER( BusHandler );
+ UNREFERENCED_PARAMETER( RootHandler );
+ UNREFERENCED_PARAMETER( BusInterruptVector );
+
+ //
+ // Set default SystemVector, IRQL & CPU
+ //
+
+ SystemVector = BusInterruptLevel + PRIMARY_VECTOR_BASE;
+ Irql = (KIRQL)(HIGHEST_LEVEL_FOR_8259 + PRIMARY_VECTOR_BASE - SystemVector);
+ Cpu = 0;
+
+
+ if (SystemVector < PRIMARY_VECTOR_BASE ||
+ SystemVector > PRIMARY_VECTOR_BASE + HIGHEST_LEVEL_FOR_8259 ||
+ HalpIDTUsage[SystemVector].Flags & IDTOwned ) {
+
+ //
+ // This is an illegal BusInterruptVector and cannot be connected.
+ //
+
+ return(0);
+ }
+
+ //
+ // If this is machine has reported SMP Dev Ints then lets
+ // use them in a static interrupt distribution method.
+ // Notice some devices are kept on P0 for compatibility.
+ // These interrupts and their devices are not generally used
+ // for steady state operations.
+ //
+
+ if (Sp8259PerProcessorMode & SP_SMPDEVINTS) {
+
+ //
+ // This is for overriding some devices that belong on P0.
+ //
+
+ switch (BusInterruptLevel) {
+ case 1: // keyboard
+ case 3: // com2
+ case 4: // com1
+ case 5: // SysMgmt Modem
+ case 6: // floppy
+ case 12: // mouse
+ // use first cpu
+ break;
+
+ case 13: // Health (IPIs on all)
+ // use first cpu, as:
+ Irql = IPI_LEVEL;
+ SystemVector = PRIMARY_VECTOR_BASE + SECOND_IPI_DISPATCH;
+ break;
+
+ default:
+ Cpu = SystemVector % HalpCpuCount;
+ break;
+ }
+ }
+
+ //
+ // Get Affinity for Cpu
+ //
+
+ Affinity = 1 << Cpu;
+ ASSERT (Affinity);
+
+ //
+ // Done
+ //
+
+ *pAffinity = Affinity;
+ *pIrql = Irql;
+ return SystemVector;
+}
diff --git a/private/ntos/nthals/halsp/i386/spsysint.asm b/private/ntos/nthals/halsp/i386/spsysint.asm
new file mode 100644
index 000000000..1f09bbb39
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/spsysint.asm
@@ -0,0 +1,393 @@
+;++
+;
+;Copyright (c) 1991 Microsoft Corporation
+;
+;Module Name:
+;
+; spsysint.asm
+;
+;Abstract:
+;
+; This module implements the HAL routines to enable/disable system
+; interrupts, for the MP systempro implementation
+;
+;Author:
+;
+; John Vert (jvert) 22-Jul-1991
+;
+;Environment:
+;
+; Kernel Mode
+;
+;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\spmp.inc
+ .list
+
+ extrn KiI8259MaskTable:DWORD
+ EXTRNP _KeBugCheck,1,IMPORT
+
+;
+; Constants used to initialize CMOS/Real Time Clock
+;
+
+CMOS_CONTROL_PORT EQU 70h ; command port for cmos
+CMOS_DATA_PORT EQU 71h ; cmos data port
+
+;
+; Macros to Read/Write/Reset CMOS to initialize RTC
+;
+
+; CMOS_READ
+;
+; Description: This macro read a byte from the CMOS register specified
+; in (AL).
+;
+; Parameter: (AL) = address/register to read
+; Return: (AL) = data
+;
+
+CMOS_READ MACRO
+ OUT CMOS_CONTROL_PORT,al ; ADDRESS LOCATION AND DISABLE NMI
+ IODelay ; I/O DELAY
+ IN AL,CMOS_DATA_PORT ; READ IN REQUESTED CMOS DATA
+ IODelay ; I/O DELAY
+ENDM
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+align dword
+;
+; HalDismissSystemInterrupt does an indirect jump through this table so it
+; can quickly execute specific code for different interrupts.
+;
+ public HalpSpecialDismissTable
+HalpSpecialDismissTable label dword
+ dd offset FLAT:HalpDismissNormal ; irq 0
+ dd offset FLAT:HalpDismissNormal ; irq 1
+ dd offset FLAT:HalpDismissNormal ; irq 2
+ dd offset FLAT:HalpDismissNormal ; irq 3
+ dd offset FLAT:HalpDismissNormal ; irq 4
+ dd offset FLAT:HalpDismissNormal ; irq 5
+ dd offset FLAT:HalpDismissNormal ; irq 6
+ dd offset FLAT:HalpDismissIrq07 ; irq 7
+ dd offset FLAT:HalpDismissNormal ; irq 8
+ dd offset FLAT:HalpDismissNormal ; irq 9
+ dd offset FLAT:HalpDismissNormal ; irq A
+ dd offset FLAT:HalpDismissNormal ; irq B
+ dd offset FLAT:HalpDismissNormal ; irq C
+ dd offset FLAT:HalpDismissNormal ; irq D
+ dd offset FLAT:HalpDismissNormal ; irq E
+ dd offset FLAT:HalpDismissIrq0f ; irq F
+ dd offset FLAT:HalpDismissNormal ; irq 10
+ dd offset FLAT:HalpDismissNormal ; irq 11
+ dd offset FLAT:HalpDismissNormal ; irq 12
+ dd offset FLAT:HalpDismissNormal ; irq 13
+ dd offset FLAT:HalpDismissNormal ; irq 14
+ dd offset FLAT:HalpDismissNormal ; irq 15
+ dd offset FLAT:HalpDismissNormal ; irq 16
+ dd offset FLAT:HalpDismissNormal ; irq 17
+ dd offset FLAT:HalpDismissNormal ; irq 18
+ dd offset FLAT:HalpDismissNormal ; irq 19
+ dd offset FLAT:HalpDismissNormal ; irq 1A
+ dd offset FLAT:HalpDismissNormal ; irq 1B
+ dd offset FLAT:HalpDismissNormal ; irq 1C
+ dd offset FLAT:HalpDismissNormal ; irq 1D
+ dd offset FLAT:HalpDismissNormal ; irq 1E
+ dd offset FLAT:HalpDismissNormal ; irq 1F
+ dd offset FLAT:HalpDismissNormal ; irq 20
+ dd offset FLAT:HalpDismissNormal ; irq 21
+ dd offset FLAT:HalpDismissNormal ; irq 22
+ dd offset FLAT:HalpDismissNormal ; irq 23
+ dd offset FLAT:HalpDispatch ; irq 24 - 2nd level dispatch from ipi
+
+_DATA ENDS
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME 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 dismiss the specified vector number. It is called
+; before any interrupt service routine code is executed.
+;
+; N.B. This routine does NOT preserve EAX or EBX
+;
+; On the SystemPro, since all interrupt go to P0, HalBeing/EndSystem-
+; Interrupt are treated very much like the UP case. All calls to this
+; function will occur from P0.
+;
+;Arguments:
+;
+; Irql - Supplies the IRQL to raise to
+;
+; Vector - Supplies the vector of the interrupt to be dismissed
+;
+; OldIrql- Location to return OldIrql
+;
+;
+;Return Value:
+;
+; FALSE - Interrupt is spurious and should be ignored
+;
+; TRUE - Interrupt successfully dismissed and Irql raised.
+;
+;--
+align dword
+HbsiIrql equ byte ptr [esp+4]
+HbsiVector equ byte ptr [esp+8]
+HbsiOldIrql equ dword ptr [esp+12]
+
+cPublicProc _HalBeginSystemInterrupt ,3
+ mov ebx, dword ptr HbsiVector ; (ebx) = System Vector
+ sub ebx, PRIMARY_VECTOR_BASE ; (ebx) = 8259 IRQ #
+
+ cmp ebx, 25h ; Interrupt in table?
+ jnc hbsi00 ; no go handle
+ jmp HalpSpecialDismissTable[ebx*4]
+
+hbsi00:
+;
+; Interrupt is out of range. There's no EOI here since it wouldn't
+; have been out of range if it occured on either interrupt controller
+; which is known about.
+;
+ xor eax,eax ; return FALSE
+ stdRET _HalBeginSystemInterrupt
+
+align 4
+HalpDismissIrq0f:
+;
+; Check to see if this is a spurious interrupt
+;
+ mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
+ out PIC2_PORT0, al
+ IODelay ; delay
+ in al, PIC2_PORT0 ; (al) = content of PIC 1 ISR
+ test al, 10000000B ; Is In-Service register set?
+ jnz short HalpDismissNormal ; 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 4
+HalpDismissIrq07:
+;
+; Check to see if this is a spurious interrupt
+;
+ mov al, OCW3_READ_ISR ; tell 8259 we want to read ISR
+ out PIC1_PORT0, al
+ IODelay ; delay
+ in al, PIC1_PORT0 ; (al) = content of PIC 1 ISR
+ test al, 10000000B ; Is In-Service register set?
+ jnz short HalpDismissNormal ; No, so this is NOT a spurious int
+ xor eax, eax ; return FALSE
+ stdRET _HalBeginSystemInterrupt
+
+align 4
+HalpDismissNormal:
+;
+; Store OldIrql
+;
+ mov eax, HbsiOldIrql
+ mov cl, fs:PcIrql
+ mov byte ptr [eax], cl
+
+;
+; Raise IRQL to requested level
+;
+ xor eax, eax
+ mov al, HbsiIrql ; (eax) = irql
+ ; (ebx) = IRQ #
+
+ mov fs:PcIrql, al ; set new Irql
+
+
+ mov eax, KiI8259MaskTable[eax*4] ; get 8259's masks
+ or eax, fs:PcIDR ; mask disabled irqs
+ SET_8259_MASK ; send mask to 8259s
+
+;
+; Dismiss interrupt. Current interrupt is already masked off.
+;
+ mov eax, ebx ; (eax) = IRQ #
+ cmp eax, 8 ; EOI to master or slave?
+
+ jae short Hbsi100 ; 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 Hbsi200 ; IO delay
+
+align 4
+Hbsi100:
+ 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
+align 4
+Hbsi200:
+ PIC1DELAY
+
+HalpDispatch:
+ sti
+ mov eax, 1 ; return TRUE, interrupt dismissed
+ stdRET _HalBeginSystemInterrupt
+stdENDP _HalBeginSystemInterrupt
+
+;++
+;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
+
+;
+
+ movzx ecx, byte ptr [esp+4] ; (ecx) = Vector
+ sub ecx, PRIMARY_VECTOR_BASE ; (ecx) = 8259 irq #
+ mov edx, 1
+ shl edx, cl ; (ebx) = bit in IMR to disable
+ cli
+ or fs:PcIDR, 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
+ 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
+
+ mov ecx, dword ptr [esp+4] ; (ecx) = vector
+ sub ecx, PRIMARY_VECTOR_BASE
+ jc hes_error
+ cmp ecx, CLOCK2_LEVEL
+ jnc hes_error
+
+ mov eax, 1
+ shl eax, cl ; (ebx) = bit in IMR to enable
+ not eax
+
+ pushfd
+ cli
+ and fs:PcIDR, eax
+
+;
+; Get the PIC masks for the current Irql
+;
+ movzx eax, byte ptr fs:PcIrql
+ mov eax, KiI8259MaskTable[eax*4]
+ or eax, fs:PcIDR
+;
+; Write the new interrupt mask register back to the 8259
+;
+ SET_8259_MASK
+
+ popfd
+ mov eax, 1 ; return TRUE
+ stdRET _HalEnableSystemInterrupt
+
+hes_error:
+if DBG
+ int 3
+endif
+ xor eax, eax ; FALSE
+ stdRET _HalEnableSystemInterrupt
+
+stdENDP _HalEnableSystemInterrupt
+
+
+_TEXT ENDS
+ END
diff --git a/private/ntos/nthals/halsp/i386/xxbiosa.asm b/private/ntos/nthals/halsp/i386/xxbiosa.asm
new file mode 100644
index 000000000..bc0173a17
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/xxbiosc.c b/private/ntos/nthals/halsp/i386/xxbiosc.c
new file mode 100644
index 000000000..60cf92748
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/xxdisp.c b/private/ntos/nthals/halsp/i386/xxdisp.c
new file mode 100644
index 000000000..d48977df0
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/xxflshbf.c b/private/ntos/nthals/halsp/i386/xxflshbf.c
new file mode 100644
index 000000000..b054121cf
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/xxhal.c b/private/ntos/nthals/halsp/i386/xxhal.c
new file mode 100644
index 000000000..198d08346
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/xxioacc.asm b/private/ntos/nthals/halsp/i386/xxioacc.asm
new file mode 100644
index 000000000..8445c3404
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/xxkdsup.c b/private/ntos/nthals/halsp/i386/xxkdsup.c
new file mode 100644
index 000000000..6e569b5ac
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/xxmemory.c b/private/ntos/nthals/halsp/i386/xxmemory.c
new file mode 100644
index 000000000..920714540
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/xxstubs.c b/private/ntos/nthals/halsp/i386/xxstubs.c
new file mode 100644
index 000000000..8421fb30a
--- /dev/null
+++ b/private/ntos/nthals/halsp/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/halsp/i386/xxtime.c b/private/ntos/nthals/halsp/i386/xxtime.c
new file mode 100644
index 000000000..92abb2aeb
--- /dev/null
+++ b/private/ntos/nthals/halsp/i386/xxtime.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\xxtime.c"