summaryrefslogtreecommitdiffstats
path: root/private/ntos/nthals/halws3/i386
diff options
context:
space:
mode:
Diffstat (limited to 'private/ntos/nthals/halws3/i386')
-rw-r--r--private/ntos/nthals/halws3/i386/apic.inc556
-rw-r--r--private/ntos/nthals/halws3/i386/halp.h5
-rw-r--r--private/ntos/nthals/halws3/i386/halver.h42
-rw-r--r--private/ntos/nthals/halws3/i386/ix8259.inc5
-rw-r--r--private/ntos/nthals/halws3/i386/ixbeep.asm5
-rw-r--r--private/ntos/nthals/halws3/i386/ixbusdat.c5
-rw-r--r--private/ntos/nthals/halws3/i386/ixcmos.asm5
-rw-r--r--private/ntos/nthals/halws3/i386/ixcmos.inc5
-rw-r--r--private/ntos/nthals/halws3/i386/ixdat.c5
-rw-r--r--private/ntos/nthals/halws3/i386/ixenvirv.c5
-rw-r--r--private/ntos/nthals/halws3/i386/ixfirm.c5
-rw-r--r--private/ntos/nthals/halws3/i386/ixhwsup.c5
-rw-r--r--private/ntos/nthals/halws3/i386/ixidle.asm5
-rw-r--r--private/ntos/nthals/halws3/i386/ixinfo.c5
-rw-r--r--private/ntos/nthals/halws3/i386/ixisabus.c5
-rw-r--r--private/ntos/nthals/halws3/i386/ixisasup.c5
-rw-r--r--private/ntos/nthals/halws3/i386/ixkdcom.c5
-rw-r--r--private/ntos/nthals/halws3/i386/ixphwsup.c5
-rw-r--r--private/ntos/nthals/halws3/i386/ixreboot.c5
-rw-r--r--private/ntos/nthals/halws3/i386/ixthunk.c5
-rw-r--r--private/ntos/nthals/halws3/i386/ixusage.c5
-rw-r--r--private/ntos/nthals/halws3/i386/w3.inc341
-rw-r--r--private/ntos/nthals/halws3/i386/w3clock.asm782
-rw-r--r--private/ntos/nthals/halws3/i386/w3detect.asm106
-rw-r--r--private/ntos/nthals/halws3/i386/w3hal.c660
-rw-r--r--private/ntos/nthals/halws3/i386/w3ipi.asm955
-rw-r--r--private/ntos/nthals/halws3/i386/w3irql.asm776
-rw-r--r--private/ntos/nthals/halws3/i386/w3nmi.c78
-rw-r--r--private/ntos/nthals/halws3/i386/w3profil.asm223
-rw-r--r--private/ntos/nthals/halws3/i386/w3space.asm1346
-rw-r--r--private/ntos/nthals/halws3/i386/w3spin.asm389
-rw-r--r--private/ntos/nthals/halws3/i386/w3sproc.c710
-rw-r--r--private/ntos/nthals/halws3/i386/w3sproca.asm377
-rw-r--r--private/ntos/nthals/halws3/i386/w3stall.asm382
-rw-r--r--private/ntos/nthals/halws3/i386/w3swint.asm317
-rw-r--r--private/ntos/nthals/halws3/i386/w3swint.bak267
-rw-r--r--private/ntos/nthals/halws3/i386/w3sysbus.c233
-rw-r--r--private/ntos/nthals/halws3/i386/w3sysint.asm613
-rw-r--r--private/ntos/nthals/halws3/i386/xxbiosa.asm5
-rw-r--r--private/ntos/nthals/halws3/i386/xxbiosc.c5
-rw-r--r--private/ntos/nthals/halws3/i386/xxdisp.c5
-rw-r--r--private/ntos/nthals/halws3/i386/xxioacc.asm5
-rw-r--r--private/ntos/nthals/halws3/i386/xxkdsup.c5
-rw-r--r--private/ntos/nthals/halws3/i386/xxmemory.c5
-rw-r--r--private/ntos/nthals/halws3/i386/xxstubs.c5
-rw-r--r--private/ntos/nthals/halws3/i386/xxtime.c5
46 files changed, 9288 insertions, 0 deletions
diff --git a/private/ntos/nthals/halws3/i386/apic.inc b/private/ntos/nthals/halws3/i386/apic.inc
new file mode 100644
index 000000000..133cb8e8f
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/apic.inc
@@ -0,0 +1,556 @@
+;/*
+;++
+;
+; Copyright (c) 1992 Intel Corporation
+; All rights reserved
+;
+; INTEL CORPORATION PROPRIETARY INFORMATION
+;
+; This software is supplied to Microsoft under the terms
+; of a license agreement with Intel Corporation and may not be
+; copied nor disclosed except in accordance with the terms
+; of that agreement.
+;
+;
+; Module Name:
+;
+; apic.inc
+;
+; Abstract:
+;
+; This module contains the definitions used by HAL to manipulate
+; APIC interrupt controller and APIC-specific constants.
+;
+; WARNING: This file is included by both ASM and C files.
+;
+; Author:
+;
+; Hugh Bynum and Ron Mosgrove Aug-1992
+;
+;--
+if 0 ; Begin C only code */
+
+//
+// APIC defines for C code
+// BE SURE TO CHANGE THESE VALUES IN BOTH TABLES!
+//
+
+#define IO_BASE_ADDRESS 0xFEC00000 // Physical address
+#define IO_REGISTER_SELECT 0x00000000 // offset from IO_BASE_ADDRESS
+#define IO_REGISTER_WINDOW 0x00000010 // offset from IO_BASE_ADDRESS
+
+#define IO_UNIT_0 0x00000000 // adder for IO unit 0
+#define IO_UNIT_1 0x00001000 // adder for IO unit 1
+#define IO_UNIT_2 0x00002000 // adder for IO unit 2
+#define IO_UNIT_3 0x00003000 // adder for IO unit 3
+
+#define IO_ID_REGISTER 0x00000000
+#define IO_VERS_REGISTER 0x00000001
+#define IO_ARB_ID_REGISTER 0x00000002
+#define IO_REDIR_00_LOW 0x00000010
+#define IO_REDIR_00_HIGH 0x00000011
+
+#define IO_MAX_REDIR_MASK 0x00FF0000
+#define IO_VERSION_MASK 0x000000FF
+
+#define LU_BASE_ADDRESS 0xFEE00000 // Physical address
+#define LU_ID_REGISTER 0x00000020 // offset from LU_BASE_ADDRESS
+#define LU_VERS_REGISTER 0x00000030 // offset from LU_BASE_ADDRESS
+#define LU_TPR 0x00000080 // offset from LU_BASE_ADDRESS
+#define LU_APR 0x00000090 // offset from LU_BASE_ADDRESS
+#define LU_PPR 0x000000A0 // offset from LU_BASE_ADDRESS
+#define LU_EOI 0x000000B0 // offset from LU_BASE_ADDRESS
+#define LU_REMOTE_REGISTER 0x000000C0 // offset from LU_BASE_ADDRESS
+
+#define LU_LOGICAL_DEST 0x000000D0 // offset from LU_BASE_ADDRESS
+#define LU_LOGICAL_DEST_MASK 0xFF000000
+
+#define LU_DEST_FORMAT 0x000000E0 // offset from LU_BASE_ADDRESS
+#define LU_DEST_FORMAT_MASK 0xF0000000
+#define LU_DEST_FORMAT_FLAT 0xFFFFFFFF
+
+#define LU_SPURIOUS_VECTOR 0x000000F0 // offset from LU_BASE_ADDRESS
+#define LU_UNIT_ENABLED 0x00000100
+
+#define LU_ISR_0 0x00000100 // offset from LU_BASE_ADDRESS
+#define LU_TMR_0 0x00000180 // offset from LU_BASE_ADDRESS
+#define LU_IRR_0 0x00000200 // offset from LU_BASE_ADDRESS
+#define LU_ERROR_STATUS 0x00000280 // offset from LU_BASE_ADDRESS
+#define LU_INT_CMD_LOW 0x00000300 // offset from LU_BASE_ADDRESS
+#define LU_INT_CMD_HIGH 0x00000310 // offset from LU_BASE_ADDRESS
+#define LU_TIMER_VECTOR 0x00000320 // offset from LU_BASE_ADDRESS
+#define LU_INT_VECTOR_0 0x00000350 // TEMPORARY - do not use
+#define LU_INT_VECTOR_1 0x00000360 // TEMPORARY - do not use
+#define LU_INITIAL_COUNT 0x00000380 // offset from LU_BASE_ADDRESS
+#define LU_CURRENT_COUNT 0x00000390 // offset from LU_BASE_ADDRESS
+#define LU_DIVIDER_CONFIG 0x000003E0 // offset from LU_BASE_ADDRESS
+
+#define APIC_ID_MASK 0x0F000000
+#define APIC_ID_SHIFT 24
+
+#define INT_VECTOR_MASK 0x000000FF
+#define RESERVED_HIGH_INT 0x000000F8
+#define DELIVERY_MODE_MASK 0x00000700
+#define DELIVER_FIXED 0x00000000
+#define DELIVER_LOW_PRIORITY 0x00000100
+#define DELIVER_SMI 0x00000200
+#define DELIVER_REMOTE_READ 0x00000300
+#define DELIVER_NMI 0x00000400
+#define DELIVER_INIT 0x00000500
+#define DELIVER_EXTINT 0x00000700
+#define LOGICAL_DESTINATION 0x00000800
+#define DELIVERY_PENDING 0x00001000
+#define ACTIVE_LOW 0x00002000
+#define REMOTE_IRR 0x00004000
+#define LEVEL_TRIGGERED 0x00008000
+#define INTERRUPT_MASKED 0x00010000
+#define PERIODIC_TIMER 0x00020000
+
+#define ICR_LEVEL_ASSERTED 0x00004000
+#define ICR_RR_STATUS_MASK 0x00030000
+#define ICR_RR_INVALID 0x00000000
+#define ICR_RR_IN_PROGRESS 0x00010000
+#define ICR_RR_VALID 0x00020000
+#define ICR_SHORTHAND_MASK 0x000C0000
+#define ICR_USE_DEST_FIELD 0x00000000
+#define ICR_SELF 0x00040000
+#define ICR_ALL_INCL_SELF 0x00080000
+#define ICR_ALL_EXCL_SELF 0x000C0000
+
+#define DESTINATION_MASK 0xFF000000
+#define DESTINATION_SHIFT 24
+
+/*
+endif
+
+; APIC defines for assembly code
+; BE SURE TO CHANGE THESE VALUES IN BOTH TABLES!
+;
+
+IO_BASE_ADDRESS equ 0FEC00000H ; Physical address
+IO_REGISTER_SELECT equ 00000000H ; offset from IO_BASE_ADDRESS
+IO_REGISTER_WINDOW equ 00000010H ; offset from IO_BASE_ADDRESS
+
+IO_UNIT_0 equ 00000000H ; adder for IO unit 0
+IO_UNIT_1 equ 00001000H ; adder for IO unit 1
+IO_UNIT_2 equ 00002000H ; adder for IO unit 2
+IO_UNIT_3 equ 00003000H ; adder for IO unit 3
+
+IO_ID_REGISTER equ 00000000H ;
+IO_VERS_REGISTER equ 00000001H ;
+IO_ARB_ID_REGISTER equ 00000002H ;
+IO_REDIR_00_LOW equ 00000010H ;
+IO_REDIR_00_HIGH equ 00000011H ;
+
+IO_MAX_REDIR_MASK equ 00FF0000H ;
+IO_VERSION_MASK equ 000000FFH ;
+
+LU_BASE_ADDRESS equ 0FEE00000H ;
+LU_ID_REGISTER equ 00000020H ; offset from LU_BASE_ADDRESS
+LU_VERS_REGISTER equ 00000030H ; offset from LU_BASE_ADDRESS
+LU_TPR equ 00000080H ; offset from LU_BASE_ADDRESS
+LU_APR equ 00000090H ; offset from LU_BASE_ADDRESS
+LU_PPR equ 000000A0H ; offset from LU_BASE_ADDRESS
+LU_EOI equ 000000B0H ; offset from LU_BASE_ADDRESS
+LU_REMOTE_REGISTER equ 000000C0H ; offset from LU_BASE_ADDRESS
+
+LU_LOGICAL_DEST equ 000000D0H ; offset from LU_BASE_ADDRESS
+LU_LOGICAL_DEST_MASK equ 0FF000000H ;
+
+LU_DEST_FORMAT equ 000000E0H ; offset from LU_BASE_ADDRESS
+LU_DEST_FORMAT_MASK equ 0F0000000H ;
+LU_DEST_FORMAT_FLAT equ 0FFFFFFFFH ;
+
+LU_SPURIOUS_VECTOR equ 000000F0H ; offset from LU_BASE_ADDRESS
+LU_UNIT_ENABLED equ 00000100H ;
+
+LU_ISR_0 equ 00000100H ; offset from LU_BASE_ADDRESS
+LU_TMR_0 equ 00000180H ; offset from LU_BASE_ADDRESS
+LU_IRR_0 equ 00000200H ; offset from LU_BASE_ADDRESS
+LU_ERROR_STATUS equ 00000280H ; offset from LU_BASE_ADDRESS
+LU_INT_CMD_LOW equ 00000300H ; offset from LU_BASE_ADDRESS
+LU_INT_CMD_HIGH equ 00000310H ; offset from LU_BASE_ADDRESS
+LU_TIMER_VECTOR equ 00000320H ; offset from LU_BASE_ADDRESS
+LU_INT_VECTOR_0 equ 00000350H ; TEMPORARY - do not use
+LU_INT_VECTOR_1 equ 00000360H ; TEMPORARY - do not use
+LU_INITIAL_COUNT equ 00000380H ; offset from LU_BASE_ADDRESS
+LU_CURRENT_COUNT equ 00000390H ; offset from LU_BASE_ADDRESS
+
+LU_DIVIDER_CONFIG equ 000003E0H ; offset from LU_BASE_ADDRESS
+LU_DIVIDE_BY_1 equ 0000000BH ;
+LU_DIVIDE_BY_2 equ 00000000H ;
+LU_DIVIDE_BY_4 equ 00000001H ;
+LU_DIVIDE_BY_8 equ 00000002H ;
+LU_DIVIDE_BY_16 equ 00000003H ;
+LU_DIVIDE_BY_32 equ 00000008H ;
+LU_DIVIDE_BY_64 equ 00000009H ;
+LU_DIVIDE_BY_128 equ 0000000AH ;
+
+APIC_ID_MASK equ 0F000000H ;
+APIC_ID_SHIFT equ 24 ;
+
+INT_VECTOR_MASK equ 000000FFH ;
+RESERVED_HIGH_INT equ 000000F8H ;
+DELIVERY_MODE_MASK equ 00000700H ;
+DELIVER_FIXED equ 00000000H ;
+DELIVER_LOW_PRIORITY equ 00000100H ;
+DELIVER_SMI equ 00000200H ;
+DELIVER_REMOTE_READ equ 00000300H ;
+DELIVER_NMI equ 00000400H ;
+DELIVER_INIT equ 00000500H ;
+DELIVER_EXTINT equ 00000700H ;
+PHYSICAL_DESTINATION equ 00000000H ;
+LOGICAL_DESTINATION equ 00000800H ;
+DELIVERY_PENDING equ 00001000H ;
+ACTIVE_LOW equ 00002000H ;
+REMOTE_IRR equ 00004000H ;
+LEVEL_TRIGGERED equ 00008000H ;
+INTERRUPT_MASKED equ 00010000H ;
+INTERRUPT_MOT_MASKED equ 00000000H ;
+PERIODIC_TIMER equ 00020000H ;
+
+ICR_LEVEL_ASSERTED equ 00004000H ;
+ICR_RR_STATUS_MASK equ 00030000H ;
+ICR_RR_INVALID equ 00000000H ;
+ICR_RR_IN_PROGRESS equ 00010000H ;
+ICR_RR_VALID equ 00020000H ;
+ICR_SHORTHAND_MASK equ 000C0000H ;
+ICR_USE_DEST_FIELD equ 00000000H ;
+ICR_SELF equ 00040000H ;
+ICR_ALL_INCL_SELF equ 00080000H ;
+ICR_ALL_EXCL_SELF equ 000C0000H ;
+
+DESTINATION_MASK equ 0FF000000H ;
+DESTINATION_SHIFT equ 24 ; shift count for dest. mask
+
+;
+; remaining macro definitions for assembler only
+;
+
+;++
+;
+; WRITE_IO_APIC
+;
+; Macro Description:
+;
+; This macro writes a value to a register in the I/O Apic.
+;
+; Arguments:
+;
+; Register - Register to be written
+;
+; Value - Value to write
+;
+;--
+WRITE_IO_APIC MACRO Register , Value
+
+.errb <Register>
+.errb <Value>
+
+ ; Need two scratch registers
+ push eax ; Save registers
+ push ecx
+
+ push Value ; Save paramters on the stack
+ push Register
+
+ pop eax ; Get the Register
+ mov ecx, _HalpIOunitBase
+ add ecx, IO_REGISTER_SELECT+IO_UNIT_0 ; Register select on I/O Unit
+ mov dword ptr [ecx], eax ; Program register
+
+ pop eax ; Get the Value
+ mov ecx, _HalpIOunitBase
+ add ecx, IO_REGISTER_WINDOW+IO_UNIT_0 ; Register select on I/O Unit
+ mov dword ptr [ecx], eax ; Program register
+
+ pop ecx ; Restore scratch registers
+ pop eax
+
+ ; We're Out'a Here
+
+endm
+
+;++
+;
+; READ_IO_APIC
+;
+; Macro Description:
+;
+; This macro reads a 32 bit register from the I/O Apic.
+;
+; Arguments:
+;
+; Register - Register to be read
+;
+; Return
+;
+; eax - value read from I/O Apic
+;
+;--
+READ_IO_APIC MACRO Register
+
+.errb <Register>
+
+ifndef _HalpIOunitBase
+ extrn _HalpIOunitBase:DWORD
+endif
+
+ push ecx ; Need one scratch register
+ push Register
+
+ pop eax ; Get the Register
+ mov ecx, _HalpIOunitBase
+ add ecx, IO_REGISTER_SELECT+IO_UNIT_0 ; Register select on I/O Unit
+ mov dword ptr [ecx], eax ; Program register
+
+ mov ecx, _HalpIOunitBase
+ add ecx, IO_REGISTER_WINDOW+IO_UNIT_0 ; Register Window on I/O Unit
+ mov eax, dword ptr [ecx] ; Program register
+
+ pop ecx ; Restore scratch register
+
+ ; We're Out'a Here
+
+endm
+
+;++
+;
+; GetIOApicRedirTable
+;
+; Macro Description:
+;
+; This reads a redirection table entry from the I/O APIC (unit 0).
+;
+; Arguments:
+;
+; IoApicInputPin - Interrupt Input (INTI) we're interested in
+; The Caller MUST have locked access to the IO Apic prior to
+; this call.
+;
+; Return
+;
+; 64 Bit redirection table entry in eax [31:0] and edx [63:32]
+;
+;--
+GetIOApicRedirTable MACRO IoApicInputPin
+
+.errb <IoApicInputPin>
+
+ push IoApicInputPin ; Save paramter on the stack
+
+ pop eax ; INTI we're looking for
+ and eax, 0fh ; Make sure we're dealing with
+ ; defined inputs
+ shl eax, 1 ; <IoApicInputPin> * 2
+ add eax, IO_REDIR_00_LOW+IO_UNIT_0 ; eax == low(redir) of INTI
+
+ push eax ; Save the register address
+ inc eax ; Points to high(redir)
+
+ READ_IO_APIC eax ; Read the Upper 32 Bits of the Redir
+
+ mov edx, eax ; Save the High 32 Bits to return
+ pop eax ; Get the low register address
+
+ READ_IO_APIC eax ; Read the Lower 32 Bits of the Redir
+
+ ;
+ ; edx == bits 32-63 of RedirectionTable[IoApicInputPin]
+ ; eax == bits 00-31 of RedirectionTable[IoApicInputPin]
+ ;
+
+endm
+
+;++
+;
+; PutIOApicRedirTable
+;
+; Macro Description:
+;
+; This writes a redirection table entry to the I/O APIC (unit 0)..
+; The Caller MUST have locked access to the IO Apic prior to
+; this call.
+;
+; Arguments:
+;
+; IoApicInputPin - Interrupt Input (INTI) we're interested in
+;
+; LowWord - Low 32 Bits of redirection Table entry
+;
+; HighWord - High 32 Bits of redirection Table entry
+;
+;
+;--
+PutIOApicRedirTable MACRO IoApicInputPin , LowWord , HighWord
+
+.errb <IoApicInputPin>
+.errb <LowWord>
+.errb <HighWord>
+
+ push LowWord ; Save paramter on the stack
+ push HighWord
+ push IoApicInputPin
+
+ pop eax ; INTI we're looking for
+ and eax, 0fh ; Make sure we're dealing with
+ ; defined inputs
+ shl eax, 1 ; <IoApicInputPin> * 2
+ add eax, IO_REDIR_00_LOW+IO_UNIT_0 ; eax == low(redir) of INTI
+
+ pop edx ; edx <= Bits 31-63 of redir
+
+ push eax ; Save the register address
+ inc eax ; Points to high(redir)
+
+ WRITE_IO_APIC eax , edx ; Write the Upper 32 Bits of the Redir
+
+ pop eax ; Get the low register address
+ pop edx ; edx <= Bits 00-31 of redir
+
+ WRITE_IO_APIC eax , edx ; Write the Lower 32 Bits of the Redir
+
+endm
+
+;++
+;
+; GrabHalIoApicSpinLock
+;
+; Macro Description:
+;
+; This macro is used to prevent multiple CPU's from accessing the IO APIC on a MP
+; system. It grabs the IoAPIC Spin lock if available, ifnot then it waits until
+; it is available.
+;
+; The compliment of this macro is ReleaseHalIoApicSpinLock.
+;
+;--
+GrabHalIoApicSpinLock MACRO
+local WaitForRelease, StartSpinLockLoop, Gotit
+
+ifndef _HalpIOunitLock
+ extrn _HalpIOunitLock:DWORD ; IoUnit SpinLock
+endif ; _HalpIOunitLock
+
+StartSpinLockLoop:
+
+ pushfd ; Save Flags
+ cli ; Don't Interrupt us here
+
+ lea eax, _HalpIOunitLock ; The SpinLock we're interested in
+ ACQUIRE_SPINLOCK eax, WaitForRelease ; Try for the lock, if Not successful
+ ; Go and wait till the owner frees it.
+
+ ;
+ ; We now own the spinlock
+ ;
+
+ jmp Gotit
+
+WaitForRelease:
+ sti ; Allow other activity while we wait
+ SPIN_ON_SPINLOCK eax, StartSpinLockLoop ; Stare at it until it's free
+
+ ;
+ ; We'll Never get here
+ ;
+
+Gotit:
+
+ popfd ; restore Original Flags
+
+endm
+
+;++
+;
+; ReleaseHalIoApicSpinLock
+;
+; Macro Description:
+;
+; This macro is used to prevent multiple CPU's from accessing the IO Apic on a MP
+; system. It frees the IoApic Spin lock.
+;
+; The compliment of this macro is GrabHalIoApicSpinLock.
+;--
+ReleaseHalIoApicSpinLock MACRO
+
+ifndef _HalpIOunitLock
+ extrn _HalpIOunitLock:DWORD ; IoUnit SpinLock
+endif ; _HalpIOunitLock
+
+ lea eax, _HalpIOunitLock
+ RELEASE_SPINLOCK eax
+
+endm
+
+;++
+;
+; GrabHal8259SpinLock
+;
+; Macro Description:
+;
+; This macro is used to prevent multiple CPU's from accessing the IO APIC on a MP
+; system. It grabs the 8259 Spin lock if available, ifnot then it waits until
+; it is available.
+;
+; The compliment of this macro is ReleaseHal8259SpinLock.
+;
+;--
+GrabHal8259SpinLock MACRO
+local WaitForRelease, StartSpinLockLoop, Gotit
+
+ifndef _Halp8259Lock
+ extrn _Halp8259Lock:DWORD ; 8259 SpinLock
+endif ; _Halp8259Lock
+
+StartSpinLockLoop:
+
+ pushfd ; Save Flags
+ cli ; Don't Interrupt us here
+
+ lea eax, _Halp8259Lock ; The SpinLock we're interested in
+ ACQUIRE_SPINLOCK eax, WaitForRelease ; Try for the lock, if Not successful
+ ; Go and wait till the owner frees it.
+
+ ;
+ ; We now own the spinlock
+ ;
+
+ jmp Gotit
+
+WaitForRelease:
+ sti ; Allow other activity while we wait
+ SPIN_ON_SPINLOCK eax, StartSpinLockLoop ; Stare at it until it's free
+
+ ;
+ ; We'll Never get here
+ ;
+
+Gotit:
+
+ popfd ; restore Original Flags
+
+endm
+
+;++
+;
+; ReleaseHal8259SpinLock
+;
+; Macro Description:
+;
+; This macro is used to prevent multiple CPU's from accessing the IO Apic on a MP
+; system. It frees the 8259 Spin lock.
+;
+; The compliment of this macro is GrabHal8259SpinLock.
+;--
+ReleaseHal8259SpinLock MACRO
+
+ifndef _Halp8259Lock
+ extrn _Halp8259Lock:DWORD ; 8259 SpinLock
+endif ; _Halp8259Lock
+
+ lea eax, _Halp8259Lock
+ RELEASE_SPINLOCK eax
+
+endm
+;*/
diff --git a/private/ntos/nthals/halws3/i386/halp.h b/private/ntos/nthals/halws3/i386/halp.h
new file mode 100644
index 000000000..a9dbf1e13
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/halver.h b/private/ntos/nthals/halws3/i386/halver.h
new file mode 100644
index 000000000..1c18a5540
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/halver.h
@@ -0,0 +1,42 @@
+/*++
+
+Module Name:
+
+ halver.h
+
+Abstract:
+
+ HAL WS3500 version file.
+
+ Update the version number and date in this file before each HAL release.
+ This file is maintained for the benefit of Microsoft builds of our
+ HAL source only. Sequent builds use halver.tmp to create halver.h
+ during the build process. (6/6/94 rlary)
+
+Author:
+
+ Phil Hochstetler (phil@sequent.com)
+
+Environment:
+
+ Kernel mode only.
+
+--*/
+
+#if defined(NT_UP)
+
+#if DBG
+UCHAR HalName[] = "Sequent WinServer (TM) 3500 HAL -DNT_UP -DDBG";
+#else
+UCHAR HalName[] = "Sequent WinServer (TM) 3500 HAL -DNT_UP";
+#endif
+
+#else // !defined(NT_UP)
+
+#if DBG
+UCHAR HalName[] = "Sequent WinServer (TM) 3500 HAL -DDBG";
+#else
+UCHAR HalName[] = "Sequent WinServer (TM) 3500 HAL";
+#endif
+
+#endif // defined(NT_UP)
diff --git a/private/ntos/nthals/halws3/i386/ix8259.inc b/private/ntos/nthals/halws3/i386/ix8259.inc
new file mode 100644
index 000000000..b9e0a196a
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixbeep.asm b/private/ntos/nthals/halws3/i386/ixbeep.asm
new file mode 100644
index 000000000..f53bd3e58
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/ixbeep.asm
@@ -0,0 +1,5 @@
+;
+; Include code from halx86
+; This is a cpp style symbolic link
+
+include ..\halx86\i386\ixbeep.asm
diff --git a/private/ntos/nthals/halws3/i386/ixbusdat.c b/private/ntos/nthals/halws3/i386/ixbusdat.c
new file mode 100644
index 000000000..a42039752
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixcmos.asm b/private/ntos/nthals/halws3/i386/ixcmos.asm
new file mode 100644
index 000000000..7f4e7393e
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixcmos.inc b/private/ntos/nthals/halws3/i386/ixcmos.inc
new file mode 100644
index 000000000..2fe289fb0
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixdat.c b/private/ntos/nthals/halws3/i386/ixdat.c
new file mode 100644
index 000000000..f6b0e34de
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixenvirv.c b/private/ntos/nthals/halws3/i386/ixenvirv.c
new file mode 100644
index 000000000..e194820ba
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixfirm.c b/private/ntos/nthals/halws3/i386/ixfirm.c
new file mode 100644
index 000000000..f666e405c
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixhwsup.c b/private/ntos/nthals/halws3/i386/ixhwsup.c
new file mode 100644
index 000000000..ea91dc8d0
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixidle.asm b/private/ntos/nthals/halws3/i386/ixidle.asm
new file mode 100644
index 000000000..9bdd670f3
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixinfo.c b/private/ntos/nthals/halws3/i386/ixinfo.c
new file mode 100644
index 000000000..7f211f7a9
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixisabus.c b/private/ntos/nthals/halws3/i386/ixisabus.c
new file mode 100644
index 000000000..c1edfb067
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixisasup.c b/private/ntos/nthals/halws3/i386/ixisasup.c
new file mode 100644
index 000000000..58c426544
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixkdcom.c b/private/ntos/nthals/halws3/i386/ixkdcom.c
new file mode 100644
index 000000000..29bb8308e
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixphwsup.c b/private/ntos/nthals/halws3/i386/ixphwsup.c
new file mode 100644
index 000000000..a1cdab598
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixreboot.c b/private/ntos/nthals/halws3/i386/ixreboot.c
new file mode 100644
index 000000000..15d7bd898
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixthunk.c b/private/ntos/nthals/halws3/i386/ixthunk.c
new file mode 100644
index 000000000..6f15aad73
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/ixusage.c b/private/ntos/nthals/halws3/i386/ixusage.c
new file mode 100644
index 000000000..519ec31f3
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/w3.inc b/private/ntos/nthals/halws3/i386/w3.inc
new file mode 100644
index 000000000..5eb27638d
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3.inc
@@ -0,0 +1,341 @@
+;/*
+;++
+;
+;Copyright (c) 1992 Sequent Computer Systems, Inc.
+;
+;Module Name:
+;
+; w3hal.h
+;
+;Abstract:
+;
+; This header file contains definitions for the WinServer 3000.
+;
+;Author:
+;
+; Phil Hochstetler (phil@sequent.com)
+;
+;Environment:
+;
+; Kernel mode only.
+;
+;Revision History:
+;
+;--
+if 0 ; Begin C only code */
+
+//
+// Interrupt vector definitions for C
+//
+
+#define APIC_APC_VECTOR 0x30
+#define APIC_DPC_VECTOR 0x40
+
+#define APIC_IRQ16_VECTOR 0x60
+#define APIC_IRQ17_VECTOR 0x61
+#define APIC_IRQ18_VECTOR 0x62
+#define APIC_IRQ19_VECTOR 0x63
+#define APIC_IRQ20_VECTOR 0x64
+#define APIC_IRQ21_VECTOR 0x65
+#define APIC_IRQ22_VECTOR 0x66
+#define APIC_IRQ23_VECTOR 0x67
+
+#define APIC_IRQ8_VECTOR 0x70
+#define APIC_IRQ9_VECTOR 0x71
+#define APIC_IRQ10_VECTOR 0x72
+#define APIC_IRQ11_VECTOR 0x73
+#define APIC_IRQ12_VECTOR 0x74
+#define APIC_IRQ13_VECTOR 0x75
+#define APIC_IRQ14_VECTOR 0x76
+#define APIC_IRQ15_VECTOR 0x77
+
+#define APIC_IRQ0_VECTOR 0x80
+#define APIC_IRQ1_VECTOR 0x81
+#define APIC_IRQ2_VECTOR 0x82
+#define APIC_IRQ3_VECTOR 0x83
+#define APIC_IRQ4_VECTOR 0x84
+#define APIC_IRQ5_VECTOR 0x85
+#define APIC_IRQ6_VECTOR 0x86
+#define APIC_IRQ7_VECTOR 0x87
+
+#define APIC_RTC_VECTOR 0x70
+#define APIC_MOUSE_VECTOR 0x74
+#define APIC_DMA_VECTOR 0x75
+#define APIC_IDE_VECTOR 0x76
+#define APIC_KBD_VECTOR 0x81
+#define APIC_FLOPPY_VECTOR 0x86
+
+#define APIC_PROFILE_VECTOR 0x90
+#define APIC_CLOCK_VECTOR 0xA0
+#define APIC_IPI_VECTOR 0xB0
+#define APIC_POWERFAIL_VECTOR 0xC0
+#define EISA_CLOCK_VECTOR 0xD0
+#define EISA_KBD_VECTOR 0xD1
+#define EISA_IRQ2_VECTOR 0xD2
+#define EISA_FLOPPY_VECTOR 0xD6
+#define EISA_PIC1_SPURIOUS_VECTOR 0xD7
+#define EISA_RTC_VECTOR 0xD8
+#define EISA_MOUSE_VECTOR 0xDC
+#define EISA_DMA_VECTOR 0xDD
+#define EISA_IDE_VECTOR 0xDE
+#define EISA_PIC2_SPURIOUS_VECTOR 0xDF
+#define APIC_SPURIOUS_VECTOR 0xE0
+#define APIC_SYSINT_VECTOR 0xE1
+#define APIC_HIGH_VECTOR 0xF0
+#define APIC_STALL_VECTOR 0xF8
+
+
+#define PIC0_BASE_VECTOR EISA_CLOCK_VECTOR
+#define PIC1_BASE_VECTOR EISA_RTC_VECTOR
+
+#define EISA_SHIFT 12 // EISA slot starts at this offset
+#define EISA_MASK 0xfff // Low bits of EISA slot address
+#define POSTREGISTERPORT 0x80 // BIOS post register
+#define OCW2_SPECIFIC_EOI 0x60
+#define OCW2_NON_SPECIFIC_EOI 0x20
+#define PIC1_PORT0 0x20
+#define PIC1_PORT1 0x21
+#define PIC2_PORT0 0xA0
+#define PIC2_PORT1 0xA1
+#define PIC3_PORT0 0xCC0
+#define PIC3_PORT1 0xCC1
+#define EISA_2_MPIC_POLARITY_REG 0x0C0E
+#define ELCR_MASK 0xDEF8
+#define PIC1_ELCR_PORT 0x04D0
+#define PIC2_ELCR_PORT 0x04D1
+#define DESTINATION_ALL_CPUS 0xff
+#define DESTINATION_CPU_0 0x01
+#define FCR 0x0C84
+#define WarmResetVector 0x467
+#define FCR_RESET_MASK 0x0080
+#define IOMPIC_RT_MASK 0x10000
+#define FIRST_SYSTEM_SLOT 9
+#define LAST_SYSTEM_SLOT 15
+#define SLOT_ID_REG 0x0C80
+#define SLOT_ID_BOARDTYPE 0x00F00000
+#define SLOT_ID_TYPECPU 0x00100000
+#define IOUNIT_APIC_ID 7
+#define IOUNIT2_APIC_ID 8
+#define D_INT032 8E00h
+#define PeriodInUsec 200
+
+
+
+#define IRQL_APIC_KBD 25
+#define IRQL_APIC_FLOPPY 21
+#define IRQL_APIC_RTC 19
+#define IRQL_APIC_DMA 14
+#define IRQL_APIC_IDE 13
+#define IRQL_APIC_MOUSE 15
+
+//
+// Hal private data structures (max 64 bytes in length)
+//
+
+typedef struct _WS3_HAL_PRIVATE {
+ UCHAR PcrNumber; // Logical Processor Number
+ UCHAR ProcLightState; // State of Processor light (1=on,0=off)
+ UCHAR ProcIrql; // Current IRQL
+ UCHAR ProcPad1; // Reserved (for padding)
+ USHORT ProcSlotAddr; // (slot << EISA_SHIFT)
+ USHORT ProcPad2; // Reserved (for padding)
+} WS3_HAL_PRIVATE, *PWS3_HAL_PRIVATE;
+
+/*
+endif
+
+; Start of Assembly only code
+
+;
+; Interrupt vector definitions for ASM
+;
+
+APIC_APC_VECTOR equ 030h
+APIC_DPC_VECTOR equ 040h
+
+APIC_IRQ16_VECTOR equ 060h
+APIC_IRQ17_VECTOR equ 061h
+APIC_IRQ18_VECTOR equ 062h
+APIC_IRQ19_VECTOR equ 063h
+APIC_IRQ20_VECTOR equ 064h
+APIC_IRQ21_VECTOR equ 065h
+APIC_IRQ22_VECTOR equ 066h
+APIC_IRQ23_VECTOR equ 067h
+
+APIC_IRQ8_VECTOR equ 070h
+APIC_IRQ9_VECTOR equ 071h
+APIC_IRQ10_VECTOR equ 072h
+APIC_IRQ11_VECTOR equ 073h
+APIC_IRQ12_VECTOR equ 074h
+APIC_IRQ13_VECTOR equ 075h
+APIC_IRQ14_VECTOR equ 076h
+APIC_IRQ15_VECTOR equ 077h
+
+APIC_IRQ0_VECTOR equ 080h
+APIC_IRQ1_VECTOR equ 081h
+APIC_IRQ2_VECTOR equ 082h
+APIC_IRQ3_VECTOR equ 083h
+APIC_IRQ4_VECTOR equ 084h
+APIC_IRQ5_VECTOR equ 085h
+APIC_IRQ6_VECTOR equ 086h
+APIC_IRQ7_VECTOR equ 087h
+
+APIC_RTC_VECTOR equ 070h
+APIC_MOUSE_VECTOR equ 074h
+APIC_DMA_VECTOR equ 075h
+APIC_IDE_VECTOR equ 076h
+APIC_KBD_VECTOR equ 081h
+APIC_FLOPPY_VECTOR equ 086h
+
+APIC_PROFILE_VECTOR equ 090h
+APIC_CLOCK_VECTOR equ 0A0h
+APIC_IPI_VECTOR equ 0B0h
+APIC_POWERFAIL_VECTOR equ 0C0h
+EISA_CLOCK_VECTOR equ 0D0h
+EISA_KBD_VECTOR equ 0D1h
+EISA_IRQ2_VECTOR equ 0D2h
+EISA_FLOPPY_VECTOR equ 0D6h
+EISA_PIC1_SPURIOUS_VECTOR equ 0D7h
+EISA_RTC_VECTOR equ 0D8h
+EISA_MOUSE_VECTOR equ 0DCh
+EISA_DMA_VECTOR equ 0DDh
+EISA_IDE_VECTOR equ 0DEh
+EISA_PIC2_SPURIOUS_VECTOR equ 0DFh
+APIC_SPURIOUS_VECTOR equ 0E0h
+APIC_SYSINT_VECTOR equ 0E1h
+APIC_HIGH_VECTOR equ 0F0h
+APIC_STALL_VECTOR equ 0F8h
+
+PIC0_BASE_VECTOR equ EISA_CLOCK_VECTOR
+PIC1_BASE_VECTOR equ EISA_RTC_VECTOR
+
+
+EISA_SHIFT equ 12 ; EISA slot starts at this offset
+EISA_MASK equ 0fffh ; Low bits of EISA slot address
+PostRegisterPort equ 080h ; BIOS post register
+OCW2_SPECIFIC_EOI equ 060h
+OCW2_NON_SPECIFIC_EOI equ 020h
+PIC1_PORT0 equ 020h
+PIC1_PORT1 equ 021h
+PIC2_PORT0 equ 0A0h
+PIC2_PORT1 equ 0A1h
+PIC3_PORT0 equ 0CC0h
+PIC3_PORT1 equ 0CC1h
+EISA_2_MPIC_POLARITY_REG equ 0C0Eh
+ELCR_MASK equ 0DEF8h
+PIC1_ELCR_PORT equ 04D0h
+PIC2_ELCR_PORT equ 04D1h
+DESTINATION_ALL_CPUS equ 0ffh
+DESTINATION_CPU_0 equ 1
+FCR equ 0C84h
+WarmResetVector equ 0467h
+FCR_RESET_MASK equ 0080h
+IOMPIC_RT_MASK equ 10000h
+FIRST_SYSTEM_SLOT equ 9
+LAST_SYSTEM_SLOT equ 15
+SLOT_ID_REG equ 0C80h
+SLOT_ID_BOARDTYPE equ 00F00000h
+SLOT_ID_TYPECPU equ 00100000h
+IOUNIT_APIC_ID equ 7
+IOUNIT2_APIC_ID equ 8
+D_INT032 equ 8E00h ; access word for 386 ring 0 interrupt gate
+PeriodInUsec equ 200
+
+
+IRQL_APIC_KBD equ 25
+IRQL_APIC_FLOPPY equ 21
+IRQL_APIC_RTC equ 19
+IRQL_APIC_DMA equ 14
+IRQL_APIC_IDE equ 13
+IRQL_APIC_MOUSE equ 15
+
+;
+; The kernel leaves some space (64 bytes) 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-dependent.
+; Must match the preceeding C structure.
+
+PcrE struc
+ PcrNumber db 0 ; Processor's number
+ ProcLightState db 0 ; State of Processor light
+ ProcIrql db 0 ; Current IRQL
+ ProcPad1 db 0 ; Reserved (for padding)
+ ProcSlotAddr dw 0 ; Slot (9-15) << 12
+ ProcPad2 dw 0 ; Reserved (for padding)
+PcrE ends
+
+CR equ 0dh
+LF equ 0ah
+
+IoDelay macro
+ push eax
+ in al, 020h
+ pop eax
+endm
+
+SET_8259_MASK macro
+ out PIC1_PORT1, al ; set master 8259 mask
+ shr eax, 8 ; shift slave 8259 mask to al
+ out PIC2_PORT1, al ; set slave 8259 mask
+endm
+
+PIC1DELAY macro
+ in al, PIC1_PORT1
+endm
+
+PIC2DELAY macro
+ in al, PIC2_PORT1
+endm
+
+DISABLE_INTERRUPTS_AT_CPU macro
+ pushfd ; save interrupt mode
+ cli ; disable interrupt
+endm
+
+RESTORE_INTERRUPTS_AT_CPU macro
+ popfd ; restore original interrupt mode
+endm
+
+;++
+;
+; SOFT_INTERRUPT_EXIT
+;
+; Macro Description:
+;
+; This macro is executed on return from the soft interrupt
+; service routine. Its function is to restore privileged processor
+; state, and continue thread execution.
+;
+; Arguments:
+;
+; (TOS) = previous irql
+; (TOS+4 ...) = machine_state frame
+;
+;--
+
+SOFT_INTERRUPT_EXIT macro
+
+ EXTRNP _KeLowerIrql,1
+ cli
+ call _KeLowerIrql@4 ; restore irql
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without EOI
+endm
+
+; Macro for programming IDT entries directly
+
+IDTEntry macro Vector, Handler
+ sub esp, 8 ; allocate temp stack space
+ sidt fword ptr [esp] ; IDT base + limit
+ mov edx, [esp+2] ; IDT linear base address
+ mov ecx, Vector ; get Vector
+ mov eax, offset FLAT:Handler ; Get Handler
+ mov word ptr [edx+8*ecx], ax ; Lower half of handler addr
+ mov word ptr [edx+8*ecx+2], KGDT_R0_CODE ; set up selector
+ mov word ptr [edx+8*ecx+4], D_INT032 ; 386 interrupt gate
+ shr eax, 16 ; (ax)=higher half of handler addr
+ mov word ptr [edx+8*ecx+6], ax
+ add esp, 8 ; deallocate temp stack space
+endm
+
+; End of Assembly only code
+;*/
diff --git a/private/ntos/nthals/halws3/i386/w3clock.asm b/private/ntos/nthals/halws3/i386/w3clock.asm
new file mode 100644
index 000000000..b45761307
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3clock.asm
@@ -0,0 +1,782 @@
+ title "Interval Clock Interrupt"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+; Copyright (c) 1993 Sequent Computer Systems, Inc.
+;
+; Module Name:
+;
+; w3clock.asm
+;
+; Abstract:
+;
+; This module implements the code necessary to field and process the
+; interval clock interrupt.
+;
+; Author:
+;
+; Phil Hochstetler (phil@sequent.com)
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc
+include i386\kimacro.inc
+include mac386.inc
+include i386\apic.inc
+include i386\ixcmos.inc
+include i386\w3.inc
+ .list
+
+ EXTRNP _DbgBreakPoint,0,IMPORT
+ EXTRNP _KeUpdateSystemTime,0
+ EXTRNP _KeUpdateRunTime,1,IMPORT
+ EXTRNP _KeProfileInterrupt,1,IMPORT
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _KeSetTimeIncrement,2,IMPORT
+ EXTRNP _HalEndSystemInterrupt,2
+ EXTRNP _HalBeginSystemInterrupt,3
+ extrn _HalpLocalUnitBase:DWORD
+ extrn _HalpW3PostRegisterImage:DWORD
+
+;
+; Constants used to initialize timer 0
+;
+
+TIMER1_DATA_PORT0 EQU 40H ; Timer1, channel 0 data port
+TIMER1_CONTROL_PORT0 EQU 43H ; Timer1, channel 0 control port
+TIMER2_DATA_PORT0 EQU 48H ; Timer1, channel 0 data port
+TIMER2_CONTROL_PORT0 EQU 4BH ; 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 ====
+;
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+;
+; 8254 spinlock. This must be acquired before touching the 8254 chip.
+;
+ public _Halp8254Lock
+_Halp8254Lock dd 0
+
+
+ public HalpPerfCounterLow, HalpPerfCounterHigh
+ public HalpLastPerfCounterLow, HalpLastPerfCounterHigh
+HalpPerfCounterLow dd 0
+HalpPerfCounterHigh dd 0
+HalpLastPerfCounterLow dd 0
+HalpLastPerfCounterHigh dd 0
+
+
+ public HalpCurrentRollOver, HalpCurrentTimeIncrement
+HalpCurrentRollOver dd 0
+HalpCurrentTimeIncrement dd 0
+
+;
+; 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 is 10.0144012689ms:
+; ROLLOVER_COUNT 11949
+; TIME_INCREMENT 100144
+; Calculated error is -.0109472 s/day
+;
+;
+; The following table contains 8254 values timer values to use at
+; any given ms setting from 1ms - 15ms. All values work out to the
+; same error per day (-.0109472 s/day).
+;
+
+ public HalpRollOverTable
+
+ ; RollOver Time
+ ; Count Increment MS
+HalpRollOverTable dd 1197, 10032 ; 1ms
+ dd 2394, 20064 ; 2 ms
+ dd 3591, 30096 ; 3 ms
+ dd 4767, 39952 ; 4 ms
+ dd 5964, 49984 ; 5 ms
+ dd 7161, 60016 ; 6 ms
+ dd 8358, 70048 ; 7 ms
+ dd 9555, 80080 ; 8 ms
+ dd 10731, 89936 ; 9 ms
+ dd 11949, 100144 ; 10 ms
+ dd 13125, 110000 ; 11 ms
+ dd 14322, 120032 ; 12 ms
+ dd 15519, 130064 ; 13 ms
+ dd 16695, 139920 ; 14 ms
+ dd 17892, 149952 ; 15 ms
+
+TimeIncr equ 4
+RollOver equ 0
+
+ public HalpLargestClockMS, HalpNextMSRate, HalpPendingMSRate
+HalpLargestClockMS dd 15 ; Table goes to 15MS
+HalpNextMSRate dd 0
+HalpPendingMSRate dd 0
+
+
+_DATA ends
+
+
+INIT 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 10ms interval at EISA_CLOCK_VECTOR
+;
+; The Eisa clock interrupt handler then IPIs all processors at
+; APIC_CLOCK_VECTOR
+;
+; See the definitions of TIME_INCREMENT and ROLLOVER_COUNT if clock rate
+; needs to be changed.
+;
+; This routine assumes it runs during Phase 0 on P0.
+;
+; Arguments:
+;
+; None
+;
+; Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalpInitializeClock ,0
+
+ mov eax, PCR[PcPrcb]
+ cmp byte ptr [eax].PbCpuType, 4 ; 486 or better?
+ jc short @f ; no, skip
+
+ mov HalpLargestClockMS, 10 ; Limit 486's to 10MS
+@@:
+ mov eax, HalpLargestClockMS
+ mov ecx, HalpRollOverTable.TimeIncr
+ mov edx, HalpRollOverTable[eax*8-8].TimeIncr
+ mov eax, HalpRollOverTable[eax*8-8].RollOver
+
+ mov HalpCurrentTimeIncrement, edx
+
+;
+; (ecx) = Min time_incr
+; (edx) = Max time_incr
+; (eax) = max roll over count
+;
+
+ push eax
+ stdCall _KeSetTimeIncrement, <edx, ecx>
+ 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 HalpCurrentRollOver, ecx ; Set RollOverCount & initialized
+
+ stdRET _HalpInitializeClock
+
+stdENDP _HalpInitializeClock
+
+INIT ends
+
+_TEXT$03 SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+ page ,132
+ subttl "Query Performance Counter"
+;++
+;
+; LARGE_INTEGER
+; KeQueryPerformanceCounter (
+; OUT PLARGE_INTEGER PerformanceFrequency OPTIONAL
+; )
+;
+; Routine Description:
+;
+; This routine returns current 64-bit performance counter and,
+; optionally, the Performance Frequency.
+;
+; Note this routine can NOT be called at Profiling interrupt
+; service routine. Because this routine depends on IRR0 to determine
+; the actual count.
+;
+; Also note that the performace counter returned by this routine
+; is not necessary the value when this routine is just entered.
+; The value returned is actually the counter value at any point
+; between the routine is entered and is exited.
+;
+; Arguments:
+;
+; PerformanceFrequency [TOS+4] - optionally, supplies the address
+; of a variable to receive the performance counter frequency.
+;
+; Return Value:
+;
+; Current value of the performance counter will be returned.
+;
+;--
+
+;
+; Parameter definitions
+;
+
+KqpcFrequency EQU [esp+12] ; User supplied Performance Frequence
+
+cPublicProc _KeQueryPerformanceCounter ,1
+cPublicFpo 1, 0
+;
+; 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 Timer
+; initialization has occured. Reading garbage off the Timer is not reasonable.
+;
+ cmp HalpCurrentRollOver, 0
+ je Kqpc50
+
+ push ebx
+ push esi
+
+Kqpc01: pushfd
+ cli
+Kqpc20:
+ifndef NT_UP
+ lea eax, _Halp8254Lock
+ ACQUIRE_SPINLOCK eax, Kqpc198
+endif
+
+;
+; Fetch the base value. Note that interrupts are off.
+;
+
+@@:
+ mov ebx, HalpPerfCounterLow
+ mov esi, HalpPerfCounterHigh ; [esi:ebx] = Performance counter
+
+ cmp ebx, HalpPerfCounterLow
+ jne @b
+
+;
+; Fetch the current counter value from the hardware
+;
+
+ mov al, COMMAND_8254_LATCH_READ+COMMAND_8254_COUNTER0
+ ;Latch PIT Ctr 0 command.
+ out TIMER1_CONTROL_PORT0, al
+ IoDelay
+ in al, TIMER1_DATA_PORT0 ;Read PIT Ctr 0, LSByte.
+ movzx ecx,al ;Zero upper bytes of (ECX).
+ IoDelay
+ in al, TIMER1_DATA_PORT0 ;Read PIT Ctr 0, MSByte.
+ mov ch, al ;(CX) = PIT Ctr 0 count.
+
+ifndef NT_UP
+ lea eax, _Halp8254Lock
+ RELEASE_SPINLOCK eax
+endif
+
+
+;
+; 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
+
+;
+; Fetch the base value again.
+;
+
+@@:
+ mov eax, HalpPerfCounterLow
+ mov edx, HalpPerfCounterHigh ; [edx:eax] = new counter value
+
+ cmp eax, HalpPerfCounterLow
+ jne @b
+;
+; Compare the two reads of Performance counter. If they are different,
+; start over
+;
+
+ cmp eax, ebx
+ jne Kqpc20
+ cmp edx, esi
+ jne Kqpc20
+
+ neg ecx ; PIT counts down from 0h
+ add ecx, HalpCurrentRollOver
+ jnc short Kqpc60
+
+Kqpc30:
+ add eax, ecx
+ adc edx, 0 ; [edx:eax] = Final result
+
+ cmp edx, HalpLastPerfCounterHigh
+ jc short Kqpc70 ; jmp if edx < lastperfcounterhigh
+ jne short Kqpc35 ; jmp if edx > lastperfcounterhigh
+
+ cmp eax, HalpLastPerfCounterLow
+ jc short Kqpc70 ; jmp if eax < lastperfcounterlow
+
+Kqpc35:
+ mov HalpLastPerfCounterLow, eax
+ mov HalpLastPerfCounterHigh, edx
+
+ popfd ; restore interrupt flag
+
+
+;
+; Return the freq. if caller wants it.
+;
+ cmp dword ptr KqpcFrequency, 0 ; is it a NULL variable?
+ jz short Kqpc40 ; 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
+
+Kqpc40:
+ pop esi ; restore esi and ebx
+ pop ebx
+ stdRET _KeQueryPerformanceCounter
+
+Kqpc50:
+; Initialization hasn't occured yet, so just return zeroes.
+ mov eax, 0
+ mov edx, 0
+ stdRET _KeQueryPerformanceCounter
+
+Kqpc60:
+;
+; The current count is larger then the HalpCurrentRollOver. The only way
+; that could happen is if there is an interrupt in route to the processor
+; but it was not processed while interrupts were enabled.
+;
+ mov esi, [esp] ; (esi) = flags
+ mov ecx, HalpCurrentRollOver ; (ecx) = max possible value
+ popfd ; restore flags
+
+ test esi, EFLAGS_INTERRUPT_MASK
+ jnz Kqpc01 ; ints are enabled, problem should go away
+
+ pushfd ; fix stack
+ jmp short Kqpc30 ; ints are disabled, use max count (ecx)
+
+Kqpc70:
+;
+; The current count is smaller then the last returned count. The only way
+; this should occur is if there is an interrupt in route to the processor
+; which was not been processed.
+;
+
+ mov ebx, HalpLastPerfCounterLow
+ mov esi, HalpLastPerfCounterHigh
+
+ mov ecx, ebx
+ or ecx, esi ; is last returned value 0?
+ jz short Kqpc35 ; Yes, then just return what we have
+
+ ; sanity check - make sure count is not off by bogus amount
+ sub ebx, eax
+ sbb esi, edx
+ jnz short Kqpc75 ; off by bogus amount
+ cmp ebx, HalpCurrentRollOver
+ jg short Kqpc75 ; off by bogus amount
+
+ sub eax, ebx
+ sbb edx, esi ; (edx:eax) = last returned count
+
+ mov ecx, [esp] ; (ecx) = flags
+ popfd
+
+ test ecx, EFLAGS_INTERRUPT_MASK
+ jnz Kqpc01 ; ints enabled, problem should go away
+
+ pushfd ; fix stack
+ jmp Kqpc35 ; ints disabled, just return last count
+
+Kqpc75:
+ popfd
+ xor eax, eax ; reset bogus values
+ mov HalpLastPerfCounterLow, eax
+ mov HalpLastPerfCounterHigh, eax
+ jmp Kqpc01 ; go try again
+
+ifndef NT_UP
+Kqpc198: popfd
+ SPIN_ON_SPINLOCK eax,<Kqpc01>
+endif
+
+stdENDP _KeQueryPerformanceCounter
+
+;++
+;
+; 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
+cPublicFpo 1, 0
+
+ mov eax, [esp+4] ; ponter to Number
+cPublicFpo 1, 1
+ pushfd ; save previous interrupt state
+ cli ; disable interrupts (go to high_level)
+
+ lock dec dword ptr [eax] ; count down
+
+@@: cmp dword ptr [eax], 0 ; wait for all processors to signal
+ jnz short @b
+
+ ;
+ ; Nothing to calibrate on this apic based MP machine. There is only
+ ; a single 8254 device in use
+ ;
+
+cPublicFpo 1, 0
+ popfd ; restore interrupt flag
+ stdRET _HalCalibratePerformanceCounter
+
+stdENDP _HalCalibratePerformanceCounter
+
+
+
+ page ,132
+ subttl "System Clock Interrupt"
+;++
+;
+; Routine Description:
+;
+;
+; This routine is entered as the result of an interrupt generated by CLOCK2.
+; Its function is to dismiss the interrupt, raise system Irql to
+; CLOCK2_LEVEL, update performance counter and transfer control to the
+; standard system routine to update the system time and the execution
+; time of the current thread
+; and process.
+;
+;
+; Arguments:
+;
+; None
+; Interrupt is disabled
+;
+; Return Value:
+;
+; Does not return, jumps directly to KeUpdateSystemTime, which returns
+;
+; Sets Irql = CLOCK2_LEVEL and dismisses the interrupt
+;
+;--
+
+ ENTER_DR_ASSIST Hci_a, Hci_t
+
+cPublicProc _HalpClockInterrupt ,0
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT Hci_a, Hci_t
+
+;
+; (esp) - base of trap frame
+;
+; dismiss interrupt and raise Irql
+;
+
+ push APIC_CLOCK_VECTOR
+ sub esp, 4 ; allocate space to save OldIrql
+ stdCall _HalBeginSystemInterrupt, <CLOCK2_LEVEL,APIC_CLOCK_VECTOR,esp>
+ or al,al ; check for spurious interrupt
+ jz Hci100
+
+;
+; Turn off (on) the processor active light to reflect whether
+; we are (are not) currently executing the Idle Thread.
+;
+
+ mov edi, PCR[PcPrcb] ; (edi) -> Prcb
+ mov eax, [edi].PbCurrentThread
+ cmp eax, [edi].PbIdleThread ; running idle thread?
+ setnz al ; set al to desired light state
+ cmp al, byte ptr PCR[PcHal.ProcLightState]
+ jne Hci05
+Hci10:
+
+ifndef NT_UP
+ cmp byte ptr PCR[PcHal.PcrNumber], 0 ; Only P0 Will update System Time
+ je Do_P0Timer
+
+ ;
+ ; All processors will update RunTime for current thread
+ ;
+
+ sti
+ ; TOS const PreviousIrql
+ stdCall _KeUpdateRunTime,<dword ptr [esp]>
+
+ INTERRUPT_EXIT ; lower irql to old value, iret
+
+ ;
+ ; We don't return here
+ ;
+
+
+Do_P0Timer:
+
+endif
+
+;
+; Update front panel light show
+;
+ mov eax, _HalpW3PostRegisterImage ; get current bits
+ and al, 01111111b ; clear disk error bit
+ out PostRegisterPort, al ; write PostCode Reg
+
+;
+; Update performance counter
+;
+
+ mov eax, HalpCurrentRollOver
+ add HalpPerfCounterLow, eax ; update performace counter
+ adc HalpPerfCounterHigh, dword ptr 0
+
+ mov eax, HalpCurrentTimeIncrement
+Hci30:
+
+;
+; (esp) = OldIrql
+; (esp+4) = Vector
+; (esp+8) = base of trap frame
+; ebp = trap frame
+; eax = time increment
+;
+ cmp HalpNextMSRate, 0 ; New clock rate desired?
+ jz _KeUpdateSystemTime@0 ; No, process tick
+
+;
+; Time of clock frequency is being changed. See if the 8254 was
+; was reprogrammed for a new rate during last tick
+;
+ cmp HalpPendingMSRate, 0 ; Was a new rate set durning last
+ jnz short Hci50 ; tick? Yes, go update globals
+
+Hci40:
+; (eax) = time increment for current tick
+
+;
+; A new clock rate needs to be set. Setting the rate here will
+; cause the tick after the next tick to be at the new rate.
+; (the next tick is already in progress by the 8254 and will occur
+; at the same rate as this tick)
+;
+Kci01: pushfd
+ cli
+ifndef NT_UP
+ lea ecx, _Halp8254Lock
+ ACQUIRE_SPINLOCK ecx, Kci198
+endif
+ mov ebx, HalpNextMSRate
+ mov HalpPendingMSRate, ebx ; pending rate
+
+ mov ecx, HalpRollOverTable[ebx*8-8].RollOver
+
+;
+; Set clock rate
+; (ecx) = RollOverCount
+;
+
+ push eax ; save current tick's rate
+
+
+ mov al,COMMAND_8254_COUNTER0+COMMAND_8254_RW_16BIT+COMMAND_8254_MODE2
+ out TIMER1_CONTROL_PORT0, al ;program count mode of timer 0
+ IoDelay
+ mov 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
+
+ifndef NT_UP
+ lea eax, _Halp8254Lock
+ RELEASE_SPINLOCK eax
+endif
+
+ pop eax
+ popfd
+ jmp Hci30 ; dispatch this tick
+
+Hci50:
+;
+; The next tick will occur at the rate which was programmed during the last
+; tick. Update globals for new rate which starts with the next tick.
+;
+; (eax) = time increment for current tick
+;
+ mov ebx, HalpPendingMSRate
+ mov ecx, HalpRollOverTable[ebx*8-8].RollOver
+ mov edx, HalpRollOverTable[ebx*8-8].TimeIncr
+
+ mov HalpCurrentRollOver, ecx
+ mov HalpCurrentTimeIncrement, edx ; next tick rate
+ mov HalpPendingMSRate, 0 ; no longer pending, clear it
+
+ cmp ebx, HalpNextMSRate ; new rate == NextRate?
+ jne Hci40 ; no, go set new pending rate
+
+ mov HalpNextMSRate, 0 ; we are at this rate, clear it
+ jmp Hci30 ; process this tick
+
+Hci100:
+ add esp, 8 ; spurious, no EndOfInterrupt
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+ifndef NT_UP
+Kci198: popfd
+ SPIN_ON_SPINLOCK ecx,<Kqpc01>
+endif
+
+;
+; Update the state of hardware lights and state variable
+;
+Hci05:
+ cmp al, 1 ; identify light going
+ je Hci06 ; on (or going off)
+
+; Turn light off that was on
+
+ xor eax, eax
+ mov al, byte ptr PCR[PcHal.PcrNumber] ; get processor number
+ lock btr _HalpW3PostRegisterImage, eax ; clear the bit
+ mov byte ptr PCR[PcHal.ProcLightState], 0 ; update flag
+ jmp hci10 ; return
+
+; Turn light on that was off
+Hci06:
+ xor eax, eax
+ mov al, byte ptr PCR[PcHal.PcrNumber] ; get processor number
+ lock bts _HalpW3PostRegisterImage, eax ; set the bit
+ mov byte ptr PCR[PcHal.ProcLightState], 1 ; update flag
+ jmp hci10 ; return
+
+stdENDP _HalpClockInterrupt
+
+;++
+;
+; 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, [esp+4] ; desired setting
+ xor edx, edx
+ mov ecx, 10000
+ div ecx ; round to MS
+
+ cmp eax, HalpLargestClockMS ; MS > max?
+ jc short @f
+ mov eax, HalpLargestClockMS ; yes, use max
+@@:
+ or eax, eax ; MS < min?
+ jnz short @f
+ inc eax ; yes, use min
+@@:
+ mov HalpNextMSRate, eax
+
+ mov eax, HalpRollOverTable[eax*8-8].TimeIncr
+ stdRET _HalSetTimeIncrement
+
+stdENDP _HalSetTimeIncrement
+_TEXT$03 ends
+
+ end
diff --git a/private/ntos/nthals/halws3/i386/w3detect.asm b/private/ntos/nthals/halws3/i386/w3detect.asm
new file mode 100644
index 000000000..0a77c4b3b
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3detect.asm
@@ -0,0 +1,106 @@
+;++
+;
+; Copyright (c) 1991 Microsoft Corporation
+; Copyright (c) 1993,1994 Sequent Computer Systems, Inc.
+;
+; Module Name:
+;
+; w3detect.asm
+;
+; Abstract:
+;
+; This module detects a Sequent WinServer 3000. It is included
+; by w3ipi.asm and the setup program. It must assemble more or less
+; standalone and run in protected mode.
+;
+; Author:
+;
+; Phil Hochstetler (phil@sequent.com) 3-30-93
+;
+; Revision History:
+;
+;--
+
+include callconv.inc
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+; W3SystemType: SystemType is read from 0c80-0c83.
+;
+; 0c80-0c81: Compressed "TRI" (5 bit encoding).
+; 0c82: System Board Type.
+; 0c83: System Board Revision Level.
+
+
+W3SystemTypeTable db 052h, 049h, 08h, 00h
+W3SystemType db 5 dup(0)
+
+_DATA ends
+
+ page ,132
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+;++
+; ULONG
+; DetectWS3000(
+; OUT PBOOLEAN IsConfiguredMp
+; );
+;
+; Routine Description:
+; Determines the type of system (specifically for eisa machine), by reading
+; the system board system ID. It compares the 4 bytes of the ID, to
+; a predefined table <W3SystemTypeTable> and returns the index to the
+; found entry.
+;
+; Arguments:
+; IsConfiguredMp - If detected, then this value is
+; set to TRUE if it's an MP system, else FALSE.
+;
+; Return Value:
+;
+; A value of 1 is returned if a WS3000 machine is detected.
+; Otherwise a value of 0 is returned.
+;--
+cPublicProc _DetectWS3000 ,1
+cPublicFpo 1, 3
+
+ push edi
+ push esi
+ push ebx ; Save C Runtime
+
+ ; A 4 byte value is read from 0c80-0c83, and saved in <W3SystemType>.
+ ; This value is compared to the first 3 bytes of the value in
+ ; <W3SystemTypeTable>.
+
+ cld ; set direction to forward
+ lea edi, W3SystemType
+ mov edx, 0c80h
+ insb ; 52h
+ inc edx
+ insb ; 49h
+ inc edx
+ insb ; 08h - System Board Type
+ inc edx
+ insb ; 00h - Revision Level
+
+ xor eax, eax ; default to return failure
+ lea edi, W3SystemTypeTable ; Type Table
+ mov ecx, 3 ; bytes to compare against
+ lea esi, W3SystemType ; match string against table entry
+ repe cmpsb ; if (ecx == 0 and ZF set)
+ jnz @f ; we have a winner
+ inc al
+ mov ebx, dword ptr [esp+16]
+ mov byte ptr [ebx], 1 ; *IsConfiguredMp = TRUE
+
+@@:
+ pop ebx
+ pop esi
+ pop edi ; Restore C Runtime
+
+ stdRET _DetectWS3000
+
+stdENDP _DetectWS3000
+
+_TEXT ENDS
diff --git a/private/ntos/nthals/halws3/i386/w3hal.c b/private/ntos/nthals/halws3/i386/w3hal.c
new file mode 100644
index 000000000..a0476e92b
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3hal.c
@@ -0,0 +1,660 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1993,1994 Sequent Computer Systems, Inc.
+
+Module Name:
+
+ w3hal.c
+
+Abstract:
+
+
+ This module implements the initialization of the system dependent
+ functions that define the Hardware Architecture Layer (HAL) for an
+ x86 system.
+
+Author:
+
+ Phil Hochstetler (phil@sequent.com)
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "w3.inc"
+
+UCHAR SequentCopyright[] = "\n\n\
+Copyright (c) 1993,1994\n\
+Sequent Computer Systems, Inc. All rights reserved.\n\
+ \n\
+This software is furnished under a license and may be used\n\
+only in accordance with the terms of that license and with the\n\
+inclusion of the above copyright notice. This software may not\n\
+be provided or otherwise made available to, or used by, any\n\
+other person. No title to or ownership of the software is\n\
+hereby transferred.\n\n";
+
+ULONG HalpBusType;
+ULONG ProcessorsPresent;
+
+extern ADDRESS_USAGE HalpDefaultPcIoSpace;
+extern ADDRESS_USAGE HalpEisaIoSpace;
+
+ADDRESS_USAGE HalpW3IoSpace = {
+ NULL, CmResourceTypePort, InternalUsage,
+ {
+ 0x800, 0x100, // EISA CMOS Page
+ 0xC00, 0x10, // SBC
+ 0xC10, 0x10, // EISA Page Select
+ 0xC20, 0x10, // LCD
+ 0xC30, 0x10, // Cache Flush
+ 0xC80, 0x4, // EISA SBID
+ 0xC84, 0x4, // EISA SBE
+ 0xCC0, 0x2, // PIC 3
+ 0xCC2, 0x3E, // Reserved
+ 0,0
+ }
+};
+
+#ifdef NT_UP
+
+UCHAR UPWarn[] = "\
+HAL: Incorrect system configuration.\n\
+HAL: Uniprocessor HAL.DLL and NTOSKRNL.EXE are running\n\
+HAL: on a system that contains more than one processor.\n\
+HAL: Please install multiprocessor HAL.DLL and NTOSKRNL.EXE to correct.\n\
+HAL: Only using 1 processor to allow system boot to continue.\n";
+
+#else
+
+UCHAR MPWarn[] = "\
+HAL: Incorrect system configuration.\n\
+HAL: Multiprocessor HAL.DLL and NTOSKRNL.EXE are running\n\
+HAL: on a system that contains only one processor.\n\
+HAL: Please install uniprocessor HAL.DLL and NTOSKRNL.EXE to correct.\n";
+
+#endif
+
+#ifndef NT_UP
+ULONG
+HalpInitMP(
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ );
+#endif
+
+KSPIN_LOCK HalpSystemHardwareLock;
+
+VOID
+HalpIpiHandler(
+ VOID
+ );
+
+USHORT
+HalpMySlotAddr(
+ );
+
+VOID
+HalpSetProcessorsPresent(
+ );
+
+//
+// CAUTION!! these local vector definitions must match those in w3.inc
+// these are included to avoid conflicts with vectors defined in ix8259.inc
+// (which is included by halp.h)
+//
+#define APIC_PROFILE_VECTOR 0x90
+#define APIC_CLOCK_VECTOR 0xA0
+#define APIC_IPI_VECTOR 0xB0
+
+#define KB_STAT 0x64 // keyboard controller status
+#define KB_IDAT 0x60 // input buffer data write
+#define KB_OUTBF 0x01 // output buffer full
+
+extern UCHAR HalName[];
+extern PKPCR HalpProcessorPCR[];
+
+
+VOID
+HalpGetUserInput (
+ )
+
+{
+ UCHAR i, j;
+ UCHAR byte;
+ UCHAR OldPicMask;
+
+ //
+ // Mask keyboard interrupt directly at the PIC
+ //
+ OldPicMask = READ_PORT_UCHAR((PUCHAR) 0x21);
+ WRITE_PORT_UCHAR((PUCHAR) 0x21, (UCHAR)(OldPicMask | 1));
+
+ j = 1;
+ do {
+ for (i = 0; i < 50; i++) {
+ // flush all keyboard input
+ if (READ_PORT_UCHAR((PUCHAR) KB_STAT) & KB_OUTBF)
+ byte = READ_PORT_UCHAR((PUCHAR) KB_IDAT); // read scan code
+ KeStallExecutionProcessor(1000); // delay 1 ms
+ }
+ if (j == 1) {
+ HalDisplayString("HAL: Press any key to continue ...");
+ while ((READ_PORT_UCHAR((PUCHAR) KB_STAT) & KB_OUTBF) == 0)
+ continue;
+ HalDisplayString("\n");
+ }
+ } while (j-- > 0);
+
+ WRITE_PORT_UCHAR((PUCHAR) 0x21, OldPicMask); // restore mask
+ return;
+}
+
+
+BOOLEAN
+HalInitSystem (
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+
+/*++
+
+Routine Description:
+
+ This function initializes the Hardware Architecture Layer (HAL) for
+ the WINSERVER 3000 x86 SMP system.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ A value of TRUE is returned is the initialization was successfully
+ complete. Otherwise a value of FALSE is returend.
+
+--*/
+
+{
+ PMEMORY_ALLOCATION_DESCRIPTOR Descriptor;
+ PLIST_ENTRY NextMd;
+ KIRQL CurrentIrql;
+ PKPRCB pPRCB;
+
+ pPRCB = KeGetCurrentPrcb();
+
+ if (Phase == 0) {
+
+ HalpBusType = LoaderBlock->u.I386.MachineType & 0x00ff;
+
+ //
+ // Verify Prcb version and build flags conform to
+ // this image
+ //
+
+#if DBG
+ if (!(pPRCB->BuildType & PRCB_BUILD_DEBUG)) {
+ // This checked hal requires a checked kernel
+ KeBugCheckEx (MISMATCHED_HAL,
+ 2, pPRCB->BuildType, PRCB_BUILD_DEBUG, 0);
+ }
+#else
+ if (pPRCB->BuildType & PRCB_BUILD_DEBUG) {
+ // This free hal requires a free kernel
+ KeBugCheckEx (MISMATCHED_HAL, 2, pPRCB->BuildType, 0, 0);
+ }
+#endif
+#ifndef NT_UP
+ if (pPRCB->BuildType & PRCB_BUILD_UNIPROCESSOR) {
+ // This MP hal requires an MP kernel
+ KeBugCheckEx (MISMATCHED_HAL, 2, pPRCB->BuildType, 0, 0);
+ }
+#endif
+ if (pPRCB->MajorVersion != PRCB_MAJOR_VERSION) {
+ KeBugCheckEx (MISMATCHED_HAL,
+ 1, pPRCB->MajorVersion, PRCB_MAJOR_VERSION, 0);
+ }
+
+ HalpSetProcessorsPresent();
+ ProcessorsPresent &= ~(1 << (HalpMySlotAddr() >> EISA_SHIFT));
+
+#ifdef NT_UP
+ if (ProcessorsPresent) {
+ HalDisplayString(UPWarn); // UP HAL/NTOSKRNL on MP HW
+ ProcessorsPresent = 0; // Hide procs to allow boot
+ HalpGetUserInput();
+ }
+#else
+ if (ProcessorsPresent == 0) {
+ HalDisplayString(MPWarn); // MP HAL/NTOSKRNL on UP HW
+ HalpGetUserInput();
+ }
+#endif
+
+ //
+ // Phase 0 initialization only called by P0
+ //
+
+ HalpInitializePICs();
+
+ //
+ // Initialize CMOS
+ //
+
+ HalpInitializeCmos();
+
+ //
+ // Register cascade vector
+ //
+
+ HalpRegisterVector (
+ InternalUsage, EISA_IRQ2_VECTOR, EISA_IRQ2_VECTOR, HIGH_LEVEL );
+
+ //
+ // Register PIC vectors
+ //
+
+ HalpRegisterVector (
+ InternalUsage,
+ EISA_PIC1_SPURIOUS_VECTOR,
+ EISA_PIC1_SPURIOUS_VECTOR,
+ HIGH_LEVEL );
+
+ HalpRegisterVector (
+ InternalUsage,
+ EISA_PIC2_SPURIOUS_VECTOR,
+ EISA_PIC2_SPURIOUS_VECTOR,
+ HIGH_LEVEL );
+
+ HalpRegisterVector (
+ DeviceUsage,
+ EISA_CLOCK_VECTOR,
+ EISA_CLOCK_VECTOR,
+ HIGH_LEVEL );
+
+ HalpRegisterVector (
+ DeviceUsage,
+ EISA_KBD_VECTOR,
+ EISA_KBD_VECTOR,
+ HIGH_LEVEL );
+
+ HalpRegisterVector (
+ DeviceUsage,
+ EISA_FLOPPY_VECTOR,
+ EISA_FLOPPY_VECTOR,
+ HIGH_LEVEL );
+
+ HalpRegisterVector (
+ DeviceUsage,
+ EISA_RTC_VECTOR,
+ EISA_RTC_VECTOR,
+ HIGH_LEVEL );
+
+ HalpRegisterVector (
+ DeviceUsage,
+ EISA_MOUSE_VECTOR,
+ EISA_MOUSE_VECTOR,
+ HIGH_LEVEL );
+
+ HalpRegisterVector (
+ DeviceUsage,
+ EISA_DMA_VECTOR,
+ EISA_DMA_VECTOR,
+ HIGH_LEVEL );
+
+ HalpRegisterVector (
+ DeviceUsage,
+ EISA_IDE_VECTOR,
+ EISA_IDE_VECTOR,
+ HIGH_LEVEL );
+
+ //
+ // Register APIC spurious vector
+ //
+
+ HalpRegisterVector (
+ InternalUsage,
+ APIC_SPURIOUS_VECTOR,
+ APIC_SPURIOUS_VECTOR,
+ HIGH_LEVEL );
+
+ //
+ // Now that the PICs are initialized, we need to mask them to
+ // reflect the current Irql
+ //
+
+ CurrentIrql = KeGetCurrentIrql();
+ CurrentIrql = KfRaiseIrql(CurrentIrql);
+
+ //
+ // Fill in handlers for APIs which this hal supports
+ //
+
+ HalQuerySystemInformation = HaliQuerySystemInformation;
+ HalSetSystemInformation = HaliSetSystemInformation;
+
+ //
+ // Register base IO space used by hal
+ //
+
+ HalpRegisterAddressUsage (&HalpDefaultPcIoSpace);
+ HalpRegisterAddressUsage (&HalpEisaIoSpace);
+ HalpRegisterAddressUsage (&HalpW3IoSpace);
+
+ //
+ // P0's stall execution is initialized here to allow the kernel
+ // debugger to work properly before initializing all the other
+ // processors.
+ //
+
+ HalpInitializeStallExecution(0);
+
+ HalpEnableInterruptHandler (
+ DeviceUsage, // Report as device vector
+ APIC_CLOCK_VECTOR, // Bus interrupt level
+ APIC_CLOCK_VECTOR, // System IDT
+ CLOCK2_LEVEL, // System Irql
+ HalpClockInterrupt, // IRS
+ Latched );
+
+ HalpInitializeClock();
+
+ //
+ // Initialize the profile interrupt vector.
+ //
+
+ HalStopProfileInterrupt(0);
+
+ HalpEnableInterruptHandler (
+ DeviceUsage, // Report as device vector
+ APIC_PROFILE_VECTOR, // Bus interrupt level
+ APIC_PROFILE_VECTOR, // System IDT
+ PROFILE_LEVEL, // System Irql
+ HalpProfileInterrupt, // IRS
+ Latched );
+
+ //
+ // Initialize the IPI handler
+ //
+
+ HalpEnableInterruptHandler (
+ DeviceUsage, // Report as device vector
+ APIC_IPI_VECTOR, // Bus interrupt level
+ APIC_IPI_VECTOR, // System IDT
+ IPI_LEVEL, // System Irql
+ HalpIpiHandler, // IRS
+ Latched );
+
+ HalpInitializeDisplay();
+
+ //
+ // Initialize spinlock used by HalGetBusData hardware access routines
+ //
+
+ KeInitializeSpinLock(&HalpSystemHardwareLock);
+
+ //
+ // Determine if there is physical memory above 16 MB.
+ //
+
+ LessThan16Mb = TRUE;
+
+ NextMd = LoaderBlock->MemoryDescriptorListHead.Flink;
+
+ while (NextMd != &LoaderBlock->MemoryDescriptorListHead) {
+ Descriptor = CONTAINING_RECORD( NextMd,
+ MEMORY_ALLOCATION_DESCRIPTOR,
+ ListEntry );
+
+ if (Descriptor->BasePage + Descriptor->PageCount > 0x1000) {
+ LessThan16Mb = FALSE;
+ }
+
+ NextMd = Descriptor->ListEntry.Flink;
+ }
+
+ //
+ // Determine the size need for map buffers. If this system has
+ // memory with a physical address of greater than
+ // MAXIMUM_PHYSICAL_ADDRESS, then allocate a large chunk; otherwise,
+ // allocate a small chunk.
+ //
+
+ if (LessThan16Mb) {
+
+ //
+ // Allocate a small set of map buffers. They are only need for
+ // slave DMA devices.
+ //
+
+ HalpMapBufferSize = INITIAL_MAP_BUFFER_SMALL_SIZE;
+
+ } else {
+
+ //
+ // Allocate a larger set of map buffers. These are used for
+ // slave DMA controllers and Isa cards.
+ //
+
+ HalpMapBufferSize = INITIAL_MAP_BUFFER_LARGE_SIZE;
+
+ }
+
+ //
+ // Allocate map buffers for the adapter objects
+ //
+
+ HalpMapBufferPhysicalAddress.LowPart =
+ HalpAllocPhysicalMemory (LoaderBlock, MAXIMUM_PHYSICAL_ADDRESS,
+ HalpMapBufferSize >> PAGE_SHIFT, TRUE);
+ HalpMapBufferPhysicalAddress.HighPart = 0;
+
+
+ if (!HalpMapBufferPhysicalAddress.LowPart) {
+
+ //
+ // There was not a satisfactory block. Clear the allocation.
+ //
+
+ HalpMapBufferSize = 0;
+ }
+
+ //
+ // Print copyright notice
+ //
+
+ HalDisplayString(HalName);
+ HalDisplayString(SequentCopyright);
+
+ } else {
+
+ //
+ // Phase 1 initialization
+ //
+
+ if (pPRCB->Number == 0) {
+
+ HalpRegisterInternalBusHandlers ();
+
+ } else {
+
+ //
+ // Other processors inherit P0 stall factor.
+ // This assumes all procs have the same basic speed.
+ //
+
+ KiPcr()->StallScaleFactor = HalpProcessorPCR[0]->StallScaleFactor;
+ }
+
+ HalpEnableInterruptHandler (
+ DeviceUsage, // Report as device vector
+ APIC_PROFILE_VECTOR, // Bus interrupt level
+ APIC_PROFILE_VECTOR, // System IDT
+ PROFILE_LEVEL, // System Irql
+ HalpProfileInterrupt, // IRS
+ Latched );
+
+ HalpEnableInterruptHandler (
+ DeviceUsage, // Report as device vector
+ APIC_CLOCK_VECTOR, // Bus interrupt level
+ APIC_CLOCK_VECTOR, // System IDT
+ CLOCK2_LEVEL, // System Irql
+ HalpClockInterrupt, // IRS
+ Latched );
+
+ HalpEnableInterruptHandler (
+ DeviceUsage, // Report as device vector
+ APIC_IPI_VECTOR, // Bus interrupt level
+ APIC_IPI_VECTOR, // System IDT
+ IPI_LEVEL, // System Irql
+ HalpIpiHandler, // IRS
+ Latched );
+
+ }
+
+#ifndef NT_UP
+ HalpInitMP (Phase, LoaderBlock);
+#endif
+
+ return TRUE;
+}
+
+//
+// XXX, hack for now. Need to remove this code.
+//
+
+static UCHAR tmasterline[] = {0, 2, 5, 0};
+
+static USHORT cmdport[] /* command port addrs for pics */
+ = { PIC1_PORT0, PIC2_PORT0, PIC2_PORT0 };
+
+static USHORT imrport[] /* intr mask port addrs for pics */
+ = { PIC1_PORT1, PIC2_PORT1, PIC2_PORT1 };
+
+VOID
+Halptpicinit()
+{
+ ULONG cmd, imr, pic;
+
+/*
+ * --- Initialize the 8259s
+ */
+
+#define PIC_EDGED 0
+#define PIC_ICW1BASE 0x10
+#define PIC_NEEDICW4 1
+#define PIC_86MODE 1
+#define PIC_READISR 0xb
+#define PIC_SLAVEBUF 0x8
+ /*
+ * Initialize master ICW1-ICW4
+ */
+ WRITE_PORT_UCHAR((PUCHAR)cmdport[0], (UCHAR)PIC_EDGED | PIC_ICW1BASE | PIC_NEEDICW4);
+ WRITE_PORT_UCHAR((PUCHAR)imrport[0], (UCHAR)PIC0_BASE_VECTOR);
+ WRITE_PORT_UCHAR((PUCHAR)imrport[0], (UCHAR)0x4); /* Cascade IRQ2 */
+ WRITE_PORT_UCHAR((PUCHAR)imrport[0], (UCHAR)PIC_86MODE);
+
+ /* OCW1 -- Mask everything for now */
+ WRITE_PORT_UCHAR((PUCHAR)imrport[0], (UCHAR)0xFF);
+
+ /* OCW3*/
+ WRITE_PORT_UCHAR((PUCHAR)cmdport[0], (UCHAR)PIC_READISR);
+
+ /*
+ * Initialize slave(s) - We only do 1 slave now....
+ */
+ for (pic = 1; pic < 2; pic++)
+ {
+ cmd = cmdport[pic];
+ imr = imrport[pic];
+
+ /*
+ * --- Set up ICW1-ICW4
+ */
+
+ WRITE_PORT_UCHAR((PUCHAR)cmd, (UCHAR)(PIC_EDGED | PIC_ICW1BASE | PIC_NEEDICW4));
+ WRITE_PORT_UCHAR((PUCHAR)imr, (UCHAR)(PIC0_BASE_VECTOR + (UCHAR)(pic * 8)));
+ WRITE_PORT_UCHAR((PUCHAR)imr, (UCHAR)tmasterline[pic]);
+ if (pic == 2)
+ WRITE_PORT_UCHAR((PUCHAR)imr, (UCHAR)(PIC_SLAVEBUF | PIC_86MODE)); /* Tricord PIC buffered */
+ else
+ WRITE_PORT_UCHAR((PUCHAR)imr, (UCHAR)PIC_86MODE);
+
+ /* OCW1 */
+
+ WRITE_PORT_UCHAR( (PUCHAR)imr, (UCHAR)0xFF);
+
+ /* OCW3 */
+
+ WRITE_PORT_UCHAR((PUCHAR)cmd, (UCHAR)PIC_READISR);
+ }
+}
+
+USHORT
+HalpMySlotAddr(
+ )
+{
+ UCHAR slot;
+ ULONG id;
+ UCHAR stat;
+
+ for (slot=9; slot <= 15 ; slot++)
+ {
+ /*
+ * --- Insure system bus board is a CPU
+ */
+ id = READ_PORT_ULONG((PULONG)((slot<<12) | 0xC80));
+ id = id>>16;
+ if ((id & 0xf0) == 0x10)
+ {
+ stat = READ_PORT_UCHAR((PUCHAR)((slot<<12) | 0xC90));
+
+ /*
+ * --- If bus cycle is active it's us!
+ */
+ if ((stat & 0x40) != 0)
+ break;
+ }
+ }
+ if (slot == 16)
+ slot = 0;
+ return (slot << EISA_SHIFT);
+}
+
+VOID
+HalpSetProcessorsPresent(
+ )
+
+/*++
+
+Routine Description:
+
+ This routine sets a global 32 bit word "ProcessorsPresent"
+ with a "1" bit for each SYSTEM slot that contains a processor board.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UCHAR slot;
+ ULONG cpuid;
+
+ for (slot = FIRST_SYSTEM_SLOT; slot < LAST_SYSTEM_SLOT + 1; slot++) {
+ cpuid = READ_PORT_ULONG((PULONG)((slot << EISA_SHIFT) | SLOT_ID_REG));
+ if ((cpuid & SLOT_ID_BOARDTYPE) == SLOT_ID_TYPECPU)
+ ProcessorsPresent |= (1 << slot);
+ }
+}
diff --git a/private/ntos/nthals/halws3/i386/w3ipi.asm b/private/ntos/nthals/halws3/i386/w3ipi.asm
new file mode 100644
index 000000000..a7084dc11
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3ipi.asm
@@ -0,0 +1,955 @@
+ title "Interprocessor Interrupt"
+;++
+;
+; Copyright (c) 1991 Microsoft Corporation
+; Copyright (c) 1993 Sequent Computer Systems, Inc.
+;
+; Module Name:
+;
+; w3ipi.asm
+;
+; Abstract:
+;
+; Provides the HAL support for Interprocessor Interrupts and
+; the initial processor initialization.
+;
+; Author:
+;
+; Phil Hochstetler (phil@sequent.com) 3-30-93
+;
+; Revision History:
+;
+;--
+.386p
+ .xlist
+
+;
+; Include WinServer 3000 detection code
+;
+
+include i386\w3detect.asm
+
+;
+; Normal includes
+;
+
+include ks386.inc
+include i386\kimacro.inc
+include callconv.inc ; calling convention macros
+include i386\apic.inc
+include i386\w3.inc
+
+;
+; Import/Export
+;
+ EXTRNP _KiCoprocessorError,0,IMPORT
+ EXTRNP _KeRaiseIrql,2
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _HalBeginSystemInterrupt,3
+ EXTRNP _HalEndSystemInterrupt,2
+ EXTRNP _KiIpiServiceRoutine,2,IMPORT
+ EXTRNP _HalEnableSystemInterrupt,3
+ EXTRNP _HalDisplayString,1
+ EXTRNP _HalEnableSystemInterrupt,3
+ EXTRNP _HalDisableSystemInterrupt,2
+
+ EXTRNP _HalpInitializeLocalUnit,0
+ EXTRNP _DbgBreakPoint,0,IMPORT
+
+ EXTRNP _HalpMapPhysicalMemoryWriteThrough,2
+ EXTRNP _HalpMySlotAddr,0
+ EXTRNP _HalpResetLocalUnits,0
+
+ extrn _HalpDefaultInterruptAffinity:DWORD
+ extrn _HalpActiveProcessors:DWORD
+ extrn _HalpLocalUnitBase:DWORD
+ extrn _HalpIOunitBase:DWORD
+ extrn _HalpIOunitTwoBase:DWORD
+ extrn _HalpELCRImage:WORD
+ extrn _HalpMASKED:WORD
+
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+HALBadVaddr db 'HAL: No Virtual Address available to map the APIC', CR, LF, 0
+HALMisMatch db 'HAL: This HAL only runs on a WinServer 3000.', CR, LF
+ db ' Please replace the hal.dll with the correct hal', CR, LF
+ db ' System is HALTING.', 0
+
+ ALIGN dword
+ public _HalpProcessorPCR
+_HalpProcessorPCR dd 8 dup (0) ; PCR pointer for each processor
+
+_DATA ENDS
+
+ page ,132
+ subttl "Initialize Processor"
+_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 KeRaiseIrql/LowerIrq's must be available once this function
+; returns. (IPI's are only used once two or more processors are
+; available)
+;
+; . Save EISA Slot Address in PCR.
+; . Save Processor Number in PCR.
+; . Set initial StallScaleFactor
+; . Set bit in global data structures for each new processor
+; . if (P0)
+; . determine if the system is a WS3000,
+; . if (!WS3000) Halt;
+; . Enable IPI's on CPU.
+;
+;Arguments:
+;
+; Number - Logical processor number of calling processor
+;
+;Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalInitializeProcessor ,1
+cPublicFpo 1, 0
+
+ mov dword ptr PCR[PcStallScaleFactor], INITIAL_STALL_COUNT
+
+ stdCall _HalpMySlotAddr
+ mov PCR[PcHal.ProcSlotAddr], ax ; Save processor slot
+
+ mov eax, [esp+4]
+ mov PCR[PcHal.PcrNumber], al ; Save processor # in PCR
+
+ mov ecx, PCR[PcSelfPcr] ; Flat address of this PCR
+ mov _HalpProcessorPCR[eax * 4], ecx ; Save it away
+
+ lock bts _HalpDefaultInterruptAffinity, eax ; update globals for each
+ lock bts _HalpActiveProcessors, eax ; online processor
+
+ test eax, eax
+ jnz ipi_10
+
+ ; Only Boot Processor executes from here to label ipi_10
+
+ sub esp, 4
+ stdCall _DetectWS3000 <esp>
+ add esp, 4
+
+ test eax, eax
+ jz ipi_notW3
+
+ ; Initialize PICs and IDT for PICs
+
+ mov ax, 0FFFFh
+ SET_8259_MASK
+ stdCall _HalInitPicInterruptHandlers
+
+ ; call HAL memory manager to get a virtual address mapping for the
+ ; APIC(s); virtual addresses are saved in global variables for indirect
+ ; addressing later. This assumes that the page tables are built
+ ; for P0 in Phase 0 are valid for P1.
+
+ stdCall _HalpMapPhysicalMemoryWriteThrough <LU_BASE_ADDRESS,1>
+ test eax, eax
+ jz NoHalVaddr
+ mov _HalpLocalUnitBase, eax
+
+ stdCall _HalpMapPhysicalMemoryWriteThrough <IO_BASE_ADDRESS,1>
+ test eax, eax
+ jz NoHalVaddr
+ mov _HalpIOunitBase, eax
+
+ stdCall _HalpMapPhysicalMemoryWriteThrough <IO_BASE_ADDRESS+020000h,1>
+ test eax, eax
+ jz NoHalVaddr
+ mov _HalpIOunitTwoBase, eax
+
+ ; Reset all other local units to keep them from accepting any
+ ; interrupts until their processor is out of reset. This is a
+ ; problem because starting with Beta 2, not all processors may
+ ; be brought up during install and the WS3000 BIOS enables the
+ ; APICs even though the corresponding processor is held in reset.
+ ; This would not be a bug if setting the FCR to put the processor
+ ; into reset also put the APIC into reset, or if the APIC reset output
+ ; was wired to the processor and used to reset it instead of the FCR.
+
+ stdCall _HalpResetLocalUnits
+
+ipi_10:
+
+ ; For P0-Pn, disable the IO unit so it can't suprise us.
+ ; We have to do this on each CPU on the WS3000 since each CPU can
+ ; only address the IO unit on its local APIC. Each CPU IO unit
+ ; has the same address.
+
+ mov edx, _HalpIOunitTwoBase ; get base address of IO unit
+ mov ecx, IO_REDIR_00_LOW
+ mov eax, INTERRUPT_MASKED
+
+ipi_15:
+ mov [edx+IO_REGISTER_SELECT], ecx ; write mask to redir entry
+ mov [edx+IO_REGISTER_WINDOW], eax
+
+ add ecx, 2 ; increment to next redir entry
+ cmp ecx, IO_REDIR_00_LOW + 32 ; go for 16 entries
+ jb ipi_15 ; more to go
+
+ ;
+ ; initialize the APIC local unit for this Processor
+ ;
+
+ stdCall _HalpInitializeLocalUnit
+
+ stdRET _HalInitializeProcessor
+
+NoHalVaddr:
+ stdCall _HalDisplayString, <offset HALBadVaddr>
+ hlt
+
+ipi_notW3:
+ stdCall _HalDisplayString, <offset HALMisMatch>
+ hlt
+
+stdENDP _HalInitializeProcessor
+
+;++
+;
+; VOID
+; HalInitPicInterruptHandlers(
+; );
+;
+;Routine Description:
+;
+; initialize the EISA IDT entries for the WinServer 3000.
+; This includes installing spurious interrupt handlers for:
+;
+; PIC1 spurious interrupt vector (EISA_IRQ7_VECTOR)
+; PIC2 spurious interrupt vector (EISA_IRQ15_VECTOR)
+;
+; and handlers for
+;
+; CLOCK on PIC1 Vector (EISA_IRQ0_VECTOR)
+; KEYBOARD on PIC1 Vector (EISA_IRQ1_VECTOR)
+; FLOPPY on PIC1 Vector (EISA_IRQ6_VECTOR)
+; RTC on PIC2 Vector (EISA_IRQ8_VECTOR)
+; MOUSE on PIC2 Vector (EISA_IRQ12_VECTOR)
+; DMA on PIC2 Vector (EISA_IRQ13_VECTOR)
+; IDE on PIC2 Vector (EISA_IRQ14_VECTOR)
+;
+; The 82357 ISP on the WinServer 3000 platform does not route the
+; clock and DMA interrupts externally. And the Keyboard, Floppy, Rtc,
+; Mouse, and Ide are not available to the APIC by design. Instead, we
+; must get these interrupts from the integrated PIC (master and
+; slave, actually), whose interrupt output drives INTIN<13> of the 82489DX
+; APIC. This APIC interrupt input is programmed for ExtINT (external
+; interrupt) mode, which causes the integrated PIC to generate the
+; interrupt vector instead of the APIC.
+;
+; Since we want to route all system interrupts through the APIC to take
+; advantage of its prioritization mechanism, we install our own interrupt
+; handlers for the Clock, Keyboard, Floppy, RTC, , Mouse, DMA, and
+; IDE interrupts from the PIC, then redispatch the interrupts through the
+; APIC.
+;
+; Spurious interrupt handlers for the integrated PICs are required because
+; the devices can still generate spurious interrupts.
+;
+;Arguments:
+;
+; None.
+;
+;Return Value:
+;
+; None.
+;
+;--
+
+cPublicProc _HalInitPicInterruptHandlers ,0
+
+ IDTEntry EISA_PIC1_SPURIOUS_VECTOR, EisaPic1SpuriousService
+ IDTEntry EISA_PIC2_SPURIOUS_VECTOR, EisaPic2SpuriousService
+ IDTEntry EISA_CLOCK_VECTOR, EisaClockService
+ IDTEntry EISA_KBD_VECTOR, EisaKbdService
+ IDTEntry EISA_FLOPPY_VECTOR, EisaFloppyService
+ IDTEntry EISA_RTC_VECTOR, EisaRTCService
+ IDTEntry EISA_DMA_VECTOR, EisaDmaService
+ IDTEntry EISA_MOUSE_VECTOR, EisaMouseService
+ IDTEntry EISA_IDE_VECTOR, EisaIDEService
+
+ stdRET _HalInitPicInterruptHandlers
+
+stdENDP _HalInitPicInterruptHandlers
+
+;++
+;
+; VOID
+; ApicSpuriousService(
+; );
+;
+;Routine Description:
+;
+; A place for spurious interrupts to end up.
+;
+;--
+cPublicProc ApicSpuriousService ,0
+ iretd
+stdENDP ApicSpuriousService
+
+;++
+;
+; VOID
+; EisaPic1SpuriousService(
+; );
+;
+;Routine Description:
+;
+; A place for spurious EISA PIC one interrupts to end up.
+;
+;--
+cPublicProc EisaPic1SpuriousService,0
+ iretd
+stdENDP EisaPic1SpuriousService
+
+;++
+;
+; VOID
+; EisaPic2SpuriousService(
+; );
+;
+;Routine Description:
+;
+; A place for spurious EISA PIC two interrupts to end up.
+;
+;--
+cPublicProc EisaPic2SpuriousService,0
+ iretd
+stdENDP EisaPic2SpuriousService
+
+;++
+;
+; VOID
+; EisaClockService(
+; );
+;
+;Routine Description:
+;
+; This handler receives interrupts from the EISA PIC and reissues them via
+; a vector at the proper priority level. This is needed on the WinServer
+; 3000 because we use the PIC interrupts as EXTINT for the 8254 Clock,
+; Keyboard, Floppy, RTC, Mouse, DMA, and IDE. Since EXTINT interrupts are
+; received outside of the APIC priority structure we use the APIC ICR
+; to generate interrupts to the proper handler at the proper priority.
+;
+; The EXTINT interrupts are programmed via the CCS APIC IO Unit's
+; redirection table. They are directed to Processor zero only.
+;
+;--
+
+IPI_CLOCK_ALL equ (DELIVER_FIXED OR ICR_ALL_INCL_SELF OR APIC_CLOCK_VECTOR)
+
+ ENTER_DR_ASSIST H99_a, H99_t
+
+cPublicProc EisaClockService,0
+
+ ;
+ ; Save machine state in trap frame
+ ;
+
+ ENTER_INTERRUPT H99_a, H99_t ; (esp) - base of trap frame
+
+ ;
+ ; Just IPI All Processors ( this is done from P0 )
+ ;
+
+ mov al, OCW2_SPECIFIC_EOI OR (EISA_CLOCK_VECTOR - PIC0_BASE_VECTOR)
+ ; specific eoi
+ out PIC1_PORT0, al ; dismiss the interrupt
+ ;
+ ; Make sure the ICR is available
+ ;
+ mov ecx, _HalpLocalUnitBase ; load base address of CCS
+ ; local unit
+
+@@:
+ test [ecx+LU_INT_CMD_LOW], DELIVERY_PENDING
+ jnz @b
+
+ ;
+ ; Write the Clock IPI Command to the Memory Mapped Register
+ ;
+
+ mov [ecx+LU_INT_CMD_LOW], IPI_CLOCK_ALL
+
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+stdENDP EisaClockService
+
+;++
+;
+; VOID
+; EisaKbdService(
+; );
+;
+;Routine Description:
+;
+; This handler receives interrupts from the EISA PIC and reissues them via
+; a vector at the proper priority level. This is needed on the WinServer
+; 3000 because we use the PIC interrupts as EXTINT for the 8254 Clock,
+; Keyboard, Floppy, RTC, Mouse, DMA, and IDE. Since EXTINT interrupts are
+; received outside of the APIC priority structure we use the APIC ICR
+; to generate interrupts to the proper handler at the proper priority.
+;
+; The EXTINT interrupts are programmed via the CCS APIC IO Unit's
+; redirection table. They are directed to Processor zero only.
+;
+;--
+
+IPI_KBD_ALL equ (DELIVER_LOW_PRIORITY OR LOGICAL_DESTINATION OR ICR_ALL_INCL_SELF OR APIC_KBD_VECTOR)
+
+ ENTER_DR_ASSIST H98_a, H98_t
+
+cPublicProc EisaKbdService ,0
+
+ ;
+ ; Save machine state in trap frame
+ ;
+
+ ENTER_INTERRUPT H98_a, H98_t ; (esp) - base of trap frame
+
+ mov al, OCW2_SPECIFIC_EOI OR (EISA_KBD_VECTOR - PIC0_BASE_VECTOR)
+ ; specific eoi
+ out PIC1_PORT0, al ; dismiss the interrupt
+
+ ;
+ ; Make sure the ICR is available
+ ;
+
+ mov ecx, _HalpLocalUnitBase ; load base address of CCS
+ ; local unit
+
+@@:
+ test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
+ jnz @b
+
+ ;
+ ; Write the KEYBOARD IPI Command to the Memory Mapped Register
+ ;
+
+ mov [ecx+LU_INT_CMD_LOW], IPI_KBD_ALL
+
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+stdENDP EisaKbdService
+
+;++
+;
+; VOID
+; EisaFloppyService(
+; );
+;
+;Routine Description:
+;
+; This handler receives interrupts from the EISA PIC and reissues them via
+; a vector at the proper priority level. This is needed on the WinServer
+; 3000 because we use the PIC interrupts as EXTINT for the 8254 Clock,
+; Keyboard, Floppy, RTC, Mouse, DMA, and IDE. Since EXTINT interrupts are
+; received outside of the APIC priority structure we use the APIC ICR
+; to generate interrupts to the proper handler at the proper priority.
+;
+; The EXTINT interrupts are programmed via the CCS APIC IO Unit's
+; redirection table. They are directed to Processor zero only.
+;
+;--
+
+IPI_FLOPPY_ALL equ (DELIVER_LOW_PRIORITY OR LOGICAL_DESTINATION OR ICR_ALL_INCL_SELF OR APIC_FLOPPY_VECTOR)
+
+ ENTER_DR_ASSIST H97_a, H97_t
+
+cPublicProc EisaFloppyService ,0
+
+ ;
+ ; Save machine state in trap frame
+ ;
+
+ ENTER_INTERRUPT H97_a, H97_t ; (esp) - base of trap frame
+
+ mov al, OCW2_SPECIFIC_EOI OR (EISA_FLOPPY_VECTOR - PIC0_BASE_VECTOR)
+ ; specific eoi
+ out PIC1_PORT0, al ; dismiss the interrupt
+ ;
+ ; Make sure the ICR is available
+ ;
+
+ mov ecx, _HalpLocalUnitBase ; load base address of CCS
+ ; local unit
+
+@@:
+ test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
+ jnz @b
+
+ ;
+ ; Write the FLOPPY IPI Command to the Memory Mapped Register
+ ;
+
+ mov [ecx+LU_INT_CMD_LOW], IPI_FLOPPY_ALL
+
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+stdENDP EisaFloppyService
+
+;++
+;
+; VOID
+; EisaRTCService(
+; );
+;
+;Routine Description:
+;
+; This handler receives interrupts from the EISA PIC and reissues them via
+; a vector at the proper priority level. This is needed on the WinServer
+; 3000 because we use the PIC interrupts as EXTINT for the 8254 Clock,
+; Keyboard, Floppy, RTC, Mouse, DMA, and IDE. Since EXTINT interrupts are
+; received outside of the APIC priority structure we use the APIC ICR
+; to generate interrupts to the proper handler at the proper priority.
+;
+; The EXTINT interrupts are programmed via the CCS APIC IO Unit's
+; redirection table. They are directed to Processor zero only.
+;
+;--
+
+IPI_RTC_ALL equ (DELIVER_LOW_PRIORITY OR LOGICAL_DESTINATION OR ICR_ALL_INCL_SELF OR APIC_RTC_VECTOR)
+
+ ENTER_DR_ASSIST H96_a, H96_t
+
+cPublicProc EisaRTCService ,0
+
+ ;
+ ; Save machine state in trap frame
+ ;
+
+ ENTER_INTERRUPT H96_a, H96_t ; (esp) - base of trap frame
+
+ mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
+ out PIC2_PORT0, al
+ mov al, OCW2_SPECIFIC_EOI OR (EISA_IRQ2_VECTOR - PIC0_BASE_VECTOR)
+ ; specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+ ;
+ ; Make sure the ICR is available
+ ;
+
+ mov ecx, _HalpLocalUnitBase ; load base address of CCS
+ ; local unit
+
+@@:
+ test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
+ jnz @b
+
+ ;
+ ; Write the RTC IPI Command to the Memory Mapped Register
+ ;
+
+ mov [ecx+LU_INT_CMD_LOW], IPI_RTC_ALL
+
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+stdENDP EisaRTCService
+
+;++
+;
+; VOID
+; EisaDmaService(
+; );
+;
+;Routine Description:
+;
+; This handler receives interrupts from the EISA PIC and reissues them via
+; a vector at the proper priority level. This is needed on the WinServer
+; 3000 because we use the PIC interrupts as EXTINT for the 8254 Clock,
+; Keyboard, Floppy, RTC, Mouse, DMA, and IDE. Since EXTINT interrupts are
+; received outside of the APIC priority structure we use the APIC ICR
+; to generate interrupts to the proper handler at the proper priority.
+;
+; The EXTINT interrupts are programmed via the CCS APIC IO Unit's
+; redirection table. They are directed to Processor zero only.
+;
+;--
+
+IPI_DMA_ALL equ (DELIVER_LOW_PRIORITY OR LOGICAL_DESTINATION OR ICR_ALL_INCL_SELF OR APIC_DMA_VECTOR)
+
+ ENTER_DR_ASSIST H95_a, H95_t
+
+cPublicProc EisaDmaService ,0
+
+ ;
+ ; Save machine state in trap frame
+ ;
+
+ ENTER_INTERRUPT H95_a, H95_t ; (esp) - base of trap frame
+
+ mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
+ out PIC2_PORT0, al
+ mov al, OCW2_SPECIFIC_EOI OR (EISA_IRQ2_VECTOR - PIC0_BASE_VECTOR)
+ ; specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+ ;
+ ; Make sure the ICR is available
+ ;
+
+ mov ecx, _HalpLocalUnitBase ; load base address of CCS
+ ; local unit
+
+@@:
+ test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
+ jnz @b
+
+ ;
+ ; Write the DMA IPI Command to the Memory Mapped Register
+ ;
+
+ mov [ecx+LU_INT_CMD_LOW], IPI_DMA_ALL
+
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+stdENDP EisaDmaService
+
+;++
+;
+; VOID
+; EisaMouseService(
+; );
+;
+;Routine Description:
+;
+; This handler receives interrupts from the EISA PIC and reissues them via
+; a vector at the proper priority level. This is needed on the WinServer
+; 3000 because we use the PIC interrupts as EXTINT for the 8254 Clock,
+; Keyboard, Floppy, RTC, DMA, Mouse, and IDE. Since EXTINT interrupts are
+; received outside of the APIC priority structure we use the APIC ICR
+; to generate interrupts to the proper handler at the proper priority.
+;
+; The EXTINT interrupts are programmed via the CCS APIC IO Unit's
+; redirection table. They are directed to Processor zero only.
+;
+;--
+
+IPI_MOUSE_ALL equ (DELIVER_LOW_PRIORITY OR LOGICAL_DESTINATION OR ICR_ALL_INCL_SELF OR APIC_MOUSE_VECTOR)
+
+ ENTER_DR_ASSIST H94_a, H94_t
+
+cPublicProc EisaMouseService ,0
+
+ ;
+ ; Save machine state in trap frame
+ ;
+
+ ENTER_INTERRUPT H94_a, H94_t ; (esp) - base of trap frame
+
+ mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
+ out PIC2_PORT0, al
+ mov al, OCW2_SPECIFIC_EOI OR (EISA_IRQ2_VECTOR - PIC0_BASE_VECTOR)
+ ; specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+ ;
+ ; Make sure the ICR is available
+ ;
+
+ mov ecx, _HalpLocalUnitBase ; load base address of CCS
+ ; local unit
+
+@@:
+ test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
+ jnz @b
+
+ ;
+ ; Write the MOUSE IPI Command to the Memory Mapped Register
+ ;
+
+ mov [ecx+LU_INT_CMD_LOW], IPI_MOUSE_ALL
+
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+stdENDP EisaMouseService
+
+
+;++
+;
+; VOID
+; EisaIDEService(
+; );
+;
+;Routine Description:
+;
+; This handler receives interrupts from the EISA PIC and reissues them via
+; a vector at the proper priority level. This is needed on the WinServer
+; 3000 because we use the PIC interrupts as EXTINT for the 8254 Clock,
+; Keyboard, Floppy, RTC, Mouse, DMA, and IDE. Since EXTINT interrupts are
+; received outside of the APIC priority structure we use the APIC ICR
+; to generate interrupts to the proper handler at the proper priority.
+;
+; The EXTINT interrupts are programmed via the CCS APIC IO Unit's
+; redirection table. They are directed to Processor zero only.
+;
+;--
+
+ ENTER_DR_ASSIST H93_a, H93_t
+
+cPublicProc EisaIDEService ,0
+
+ ;
+ ; Save machine state in trap frame
+ ;
+
+ ENTER_INTERRUPT H93_a, H93_t ; (esp) - base of trap frame
+
+ mov ebx, (DELIVER_LOW_PRIORITY OR LOGICAL_DESTINATION OR ICR_ALL_INCL_SELF OR APIC_IDE_VECTOR)
+ test _HalpELCRImage, (1 SHL (EISA_IDE_VECTOR - PIC0_BASE_VECTOR))
+ jz short @f
+
+ ; If a level PIC interrupt, mask the interrupt at the PIC until
+ ; the APIC interrupt HalEndSystemInterrupt unmasks it.
+ ; We also only send it to ourselves since it needs to mess with the
+ ; pic in the end of interrupt code.
+
+
+lock or _HalpMASKED, (1 SHL (EISA_IDE_VECTOR - PIC0_BASE_VECTOR))
+ in al, PIC2_PORT1
+ or al, (1 SHL (EISA_IDE_VECTOR - PIC1_BASE_VECTOR))
+ out PIC2_PORT1, al
+ mov ebx, (DELIVER_LOW_PRIORITY OR LOGICAL_DESTINATION OR ICR_SELF OR APIC_IDE_VECTOR)
+
+@@:
+ mov al, OCW2_NON_SPECIFIC_EOI ; send non specific eoi to slave
+ out PIC2_PORT0, al
+ mov al, OCW2_SPECIFIC_EOI OR (EISA_IRQ2_VECTOR - PIC0_BASE_VECTOR)
+ ; specific eoi to master for pic2 eoi
+ out PIC1_PORT0, al ; send irq2 specific eoi to master
+ ;
+ ; Make sure the ICR is available
+ ;
+
+ mov ecx, _HalpLocalUnitBase ; load base address of CCS
+ ; local unit
+@@: test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
+ jnz @b
+
+ ;
+ ; Write the IDE IPI Command to the Memory Mapped Register
+ ;
+
+ mov [ecx+LU_INT_CMD_LOW], ebx
+
+ SPURIOUS_INTERRUPT_EXIT ; exit interrupt without eoi
+
+stdENDP EisaIDEService
+
+;++
+;
+; VOID
+; HalRequestIpi(
+; IN KAFFINITY Mask
+; );
+;
+;Routine Description:
+;
+; Requests an interprocessor interrupt
+;
+;Arguments:
+;
+; Mask - Supplies a mask of the processors to be interrupted
+;
+;Return Value:
+;
+; None.
+;
+;--
+APIC_IPI equ (DELIVER_FIXED OR LOGICAL_DESTINATION OR ICR_USE_DEST_FIELD OR APIC_IPI_VECTOR)
+
+cPublicProc _HalRequestIpi ,1
+cPublicFpo 1, 0
+
+ mov eax, dword ptr [esp+4] ; (eax) = Processor bitmask
+ mov ecx, _HalpLocalUnitBase ; load base address of local unit
+
+ DISABLE_INTERRUPTS_AT_CPU
+
+if DBG
+ or eax, eax ; must ipi somebody
+ jz short ipibad
+ movzx edx, byte ptr PCR[PcHal.PcrNumber] ; Get Processor Number
+ bt eax, edx ; cannot ipi yourself
+ jc short ipibad
+endif
+
+ ;
+ ; With an APIC we'll IPI everyone needed at the same time.
+ ; This assumes that:
+ ; (mask passed in) == (APIC logical destination mask) Since we've programmed
+ ; the APIC Local Units to use the Processor ID as the APIC ID this IS true
+ ;
+ ;
+ ; Make sure the ICR is available
+ ;
+
+@@:
+ test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
+ jnz @b
+
+ ;
+ ; Set the destination address, (eax) = Processor bitmask
+ ;
+
+ mov [ecx+LU_INT_CMD_HIGH], eax
+
+ ;
+ ; Now issue the command by writing to the Memory Mapped Register
+ ;
+
+ mov [ecx+LU_INT_CMD_LOW], APIC_IPI
+
+ RESTORE_INTERRUPTS_AT_CPU
+
+ stdRET _HalRequestIpi
+
+if DBG
+ipibad:
+ RESTORE_INTERRUPTS_AT_CPU
+ stdCall _DbgBreakPoint
+ stdRET _HalRequestIpi
+endif
+
+stdENDP _HalRequestIpi
+
+;++
+;
+; VOID
+; HalIntProcessorAPIC(
+; IN ULONG Mask,
+; IN ULONG ICRCommand
+; );
+;
+;Routine Description:
+;
+; Requests an interprocessor interrupt
+;
+;Arguments:
+;
+; Mask - Supplies a mask of the processors to be interrupted
+;
+; ICRCommand - ICR Command to use
+;
+;Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalIntProcessorAPIC ,2
+
+ mov edx, dword ptr [esp+4] ; (edx) = Processor bitmask
+ mov eax, dword ptr [esp+8] ; (eax) = ICR Command
+
+ mov ecx, _HalpLocalUnitBase ; load base address of local unit
+
+ ;
+ ; Make sure the ICR is available
+ ;
+
+ pushfd ; save interrupt mode
+ cli ; disable interrupt
+
+@@:
+ test [ecx+LU_INT_CMD_LOW],DELIVERY_PENDING
+ jnz @b
+
+ ; (edx) = Processor bitmask
+ ; (eax) = ICR Command
+
+ mov [ecx+LU_INT_CMD_HIGH], edx
+
+ ;
+ ; Now issue the command by writing the ICR Command to the Memory Mapped Register
+ ;
+
+ mov [ecx+LU_INT_CMD_LOW], eax
+
+ popfd
+
+ stdRET _HalIntProcessorAPIC
+
+stdENDP _HalIntProcessorAPIC
+
+
+ page ,132
+ subttl "IPI Interrupt Handler"
+;++
+;
+; VOID
+; HalpIpiHandler (
+; );
+;
+; Routine Description:
+;
+; This routine is entered as the result of an interrupt generated by inter
+; processor communication.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+ ENTER_DR_ASSIST Hipi_a, Hipi_t
+
+cPublicProc _HalpIpiHandler ,0
+
+;
+; Save machine state in trap frame
+;
+
+ ENTER_INTERRUPT Hipi_a, Hipi_t ; (ebp) -> Trap frame
+
+;
+; Save previous IRQL
+;
+ push APIC_IPI_VECTOR ; Vector
+ sub esp, 4 ; space for OldIrql
+;
+; We now dismiss the interprocessor interrupt and call its handler
+;
+
+ stdCall _HalBeginSystemInterrupt,<IPI_LEVEL,APIC_IPI_VECTOR,esp>
+
+; Pass Null ExceptionFrame
+; Pass TrapFrame to Ipi service rtn
+;
+ stdCall _KiIpiServiceRoutine, <ebp,0>
+
+;
+; Do interrupt exit processing
+;
+
+ INTERRUPT_EXIT ; will return to caller
+
+stdENDP _HalpIpiHandler
+
+_TEXT ENDS
+
+ END
diff --git a/private/ntos/nthals/halws3/i386/w3irql.asm b/private/ntos/nthals/halws3/i386/w3irql.asm
new file mode 100644
index 000000000..9b830dac6
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3irql.asm
@@ -0,0 +1,776 @@
+ title "Irql Processing"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+; Copyright (c) 1993 Sequent Computer Systems, Inc.
+;
+; Module Name:
+;
+; w3irql.asm
+;
+; Abstract:
+;
+; WinServer 3000 IRQL implementation.
+;
+; This module implements the code necessary to raise and lower i386
+; Irql and dispatch software interrupts with the WinServer APIC/PIC system.
+;
+; Author:
+;
+; Phil Hochstetler (phil@sequent.com) 3-30-93
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+
+.386p
+ .xlist
+include ks386.inc
+include callconv.inc ; calling convention macros
+include i386\apic.inc
+include i386\kimacro.inc
+include i386\w3.inc
+ .list
+
+ EXTRNP _KeBugCheck,1
+ EXTRNP _Halptpicinit,0
+ EXTRNP _HalpDispatchInterrupt,0
+ EXTRNP _HalpApcInterrupt,0
+
+ extrn _HalpIrql2TPR:byte
+ extrn _HalpK2Rdir2Irq:byte
+ extrn _HalpELCRImage:word
+ extrn _HalpW3BaseIOunitRedirectionTable:dword
+ extrn _HalpK2EbsIOunitRedirectionTable:dword
+ extrn _HalpK2EISAIrq2Irql:byte
+ extrn _HalpK2Irql2Eisa:byte
+ extrn _HalpActiveProcessors:DWORD
+ extrn _HalpIrql2IRRMask:dword
+ extrn ApicSpuriousService@0:near
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+;
+; Virtual addresses of the APIC Local and IO units.
+; The virtual mapping is done in HalInitializeProcessor.
+;
+ align dword
+ public _HalpLocalUnitBase, _HalpIOunitBase, _HalpIOunitTwoBase
+_HalpLocalUnitBase dd 0
+_HalpIOunitBase dd 0
+_HalpIOunitTwoBase dd 0
+
+SyncIdCommand equ DELIVER_INIT + \
+ LOGICAL_DESTINATION + \
+ LEVEL_TRIGGERED
+ResetAllExclSelf equ DELIVER_INIT + \
+ LEVEL_TRIGGERED + \
+ ICR_LEVEL_ASSERTED + \
+ ICR_ALL_EXCL_SELF
+UnResetLogical equ DELIVER_INIT + \
+ LOGICAL_DESTINATION + \
+ LEVEL_TRIGGERED
+
+;
+; This table is used to mask all pending interrupts below a given Irql
+; out of the IRR
+;
+ align 4
+
+ public FindHigherIrqlMask
+FindHigherIrqlMask label dword
+ dd 11111111111111111111111111111110B ; irql 0
+ dd 11111111111111111111111111111100B ; irql 1
+ dd 11111111111111111111111111111000B ; irql 2
+ dd 11111111111111111111111111110000B ; irql 3
+ dd 11111111111111111111111111100000B ; irql 4
+ dd 11111111111111111111111111000000B ; irql 5
+ dd 11111111111111111111111110000000B ; irql 6
+ dd 11111111111111111111111100000000B ; irql 7
+ dd 11111111111111111111111000000000B ; irql 8
+ dd 11111111111111111111110000000000B ; irql 9
+ dd 11111111111111111111100000000000B ; irql 10
+ dd 11111111111111111111000000000000B ; irql 11
+ dd 11111111111111111110000000000000B ; irql 12
+ dd 11111111111111111100000000000000B ; irql 13
+ dd 11111111111111111000000000000000B ; irql 14
+ dd 11111111111111110000000000000000B ; irql 15
+ dd 11111111111111100000000000000000B ; irql 16
+ dd 11111111111111000000000000000000B ; irql 17
+ dd 11111111111110000000000000000000B ; irql 18
+ dd 11111111111100000000000000000000B ; irql 19
+ dd 11111111111000000000000000000000B ; irql 20
+ dd 11111111110000000000000000000000B ; irql 21
+ dd 11111111100000000000000000000000B ; irql 22
+ dd 11111111000000000000000000000000B ; irql 23
+ dd 11111110000000000000000000000000B ; irql 24
+ dd 11111100000000000000000000000000B ; irql 25
+ dd 11111000000000000000000000000000B ; irql 26
+ dd 11110000000000000000000000000000B ; irql 27
+ dd 11100000000000000000000000000000B ; irql 28
+ dd 11000000000000000000000000000000B ; irql 29
+ dd 10000000000000000000000000000000B ; irql 30
+ dd 00000000000000000000000000000000B ; irql 31
+
+_DATA ENDS
+
+ page ,132
+ subttl "RaiseIrql"
+
+_TEXT$01 SEGMENT PARA PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
+
+;++
+;
+; KIRQL
+; KfRaiseIrql (
+; IN KIRQL NewIrql,
+; )
+;
+; Routine Description:
+;
+; This routine is used to raise IRQL to the specified value.
+;
+; *** IMPORTANT IMPLEMENTATION NOTE ***
+; Be sure to not write the OldIrql return value until after the
+; IRQL has taken effect (due to poor coding practices).
+;
+; Arguments:
+;
+; (cl) = NewIrql - the new irql to be raised to
+;
+; Return Value:
+;
+; OldIrql - old irql
+;
+;--
+
+cPublicFastCall KfRaiseIrql ,1
+cPublicFpo 0,0
+
+ mov al, PCR[PcHal.ProcIrql] ; (al) = old irql
+if DBG
+ cmp al, cl ; old > new?
+ ja short KriErr1
+endif
+ cmp cl, DISPATCH_LEVEL ; a software level?
+ ja short @f ; if yes, set the hardware
+ mov PCR[PcHal.ProcIrql], cl ; Save new irql
+ fstRET KfRaiseIrql
+@@:
+ mov edx, _HalpLocalUnitBase ; Get address of Local APIC
+ and ecx, 0ffh ; clear upper 3 bytes
+
+ pushfd ; enter critical region
+ cli ;
+
+ mov PCR[PcHal.ProcIrql], cl ; Save new irql
+ mov cl, _HalpIrql2TPR[ecx] ; convert irql to TPR
+ mov [edx+LU_TPR], ecx ; write new irql
+ mov ecx, [edx+LU_TPR] ; Flush CPU write buffer
+
+ popfd ; leave critical region
+
+ fstRET KfRaiseIrql
+if DBG
+cPublicFpo 0, 2
+KriErr1:
+ 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 PCR[PcHal.ProcIrql], 0 ; avoid recursive error
+ stdCall _KeBugCheck, <IRQL_NOT_GREATER_OR_EQUAL>
+endif
+
+fstENDP KfRaiseIrql
+
+ page ,132
+ subttl "LowerIrql"
+;++
+;
+; VOID
+; KfLowerIrql (
+; IN KIRQL NewIrql
+; )
+;
+; Routine Description:
+;
+; This routine is used to lower IRQL to the specified value.
+;
+; Arguments:
+;
+; (cl) = NewIrql - the new irql to be set.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+
+cPublicFastCall KfLowerIrql ,1
+cPublicFpo 0,0
+
+ movzx ecx, cl ; get new irql value
+if DBG
+ cmp cl, PCR[PcHal.ProcIrql] ; new > old ?
+ ja KliErr ; panic if so
+endif
+ cmp byte ptr PCR[PcHal.ProcIrql], DISPATCH_LEVEL
+ ja short KliHW ; if old irql <= 2, software only
+ mov PCR[PcHal.ProcIrql], cl ; Save new irql
+;
+; Check for any pending DISPATCH interrupts
+;
+KliChkSW:
+ mov edx, PCR[PcIRR] ; get current IRR
+ and edx, FindHigherIrqlMask[ecx*4]
+ jnz KliSW
+KliEnd:
+ fstRET KfLowerIrql ; return
+KliSW:
+ pushfd
+ cli
+ test dword ptr PCR[PcIRR], (1 SHL DISPATCH_LEVEL)
+ jz short @f
+ stdCall _HalpDispatchInterrupt
+ popfd
+ xor ecx, ecx
+ mov cl, PCR[PcHal.ProcIrql] ; restore current irql value
+ jmp short KliChkSW
+@@:
+ cmp cl, APC_LEVEL
+ jae short KliPop
+ test dword ptr PCR[PcIRR], (1 SHL APC_LEVEL)
+ jz short KliPop
+ stdCall _HalpApcInterrupt
+ popfd
+ xor ecx, ecx
+ mov cl, PCR[PcHal.ProcIrql] ; restore current irql value
+ jmp short KliChkSW
+KliPop:
+ popfd
+ jmp short KliEnd
+
+;
+; Lower APIC Task Priority Register to reflect change in IRQL
+; and then check for software interrupts (if below DISPATCH)
+;
+KliHW:
+ mov edx, _HalpLocalUnitBase ; get address of Local APIC
+ pushfd
+ cli
+ mov PCR[PcHal.ProcIrql], cl ; Save new irql
+ mov cl, _HalpIrql2TPR[ecx] ; convert irql to TPR
+ mov [edx+LU_TPR], ecx ; write new TPR value
+ mov ecx, [edx+LU_TPR] ; Flush CPU write buffer
+ popfd
+ mov cl, byte ptr PCR[PcHal.ProcIrql] ; restore current irql value
+ cmp cl, DISPATCH_LEVEL
+ jb KliChkSW
+ fstRET KfLowerIrql ; return
+
+if DBG
+cPublicFpo 1, 2
+KliErr:
+ push ecx ; new irql for debugging
+ mov cl, PCR[PcHal.ProcIrql] ; get old irql
+ push ecx ; old irql for debugging
+ mov byte ptr PCR[PcHal.ProcIrql], HIGH_LEVEL ; avoid recursive error
+ stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL>
+endif
+fstENDP KfLowerIrql
+
+
+;++
+;
+; 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
+
+
+;++
+;
+; KIRQL
+; KeGetCurrentIrql (VOID)
+;
+; Routine Description:
+;
+; This routine returns to current IRQL.
+;
+; Arguments:
+;
+; None.
+;
+; Return Value:
+;
+; The current IRQL.
+;
+;--
+
+cPublicProc _KeGetCurrentIrql ,0
+
+ xor eax, eax
+ mov al, PCR[PcHal.ProcIrql] ; return 32 bits to cover mistakes
+ 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 all interrupts
+;
+
+ mov ax, 0FFFFh
+ SET_8259_MASK
+ mov ecx, HIGH_LEVEL
+ fstCall KfRaiseIrql
+
+ stdRET _HalpDisableAllInterrupts
+
+stdENDP _HalpDisableAllInterrupts
+
+_TEXT$01 ends
+
+ page ,132
+ subttl "Interrupt Controller Initialization"
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
+;++
+;
+; VOID
+; _HalpInitializePICs (
+; )
+;
+; Routine Description:
+;
+; Call the _Halptpicinit C routine to initialize 8259 and APIC
+;
+;Arguments:
+;
+; None
+;
+; Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalpInitializePICs ,0
+
+ DISABLE_INTERRUPTS_AT_CPU
+
+ stdCall _HalpInitializeEbsIOunit ; Initialize EBS I/O APIC
+ stdCall _HalpInitializeBaseIOunit ; Initialize P0 I/O APIC
+ stdCall _Halptpicinit ; Initialize PICs
+
+ RESTORE_INTERRUPTS_AT_CPU
+
+ stdRET _HalpInitializePICs
+
+stdENDP _HalpInitializePICs
+
+ page ,132
+ subttl "APIC EBS IO Unit Initialization"
+;++
+;
+; VOID
+; HalpInitializeEbsIOUnit (
+; )
+;
+; Routine Description:
+;
+; This routine initializes the interrupt structures for the IO unit of
+; the 82489DX APIC. It masks all interrupt inputs in the redirection
+; table - these will be unmasked when the interrupts are enabled by
+; HalpEnableSystemInterrupt.
+;
+; HalpInitializeIOunit is called by HalpInitializePics during Phase 0
+; initialization. It is executed by P0 only, and executes AFTER the
+; local unit is initialized. This procedure assumes that the APIC virtual
+; address space has been mapped.
+;
+; The I/O unit for external WinServer 3000 interrupts resides on the
+; EBS module.
+;
+; Arguments:
+;
+; None
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicProc _HalpInitializeEbsIOUnit ,0
+
+ push esi ; save regs
+ push ebx ;
+
+;
+; When using the Intel 82350 ISP Chipset the interrupt edge/level definitions
+; are readable from the ISP's edge/level control register (ELCR).
+;
+; Read the ELCR so the input polarity control XOR gates on the APIC interrupt
+; inputs can be programmed. This whole thing works because EISA defines edge
+; -triggered interrupts as active-high and level interrupts as active-low.
+;
+; We will use the ELCR later to set the ACTIVE_LOW bit as required in the
+; IOunit redirection table.
+;
+ mov dx, PIC2_ELCR_PORT ; read the edge/level control reg
+ in al, dx
+ shl ax, 8
+ mov dx, PIC1_ELCR_PORT
+ in al, dx
+ and ax, ELCR_MASK ; clear reserved IRQs
+ mov _HalpELCRImage, ax ; save the image for later
+;
+; load addresses of the register-select register and register-window register
+;
+ mov ecx, _HalpIOunitBase
+ lea edx, [ecx+IO_REGISTER_SELECT]
+ lea ecx, [ecx+IO_REGISTER_WINDOW]
+
+;
+; write the I/O unit APIC-ID - Since we are using the Processor
+; Numbers for the local unit ID's we need to set the IO unit
+; to a high (out of Processor Number range) value.
+;
+ mov dword ptr [edx], IO_ID_REGISTER
+ mov dword ptr [ecx], (IOUNIT_APIC_ID SHL APIC_ID_SHIFT)
+
+;
+; program the redirection table
+;
+ mov ebx, IO_REDIR_00_LOW ; [EBX] has register select
+ lea esi, _HalpK2EbsIOunitRedirectionTable ; [ESI] has address of image
+
+RedirLoop1:
+ lodsd ; load low dword
+ or eax, eax ; end of table?
+ jz RedirLoopExit1 ; yup - we're done
+ push ebx
+ push ecx
+ push eax
+ sub ebx, IO_REDIR_00_LOW
+ shr ebx, 1 ; Form RDIR #
+ xor ecx,ecx
+ mov cl, _HalpK2Rdir2Irq[ebx] ; Form IRQ #
+ xor eax, eax ; clear reg.
+ mov ax, _HalpELCRImage
+ bt eax, ecx
+ pop eax
+ pop ecx
+; Note: 0 will result for all K2 IRQs, this is what we want....
+ jnc @f ; bit is 0 => active high (default)
+ ; eax is val
+ ; ebx in RDIR entry #
+ or eax, LEVEL_TRIGGERED ; This is a level triggered interrupt
+;
+; We must tell the hardware to invert the polarity for level triggered
+; interrupts because APIC is "active HIGH", EISA is active low for level
+; triggered interrupts...so tickle the K2 EISA to APIC Polarity Register..
+;
+ push eax
+ push edx
+ mov dx, EISA_2_MPIC_POLARITY_REG
+ in al, dx
+ bts eax, ebx ;
+ out dx, al
+ pop edx
+ pop eax
+@@:
+ pop ebx
+ mov dword ptr [edx], ebx ; write to select register
+ mov dword ptr [ecx], eax ; write redirection table entry
+ inc ebx ; increment to next entry
+ lodsd ; load high dword
+ mov dword ptr [edx], ebx ; write to select register
+ mov dword ptr [ecx], eax ; write redirection table entry
+ inc ebx ; increment to next entry
+ jmp RedirLoop1 ; continue...
+RedirLoopExit1:
+
+ pop ebx ; restore registers and return
+ pop esi ;
+ stdRET _HalpInitializeEbsIOUnit
+stdENDP _HalpInitializeEbsIOUnit
+ page ,132
+ subttl "APIC Base IO Unit Initialization"
+;++
+;
+; VOID
+; HalpInitializeBaseIOUnit (
+; )
+;
+; Routine Description:
+;
+; This routine initializes the interrupt structures for the IO unit of
+; the 82489DX APIC. It masks all interrupt inputs in the redirection
+; table - these will be unmasked when the interrupts are enabled by
+; HalpEnableSystemInterrupt.
+;
+; HalpInitializeIOunit is called by HalpInitializePics during Phase 0
+; initialization. It is executed by CPU0 only, and executes AFTER the
+; local unit is initialized. This procedure assumes that the APIC virtual
+; address space has been mapped.
+;
+; The I/O unit for external K2 interrupts resides on the EBS module.
+;
+; Arguments:
+;
+; None
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+cPublicProc _HalpInitializeBaseIOUnit ,0
+
+ push esi ; save regs
+ push ebx ;
+
+;
+; load addresses of the register-select register and register-window register
+;
+ mov ecx, _HalpIOunitTwoBase
+ lea edx, [ecx+IO_REGISTER_SELECT]
+ lea ecx, [ecx+IO_REGISTER_WINDOW]
+;
+; write the I/O unit APIC-ID - Since we are using the Processor
+; Numbers for the local unit ID's we need to set the 2nd IO unit
+; to a high (out of Processor Number range) value (but != other IO unit).
+;
+ mov dword ptr [edx], IO_ID_REGISTER
+ mov dword ptr [ecx], (IOUNIT2_APIC_ID SHL APIC_ID_SHIFT)
+
+;
+; re-program the redirection table
+;
+ mov ebx, IO_REDIR_00_LOW ; [EBX] has register select
+ lea esi, _HalpW3BaseIOunitRedirectionTable ; [ESI] has address of image
+
+RedirLoop:
+ lodsd ; load low dword
+ or eax, eax ; end of table?
+ jz RedirLoopExit ; yup - we're done
+ mov dword ptr [edx], ebx ; write to select register
+ mov dword ptr [ecx], eax ; write redirection table entry
+ inc ebx ; increment to next entry
+ lodsd ; load high dword
+ mov dword ptr [edx], ebx ; write to select register
+ mov dword ptr [ecx], eax ; write redirection table entry
+ inc ebx ; increment to next entry
+ jmp RedirLoop ; continue...
+RedirLoopExit:
+
+ pop ebx ; restore registers and return
+ pop esi ;
+ stdRET _HalpInitializeBaseIOUnit
+stdENDP _HalpInitializeBaseIOUnit
+
+cPublicProc _HalpUnResetLocalUnit ,1
+
+ movzx ecx, byte ptr [esp+4] ; get CPU logical number
+ xor eax, eax
+ bts eax, ecx ; convert to bit mask of 1 bit
+ mov ecx, _HalpLocalUnitBase ; pointer to local unit
+
+ DISABLE_INTERRUPTS_AT_CPU
+
+@@: test dword ptr [ecx+LU_INT_CMD_LOW], DELIVERY_PENDING
+ jnz short @b
+
+ mov dword ptr [ecx+LU_INT_CMD_HIGH], eax ; destination bit mask
+ mov dword ptr [ecx+LU_INT_CMD_LOW], UnResetLogical
+
+ RESTORE_INTERRUPTS_AT_CPU
+
+ stdRET _HalpUnResetLocalUnit
+
+stdENDP _HalpUnResetLocalUnit
+
+cPublicProc _HalpResetLocalUnits ,0
+
+ mov ecx, _HalpLocalUnitBase ; pointer to local unit
+
+ DISABLE_INTERRUPTS_AT_CPU
+
+@@: test dword ptr [ecx+LU_INT_CMD_LOW], DELIVERY_PENDING
+ jnz short @b
+
+ mov dword ptr [ecx+LU_INT_CMD_LOW], ResetAllExclSelf
+
+ RESTORE_INTERRUPTS_AT_CPU
+
+ stdRET _HalpResetLocalUnits
+stdENDP _HalpResetLocalUnits
+
+ page ,132
+ subttl "APIC Local Unit Initialization"
+;++
+;
+; VOID
+; HalpInitializeLocalUnit (
+; )
+;
+; Routine Description:
+;
+; This routine initializes the interrupt structures for the local unit
+; of the 82489DX APIC. This procedure is called by HalInitializeProcessor
+; as it is executed by each CPU.
+;
+; Arguments:
+;
+; None
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+APIC_ENABLE equ (APIC_SPURIOUS_VECTOR OR LU_UNIT_ENABLED)
+
+cPublicProc _HalpInitializeLocalUnit ,0
+cPublicFpo 0, 1
+
+ pushfd
+ cli
+
+ mov edx, _HalpLocalUnitBase ; base address of local unit
+ mov dword ptr [edx+LU_TPR], 0FFh ; Disable all interrupts
+ movzx eax, byte ptr PCR[PcHal.PcrNumber] ; use CPU number for APIC-id
+ mov dword ptr [edx+LU_DEST_FORMAT], LU_DEST_FORMAT_FLAT
+ xor ecx, ecx ; zero bitmask
+ bts ecx, eax ; create logical dest bitmask
+ mov [edx+LU_LOGICAL_DEST], ecx ; and set it
+ shl eax, APIC_ID_SHIFT ; ID_REGISTER has ID in MSB
+ mov dword ptr [edx+LU_ID_REGISTER], eax ; set local unit ID
+;
+; APIC does not seem to see a hardware reset across a reboot thus an interrupt
+; could have been taken but the EOI is never written. The BIOS does not
+; recover from this condition so we must do it here. Many days with a logic
+; analyzer finally found this one. If there are any ISR bits set, clear
+; one by a write to the EOI register and look again.
+;
+@@:
+ mov eax, [edx+LU_ISR_0+000h] ; read ISR 0
+ or eax, [edx+LU_ISR_0+010h] ; read ISR 1
+ or eax, [edx+LU_ISR_0+020h] ; read ISR 2
+ or eax, [edx+LU_ISR_0+030h] ; read ISR 3
+ or eax, [edx+LU_ISR_0+040h] ; read ISR 4
+ or eax, [edx+LU_ISR_0+050h] ; read ISR 5
+ or eax, [edx+LU_ISR_0+060h] ; read ISR 6
+ or eax, [edx+LU_ISR_0+070h] ; read ISR 7
+ jz short @f
+ mov dword ptr [edx+LU_EOI], eax ; clear highest ISR bit
+ jmp short @b
+@@:
+ mov dword ptr [edx+LU_SPURIOUS_VECTOR], APIC_ENABLE
+;
+; Sync all APIC IDs by using Data Sheet recommended procedure
+;
+ xor eax, eax
+ mov dword ptr [edx+LU_INT_CMD_HIGH], eax
+ mov dword ptr [edx+LU_INT_CMD_LOW], SyncIdCommand
+;
+; we're done - set TPR back to zero and return
+;
+ mov PCR[PcHal.ProcIrql], al ; Set CurrentIrql=0
+ mov [edx+LU_TPR], eax
+
+;
+; Program in the spurious interrupt vector into the IDT
+;
+ IDTEntry APIC_SPURIOUS_VECTOR, ApicSpuriousService@0
+
+ popfd
+
+ stdRET _HalpInitializeLocalUnit
+
+stdENDP _HalpInitializeLocalUnit
+
+_TEXT ends
+
+ end
diff --git a/private/ntos/nthals/halws3/i386/w3nmi.c b/private/ntos/nthals/halws3/i386/w3nmi.c
new file mode 100644
index 000000000..a368bf610
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3nmi.c
@@ -0,0 +1,78 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1993 Sequent Computer Systems, Inc.
+
+Module Name:
+
+ ws3nmi.c
+
+Abstract:
+
+ Provides x86 NMI handler for the WinServer 3000.
+
+Author:
+
+ Phil Hochstetler (phil@sequent.com) 3-30-93
+
+Revision History:
+
+--*/
+#include "halp.h"
+#include "bugcodes.h"
+#include "w3.inc"
+
+
+VOID
+HalHandleNMI(
+ IN OUT PVOID NmiInfo
+ )
+/*++
+
+Routine Description:
+
+ Called DURING an NMI. The system will BugCheck when an NMI occurs.
+ This function can return the proper bugcheck code, bugcheck itself,
+ or return success which will cause the system to iret from the nmi.
+
+ This function is called during an NMI - no system services are available.
+ In addition, you don't want to touch any spinlock which is normally
+ used since we may have been interrupted while owning it, etc, etc...
+
+Warnings:
+
+ Do NOT:
+ Make any system calls
+ Attempt to acquire any spinlock used by any code outside the NMI handler
+ Change the interrupt state. Do not execute any IRET inside this code
+
+ Passing data to non-NMI code must be done using manual interlocked
+ functions. (xchg instructions).
+
+Arguments:
+
+ NmiInfo - Pointer to NMI information structure (TBD)
+ - NULL means no NMI information structure was passed
+
+Return Value:
+
+ BugCheck code
+
+--*/
+{
+ //
+ // We can not look at the hardware to determine the source
+ // of the error because reads of many error registers clear
+ // the error and the IMP board is racing with us.
+ //
+ // If support for systems without an IMP board is added, we need
+ // to duplicate all the error reporting of the IMP board here.
+ //
+
+ HalDisplayString (MSG_HARDWARE_ERROR1);
+ HalDisplayString (MSG_HARDWARE_ERROR2);
+ HalDisplayString ("NMI: The system has detected a fatal NMI\n");
+ HalDisplayString (MSG_HALT);
+
+ KeEnterKernelDebugger();
+}
diff --git a/private/ntos/nthals/halws3/i386/w3profil.asm b/private/ntos/nthals/halws3/i386/w3profil.asm
new file mode 100644
index 000000000..8d8c58ff4
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3profil.asm
@@ -0,0 +1,223 @@
+ title "Profile Support"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+; Copyright (c) 1994 Sequent Computer Systems, Inc.
+;
+; Module Name:
+;
+; w3profil.asm
+;
+; Abstract:
+;
+; This module implements the code necessary to initialize,
+; field, and process the profile interrupt.
+;
+; Author:
+;
+; Phil Hochstetler (phil@sequent.com) 3-30-93
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc
+include i386\kimacro.inc
+include mac386.inc
+include i386\apic.inc
+include i386\ixcmos.inc
+include i386\w3.inc
+ .list
+
+ EXTRNP _DbgBreakPoint,0,IMPORT
+ EXTRNP _KeProfileInterrupt,1,IMPORT
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _HalEndSystemInterrupt,2
+ EXTRNP _HalBeginSystemInterrupt,3
+ extrn _HalpLocalUnitBase:DWORD
+
+;
+; APIC Timer Constants
+;
+
+APIC_TIMER_DISABLED equ (INTERRUPT_MASKED OR PERIODIC_TIMER OR APIC_PROFILE_VECTOR)
+APIC_TIMER_ENABLED equ (PERIODIC_TIMER OR APIC_PROFILE_VECTOR)
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+
+ProfileCountDownValue dd (200 * 11)
+HalpProfileRunning dd 0
+
+_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 set the interrupt rate to the value that's been set
+; by the KeSetProfileInterval routine. Then enable the APIC Timer interrupt.
+; This function gets called on every processor so the hal can enable
+; a profile interrupt on each processor.
+;--
+
+cPublicProc _HalStartProfileInterrupt ,1
+cPublicFpo 1, 0
+
+ mov ecx, _HalpLocalUnitBase ; load base address of local unit
+
+;
+; Set the interrupt rate to what is actually needed.
+;
+
+ mov eax, ProfileCountDownValue
+ mov [ecx+LU_INITIAL_COUNT], eax
+
+;
+; Set the Local APIC Timer to interrupt Periodically at APIC_PROFILE_VECTOR
+;
+
+ mov [ecx+LU_TIMER_VECTOR], APIC_TIMER_ENABLED
+
+
+ stdRET _HalStartProfileInterrupt
+
+stdENDP _HalStartProfileInterrupt
+
+
+
+;++
+;
+; HalStopProfileInterrupt(
+; IN ULONG Reserved
+; );
+;
+; Routine Description:
+;
+;--
+
+cPublicProc _HalStopProfileInterrupt ,1
+cPublicFpo 1, 0
+
+ mov ecx, _HalpLocalUnitBase ; load base address of local unit
+ mov [ecx+LU_TIMER_VECTOR], APIC_TIMER_DISABLED
+
+ 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.
+;
+; Arguments:
+;
+; (TOS+4) - Interval in 100ns unit.
+;
+; Return Value:
+;
+; Interval actually used by system.
+;--
+
+cPublicProc _HalSetProfileInterval ,1
+cPublicFpo 1, 0
+
+;
+; --- On the WinServer 3000, the profile timer uses TBASE on the local APIC
+; Timer zero. The TMBASE clock runs at 11Mhz so each clock tick is
+; equal to 90.9090ns or roughly 91ns. Since this is close to 100ns
+; we will use the 100ns units at the timer counter value directly.
+; To use an accurate muliple of 100ns units the profiler would have
+; to use 1000ns (1usec) intervals, this interval is equal to 11 clock
+; ticks.
+;
+
+ mov eax, [esp+4] ; ecx = interval in 100ns unit
+
+ mov ProfileCountDownValue, eax ; Save the Computed Count Down
+ mov ecx, _HalpLocalUnitBase ; load base address of local unit
+
+ ;
+ ; Set the interrupt rate in the chip.
+ ;
+
+ mov [ecx+LU_INITIAL_COUNT], eax
+
+ stdRET _HalSetProfileInterval
+
+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
+;
+
+ push APIC_PROFILE_VECTOR
+ sub esp, 4 ; allocate space to save OldIrql
+ stdCall _HalBeginSystemInterrupt, <PROFILE_LEVEL,APIC_PROFILE_VECTOR,esp>
+ or al,al ; check for spurious interrupt
+ jz Hpi100
+
+ stdCall _KeProfileInterrupt,<ebp> ; (ebp) = TrapFrame address
+
+ INTERRUPT_EXIT
+Hpi100:
+ add esp, 8 ; spurious, no EndOfInterrupt
+ SPURIOUS_INTERRUPT_EXIT
+
+stdENDP _HalpProfileInterrupt
+
+_TEXT ends
+
+ end
diff --git a/private/ntos/nthals/halws3/i386/w3space.asm b/private/ntos/nthals/halws3/i386/w3space.asm
new file mode 100644
index 000000000..ea6a125dc
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3space.asm
@@ -0,0 +1,1346 @@
+ title "Global Storage and Tables"
+;++
+;
+; Copyright (c) 1991 Microsoft Corporation
+; Copyright (c) 1993 Sequent Computer Systems, Inc.
+;
+; Module Name:
+;
+; w3space.asm
+;
+; Abstract:
+;
+; This module contains global storage and tables
+; used by the WinServer 3000 HAL implementation.
+;
+; Author:
+;
+; Phil Hochstetler (phil@sequent.com) 3-30-93
+;
+; Environment:
+;
+; Kernel Mode
+;
+; Revision History:
+;
+;--
+
+.386p
+ .xlist
+include ks386.inc
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+include mac386.inc
+include i386\apic.inc
+include i386\w3.inc
+ .list
+
+ extrn _HalpBeginW3InvalidInterrupt:near
+ extrn _HalpBeginW3APICInterrupt:near
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+;
+; This location is used to store the EISA Edge/Level Register
+; contents read once during initialization.
+;
+ align 4
+ public _HalpELCRImage
+_HalpELCRImage label word
+ dw 0
+
+;
+; This location is used to keep state around when a
+; level PIC interrupt occurs.
+;
+ align 4
+ public _HalpMASKED
+_HalpMASKED label word
+ dw 0
+
+;
+; The following location is used to keep a software copy
+; of the Post Code Register (register is write only). Used
+; to run front panel lights on the WinServer 3000.
+;
+ align 4
+ public _HalpW3PostRegisterImage
+_HalpW3PostRegisterImage label dword
+ dd 0
+
+;
+; Table to convert an Irql to a mask that looks for bits to
+; be exposed in the software copy of the IRR.
+;
+ align 4
+ public _HalpIrql2IRRMask
+_HalpIrql2IRRMask label dword
+ dd 11111111111111111111111111111110B ; irql 0
+ dd 11111111111111111111111111111100B ; irql 1
+ dd 11111111111111111111111111111000B ; irql 2
+ dd 11111111111111111111111111110000B ; irql 3
+ dd 11111111111111111111111111100000B ; irql 4
+ dd 11111111111111111111111111000000B ; irql 5
+ dd 11111111111111111111111110000000B ; irql 6
+ dd 11111111111111111111111100000000B ; irql 7
+ dd 11111111111111111111111000000000B ; irql 8
+ dd 11111111111111111111110000000000B ; irql 9
+ dd 11111111111111111111100000000000B ; irql 10
+ dd 11111111111111111111000000000000B ; irql 11
+ dd 11111111111111111110000000000000B ; irql 12
+ dd 11111111111111111100000000000000B ; irql 13
+ dd 11111111111111111000000000000000B ; irql 14
+ dd 11111111111111110000000000000000B ; irql 15
+ dd 11111111111111100000000000000000B ; irql 16
+ dd 11111111111111000000000000000000B ; irql 17
+ dd 11111111111110000000000000000000B ; irql 18
+ dd 11111111111100000000000000000000B ; irql 19
+ dd 11111111111000000000000000000000B ; irql 20
+ dd 11111111110000000000000000000000B ; irql 21
+ dd 11111111100000000000000000000000B ; irql 22
+ dd 11111111000000000000000000000000B ; irql 23
+ dd 11111110000000000000000000000000B ; irql 24
+ dd 11111100000000000000000000000000B ; irql 25
+ dd 11111000000000000000000000000000B ; irql 26
+ dd 11110000000000000000000000000000B ; irql 27
+ dd 11100000000000000000000000000000B ; irql 28
+ dd 11000000000000000000000000000000B ; irql 29
+ dd 10000000000000000000000000000000B ; irql 30
+ dd 00000000000000000000000000000000B ; irql 31
+
+;
+;
+; HalpBeginW3Interrupt does an indirect jump through this table so it
+; can quickly execute specific code for different interrupts. Vectors
+; are assigned to accomodate NT IRQL requirements and the APIC task
+; priority register definition.
+;
+ align 4
+ public _HalpBeginW3InterruptTable
+_HalpBeginW3InterruptTable label dword
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; Vector 0
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; 10
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; 20
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; 50 - Wake
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 60 - IRQ16
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 61 - IRQ17
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 62 - IRQ18
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 63 - IRQ19
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 64 - IRQ20
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 65 - IRQ21
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 66 - IRQ22
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 67 - IRQ23
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 70 - IRQ8
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 71 - IRQ9
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 72 - IRQ10
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 73 - IRQ11
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 74 - IRQ12
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 75 - IRQ13
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 76 - IRQ14
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 77 - IRQ15
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; 80 - IRQ0
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 81 - IRQ1
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; 82 - IRQ2
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 83 - IRQ3
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 84 - IRQ4
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 85 - IRQ5
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 86 - IRQ6
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 87 - IRQ7
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; 90 - Profile
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; A0 - Clock
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; B0 - IPI
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; C0 - Powerfail
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; D0 - IRQ0 8259
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; DF - IRQ15 8259
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; E0 - APIC_SPURIOUS
+ dd offset FLAT:_HalpBeginW3APICInterrupt ; E1 - APIC_SYSINT
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; F0
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; ..
+ dd offset FLAT:_HalpBeginW3InvalidInterrupt ; Vector FF
+;
+; This table is used by KeRaiseIrql and KeLowerIrql to convert an IRQL
+; value to an APIC task priority value. The APIC uses groups of 16
+; interrupt vectors for each task priority. Windows NT has allowed us
+; to use vectors 48-255 for external interrupt processing. This means we
+; actually have 14 hardware priorities available to work with. We only
+; use 11.
+;
+; To simplify the prioritization of PIC interrupts we decided to only create
+; 3 hardware priorities, i.e., 1 for each PIC. This keeps us from using
+; up all of the vectors in case we need them in the future and creates
+; less confusion about IRQ numbers and priority..
+;
+; The hardware priorities, vectors and APIC task priorities for the 32
+; NT IRQLs are established as follows:
+;
+ align 4
+ public _HalpIrql2TPR
+_HalpIrql2TPR label byte
+ db 0 SHL 4 ; IRQL = 0, tpr = 0:0 - Low
+ db 0 SHL 4 ; IRQL = 1, tpr = 0:0 - APC
+ db 0 SHL 4 ; IRQL = 2, tpr = 0:0 - DPC
+ db 0 SHL 4 ; IRQL = 3, tpr = 0:0 - Wake
+;
+; --- Divide the 24 device IRQLs into 3 hardware priority levels
+; ...1 for each 8259 PIC grouping....PIC 1 is highest priority
+;
+; PIC3
+ db 6 SHL 4 ; IRQL = 4, tpr = 6:0 - IRQ23 -
+ db 6 SHL 4 ; IRQL = 5, tpr = 6:0 - IRQ22 -
+ db 6 SHL 4 ; IRQL = 6, tpr = 6:0 - IRQ21 -
+ db 6 SHL 4 ; IRQL = 7, tpr = 6:0 - IRQ20 -
+ db 6 SHL 4 ; IRQL = 8, tpr = 6:0 - IRQ19 -
+ db 6 SHL 4 ; IRQL = 9, tpr = 6:0 - IRQ18 -
+ db 6 SHL 4 ; IRQL = 10, tpr = 6:0 - IRQ17
+ db 6 SHL 4 ; IRQL = 11, tpr = 6:0 - IRQ16 -
+; PIC2
+ db 7 SHL 4 ; IRQL = 12, tpr = 7:0 - IRQ15 -
+ db 7 SHL 4 ; IRQL = 13, tpr = 7:0 - IRQ14 -
+ db 7 SHL 4 ; IRQL = 14, tpr = 7:0 - IRQ13 -
+ db 7 SHL 4 ; IRQL = 15, tpr = 7:0 - IRQ12 -
+ db 7 SHL 4 ; IRQL = 16, tpr = 7:0 - IRQ11 -
+ db 7 SHL 4 ; IRQL = 17, tpr = 7:0 - IRQ10 -
+ db 7 SHL 4 ; IRQL = 18, tpr = 7:0 - IRQ9 -
+ db 7 SHL 4 ; IRQL = 19, tpr = 7:0 - IRQ8 -
+; PIC1
+ db 8 SHL 4 ; IRQL = 20, tpr = 8:0 - IRQ7 -
+ db 8 SHL 4 ; IRQL = 21, tpr = 8:0 - IRQ6 -
+ db 8 SHL 4 ; IRQL = 22, tpr = 8:0 - IRQ5 -
+ db 8 SHL 4 ; IRQL = 23, tpr = 8:0 - IRQ4 -
+ db 8 SHL 4 ; IRQL = 24, tpr = 8:0 - IRQ3 -
+; IRQ2 is dropped due to being invalid
+ db 8 SHL 4 ; IRQL = 25, tpr = 8:0 - IRQ1 -
+ db 8 SHL 4 ; IRQL = 26, tpr = 8:0 - IRQ0 -
+;
+ db 9 SHL 4 ; IRQL = 27, tpr = 9:0 - Profile
+ db 10 SHL 4 ; IRQL = 28, tpr = 10:0 - Clock -
+ db 11 SHL 4 ; IRQL = 29, tpr = 11:0 - IPI -
+ db 12 SHL 4 ; IRQL = 30, tpr = 12:0 - Power
+ db 13 SHL 4 ; IRQL = 31, tpr = 13:0 - High
+;
+ align 4
+;
+; --- The following table is used to convert a given interrupt vector
+; to a specific APIC Redirection table entry address. The redirection
+; table entries are used to mask/unmask interrupts, target interrupts,
+; and specify vectors for APIC interrupts.
+;
+; The value of each table entry is defined as follows:
+;
+; 0ybbbbbbb - RDIR window address
+; y = 0 - EBS RDIR entry
+; y = 1 - Base Processor I/O APIC RDIR entry
+; bbbbbbb = I/O Window address of RDIR entry
+; 00 - Vector unused/invalid
+; FF - Vector used but no RDIR enable mask needed
+;
+
+ public _HalpK2Vector2RdirTabEntry
+_HalpK2Vector2RdirTabEntry label byte
+ db 000H ; Vector 0
+ db 0ACH ; Vector 2 - SYS_NMI - Base I/O APIC
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 10
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 20
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 0FFH ; 30 - APC
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 0FFH ; 40 - DPC
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 020H ; 60 - EBS RDIR 8 - IRQ16
+ db 02EH ; EBS RDIR 15 - IRQ17
+ db 02CH ; EBS RDIR 14 - IRQ18
+ db 02AH ; EBS RDIR 13 - IRQ19
+ db 028H ; EBS RDIR 12 - IRQ20
+ db 026H ; EBS RDIR 11 - IRQ21
+ db 024H ; EBS RDIR 10 - IRQ22
+ db 022H ; EBS RDIR 9 - IRQ23
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 70
+ db 018H ; EBS RDIR 4 - IRQ9
+ db 01AH ; EBS RDIR 5 - IRQ10
+ db 01CH ; EBS RDIR 6 - IRQ11
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 01EH ; EBS RDIR 7 - IRQ15
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 80
+ db 000H ;
+ db 000H ;
+ db 010H ; EBS RDIR 0 - IRQ3
+ db 012H ; EBS RDIR 1 - IRQ4
+ db 014H ; EBS RDIR 2 - IRQ5
+ db 000H ;
+ db 016H ; EBS RDIR 3 - IRQ7
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 0FFH ; 90 - Profile
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; A0
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 0FFH ; B0
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 0A0H ; C0 - Power Fail, I/O RDIR 8
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; D0 - High
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 0FFH ; E0 - APIC Spurious
+ db 0AAH ; E1 - SYS_INT I/O RDIR 13
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; F0
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; FF
+;
+;
+; The following table is used to convert a vector number to an
+; EISA IRQ number. It is used by Begin and End System interrupt
+; to know when to do an EOI for edge and level interrupt considerations
+;
+ align 4
+ public _HalpK2Vector2EISA
+_HalpK2Vector2EISA label byte
+ db 000H ; Vector 0
+ db 000H ; Vector 2 - SYS_NMI - Base I/O APIC
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 16
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 32
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 48 - APC
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 64 - DPC
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 16 ; 96 - IRQ16
+ db 17 ; - IRQ17
+ db 18 ; - IRQ18
+ db 19 ; - IRQ19
+ db 20 ; - IRQ20
+ db 21 ; - IRQ21
+ db 22 ; - IRQ22
+ db 23 ; - IRQ23
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 8 ; 112 - IRQ8
+ db 9 ; - IRQ9
+ db 10 ; - IRQ10
+ db 11 ; - IRQ11
+ db 12 ; - IRQ12
+ db 13 ; - IRQ13
+ db 14 ; - IRQ14
+ db 15 ; - IRQ15
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 0 ; 128 - IRQ0
+ db 1 ; - IRQ1
+ db 2 ; - IRQ2
+ db 3 ; - IRQ3
+ db 4 ; - IRQ4
+ db 5 ; - IRQ5
+ db 6 ; - IRQ6
+ db 7 ; - IRQ7
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 8 ; 144 - Profile
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 160 - IRQ0 , Clock
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 176 - IPI
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 192 - Power Fail, I/O RDIR 8
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 208 - High
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 224 - APIC Spurious
+ db 000H ; 225 - SYS_ATTN I/O RDIR 7
+ db 000H ; 226 - SYS_TIMEOUT " " 9
+ db 000H ; 227 - SYS_ERROR " " 10
+ db 000H ; 228 - SYS_EISA_PERR " 11
+ db 000H ; 229 - SYS_IMS_ATTN " 12
+ db 000H ; 230 - SYS_INT " " 13
+ db 000H ; 231 - LOCAL_RESET " " 15
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 240
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ;
+ db 000H ; 255
+;
+ align 4
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+; This table is used to convert a designated IRQL number to
+; a specific interrupt vector. This is used by the generate
+; software interrupt mechanism and HalGetInterruptVector...
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+ public _HalpIRQLtoTPR
+_HalpIRQLtoTPR label byte
+ db 0 ; IRQL = 0, tpr = 0 - Low
+ db APIC_APC_VECTOR ; IRQL = 1, tpr = 3 - APC
+ db APIC_DPC_VECTOR ; IRQL = 2, tpr = 4 - DPC
+ db 0 ; IRQL = 3, tpr = 5
+;
+; --- Divide the 24 device IRQLs into 3 hardware priority levels
+; ...1 for each 8259 PIC grouping....PIC 1 is highest priority
+;
+; PIC3
+ db APIC_IRQ23_VECTOR ; IRQL = 4, tpr = 6 - IRQ23
+ db APIC_IRQ22_VECTOR ; IRQL = 5, tpr = 6 - IRQ22
+ db APIC_IRQ21_VECTOR ; IRQL = 6, tpr = 6 - IRQ21
+ db APIC_IRQ20_VECTOR ; IRQL = 7, tpr = 6 - IRQ20
+ db APIC_IRQ19_VECTOR ; IRQL = 8, tpr = 6 - IRQ19
+ db APIC_IRQ18_VECTOR ; IRQL = 9, tpr = 6 - IRQ18
+ db APIC_IRQ17_VECTOR ; IRQL = 10, tpr = 6 - IRQ17
+ db APIC_IRQ16_VECTOR ; IRQL = 11, tpr = 6 - IRQ16
+; PIC2
+ db APIC_IRQ15_VECTOR ; IRQL = 12, tpr = 7 - IRQ15
+ db APIC_IRQ14_VECTOR ; IRQL = 13, tpr = 7 - IRQ14
+ db APIC_IRQ13_VECTOR ; IRQL = 14, tpr = 7 - IRQ13
+ db APIC_IRQ12_VECTOR ; IRQL = 15, tpr = 7 - IRQ12
+ db APIC_IRQ11_VECTOR ; IRQL = 16, tpr = 7 - IRQ11
+ db APIC_IRQ10_VECTOR ; IRQL = 17, tpr = 7 - IRQ10
+ db APIC_IRQ9_VECTOR ; IRQL = 18, tpr = 7 - IRQ9
+ db APIC_IRQ8_VECTOR ; IRQL = 19, tpr = 7 - IRQ8
+; PIC1
+ db APIC_IRQ7_VECTOR ; IRQL = 20, tpr = 8 - IRQ7
+ db APIC_IRQ6_VECTOR ; IRQL = 21, tpr = 8 - IRQ6
+ db APIC_IRQ5_VECTOR ; IRQL = 22, tpr = 8 - IRQ5
+ db APIC_IRQ4_VECTOR ; IRQL = 23, tpr = 8 - IRQ4
+ db APIC_IRQ3_VECTOR ; IRQL = 24, tpr = 8 - IRQ3
+ db APIC_IRQ1_VECTOR ; IRQL = 25, tpr = 8 - IRQ1
+ db APIC_IRQ0_VECTOR ; IRQL = 26, tpr = 8 - IRQ0
+;
+ db APIC_PROFILE_VECTOR ; IRQL = 27, tpr = 9 - Profile
+ db APIC_CLOCK_VECTOR ; IRQL = 28, tpr = 10 - Clock
+ db APIC_IPI_VECTOR ; IRQL = 29, tpr = 11 - IPI
+ db APIC_POWERFAIL_VECTOR ; IRQL = 30, tpr = 12 - Power
+ db APIC_HIGH_VECTOR ; IRQL = 31, tpr = 13 - High
+;
+;
+; This table is used by HalGetInterruptVector to convert a
+; traditional EISA/ISA IRQ to an NT IRQL value.
+;
+ align 4
+ public _HalpK2EISAIrq2Irql
+_HalpK2EISAIrq2Irql label byte
+ db CLOCK2_LEVEL ; INTI 0 - system clock
+ db 25 ; INTI 1 - keyboard
+ db 24 ; INTI 2 - unused
+ db 24 ; INTI 3 - COM2
+ db 23 ; INTI 4 - COM1
+ db 22 ; INTI 5 - LPT2
+ db 21 ; INTI 6 - floppy
+ db 20 ; INTI 7 - LPT1
+ db 19 ; INTI 8 - RTC
+ db 18 ; INTI 9 - EISA IRQ9
+ db 17 ; INTI 10 - EISA IRQ10
+ db 16 ; INTI 11 - EISA IRQ11
+ db 15 ; INTI 12 - Mouse
+ db 14 ; INTI 13 - DMA
+ db 13 ; INTI 14 - IDE disk
+ db 12 ; INTI 15 - EISA IRQ15
+ db 11 ; INTI 16 - K2 IRQ 16
+ db 10 ; INTI 17 - K2 IRQ 17
+ db 9 ; INTI 18 - K2 IRQ 18
+ db 8 ; INIT 19 - K2 IRQ 19
+ db 7 ; INIT 20 - K2 IRQ 20
+ db 6 ; INIT 21 - K2 IRQ 21
+ db 5 ; INIT 22 - K2 IRQ 22
+ db 4 ; INIT 23 - K2 IRQ 23
+;
+; The following table is used to convert an IRQL to a corresponding
+; EISA IRQ. This is used to determine in BeginInterrupt and
+; EndInterrupt how do do EOI processing for edge/level EISA
+; interrupts. IRQ0 is always designated as edge and will not
+; change. We use this for all Irqls which do not correspond
+; to EISA IRQ numbers
+;
+ align 4
+ public _HalpK2Irql2Eisa
+_HalpK2Irql2Eisa label byte
+ db 0 ; IRQL = 0, tpr = 0 - Low
+ db 0 ; IRQL = 1, tpr = 3 - APC
+ db 0 ; IRQL = 2, tpr = 4 - DPC
+ db 0 ; IRQL = 3, tpr = 5
+;
+; --- Divide the 24 device IRQLs into 3 hardware priority levels
+; ...1 for each 8259 PIC grouping....PIC 1 is highest priority
+;
+; PIC3
+ db 0 ; IRQL = 4, tpr = 6 - IRQ23
+ db 0 ; IRQL = 5, tpr = 6 - IRQ22
+ db 0 ; IRQL = 6, tpr = 6 - IRQ21
+ db 0 ; IRQL = 7, tpr = 6 - IRQ20
+ db 0 ; IRQL = 8, tpr = 6 - IRQ19
+ db 0 ; IRQL = 9, tpr = 6 - IRQ18
+ db 0 ; IRQL = 10, tpr = 6 - IRQ17
+ db 0 ; IRQL = 11, tpr = 6 - IRQ16
+; PIC2
+ db 15 ; IRQL = 12, tpr = 7 - IRQ15
+ db 14 ; IRQL = 13, tpr = 7 - IRQ14
+ db 13 ; IRQL = 14, tpr = 7 - IRQ13
+ db 12 ; IRQL = 15, tpr = 7 - IRQ12
+ db 11 ; IRQL = 16, tpr = 7 - IRQ11
+ db 10 ; IRQL = 17, tpr = 7 - IRQ10
+ db 9 ; IRQL = 18, tpr = 7 - IRQ9
+ db 8 ; IRQL = 19, tpr = 7 - IRQ8
+; PIC1
+ db 7 ; IRQL = 20, tpr = 8 - IRQ7
+ db 6 ; IRQL = 21, tpr = 8 - IRQ6
+ db 5 ; IRQL = 22, tpr = 8 - IRQ5
+ db 4 ; IRQL = 23, tpr = 8 - IRQ4
+ db 3 ; IRQL = 24, tpr = 8 - IRQ3
+ db 1 ; IRQL = 25, tpr = 8 - IRQ1
+ db 0 ; IRQL = 26, tpr = 8 - IRQ0
+;
+ db 0 ; IRQL = 27, tpr = 9 - Profile
+ db 0 ; IRQL = 28, tpr = 10 - Clock
+ db 0 ; IRQL = 29, tpr = 11 - IPI
+ db 0 ; IRQL = 30, tpr = 12 - Power
+ db 0 ; IRQL = 31, tpr = 13 - High
+;
+
+;
+; _HalpK2EbsIOunitRedirectionTable is the memory image of the redirection table to be
+; loaded into APIC I/O unit 0 at initialization. there is one 64-bit entry
+; per interrupt input to the I/O unit. the edge/level trigger mode bit will
+; be set dynamically when the table is actually loaded. the mask bit is set
+; initially, and reset by EnableSystemInterrupt.
+;
+ align dword
+ public _HalpK2EbsIOunitRedirectionTable
+_HalpK2EbsIOunitRedirectionTable label dword
+
+ ; INTI0 - EISA IRQ3
+
+ dd APIC_IRQ3_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI1 - EISA IRQ4
+
+ dd APIC_IRQ4_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI2 - EISA IRQ5
+
+ dd APIC_IRQ5_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI3 - EISA IRQ7
+
+ dd APIC_IRQ7_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI4 - EISA IRQ9
+
+ dd APIC_IRQ9_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI5 - EISA IRQ10
+
+ dd APIC_IRQ10_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI6 - EISA IRQ11
+
+ dd APIC_IRQ11_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI7 - EISA IRQ15
+
+ dd APIC_IRQ15_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI8 - PowerBus IRQ16
+
+ dd APIC_IRQ16_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI9 - PowerBus IRQ23
+
+ dd APIC_IRQ23_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI10 - PowerBus IRQ22
+
+ dd APIC_IRQ22_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI11 - PowerBus IRQ21
+
+ dd APIC_IRQ21_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI12 - PowerBus IRQ20
+
+ dd APIC_IRQ20_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI13 - PowerBus IRQ19
+
+ dd APIC_IRQ19_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI14 - PowerBus IRQ18
+
+ dd APIC_IRQ18_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; INTI15 - PowerBus IRQ17
+
+ dd APIC_IRQ17_VECTOR + INTERRUPT_MASKED + \
+ DELIVER_LOW_PRIORITY + LOGICAL_DESTINATION
+ dd DESTINATION_ALL_CPUS
+
+ ; zero entry indicates end of table
+
+ dd 0
+;
+;
+; The following table is used to convert a RDIR # on the EBS
+; I/O APIC to an EISA IRQ
+;
+ align 4
+ public _HalpK2Rdir2Irq
+_HalpK2Rdir2Irq label byte
+ db 3 ; RDIR = 0, IRQ = 3
+ db 4 ; RDIR = 1, IRQ = 4
+ db 5 ; RDIR = 2, IRQ = 5
+ db 7 ; RDIR = 3, IRQ = 7
+ db 9 ; RDIR = 4, IRQ = 9
+ db 10 ; RDIR = 5, IRQ = 10
+ db 11 ; RDIR = 6, IRQ = 11
+ db 15 ; RDIR = 7, IRQ = 15
+ db 16 ; RDIR = 8, IRQ = 16
+ db 23 ; RDIR = 9, IRQ = 23
+ db 22 ; RDIR = 10, IRQ = 22
+ db 21 ; RDIR = 11, IRQ = 21
+ db 20 ; RDIR = 12, IRQ = 20
+ db 19 ; RDIR = 13, IRQ = 19
+ db 18 ; RDIR = 14, IRQ = 18
+ db 17 ; RDIR = 15, IRQ = 17
+;
+; _HalpW3BaseIOunitRedirectionTable is the memory image of the
+; redirection table to be loaded into APIC I/O unit 1 at initialization.
+; there is one 64-bit entry per interrupt input to the I/O unit.
+;
+ align 4
+ public _HalpW3BaseIOunitRedirectionTable
+_HalpW3BaseIOunitRedirectionTable label dword
+
+ ; INTI0 - Unused
+
+ dd INTERRUPT_MASKED
+ dd 0
+
+ ; INTI1 - Unused
+
+ dd INTERRUPT_MASKED
+ dd 0
+
+ ; INTI2 - Unused
+
+ dd INTERRUPT_MASKED
+ dd 0
+
+ ; INTI3 - Unused
+
+ dd INTERRUPT_MASKED
+ dd 0
+
+
+ ; INTI4 - Unused
+
+ dd INTERRUPT_MASKED
+ dd 0
+
+
+ ; INTI5 - Unused
+
+ dd INTERRUPT_MASKED
+ dd 0
+
+ ; INTI6 - Unused
+
+ dd INTERRUPT_MASKED
+ dd 0
+
+ ; INTI7 - SYS_ATTN_L
+
+ dd INTERRUPT_MASKED
+ dd 0
+
+ ; INTI8 - SYS_POWER_FAIL
+
+ dd INTERRUPT_MASKED
+ dd 0
+
+ ; INTI9 - SYS_TIMEOUT
+
+ dd INTERRUPT_MASKED
+ dd 0
+
+ ; INTI10 - SYS_ERROR
+
+ dd INTERRUPT_MASKED
+ dd 0
+
+ ; INTI11 - SYS_EISA_PERR
+
+ dd INTERRUPT_MASKED
+ dd 0
+
+ ; INTI12 - SYS_IMS_ATTN
+
+ dd INTERRUPT_MASKED
+ dd 0
+
+ ; INTI13 - SYS_INT
+
+ dd APIC_SYSINT_VECTOR + DELIVER_EXTINT + LOGICAL_DESTINATION
+ dd DESTINATION_CPU_0
+
+ ; INTI14 - SYS_NMI
+
+ dd DELIVER_NMI + LEVEL_TRIGGERED + LOGICAL_DESTINATION
+ dd DESTINATION_CPU_0
+
+ ; INTI15 - LOC_RESET_CPU
+
+ dd DELIVER_NMI + LEVEL_TRIGGERED + LOGICAL_DESTINATION
+ dd DESTINATION_CPU_0
+
+ ; zero entry indicates end of table
+
+ dd 0
+_DATA ENDS
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+_TEXT ENDS
+
+ END
diff --git a/private/ntos/nthals/halws3/i386/w3spin.asm b/private/ntos/nthals/halws3/i386/w3spin.asm
new file mode 100644
index 000000000..32746cfb6
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3spin.asm
@@ -0,0 +1,389 @@
+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:
+;
+; (al) = OldIrql - old irql
+;
+;--
+
+align 16
+cPublicFastCall KfAcquireSpinLock ,1
+cPublicFpo 0,0
+
+
+ifdef NT_UP ; On up build just perform raiseirql
+
+ jmp @KfRaiseIrql@4 ; (al) = oldIrql
+else
+
+;
+; On a MP build we raise to dispatch_level
+; and then acquire the spinlock
+;
+
+ push ecx ; Save address of spin lock
+
+ mov ecx, DISPATCH_LEVEL ; (cl) = newIrql
+ fstCall KfRaiseIrql ; (al) = oldIrql
+
+ pop ecx ; (ecx) -> spinlock
+
+;
+; Attempt to assert the lock
+;
+
+sl10: ACQUIRE_SPINLOCK ecx,<short sl20>
+
+ fstRET KfAcquireSpinLock ; (al) = oldIrql
+
+;
+; Lock is owned, spin till it looks free, then go get it again.
+;
+
+sl20: SPIN_ON_SPINLOCK ecx,sl10
+
+endif
+
+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
+cPublicFpo 2,0
+
+ RELEASE_SPINLOCK ecx ; release it
+endif
+ mov ecx, edx
+ 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/halws3/i386/w3sproc.c b/private/ntos/nthals/halws3/i386/w3sproc.c
new file mode 100644
index 000000000..54a5b5395
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3sproc.c
@@ -0,0 +1,710 @@
+/*++
+
+Copyright (c) 1991 Microsoft Corporation
+Copyright (c) 1993 Sequent Computer Systems, Inc.
+
+Module Name:
+
+ w3sproc.c
+
+Abstract:
+
+ WinServer 3000 Start Next Processor C code.
+
+ This module implements the initialization of the system dependent
+ functions that define the Hardware Architecture Layer (HAL) for a
+ WinServer 3000.
+
+Author:
+
+ Ken Reneris (kenr) 22-Jan-1991
+ Phil Hochstetler (phil@sequent.com) 3-30-93
+
+Environment:
+
+ Kernel mode only.
+
+Revision History:
+
+--*/
+
+#include "halp.h"
+#include "apic.inc"
+#include "w3.inc"
+#include "halver.h"
+
+VOID
+HalpMapCR3 (
+ IN ULONG VirtAddress,
+ IN PVOID PhysicalAddress,
+ IN ULONG Length
+ );
+
+ULONG
+HalpBuildTiledCR3 (
+ IN PKPROCESSOR_STATE ProcessorState
+ );
+
+VOID
+HalpFreeTiledCR3 (
+ VOID
+ );
+
+ULONG
+HalpGetW3EisaInterruptVector(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ );
+
+
+VOID HalpInitOtherBuses (VOID);
+
+#define LOW_MEMORY 0x000100000
+#define MAX_PT 8
+
+extern VOID StartPx_PMStub(VOID);
+extern PKPCR HalpProcessorPCR[];
+
+
+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
+#ifndef NT_UP
+
+BOOLEAN
+HalpInitMP (
+ IN ULONG Phase,
+ IN PLOADER_PARAMETER_BLOCK LoaderBlock
+ )
+/*++
+
+Routine Description:
+ Allows MP initialization from HalInitSystem.
+
+Arguments:
+ Same as HalInitSystem
+
+Return Value:
+ none.
+
+--*/
+{
+ PKPCR pPCR;
+
+ pPCR = KeGetPcr();
+
+ if (Phase == 0) {
+ 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);
+ return TRUE;
+
+ } else {
+
+ //
+ // Phase 1 for another processor
+ //
+
+ }
+}
+#endif
+
+VOID
+HalpFatal (
+ IN PCHAR ErrorCode
+ )
+
+/*++
+
+Routine Description:
+
+ Print the fatal error code and direct end user to
+ call service representitive for help.
+
+Arguments:
+
+ ErrorCode - the error code string to print on error.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+
+ HalDisplayString("HAL: FATAL error #");
+ HalDisplayString(ErrorCode);
+ HalDisplayString(" has occured.\n");
+ HalDisplayString("HAL: Call your service representitive for help.\n");
+ HalDisplayString(MSG_HALT);
+ KeEnterKernelDebugger();
+}
+
+
+VOID
+HalpCheckHw (
+ )
+
+/*++
+
+Routine Description:
+
+ Verify different aspects of the hardware to assure
+ the current hardware is both a WinServer and running
+ sufficient level hardware to support Windows NT.
+
+Arguments:
+
+ None.
+
+Return Value:
+
+ None.
+
+--*/
+
+{
+ UNICODE_STRING unicodeValueName;
+ UNICODE_STRING KeyName;
+ OBJECT_ATTRIBUTES ObjectAttributes;
+ PKEY_VALUE_PARTIAL_INFORMATION KeyValueInformation;
+ NTSTATUS NtStatus;
+ HANDLE SystemHandle;
+ UCHAR KeyValueBuffer[512];
+ ULONG resultLength;
+ PWSTR s;
+ ULONG m, d, y;
+
+ KeyValueInformation = (PKEY_VALUE_PARTIAL_INFORMATION)KeyValueBuffer;
+
+ RtlInitUnicodeString(
+ &unicodeValueName,
+ L"\\Registry\\Machine\\Hardware\\Description\\System"
+ );
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &unicodeValueName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE) NULL,
+ (PSECURITY_DESCRIPTOR) NULL
+ );
+
+ NtStatus = ZwOpenKey(
+ &SystemHandle,
+ KEY_READ,
+ &ObjectAttributes
+ );
+
+ if (!NT_SUCCESS( NtStatus ))
+ HalpFatal("1015801");
+
+ RtlInitUnicodeString( &KeyName, L"SystemBiosDate" );
+
+ NtStatus = ZwQueryValueKey(
+ SystemHandle,
+ &KeyName,
+ KeyValuePartialInformation,
+ KeyValueInformation,
+ sizeof(KeyValueBuffer),
+ &resultLength
+ );
+
+ if (!NT_SUCCESS( NtStatus )
+ || KeyValueInformation->Type != REG_SZ
+ || KeyValueInformation->DataLength < 16
+ )
+ HalpFatal("1015802");
+
+ //
+ // Bios date must be greater than or equal to "02/27/93"
+ //
+
+ s = (PWSTR)KeyValueInformation->Data;
+ m = (*s++ - L'0') * 10; m += (*s++ - L'0'); *s++; // skip '/'
+ d = (*s++ - L'0') * 10; d += (*s++ - L'0'); *s++; // skip '/'
+ y = (*s++ - L'0') * 10; y += (*s++ - L'0');
+
+ if ((y * 365) + (m * 31) + d < (93 * 365) + (2 * 31) + 27)
+ HalpFatal("1015803");
+
+ RtlInitUnicodeString( &KeyName, L"VideoBiosVersion" );
+
+ NtStatus = ZwQueryValueKey(
+ SystemHandle,
+ &KeyName,
+ KeyValueBasicInformation,
+ KeyValueInformation,
+ sizeof(KeyValueBuffer),
+ &resultLength
+ );
+
+ if (!NT_SUCCESS( NtStatus )
+ || KeyValueInformation->Type != REG_MULTI_SZ
+ )
+ HalpFatal("1015804");
+
+ ZwClose(SystemHandle);
+
+ RtlInitUnicodeString(
+ &unicodeValueName,
+ L"\\Registry\\Machine\\Hardware\\Description\\System\\EisaAdapter\\0\\DiskController"
+ );
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &unicodeValueName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE) NULL,
+ (PSECURITY_DESCRIPTOR) NULL
+ );
+
+ NtStatus = ZwOpenKey(
+ &SystemHandle,
+ KEY_READ,
+ &ObjectAttributes
+ );
+
+ if (!NT_SUCCESS( NtStatus ))
+ HalpFatal("1015805");
+
+ ZwClose(SystemHandle);
+
+ RtlInitUnicodeString(
+ &unicodeValueName,
+ L"\\Registry\\Machine\\Hardware\\Description\\System\\EisaAdapter\\0\\DisplayController"
+ );
+
+ InitializeObjectAttributes(
+ &ObjectAttributes,
+ &unicodeValueName,
+ OBJ_CASE_INSENSITIVE,
+ (HANDLE) NULL,
+ (PSECURITY_DESCRIPTOR) NULL
+ );
+
+ NtStatus = ZwOpenKey(
+ &SystemHandle,
+ KEY_READ,
+ &ObjectAttributes
+ );
+
+ if (!NT_SUCCESS( NtStatus ))
+ HalpFatal("1015806");
+
+ ZwClose(SystemHandle);
+}
+
+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 // WinServer 3000 is an EISA machine
+ );
+
+ RtlFreeUnicodeString (&UHalName);
+
+ //
+ // Take advantage of the registry being enabled to check
+ // it for a WinServer with the proper hardware support.
+ //
+
+ HalpCheckHw();
+
+}
+
+
+VOID
+HalpRebootNow(
+ )
+/*++
+--*/
+{
+#define KEYBPORT (PUCHAR)0x64
+#define RESET 0xfe
+
+#ifndef NT_UP
+ PKPCR pPCR;
+ PWS3_HAL_PRIVATE pPriv;
+ USHORT FCRAddr;
+ UCHAR i;
+ UCHAR Me;
+
+ pPCR = KeGetPcr();
+ pPriv = (PWS3_HAL_PRIVATE) &pPCR->HalReserved[0];
+ Me = pPriv->PcrNumber;
+
+ //
+ // Reset each of the slaves and issue the reset command.
+ //
+
+ for (i = 1; HalpProcessorPCR[i]; i++) {
+
+ //
+ // Never reset myself
+ //
+
+ if (i == Me)
+ continue;
+
+ //
+ // Put processor into reset by setting the FCR reset bit
+ //
+
+ pPriv = (PWS3_HAL_PRIVATE) &HalpProcessorPCR[i]->HalReserved[0];
+ FCRAddr = pPriv->ProcSlotAddr | FCR;
+ WRITE_PORT_USHORT((PUSHORT) FCRAddr,
+ (USHORT)(READ_PORT_USHORT((PUSHORT) FCRAddr) |
+ ((USHORT) FCR_RESET_MASK)));
+ }
+
+ //
+ // Send the reset command to the keyboard controller
+ //
+
+ for (;;) {
+ WRITE_PORT_UCHAR(KEYBPORT, RESET);
+ KeStallExecutionProcessor(30 * 1000000);
+ }
+#else
+ //
+ // Send the reset command to the keyboard controller
+ //
+
+ for (;;) {
+ WRITE_PORT_UCHAR(KEYBPORT, RESET);
+ KeStallExecutionProcessor(30 * 1000000);
+ }
+#endif
+}
+
+VOID
+HalpResetAllProcessors (
+ )
+/*++
+
+Routine Description:
+ Called very late in the process of rebooting the machine
+ from HalpReboot() to attempt to put the machine in a state
+ where sending the reset command to the keyboard controller will
+ actually reboot the machine.
+
+ On a WinServer 3000, only the P0 processor will see the system
+ reset line so we must attempt to shutdown each of the slaves.
+ If the P0 processor is not responding, then we make a best attempt.
+ Also, this has some implication on leaving errors asserted (like
+ the APIC NMI state) which the BIOS does not handle.
+
+ N.B. Is is critical that we do not put P0 into reset by writing
+ the feature control register (FCR) because it will not see the
+ reset and the system will hang.
+
+Arguments:
+ None.
+
+Return Value:
+ None.
+
+--*/
+{
+#ifdef NT_UP
+ HalDisplayString("System Reboot in progress.\n");
+ HalDisplayString("Please wait while the system reboots.\n");
+ HalpRebootNow();
+#else
+ PWS3_HAL_PRIVATE pPriv;
+ PKPCR pPCR;
+
+ pPCR = KeGetPcr();
+ pPriv = (PWS3_HAL_PRIVATE) &pPCR->HalReserved[0];
+
+ HalDisplayString("System Reboot in progress.\n");
+ HalDisplayString("Please wait while the system reboots.\n");
+
+ if (pPriv->PcrNumber == 0)
+ HalpRebootNow();
+
+ //
+ // On P1-PN, so try to signal P0 to reboot the system by
+ // taking over P0's IPI handler and sending an IPI.
+ //
+
+ HalpProcessorPCR[0]->IDT[APIC_IPI_VECTOR].ExtendedOffset = HIGHWORD(HalpRebootNow);
+ HalpProcessorPCR[0]->IDT[APIC_IPI_VECTOR].Offset = LOWWORD(HalpRebootNow);
+ HalRequestIpi(1);
+ KeStallExecutionProcessor(30 * 1000000);
+
+ //
+ // We only reach here if P0 fails to reboot the system.
+ // Try to reset all the slaves but our self and P0 and
+ // then try to reboot. This is the last attempt and
+ // if it fails, we will probably hang the system.
+ //
+
+ HalpRebootNow();
+#endif
+}
+
+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
+ )
+{
+ PBUS_HANDLER Bus;
+
+ //
+ // Change GetInterruptVector handler on Eisa Bus 0 to a
+ // Winserver specific handler which supports the Winserver's
+ // Eisa interrupt vectors 16-23.
+ //
+
+ Bus = HalpHandlerForBus (Eisa, 0);
+ Bus->GetInterruptVector = HalpGetW3EisaInterruptVector;
+
+ //
+ // no other internal buses supported
+ //
+}
+
+
+NTSTATUS
+HalpGetMcaLog (
+ OUT PMCA_EXCEPTION Exception,
+ OUT PULONG ReturnedLength
+ )
+{
+ return STATUS_NOT_SUPPORTED;
+}
+
+NTSTATUS
+HalpMcaRegisterDriver(
+ IN PMCA_DRIVER_INFO DriverInfo
+ )
+{
+ return STATUS_NOT_SUPPORTED;
+}
+
+ULONG
+FASTCALL
+HalSystemVectorDispatchEntry (
+ IN ULONG Vector,
+ OUT PKINTERRUPT_ROUTINE **FlatDispatch,
+ OUT PKINTERRUPT_ROUTINE *NoConnection
+ )
+{
+ return FALSE;
+}
diff --git a/private/ntos/nthals/halws3/i386/w3sproca.asm b/private/ntos/nthals/halws3/i386/w3sproca.asm
new file mode 100644
index 000000000..8c0fe0b37
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3sproca.asm
@@ -0,0 +1,377 @@
+ title "MP primitives for WinServer 3000"
+;++
+;
+; Copyright (c) 1991 Microsoft Corporation
+; Copyright (c) 1993 Sequent Computer Systems, Inc.
+;
+; Module Name:
+;
+; w3sproca.asm
+;
+; Abstract:
+;
+; WinServer 3000 Start Next Processor assembly code
+;
+; This module along with w3sproc.c implement the code to start
+; off the mulitple processors on the WinServer 3000.
+;
+; Author:
+;
+; Phil Hochstetler (phil@sequent.com) 3-30-93
+;
+; Revision History:
+;
+;--
+.386p
+ .xlist
+include ks386.inc
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+include mac386.inc
+include i386\w3.inc
+ .list
+
+ EXTRNP _ExAllocatePool,2
+ EXTRNP _HalpBuildTiledCR3,1
+ EXTRNP _HalpFreeTiledCR3,0
+ EXTRNP _HalpUnResetLocalUnit,1
+
+ extrn _MppIDT:DWORD
+ extrn _MpLowStub:DWORD
+ extrn _MpLowStubPhysicalAddress:DWORD
+ extrn _ProcessorsPresent:DWORD
+
+;
+; Internal defines and structures
+;
+
+PxParamBlock struc
+ WS3_flag dd ?
+ WS3_TiledCR3 dd ?
+ WS3_P0EBP dd ?
+ WS3_ControlPort dd ?
+ WS3_PB db ProcessorStateLength dup (?)
+PxParamBlock ends
+
+_TEXT SEGMENT DWORD 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]
+;
+; CMOS equates for warm boot
+;
+CMOS_ADDR EQU 70h
+CMOS_DATA EQU 71h
+CMOSCTL EQU 0Fh
+CMOSWARMBOOT EQU 0Ah
+;
+
+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.WS3_flag, eax
+
+ cmp _ProcessorsPresent, eax ; any processors left to start
+ je snp_exit ; exit FALSE
+;
+ bsf eax, _ProcessorsPresent ; get slot index
+ btr _ProcessorsPresent, eax ; clear slot index
+ shl eax, EISA_SHIFT
+ or eax,FCR ; Create Control Port Address
+ mov PxFrame.WS3_ControlPort, eax ; Store in Frame
+
+ 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.WS3_PB
+ mov esi, pProcessorState
+ mov ecx, ProcessorStateLength ; Copy processorstate
+ rep movsb ; to PxFrame
+
+ stdCall _HalpBuildTiledCR3, <pProcessorState>
+
+ mov PxFrame.WS3_TiledCR3, eax
+ mov PxFrame.WS3_P0EBP, ebp
+
+ 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.WS3_PB.PsContextFrame.CsSegCs]
+ mov [eax.W3rxFlatCS], bx ; patch realmode stub with
+ mov [eax.W3rxPMStub], 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
+
+ mov eax, pLoaderBlock ; lookup processor # we are
+ mov eax, [eax].LpbPrcb ; starting
+ movzx eax, byte ptr [eax].PbNumber
+ stdCall _HalpUnResetLocalUnit,<eax>
+
+ mov edx, PxFrame.WS3_ControlPort ; Control port of target
+ mov al,CMOSCTL
+ out CMOS_ADDR,al ; Tell BIOS its warm BOOT
+ mov al,CMOSWARMBOOT
+ out CMOS_DATA,al
+ in ax, dx ; processor
+ and ax, NOT FCR_RESET_MASK ; remove Reset bit
+ out dx, ax ; bring Pn out of reset
+@@:
+ cmp PxFrame.WS3_flag, 0 ; wait for Px to get it's
+ jz @b ; info
+
+; REMOVE THIS CODE FRAGMENT WHEN WE FORCE BIOS REV TO BE 4.0 OR GREATER
+
+ mov al,0 ; Re-enable NMI in ISP
+ out CMOS_ADDR,al ; because pre 4.0 BIOS
+ ; code executed by
+ ; Px leaves it disabled.
+
+; REMOVE THIS CODE FRAGMENT WHEN WE FORCE BIOS REV TO BE 4.0 OR GREATER
+
+ pop dword ptr [ebx] ; restore WarmResetVector
+ sti
+
+ stdCall _HalpFreeTiledCR3 ; free memory used for tiled
+ ; CR3
+
+ 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
+cPublicFpo 0, 0
+
+ cli
+
+ db 066h ; load the GDT
+ lgdt fword ptr cs:[WS3_PB.PsSpecialRegisters.SrGdtr]
+
+ db 066h ; load the IDT
+ lidt fword ptr cs:[WS3_PB.PsSpecialRegisters.SrIdtr]
+
+ mov eax, cs:[WS3_TiledCR3]
+ mov cr3, eax
+
+ mov ebp, dword ptr cs:[WS3_P0EBP]
+ mov ecx, dword ptr cs:[WS3_PB.PsContextFrame.CsSegDs]
+ mov ebx, dword ptr cs:[WS3_PB.PsSpecialRegisters.SrCr3]
+ mov eax, dword ptr cs:[WS3_PB.PsSpecialRegisters.SrCr0]
+
+ mov cr0, eax ; into prot mode
+
+ db 066h
+ db 0eah ; reload cs:eip
+W3rxPMStub dd 0
+W3rxFlatCS dw 0
+
+StartPx_RMStub_Len equ $ - StartPx_RMStub
+stdENDP StartPx_RMStub
+
+
+_TEXT16 ends ; End 16 bit code
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE' ; 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
+;
+;--
+
+cPublicProc _StartPx_PMStub ,0
+cPublicFpo 0, 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.WS3_PB.PsSpecialRegisters
+
+ lldt word ptr ds:[esi].SrLdtr ; load ldtr
+ ltr word ptr ds:[esi].SrTr ; load tss
+
+ lea edi, PxFrame.WS3_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
+
+;
+ inc [PxFrame.WS3_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/halws3/i386/w3stall.asm b/private/ntos/nthals/halws3/i386/w3stall.asm
new file mode 100644
index 000000000..588878a83
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3stall.asm
@@ -0,0 +1,382 @@
+
+ title "Stall Execution Support"
+;++
+;
+; Copyright (c) 1989 Microsoft Corporation
+; Copyright (c) 1993 Sequent Computer Systems, Inc.
+;
+; Module Name:
+;
+; w3stall.asm
+;
+; Abstract:
+;
+; This module implements the code necessary to stall the processor
+; for some specified period of time.
+;
+; Author:
+;
+; Phil Hochstetler (phil@sequent.com)
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc
+include i386\kimacro.inc
+include mac386.inc
+include i386\apic.inc
+include i386\ixcmos.inc
+include i386\w3.inc
+
+
+ EXTRNP _DbgBreakPoint,0,IMPORT
+ extrn _HalpLocalUnitBase:DWORD
+
+ page ,132
+ subttl "Initialize Stall Execution Counter"
+;++
+;
+; VOID
+; HalpInitializeStallExecution (
+; IN CCHAR ProcessorNumber
+; )
+;
+; Routine Description:
+;
+; This routine initialize the per Microsecond counter for
+; KeStallExecutionProcessor
+;
+; Arguments:
+;
+; ProcessorNumber - Processor Number
+;
+; Return Value:
+;
+; None.
+;
+; Note:
+;
+; This routine is called from the HalInitSystem routine in w3hal.c.
+; It is only called during Phase 0 init on P0
+;
+;--
+
+;
+; Local Variables - These are valid even in the Isr because we're the only thing
+; running on this processor and no-one else will change the ebp
+; register.
+
+StallIDTPointer equ [ebp-6]
+StallIDTArea equ [ebp-8]
+StallInterruptCount equ [ebp-12]
+StallLVTentry equ dword ptr [ebp-16]
+StallDummyentry0 equ dword ptr [ebp-20]
+StallDummyentry1 equ [ebp-24]
+StallApicTpr equ dword ptr [ebp-28]
+
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:NOTHING, FS:NOTHING, GS:NOTHING
+
+cPublicProc _HalpInitializeStallExecution,1
+
+ push ebp ; save ebp
+ mov ebp, esp ; set up 28 bytes for local use
+ sub esp, 32
+
+ pushfd ; save caller's eflag
+
+;
+; --- For an APIC implementaion we use the APIC timer0 and install a
+; --- Local Vector Table entry to point to a high priority
+; --- vector for the Timer0 Interrupt. Then use the TPR in the local APIC
+; --- to mask out every thing below it. To this end we've reserved a vector
+; --- in the highest priority group (0F8) to be used here.
+;
+
+;
+; Since APIC timer interrupt will come from APIC_STALL_VECTOR, we need to
+; Save original APIC_STALL_VECTOR descriptor and set the descriptor
+; to point to our own handler.
+;
+ sidt fword ptr StallIDTArea ; get IDT address
+ mov edx, StallIDTPointer ; (edx)->IDT
+
+;
+; --- Save Original Descriptor on Stack
+;
+ push dword ptr [edx+8*APIC_STALL_VECTOR]; (TOS) = orig. Vector
+ push dword ptr [edx+8*APIC_STALL_VECTOR + 4]
+ push edx ; (TOS) -> IDT
+;
+; --- Install our IDT entry
+;
+ mov eax, offset FLAT:ApicTimer0Handler
+ mov word ptr [edx+8*APIC_STALL_VECTOR], ax ; Low half handler addr
+ mov word ptr [edx+8*APIC_STALL_VECTOR+2], KGDT_R0_CODE ; set up selector
+ mov word ptr [edx+8*APIC_STALL_VECTOR+4], D_INT032 ; 386 interrupt gate
+ shr eax, 16 ; (ax)=higher half of handler addr
+ mov word ptr [edx+8*APIC_STALL_VECTOR+6], ax
+;
+; --- Init. interrupt Flag
+;
+ mov dword ptr StallinterruptCount, 0 ; set no interrupt yet
+
+ ;
+ ; Get the Local Vector Table Timer Zero entry and save it
+ ;
+ mov edx, _HalpLocalUnitBase ; get the current TPR
+ mov eax, [edx+LU_TIMER_VECTOR] ; get Timer zero LVT
+ mov StallLVTentry, eax ; Save LVT
+
+ ;
+ ; --- Set the Inital Timer count
+ ; --- Note: we will use TMBASE with No Divider
+ ; --- which runs at 11 Mhz
+ ;
+
+ mov eax,(PeriodInUsec*11) ; Set the initial TIMER0 count
+ mov [edx+LU_INITIAL_COUNT], eax
+ ;
+ ; Save then set the Local APIC's TPR to mask all interrupts except the
+ ; highest priority group
+ ;
+
+ mov eax, [edx+LU_TPR] ; get TPR
+ mov StallApicTpr, eax ; save TPR for later
+
+ ;
+ ; Set TPR (Priority of CPU) = TPR (VECTOR - 16). So that all interrupts
+ ; in VECTOR's priority group will be allowed in.
+ ;
+ mov eax, APIC_STALL_VECTOR-10H
+ mov [edx+LU_TPR], eax ; Write the new TPR
+ ;
+ ;
+ ; --- Create Timer zero entry and store in Local Vector Table
+ ; --- STARTING the clock
+ ;
+ mov eax,(00040000H OR PERIODIC_TIMER)
+ or eax,(INTERRUPT_MOT_MASKED OR APIC_STALL_VECTOR)
+@@:
+ test [edx+LU_TIMER_VECTOR], DELIVERY_PENDING
+ jnz @b
+
+ mov [edx+LU_TIMER_VECTOR], eax
+;
+; --- Now enable the interrupt and start the counter
+;
+
+ xor eax, eax ; (eax) = 0, initialize loopcount
+;
+; --- ENABLE TIMER ZERO INTERRUPT
+;
+ sti
+;
+; --- BEGIN SPIN Calibration LOOP
+;
+
+Stall10:
+ add eax, 1 ; increment the loopcount
+ jnz short Stall10
+;
+; Counter overflowed
+;
+
+ stdCall _DbgBreakPoint
+
+;++
+;
+; VOID
+; ApicTimer0Handler(
+; );
+;
+;Routine Description:
+;
+; APIC Timer zero interrupt Handler for Calibrating Spin Loop for
+; KeStallExecution();
+;
+; Note: we discard first real time clock interrupt and compute the
+; permicrosecond loopcount on receiving of the second real time
+; interrupt. This is because the first interrupt is generated
+; based on the previous real time tick interval.
+;
+;--
+ Public ApicTimer0Handler
+
+ApicTimer0Handler:
+
+ inc dword ptr StallInterruptCount ; increment interrupt count
+ cmp dword ptr StallInterruptCount,1 ; Is this the first interrupt?
+ jnz Stall25 ; no, its the second go process it
+
+ pop eax ; get rid of original ret addr
+ push offset FLAT:Stall10 ; set new ret addr --> top of loop
+
+ ;
+ ; EOI the Local Apic, the value written is immaterial
+ ;
+
+ mov eax, _HalpLocalUnitBase ; write to local unit EOI register
+ mov dword ptr [eax+LU_EOI], 0
+;
+ xor eax, eax ; reset loop counter
+;
+ iretd
+;
+; --- Process EAX for Spin Count
+;
+;
+Stall25:
+
+ifdef DBG
+ cmp eax, 0
+ jnz short Stall30
+
+ stdCall _DbgBreakPoint
+endif
+;
+Stall30:
+
+ xor edx, edx ; (edx:eax) = dividend
+ mov ecx, PeriodInUSec; ; (ecx) = time spent in the loop
+ div ecx ; (eax) = loop count per microsecond
+ cmp edx, 0 ; Is remainder =0?
+ jz short Stall40 ; yes, go Stall40
+ inc eax ; increment loopcount by 1
+;
+Stall40:
+ movzx ecx, byte ptr [ebp+8] ; Current processor number
+
+ mov PCR[PcStallScaleFactor], eax
+;
+; Reset return address to kexit
+;
+
+ pop eax ; discard original return address
+ push offset FLAT:kexit ; return to kexit
+
+ ;
+ ; EOI the Local Apic, the value written is immaterial
+ ;
+
+ mov eax, _HalpLocalUnitBase ; write the local unit EOI register
+ mov dword ptr [eax+LU_EOI], 0
+
+ and word ptr [esp+8], NOT 0200H ; Disable interrupt upon return
+;
+ iretd
+;
+;
+; --- Calibration is Done Restore all values and exit
+; --- Interrupts are disabled
+;
+kexit:
+ ;
+ ; Turn OFF TIMER ZERO
+ ;
+ ;
+ mov edx, _HalpLocalUnitBase
+ mov eax, StallLVTentry ; get Saved LVT
+
+@@:
+ test [edx+LU_TIMER_VECTOR], DELIVERY_PENDING
+ jnz @b
+
+ mov [edx+LU_TIMER_VECTOR], eax
+;
+; --- Restore the interrupt vector we used
+;
+ pop edx ; (edx)->IDT
+ pop [edx+8*APIC_STALL_VECTOR+4] ; higher half of desc
+ pop [edx+8*APIC_STALL_VECTOR] ; lower half of desc
+
+;
+; --- Restore the Local APIC's TPR
+;
+
+ mov eax, StallApicTpr ; get the saved TPR
+ mov edx, _HalpLocalUnitBase ; write old value to TPR
+ mov [edx+LU_TPR], eax
+
+
+ sub esp, 32
+ popfd ; restore caller's eflags
+ mov esp, ebp
+ pop ebp ; restore ebp
+
+ stdRET _HalpInitializeStallExecution
+
+stdENDP _HalpInitializeStallExecution
+
+ page ,132
+ subttl "Stall Execution"
+;++
+;
+; VOID
+; KeStallExecutionProcessor (
+; IN ULONG MicroSeconds
+; )
+;
+; Routine Description:
+;
+; This function stalls execution for the specified number of microseconds.
+; KeStallExecutionProcessor
+;
+; Arguments:
+;
+; MicroSeconds - Supplies the number of microseconds that execution is to be
+; stalled.
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+MicroSeconds equ [esp + 4]
+
+cPublicProc _KeStallExecutionProcessor ,1
+cPublicFpo 1, 0
+
+ mov ecx, MicroSeconds ; (ecx) = Microseconds
+ jecxz short kese10 ; return if no loop needed
+
+ mov eax, PCR[PcStallScaleFactor] ; get per microsecond
+
+ mul ecx ; (eax) = desired loop count
+
+ifdef DBG
+;
+; Make sure we the loopcount is less than 4G and is not equal to zero
+;
+
+ cmp edx, 0
+ jz short @f
+ int 3
+
+@@: cmp eax,0
+ jnz short @f
+ int 3
+endif
+
+ALIGN 4
+@@:
+ sub eax, 1 ; (eax) = (eax) - 1
+ jnz short @b
+kese10:
+ stdRET _KeStallExecutionProcessor
+
+stdENDP _KeStallExecutionProcessor
+
+_TEXT ends
+
+ end
diff --git a/private/ntos/nthals/halws3/i386/w3swint.asm b/private/ntos/nthals/halws3/i386/w3swint.asm
new file mode 100644
index 000000000..1becece07
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3swint.asm
@@ -0,0 +1,317 @@
+ title "Software Interrupts"
+;++
+;
+; Copyright (c) 1992 Microsoft Corporation
+; Copyright (c) 1992 Sequent Computer Systems, Inc.
+;
+; Module Name:
+;
+; w3swint.asm
+;
+; Abstract:
+;
+; This module implements the software interrupt handlers for the
+; APIC-based WinServer 3000 multiprocessor.
+;
+; Author:
+;
+; Phil Hochstetler (phil@sequent.com) 3-30-93
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+include i386\apic.inc
+include i386\w3.inc
+ .list
+
+ EXTRNP _KeBugCheck,1
+ EXTRNP KfLowerIrql,1,IMPORT,FASTCALL
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _HalEndSystemInterrupt,2
+ EXTRNP _KiDeliverApc,3,IMPORT
+ EXTRNP _KiDispatchInterrupt,0,IMPORT
+ EXTRNP _HalBeginSystemInterrupt,3
+
+ extrn _HalpIRQLtoTPR:byte
+ extrn _HalpLocalUnitBase:dword
+ extrn _HalpIrql2IRRMask:dword
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
+
+
+ page ,132
+ subttl "Request Software Interrupt"
+;++
+;
+; VOID
+; HalRequestSoftwareInterrupt (
+; IN KIRQL RequestIrql
+; )
+;
+; Routine Description:
+;
+; This routine is used to issue a software interrupt to the
+; calling processor. Instead of using the hardware to do this,
+; we have observed that emulation in software is *much* faster.
+; This mostly because it takes 30 clocks or so to do a APIC access.
+; The biggest win here is in avoiding having KeRaiseIrql/KeLowerIrql
+; write to the APIC for 75% of the traffic (LOW_LEVEL to APC/DPC LEVEL).
+;
+; Arguments:
+;
+; (cl) = RequestIrql - Supplies the request IRQL value
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+; equates for accessing argument
+;
+
+cPublicFastCall HalRequestSoftwareInterrupt ,1
+cPublicFpo 0, 0
+
+ mov eax, 1
+ shl eax, cl ; create IRR bitmask
+
+ pushfd ; save interrupt mode
+ cli ; disable interrupt
+
+ or PCR[PcIRR], eax ; request SW interrupt
+ cmp PCR[PcHal.ProcIrql], cl ; take it now?
+ jb short @f
+
+ popfd ; restore interrupt mode
+
+ fstRET HalRequestSoftwareInterrupt ; no, just return
+;
+; Call KfLowerIrql(CurrentIrql) which handles unmasked software interrupts
+;
+@@:
+ mov cl, PCR[PcHal.ProcIrql]
+
+ popfd ; restore interrupt mode
+
+ fstCall KfLowerIrql ; (cl) = CurrentIrql
+ fstRET HalRequestSoftwareInterrupt
+
+fstENDP HalRequestSoftwareInterrupt
+
+ page ,132
+ subttl "Clear 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
+
+cPublicProc _HalpDispatchInterrupt ,0
+
+;
+; 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, set new priority level, and clear IRR bit
+;
+ push dword ptr PCR[PcHal.ProcIrql]
+ mov byte ptr PCR[PcHal.ProcIrql], DISPATCH_LEVEL
+ and dword ptr PCR[PcIRR], NOT (1 SHL DISPATCH_LEVEL)
+
+;
+; 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
+
+stdENDP _HalpDispatchInterrupt
+
+ 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
+
+cPublicProc _HalpApcInterrupt ,0
+
+;
+; Create IRET frame on stack
+;
+ pop eax ; get caller PC
+ pushfd ; flags
+ push cs ; cs
+ push eax ; ip
+
+;
+; Save machine state on trap frame
+;
+
+ ENTER_INTERRUPT hapc_a, hapc_t
+.FPO ( FPO_LOCALS+1, 0, 0, 0, 0, FPO_TRAPFRAME )
+
+ public HalpApcInterrupt2ndEntry
+HalpApcInterrupt2ndEntry:
+
+;
+; Save previous IRQL, set new priority level, and clear IRR bit
+;
+ push dword ptr PCR[PcHal.ProcIrql]
+ mov byte ptr PCR[PcHal.ProcIrql], APC_LEVEL
+ and dword ptr PCR[PcIRR], NOT (1 SHL APC_LEVEL)
+
+;
+; 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
+
+stdENDP _HalpApcInterrupt
+
+_TEXT ends
+
+ end
diff --git a/private/ntos/nthals/halws3/i386/w3swint.bak b/private/ntos/nthals/halws3/i386/w3swint.bak
new file mode 100644
index 000000000..669085cf5
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3swint.bak
@@ -0,0 +1,267 @@
+ title "Software Interrupts"
+;++
+;
+; Copyright (c) 1992 Microsoft Corporation
+; Copyright (c) 1992 Sequent Computer Systems, Inc.
+;
+; Module Name:
+;
+; w3swint.asm
+;
+; Abstract:
+;
+; This module implements the software interrupt handlers for the
+; APIC-based WinServer 3000 multiprocessor.
+;
+; Author:
+;
+; Phil Hochstetler (phil@sequent.com) 3-30-93
+;
+; Environment:
+;
+; Kernel mode only.
+;
+; Revision History:
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+include i386\apic.inc
+include i386\w3.inc
+ .list
+
+ EXTRNP _KeBugCheck,1
+ EXTRNP KfLowerIrql,1,IMPORT,FASTCALL
+ EXTRNP Kei386EoiHelper,0,IMPORT
+ EXTRNP _HalEndSystemInterrupt,2
+ EXTRNP _KiDeliverApc,3,IMPORT
+ EXTRNP _KiDispatchInterrupt,0,IMPORT
+ EXTRNP _HalBeginSystemInterrupt,3
+
+ extrn _HalpIRQLtoTPR:byte
+ extrn _HalpLocalUnitBase:dword
+ extrn _HalpIrql2IRRMask:dword
+
+_TEXT SEGMENT DWORD PUBLIC 'CODE'
+ ASSUME DS:FLAT, ES:FLAT, SS:FLAT, FS:NOTHING, GS:NOTHING
+
+
+ page ,132
+ subttl "Request Software Interrupt"
+;++
+;
+; VOID
+; HalRequestSoftwareInterrupt (
+; IN KIRQL RequestIrql
+; )
+;
+; Routine Description:
+;
+; This routine is used to issue a software interrupt to the
+; calling processor. Instead of using the hardware to do this,
+; we have observed that emulation in software is *much* faster.
+; This mostly because it takes 30 clocks or so to do a APIC access.
+; The biggest win here is in avoiding having KeRaiseIrql/KeLowerIrql
+; write to the APIC for 75% of the traffic (LOW_LEVEL to APC/DPC LEVEL).
+;
+; Arguments:
+;
+; (cl) = RequestIrql - Supplies the request IRQL value
+;
+; Return Value:
+;
+; None.
+;
+;--
+
+; equates for accessing argument
+;
+
+cPublicFastCall HalRequestSoftwareInterrupt ,1
+cPublicFpo 0, 1
+
+ mov eax, 1
+ shl eax, cl ; create IRR bitmask
+ or PCR[PcIRR], eax ; request SW interrupt
+ cmp PCR[PcHal.ProcIrql], cl ; take it now?
+ jb short @f
+ fstRET HalRequestSoftwareInterrupt ; no, just return
+;
+; Call KfLowerIrql(CurrentIrql) which handles unmasked software interrupts
+;
+@@:
+ mov ecx, dword ptr PCR[PcHal.ProcIrql]
+ fstCall KfLowerIrql ; (cl) = CurrentIrql
+ fstRET HalRequestSoftwareInterrupt
+
+fstENDP HalRequestSoftwareInterrupt
+
+ 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
+
+cPublicProc _HalpDispatchInterrupt ,0
+
+;
+; 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, set new priority level, and clear IRR bit
+;
+ push dword ptr PCR[PcHal.ProcIrql]
+ mov byte ptr PCR[PcHal.ProcIrql], DISPATCH_LEVEL
+ and dword ptr PCR[PcIRR], NOT (1 SHL DISPATCH_LEVEL)
+
+;
+; 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
+
+stdENDP _HalpDispatchInterrupt
+
+ 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
+
+cPublicProc _HalpApcInterrupt ,0
+
+;
+; Create IRET frame on stack
+;
+ pop eax ; get caller PC
+ pushfd ; flags
+ push cs ; cs
+ push eax ; ip
+
+;
+; Save machine state on trap frame
+;
+
+ ENTER_INTERRUPT hapc_a, hapc_t
+.FPO ( FPO_LOCALS+1, 0, 0, 0, 0, FPO_TRAPFRAME )
+
+ public HalpApcInterrupt2ndEntry
+HalpApcInterrupt2ndEntry:
+
+;
+; Save previous IRQL, set new priority level, and clear IRR bit
+;
+ push dword ptr PCR[PcHal.ProcIrql]
+ mov byte ptr PCR[PcHal.ProcIrql], APC_LEVEL
+ and dword ptr PCR[PcIRR], NOT (1 SHL APC_LEVEL)
+
+;
+; 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
+
+stdENDP _HalpApcInterrupt
+
+_TEXT ends
+
+ end
diff --git a/private/ntos/nthals/halws3/i386/w3sysbus.c b/private/ntos/nthals/halws3/i386/w3sysbus.c
new file mode 100644
index 000000000..68cd71b7d
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3sysbus.c
@@ -0,0 +1,233 @@
+/*++
+
+
+Copyright (c) 1989 Microsoft Corporation
+
+Module Name:
+
+ w3sysbus.c
+
+Abstract:
+
+Author:
+
+Environment:
+
+Revision History:
+
+
+--*/
+
+#include "halp.h"
+
+extern UCHAR HalpIRQLtoTPR[];
+extern UCHAR HalpK2EISAIrq2Irql[];
+
+ULONG HalpDefaultInterruptAffinity;
+
+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
+ );
+
+ULONG
+HalpGetW3EisaInterruptVector(
+ 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,HalpTranslateSystemBusAddress)
+#pragma alloc_text(PAGE,HalpGetSystemInterruptVector)
+#pragma alloc_text(PAGE,HalpGetW3EisaInterruptVector)
+#endif
+
+
+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
+
+--*/
+
+{
+ UNREFERENCED_PARAMETER( BusHandler );
+ UNREFERENCED_PARAMETER( RootHandler );
+
+ if (BusAddress.HighPart != 0 || *AddressSpace > 1) {
+ return (FALSE);
+ }
+
+ TranslatedAddress->LowPart = BusAddress.LowPart;
+ TranslatedAddress->HighPart = 0;
+
+ return(TRUE);
+}
+
+
+ULONG
+HalpGetSystemInterruptVector(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ )
+
+/*++
+
+Routine Description:
+
+Arguments:
+
+ BusInterruptLevel - Supplies the bus specific interrupt level.
+
+ BusInterruptVector - Supplies the bus specific interrupt vector.
+
+ Irql - Returns the system request priority.
+
+ Affinity - Returns the system wide irq affinity.
+
+Return Value:
+
+ Returns the system interrupt vector corresponding to the specified device.
+
+--*/
+{
+ ULONG SystemVector;
+ KIRQL lIrql;
+
+ UNREFERENCED_PARAMETER( BusHandler );
+ UNREFERENCED_PARAMETER( RootHandler );
+ UNREFERENCED_PARAMETER( BusInterruptVector );
+
+ lIrql = (KIRQL) HalpK2EISAIrq2Irql[BusInterruptLevel];
+ SystemVector = HalpIRQLtoTPR[lIrql];
+
+ if (BusInterruptLevel > 23 ||
+ HalpIDTUsage[SystemVector].Flags & IDTOwned ) {
+
+ //
+ // This is an illegal BusInterruptVector and cannot be connected.
+ //
+
+ return(0);
+ }
+
+ *Irql = lIrql;
+ *Affinity = HalpDefaultInterruptAffinity;
+ ASSERT(HalpDefaultInterruptAffinity);
+ return SystemVector;
+}
+
+ULONG
+HalpGetW3EisaInterruptVector(
+ IN PBUS_HANDLER BusHandler,
+ IN PBUS_HANDLER RootHandler,
+ IN ULONG BusInterruptLevel,
+ IN ULONG BusInterruptVector,
+ OUT PKIRQL Irql,
+ OUT PKAFFINITY Affinity
+ )
+
+/*++
+
+Routine Description:
+
+ This function returns the system interrupt vector and IRQL level
+ corresponding to the specified bus interrupt level and/or vector. The
+ system interrupt vector and IRQL are suitable for use in a subsequent call
+ to KeInitializeInterrupt.
+
+Arguments:
+
+ BusHandle - Per bus specific structure
+
+ Irql - Returns the system request priority.
+
+ Affinity - Returns the system wide irq affinity.
+
+Return Value:
+
+ Returns the system interrupt vector corresponding to the specified device.
+
+--*/
+{
+ UNREFERENCED_PARAMETER( BusInterruptVector );
+
+ //
+ // On standard PCs, IRQ 2 is the cascaded interrupt, and it really shows
+ // up on IRQ 9.
+ //
+ if (BusInterruptLevel == 2) {
+ BusInterruptLevel = 9;
+ }
+
+ if (BusInterruptLevel > 23) {
+ return 0;
+ }
+
+ //
+ // Get parent's translation from here..
+ //
+ return BusHandler->ParentHandler->GetInterruptVector (
+ BusHandler->ParentHandler,
+ RootHandler,
+ BusInterruptLevel,
+ BusInterruptVector,
+ Irql,
+ Affinity
+ );
+}
diff --git a/private/ntos/nthals/halws3/i386/w3sysint.asm b/private/ntos/nthals/halws3/i386/w3sysint.asm
new file mode 100644
index 000000000..cc2b79af9
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/w3sysint.asm
@@ -0,0 +1,613 @@
+ title "System Interrupt"
+;++
+;
+; Copyright (c) 1991 Microsoft Corporation
+; Copyright (c) 1993 Sequent Computer Systems, Inc.
+;
+; Module Name:
+;
+; w3sysint.asm
+;
+; Abstract:
+;
+; This module implements the HAL routines to begin a system interrupt,
+; end a system interrupt, and enable/disable system interrupts
+; for the WinServer 3000.
+;
+; Author:
+;
+; Phil Hochstetler (phil@sequent.com) 3-30-93
+;
+; Environment:
+;
+; Kernel Mode
+;
+; Revision History:
+;
+;--
+
+.386p
+ .xlist
+include hal386.inc
+include callconv.inc ; calling convention macros
+include i386\kimacro.inc
+include mac386.inc
+include i386\apic.inc
+include i386\w3.inc
+ .list
+
+ EXTRNP _KeBugCheck,1
+ EXTRNP _KeLowerIrql,1
+ extrn _HalpIrql2TPR:byte
+ extrn _HalpLocalUnitBase:dword
+ extrn _HalpIOunitTwoBase:dword
+ extrn _HalpIOunitBase:dword
+ extrn _HalpK2Rdir2Irq:byte
+ extrn _HalpELCRImage:word
+ extrn _HalpK2EbsIOunitRedirectionTable:dword
+ extrn _HalpBeginW3InterruptTable:dword
+ extrn _HalpK2Vector2RdirTabEntry:byte
+ extrn _HalpK2EISAIrq2Irql:byte
+ extrn _HalpK2Irql2Eisa:byte
+ extrn _HalpK2Vector2EISA:byte
+ extrn FindHigherIrqlMask:dword
+ extrn HalpDispatchInterrupt2ndEntry:NEAR
+ extrn HalpApcInterrupt2ndEntry:NEAR
+ extrn _HalpMASKED:WORD
+
+_DATA SEGMENT DWORD PUBLIC 'DATA'
+
+_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 handles the initial interrupt sequence for all
+; external APIC interrupts for both single processor and multiple
+; processor WinServer 3000 systems. On the WinServer 3000 we use
+; the APIC to generate all I/O interrupts and their respective
+; priorities. We do not abstract the prioritization of interrupts
+; from the hardware since the APIC accomodates all Windows NT
+; requirements for IRQLs. In addition to I/O interrupts the APIC
+; is used to generate software interrupts for APCs and DPCs.
+; The APCs and DPCs are generated by a CPU via it's
+; local APIC interrupt command register. The interrupts are sent
+; as a self directed interrupt. It is required by NT that software
+; interrupts are always handled by the CPU which issues them.
+;
+; Note: Wakeup is included also in the above fashion
+;
+; This routine does not process an 8259 generated interrupt which
+; is not tied to the APIC. This processing is done in the w3ipi.asm
+; module. A subset of IRQs 0-15 are not wired through the EBS APIC.
+; This is because the APIC on the EBS only accomodates 16 interrupts
+; We have a total of 24 on a WS3000. We chose to have all system bus
+; generated interrupts 16-23 tied to the EBS APIC. The remaining
+; 8 are divided up for EISA cards. TheHalpK2EbsIounitRedirectionTable
+; in k2space.asm describes the EISA IRQs chosen for the EBS APIC.
+;
+; Prioritization of 8259 interrupts is done by generating an APIC
+; interrupt with the appropriate APIC vector which corresponds to
+; the incoming 8259 IRQ number. Thus, 2 interrupts are always
+; generated by an 8259 interrupt. The first is the 8259 interrupt
+; and the second is the APIC interrupt.
+;
+; The APIC interrupt is then appropriately prioritized by the hardware
+; and received accordingly via this routine.
+;
+
+;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 - Valid interrupt and Irql raised appropriately.
+;
+;--
+HbsiOldIrql equ dword ptr [esp+16]
+HbsiVector equ byte ptr [esp+12]
+HbsiIrql equ byte ptr [esp+8]
+
+ align 4
+cPublicProc _HalBeginSystemInterrupt ,3
+ push ebx
+ movzx ebx, HbsiVector ; (ebx) = System Vector
+ jmp _HalpBeginW3InterruptTable[ebx*4]
+;
+; --- Process APIC external interrupt, i.e., generated via EBS I/O APIC
+; - simply raise the Irql to the interrupt level of the
+; current interrupt, EOI APIC, and return TRUE
+;
+ align 4
+ public _HalpBeginW3APICInterrupt
+
+_HalpBeginW3APICInterrupt:
+ mov edx, _HalpLocalUnitBase ; Get address of Local APIC
+ movzx eax, HbsiIrql ; Get New IRQL
+ mov cl, PCR[PcHal.ProcIrql] ; Get current irql
+ cli ; Don't trust caller..
+if DBG
+ cmp al, cl
+ ja @f ; New IRQL is > Current
+ push eax ; New IRQL
+ push ebx ; Vector
+ push ecx ; Old IRQL
+ push [edx+LU_TPR] ;
+ mov dword ptr [edx+LU_TPR], 0FFH
+ mov PCR[PcHal.ProcIrql], HIGH_LEVEL ; Set to avoid recursive error
+ stdCall _KeBugCheck, <0Bh>
+@@:
+endif
+
+;
+; --- Do to the fact that some drivers like the i8042prt driver
+; and possibly other foolhardy drivers which don't use the IRQL
+; returned by the HalGetInterrupt routine when they do an IoConnectInt
+; we have to use the IRQL passed and not use the vector to set the
+; TPR...THESE TYPE OF DRIVERS HAVE TO BE EDGE SENSITIVE DEVICES TO
+; WORK IF THEY DO THIS CRAP....We allow changes in the IRQL as long
+; as it is a higher IRQL than the one returned by the HAL
+;
+ mov PCR[PcHal.ProcIrql], al ; Set new irql
+ movzx eax, _HalpIrql2TPR[eax]
+ mov [edx+LU_TPR], eax ; Set task priority register
+ mov eax, [edx+LU_TPR] ; Read it to make sure write occurs
+ mov eax, HbsiOldIrql ; get addr to store old irql
+ mov [eax], cl ; save old irql in the return variable
+;
+; --- EOI the APIC if the interrupt is not a level sensitive EISA interrupt
+; Level sensitive interrupts are EOI'ed in EndSystemInterrupt
+;
+ xor ah, ah
+ mov al, _HalpK2Vector2EISA[ebx] ; Get EISA IRQ #
+ mov cx, _HalpELCRImage ; Get edge/level register value
+ mov bx, _HalpMASKED ; get PIC level interrupts
+ not bx
+ and cx, bx ; clear level bits from PIC
+ bt cx, ax ; test appropriate bit
+ jc short @f
+ mov [edx+LU_EOI], eax ; EOI APIC
+@@:
+ mov eax, 1 ; True interrupt
+ sti ; Let interrupts go
+ pop ebx
+
+ stdRET _HalBeginSystemInterrupt
+;
+; --- Invalid or illegal vector
+;
+ align 4
+ public _HalpBeginW3InvalidInterrupt
+_HalpBeginW3InvalidInterrupt:
+ mov eax,0 ; return False
+ pop ebx
+
+ stdRET _HalBeginSystemInterrupt
+stdENDP _HalBeginSystemInterrupt
+
+;++
+;VOID
+;HalDisableSystemInterrupt(
+; IN CCHAR Vector,
+; IN KIRQL Irql
+; )
+;
+;
+;
+;Routine Description:
+;
+; Disables a system interrupt via the EBS APIC Redirection table
+; entries or the 8259 Interrupt mask registers
+;
+;Arguments:
+;
+; Vector - Supplies the vector of the interrupt to be disabled
+;
+; Irql - Supplies the interrupt level of the interrupt to be disabled
+;
+;Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalDisableSystemInterrupt ,2
+cPublicFpo 2, 0
+
+;
+; --- Exit if this is not the base processor
+;
+ movzx ecx, byte ptr [esp+4] ; (ecx) = Vector
+ movzx eax, byte ptr PCR[PcHal.PcrNumber]
+ cmp al, 0
+ jne HalDisableInt999 ; Exit if not base proc
+cPublicFpo 2, 1
+ pushfd
+ cli ; Disable interrupts
+
+;
+; --- Enable/Disable does not get called for the interrupt vectors
+; which are used for the 8259 generated interrupts. It only gets
+; called for the the APIC vectors which correspond to the 8259 ints...
+;
+ cmp ecx, APIC_DMA_VECTOR ; Is this for the 8259 DMA?
+ jne short HalDisableInt10 ; No - branch
+ mov ecx, 13 ; EISA DMA IRQ
+ jmp HalDisableInt60 ; Enable 8259 Int
+HalDisableInt10:
+ cmp ecx, APIC_KBD_VECTOR ; Is this the keyboard vector?
+ jne short HalDisableInt20 ; Yes - branch
+ mov ecx, 1 ; Keyboard IRQ
+ jmp HalDisableInt60 ; Enable 8259 Int
+HalDisableInt20:
+ cmp ecx, APIC_CLOCK_VECTOR ; 8259 clock?
+ jne short HalDisableInt30 ; Yes - branch
+ mov ecx, 0 ; Clock IRQ
+ jmp HalDisableInt60
+HalDisableInt30:
+ cmp ecx, APIC_RTC_VECTOR ; Real-time clock?
+ jne short HalDisableInt31 ; No -branch
+ mov ecx, 8 ; RTC IRQ
+ jmp HalDisableInt60
+HalDisableInt31:
+ cmp ecx, APIC_FLOPPY_VECTOR ; Floppy?
+ jne short HalDisableInt32 ; No -branch
+ mov ecx, 6 ; Floppy IRQ
+ jmp HalDisableInt60
+HalDisableInt32:
+ cmp ecx, APIC_IDE_VECTOR ; IDE Disk?
+ jne short HalDisableInt33 ; No -branch
+ mov ecx, 14 ; IDE Disk IRQ
+ jmp HalDisableInt60
+HalDisableInt33:
+ cmp ecx, APIC_MOUSE_VECTOR ; IRQ12 vector
+ jne short HalDisableInt34 ; No -branch
+ mov ecx, 12 ; IRQ12
+ jmp HalDisableInt60
+HalDisableInt34:
+
+;
+; --- Process other APIC vectors
+;
+ xor eax,eax
+ mov al, _HalpK2Vector2RdirTabEntry[ecx] ; Get EBS RDIR entry
+ cmp al, 0FFH ; No RDIR entry..exit
+ je HalDisableInt50 ; ..exit
+ cmp al, 0 ; Not used vector
+ je HalDisableInt50 ; ..exit
+ btr eax, 7 ; EBS I/O APIC RDIR??
+ jnc HalDisableInt35 ; Yes
+ mov edx, _HalpIOunitTwoBase ; Boot processor I/O APIC RDIR
+ jmp HalDisableInt40 ; continue
+HalDisableInt35:
+ mov edx, _HalpIOunitBase ; Address of EBS I/O APIC
+HalDisableInt40:
+;
+; No need for a lock here since only the base manipulates these registers
+;
+ mov [edx+IO_REGISTER_SELECT], eax ; Select register
+ or dword ptr [edx+IO_REGISTER_WINDOW], IOMPIC_RT_MASK ; mask it
+HalDisableInt50:
+cPublicFpo 2, 0
+ popfd
+ stdRET _HalDisableSystemInterrupt
+;
+; --- 8259 interrupt enable...
+;
+HalDisableInt60:
+;
+; --- 8259 interrupt disable...
+;
+ mov edx, 1
+ shl edx, cl ; (ebx) = bit in IMR to disable
+ 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
+cPublicFpo 2, 0
+ popfd
+HalDisableInt999:
+ stdRET _HalDisableSystemInterrupt
+
+stdENDP _HalDisableSystemInterrupt
+
+;++
+;
+;BOOLEAN
+;HalEnableSystemInterrupt(
+; IN ULONG Vector,
+; IN KIRQL Irql,
+; IN KINTERRUPT_MODE InterruptMode
+; )
+;
+;
+;Routine Description:
+;
+ ; Enables a system interrupt via PIC or APIC hardware masks
+;
+;Arguments:
+;
+; Vector - Supplies the vector of the interrupt to be enabled
+;
+; Irql - Supplies the interrupt level of the interrupt to be enabled.
+;
+;Return Value:
+;
+; None.
+;
+;--
+cPublicProc _HalEnableSystemInterrupt ,3
+cPublicFpo 3, 0
+;
+; --- The base processor controls enabling/disabling of all ints
+;
+ movzx ecx, byte ptr [esp+4] ; (ecx) = Vector
+ movzx eax, byte ptr PCR[PcHal.PcrNumber]
+ cmp al, 0
+ jne HalEnableInt999 ; Exit if not base proc
+cPublicFpo 3, 1
+ pushfd
+ cli
+;
+; --- Enable/Disable does not get called for the interrupt vectors
+; which are used for the 8259 generated interrupts. It only gets
+; called for the the APIC vectors which correspond to the 8259 ints...
+;
+ cmp ecx, APIC_DMA_VECTOR ; Is this for the 8259 DMA?
+ jne short HalEnableInt10 ; No - branch
+ mov ecx, 13 ; EISA DMA IRQ
+ jmp HalEnableInt60 ; Enable 8259 Int
+HalEnableInt10:
+ cmp ecx, APIC_KBD_VECTOR ; Is this the keyboard vector?
+ jne short HalEnableInt20 ; No - branch
+ mov ecx, 1 ; Keyboard IRQ
+ jmp HalEnableInt60 ; Enable 8259 Int
+HalEnableInt20:
+ cmp ecx, APIC_CLOCK_VECTOR ; 8259 clock?
+ jne short HalEnableInt30 ; No - branch
+ mov ecx, 0 ; Clock IRQ
+ jmp HalEnableInt60
+HalEnableInt30:
+ cmp ecx, APIC_RTC_VECTOR ; Real-time clock?
+ jne short HalEnableInt31 ; No -branch
+ mov ecx, 8 ; RTC IRQ
+ jmp HalEnableInt60
+HalEnableInt31:
+ cmp ecx, APIC_FLOPPY_VECTOR ; Floppy?
+ jne short HalEnableInt32 ; No -branch
+ mov ecx, 6 ; Floppy IRQ
+ jmp HalEnableInt60
+HalEnableInt32:
+ cmp ecx, APIC_IDE_VECTOR ; IDE Disk?
+ jne short HalEnableInt33 ; No -branch
+ mov ecx, 14 ; IDE Disk IRQ
+ jmp HalEnableInt60
+HalEnableInt33:
+ cmp ecx, APIC_MOUSE_VECTOR ; IRQ12 vector
+ jne short HalEnableInt34 ; No -branch
+ mov ecx, 12 ; IRQ12
+ jmp HalEnableInt60
+HalEnableInt34:
+
+
+;
+; --- Process APIC vectors
+;
+ xor eax,eax
+ mov al, _HalpK2Vector2RdirTabEntry[ecx] ; Get EBS RDIR entry
+ cmp al, 0FFH ; No RDIR entry..exit
+ je HalEnableInt50 ; ..exit
+ cmp al, 0 ; Not used vector
+ je HalEnableInt50 ; ..exit
+ btr eax, 7 ; EBS I/O APIC RDIR??
+ jnc HalEnableInt35 ; Yes
+ mov edx, _HalpIOunitTwoBase ; Boot processor I/O APIC RDIR
+ jmp HalEnableInt40 ; continue
+HalEnableInt35:
+ mov edx, _HalpIOunitBase ; Address of EBS I/O APIC
+HalEnableInt40:
+;
+; No need for a lock here since only the base manipulates these registers
+;
+ mov [edx+IO_REGISTER_SELECT], eax ; Select register
+ and dword ptr [edx+IO_REGISTER_WINDOW], NOT IOMPIC_RT_MASK ; Unmask it
+HalEnableInt50:
+cPublicFpo 3, 0
+ popfd
+ stdRET _HalEnableSystemInterrupt
+;
+; --- 8259 interrupt enable...
+;
+HalEnableInt60:
+ xor eax, eax
+;
+; Get the current interrupt mask register from the 8259
+;
+ in al, PIC2_PORT1
+ shl eax, 8
+ in al, PIC1_PORT1
+;
+; Unmask the interrupt to be enabled
+;
+ btr eax, ecx
+ btr eax, 2 ; Enable cascaded IRQ2
+
+;
+; Write the new interrupt mask register back to the 8259
+;
+ out PIC1_PORT1, al
+ shr eax, 8
+ out PIC2_PORT1, al
+ PIC2DELAY
+cPublicFpo 3, 0
+ popfd
+HalEnableInt999:
+ stdRET _HalEnableSystemInterrupt
+stdENDP _HalEnableSystemInterrupt
+
+
+; HalpEndSystemInterrupt
+; IN KIRQL NewIrql,
+; IN ULONG Vector
+; )
+;
+; Routine Description:
+;
+; This routine is used to lower IRQL to the specified value just prior
+; to ending interrupt processing.
+;
+; 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.
+;
+; Return Value:
+;
+; None.
+;
+;--
+HeiVector equ [esp+8]
+HeiNewIrql equ [esp+4]
+
+cPublicProc _HalEndSystemInterrupt ,2
+cPublicFpo 2, 0
+
+ mov eax, HeiVector ; Get the current vector
+ mov edx, _HalpLocalUnitBase ; Local APIC address
+if DBG
+ xor ecx, ecx
+ mov cl, byte ptr HeiNewIrql
+ cmp cl, PCR[PcHal.ProcIrql]
+ jbe short @f
+ push dword ptr ecx ; new irql for debugging
+ push dword ptr PCR[PcHal.ProcIrql] ; old irql for debugging
+ mov dword ptr [edx+LU_TPR], 0FFH
+ mov PCR[PcHal.ProcIrql], HIGH_LEVEL ; Set to avoid recursive error
+ stdCall _KeBugCheck, <IRQL_NOT_LESS_OR_EQUAL>
+@@:
+endif
+;
+; EOI the APIC on level EISA interrupts
+;
+ mov al, _HalpK2Vector2EISA[eax] ; Get EISA IRQ #
+ mov cx, _HalpELCRImage ; Get edge/level register value
+ bt cx, ax ; test appropriate bit
+ jnc short NoEOI ; 1 means level interrupt
+
+ ;
+ ; Level interrupt so we need to determine if the source
+ ; is the PIC or APIC. If the PIC, then we need to unmask the
+ ; source, if the APIC, then we need to do an EOI to the APIC.
+ ;
+
+ mov cx, _HalpMASKED ; get PIC level ints
+ bt cx, ax ; test appropriate bit
+ jnc short @f ; CF=1 means PIC level int
+
+lock btr _HalpMASKED, ax ; atomic clear of bit
+
+ mov cx, ax
+ mov ax, 1
+ shl ax, cl
+ or al, ah
+ not al
+ mov cl, al
+
+ in al, PIC2_PORT1 ; unmask bit in PIC
+ and al, cl
+ out PIC2_PORT1, al
+
+ jmp short NoEOI
+@@:
+ mov [edx+LU_EOI], eax ; EOI APIC
+NoEOI:
+ xor eax, eax
+ mov al, byte ptr HeiNewIrql
+
+;
+; Write new lower priority level into the APIC Task Priority Register
+;
+ pushfd
+ cli
+ mov PCR[PcHal.ProcIrql], al ; set new IRQL
+ mov al, _HalpIrql2TPR[eax] ; get new TPR
+ mov [edx+LU_TPR], eax ; write new TPR
+ mov eax, [edx+LU_TPR] ; Flush CPU write buffer
+ popfd
+
+ mov al, byte ptr HeiNewIrql ; get current irql
+ cmp al, DISPATCH_LEVEL ; SW ints possible?
+ jb short @f
+ stdRET _HalEndSystemInterrupt
+
+;
+; Check for any pending software interrupts
+;
+@@:
+ mov edx, PCR[PcIRR] ; get current IRR
+ and edx, FindHigherIrqlMask[eax*4]
+ jnz short @f
+ stdRET _HalEndSystemInterrupt
+
+;
+; Software interrupt(s) pending, figure out which one(s) and take it
+;
+@@:
+ cli
+ test dword ptr PCR[PcIRR], (1 SHL DISPATCH_LEVEL)
+ jz short @f
+ add esp, 12
+ jmp HalpDispatchInterrupt2ndEntry
+@@:
+ cmp al, APC_LEVEL
+ jae short @f
+ test dword ptr PCR[PcIRR], (1 SHL APC_LEVEL)
+ jz short @f
+ add esp, 12
+ jmp HalpApcInterrupt2ndEntry
+@@:
+ sti
+ stdRET _HalEndSystemInterrupt
+
+stdENDP _HalEndSystemInterrupt
+
+_TEXT ENDS
+
+ END
diff --git a/private/ntos/nthals/halws3/i386/xxbiosa.asm b/private/ntos/nthals/halws3/i386/xxbiosa.asm
new file mode 100644
index 000000000..bc0173a17
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/xxbiosc.c b/private/ntos/nthals/halws3/i386/xxbiosc.c
new file mode 100644
index 000000000..60cf92748
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/xxdisp.c b/private/ntos/nthals/halws3/i386/xxdisp.c
new file mode 100644
index 000000000..d48977df0
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/xxioacc.asm b/private/ntos/nthals/halws3/i386/xxioacc.asm
new file mode 100644
index 000000000..8445c3404
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/xxkdsup.c b/private/ntos/nthals/halws3/i386/xxkdsup.c
new file mode 100644
index 000000000..6e569b5ac
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/xxmemory.c b/private/ntos/nthals/halws3/i386/xxmemory.c
new file mode 100644
index 000000000..920714540
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/xxstubs.c b/private/ntos/nthals/halws3/i386/xxstubs.c
new file mode 100644
index 000000000..8421fb30a
--- /dev/null
+++ b/private/ntos/nthals/halws3/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/halws3/i386/xxtime.c b/private/ntos/nthals/halws3/i386/xxtime.c
new file mode 100644
index 000000000..92abb2aeb
--- /dev/null
+++ b/private/ntos/nthals/halws3/i386/xxtime.c
@@ -0,0 +1,5 @@
+//
+// Include code from halx86
+// This is a cpp style symbolic link
+
+#include "..\halx86\i386\xxtime.c"