diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/nthals/halsp/i386 | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/ntos/nthals/halsp/i386')
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" |