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